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")
55
60
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
67
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")
68
return not delta.has_changed(), non_source
70
def set_push_data(tree, location):
71
push_file = file (tree.branch.control_files.controlfilename("x-push-data"), "wb")
91
72
push_file.write("%s\n" % location)
93
def get_push_data(br):
74
def get_push_data(tree):
95
>>> br = temp_branch()
96
>>> get_push_data(br) is None
76
>>> tree = temp_tree()
77
>>> get_push_data(tree) is None
98
>>> set_push_data(br, 'http://somewhere')
79
>>> set_push_data(tree, 'http://somewhere')
80
>>> get_push_data(tree)
100
81
'http://somewhere'
103
filename = br.controlfilename("x-push-data")
84
filename = tree.branch.control_files.controlfilename("x-push-data")
104
85
if not os.path.exists(filename):
106
87
push_file = file (filename, "rb")
136
117
def rsync(source, target, ssh=False, excludes=(), silent=False,
137
118
rsync_name="rsync"):
120
>>> new_dir = tempfile.mkdtemp()
121
>>> old_dir = os.getcwd()
122
>>> os.chdir(new_dir)
139
123
>>> rsync("a", "b", silent=True)
140
124
Traceback (most recent call last):
141
RsyncNoFile: No such file a
142
>>> rsync("a", "b", excludes=("*.py",), silent=True)
125
RsyncNoFile: No such file...
126
>>> rsync(new_dir + "/a", new_dir + "/b", excludes=("*.py",), silent=True)
143
127
Traceback (most recent call last):
144
RsyncNoFile: No such file a
145
>>> rsync("a", "b", excludes=("*.py",), silent=True, rsync_name="rsyncc")
128
RsyncNoFile: No such file...
129
>>> rsync(new_dir + "/a", new_dir + "/b", excludes=("*.py",), silent=True, rsync_name="rsyncc")
146
130
Traceback (most recent call last):
147
131
NoRsync: rsyncc not found.
132
>>> os.chdir(old_dir)
133
>>> os.rmdir(new_dir)
149
135
cmd = [rsync_name, "-av", "--delete"]
205
191
raise RsyncUnknownStatus(proc.returncode)
206
192
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',
194
exclusions = ('.bzr/x-push-data', '.bzr/branch/x-push/data', '.bzr/parent',
195
'.bzr/branch/parent', '.bzr/x-pull-data', '.bzr/x-pull',
196
'.bzr/pull', '.bzr/stat-cache', '.bzr/x-rsync-data',
197
'.bzr/basis-inventory', '.bzr/inventory.backup.weave')
213
200
def read_revision_history(fname):
250
241
except RsyncNoFile:
253
def push(cur_branch, location=None, overwrite=False):
254
push_location = get_push_data(cur_branch)
244
def push(tree, location=None, overwrite=False, working_tree=True):
245
push_location = get_push_data(tree)
255
246
if location is not None:
256
247
if not location.endswith('/'):
258
249
push_location = location
260
251
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)
252
if tree.branch.get_push_location() is None:
253
raise BzrCommandError("No push location known or specified.")
255
raise bzrlib.errors.MustUseDecorated
257
if push_location.find('://') != -1:
258
raise bzrlib.errors.MustUseDecorated
260
if push_location.find(':') == -1:
261
raise bzrlib.errors.MustUseDecorated
264
clean, non_source = is_clean(tree)
266
print """Error: This tree has uncommitted changes or unknown (?) files.
267
Use "bzr status" to list them."""
269
final_exclusions = non_source[:]
272
final_exclusions = []
273
for path, status, kind, file_id, entry in wt.list_files():
274
final_exclusions.append(path)
276
final_exclusions.extend(exclusions)
270
277
if not overwrite:
272
if not history_subset(push_location, cur_branch):
279
if not history_subset(push_location, tree.branch):
273
280
raise bzrlib.errors.BzrCommandError("Local branch is not a"
274
281
" newer version of remote"
283
290
" specified location. Please ensure that"
284
291
' "%s" is of the form "machine:/path".' % push_location)
285
292
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)
293
rsync(tree.basedir+'/', push_location, ssh=True,
294
excludes=final_exclusions)
296
set_push_data(tree, push_location)
299
def short_committer(committer):
300
new_committer = re.sub('<.*>', '', committer).strip(' ')
301
if len(new_committer) < 2:
307
"""Screen-scrape Apache listings"""
308
apache_dir = '<img border="0" src="/icons/folder.gif" alt="[dir]">'\
311
expr = re.compile('<a[^>]*href="([^>]*)"[^>]*>', flags=re.I)
313
match = expr.search(line)
317
if url.startswith('http://') or url.startswith('/') or '../' in url:
321
yield url.rstrip('/')
324
def iter_branches(t, lister=None):
325
"""Iterate through all the branches under a transport"""
326
for bzrdir in iter_bzrdirs(t, lister):
328
branch = bzrdir.open_branch()
329
if branch.bzrdir is bzrdir:
331
except (NotBranchError, UnsupportedFormatError):
335
def iter_branch_tree(t, lister=None):
336
for bzrdir in iter_bzrdirs(t, lister):
338
wt = bzrdir.open_workingtree()
340
except NoWorkingTree, UnsupportedFormatError:
342
branch = bzrdir.open_branch()
343
if branch.bzrdir is bzrdir:
345
except (NotBranchError, UnsupportedFormatError):
349
def iter_bzrdirs(t, lister=None):
352
return t.list_dir('.')
354
bzrdir = bzrdir_from_transport(t)
356
except (NotBranchError, UnsupportedFormatError, TransportError,
360
for directory in lister(t):
361
if directory == ".bzr":
364
subt = t.clone(directory)
365
except UnicodeDecodeError:
367
for bzrdir in iter_bzrdirs(subt, lister):
369
except (NoSuchFile, PermissionDenied, TransportError):
373
def bzrdir_from_transport(t):
374
"""Open a bzrdir from a transport (not a location)"""
375
format = BzrDirFormat.find_format(t)
376
BzrDir._check_supported(format, False)
377
return format.open(t)