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
25
23
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
30
34
dirname = tempfile.mkdtemp("temp-branch")
31
return bzrlib.branch.Branch.initialize(dirname)
34
shutil.rmtree(br.base)
36
def is_clean(cur_branch):
35
return BzrDir.create_standalone_workingtree(dirname)
38
shutil.rmtree(tree.basedir)
40
def is_clean(cur_tree):
38
42
Return true if no files are modifed or unknown
40
>>> br = temp_branch()
43
>>> fooname = os.path.join(br.base, "foo")
44
>>> file(fooname, "wb").write("bar")
47
>>> br.working_tree().add(["foo"])
50
>>> br.working_tree().commit("added file")
55
from bzrlib.diff import compare_trees
56
old_tree = cur_branch.basis_tree()
57
new_tree = cur_branch.working_tree()
44
old_tree = cur_tree.basis_tree()
59
for path, file_class, kind, file_id, entry in new_tree.list_files():
60
if file_class in ('?', 'I'):
61
non_source.append(path)
62
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)
63
55
return not delta.has_changed(), non_source
65
def set_push_data(br, location):
66
push_file = file (br.control_files.controlfilename("x-push-data"), "wb")
67
push_file.write("%s\n" % location)
57
def set_push_data(tree, location):
58
tree.branch.control_files.put_utf8("x-push-data", "%s\n" % location)
69
def get_push_data(br):
60
def get_push_data(tree):
71
>>> br = temp_branch()
72
>>> get_push_data(br) is None
62
>>> tree = temp_tree()
63
>>> get_push_data(tree) is None
74
>>> set_push_data(br, 'http://somewhere')
65
>>> set_push_data(tree, 'http://somewhere')
66
>>> get_push_data(tree)
79
filename = br.control_files.controlfilename("x-push-data")
80
if not os.path.exists(filename):
71
location = tree.branch.control_files.get_utf8('x-push-data').read()
82
push_file = file (filename, "rb")
83
(location,) = [f.rstrip('\n') for f in push_file]
74
return location.rstrip('\n')
87
77
>>> shell_escape('hello')
109
99
def __init__(self, rsync_name):
110
100
Exception.__init__(self, "%s not found." % rsync_name)
112
def rsync(source, target, ssh=False, excludes=(), silent=False,
102
def rsync(source, target, ssh=False, excludes=(), silent=False,
113
103
rsync_name="rsync"):
105
>>> new_dir = tempfile.mkdtemp()
106
>>> old_dir = os.getcwd()
107
>>> os.chdir(new_dir)
115
108
>>> rsync("a", "b", silent=True)
116
109
Traceback (most recent call last):
117
RsyncNoFile: No such file a
118
>>> rsync("a", "b", excludes=("*.py",), silent=True)
110
RsyncNoFile: No such file...
111
>>> rsync(new_dir + "/a", new_dir + "/b", excludes=("*.py",), silent=True)
119
112
Traceback (most recent call last):
120
RsyncNoFile: No such file a
121
>>> rsync("a", "b", excludes=("*.py",), silent=True, rsync_name="rsyncc")
113
RsyncNoFile: No such file...
114
>>> rsync(new_dir + "/a", new_dir + "/b", excludes=("*.py",), silent=True, rsync_name="rsyncc")
122
115
Traceback (most recent call last):
123
116
NoRsync: rsyncc not found.
117
>>> os.chdir(old_dir)
118
>>> os.rmdir(new_dir)
125
120
cmd = [rsync_name, "-av", "--delete"]
181
176
raise RsyncUnknownStatus(proc.returncode)
182
177
return [l.split(' ')[-1].rstrip('\n') for l in result.splitlines(True)]
184
exclusions = ('.bzr/x-push-data', '.bzr/parent', '.bzr/x-pull-data',
185
'.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')
189
185
def read_revision_history(fname):
202
198
tempdir = tempfile.mkdtemp('push')
204
200
history_fname = os.path.join(tempdir, 'revision-history')
205
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,
207
207
history = read_revision_history(history_fname)
209
209
shutil.rmtree(tempdir)
226
226
except RsyncNoFile:
229
def push(cur_branch, location=None, overwrite=False, working_tree=True):
230
push_location = get_push_data(cur_branch)
229
def rspush(tree, location=None, overwrite=False, working_tree=True):
230
push_location = get_push_data(tree)
231
231
if location is not None:
232
232
if not location.endswith('/'):
234
234
push_location = location
236
236
if push_location is None:
237
raise bzrlib.errors.MustUseDecorated
239
if push_location.find('://') != -1:
240
raise bzrlib.errors.MustUseDecorated
242
if push_location.find(':') == -1:
243
raise bzrlib.errors.MustUseDecorated
245
clean, non_source = is_clean(cur_branch)
247
print """Error: This tree has uncommitted changes or unknown (?) files.
248
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."""
251
254
final_exclusions = non_source[:]
253
wt = cur_branch.working_tree()
254
257
final_exclusions = []
255
258
for path, status, kind, file_id, entry in wt.list_files():
256
259
final_exclusions.append(path)
272
275
" specified location. Please ensure that"
273
276
' "%s" is of the form "machine:/path".' % push_location)
274
277
print "Pushing to %s" % push_location
275
rsync(cur_branch.base+'/', push_location, ssh=True,
278
rsync(tree.basedir+'/', push_location, ssh=usessh,
276
279
excludes=final_exclusions)
278
set_push_data(cur_branch, push_location)
281
set_push_data(tree, push_location)
280
284
def short_committer(committer):
281
285
new_committer = re.sub('<.*>', '', committer).strip(' ')
284
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)
289
367
result = doctest.testmod()