29
29
from bzrlib.revision import common_ancestor
30
30
from bzrlib.errors import (BzrError, BzrCheckError, BzrCommandError,
31
31
NotBranchError, DivergedBranches, NotConflicted,
32
NoSuchFile, NoWorkingTree, FileInWrongBranch)
32
NoSuchFile, NoWorkingTree, FileInWrongBranch)
33
33
from bzrlib.option import Option
34
34
from bzrlib.revisionspec import RevisionSpec
35
35
import bzrlib.trace
37
37
from bzrlib.workingtree import WorkingTree
40
def branch_files(file_list, default_branch='.'):
40
def tree_files(file_list, default_branch='.'):
42
return inner_branch_files(file_list, default_branch)
42
return internal_tree_files(file_list, default_branch)
43
43
except FileInWrongBranch, e:
44
44
raise BzrCommandError("%s is not in the same branch as %s" %
45
45
(e.path, file_list[0]))
47
def inner_branch_files(file_list, default_branch='.'):
47
def internal_tree_files(file_list, default_branch='.'):
49
49
Return a branch and list of branch-relative paths.
50
50
If supplied file_list is empty or None, the branch default will be used,
51
51
and returned file_list will match the original.
53
53
if file_list is None or len(file_list) == 0:
54
return Branch.open_containing(default_branch)[0], file_list
55
b = Branch.open_containing(file_list[0])[0]
57
# note that if this is a remote branch, we would want
58
# relpath against the transport. RBC 20051018
59
# Most branch ops can't meaningfully operate on files in remote branches;
60
# the above comment was in cmd_status. ADHB 20051026
61
tree = WorkingTree(b.base, b)
54
return WorkingTree.open_containing(default_branch)[0], file_list
55
tree = WorkingTree.open_containing(file_list[0])[0]
63
57
for filename in file_list:
65
59
new_list.append(tree.relpath(filename))
66
60
except NotBranchError:
67
raise FileInWrongBranch(b, filename)
61
raise FileInWrongBranch(tree.branch, filename)
71
65
# TODO: Make sure no commands unconditionally use the working directory as a
124
118
def run(self, all=False, show_ids=False, file_list=None, revision=None):
125
b, file_list = branch_files(file_list)
119
tree, file_list = tree_files(file_list)
127
121
from bzrlib.status import show_status
128
show_status(b, show_unchanged=all, show_ids=show_ids,
122
show_status(tree.branch, show_unchanged=all, show_ids=show_ids,
129
123
specific_files=file_list, revision=revision)
147
141
raise BzrCommandError('You can only supply one of revision_id or --revision')
148
142
if revision_id is None and revision is None:
149
143
raise BzrCommandError('You must supply either --revision or a revision_id')
150
b = Branch.open_containing('.')[0]
144
b = WorkingTree.open_containing('.')[0].branch
151
145
if revision_id is not None:
152
146
sys.stdout.write(b.get_revision_xml(revision_id))
153
147
elif revision is not None:
270
262
def run(self, revision=None, show_ids=False, kind=None):
271
263
if kind and kind not in ['file', 'directory', 'symlink']:
272
264
raise BzrCommandError('invalid kind specified')
273
b = Branch.open_containing('.')[0]
265
tree = WorkingTree.open_containing('.')[0]
274
266
if revision is None:
275
inv = b.working_tree().read_working_inventory()
267
inv = tree.read_working_inventory()
277
269
if len(revision) > 1:
278
270
raise BzrCommandError('bzr inventory --revision takes'
279
271
' exactly one revision identifier')
280
inv = b.get_revision_inventory(revision[0].in_history(b).rev_id)
272
inv = tree.branch.get_revision_inventory(
273
revision[0].in_history(tree.branch).rev_id)
282
275
for path, entry in inv.entries():
283
276
if kind and kind != entry.kind:
299
292
takes_args = ['source$', 'dest']
300
293
def run(self, source_list, dest):
301
b, source_list = branch_files(source_list)
294
tree, source_list = tree_files(source_list)
303
295
# TODO: glob expansion on windows?
304
tree = WorkingTree(b.base, b)
305
b.move(source_list, tree.relpath(dest))
296
tree.move(source_list, tree.relpath(dest))
308
299
class cmd_rename(Command):
322
313
takes_args = ['from_name', 'to_name']
324
315
def run(self, from_name, to_name):
325
b, (from_name, to_name) = branch_files((from_name, to_name))
326
b.rename_one(from_name, to_name)
316
tree, (from_name, to_name) = tree_files((from_name, to_name))
317
tree.rename_one(from_name, to_name)
329
320
class cmd_mv(Command):
343
334
def run(self, names_list):
344
335
if len(names_list) < 2:
345
336
raise BzrCommandError("missing file argument")
346
b, rel_names = branch_files(names_list)
337
tree, rel_names = tree_files(names_list)
348
339
if os.path.isdir(names_list[-1]):
349
340
# move into existing directory
350
for pair in b.move(rel_names[:-1], rel_names[-1]):
341
for pair in tree.move(rel_names[:-1], rel_names[-1]):
351
342
print "%s => %s" % pair
353
344
if len(names_list) != 2:
354
345
raise BzrCommandError('to mv multiple files the destination '
355
346
'must be a versioned directory')
356
b.rename_one(rel_names[0], rel_names[1])
347
tree.rename_one(rel_names[0], rel_names[1])
357
348
print "%s => %s" % (rel_names[0], rel_names[1])
382
373
from bzrlib.merge import merge
383
374
from shutil import rmtree
386
br_to = Branch.open_containing('.')[0]
387
stored_loc = br_to.get_parent()
376
# FIXME: too much stuff is in the command class
377
tree_to = WorkingTree.open_containing('.')[0]
378
stored_loc = tree_to.branch.get_parent()
388
379
if location is None:
389
380
if stored_loc is None:
390
381
raise BzrCommandError("No pull location known or specified.")
392
383
print "Using saved location: %s" % stored_loc
393
384
location = stored_loc
394
385
br_from = Branch.open(location)
386
br_to = tree_to.branch
396
388
old_rh = br_to.revision_history()
397
count = br_to.working_tree().pull(br_from, overwrite)
389
count = tree_to.pull(br_from, overwrite)
398
390
except DivergedBranches:
391
# FIXME: Just make DivergedBranches display the right message
399
393
raise BzrCommandError("These branches have diverged."
401
395
if br_to.get_parent() is None or remember:
402
396
br_to.set_parent(location)
403
note('%d revision(s) pulled.' % (count,))
397
note('%d revision(s) pulled.', count)
406
new_rh = br_to.revision_history()
399
new_rh = tree_to.branch.revision_history()
407
400
if old_rh != new_rh:
408
401
# Something changed
409
402
from bzrlib.log import show_changed_revisions
410
show_changed_revisions(br_to, old_rh, new_rh)
403
show_changed_revisions(tree_to.branch, old_rh, new_rh)
413
406
class cmd_push(Command):
442
435
def run(self, location=None, remember=False, overwrite=False,
443
436
create_prefix=False, verbose=False):
437
# FIXME: Way too big! Put this into a function called from the
445
440
from shutil import rmtree
446
441
from bzrlib.transport import get_transport
448
br_from = Branch.open_containing('.')[0]
449
stored_loc = br_from.get_push_location()
443
tree_from = WorkingTree.open_containing('.')[0]
444
br_from = tree_from.branch
445
stored_loc = tree_from.branch.get_push_location()
450
446
if location is None:
451
447
if stored_loc is None:
452
448
raise BzrCommandError("No push location known or specified.")
590
584
def run(self, dir='.'):
591
b = Branch.open_containing(dir)[0]
592
old_inv = b.basis_tree().inventory
593
new_inv = b.working_tree().read_working_inventory()
585
tree = WorkingTree.open_containing(dir)[0]
586
old_inv = tree.branch.basis_tree().inventory
587
new_inv = tree.read_working_inventory()
595
589
renames = list(bzrlib.tree.find_renames(old_inv, new_inv))
622
616
def run(self, file_list, verbose=False):
623
b, file_list = branch_files(file_list)
624
tree = b.working_tree()
617
tree, file_list = tree_files(file_list)
625
618
tree.remove(file_list, verbose=verbose)
636
629
takes_args = ['filename']
638
631
def run(self, filename):
639
b, relpath = Branch.open_containing(filename)
640
i = b.working_tree().inventory.path2id(relpath)
632
tree, relpath = WorkingTree.open_containing(filename)
633
i = tree.inventory.path2id(relpath)
642
635
raise BzrError("%r is not a versioned file" % filename)
743
739
def run(self, revision=None, file_list=None, diff_options=None):
744
740
from bzrlib.diff import show_diff
746
b, file_list = inner_branch_files(file_list)
742
tree, file_list = internal_tree_files(file_list)
748
745
except FileInWrongBranch:
749
746
if len(file_list) != 2:
752
749
b, file1 = Branch.open_containing(file_list[0])
753
750
b2, file2 = Branch.open_containing(file_list[1])
754
751
if file1 != "" or file2 != "":
752
# FIXME diff those two files. rbc 20051123
755
753
raise BzrCommandError("Files are in different branches")
757
755
if revision is not None:
758
756
if b2 is not None:
759
757
raise BzrCommandError("Can't specify -r with two branches")
760
758
if len(revision) == 1:
761
return show_diff(b, revision[0], specific_files=file_list,
759
return show_diff(tree.branch, revision[0], specific_files=file_list,
762
760
external_diff_options=diff_options)
763
761
elif len(revision) == 2:
764
return show_diff(b, revision[0], specific_files=file_list,
762
return show_diff(tree.branch, revision[0], specific_files=file_list,
765
763
external_diff_options=diff_options,
766
764
revision2=revision[1])
768
766
raise BzrCommandError('bzr diff --revision takes exactly one or two revision identifiers')
770
return show_diff(b, None, specific_files=file_list,
771
external_diff_options=diff_options, b2=b2)
769
return show_diff(b, None, specific_files=file_list,
770
external_diff_options=diff_options, b2=b2)
772
return show_diff(tree.branch, None, specific_files=file_list,
773
external_diff_options=diff_options)
774
776
class cmd_deleted(Command):
782
784
# if the directories are very large...)
784
786
def run(self, show_ids=False):
785
b = Branch.open_containing('.')[0]
787
new = b.working_tree()
787
tree = WorkingTree.open_containing('.')[0]
788
old = tree.branch.basis_tree()
788
789
for path, ie in old.inventory.iter_entries():
789
if not new.has_id(ie.file_id):
790
if not tree.has_id(ie.file_id):
791
792
print '%-50s %s' % (path, ie.file_id)
801
802
from bzrlib.delta import compare_trees
803
b = Branch.open_containing('.')[0]
804
td = compare_trees(b.basis_tree(), b.working_tree())
804
tree = WorkingTree.open_containing('.')[0]
805
td = compare_trees(tree.branch.basis_tree(), tree)
806
807
for path, id, kind, text_modified, meta_modified in td.modified:
879
879
direction = (forward and 'forward') or 'reverse'
882
b, fp = Branch.open_containing(filename)
885
tree, fp = WorkingTree.open_containing(filename)
888
inv = tree.read_working_inventory()
889
except NotBranchError:
892
b, fp = Branch.open_containing(filename)
894
inv = b.get_inventory(b.last_revision())
885
inv = b.working_tree().read_working_inventory()
886
except NoWorkingTree:
887
inv = b.get_inventory(b.last_revision())
888
896
file_id = inv.path2id(fp)
890
898
file_id = None # points to branch root
892
b, relpath = Branch.open_containing('.')
900
tree, relpath = WorkingTree.open_containing('.')
895
904
if revision is None:
944
953
takes_args = ["filename"]
946
955
def run(self, filename):
947
b, relpath = Branch.open_containing(filename)[0]
948
inv = b.working_tree().read_working_inventory()
956
tree, relpath = WorkingTree.open_containing(filename)
958
inv = tree.read_working_inventory()
949
959
file_id = inv.path2id(relpath)
950
960
for revno, revision_id, what in bzrlib.log.find_touching_revisions(b, file_id):
951
961
print "%6d %s" % (revno, what)
980
990
selection = {'I':ignored, '?':unknown, 'V':versioned}
982
b, relpath = Branch.open_containing('.')
992
tree, relpath = WorkingTree.open_containing('.')
988
tree = b.working_tree()
990
tree = b.revision_tree(revision[0].in_history(b).rev_id)
997
if revision is not None:
998
tree = tree.branch.revision_tree(
999
revision[0].in_history(tree.branch).rev_id)
991
1000
for fp, fc, kind, fid, entry in tree.list_files():
992
1001
if fp.startswith(relpath):
993
1002
fp = fp[len(relpath):]
1010
1018
class cmd_unknowns(Command):
1011
1019
"""List unknown files."""
1012
1020
@display_command
1014
1022
from bzrlib.osutils import quotefn
1015
for f in Branch.open_containing('.')[0].unknowns():
1023
for f in WorkingTree.open_containing('.')[0].unknowns():
1016
1024
print quotefn(f)
1020
1027
class cmd_ignore(Command):
1021
1028
"""Ignore a command or pattern.
1127
1133
takes_options = ['revision', 'format', 'root']
1128
1134
def run(self, dest, revision=None, format=None, root=None):
1130
b = Branch.open_containing('.')[0]
1136
tree = WorkingTree.open_containing('.')[0]
1131
1138
if revision is None:
1132
rev_id = b.last_revision()
1139
# should be tree.last_revision FIXME
1140
rev_id = tree.branch.last_revision()
1134
1142
if len(revision) != 1:
1135
1143
raise BzrError('bzr export --revision takes exactly 1 argument')
1167
1175
raise BzrCommandError("bzr cat requires a revision number")
1168
1176
elif len(revision) != 1:
1169
1177
raise BzrCommandError("bzr cat --revision takes exactly one number")
1170
b, relpath = Branch.open_containing(filename)
1180
tree, relpath = WorkingTree.open_containing(filename)
1182
except NotBranchError:
1185
b, relpath = Branch.open_containing(filename)
1171
1186
b.print_file(relpath, revision[0].in_history(b).revno)
1223
1238
from bzrlib.status import show_status
1224
1239
from cStringIO import StringIO
1226
b, selected_list = branch_files(selected_list)
1241
tree, selected_list = tree_files(selected_list)
1227
1242
if message is None and not file:
1228
1243
catcher = StringIO()
1229
show_status(b, specific_files=selected_list,
1244
show_status(tree.branch, specific_files=selected_list,
1230
1245
to_file=catcher)
1231
1246
message = edit_commit_message(catcher.getvalue())
1244
1259
raise BzrCommandError("empty commit message specified")
1247
b.working_tree().commit(message, specific_files=selected_list,
1248
allow_pointless=unchanged, strict=strict)
1262
tree.commit(message, specific_files=selected_list,
1263
allow_pointless=unchanged, strict=strict)
1249
1264
except PointlessCommit:
1250
1265
# FIXME: This should really happen before the file is read in;
1251
1266
# perhaps prepare the commit; get the message; then actually commit
1257
1272
except StrictCommitFailed:
1258
1273
raise BzrCommandError("Commit refused because there are unknown "
1259
1274
"files in the working tree.")
1260
note('Committed revision %d.' % (b.revno(),))
1275
note('Committed revision %d.' % (tree.branch.revno(),))
1263
1278
class cmd_check(Command):
1272
1287
def run(self, dir='.', verbose=False):
1273
1288
from bzrlib.check import check
1274
check(Branch.open_containing(dir)[0], verbose)
1289
check(WorkingTree.open_containing(dir)[0].branch, verbose)
1277
1292
class cmd_scan_cache(Command):
1556
1571
from bzrlib.merge_core import ApplyMerge3
1557
1572
if merge_type is None:
1558
1573
merge_type = ApplyMerge3
1559
b, file_list = branch_files(file_list)
1574
tree, file_list = tree_files(file_list)
1562
pending_merges = b.working_tree().pending_merges()
1577
pending_merges = tree.pending_merges()
1563
1578
if len(pending_merges) != 1:
1564
1579
raise BzrCommandError("Sorry, remerge only works after normal"
1565
1580
+ " merges. Not cherrypicking or"
1566
1581
+ "multi-merges.")
1567
this_tree = b.working_tree()
1568
base_revision = common_ancestor(b.last_revision(),
1569
pending_merges[0], b)
1570
base_tree = b.revision_tree(base_revision)
1571
other_tree = b.revision_tree(pending_merges[0])
1582
base_revision = common_ancestor(tree.branch.last_revision(),
1583
pending_merges[0], tree.branch)
1584
base_tree = tree.branch.revision_tree(base_revision)
1585
other_tree = tree.branch.revision_tree(pending_merges[0])
1572
1586
interesting_ids = None
1573
1587
if file_list is not None:
1574
1588
interesting_ids = set()
1575
1589
for filename in file_list:
1576
file_id = this_tree.path2id(filename)
1590
file_id = tree.path2id(filename)
1577
1591
interesting_ids.add(file_id)
1578
if this_tree.kind(file_id) != "directory":
1592
if tree.kind(file_id) != "directory":
1581
for name, ie in this_tree.inventory.iter_entries(file_id):
1595
for name, ie in tree.inventory.iter_entries(file_id):
1582
1596
interesting_ids.add(ie.file_id)
1583
transform_tree(this_tree, b.basis_tree(), interesting_ids)
1597
transform_tree(tree, tree.branch.basis_tree(), interesting_ids)
1584
1598
if file_list is None:
1585
restore_files = list(this_tree.iter_conflicts())
1599
restore_files = list(tree.iter_conflicts())
1587
1601
restore_files = file_list
1588
1602
for filename in restore_files:
1590
restore(this_tree.abspath(filename))
1604
restore(tree.abspath(filename))
1591
1605
except NotConflicted:
1593
conflicts = merge_inner(b, other_tree, base_tree,
1607
conflicts = merge_inner(tree.branch, other_tree, base_tree,
1594
1608
interesting_ids = interesting_ids,
1595
1609
other_rev_id=pending_merges[0],
1596
1610
merge_type=merge_type,
1597
1611
show_base=show_base,
1598
1612
reprocess=reprocess)
1601
1615
if conflicts > 0:
1625
1639
if revision is None:
1627
b = Branch.open_containing('.')[0]
1628
rev_id = b.last_revision()
1641
tree = WorkingTree.open_containing('.')[0]
1642
# FIXME should be tree.last_revision
1643
rev_id = tree.branch.last_revision()
1629
1644
elif len(revision) != 1:
1630
1645
raise BzrCommandError('bzr revert --revision takes exactly 1 argument')
1632
b, file_list = branch_files(file_list)
1633
rev_id = revision[0].in_history(b).rev_id
1634
b.working_tree().revert(file_list, b.revision_tree(rev_id),
1647
tree, file_list = tree_files(file_list)
1648
rev_id = revision[0].in_history(tree.branch).rev_id
1649
tree.revert(file_list, tree.branch.revision_tree(rev_id),
1712
1727
if verbose and is_quiet():
1713
1728
raise BzrCommandError('Cannot pass both quiet and verbose')
1715
b = Branch.open_containing('.')[0]
1716
parent = b.get_parent()
1730
tree = WorkingTree.open_containing('.')[0]
1731
parent = tree.branch.get_parent()
1717
1732
if remote is None:
1718
1733
if parent is None:
1719
1734
raise BzrCommandError("No missing location known or specified.")
1724
1739
elif parent is None:
1725
1740
# We only update parent if it did not exist, missing
1726
1741
# should not change the parent
1727
b.set_parent(remote)
1742
tree.branch.set_parent(remote)
1728
1743
br_remote = Branch.open_containing(remote)[0]
1729
return show_missing(b, br_remote, verbose=verbose, quiet=is_quiet())
1744
return show_missing(tree.branch, br_remote, verbose=verbose,
1732
1748
class cmd_plugins(Command):
1794
1810
@display_command
1795
1811
def run(self, filename, all=False, long=False):
1796
1812
from bzrlib.annotate import annotate_file
1797
b, relpath = Branch.open_containing(filename)
1813
tree, relpath = WorkingTree.open_containing(filename)
1814
branch = tree.branch
1800
tree = WorkingTree(b.base, b)
1801
tree = b.revision_tree(b.last_revision())
1802
1817
file_id = tree.inventory.path2id(relpath)
1818
tree = branch.revision_tree(branch.last_revision())
1803
1819
file_version = tree.inventory[file_id].revision
1804
annotate_file(b, file_version, file_id, long, all, sys.stdout)
1820
annotate_file(branch, file_version, file_id, long, all, sys.stdout)
1809
1825
class cmd_re_sign(Command):
1821
1837
raise BzrCommandError('You can only supply one of revision_id or --revision')
1822
1838
if revision_id is None and revision is None:
1823
1839
raise BzrCommandError('You must supply either --revision or a revision_id')
1824
b = Branch.open_containing('.')[0]
1840
b = WorkingTree.open_containing('.')[0].branch
1825
1841
gpg_strategy = gpg.GPGStrategy(config.BranchConfig(b))
1826
1842
if revision_id is not None:
1827
1843
b.sign_revision(revision_id, gpg_strategy)