14
14
# You should have received a copy of the GNU General Public License
15
15
# along with this program; if not, write to the Free Software
16
16
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23
25
from subprocess import Popen, PIPE
28
from bzrlib.errors import (BzrCommandError, NotBranchError, NoSuchFile,
29
UnsupportedFormatError, TransportError,
30
NoWorkingTree, PermissionDenied)
31
from bzrlib.bzrdir import BzrDir, BzrDirFormat
34
29
dirname = tempfile.mkdtemp("temp-branch")
35
return BzrDir.create_standalone_workingtree(dirname)
38
shutil.rmtree(tree.basedir)
40
def is_clean(cur_tree):
30
return bzrlib.branch.Branch.initialize(dirname)
33
shutil.rmtree(br.base)
35
def is_clean(cur_branch):
42
37
Return true if no files are modifed or unknown
39
>>> br = temp_branch()
42
>>> fooname = os.path.join(br.base, "foo")
43
>>> file(fooname, "wb").write("bar")
46
>>> br.working_tree().add(["foo"])
49
>>> br.working_tree().commit("added file")
44
old_tree = cur_tree.basis_tree()
54
from bzrlib.diff import compare_trees
55
old_tree = cur_branch.basis_tree()
56
new_tree = cur_branch.working_tree()
49
for path, file_class, kind, file_id, entry in new_tree.list_files():
50
if file_class in ('?', 'I'):
51
non_source.append(path)
52
delta = new_tree.changes_from(old_tree, want_unchanged=False)
58
for path, file_class, kind, file_id, entry in new_tree.list_files():
59
if file_class in ('?', 'I'):
60
non_source.append(path)
61
delta = compare_trees(old_tree, new_tree, want_unchanged=False)
55
62
return not delta.has_changed(), non_source
57
def set_push_data(tree, location):
58
tree.branch.control_files.put_utf8("x-push-data", "%s\n" % location)
60
def get_push_data(tree):
62
>>> tree = temp_tree()
63
>>> get_push_data(tree) is None
64
def set_pull_data(br, location, rev_id):
65
pull_file = file (br.control_files.controlfilename("x-pull-data"), "wb")
66
pull_file.write("%s\n%s\n" % (location, rev_id))
68
def get_pull_data(br):
70
>>> br = temp_branch()
73
>>> set_pull_data(br, 'http://somewhere', '888-777')
75
('http://somewhere', '888-777')
78
filename = br.control_files.controlfilename("x-pull-data")
79
if not os.path.exists(filename):
81
pull_file = file (filename, "rb")
82
location, rev_id = [f.rstrip('\n') for f in pull_file]
83
return location, rev_id
85
def set_push_data(br, location):
86
push_file = file (br.control_files.controlfilename("x-push-data"), "wb")
87
push_file.write("%s\n" % location)
89
def get_push_data(br):
91
>>> br = temp_branch()
92
>>> get_push_data(br) is None
65
>>> set_push_data(tree, 'http://somewhere')
66
>>> get_push_data(tree)
94
>>> set_push_data(br, 'http://somewhere')
71
location = tree.branch.control_files.get_utf8('x-push-data').read()
99
filename = br.control_files.controlfilename("x-push-data")
100
if not os.path.exists(filename):
74
return location.rstrip('\n')
102
push_file = file (filename, "rb")
103
(location,) = [f.rstrip('\n') for f in push_file]
77
107
>>> shell_escape('hello')
99
129
def __init__(self, rsync_name):
100
130
Exception.__init__(self, "%s not found." % rsync_name)
102
def rsync(source, target, ssh=False, excludes=(), silent=False,
132
def rsync(source, target, ssh=False, excludes=(), silent=False,
103
133
rsync_name="rsync"):
105
>>> new_dir = tempfile.mkdtemp()
106
>>> old_dir = os.getcwd()
107
>>> os.chdir(new_dir)
108
135
>>> rsync("a", "b", silent=True)
109
136
Traceback (most recent call last):
110
RsyncNoFile: No such file...
111
>>> rsync(new_dir + "/a", new_dir + "/b", excludes=("*.py",), silent=True)
137
RsyncNoFile: No such file a
138
>>> rsync("a", "b", excludes=("*.py",), silent=True)
112
139
Traceback (most recent call last):
113
RsyncNoFile: No such file...
114
>>> rsync(new_dir + "/a", new_dir + "/b", excludes=("*.py",), silent=True, rsync_name="rsyncc")
140
RsyncNoFile: No such file a
141
>>> rsync("a", "b", excludes=("*.py",), silent=True, rsync_name="rsyncc")
115
142
Traceback (most recent call last):
116
143
NoRsync: rsyncc not found.
117
>>> os.chdir(old_dir)
118
>>> os.rmdir(new_dir)
120
145
cmd = [rsync_name, "-av", "--delete"]
176
201
raise RsyncUnknownStatus(proc.returncode)
177
202
return [l.split(' ')[-1].rstrip('\n') for l in result.splitlines(True)]
179
exclusions = ('.bzr/x-push-data', '.bzr/branch/x-push/data', '.bzr/parent',
180
'.bzr/branch/parent', '.bzr/x-pull-data', '.bzr/x-pull',
181
'.bzr/pull', '.bzr/stat-cache', '.bzr/x-rsync-data',
182
'.bzr/basis-inventory', '.bzr/inventory.backup.weave')
204
exclusions = ('.bzr/x-push-data', '.bzr/parent', '.bzr/x-pull-data',
205
'.bzr/x-pull', '.bzr/pull', '.bzr/stat-cache',
185
209
def read_revision_history(fname):
226
246
except RsyncNoFile:
229
def rspush(tree, location=None, overwrite=False, working_tree=True):
230
push_location = get_push_data(tree)
249
def push(cur_branch, location=None, overwrite=False):
250
push_location = get_push_data(cur_branch)
231
251
if location is not None:
232
252
if not location.endswith('/'):
234
254
push_location = location
236
256
if push_location is None:
237
raise BzrCommandError("No rspush location known or specified.")
239
if (push_location.find('::') != -1):
244
if (push_location.find('://') != -1 or
245
push_location.find(':') == -1):
246
raise BzrCommandError("Invalid rsync path %r." % push_location)
249
clean, non_source = is_clean(tree)
251
print """Error: This tree has uncommitted changes or unknown (?) files.
252
Use "bzr status" to list them."""
254
final_exclusions = non_source[:]
257
final_exclusions = []
258
for path, status, kind, file_id, entry in wt.list_files():
259
final_exclusions.append(path)
261
final_exclusions.extend(exclusions)
257
raise bzrlib.errors.MustUseDecorated
259
if push_location.find('://') != -1:
260
raise bzrlib.errors.MustUseDecorated
262
if push_location.find(':') == -1:
263
raise bzrlib.errors.MustUseDecorated
265
clean, non_source = is_clean(cur_branch)
267
print """Error: This tree has uncommitted changes or unknown (?) files.
268
Use "bzr status" to list them."""
270
non_source.extend(exclusions)
262
271
if not overwrite:
264
if not history_subset(push_location, tree.branch):
273
if not history_subset(push_location, cur_branch):
265
274
raise bzrlib.errors.BzrCommandError("Local branch is not a"
266
275
" newer version of remote"
275
284
" specified location. Please ensure that"
276
285
' "%s" is of the form "machine:/path".' % push_location)
277
286
print "Pushing to %s" % push_location
278
rsync(tree.basedir+'/', push_location, ssh=usessh,
279
excludes=final_exclusions)
281
set_push_data(tree, push_location)
284
def short_committer(committer):
285
new_committer = re.sub('<.*>', '', committer).strip(' ')
286
if len(new_committer) < 2:
292
"""Screen-scrape Apache listings"""
293
apache_dir = '<img border="0" src="/icons/folder.gif" alt="[dir]">'\
296
expr = re.compile('<a[^>]*href="([^>]*)"[^>]*>', flags=re.I)
298
match = expr.search(line)
302
if url.startswith('http://') or url.startswith('/') or '../' in url:
306
yield url.rstrip('/')
309
def iter_branches(t, lister=None):
310
"""Iterate through all the branches under a transport"""
311
for bzrdir in iter_bzrdirs(t, lister):
313
branch = bzrdir.open_branch()
314
if branch.bzrdir is bzrdir:
316
except (NotBranchError, UnsupportedFormatError):
320
def iter_branch_tree(t, lister=None):
321
for bzrdir in iter_bzrdirs(t, lister):
323
wt = bzrdir.open_workingtree()
325
except NoWorkingTree, UnsupportedFormatError:
327
branch = bzrdir.open_branch()
328
if branch.bzrdir is bzrdir:
330
except (NotBranchError, UnsupportedFormatError):
334
def iter_bzrdirs(t, lister=None):
337
return t.list_dir('.')
339
bzrdir = bzrdir_from_transport(t)
341
except (NotBranchError, UnsupportedFormatError, TransportError,
345
for directory in lister(t):
346
if directory == ".bzr":
349
subt = t.clone(directory)
350
except UnicodeDecodeError:
352
for bzrdir in iter_bzrdirs(subt, lister):
354
except (NoSuchFile, PermissionDenied, TransportError):
358
def bzrdir_from_transport(t):
359
"""Open a bzrdir from a transport (not a location)"""
360
format = BzrDirFormat.find_format(t)
361
BzrDir._check_supported(format, False)
362
return format.open(t)
287
rsync(cur_branch.base+'/', push_location, ssh=True, excludes=non_source)
289
set_push_data(cur_branch, push_location)