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
29
34
dirname = tempfile.mkdtemp("temp-branch")
30
return bzrlib.branch.Branch.initialize(dirname)
33
shutil.rmtree(br.base)
35
def is_clean(cur_branch):
35
return BzrDir.create_standalone_workingtree(dirname)
38
shutil.rmtree(tree.basedir)
40
def is_clean(cur_tree):
37
42
Return true if no files are modifed or unknown
38
43
>>> import bzrlib.add
39
>>> br = temp_branch()
44
>>> tree = temp_tree()
42
>>> fooname = os.path.join(br.base, "foo")
47
>>> fooname = os.path.join(tree.basedir, "foo")
43
48
>>> file(fooname, "wb").write("bar")
46
>>> bzrlib.add.smart_add_branch(br, [br.base])
51
>>> bzrlib.add.smart_add_tree(tree, [tree.basedir])
50
>>> br.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)
63
if len(delta.added) > 0 or len(delta.removed) > 0 or \
64
len(delta.modified) > 0:
65
return False, non_source
66
return True, non_source
68
def set_pull_data(br, location, rev_id):
69
pull_file = file (br.controlfilename("x-pull-data"), "wb")
70
pull_file.write("%s\n%s\n" % (location, rev_id))
72
def get_pull_data(br):
74
>>> br = temp_branch()
77
>>> set_pull_data(br, 'http://somewhere', '888-777')
79
('http://somewhere', '888-777')
82
filename = br.controlfilename("x-pull-data")
83
if not os.path.exists(filename):
85
pull_file = file (filename, "rb")
86
location, rev_id = [f.rstrip('\n') for f in pull_file]
87
return location, rev_id
89
def set_push_data(br, location):
90
push_file = file (br.controlfilename("x-push-data"), "wb")
91
push_file.write("%s\n" % location)
93
def get_push_data(br):
95
>>> br = temp_branch()
96
>>> get_push_data(br) is None
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
98
>>> set_push_data(br, 'http://somewhere')
78
>>> set_push_data(tree, 'http://somewhere')
79
>>> get_push_data(tree)
103
filename = br.controlfilename("x-push-data")
104
if not os.path.exists(filename):
84
location = tree.branch.control_files.get_utf8('x-push-data').read()
106
push_file = file (filename, "rb")
107
(location,) = [f.rstrip('\n') for f in push_file]
87
return location.rstrip('\n')
111
90
>>> shell_escape('hello')
136
115
def rsync(source, target, ssh=False, excludes=(), silent=False,
137
116
rsync_name="rsync"):
118
>>> new_dir = tempfile.mkdtemp()
119
>>> old_dir = os.getcwd()
120
>>> os.chdir(new_dir)
139
121
>>> rsync("a", "b", silent=True)
140
122
Traceback (most recent call last):
141
RsyncNoFile: No such file a
142
>>> rsync("a", "b", excludes=("*.py",), silent=True)
123
RsyncNoFile: No such file...
124
>>> rsync(new_dir + "/a", new_dir + "/b", excludes=("*.py",), silent=True)
143
125
Traceback (most recent call last):
144
RsyncNoFile: No such file a
145
>>> 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")
146
128
Traceback (most recent call last):
147
129
NoRsync: rsyncc not found.
130
>>> os.chdir(old_dir)
131
>>> os.rmdir(new_dir)
149
133
cmd = [rsync_name, "-av", "--delete"]
205
189
raise RsyncUnknownStatus(proc.returncode)
206
190
return [l.split(' ')[-1].rstrip('\n') for l in result.splitlines(True)]
208
exclusions = ('.bzr/x-push-data', '.bzr/parent', '.bzr/x-pull-data',
209
'.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')
213
198
def read_revision_history(fname):
250
239
except RsyncNoFile:
253
def push(cur_branch, location=None, overwrite=False):
254
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)
255
244
if location is not None:
256
245
if not location.endswith('/'):
258
247
push_location = location
260
249
if push_location is None:
261
print "No push location saved. Please specify one on the command line."
264
clean, non_source = is_clean(cur_branch)
266
print """Error: This tree has uncommitted changes or unknown (?) files.
267
Use "bzr status" to list them."""
269
non_source.extend(exclusions)
250
raise BzrCommandError("No rspush location known or specified.")
252
if (push_location.find('://') != -1 or
253
push_location.find(':') == -1):
254
raise BzrCommandError("Invalid rsync path %r." % push_location)
257
clean, non_source = is_clean(tree)
259
print """Error: This tree has uncommitted changes or unknown (?) files.
260
Use "bzr status" to list them."""
262
final_exclusions = non_source[:]
265
final_exclusions = []
266
for path, status, kind, file_id, entry in wt.list_files():
267
final_exclusions.append(path)
269
final_exclusions.extend(exclusions)
270
270
if not overwrite:
272
if not history_subset(push_location, cur_branch):
272
if not history_subset(push_location, tree.branch):
273
273
raise bzrlib.errors.BzrCommandError("Local branch is not a"
274
274
" newer version of remote"
283
283
" specified location. Please ensure that"
284
284
' "%s" is of the form "machine:/path".' % push_location)
285
285
print "Pushing to %s" % push_location
286
rsync(cur_branch.base+'/', push_location, ssh=True, excludes=non_source)
288
set_push_data(cur_branch, push_location)
286
rsync(tree.basedir+'/', push_location, ssh=True,
287
excludes=final_exclusions)
289
set_push_data(tree, push_location)
292
def short_committer(committer):
293
new_committer = re.sub('<.*>', '', committer).strip(' ')
294
if len(new_committer) < 2:
300
"""Screen-scrape Apache listings"""
301
apache_dir = '<img border="0" src="/icons/folder.gif" alt="[dir]">'\
304
expr = re.compile('<a[^>]*href="([^>]*)"[^>]*>', flags=re.I)
306
match = expr.search(line)
310
if url.startswith('http://') or url.startswith('/') or '../' in url:
314
yield url.rstrip('/')
317
def iter_branches(t, lister=None):
318
"""Iterate through all the branches under a transport"""
319
for bzrdir in iter_bzrdirs(t, lister):
321
branch = bzrdir.open_branch()
322
if branch.bzrdir is bzrdir:
324
except (NotBranchError, UnsupportedFormatError):
328
def iter_branch_tree(t, lister=None):
329
for bzrdir in iter_bzrdirs(t, lister):
331
wt = bzrdir.open_workingtree()
333
except NoWorkingTree, UnsupportedFormatError:
335
branch = bzrdir.open_branch()
336
if branch.bzrdir is bzrdir:
338
except (NotBranchError, UnsupportedFormatError):
342
def iter_bzrdirs(t, lister=None):
345
return t.list_dir('.')
347
bzrdir = bzrdir_from_transport(t)
349
except (NotBranchError, UnsupportedFormatError, TransportError,
353
for directory in lister(t):
354
if directory == ".bzr":
357
subt = t.clone(directory)
358
except UnicodeDecodeError:
360
for bzrdir in iter_bzrdirs(subt, lister):
362
except (NoSuchFile, PermissionDenied, TransportError):
366
def bzrdir_from_transport(t):
367
"""Open a bzrdir from a transport (not a location)"""
368
format = BzrDirFormat.find_format(t)
369
BzrDir._check_supported(format, False)
370
return format.open(t)