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
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('_','-')
54
55
def _parse_revision_str(revstr):
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' -> ?
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')
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])
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('..'):
296
332
directory is shown. Otherwise, only the status of the specified
297
333
files or directories is reported. If a directory is given, status
298
334
is reported for everything inside that directory.
336
If a revision is specified, the changes since that revision are shown.
300
338
takes_args = ['file*']
301
takes_options = ['all', 'show-ids']
339
takes_options = ['all', 'show-ids', 'revision']
302
340
aliases = ['st', 'stat']
304
342
def run(self, all=False, show_ids=False, file_list=None):
313
351
b = find_branch('.')
315
status.show_status(b, show_unchanged=all, show_ids=show_ids,
316
specific_files=file_list)
353
from bzrlib.status import show_status
354
show_status(b, show_unchanged=all, show_ids=show_ids,
355
specific_files=file_list)
319
358
class cmd_cat_revision(Command):
335
374
print find_branch('.').revno()
376
class cmd_revision_info(Command):
377
"""Show revision number and revision id for a given revision identifier.
380
takes_args = ['revision_info*']
381
takes_options = ['revision']
382
def run(self, revision=None, revision_info_list=None):
383
from bzrlib.branch import find_branch
386
if revision is not None:
387
revs.extend(revision)
388
if revision_info_list is not None:
389
revs.extend(revision_info_list)
391
raise BzrCommandError('You must supply a revision identifier')
396
print '%4d %s' % b.get_revision_info(rev)
338
399
class cmd_add(Command):
339
400
"""Add specified files or directories.
401
462
if revision == None:
402
463
inv = b.read_working_inventory()
404
inv = b.get_revision_inventory(b.lookup_revision(revision))
465
if len(revision) > 1:
466
raise BzrCommandError('bzr inventory --revision takes'
467
' exactly one revision identifier')
468
inv = b.get_revision_inventory(b.lookup_revision(revision[0]))
406
470
for path, entry in inv.entries():
556
626
br_to = Branch(to_location, init=True)
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)
628
br_to.set_root_id(br_from.get_root_id())
631
if revision[0] is None:
632
revno = br_from.revno()
634
revno, rev_id = br_from.get_revision_info(revision[0])
636
br_to.update_revisions(br_from, stop_revision=revno)
637
except NoSuchRevision:
639
msg = "The branch %s has no revision %d." % (from_location,
641
raise BzrCommandError(msg)
565
643
merge((to_location, -1), (to_location, 0), this_dir=to_location,
566
644
check_clean=False, ignore_zero=True)
567
645
from_location = pull_loc(br_from)
737
815
b = find_branch('.')
817
# TODO: Make show_diff support taking 2 arguments
819
if revision is not None:
820
if len(revision) != 1:
821
raise BzrCommandError('bzr diff --revision takes exactly one revision identifier')
822
base_rev = revision[0]
739
show_diff(b, revision, specific_files=file_list,
824
show_diff(b, base_rev, specific_files=file_list,
740
825
external_diff_options=diff_options)
770
855
"""List files modified in working tree."""
773
from bzrlib.statcache import update_cache, SC_SHA1
858
from bzrlib.diff import compare_trees
774
860
b = find_branch('.')
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.
861
td = compare_trees(b.basis_tree(), b.working_tree())
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)
863
for path, id, kind in td.modified:
830
902
-r revision requests a specific revision, -r :end or -r begin: are
905
--message allows you to give a regular expression, which will be evaluated
906
so that only matching entries will be displayed.
833
908
TODO: Make --revision support uuid: and hash: [future tag:] notation.
837
912
takes_args = ['filename?']
838
takes_options = ['forward', 'timezone', 'verbose', 'show-ids', 'revision','long']
913
takes_options = ['forward', 'timezone', 'verbose', 'show-ids', 'revision','long', 'message']
840
915
def run(self, filename=None, timezone='original',
846
922
from bzrlib.branch import find_branch
847
923
from bzrlib.log import log_formatter, show_log
860
936
b = find_branch('.')
864
revision = [None, None]
865
elif isinstance(revision, int):
866
revision = [revision, revision]
942
elif len(revision) == 1:
943
rev1 = rev2 = b.get_revision_info(revision[0])[0]
944
elif len(revision) == 2:
945
rev1 = b.get_revision_info(revision[0])[0]
946
rev2 = b.get_revision_info(revision[1])[0]
871
assert len(revision) == 2
948
raise BzrCommandError('bzr log --revision takes one or two values.')
873
955
mutter('encoding log as %r' % bzrlib.user_encoding)
1042
1125
If no revision is specified this exports the last committed revision.
1044
1127
Format may be an "exporter" name, such as tar, tgz, tbz2. If none is
1045
given, exports to a directory (equivalent to --format=dir)."""
1128
given, try to find the format with the extension. If no extension
1129
is found exports to a directory (equivalent to --format=dir).
1131
Root may be the top directory for tar, tgz and tbz2 formats. If none
1132
is given, the top directory will be the root name of the file."""
1046
1133
# TODO: list known exporters
1047
1134
takes_args = ['dest']
1048
takes_options = ['revision', 'format']
1049
def run(self, dest, revision=None, format='dir'):
1135
takes_options = ['revision', 'format', 'root']
1136
def run(self, dest, revision=None, format=None, root=None):
1050
1138
b = find_branch('.')
1051
if revision == None:
1052
rh = b.revision_history()[-1]
1139
if revision is None:
1140
rev_id = b.last_patch()
1054
rh = b.lookup_revision(int(revision))
1055
t = b.revision_tree(rh)
1056
t.export(dest, format)
1142
if len(revision) != 1:
1143
raise BzrError('bzr export --revision takes exactly 1 argument')
1144
revno, rev_id = b.get_revision_info(revision[0])
1145
t = b.revision_tree(rev_id)
1146
root, ext = os.path.splitext(dest)
1148
if ext in (".tar",):
1150
elif ext in (".gz", ".tgz"):
1152
elif ext in (".bz2", ".tbz2"):
1156
t.export(dest, format, root)
1059
1159
class cmd_cat(Command):
1065
1165
def run(self, filename, revision=None):
1066
1166
if revision == None:
1067
1167
raise BzrCommandError("bzr cat requires a revision number")
1168
elif len(revision) != 1:
1169
raise BzrCommandError("bzr cat --revision takes exactly one number")
1068
1170
b = find_branch('.')
1069
b.print_file(b.relpath(filename), int(revision))
1171
b.print_file(b.relpath(filename), revision[0])
1072
1174
class cmd_local_time_offset(Command):
1093
1195
TODO: Strict commit that fails if there are unknown or deleted files.
1095
1197
takes_args = ['selected*']
1096
takes_options = ['message', 'file', 'verbose']
1198
takes_options = ['message', 'file', 'verbose', 'unchanged']
1097
1199
aliases = ['ci', 'checkin']
1099
def run(self, message=None, file=None, verbose=True, selected_list=None):
1100
from bzrlib.commit import commit
1201
def run(self, message=None, file=None, verbose=True, selected_list=None,
1203
from bzrlib.errors import PointlessCommit
1101
1204
from bzrlib.osutils import get_text_message
1103
1206
## Warning: shadows builtin file()
1122
1225
message = codecs.open(file, 'rt', bzrlib.user_encoding).read()
1124
1227
b = find_branch('.')
1125
commit(b, message, verbose=verbose, specific_files=selected_list)
1230
b.commit(message, verbose=verbose,
1231
specific_files=selected_list,
1232
allow_pointless=unchanged)
1233
except PointlessCommit:
1234
# FIXME: This should really happen before the file is read in;
1235
# perhaps prepare the commit; get the message; then actually commit
1236
raise BzrCommandError("no changes to commit",
1237
["use --unchanged to commit anyhow"])
1128
1240
class cmd_check(Command):
1257
class cmd_scan_cache(Command):
1260
from bzrlib.hashcache import HashCache
1267
print '%6d stats' % c.stat_count
1268
print '%6d in hashcache' % len(c._cache)
1269
print '%6d files removed from cache' % c.removed_count
1270
print '%6d hashes updated' % c.update_count
1271
print '%6d files changed too recently to cache' % c.danger_count
1145
1278
class cmd_upgrade(Command):
1146
1279
"""Upgrade branch storage to current format.
1170
1303
class cmd_selftest(Command):
1171
1304
"""Run internal test suite"""
1306
takes_options = ['verbose']
1307
def run(self, verbose=False):
1174
1308
from bzrlib.selftest import selftest
1175
return int(not selftest())
1309
return int(not selftest(verbose=verbose))
1178
1312
class cmd_version(Command):
1285
1425
takes_options = ['revision']
1287
def run(self, revision=-1):
1427
def run(self, revision=None):
1288
1428
from bzrlib.merge import merge
1289
merge(('.', revision), parse_spec('.'),
1429
if revision is None:
1431
elif len(revision) != 1:
1432
raise BzrCommandError('bzr merge-revert --revision takes exactly 1 argument')
1433
merge(('.', revision[0]), parse_spec('.'),
1290
1434
check_clean=False,
1291
1435
ignore_zero=True)
1329
1463
import bzrlib.plugin
1464
from inspect import getdoc
1330
1465
from pprint import pprint
1331
pprint(bzrlib.plugin.all_plugins)
1466
for plugin in bzrlib.plugin.all_plugins:
1467
print plugin.__path__[0]
1470
print '\t', d.split('\n')[0]
1472
#pprint(bzrlib.plugin.all_plugins)
1383
1526
>>> parse_args('commit --message=biter'.split())
1384
1527
(['commit'], {'message': u'biter'})
1385
1528
>>> parse_args('log -r 500'.split())
1386
(['log'], {'revision': 500})
1387
>>> parse_args('log -r500:600'.split())
1529
(['log'], {'revision': [500]})
1530
>>> parse_args('log -r500..600'.split())
1388
1531
(['log'], {'revision': [500, 600]})
1389
>>> parse_args('log -vr500:600'.split())
1532
>>> parse_args('log -vr500..600'.split())
1390
1533
(['log'], {'verbose': True, 'revision': [500, 600]})
1391
>>> parse_args('log -rv500:600'.split()) #the r takes an argument
1392
Traceback (most recent call last):
1394
ValueError: invalid literal for int(): v500
1534
>>> parse_args('log -rv500..600'.split()) #the r takes an argument
1535
(['log'], {'revision': ['v500', 600]})