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
30
dirname = tempfile.mkdtemp("temp-branch")
35
return BzrDir.create_standalone_workingtree(dirname)
38
shutil.rmtree(tree.basedir)
40
def is_clean(cur_tree):
31
return bzrlib.branch.Branch.initialize(dirname)
34
shutil.rmtree(br.base)
36
def is_clean(cur_branch):
42
38
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
>>> bzrlib.add.smart_add_tree(br.working_tree(), [br.base])
51
>>> br.working_tree().commit("added file")
44
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()
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)
60
for path, file_class, kind, file_id, entry in new_tree.list_files():
61
if file_class in ('?', 'I'):
62
non_source.append(path)
63
delta = compare_trees(old_tree, new_tree, want_unchanged=False)
55
64
return not delta.has_changed(), non_source
57
def set_push_data(tree, location):
58
tree.branch.control_files.put_utf8("x-push-data", "%s\n" % location)
60
def get_push_data(tree):
62
>>> tree = temp_tree()
63
>>> get_push_data(tree) is None
66
def set_pull_data(br, location, rev_id):
67
pull_file = file (br.controlfilename("x-pull-data"), "wb")
68
pull_file.write("%s\n%s\n" % (location, rev_id))
70
def get_pull_data(br):
72
>>> br = temp_branch()
75
>>> set_pull_data(br, 'http://somewhere', '888-777')
77
('http://somewhere', '888-777')
80
filename = br.controlfilename("x-pull-data")
81
if not os.path.exists(filename):
83
pull_file = file (filename, "rb")
84
location, rev_id = [f.rstrip('\n') for f in pull_file]
85
return location, rev_id
87
def set_push_data(br, location):
88
push_file = file (br.controlfilename("x-push-data"), "wb")
89
push_file.write("%s\n" % location)
91
def get_push_data(br):
93
>>> br = temp_branch()
94
>>> get_push_data(br) is None
65
>>> set_push_data(tree, 'http://somewhere')
66
>>> get_push_data(tree)
96
>>> set_push_data(br, 'http://somewhere')
71
location = tree.branch.control_files.get_utf8('x-push-data').read()
101
filename = br.controlfilename("x-push-data")
102
if not os.path.exists(filename):
74
return location.rstrip('\n')
104
push_file = file (filename, "rb")
105
(location,) = [f.rstrip('\n') for f in push_file]
77
109
>>> shell_escape('hello')
99
131
def __init__(self, rsync_name):
100
132
Exception.__init__(self, "%s not found." % rsync_name)
102
def rsync(source, target, ssh=False, excludes=(), silent=False,
134
def rsync(source, target, ssh=False, excludes=(), silent=False,
103
135
rsync_name="rsync"):
105
>>> new_dir = tempfile.mkdtemp()
106
>>> old_dir = os.getcwd()
107
>>> os.chdir(new_dir)
108
137
>>> rsync("a", "b", silent=True)
109
138
Traceback (most recent call last):
110
RsyncNoFile: No such file...
111
>>> rsync(new_dir + "/a", new_dir + "/b", excludes=("*.py",), silent=True)
139
RsyncNoFile: No such file a
140
>>> rsync("a", "b", excludes=("*.py",), silent=True)
112
141
Traceback (most recent call last):
113
RsyncNoFile: No such file...
114
>>> rsync(new_dir + "/a", new_dir + "/b", excludes=("*.py",), silent=True, rsync_name="rsyncc")
142
RsyncNoFile: No such file a
143
>>> rsync("a", "b", excludes=("*.py",), silent=True, rsync_name="rsyncc")
115
144
Traceback (most recent call last):
116
145
NoRsync: rsyncc not found.
117
>>> os.chdir(old_dir)
118
>>> os.rmdir(new_dir)
120
147
cmd = [rsync_name, "-av", "--delete"]
176
203
raise RsyncUnknownStatus(proc.returncode)
177
204
return [l.split(' ')[-1].rstrip('\n') for l in result.splitlines(True)]
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')
206
exclusions = ('.bzr/x-push-data', '.bzr/parent', '.bzr/x-pull-data',
207
'.bzr/x-pull', '.bzr/pull', '.bzr/stat-cache',
185
211
def read_revision_history(fname):
226
248
except RsyncNoFile:
229
def rspush(tree, location=None, overwrite=False, working_tree=True):
230
push_location = get_push_data(tree)
251
def push(cur_branch, location=None, overwrite=False):
252
push_location = get_push_data(cur_branch)
231
253
if location is not None:
232
254
if not location.endswith('/'):
234
256
push_location = location
236
258
if push_location is None:
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."""
254
final_exclusions = non_source[:]
257
final_exclusions = []
258
for path, status, kind, file_id, entry in wt.list_files():
259
final_exclusions.append(path)
261
final_exclusions.extend(exclusions)
259
raise bzrlib.errors.MustUseDecorated
261
if push_location.find('://') != -1:
262
raise bzrlib.errors.MustUseDecorated
264
if push_location.find(':') == -1:
265
raise bzrlib.errors.MustUseDecorated
267
clean, non_source = is_clean(cur_branch)
269
print """Error: This tree has uncommitted changes or unknown (?) files.
270
Use "bzr status" to list them."""
272
non_source.extend(exclusions)
262
273
if not overwrite:
264
if not history_subset(push_location, tree.branch):
275
if not history_subset(push_location, cur_branch):
265
276
raise bzrlib.errors.BzrCommandError("Local branch is not a"
266
277
" newer version of remote"
275
286
" specified location. Please ensure that"
276
287
' "%s" is of the form "machine:/path".' % push_location)
277
288
print "Pushing to %s" % push_location
278
rsync(tree.basedir+'/', push_location, ssh=usessh,
279
excludes=final_exclusions)
281
set_push_data(tree, push_location)
289
rsync(cur_branch.base+'/', push_location, ssh=True, excludes=non_source)
291
set_push_data(cur_branch, push_location)
284
293
def short_committer(committer):
285
294
new_committer = re.sub('<.*>', '', committer).strip(' ')
288
297
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)
367
302
result = doctest.testmod()