22
from bzrlib.trace import mutter, note, log_error, warning
22
from bzrlib.trace import mutter, note, log_error
23
23
from bzrlib.errors import BzrError, BzrCheckError, BzrCommandError
24
24
from bzrlib.branch import find_branch
25
25
from bzrlib import BZRDIR
51
51
assert cmd.startswith("cmd_")
52
52
return cmd[4:].replace('_','-')
55
54
def _parse_revision_str(revstr):
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')
55
"""This handles a revision string -> revno.
57
There are several possibilities:
60
'234:345' -> [234, 345]
64
In the future we will also support:
65
'uuid:blah-blah-blah' -> ?
66
'hash:blahblahblah' -> ?
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('..'):
70
if revstr.find(':') != -1:
71
revs = revstr.split(':')
73
raise ValueError('More than 2 pieces not supported for --revision: %r' % revstr)
78
revs[0] = int(revs[0])
83
revs[1] = int(revs[1])
125
def get_merge_type(typestring):
126
"""Attempt to find the merge class/factory associated with a string."""
127
from merge import merge_types
129
return merge_types[typestring][0]
131
templ = '%s%%7s: %%s' % (' '*12)
132
lines = [templ % (f[0], f[1][1]) for f in merge_types.iteritems()]
133
type_list = '\n'.join(lines)
134
msg = "No known merge type %s. Supported types are:\n%s" %\
135
(typestring, type_list)
136
raise BzrCommandError(msg)
140
90
def _get_cmd_dict(plugins_override=True):
214
164
assert isinstance(arguments, dict)
215
165
cmdargs = options.copy()
216
166
cmdargs.update(arguments)
217
if self.__doc__ == Command.__doc__:
218
from warnings import warn
219
warn("No help message set for %r" % self)
167
assert self.__doc__ != Command.__doc__, \
168
("No help message set for %r" % self)
220
169
self.status = self.run(**cmdargs)
221
if self.status is None:
349
296
directory is shown. Otherwise, only the status of the specified
350
297
files or directories is reported. If a directory is given, status
351
298
is reported for everything inside that directory.
353
If a revision is specified, the changes since that revision are shown.
355
300
takes_args = ['file*']
356
takes_options = ['all', 'show-ids', 'revision']
301
takes_options = ['all', 'show-ids']
357
302
aliases = ['st', 'stat']
359
304
def run(self, all=False, show_ids=False, file_list=None):
368
313
b = find_branch('.')
370
from bzrlib.status import show_status
371
show_status(b, show_unchanged=all, show_ids=show_ids,
372
specific_files=file_list)
315
status.show_status(b, show_unchanged=all, show_ids=show_ids,
316
specific_files=file_list)
375
319
class cmd_cat_revision(Command):
391
335
print find_branch('.').revno()
393
class cmd_revision_info(Command):
394
"""Show revision number and revision id for a given revision identifier.
397
takes_args = ['revision_info*']
398
takes_options = ['revision']
399
def run(self, revision=None, revision_info_list=None):
400
from bzrlib.branch import find_branch
403
if revision is not None:
404
revs.extend(revision)
405
if revision_info_list is not None:
406
revs.extend(revision_info_list)
408
raise BzrCommandError('You must supply a revision identifier')
413
print '%4d %s' % b.get_revision_info(rev)
416
338
class cmd_add(Command):
417
339
"""Add specified files or directories.
426
348
whether already versioned or not, are searched for files or
427
349
subdirectories that are neither versioned or ignored, and these
428
350
are added. This search proceeds recursively into versioned
429
directories. If no names are given '.' is assumed.
431
Therefore simply saying 'bzr add' will version all files that
353
Therefore simply saying 'bzr add .' will version all files that
432
354
are currently unknown.
434
356
TODO: Perhaps adding a file whose directly is not versioned should
435
357
recursively add that parent, rather than giving an error?
437
takes_args = ['file*']
359
takes_args = ['file+']
438
360
takes_options = ['verbose', 'no-recurse']
440
362
def run(self, file_list, verbose=False, no_recurse=False):
643
556
br_to = Branch(to_location, init=True)
645
br_to.set_root_id(br_from.get_root_id())
648
if revision[0] is None:
649
revno = br_from.revno()
651
revno, rev_id = br_from.get_revision_info(revision[0])
653
br_to.update_revisions(br_from, stop_revision=revno)
654
except NoSuchRevision:
656
msg = "The branch %s has no revision %d." % (from_location,
658
raise BzrCommandError(msg)
559
br_to.update_revisions(br_from, stop_revision=revision)
560
except NoSuchRevision:
562
msg = "The branch %s has no revision %d." % (from_location,
564
raise BzrCommandError(msg)
660
565
merge((to_location, -1), (to_location, 0), this_dir=to_location,
661
566
check_clean=False, ignore_zero=True)
662
567
from_location = pull_loc(br_from)
832
737
b = find_branch('.')
834
# TODO: Make show_diff support taking 2 arguments
836
if revision is not None:
837
if len(revision) != 1:
838
raise BzrCommandError('bzr diff --revision takes exactly one revision identifier')
839
base_rev = revision[0]
841
show_diff(b, base_rev, specific_files=file_list,
739
show_diff(b, revision, specific_files=file_list,
842
740
external_diff_options=diff_options)
872
770
"""List files modified in working tree."""
875
from bzrlib.diff import compare_trees
773
from bzrlib.statcache import update_cache, SC_SHA1
877
774
b = find_branch('.')
878
td = compare_trees(b.basis_tree(), b.working_tree())
775
inv = b.read_working_inventory()
776
sc = update_cache(b, inv)
777
basis = b.basis_tree()
778
basis_inv = basis.inventory
780
# We used to do this through iter_entries(), but that's slow
781
# when most of the files are unmodified, as is usually the
782
# case. So instead we iterate by inventory entry, and only
783
# calculate paths as necessary.
880
for path, id, kind in td.modified:
785
for file_id in basis_inv:
786
cacheentry = sc.get(file_id)
787
if not cacheentry: # deleted
789
ie = basis_inv[file_id]
790
if cacheentry[SC_SHA1] != ie.text_sha1:
791
path = inv.id2path(file_id)
919
830
-r revision requests a specific revision, -r :end or -r begin: are
922
--message allows you to give a regular expression, which will be evaluated
923
so that only matching entries will be displayed.
925
833
TODO: Make --revision support uuid: and hash: [future tag:] notation.
929
837
takes_args = ['filename?']
930
takes_options = ['forward', 'timezone', 'verbose', 'show-ids', 'revision','long', 'message']
838
takes_options = ['forward', 'timezone', 'verbose', 'show-ids', 'revision','long']
932
840
def run(self, filename=None, timezone='original',
939
846
from bzrlib.branch import find_branch
940
847
from bzrlib.log import log_formatter, show_log
953
860
b = find_branch('.')
959
elif len(revision) == 1:
960
rev1 = rev2 = b.get_revision_info(revision[0])[0]
961
elif len(revision) == 2:
962
rev1 = b.get_revision_info(revision[0])[0]
963
rev2 = b.get_revision_info(revision[1])[0]
864
revision = [None, None]
865
elif isinstance(revision, int):
866
revision = [revision, revision]
965
raise BzrCommandError('bzr log --revision takes one or two values.')
871
assert len(revision) == 2
972
873
mutter('encoding log as %r' % bzrlib.user_encoding)
1153
1053
def run(self, dest, revision=None, format=None, root=None):
1155
1055
b = find_branch('.')
1156
if revision is None:
1157
rev_id = b.last_patch()
1056
if revision == None:
1057
rh = b.revision_history()[-1]
1159
if len(revision) != 1:
1160
raise BzrError('bzr export --revision takes exactly 1 argument')
1161
revno, rev_id = b.get_revision_info(revision[0])
1162
t = b.revision_tree(rev_id)
1059
rh = b.lookup_revision(int(revision))
1060
t = b.revision_tree(rh)
1163
1061
root, ext = os.path.splitext(dest)
1165
1063
if ext in (".tar",):
1182
1080
def run(self, filename, revision=None):
1183
1081
if revision == None:
1184
1082
raise BzrCommandError("bzr cat requires a revision number")
1185
elif len(revision) != 1:
1186
raise BzrCommandError("bzr cat --revision takes exactly one number")
1187
1083
b = find_branch('.')
1188
b.print_file(b.relpath(filename), revision[0])
1084
b.print_file(b.relpath(filename), int(revision))
1191
1087
class cmd_local_time_offset(Command):
1212
1108
TODO: Strict commit that fails if there are unknown or deleted files.
1214
1110
takes_args = ['selected*']
1215
takes_options = ['message', 'file', 'verbose', 'unchanged']
1111
takes_options = ['message', 'file', 'verbose']
1216
1112
aliases = ['ci', 'checkin']
1218
def run(self, message=None, file=None, verbose=True, selected_list=None,
1220
from bzrlib.errors import PointlessCommit
1114
def run(self, message=None, file=None, verbose=True, selected_list=None):
1115
from bzrlib.commit import commit
1221
1116
from bzrlib.osutils import get_text_message
1223
1118
## Warning: shadows builtin file()
1242
1137
message = codecs.open(file, 'rt', bzrlib.user_encoding).read()
1244
1139
b = find_branch('.')
1247
b.commit(message, verbose=verbose,
1248
specific_files=selected_list,
1249
allow_pointless=unchanged)
1250
except PointlessCommit:
1251
# FIXME: This should really happen before the file is read in;
1252
# perhaps prepare the commit; get the message; then actually commit
1253
raise BzrCommandError("no changes to commit",
1254
["use --unchanged to commit anyhow"])
1140
commit(b, message, verbose=verbose, specific_files=selected_list)
1257
1143
class cmd_check(Command):
1274
class cmd_scan_cache(Command):
1277
from bzrlib.hashcache import HashCache
1284
print '%6d stats' % c.stat_count
1285
print '%6d in hashcache' % len(c._cache)
1286
print '%6d files removed from cache' % c.removed_count
1287
print '%6d hashes updated' % c.update_count
1288
print '%6d files changed too recently to cache' % c.danger_count
1295
1160
class cmd_upgrade(Command):
1296
1161
"""Upgrade branch storage to current format.
1320
1185
class cmd_selftest(Command):
1321
1186
"""Run internal test suite"""
1323
takes_options = ['verbose']
1324
def run(self, verbose=False):
1325
1189
from bzrlib.selftest import selftest
1326
return int(not selftest(verbose=verbose))
1190
return int(not selftest())
1329
1193
class cmd_version(Command):
1407
1265
--force is given.
1409
1267
takes_args = ['other_spec', 'base_spec?']
1410
takes_options = ['force', 'merge-type']
1268
takes_options = ['force']
1412
def run(self, other_spec, base_spec=None, force=False, merge_type=None):
1270
def run(self, other_spec, base_spec=None, force=False):
1413
1271
from bzrlib.merge import merge
1414
from bzrlib.merge_core import ApplyMerge3
1415
if merge_type is None:
1416
merge_type = ApplyMerge3
1417
1272
merge(parse_spec(other_spec), parse_spec(base_spec),
1418
check_clean=(not force), merge_type=merge_type)
1273
check_clean=(not force))
1437
1292
class cmd_merge_revert(Command):
1438
1293
"""Reverse all changes since the last commit.
1440
Only versioned files are affected. By default, any files that are changed
1441
will be backed up first. Backup files have a '~' appended to their name.
1295
Only versioned files are affected.
1297
TODO: Store backups of any files that will be reverted, so
1298
that the revert can be undone.
1443
takes_options = ['revision', 'no-backup']
1300
takes_options = ['revision']
1445
def run(self, revision=None, no_backup=False):
1302
def run(self, revision=-1):
1446
1303
from bzrlib.merge import merge
1447
if revision is None:
1449
elif len(revision) != 1:
1450
raise BzrCommandError('bzr merge-revert --revision takes exactly 1 argument')
1451
merge(('.', revision[0]), parse_spec('.'),
1304
merge(('.', revision), parse_spec('.'),
1452
1305
check_clean=False,
1454
backup_files=not no_backup)
1457
1309
class cmd_assert_fail(Command):
1547
1399
>>> parse_args('commit --message=biter'.split())
1548
1400
(['commit'], {'message': u'biter'})
1549
1401
>>> parse_args('log -r 500'.split())
1550
(['log'], {'revision': [500]})
1551
>>> parse_args('log -r500..600'.split())
1402
(['log'], {'revision': 500})
1403
>>> parse_args('log -r500:600'.split())
1552
1404
(['log'], {'revision': [500, 600]})
1553
>>> parse_args('log -vr500..600'.split())
1405
>>> parse_args('log -vr500:600'.split())
1554
1406
(['log'], {'verbose': True, 'revision': [500, 600]})
1555
>>> parse_args('log -rv500..600'.split()) #the r takes an argument
1556
(['log'], {'revision': ['v500', 600]})
1407
>>> parse_args('log -rv500:600'.split()) #the r takes an argument
1408
Traceback (most recent call last):
1410
ValueError: invalid literal for int(): v500
1693
1547
This is also a non-master option.
1694
1548
--help Run help and exit, also a non-master option (I think that should stay, though)
1696
>>> argv, opts = _parse_master_args(['--test'])
1550
>>> argv, opts = _parse_master_args(['bzr', '--test'])
1697
1551
Traceback (most recent call last):
1699
1553
BzrCommandError: Invalid master option: 'test'
1700
>>> argv, opts = _parse_master_args(['--version', 'command'])
1554
>>> argv, opts = _parse_master_args(['bzr', '--version', 'command'])
1703
1557
>>> print opts['version']
1705
>>> argv, opts = _parse_master_args(['--profile', 'command', '--more-options'])
1559
>>> argv, opts = _parse_master_args(['bzr', '--profile', 'command', '--more-options'])
1707
1561
['command', '--more-options']
1708
1562
>>> print opts['profile']
1710
>>> argv, opts = _parse_master_args(['--no-plugins', 'command'])
1564
>>> argv, opts = _parse_master_args(['bzr', '--no-plugins', 'command'])
1713
1567
>>> print opts['no-plugins']
1715
1569
>>> print opts['profile']
1717
>>> argv, opts = _parse_master_args(['command', '--profile'])
1571
>>> argv, opts = _parse_master_args(['bzr', 'command', '--profile'])
1719
1573
['command', '--profile']
1720
1574
>>> print opts['profile']
1747
1605
This is similar to main(), but without all the trappings for
1748
1606
logging and error handling.
1751
The command-line arguments, without the program name.
1753
Returns a command status or raises an exception.
1755
1608
argv = [a.decode(bzrlib.user_encoding) for a in argv]
1757
# some options like --builtin and --no-plugins have special effects
1758
argv, master_opts = _parse_master_args(argv)
1759
if not master_opts['no-plugins']:
1760
from bzrlib.plugin import load_plugins
1763
args, opts = parse_args(argv)
1765
if master_opts.get('help') or 'help' in opts:
1766
from bzrlib.help import help
1773
if 'version' in opts:
1777
if args and args[0] == 'builtin':
1778
include_plugins=False
1611
# some options like --builtin and --no-plugins have special effects
1612
argv, master_opts = _parse_master_args(argv)
1613
if not master_opts['no-plugins']:
1614
from bzrlib.plugin import load_plugins
1617
args, opts = parse_args(argv)
1619
if master_opts['help']:
1620
from bzrlib.help import help
1628
from bzrlib.help import help
1634
elif 'version' in opts:
1637
elif args and args[0] == 'builtin':
1638
include_plugins=False
1782
1640
cmd = str(args.pop(0))
1783
1641
except IndexError:
1784
print >>sys.stderr, "please try 'bzr help' for help"
1787
1647
plugins_override = not (master_opts['builtin'])
1788
1648
canonical_cmd, cmd_class = get_cmd_class(cmd, plugins_override=plugins_override)