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)
1142
1042
If no revision is specified this exports the last committed revision.
1144
1044
Format may be an "exporter" name, such as tar, tgz, tbz2. If none is
1145
given, try to find the format with the extension. If no extension
1146
is found exports to a directory (equivalent to --format=dir).
1045
given, exports to a directory (equivalent to --format=dir).
1148
Root may be the top directory for tar, tgz and tbz2 formats. If none
1149
is given, the top directory will be the root name of the file."""
1047
Root may be the top directory for tar, tgz and tbz2 formats."""
1150
1048
# TODO: list known exporters
1151
1049
takes_args = ['dest']
1152
1050
takes_options = ['revision', 'format', 'root']
1153
def run(self, dest, revision=None, format=None, root=None):
1051
def run(self, dest, revision=None, format='dir', root=None):
1155
1052
b = find_branch('.')
1156
if revision is None:
1157
rev_id = b.last_patch()
1053
if revision == None:
1054
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)
1163
root, ext = os.path.splitext(dest)
1165
if ext in (".tar",):
1167
elif ext in (".gz", ".tgz"):
1169
elif ext in (".bz2", ".tbz2"):
1056
rh = b.lookup_revision(int(revision))
1057
t = b.revision_tree(rh)
1173
1058
t.export(dest, format, root)
1182
1067
def run(self, filename, revision=None):
1183
1068
if revision == None:
1184
1069
raise BzrCommandError("bzr cat requires a revision number")
1185
elif len(revision) != 1:
1186
raise BzrCommandError("bzr cat --revision takes exactly one number")
1187
1070
b = find_branch('.')
1188
b.print_file(b.relpath(filename), revision[0])
1071
b.print_file(b.relpath(filename), int(revision))
1191
1074
class cmd_local_time_offset(Command):
1212
1095
TODO: Strict commit that fails if there are unknown or deleted files.
1214
1097
takes_args = ['selected*']
1215
takes_options = ['message', 'file', 'verbose', 'unchanged']
1098
takes_options = ['message', 'file', 'verbose']
1216
1099
aliases = ['ci', 'checkin']
1218
def run(self, message=None, file=None, verbose=True, selected_list=None,
1220
from bzrlib.errors import PointlessCommit
1101
def run(self, message=None, file=None, verbose=True, selected_list=None):
1102
from bzrlib.commit import commit
1221
1103
from bzrlib.osutils import get_text_message
1223
1105
## Warning: shadows builtin file()
1242
1124
message = codecs.open(file, 'rt', bzrlib.user_encoding).read()
1244
1126
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"])
1127
commit(b, message, verbose=verbose, specific_files=selected_list)
1257
1130
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
1147
class cmd_upgrade(Command):
1296
1148
"""Upgrade branch storage to current format.
1320
1172
class cmd_selftest(Command):
1321
1173
"""Run internal test suite"""
1323
takes_options = ['verbose']
1324
def run(self, verbose=False):
1325
1176
from bzrlib.selftest import selftest
1326
return int(not selftest(verbose=verbose))
1177
return int(not selftest())
1329
1180
class cmd_version(Command):
1407
1252
--force is given.
1409
1254
takes_args = ['other_spec', 'base_spec?']
1410
takes_options = ['force', 'merge-type']
1255
takes_options = ['force']
1412
def run(self, other_spec, base_spec=None, force=False, merge_type=None):
1257
def run(self, other_spec, base_spec=None, force=False):
1413
1258
from bzrlib.merge import merge
1414
from bzrlib.merge_core import ApplyMerge3
1415
if merge_type is None:
1416
merge_type = ApplyMerge3
1417
1259
merge(parse_spec(other_spec), parse_spec(base_spec),
1418
check_clean=(not force), merge_type=merge_type)
1260
check_clean=(not force))
1437
1279
class cmd_merge_revert(Command):
1438
1280
"""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.
1282
Only versioned files are affected.
1284
TODO: Store backups of any files that will be reverted, so
1285
that the revert can be undone.
1443
takes_options = ['revision', 'no-backup']
1287
takes_options = ['revision']
1445
def run(self, revision=None, no_backup=False):
1289
def run(self, revision=-1):
1446
1290
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('.'),
1291
merge(('.', revision), parse_spec('.'),
1452
1292
check_clean=False,
1454
backup_files=not no_backup)
1457
1296
class cmd_assert_fail(Command):
1547
1386
>>> parse_args('commit --message=biter'.split())
1548
1387
(['commit'], {'message': u'biter'})
1549
1388
>>> parse_args('log -r 500'.split())
1550
(['log'], {'revision': [500]})
1551
>>> parse_args('log -r500..600'.split())
1389
(['log'], {'revision': 500})
1390
>>> parse_args('log -r500:600'.split())
1552
1391
(['log'], {'revision': [500, 600]})
1553
>>> parse_args('log -vr500..600'.split())
1392
>>> parse_args('log -vr500:600'.split())
1554
1393
(['log'], {'verbose': True, 'revision': [500, 600]})
1555
>>> parse_args('log -rv500..600'.split()) #the r takes an argument
1556
(['log'], {'revision': ['v500', 600]})
1394
>>> parse_args('log -rv500:600'.split()) #the r takes an argument
1395
Traceback (most recent call last):
1397
ValueError: invalid literal for int(): v500
1693
1534
This is also a non-master option.
1694
1535
--help Run help and exit, also a non-master option (I think that should stay, though)
1696
>>> argv, opts = _parse_master_args(['--test'])
1537
>>> argv, opts = _parse_master_args(['bzr', '--test'])
1697
1538
Traceback (most recent call last):
1699
1540
BzrCommandError: Invalid master option: 'test'
1700
>>> argv, opts = _parse_master_args(['--version', 'command'])
1541
>>> argv, opts = _parse_master_args(['bzr', '--version', 'command'])
1703
1544
>>> print opts['version']
1705
>>> argv, opts = _parse_master_args(['--profile', 'command', '--more-options'])
1546
>>> argv, opts = _parse_master_args(['bzr', '--profile', 'command', '--more-options'])
1707
1548
['command', '--more-options']
1708
1549
>>> print opts['profile']
1710
>>> argv, opts = _parse_master_args(['--no-plugins', 'command'])
1551
>>> argv, opts = _parse_master_args(['bzr', '--no-plugins', 'command'])
1713
1554
>>> print opts['no-plugins']
1715
1556
>>> print opts['profile']
1717
>>> argv, opts = _parse_master_args(['command', '--profile'])
1558
>>> argv, opts = _parse_master_args(['bzr', 'command', '--profile'])
1719
1560
['command', '--profile']
1720
1561
>>> print opts['profile']
1747
1592
This is similar to main(), but without all the trappings for
1748
1593
logging and error handling.
1751
The command-line arguments, without the program name.
1753
Returns a command status or raises an exception.
1755
1595
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
1598
# some options like --builtin and --no-plugins have special effects
1599
argv, master_opts = _parse_master_args(argv)
1600
if not master_opts['no-plugins']:
1601
from bzrlib.plugin import load_plugins
1604
args, opts = parse_args(argv)
1606
if master_opts['help']:
1607
from bzrlib.help import help
1615
from bzrlib.help import help
1621
elif 'version' in opts:
1624
elif args and args[0] == 'builtin':
1625
include_plugins=False
1782
1627
cmd = str(args.pop(0))
1783
1628
except IndexError:
1784
print >>sys.stderr, "please try 'bzr help' for help"
1787
1634
plugins_override = not (master_opts['builtin'])
1788
1635
canonical_cmd, cmd_class = get_cmd_class(cmd, plugins_override=plugins_override)