22
from bzrlib.trace import mutter, note, log_error
22
from bzrlib.trace import mutter, note, log_error, warning
23
23
from bzrlib.errors import BzrError, BzrCheckError, BzrCommandError
24
from bzrlib.osutils import quotefn
25
from bzrlib import Branch, Inventory, InventoryEntry, BZRDIR, \
24
from bzrlib.branch import find_branch
25
from bzrlib import BZRDIR
52
51
assert cmd.startswith("cmd_")
53
52
return cmd[4:].replace('_','-')
55
55
def _parse_revision_str(revstr):
56
"""This handles a revision string -> revno.
58
There are several possibilities:
61
'234:345' -> [234, 345]
65
In the future we will also support:
66
'uuid:blah-blah-blah' -> ?
67
'hash:blahblahblah' -> ?
56
"""This handles a revision string -> revno.
58
This always returns a list. The list will have one element for
60
It supports integers directly, but everything else it
61
defers for passing to Branch.get_revision_info()
63
>>> _parse_revision_str('234')
65
>>> _parse_revision_str('234..567')
67
>>> _parse_revision_str('..')
69
>>> _parse_revision_str('..234')
71
>>> _parse_revision_str('234..')
73
>>> _parse_revision_str('234..456..789') # Maybe this should be an error
75
>>> _parse_revision_str('234....789') # Error?
77
>>> _parse_revision_str('revid:test@other.com-234234')
78
['revid:test@other.com-234234']
79
>>> _parse_revision_str('revid:test@other.com-234234..revid:test@other.com-234235')
80
['revid:test@other.com-234234', 'revid:test@other.com-234235']
81
>>> _parse_revision_str('revid:test@other.com-234234..23')
82
['revid:test@other.com-234234', 23]
83
>>> _parse_revision_str('date:2005-04-12')
85
>>> _parse_revision_str('date:2005-04-12 12:24:33')
86
['date:2005-04-12 12:24:33']
87
>>> _parse_revision_str('date:2005-04-12T12:24:33')
88
['date:2005-04-12T12:24:33']
89
>>> _parse_revision_str('date:2005-04-12,12:24:33')
90
['date:2005-04-12,12:24:33']
91
>>> _parse_revision_str('-5..23')
93
>>> _parse_revision_str('-5')
95
>>> _parse_revision_str('123a')
97
>>> _parse_revision_str('abc')
71
if revstr.find(':') != -1:
72
revs = revstr.split(':')
74
raise ValueError('More than 2 pieces not supported for --revision: %r' % revstr)
79
revs[0] = int(revs[0])
84
revs[1] = int(revs[1])
101
old_format_re = re.compile('\d*:\d*')
102
m = old_format_re.match(revstr)
104
warning('Colon separator for revision numbers is deprecated.'
107
for rev in revstr.split(':'):
109
revs.append(int(rev))
114
for x in revstr.split('..'):
165
200
assert isinstance(arguments, dict)
166
201
cmdargs = options.copy()
167
202
cmdargs.update(arguments)
168
assert self.__doc__ != Command.__doc__, \
169
("No help message set for %r" % self)
203
if self.__doc__ == Command.__doc__:
204
from warnings import warn
205
warn("No help message set for %r" % self)
170
206
self.status = self.run(**cmdargs)
207
if self.status is None:
297
335
directory is shown. Otherwise, only the status of the specified
298
336
files or directories is reported. If a directory is given, status
299
337
is reported for everything inside that directory.
339
If a revision is specified, the changes since that revision are shown.
301
341
takes_args = ['file*']
302
takes_options = ['all', 'show-ids']
342
takes_options = ['all', 'show-ids', 'revision']
303
343
aliases = ['st', 'stat']
305
345
def run(self, all=False, show_ids=False, file_list=None):
307
b = Branch(file_list[0])
347
b = find_branch(file_list[0])
308
348
file_list = [b.relpath(x) for x in file_list]
309
349
# special case: only one path was given and it's the root
311
351
if file_list == ['']:
316
status.show_status(b, show_unchanged=all, show_ids=show_ids,
317
specific_files=file_list)
356
from bzrlib.status import show_status
357
show_status(b, show_unchanged=all, show_ids=show_ids,
358
specific_files=file_list)
320
361
class cmd_cat_revision(Command):
333
375
This is equal to the number of revisions on this branch."""
335
print Branch('.').revno()
377
print find_branch('.').revno()
379
class cmd_revision_info(Command):
380
"""Show revision number and revision id for a given revision identifier.
383
takes_args = ['revision_info*']
384
takes_options = ['revision']
385
def run(self, revision=None, revision_info_list=None):
386
from bzrlib.branch import find_branch
389
if revision is not None:
390
revs.extend(revision)
391
if revision_info_list is not None:
392
revs.extend(revision_info_list)
394
raise BzrCommandError('You must supply a revision identifier')
399
print '%4d %s' % b.get_revision_info(rev)
338
402
class cmd_add(Command):
348
412
whether already versioned or not, are searched for files or
349
413
subdirectories that are neither versioned or ignored, and these
350
414
are added. This search proceeds recursively into versioned
415
directories. If no names are given '.' is assumed.
353
Therefore simply saying 'bzr add .' will version all files that
417
Therefore simply saying 'bzr add' will version all files that
354
418
are currently unknown.
356
420
TODO: Perhaps adding a file whose directly is not versioned should
357
421
recursively add that parent, rather than giving an error?
359
takes_args = ['file+']
423
takes_args = ['file*']
360
424
takes_options = ['verbose', 'no-recurse']
362
426
def run(self, file_list, verbose=False, no_recurse=False):
363
bzrlib.add.smart_add(file_list, verbose, not no_recurse)
427
from bzrlib.add import smart_add
428
smart_add(file_list, verbose, not no_recurse)
399
461
takes_options = ['revision', 'show-ids']
401
463
def run(self, revision=None, show_ids=False):
403
465
if revision == None:
404
466
inv = b.read_working_inventory()
406
inv = b.get_revision_inventory(b.lookup_revision(revision))
468
if len(revision) > 1:
469
raise BzrCommandError('bzr inventory --revision takes'
470
' exactly one revision identifier')
471
inv = b.get_revision_inventory(b.lookup_revision(revision[0]))
408
473
for path, entry in inv.entries():
485
552
print "Using last location: %s" % stored_loc
486
553
location = stored_loc
487
from branch import find_branch, DivergedBranches
554
cache_root = tempfile.mkdtemp()
555
from bzrlib.branch import DivergedBranches
488
556
br_from = find_branch(location)
489
557
location = pull_loc(br_from)
490
558
old_revno = br_to.revno()
492
br_to.update_revisions(br_from)
493
except DivergedBranches:
494
raise BzrCommandError("These branches have diverged. Try merge.")
496
merge(('.', -1), ('.', old_revno), check_clean=False)
497
if location != stored_loc:
498
br_to.controlfile("x-pull", "wb").write(location + "\n")
560
from branch import find_cached_branch, DivergedBranches
561
br_from = find_cached_branch(location, cache_root)
562
location = pull_loc(br_from)
563
old_revno = br_to.revno()
565
br_to.update_revisions(br_from)
566
except DivergedBranches:
567
raise BzrCommandError("These branches have diverged."
570
merge(('.', -1), ('.', old_revno), check_clean=False)
571
if location != stored_loc:
572
br_to.controlfile("x-pull", "wb").write(location + "\n")
514
590
def run(self, from_location, to_location=None, revision=None):
516
592
from bzrlib.merge import merge
517
from branch import find_branch, DivergedBranches, NoSuchRevision
593
from bzrlib.branch import DivergedBranches, NoSuchRevision, \
594
find_cached_branch, Branch
518
595
from shutil import rmtree
520
br_from = find_branch(from_location)
522
if e.errno == errno.ENOENT:
523
raise BzrCommandError('Source location "%s" does not exist.' %
528
if to_location is None:
529
to_location = os.path.basename(from_location.rstrip("/\\"))
532
os.mkdir(to_location)
534
if e.errno == errno.EEXIST:
535
raise BzrCommandError('Target directory "%s" already exists.' %
537
if e.errno == errno.ENOENT:
538
raise BzrCommandError('Parent of "%s" does not exist.' %
542
br_to = Branch(to_location, init=True)
545
br_to.update_revisions(br_from, stop_revision=revision)
546
except NoSuchRevision:
548
msg = "The branch %s has no revision %d." % (from_location,
550
raise BzrCommandError(msg)
551
merge((to_location, -1), (to_location, 0), this_dir=to_location,
552
check_clean=False, ignore_zero=True)
553
from_location = pull_loc(br_from)
554
br_to.controlfile("x-pull", "wb").write(from_location + "\n")
596
from meta_store import CachedStore
598
cache_root = tempfile.mkdtemp()
602
elif len(revision) > 1:
603
raise BzrCommandError('bzr branch --revision takes exactly 1 revision value')
607
br_from = find_cached_branch(from_location, cache_root)
609
if e.errno == errno.ENOENT:
610
raise BzrCommandError('Source location "%s" does not'
611
' exist.' % to_location)
615
if to_location is None:
616
to_location = os.path.basename(from_location.rstrip("/\\"))
619
os.mkdir(to_location)
621
if e.errno == errno.EEXIST:
622
raise BzrCommandError('Target directory "%s" already'
623
' exists.' % to_location)
624
if e.errno == errno.ENOENT:
625
raise BzrCommandError('Parent of "%s" does not exist.' %
629
br_to = Branch(to_location, init=True)
631
br_to.set_root_id(br_from.get_root_id())
634
if revision[0] is None:
635
revno = br_from.revno()
637
revno, rev_id = br_from.get_revision_info(revision[0])
639
br_to.update_revisions(br_from, stop_revision=revno)
640
except NoSuchRevision:
642
msg = "The branch %s has no revision %d." % (from_location,
644
raise BzrCommandError(msg)
646
merge((to_location, -1), (to_location, 0), this_dir=to_location,
647
check_clean=False, ignore_zero=True)
648
from_location = pull_loc(br_from)
649
br_to.controlfile("x-pull", "wb").write(from_location + "\n")
557
654
def pull_loc(branch):
649
745
"""Display list of revision ids on this branch."""
652
for patchid in Branch('.').revision_history():
748
for patchid in find_branch('.').revision_history():
656
752
class cmd_directories(Command):
657
753
"""Display list of versioned directories in this branch."""
659
for name, ie in Branch('.').read_working_inventory().directories():
755
for name, ie in find_branch('.').read_working_inventory().directories():
719
815
# just pointing to top-of-tree
820
# TODO: Make show_diff support taking 2 arguments
822
if revision is not None:
823
if len(revision) != 1:
824
raise BzrCommandError('bzr diff --revision takes exactly one revision identifier')
825
base_rev = revision[0]
724
show_diff(b, revision, specific_files=file_list,
827
show_diff(b, base_rev, specific_files=file_list,
725
828
external_diff_options=diff_options)
755
858
"""List files modified in working tree."""
760
inv = b.read_working_inventory()
761
sc = statcache.update_cache(b, inv)
762
basis = b.basis_tree()
763
basis_inv = basis.inventory
765
# We used to do this through iter_entries(), but that's slow
766
# when most of the files are unmodified, as is usually the
767
# case. So instead we iterate by inventory entry, and only
768
# calculate paths as necessary.
770
for file_id in basis_inv:
771
cacheentry = sc.get(file_id)
772
if not cacheentry: # deleted
774
ie = basis_inv[file_id]
775
if cacheentry[statcache.SC_SHA1] != ie.text_sha1:
776
path = inv.id2path(file_id)
861
from bzrlib.diff import compare_trees
864
td = compare_trees(b.basis_tree(), b.working_tree())
866
for path, id, kind in td.modified:
816
905
-r revision requests a specific revision, -r :end or -r begin: are
908
--message allows you to give a regular expression, which will be evaluated
909
so that only matching entries will be displayed.
819
911
TODO: Make --revision support uuid: and hash: [future tag:] notation.
823
915
takes_args = ['filename?']
824
takes_options = ['forward', 'timezone', 'verbose', 'show-ids', 'revision']
916
takes_options = ['forward', 'timezone', 'verbose', 'show-ids', 'revision','long', 'message']
826
918
def run(self, filename=None, timezone='original',
831
from bzrlib import show_log, find_branch
925
from bzrlib.branch import find_branch
926
from bzrlib.log import log_formatter, show_log
834
929
direction = (forward and 'forward') or 'reverse'
844
939
b = find_branch('.')
848
revision = [None, None]
849
elif isinstance(revision, int):
850
revision = [revision, revision]
945
elif len(revision) == 1:
946
rev1 = rev2 = b.get_revision_info(revision[0])[0]
947
elif len(revision) == 2:
948
rev1 = b.get_revision_info(revision[0])[0]
949
rev2 = b.get_revision_info(revision[1])[0]
855
assert len(revision) == 2
951
raise BzrCommandError('bzr log --revision takes one or two values.')
857
958
mutter('encoding log as %r' % bzrlib.user_encoding)
1017
1128
If no revision is specified this exports the last committed revision.
1019
1130
Format may be an "exporter" name, such as tar, tgz, tbz2. If none is
1020
given, exports to a directory (equivalent to --format=dir)."""
1131
given, try to find the format with the extension. If no extension
1132
is found exports to a directory (equivalent to --format=dir).
1134
Root may be the top directory for tar, tgz and tbz2 formats. If none
1135
is given, the top directory will be the root name of the file."""
1021
1136
# TODO: list known exporters
1022
1137
takes_args = ['dest']
1023
takes_options = ['revision', 'format']
1024
def run(self, dest, revision=None, format='dir'):
1026
if revision == None:
1027
rh = b.revision_history()[-1]
1138
takes_options = ['revision', 'format', 'root']
1139
def run(self, dest, revision=None, format=None, root=None):
1141
b = find_branch('.')
1142
if revision is None:
1143
rev_id = b.last_patch()
1029
rh = b.lookup_revision(int(revision))
1030
t = b.revision_tree(rh)
1031
t.export(dest, format)
1145
if len(revision) != 1:
1146
raise BzrError('bzr export --revision takes exactly 1 argument')
1147
revno, rev_id = b.get_revision_info(revision[0])
1148
t = b.revision_tree(rev_id)
1149
root, ext = os.path.splitext(dest)
1151
if ext in (".tar",):
1153
elif ext in (".gz", ".tgz"):
1155
elif ext in (".bz2", ".tbz2"):
1159
t.export(dest, format, root)
1034
1162
class cmd_cat(Command):
1068
1198
TODO: Strict commit that fails if there are unknown or deleted files.
1070
1200
takes_args = ['selected*']
1071
takes_options = ['message', 'file', 'verbose']
1201
takes_options = ['message', 'file', 'verbose', 'unchanged']
1072
1202
aliases = ['ci', 'checkin']
1074
def run(self, message=None, file=None, verbose=True, selected_list=None):
1075
from bzrlib.commit import commit
1204
def run(self, message=None, file=None, verbose=True, selected_list=None,
1206
from bzrlib.errors import PointlessCommit
1076
1207
from bzrlib.osutils import get_text_message
1078
1209
## Warning: shadows builtin file()
1097
1228
message = codecs.open(file, 'rt', bzrlib.user_encoding).read()
1100
commit(b, message, verbose=verbose, specific_files=selected_list)
1230
b = find_branch('.')
1233
b.commit(message, verbose=verbose,
1234
specific_files=selected_list,
1235
allow_pointless=unchanged)
1236
except PointlessCommit:
1237
# FIXME: This should really happen before the file is read in;
1238
# perhaps prepare the commit; get the message; then actually commit
1239
raise BzrCommandError("no changes to commit",
1240
["use --unchanged to commit anyhow"])
1103
1243
class cmd_check(Command):
1112
1252
takes_args = ['dir?']
1114
1254
def run(self, dir='.'):
1116
bzrlib.check.check(Branch(dir))
1255
from bzrlib.check import check
1256
check(find_branch(dir))
1260
class cmd_scan_cache(Command):
1263
from bzrlib.hashcache import HashCache
1270
print '%6d stats' % c.stat_count
1271
print '%6d in hashcache' % len(c._cache)
1272
print '%6d files removed from cache' % c.removed_count
1273
print '%6d hashes updated' % c.update_count
1274
print '%6d files changed too recently to cache' % c.danger_count
1120
1281
class cmd_upgrade(Command):
1260
1428
takes_options = ['revision']
1262
def run(self, revision=-1):
1430
def run(self, revision=None):
1263
1431
from bzrlib.merge import merge
1264
merge(('.', revision), parse_spec('.'),
1432
if revision is None:
1434
elif len(revision) != 1:
1435
raise BzrCommandError('bzr merge-revert --revision takes exactly 1 argument')
1436
merge(('.', revision[0]), parse_spec('.'),
1265
1437
check_clean=False,
1266
1438
ignore_zero=True)
1356
1529
>>> parse_args('commit --message=biter'.split())
1357
1530
(['commit'], {'message': u'biter'})
1358
1531
>>> parse_args('log -r 500'.split())
1359
(['log'], {'revision': 500})
1360
>>> parse_args('log -r500:600'.split())
1532
(['log'], {'revision': [500]})
1533
>>> parse_args('log -r500..600'.split())
1361
1534
(['log'], {'revision': [500, 600]})
1362
>>> parse_args('log -vr500:600'.split())
1535
>>> parse_args('log -vr500..600'.split())
1363
1536
(['log'], {'verbose': True, 'revision': [500, 600]})
1364
>>> parse_args('log -rv500:600'.split()) #the r takes an argument
1365
Traceback (most recent call last):
1367
ValueError: invalid literal for int(): v500
1537
>>> parse_args('log -rv500..600'.split()) #the r takes an argument
1538
(['log'], {'revision': ['v500', 600]})
1504
1675
This is also a non-master option.
1505
1676
--help Run help and exit, also a non-master option (I think that should stay, though)
1507
>>> argv, opts = _parse_master_args(['bzr', '--test'])
1678
>>> argv, opts = _parse_master_args(['--test'])
1508
1679
Traceback (most recent call last):
1510
1681
BzrCommandError: Invalid master option: 'test'
1511
>>> argv, opts = _parse_master_args(['bzr', '--version', 'command'])
1682
>>> argv, opts = _parse_master_args(['--version', 'command'])
1514
1685
>>> print opts['version']
1516
>>> argv, opts = _parse_master_args(['bzr', '--profile', 'command', '--more-options'])
1687
>>> argv, opts = _parse_master_args(['--profile', 'command', '--more-options'])
1518
1689
['command', '--more-options']
1519
1690
>>> print opts['profile']
1521
>>> argv, opts = _parse_master_args(['bzr', '--no-plugins', 'command'])
1692
>>> argv, opts = _parse_master_args(['--no-plugins', 'command'])
1524
1695
>>> print opts['no-plugins']
1526
1697
>>> print opts['profile']
1528
>>> argv, opts = _parse_master_args(['bzr', 'command', '--profile'])
1699
>>> argv, opts = _parse_master_args(['command', '--profile'])
1530
1701
['command', '--profile']
1531
1702
>>> print opts['profile']
1562
1729
This is similar to main(), but without all the trappings for
1563
1730
logging and error handling.
1733
The command-line arguments, without the program name.
1735
Returns a command status or raises an exception.
1565
1737
argv = [a.decode(bzrlib.user_encoding) for a in argv]
1739
# some options like --builtin and --no-plugins have special effects
1740
argv, master_opts = _parse_master_args(argv)
1741
if not master_opts['no-plugins']:
1742
from bzrlib.plugin import load_plugins
1745
args, opts = parse_args(argv)
1747
if master_opts.get('help') or 'help' in opts:
1748
from bzrlib.help import help
1755
if 'version' in opts:
1759
if args and args[0] == 'builtin':
1760
include_plugins=False
1568
# some options like --builtin and --no-plugins have special effects
1569
argv, master_opts = _parse_master_args(argv)
1570
if not master_opts['no-plugins']:
1571
bzrlib.load_plugins()
1573
args, opts = parse_args(argv)
1575
if master_opts['help']:
1576
from bzrlib.help import help
1584
from bzrlib.help import help
1590
elif 'version' in opts:
1593
elif args and args[0] == 'builtin':
1594
include_plugins=False
1596
1764
cmd = str(args.pop(0))
1597
1765
except IndexError:
1766
print >>sys.stderr, "please try 'bzr help' for help"
1603
1769
plugins_override = not (master_opts['builtin'])
1604
1770
canonical_cmd, cmd_class = get_cmd_class(cmd, plugins_override=plugins_override)