30
30
import bzrlib.errors as errors
31
31
from bzrlib.errors import (BzrError, BzrCheckError, BzrCommandError,
32
32
NotBranchError, DivergedBranches, NotConflicted,
33
NoSuchFile, NoWorkingTree, FileInWrongBranch)
33
NoSuchFile, NoWorkingTree, FileInWrongBranch)
34
34
from bzrlib.option import Option
35
35
from bzrlib.revisionspec import RevisionSpec
36
36
import bzrlib.trace
37
from bzrlib.trace import mutter, note, log_error, warning
37
from bzrlib.trace import mutter, note, log_error, warning, is_quiet
38
38
from bzrlib.workingtree import WorkingTree
41
def branch_files(file_list, default_branch='.'):
41
def tree_files(file_list, default_branch=u'.'):
43
return inner_branch_files(file_list, default_branch)
43
return internal_tree_files(file_list, default_branch)
44
44
except FileInWrongBranch, e:
45
45
raise BzrCommandError("%s is not in the same branch as %s" %
46
46
(e.path, file_list[0]))
48
def inner_branch_files(file_list, default_branch='.'):
48
def internal_tree_files(file_list, default_branch=u'.'):
50
50
Return a branch and list of branch-relative paths.
51
51
If supplied file_list is empty or None, the branch default will be used,
52
52
and returned file_list will match the original.
54
54
if file_list is None or len(file_list) == 0:
55
return Branch.open_containing(default_branch)[0], file_list
56
b = Branch.open_containing(file_list[0])[0]
58
# note that if this is a remote branch, we would want
59
# relpath against the transport. RBC 20051018
60
# Most branch ops can't meaningfully operate on files in remote branches;
61
# the above comment was in cmd_status. ADHB 20051026
62
tree = WorkingTree(b.base, b)
55
return WorkingTree.open_containing(default_branch)[0], file_list
56
tree = WorkingTree.open_containing(file_list[0])[0]
64
58
for filename in file_list:
66
60
new_list.append(tree.relpath(filename))
67
61
except NotBranchError:
68
raise FileInWrongBranch(b, filename)
62
raise FileInWrongBranch(tree.branch, filename)
72
66
# TODO: Make sure no commands unconditionally use the working directory as a
125
119
def run(self, all=False, show_ids=False, file_list=None, revision=None):
126
b, file_list = branch_files(file_list)
120
tree, file_list = tree_files(file_list)
128
122
from bzrlib.status import show_status
129
show_status(b, show_unchanged=all, show_ids=show_ids,
123
show_status(tree.branch, show_unchanged=all, show_ids=show_ids,
130
124
specific_files=file_list, revision=revision)
148
142
raise BzrCommandError('You can only supply one of revision_id or --revision')
149
143
if revision_id is None and revision is None:
150
144
raise BzrCommandError('You must supply either --revision or a revision_id')
151
b = Branch.open_containing('.')[0]
145
b = WorkingTree.open_containing(u'.')[0].branch
152
146
if revision_id is not None:
153
sys.stdout.write(b.get_revision_xml_file(revision_id).read())
147
sys.stdout.write(b.get_revision_xml(revision_id))
154
148
elif revision is not None:
155
149
for rev in revision:
157
151
raise BzrCommandError('You cannot specify a NULL revision.')
158
152
revno, rev_id = rev.in_history(b)
159
sys.stdout.write(b.get_revision_xml_file(rev_id).read())
153
sys.stdout.write(b.get_revision_xml(rev_id))
162
156
class cmd_revno(Command):
220
214
get added when you add a file in the directory.
222
216
takes_args = ['file*']
223
takes_options = ['no-recurse', 'quiet']
217
takes_options = ['no-recurse']
225
def run(self, file_list, no_recurse=False, quiet=False):
219
def run(self, file_list, no_recurse=False):
226
220
from bzrlib.add import smart_add, add_reporter_print, add_reporter_null
228
222
reporter = add_reporter_null
230
224
reporter = add_reporter_print
271
263
def run(self, revision=None, show_ids=False, kind=None):
272
264
if kind and kind not in ['file', 'directory', 'symlink']:
273
265
raise BzrCommandError('invalid kind specified')
274
b = Branch.open_containing('.')[0]
266
tree = WorkingTree.open_containing(u'.')[0]
275
267
if revision is None:
276
inv = b.working_tree().read_working_inventory()
268
inv = tree.read_working_inventory()
278
270
if len(revision) > 1:
279
271
raise BzrCommandError('bzr inventory --revision takes'
280
272
' exactly one revision identifier')
281
inv = b.get_revision_inventory(revision[0].in_history(b).rev_id)
273
inv = tree.branch.get_revision_inventory(
274
revision[0].in_history(tree.branch).rev_id)
283
276
for path, entry in inv.entries():
284
277
if kind and kind != entry.kind:
300
293
takes_args = ['source$', 'dest']
301
294
def run(self, source_list, dest):
302
b, source_list = branch_files(source_list)
295
tree, source_list = tree_files(source_list)
304
296
# TODO: glob expansion on windows?
305
tree = WorkingTree(b.base, b)
306
b.move(source_list, tree.relpath(dest))
297
tree.move(source_list, tree.relpath(dest))
309
300
class cmd_rename(Command):
323
314
takes_args = ['from_name', 'to_name']
325
316
def run(self, from_name, to_name):
326
b, (from_name, to_name) = branch_files((from_name, to_name))
327
b.rename_one(from_name, to_name)
317
tree, (from_name, to_name) = tree_files((from_name, to_name))
318
tree.rename_one(from_name, to_name)
330
321
class cmd_mv(Command):
344
335
def run(self, names_list):
345
336
if len(names_list) < 2:
346
337
raise BzrCommandError("missing file argument")
347
b, rel_names = branch_files(names_list)
338
tree, rel_names = tree_files(names_list)
349
340
if os.path.isdir(names_list[-1]):
350
341
# move into existing directory
351
for pair in b.move(rel_names[:-1], rel_names[-1]):
342
for pair in tree.move(rel_names[:-1], rel_names[-1]):
352
343
print "%s => %s" % pair
354
345
if len(names_list) != 2:
355
346
raise BzrCommandError('to mv multiple files the destination '
356
347
'must be a versioned directory')
357
b.rename_one(rel_names[0], rel_names[1])
348
tree.rename_one(rel_names[0], rel_names[1])
358
349
print "%s => %s" % (rel_names[0], rel_names[1])
383
374
from bzrlib.merge import merge
384
375
from shutil import rmtree
387
br_to = Branch.open_containing('.')[0]
388
stored_loc = br_to.get_parent()
377
# FIXME: too much stuff is in the command class
378
tree_to = WorkingTree.open_containing(u'.')[0]
379
stored_loc = tree_to.branch.get_parent()
389
380
if location is None:
390
381
if stored_loc is None:
391
382
raise BzrCommandError("No pull location known or specified.")
393
384
print "Using saved location: %s" % stored_loc
394
385
location = stored_loc
395
386
br_from = Branch.open(location)
387
br_to = tree_to.branch
397
389
old_rh = br_to.revision_history()
398
br_to.working_tree().pull(br_from, overwrite)
390
count = tree_to.pull(br_from, overwrite)
399
391
except DivergedBranches:
392
# FIXME: Just make DivergedBranches display the right message
400
394
raise BzrCommandError("These branches have diverged."
402
396
if br_to.get_parent() is None or remember:
403
397
br_to.set_parent(location)
398
note('%d revision(s) pulled.', count)
406
new_rh = br_to.revision_history()
400
new_rh = tree_to.branch.revision_history()
407
401
if old_rh != new_rh:
408
402
# Something changed
409
403
from bzrlib.log import show_changed_revisions
410
show_changed_revisions(br_to, old_rh, new_rh)
404
show_changed_revisions(tree_to.branch, old_rh, new_rh)
413
407
class cmd_push(Command):
442
436
def run(self, location=None, remember=False, overwrite=False,
443
437
create_prefix=False, verbose=False):
438
# FIXME: Way too big! Put this into a function called from the
445
441
from shutil import rmtree
446
442
from bzrlib.transport import get_transport
448
br_from = Branch.open_containing('.')[0]
449
stored_loc = br_from.get_push_location()
444
tree_from = WorkingTree.open_containing(u'.')[0]
445
br_from = tree_from.branch
446
stored_loc = tree_from.branch.get_push_location()
450
447
if location is None:
451
448
if stored_loc is None:
452
449
raise BzrCommandError("No push location known or specified.")
479
476
if new_transport.base == transport.base:
480
477
raise BzrCommandError("Could not creeate "
484
479
br_to = Branch.initialize(location)
486
481
old_rh = br_to.revision_history()
487
br_to.pull(br_from, overwrite)
482
count = br_to.pull(br_from, overwrite)
488
483
except DivergedBranches:
489
484
raise BzrCommandError("These branches have diverged."
490
485
" Try a merge then push with overwrite.")
491
486
if br_from.get_push_location() is None or remember:
492
487
br_from.set_push_location(location)
488
note('%d revision(s) pushed.' % (count,))
495
490
new_rh = br_to.revision_history()
496
491
if old_rh != new_rh:
585
582
takes_args = ['dir?']
588
def run(self, dir='.'):
589
b = Branch.open_containing(dir)[0]
590
old_inv = b.basis_tree().inventory
591
new_inv = b.working_tree().read_working_inventory()
585
def run(self, dir=u'.'):
586
tree = WorkingTree.open_containing(dir)[0]
587
old_inv = tree.branch.basis_tree().inventory
588
new_inv = tree.read_working_inventory()
593
590
renames = list(bzrlib.tree.find_renames(old_inv, new_inv))
634
630
takes_args = ['filename']
636
632
def run(self, filename):
637
b, relpath = Branch.open_containing(filename)
638
i = b.working_tree().inventory.path2id(relpath)
633
tree, relpath = WorkingTree.open_containing(filename)
634
i = tree.inventory.path2id(relpath)
640
636
raise BzrError("%r is not a versioned file" % filename)
741
740
def run(self, revision=None, file_list=None, diff_options=None):
742
741
from bzrlib.diff import show_diff
744
b, file_list = inner_branch_files(file_list)
743
tree, file_list = internal_tree_files(file_list)
746
746
except FileInWrongBranch:
747
747
if len(file_list) != 2:
750
750
b, file1 = Branch.open_containing(file_list[0])
751
751
b2, file2 = Branch.open_containing(file_list[1])
752
752
if file1 != "" or file2 != "":
753
# FIXME diff those two files. rbc 20051123
753
754
raise BzrCommandError("Files are in different branches")
755
756
if revision is not None:
756
757
if b2 is not None:
757
758
raise BzrCommandError("Can't specify -r with two branches")
758
759
if len(revision) == 1:
759
return show_diff(b, revision[0], specific_files=file_list,
760
return show_diff(tree.branch, revision[0], specific_files=file_list,
760
761
external_diff_options=diff_options)
761
762
elif len(revision) == 2:
762
return show_diff(b, revision[0], specific_files=file_list,
763
return show_diff(tree.branch, revision[0], specific_files=file_list,
763
764
external_diff_options=diff_options,
764
765
revision2=revision[1])
766
767
raise BzrCommandError('bzr diff --revision takes exactly one or two revision identifiers')
768
return show_diff(b, None, specific_files=file_list,
769
external_diff_options=diff_options, b2=b2)
770
return show_diff(b, None, specific_files=file_list,
771
external_diff_options=diff_options, b2=b2)
773
return show_diff(tree.branch, None, specific_files=file_list,
774
external_diff_options=diff_options)
772
777
class cmd_deleted(Command):
780
785
# if the directories are very large...)
782
787
def run(self, show_ids=False):
783
b = Branch.open_containing('.')[0]
785
new = b.working_tree()
788
tree = WorkingTree.open_containing(u'.')[0]
789
old = tree.branch.basis_tree()
786
790
for path, ie in old.inventory.iter_entries():
787
if not new.has_id(ie.file_id):
791
if not tree.has_id(ie.file_id):
789
793
print '%-50s %s' % (path, ie.file_id)
799
803
from bzrlib.delta import compare_trees
801
b = Branch.open_containing('.')[0]
802
td = compare_trees(b.basis_tree(), b.working_tree())
805
tree = WorkingTree.open_containing(u'.')[0]
806
td = compare_trees(tree.branch.basis_tree(), tree)
804
808
for path, id, kind, text_modified, meta_modified in td.modified:
877
880
direction = (forward and 'forward') or 'reverse'
880
b, fp = Branch.open_containing(filename)
886
tree, fp = WorkingTree.open_containing(filename)
889
inv = tree.read_working_inventory()
890
except NotBranchError:
893
b, fp = Branch.open_containing(filename)
895
inv = b.get_inventory(b.last_revision())
883
inv = b.working_tree().read_working_inventory()
884
except NoWorkingTree:
885
inv = b.get_inventory(b.last_revision())
886
897
file_id = inv.path2id(fp)
888
899
file_id = None # points to branch root
890
b, relpath = Branch.open_containing('.')
901
tree, relpath = WorkingTree.open_containing(u'.')
893
905
if revision is None:
942
954
takes_args = ["filename"]
944
956
def run(self, filename):
945
b, relpath = Branch.open_containing(filename)[0]
946
inv = b.working_tree().read_working_inventory()
957
tree, relpath = WorkingTree.open_containing(filename)
959
inv = tree.read_working_inventory()
947
960
file_id = inv.path2id(relpath)
948
961
for revno, revision_id, what in bzrlib.log.find_touching_revisions(b, file_id):
949
962
print "%6d %s" % (revno, what)
978
991
selection = {'I':ignored, '?':unknown, 'V':versioned}
980
b, relpath = Branch.open_containing('.')
993
tree, relpath = WorkingTree.open_containing(u'.')
986
tree = b.working_tree()
988
tree = b.revision_tree(revision[0].in_history(b).rev_id)
998
if revision is not None:
999
tree = tree.branch.revision_tree(
1000
revision[0].in_history(tree.branch).rev_id)
989
1001
for fp, fc, kind, fid, entry in tree.list_files():
990
1002
if fp.startswith(relpath):
991
1003
fp = fp[len(relpath):]
1008
1019
class cmd_unknowns(Command):
1009
1020
"""List unknown files."""
1010
1021
@display_command
1012
1023
from bzrlib.osutils import quotefn
1013
for f in Branch.open_containing('.')[0].unknowns():
1024
for f in WorkingTree.open_containing(u'.')[0].unknowns():
1014
1025
print quotefn(f)
1018
1028
class cmd_ignore(Command):
1019
1029
"""Ignore a command or pattern.
1136
1145
def run(self, dest, revision=None, format=None, root=None):
1138
1147
from bzrlib.export import export
1139
b = Branch.open_containing('.')[0]
1148
tree = WorkingTree.open_containing(u'.')[0]
1140
1150
if revision is None:
1151
# should be tree.last_revision FIXME
1141
1152
rev_id = b.last_revision()
1143
1154
if len(revision) != 1:
1162
1173
raise BzrCommandError("bzr cat requires a revision number")
1163
1174
elif len(revision) != 1:
1164
1175
raise BzrCommandError("bzr cat --revision takes exactly one number")
1165
b, relpath = Branch.open_containing(filename)
1178
tree, relpath = WorkingTree.open_containing(filename)
1180
except NotBranchError:
1183
b, relpath = Branch.open_containing(filename)
1166
1184
b.print_file(relpath, revision[0].in_history(b).revno)
1218
1236
from bzrlib.status import show_status
1219
1237
from cStringIO import StringIO
1221
b, selected_list = branch_files(selected_list)
1239
tree, selected_list = tree_files(selected_list)
1222
1240
if message is None and not file:
1223
1241
catcher = StringIO()
1224
show_status(b, specific_files=selected_list,
1242
show_status(tree.branch, specific_files=selected_list,
1225
1243
to_file=catcher)
1226
1244
message = edit_commit_message(catcher.getvalue())
1239
1257
raise BzrCommandError("empty commit message specified")
1242
b.working_tree().commit(message, specific_files=selected_list,
1243
allow_pointless=unchanged, strict=strict)
1260
tree.commit(message, specific_files=selected_list,
1261
allow_pointless=unchanged, strict=strict)
1244
1262
except PointlessCommit:
1245
1263
# FIXME: This should really happen before the file is read in;
1246
1264
# perhaps prepare the commit; get the message; then actually commit
1260
1279
This command checks various invariants about the branch storage to
1261
1280
detect data corruption or bzr bugs.
1263
takes_args = ['dir?']
1282
takes_args = ['branch?']
1264
1283
takes_options = ['verbose']
1266
def run(self, dir='.', verbose=False):
1285
def run(self, branch=None, verbose=False):
1267
1286
from bzrlib.check import check
1268
check(Branch.open_containing(dir)[0], verbose)
1288
tree = WorkingTree.open_containing()[0]
1289
branch = tree.branch
1291
branch = Branch.open(branch)
1292
check(branch, verbose)
1271
1295
class cmd_scan_cache(Command):
1550
1574
from bzrlib.merge_core import ApplyMerge3
1551
1575
if merge_type is None:
1552
1576
merge_type = ApplyMerge3
1553
b, file_list = branch_files(file_list)
1577
tree, file_list = tree_files(file_list)
1556
pending_merges = b.working_tree().pending_merges()
1580
pending_merges = tree.pending_merges()
1557
1581
if len(pending_merges) != 1:
1558
1582
raise BzrCommandError("Sorry, remerge only works after normal"
1559
1583
+ " merges. Not cherrypicking or"
1560
1584
+ "multi-merges.")
1561
this_tree = b.working_tree()
1562
base_revision = common_ancestor(b.last_revision(),
1563
pending_merges[0], b)
1564
base_tree = b.revision_tree(base_revision)
1565
other_tree = b.revision_tree(pending_merges[0])
1585
base_revision = common_ancestor(tree.branch.last_revision(),
1586
pending_merges[0], tree.branch)
1587
base_tree = tree.branch.revision_tree(base_revision)
1588
other_tree = tree.branch.revision_tree(pending_merges[0])
1566
1589
interesting_ids = None
1567
1590
if file_list is not None:
1568
1591
interesting_ids = set()
1569
1592
for filename in file_list:
1570
file_id = this_tree.path2id(filename)
1593
file_id = tree.path2id(filename)
1571
1594
interesting_ids.add(file_id)
1572
if this_tree.kind(file_id) != "directory":
1595
if tree.kind(file_id) != "directory":
1575
for name, ie in this_tree.inventory.iter_entries(file_id):
1598
for name, ie in tree.inventory.iter_entries(file_id):
1576
1599
interesting_ids.add(ie.file_id)
1577
transform_tree(this_tree, b.basis_tree(), interesting_ids)
1600
transform_tree(tree, tree.branch.basis_tree(), interesting_ids)
1578
1601
if file_list is None:
1579
restore_files = list(this_tree.iter_conflicts())
1602
restore_files = list(tree.iter_conflicts())
1581
1604
restore_files = file_list
1582
1605
for filename in restore_files:
1584
restore(this_tree.abspath(filename))
1607
restore(tree.abspath(filename))
1585
1608
except NotConflicted:
1587
conflicts = merge_inner(b, other_tree, base_tree,
1610
conflicts = merge_inner(tree.branch, other_tree, base_tree,
1588
1611
interesting_ids = interesting_ids,
1589
1612
other_rev_id=pending_merges[0],
1590
1613
merge_type=merge_type,
1591
1614
show_base=show_base,
1592
1615
reprocess=reprocess)
1595
1618
if conflicts > 0:
1619
1642
if revision is None:
1621
b = Branch.open_containing('.')[0]
1622
rev_id = b.last_revision()
1644
tree = WorkingTree.open_containing(u'.')[0]
1645
# FIXME should be tree.last_revision
1646
rev_id = tree.branch.last_revision()
1623
1647
elif len(revision) != 1:
1624
1648
raise BzrCommandError('bzr revert --revision takes exactly 1 argument')
1626
b, file_list = branch_files(file_list)
1627
rev_id = revision[0].in_history(b).rev_id
1628
b.working_tree().revert(file_list, b.revision_tree(rev_id),
1650
tree, file_list = tree_files(file_list)
1651
rev_id = revision[0].in_history(tree.branch).rev_id
1652
tree.revert(file_list, tree.branch.revision_tree(rev_id),
1697
1721
takes_args = ['remote?']
1698
1722
aliases = ['mis', 'miss']
1699
# We don't have to add quiet to the list, because
1700
# unknown options are parsed as booleans
1701
takes_options = ['verbose', 'quiet']
1723
takes_options = ['verbose']
1703
1725
@display_command
1704
def run(self, remote=None, verbose=False, quiet=False):
1726
def run(self, remote=None, verbose=False):
1705
1727
from bzrlib.errors import BzrCommandError
1706
1728
from bzrlib.missing import show_missing
1708
if verbose and quiet:
1730
if verbose and is_quiet():
1709
1731
raise BzrCommandError('Cannot pass both quiet and verbose')
1711
b = Branch.open_containing('.')[0]
1712
parent = b.get_parent()
1733
tree = WorkingTree.open_containing(u'.')[0]
1734
parent = tree.branch.get_parent()
1713
1735
if remote is None:
1714
1736
if parent is None:
1715
1737
raise BzrCommandError("No missing location known or specified.")
1718
1740
print "Using last location: %s" % parent
1719
1741
remote = parent
1720
1742
elif parent is None:
1721
1743
# We only update parent if it did not exist, missing
1722
1744
# should not change the parent
1723
b.set_parent(remote)
1745
tree.branch.set_parent(remote)
1724
1746
br_remote = Branch.open_containing(remote)[0]
1725
return show_missing(b, br_remote, verbose=verbose, quiet=quiet)
1747
return show_missing(tree.branch, br_remote, verbose=verbose,
1728
1751
class cmd_plugins(Command):
1750
1773
takes_options = ['revision', 'long']
1751
1774
takes_args = ['branch?']
1752
1775
@display_command
1753
def run(self, branch='.', revision=None, long=False):
1776
def run(self, branch=u'.', revision=None, long=False):
1754
1777
from bzrlib.testament import Testament
1755
b = Branch.open_containing(branch)[0]
1778
b = WorkingTree.open_containing(branch)[0].branch
1758
1781
if revision is None:
1790
1813
@display_command
1791
1814
def run(self, filename, all=False, long=False):
1792
1815
from bzrlib.annotate import annotate_file
1793
b, relpath = Branch.open_containing(filename)
1816
tree, relpath = WorkingTree.open_containing(filename)
1817
branch = tree.branch
1796
tree = WorkingTree(b.base, b)
1797
tree = b.revision_tree(b.last_revision())
1798
1820
file_id = tree.inventory.path2id(relpath)
1821
tree = branch.revision_tree(branch.last_revision())
1799
1822
file_version = tree.inventory[file_id].revision
1800
annotate_file(b, file_version, file_id, long, all, sys.stdout)
1823
annotate_file(branch, file_version, file_id, long, all, sys.stdout)
1805
1828
class cmd_re_sign(Command):
1817
1840
raise BzrCommandError('You can only supply one of revision_id or --revision')
1818
1841
if revision_id is None and revision is None:
1819
1842
raise BzrCommandError('You must supply either --revision or a revision_id')
1820
b = Branch.open_containing('.')[0]
1843
b = WorkingTree.open_containing(u'.')[0].branch
1821
1844
gpg_strategy = gpg.GPGStrategy(config.BranchConfig(b))
1822
1845
if revision_id is not None:
1823
1846
b.sign_revision(revision_id, gpg_strategy)