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
39
>>> br = temp_branch()
42
>>> fooname = os.path.join(br.base, "foo")
43
>>> file(fooname, "wb").write("bar")
46
>>> bzrlib.add.smart_add_branch(br, [br.base])
50
>>> br.commit("added file")
44
old_tree = cur_tree.basis_tree()
55
from bzrlib.diff import compare_trees
56
old_tree = cur_branch.basis_tree()
57
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)
55
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
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)
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
65
>>> set_push_data(tree, 'http://somewhere')
66
>>> get_push_data(tree)
98
>>> set_push_data(br, 'http://somewhere')
71
location = tree.branch.control_files.get_utf8('x-push-data').read()
103
filename = br.controlfilename("x-push-data")
104
if not os.path.exists(filename):
74
return location.rstrip('\n')
106
push_file = file (filename, "rb")
107
(location,) = [f.rstrip('\n') for f in push_file]
77
111
>>> shell_escape('hello')
99
133
def __init__(self, rsync_name):
100
134
Exception.__init__(self, "%s not found." % rsync_name)
102
def rsync(source, target, ssh=False, excludes=(), silent=False,
136
def rsync(source, target, ssh=False, excludes=(), silent=False,
103
137
rsync_name="rsync"):
105
>>> new_dir = tempfile.mkdtemp()
106
>>> old_dir = os.getcwd()
107
>>> os.chdir(new_dir)
108
139
>>> rsync("a", "b", silent=True)
109
140
Traceback (most recent call last):
110
RsyncNoFile: No such file...
111
>>> rsync(new_dir + "/a", new_dir + "/b", excludes=("*.py",), silent=True)
141
RsyncNoFile: No such file a
142
>>> rsync("a", "b", excludes=("*.py",), silent=True)
112
143
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")
144
RsyncNoFile: No such file a
145
>>> rsync("a", "b", excludes=("*.py",), silent=True, rsync_name="rsyncc")
115
146
Traceback (most recent call last):
116
147
NoRsync: rsyncc not found.
117
>>> os.chdir(old_dir)
118
>>> os.rmdir(new_dir)
120
149
cmd = [rsync_name, "-av", "--delete"]
176
205
raise RsyncUnknownStatus(proc.returncode)
177
206
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')
208
exclusions = ('.bzr/x-push-data', '.bzr/parent', '.bzr/x-pull-data',
209
'.bzr/x-pull', '.bzr/pull', '.bzr/stat-cache',
185
213
def read_revision_history(fname):
226
250
except RsyncNoFile:
229
def rspush(tree, location=None, overwrite=False, working_tree=True):
230
push_location = get_push_data(tree)
253
def push(cur_branch, location=None, overwrite=False):
254
push_location = get_push_data(cur_branch)
231
255
if location is not None:
232
256
if not location.endswith('/'):
234
258
push_location = location
236
260
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)
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)
262
270
if not overwrite:
264
if not history_subset(push_location, tree.branch):
272
if not history_subset(push_location, cur_branch):
265
273
raise bzrlib.errors.BzrCommandError("Local branch is not a"
266
274
" newer version of remote"
275
283
" specified location. Please ensure that"
276
284
' "%s" is of the form "machine:/path".' % push_location)
277
285
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)
284
def short_committer(committer):
285
new_committer = re.sub('<.*>', '', committer).strip(' ')
286
if len(new_committer) < 2:
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)
286
rsync(cur_branch.base+'/', push_location, ssh=True, excludes=non_source)
288
set_push_data(cur_branch, push_location)