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
55
from bzrlib.diff import compare_trees
62
old_tree = cur_tree.basis_tree()
56
old_tree = cur_branch.basis_tree()
57
new_tree = cur_branch.working_tree()
65
59
for path, file_class, kind, file_id, entry in new_tree.list_files():
66
60
if file_class in ('?', 'I'):
68
62
delta = compare_trees(old_tree, new_tree, want_unchanged=False)
69
63
return not delta.has_changed(), non_source
71
def set_push_data(tree, location):
72
tree.branch.control_files.put_utf8("x-push-data", "%s\n" % location)
74
def get_push_data(tree):
76
>>> tree = temp_tree()
77
>>> get_push_data(tree) is None
65
def set_pull_data(br, location, rev_id):
66
pull_file = file (br.controlfilename("x-pull-data"), "wb")
67
pull_file.write("%s\n%s\n" % (location, rev_id))
69
def get_pull_data(br):
71
>>> br = temp_branch()
74
>>> set_pull_data(br, 'http://somewhere', '888-777')
76
('http://somewhere', '888-777')
79
filename = br.controlfilename("x-pull-data")
80
if not os.path.exists(filename):
82
pull_file = file (filename, "rb")
83
location, rev_id = [f.rstrip('\n') for f in pull_file]
84
return location, rev_id
86
def set_push_data(br, location):
87
push_file = file (br.controlfilename("x-push-data"), "wb")
88
push_file.write("%s\n" % location)
90
def get_push_data(br):
92
>>> br = temp_branch()
93
>>> get_push_data(br) is None
79
>>> set_push_data(tree, 'http://somewhere')
80
>>> get_push_data(tree)
95
>>> set_push_data(br, 'http://somewhere')
85
location = tree.branch.control_files.get_utf8('x-push-data').read()
100
filename = br.controlfilename("x-push-data")
101
if not os.path.exists(filename):
88
return location.rstrip('\n')
103
push_file = file (filename, "rb")
104
(location,) = [f.rstrip('\n') for f in push_file]
91
108
>>> shell_escape('hello')
116
133
def rsync(source, target, ssh=False, excludes=(), silent=False,
117
134
rsync_name="rsync"):
119
>>> new_dir = tempfile.mkdtemp()
120
>>> old_dir = os.getcwd()
121
>>> os.chdir(new_dir)
122
136
>>> rsync("a", "b", silent=True)
123
137
Traceback (most recent call last):
124
RsyncNoFile: No such file...
125
>>> rsync(new_dir + "/a", new_dir + "/b", excludes=("*.py",), silent=True)
138
RsyncNoFile: No such file a
139
>>> rsync("a", "b", excludes=("*.py",), silent=True)
126
140
Traceback (most recent call last):
127
RsyncNoFile: No such file...
128
>>> rsync(new_dir + "/a", new_dir + "/b", excludes=("*.py",), silent=True, rsync_name="rsyncc")
141
RsyncNoFile: No such file a
142
>>> rsync("a", "b", excludes=("*.py",), silent=True, rsync_name="rsyncc")
129
143
Traceback (most recent call last):
130
144
NoRsync: rsyncc not found.
131
>>> os.chdir(old_dir)
132
>>> os.rmdir(new_dir)
134
146
cmd = [rsync_name, "-av", "--delete"]
190
202
raise RsyncUnknownStatus(proc.returncode)
191
203
return [l.split(' ')[-1].rstrip('\n') for l in result.splitlines(True)]
193
exclusions = ('.bzr/x-push-data', '.bzr/branch/x-push/data', '.bzr/parent',
194
'.bzr/branch/parent', '.bzr/x-pull-data', '.bzr/x-pull',
195
'.bzr/pull', '.bzr/stat-cache', '.bzr/x-rsync-data',
196
'.bzr/basis-inventory', '.bzr/inventory.backup.weave')
205
exclusions = ('.bzr/x-push-data', '.bzr/parent', '.bzr/x-pull-data',
206
'.bzr/x-pull', '.bzr/pull', '.bzr/stat-cache',
199
210
def read_revision_history(fname):
212
223
tempdir = tempfile.mkdtemp('push')
214
225
history_fname = os.path.join(tempdir, 'revision-history')
216
cmd = rsync(location+'.bzr/revision-history', history_fname,
219
cmd = rsync(location+'.bzr/branch/revision-history', history_fname,
226
cmd = rsync(location+'.bzr/revision-history', history_fname,
221
228
history = read_revision_history(history_fname)
223
230
shutil.rmtree(tempdir)
240
247
except RsyncNoFile:
243
def rspush(tree, location=None, overwrite=False, working_tree=True):
244
push_location = get_push_data(tree)
250
def push(cur_branch, location=None, overwrite=False):
251
push_location = get_push_data(cur_branch)
245
252
if location is not None:
246
253
if not location.endswith('/'):
248
255
push_location = location
250
257
if push_location is None:
251
raise BzrCommandError("No rspush location known or specified.")
253
if (push_location.find('://') != -1 or
254
push_location.find(':') == -1):
255
raise BzrCommandError("Invalid rsync path %r." % push_location)
258
clean, non_source = is_clean(tree)
260
print """Error: This tree has uncommitted changes or unknown (?) files.
261
Use "bzr status" to list them."""
263
final_exclusions = non_source[:]
266
final_exclusions = []
267
for path, status, kind, file_id, entry in wt.list_files():
268
final_exclusions.append(path)
270
final_exclusions.extend(exclusions)
258
raise bzrlib.errors.MustUseDecorated
260
if push_location.find('://') != -1:
261
raise bzrlib.errors.MustUseDecorated
263
if push_location.find(':') == -1:
264
raise bzrlib.errors.MustUseDecorated
266
clean, non_source = is_clean(cur_branch)
268
print """Error: This tree has uncommitted changes or unknown (?) files.
269
Use "bzr status" to list them."""
271
non_source.extend(exclusions)
271
272
if not overwrite:
273
if not history_subset(push_location, tree.branch):
274
if not history_subset(push_location, cur_branch):
274
275
raise bzrlib.errors.BzrCommandError("Local branch is not a"
275
276
" newer version of remote"
284
285
" specified location. Please ensure that"
285
286
' "%s" is of the form "machine:/path".' % push_location)
286
287
print "Pushing to %s" % push_location
287
rsync(tree.basedir+'/', push_location, ssh=True,
288
excludes=final_exclusions)
290
set_push_data(tree, push_location)
293
def short_committer(committer):
294
new_committer = re.sub('<.*>', '', committer).strip(' ')
295
if len(new_committer) < 2:
301
"""Screen-scrape Apache listings"""
302
apache_dir = '<img border="0" src="/icons/folder.gif" alt="[dir]">'\
305
expr = re.compile('<a[^>]*href="([^>]*)"[^>]*>', flags=re.I)
307
match = expr.search(line)
311
if url.startswith('http://') or url.startswith('/') or '../' in url:
315
yield url.rstrip('/')
318
def iter_branches(t, lister=None):
319
"""Iterate through all the branches under a transport"""
320
for bzrdir in iter_bzrdirs(t, lister):
322
branch = bzrdir.open_branch()
323
if branch.bzrdir is bzrdir:
325
except (NotBranchError, UnsupportedFormatError):
329
def iter_branch_tree(t, lister=None):
330
for bzrdir in iter_bzrdirs(t, lister):
332
wt = bzrdir.open_workingtree()
334
except NoWorkingTree, UnsupportedFormatError:
336
branch = bzrdir.open_branch()
337
if branch.bzrdir is bzrdir:
339
except (NotBranchError, UnsupportedFormatError):
343
def iter_bzrdirs(t, lister=None):
346
return t.list_dir('.')
348
bzrdir = bzrdir_from_transport(t)
350
except (NotBranchError, UnsupportedFormatError, TransportError,
354
for directory in lister(t):
355
if directory == ".bzr":
358
subt = t.clone(directory)
359
except UnicodeDecodeError:
361
for bzrdir in iter_bzrdirs(subt, lister):
363
except (NoSuchFile, PermissionDenied, TransportError):
367
def bzrdir_from_transport(t):
368
"""Open a bzrdir from a transport (not a location)"""
369
format = BzrDirFormat.find_format(t)
370
BzrDir._check_supported(format, False)
371
return format.open(t)
288
rsync(cur_branch.base+'/', push_location, ssh=True, excludes=non_source)
290
set_push_data(cur_branch, push_location)