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
39
43
>>> import bzrlib.add
40
>>> br = temp_branch()
44
>>> tree = temp_tree()
43
>>> fooname = os.path.join(br.base, "foo")
47
>>> fooname = os.path.join(tree.basedir, "foo")
44
48
>>> file(fooname, "wb").write("bar")
47
>>> br.working_tree().add(["foo"])
51
>>> bzrlib.add.smart_add_tree(tree, [tree.basedir])
50
>>> br.working_tree().commit("added file")
55
>>> tree.commit("added file", rev_id='commit-id')
55
from bzrlib.diff import compare_trees
56
old_tree = cur_branch.basis_tree()
57
new_tree = cur_branch.working_tree()
61
old_tree = cur_tree.basis_tree()
59
64
for path, file_class, kind, file_id, entry in new_tree.list_files():
60
65
if file_class in ('?', 'I'):
61
66
non_source.append(path)
62
delta = compare_trees(old_tree, new_tree, want_unchanged=False)
67
delta = new_tree.changes_from(old_tree, want_unchanged=False)
63
68
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)
70
def set_push_data(tree, location):
71
tree.branch.control_files.put_utf8("x-push-data", "%s\n" % location)
69
def get_push_data(br):
73
def get_push_data(tree):
71
>>> br = temp_branch()
72
>>> get_push_data(br) is None
75
>>> tree = temp_tree()
76
>>> get_push_data(tree) is None
74
>>> set_push_data(br, 'http://somewhere')
78
>>> set_push_data(tree, 'http://somewhere')
79
>>> get_push_data(tree)
79
filename = br.control_files.controlfilename("x-push-data")
80
if not os.path.exists(filename):
84
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]
87
return location.rstrip('\n')
87
90
>>> shell_escape('hello')
112
115
def rsync(source, target, ssh=False, excludes=(), silent=False,
113
116
rsync_name="rsync"):
118
>>> new_dir = tempfile.mkdtemp()
119
>>> old_dir = os.getcwd()
120
>>> os.chdir(new_dir)
115
121
>>> rsync("a", "b", silent=True)
116
122
Traceback (most recent call last):
117
RsyncNoFile: No such file a
118
>>> rsync("a", "b", excludes=("*.py",), silent=True)
123
RsyncNoFile: No such file...
124
>>> rsync(new_dir + "/a", new_dir + "/b", excludes=("*.py",), silent=True)
119
125
Traceback (most recent call last):
120
RsyncNoFile: No such file a
121
>>> rsync("a", "b", excludes=("*.py",), silent=True, rsync_name="rsyncc")
126
RsyncNoFile: No such file...
127
>>> rsync(new_dir + "/a", new_dir + "/b", excludes=("*.py",), silent=True, rsync_name="rsyncc")
122
128
Traceback (most recent call last):
123
129
NoRsync: rsyncc not found.
130
>>> os.chdir(old_dir)
131
>>> os.rmdir(new_dir)
125
133
cmd = [rsync_name, "-av", "--delete"]
181
189
raise RsyncUnknownStatus(proc.returncode)
182
190
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',
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')
189
198
def read_revision_history(fname):
202
211
tempdir = tempfile.mkdtemp('push')
204
213
history_fname = os.path.join(tempdir, 'revision-history')
205
cmd = rsync(location+'.bzr/revision-history', history_fname,
215
cmd = rsync(location+'.bzr/revision-history', history_fname,
218
cmd = rsync(location+'.bzr/branch/revision-history', history_fname,
207
220
history = read_revision_history(history_fname)
209
222
shutil.rmtree(tempdir)
226
239
except RsyncNoFile:
229
def push(cur_branch, location=None, overwrite=False, working_tree=True):
230
push_location = get_push_data(cur_branch)
242
def rspush(tree, location=None, overwrite=False, working_tree=True):
243
push_location = get_push_data(tree)
231
244
if location is not None:
232
245
if not location.endswith('/'):
234
247
push_location = location
236
249
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."""
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."""
251
267
final_exclusions = non_source[:]
253
wt = cur_branch.working_tree()
254
270
final_exclusions = []
255
271
for path, status, kind, file_id, entry in wt.list_files():
256
272
final_exclusions.append(path)
272
288
" specified location. Please ensure that"
273
289
' "%s" is of the form "machine:/path".' % push_location)
274
290
print "Pushing to %s" % push_location
275
rsync(cur_branch.base+'/', push_location, ssh=True,
291
rsync(tree.basedir+'/', push_location, ssh=usessh,
276
292
excludes=final_exclusions)
278
set_push_data(cur_branch, push_location)
294
set_push_data(tree, push_location)
280
297
def short_committer(committer):
281
298
new_committer = re.sub('<.*>', '', committer).strip(' ')
284
301
return new_committer
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)
289
380
result = doctest.testmod()