1
# Copyright (C) 2005 Aaron Bentley
2
# <aaron.bentley@utoronto.ca>
1
# Copyright (C) 2005, 2006, 2007 Aaron Bentley <aaron.bentley@utoronto.ca>
2
# Copyright (C) 2007 John Arbash Meinel
4
4
# This program is free software; you can redistribute it and/or modify
5
5
# it under the terms of the GNU General Public License as published by
27
27
import bzrlib.errors
28
from bzrlib.errors import BzrCommandError
29
from bzrlib.bzrdir import BzrDir
28
from bzrlib.errors import (BzrCommandError, NotBranchError, NoSuchFile,
29
UnsupportedFormatError, TransportError,
30
NoWorkingTree, PermissionDenied)
31
from bzrlib.bzrdir import BzrDir, BzrDirFormat
32
34
dirname = tempfile.mkdtemp("temp-branch")
38
40
def is_clean(cur_tree):
40
42
Return true if no files are modifed or unknown
42
>>> tree = temp_tree()
45
>>> fooname = os.path.join(tree.basedir, "foo")
46
>>> file(fooname, "wb").write("bar")
49
>>> bzrlib.add.smart_add_tree(tree, [tree.basedir])
53
>>> tree.commit("added file")
58
from bzrlib.diff import compare_trees
59
44
old_tree = cur_tree.basis_tree()
60
45
new_tree = cur_tree
62
for path, file_class, kind, file_id, entry in new_tree.list_files():
63
if file_class in ('?', 'I'):
64
non_source.append(path)
65
delta = compare_trees(old_tree, new_tree, want_unchanged=False)
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)
66
55
return not delta.has_changed(), non_source
68
57
def set_push_data(tree, location):
69
push_file = file (tree._control_files.controlfilename("x-push-data"), "wb")
70
push_file.write("%s\n" % location)
58
tree.branch.control_files.put_utf8("x-push-data", "%s\n" % location)
72
60
def get_push_data(tree):
77
65
>>> set_push_data(tree, 'http://somewhere')
78
66
>>> get_push_data(tree)
82
filename = tree._control_files.controlfilename("x-push-data")
83
if not os.path.exists(filename):
71
location = tree.branch.control_files.get_utf8('x-push-data').read()
85
push_file = file (filename, "rb")
86
(location,) = [f.rstrip('\n') for f in push_file]
74
return location.rstrip('\n')
90
77
>>> shell_escape('hello')
112
99
def __init__(self, rsync_name):
113
100
Exception.__init__(self, "%s not found." % rsync_name)
115
def rsync(source, target, ssh=False, excludes=(), silent=False,
102
def rsync(source, target, ssh=False, excludes=(), silent=False,
116
103
rsync_name="rsync"):
118
105
>>> new_dir = tempfile.mkdtemp()
121
108
>>> rsync("a", "b", silent=True)
122
109
Traceback (most recent call last):
123
110
RsyncNoFile: No such file...
124
>>> rsync(tempdir + "/a", tempdir + "/b", excludes=("*.py",), silent=True) #doctest: +ELLIPSIS
111
>>> rsync(new_dir + "/a", new_dir + "/b", excludes=("*.py",), silent=True)
125
112
Traceback (most recent call last):
126
113
RsyncNoFile: No such file...
127
>>> rsync(tempdir + "/a", tempdir + "/b", excludes=("*.py",), silent=True, rsync_name="rsyncc")
114
>>> rsync(new_dir + "/a", new_dir + "/b", excludes=("*.py",), silent=True, rsync_name="rsyncc")
128
115
Traceback (most recent call last):
129
116
NoRsync: rsyncc not found.
130
117
>>> os.chdir(old_dir)
189
176
raise RsyncUnknownStatus(proc.returncode)
190
177
return [l.split(' ')[-1].rstrip('\n') for l in result.splitlines(True)]
192
exclusions = ('.bzr/x-push-data', '.bzr/parent', '.bzr/x-pull-data',
193
'.bzr/x-pull', '.bzr/pull', '.bzr/stat-cache',
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')
197
185
def read_revision_history(fname):
210
198
tempdir = tempfile.mkdtemp('push')
212
200
history_fname = os.path.join(tempdir, 'revision-history')
213
cmd = rsync(location+'.bzr/revision-history', history_fname,
202
cmd = rsync(location+'.bzr/revision-history', history_fname,
205
cmd = rsync(location+'.bzr/branch/revision-history', history_fname,
215
207
history = read_revision_history(history_fname)
217
209
shutil.rmtree(tempdir)
234
226
except RsyncNoFile:
237
def push(tree, location=None, overwrite=False, working_tree=True):
229
def rspush(tree, location=None, overwrite=False, working_tree=True):
238
230
push_location = get_push_data(tree)
239
231
if location is not None:
240
232
if not location.endswith('/'):
242
234
push_location = location
244
236
if push_location is None:
245
if tree.branch.get_push_location() is None:
246
raise BzrCommandError("No push location known or specified.")
248
raise bzrlib.errors.MustUseDecorated
250
if push_location.find('://') != -1:
251
raise bzrlib.errors.MustUseDecorated
253
if push_location.find(':') == -1:
254
raise bzrlib.errors.MustUseDecorated
256
clean, non_source = is_clean(tree)
258
print """Error: This tree has uncommitted changes or unknown (?) files.
259
Use "bzr status" to list them."""
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."""
262
254
final_exclusions = non_source[:]
283
275
" specified location. Please ensure that"
284
276
' "%s" is of the form "machine:/path".' % push_location)
285
277
print "Pushing to %s" % push_location
286
rsync(tree.basedir+'/', push_location, ssh=True,
278
rsync(tree.basedir+'/', push_location, ssh=usessh,
287
279
excludes=final_exclusions)
289
281
set_push_data(tree, push_location)
296
288
return new_committer
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)
301
367
result = doctest.testmod()