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
43
38
>>> import bzrlib.add
44
>>> tree = temp_tree()
39
>>> br = temp_branch()
47
>>> fooname = os.path.join(tree.basedir, "foo")
42
>>> fooname = os.path.join(br.base, "foo")
48
43
>>> file(fooname, "wb").write("bar")
51
>>> bzrlib.add.smart_add_tree(tree, [tree.basedir])
46
>>> bzrlib.add.smart_add_branch(br, [br.base])
55
>>> tree.commit("added file", rev_id='commit-id')
50
>>> br.commit("added file")
61
old_tree = cur_tree.basis_tree()
56
from bzrlib.diff import compare_trees
57
old_tree = cur_branch.basis_tree()
58
new_tree = cur_branch.working_tree()
64
for path, file_class, kind, file_id, entry in new_tree.list_files():
60
for path, file_class, kind, file_id in new_tree.list_files():
65
61
if file_class in ('?', 'I'):
66
62
non_source.append(path)
67
delta = new_tree.changes_from(old_tree, want_unchanged=False)
68
return not delta.has_changed(), non_source
70
def set_push_data(tree, location):
71
tree.branch.control_files.put_utf8("x-push-data", "%s\n" % location)
73
def get_push_data(tree):
75
>>> tree = temp_tree()
76
>>> get_push_data(tree) is None
63
delta = compare_trees(old_tree, new_tree, want_unchanged=False)
64
if len(delta.added) > 0 or len(delta.removed) > 0 or \
65
len(delta.modified) > 0:
66
return False, non_source
67
return True, non_source
69
def set_pull_data(br, location, rev_id):
70
pull_file = file (br.controlfilename("x-pull-data"), "wb")
71
pull_file.write("%s\n%s\n" % (location, rev_id))
73
def get_pull_data(br):
75
>>> br = temp_branch()
78
>>> set_pull_data(br, 'http://somewhere', '888-777')
80
('http://somewhere', '888-777')
83
filename = br.controlfilename("x-pull-data")
84
if not os.path.exists(filename):
86
pull_file = file (filename, "rb")
87
location, rev_id = [f.rstrip('\n') for f in pull_file]
88
return location, rev_id
90
def set_push_data(br, location):
91
push_file = file (br.controlfilename("x-push-data"), "wb")
92
push_file.write("%s\n" % location)
94
def get_push_data(br):
96
>>> br = temp_branch()
97
>>> get_push_data(br) is None
78
>>> set_push_data(tree, 'http://somewhere')
79
>>> get_push_data(tree)
99
>>> set_push_data(br, 'http://somewhere')
100
>>> get_push_data(br)
84
location = tree.branch.control_files.get_utf8('x-push-data').read()
104
filename = br.controlfilename("x-push-data")
105
if not os.path.exists(filename):
87
return location.rstrip('\n')
107
push_file = file (filename, "rb")
108
(location,) = [f.rstrip('\n') for f in push_file]
90
112
>>> shell_escape('hello')
115
137
def rsync(source, target, ssh=False, excludes=(), silent=False,
116
138
rsync_name="rsync"):
118
>>> new_dir = tempfile.mkdtemp()
119
>>> old_dir = os.getcwd()
120
>>> os.chdir(new_dir)
121
140
>>> rsync("a", "b", silent=True)
122
141
Traceback (most recent call last):
123
RsyncNoFile: No such file...
124
>>> rsync(new_dir + "/a", new_dir + "/b", excludes=("*.py",), silent=True)
142
RsyncNoFile: No such file a
143
>>> rsync("a", "b", excludes=("*.py",), silent=True)
125
144
Traceback (most recent call last):
126
RsyncNoFile: No such file...
127
>>> rsync(new_dir + "/a", new_dir + "/b", excludes=("*.py",), silent=True, rsync_name="rsyncc")
145
RsyncNoFile: No such file a
146
>>> rsync("a", "b", excludes=("*.py",), silent=True, rsync_name="rsyncc")
128
147
Traceback (most recent call last):
129
148
NoRsync: rsyncc not found.
130
>>> os.chdir(old_dir)
131
>>> os.rmdir(new_dir)
133
150
cmd = [rsync_name, "-av", "--delete"]
189
206
raise RsyncUnknownStatus(proc.returncode)
190
207
return [l.split(' ')[-1].rstrip('\n') for l in result.splitlines(True)]
192
exclusions = ('.bzr/x-push-data', '.bzr/branch/x-push/data', '.bzr/parent',
193
'.bzr/branch/parent', '.bzr/x-pull-data', '.bzr/x-pull',
194
'.bzr/pull', '.bzr/stat-cache', '.bzr/x-rsync-data',
195
'.bzr/basis-inventory', '.bzr/inventory.backup.weave')
209
exclusions = ('.bzr/x-push-data', '.bzr/parent', '.bzr/x-pull-data',
210
'.bzr/x-pull', '.bzr/pull', '.bzr/stat-cache',
198
214
def read_revision_history(fname):
239
251
except RsyncNoFile:
242
def rspush(tree, location=None, overwrite=False, working_tree=True):
243
push_location = get_push_data(tree)
254
def push(cur_branch, location=None, overwrite=False):
255
push_location = get_push_data(cur_branch)
244
256
if location is not None:
245
257
if not location.endswith('/'):
247
259
push_location = location
249
261
if push_location is None:
250
raise BzrCommandError("No rspush location known or specified.")
252
if (push_location.find('::') != -1):
257
if (push_location.find('://') != -1 or
258
push_location.find(':') == -1):
259
raise BzrCommandError("Invalid rsync path %r." % push_location)
262
clean, non_source = is_clean(tree)
264
print """Error: This tree has uncommitted changes or unknown (?) files.
265
Use "bzr status" to list them."""
267
final_exclusions = non_source[:]
270
final_exclusions = []
271
for path, status, kind, file_id, entry in wt.list_files():
272
final_exclusions.append(path)
274
final_exclusions.extend(exclusions)
262
print "No push location saved. Please specify one on the command line."
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)
275
271
if not overwrite:
277
if not history_subset(push_location, tree.branch):
273
if not history_subset(push_location, cur_branch):
278
274
raise bzrlib.errors.BzrCommandError("Local branch is not a"
279
275
" newer version of remote"
288
284
" specified location. Please ensure that"
289
285
' "%s" is of the form "machine:/path".' % push_location)
290
286
print "Pushing to %s" % push_location
291
rsync(tree.basedir+'/', push_location, ssh=usessh,
292
excludes=final_exclusions)
294
set_push_data(tree, push_location)
297
def short_committer(committer):
298
new_committer = re.sub('<.*>', '', committer).strip(' ')
299
if len(new_committer) < 2:
305
"""Screen-scrape Apache listings"""
306
apache_dir = '<img border="0" src="/icons/folder.gif" alt="[dir]">'\
309
expr = re.compile('<a[^>]*href="([^>]*)"[^>]*>', flags=re.I)
311
match = expr.search(line)
315
if url.startswith('http://') or url.startswith('/') or '../' in url:
319
yield url.rstrip('/')
322
def iter_branches(t, lister=None):
323
"""Iterate through all the branches under a transport"""
324
for bzrdir in iter_bzrdirs(t, lister):
326
branch = bzrdir.open_branch()
327
if branch.bzrdir is bzrdir:
329
except (NotBranchError, UnsupportedFormatError):
333
def iter_branch_tree(t, lister=None):
334
for bzrdir in iter_bzrdirs(t, lister):
336
wt = bzrdir.open_workingtree()
338
except NoWorkingTree, UnsupportedFormatError:
340
branch = bzrdir.open_branch()
341
if branch.bzrdir is bzrdir:
343
except (NotBranchError, UnsupportedFormatError):
347
def iter_bzrdirs(t, lister=None):
350
return t.list_dir('.')
352
bzrdir = bzrdir_from_transport(t)
354
except (NotBranchError, UnsupportedFormatError, TransportError,
358
for directory in lister(t):
359
if directory == ".bzr":
362
subt = t.clone(directory)
363
except UnicodeDecodeError:
365
for bzrdir in iter_bzrdirs(subt, lister):
367
except (NoSuchFile, PermissionDenied, TransportError):
371
def bzrdir_from_transport(t):
372
"""Open a bzrdir from a transport (not a location)"""
373
format = BzrDirFormat.find_format(t)
374
BzrDir._check_supported(format, False)
375
return format.open(t)
287
rsync(cur_branch.base+'/', push_location, ssh=True, excludes=non_source)
289
set_push_data(cur_branch, push_location)