22
from bzrlib.trace import mutter, note, log_error
23
from bzrlib.errors import bailout, BzrError, BzrCheckError, BzrCommandError
24
from bzrlib.osutils import quotefn, pumpfile, isdir, isfile
25
from bzrlib.tree import RevisionTree, EmptyTree, Tree
26
from bzrlib.revision import Revision
27
from bzrlib import Branch, Inventory, InventoryEntry, ScratchBranch, BZRDIR, \
29
from bzrlib import merge
22
from bzrlib.trace import mutter, note, log_error, warning
23
from bzrlib.errors import BzrError, BzrCheckError, BzrCommandError
24
from bzrlib.branch import find_branch
25
from bzrlib import BZRDIR
31
def register_command(cmd):
32
"Utility function to help register a command"
35
if k.startswith("cmd_"):
36
k_unsquished = _unsquish_command_name(k)
39
if not plugin_cmds.has_key(k_unsquished):
40
plugin_cmds[k_unsquished] = cmd
42
log_error('Two plugins defined the same command: %r' % k)
43
log_error('Not loading the one in %r' % sys.modules[cmd.__module__])
32
46
def _squish_command_name(cmd):
37
51
assert cmd.startswith("cmd_")
38
52
return cmd[4:].replace('_','-')
40
55
def _parse_revision_str(revstr):
41
"""This handles a revision string -> revno.
43
There are several possibilities:
46
'234:345' -> [234, 345]
50
In the future we will also support:
51
'uuid:blah-blah-blah' -> ?
52
'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')
56
if revstr.find(':') != -1:
57
revs = revstr.split(':')
59
raise ValueError('More than 2 pieces not supported for --revision: %r' % revstr)
64
revs[0] = int(revs[0])
69
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('..'):
75
"""Return canonical name and class for all registered commands."""
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
def _get_cmd_dict(plugins_override=True):
76
142
for k, v in globals().iteritems():
77
143
if k.startswith("cmd_"):
78
yield _unsquish_command_name(k), v
80
def get_cmd_class(cmd):
144
d[_unsquish_command_name(k)] = v
145
# If we didn't load plugins, the plugin_cmds dict will be empty
147
d.update(plugin_cmds)
149
d2 = plugin_cmds.copy()
155
def get_all_cmds(plugins_override=True):
156
"""Return canonical name and class for all registered commands."""
157
for k, v in _get_cmd_dict(plugins_override=plugins_override).iteritems():
161
def get_cmd_class(cmd, plugins_override=True):
81
162
"""Return the canonical name and command class for a command.
83
164
cmd = str(cmd) # not unicode
85
166
# first look up this command under the specified name
167
cmds = _get_cmd_dict(plugins_override=plugins_override)
87
return cmd, globals()[_squish_command_name(cmd)]
169
return cmd, cmds[cmd]
91
173
# look for any command which claims this as an alias
92
for cmdname, cmdclass in get_all_cmds():
174
for cmdname, cmdclass in cmds.iteritems():
93
175
if cmd in cmdclass.aliases:
94
176
return cmdname, cmdclass
180
265
def __init__(self, path):
183
# TODO: If either of these fail, we should detect that and
184
# assume that path is not really a bzr plugin after all.
186
268
pipe = os.popen('%s --bzr-usage' % path, 'r')
187
269
self.takes_options = pipe.readline().split()
271
for opt in self.takes_options:
272
if not opt in OPTIONS:
273
raise BzrError("Unknown option '%s' returned by external command %s"
276
# TODO: Is there any way to check takes_args is valid here?
188
277
self.takes_args = pipe.readline().split()
279
if pipe.close() is not None:
280
raise BzrError("Failed funning '%s --bzr-usage'" % path)
191
282
pipe = os.popen('%s --bzr-help' % path, 'r')
192
283
self.__doc__ = pipe.read()
284
if pipe.close() is not None:
285
raise BzrError("Failed funning '%s --bzr-help'" % path)
195
287
def __call__(self, options, arguments):
196
288
Command.__init__(self, options, arguments)
256
349
directory is shown. Otherwise, only the status of the specified
257
350
files or directories is reported. If a directory is given, status
258
351
is reported for everything inside that directory.
353
If a revision is specified, the changes since that revision are shown.
260
355
takes_args = ['file*']
261
takes_options = ['all', 'show-ids']
356
takes_options = ['all', 'show-ids', 'revision']
262
357
aliases = ['st', 'stat']
264
359
def run(self, all=False, show_ids=False, file_list=None):
266
b = Branch(file_list[0], lock_mode='r')
361
b = find_branch(file_list[0])
267
362
file_list = [b.relpath(x) for x in file_list]
268
363
# special case: only one path was given and it's the root
270
365
if file_list == ['']:
273
b = Branch('.', lock_mode='r')
275
status.show_status(b, show_unchanged=all, show_ids=show_ids,
276
specific_files=file_list)
370
from bzrlib.status import show_status
371
show_status(b, show_unchanged=all, show_ids=show_ids,
372
specific_files=file_list)
279
375
class cmd_cat_revision(Command):
307
426
whether already versioned or not, are searched for files or
308
427
subdirectories that are neither versioned or ignored, and these
309
428
are added. This search proceeds recursively into versioned
429
directories. If no names are given '.' is assumed.
312
Therefore simply saying 'bzr add .' will version all files that
431
Therefore simply saying 'bzr add' will version all files that
313
432
are currently unknown.
315
434
TODO: Perhaps adding a file whose directly is not versioned should
316
435
recursively add that parent, rather than giving an error?
318
takes_args = ['file+']
319
takes_options = ['verbose']
437
takes_args = ['file*']
438
takes_options = ['verbose', 'no-recurse']
321
def run(self, file_list, verbose=False):
322
bzrlib.add.smart_add(file_list, verbose)
440
def run(self, file_list, verbose=False, no_recurse=False):
441
from bzrlib.add import smart_add
442
smart_add(file_list, verbose, not no_recurse)
446
class cmd_mkdir(Command):
447
"""Create a new versioned directory.
449
This is equivalent to creating the directory and then adding it.
451
takes_args = ['dir+']
453
def run(self, dir_list):
460
b.add([d], verbose=True)
325
463
class cmd_relpath(Command):
326
464
"""Show path of a file relative to root"""
327
465
takes_args = ['filename']
329
468
def run(self, filename):
330
print Branch(filename).relpath(filename)
469
print find_branch(filename).relpath(filename)
334
473
class cmd_inventory(Command):
335
474
"""Show inventory of the current working copy or a revision."""
336
takes_options = ['revision']
475
takes_options = ['revision', 'show-ids']
338
def run(self, revision=None):
477
def run(self, revision=None, show_ids=False):
340
479
if revision == None:
341
480
inv = b.read_working_inventory()
343
inv = b.get_revision_inventory(b.lookup_revision(revision))
482
if len(revision) > 1:
483
raise BzrCommandError('bzr inventory --revision takes'
484
' exactly one revision identifier')
485
inv = b.get_revision_inventory(b.lookup_revision(revision[0]))
345
487
for path, entry in inv.entries():
346
print '%-50s %s' % (entry.file_id, path)
489
print '%-50s %s' % (path, entry.file_id)
349
494
class cmd_move(Command):
378
523
takes_args = ['from_name', 'to_name']
380
525
def run(self, from_name, to_name):
382
527
b.rename_one(b.relpath(from_name), b.relpath(to_name))
533
class cmd_pull(Command):
534
"""Pull any changes from another branch into the current one.
536
If the location is omitted, the last-used location will be used.
537
Both the revision history and the working directory will be
540
This command only works on branches that have not diverged. Branches are
541
considered diverged if both branches have had commits without first
542
pulling from the other.
544
If branches have diverged, you can use 'bzr merge' to pull the text changes
545
from one into the other.
547
takes_args = ['location?']
549
def run(self, location=None):
550
from bzrlib.merge import merge
552
from shutil import rmtree
555
br_to = find_branch('.')
558
stored_loc = br_to.controlfile("x-pull", "rb").read().rstrip('\n')
560
if e.errno != errno.ENOENT:
563
if stored_loc is None:
564
raise BzrCommandError("No pull location known or specified.")
566
print "Using last location: %s" % stored_loc
567
location = stored_loc
568
cache_root = tempfile.mkdtemp()
569
from bzrlib.branch import DivergedBranches
570
br_from = find_branch(location)
571
location = pull_loc(br_from)
572
old_revno = br_to.revno()
574
from branch import find_cached_branch, DivergedBranches
575
br_from = find_cached_branch(location, cache_root)
576
location = pull_loc(br_from)
577
old_revno = br_to.revno()
579
br_to.update_revisions(br_from)
580
except DivergedBranches:
581
raise BzrCommandError("These branches have diverged."
584
merge(('.', -1), ('.', old_revno), check_clean=False)
585
if location != stored_loc:
586
br_to.controlfile("x-pull", "wb").write(location + "\n")
592
class cmd_branch(Command):
593
"""Create a new copy of a branch.
595
If the TO_LOCATION is omitted, the last component of the FROM_LOCATION will
596
be used. In other words, "branch ../foo/bar" will attempt to create ./bar.
598
To retrieve the branch as of a particular revision, supply the --revision
599
parameter, as in "branch foo/bar -r 5".
601
takes_args = ['from_location', 'to_location?']
602
takes_options = ['revision']
604
def run(self, from_location, to_location=None, revision=None):
606
from bzrlib.merge import merge
607
from bzrlib.branch import DivergedBranches, NoSuchRevision, \
608
find_cached_branch, Branch
609
from shutil import rmtree
610
from meta_store import CachedStore
612
cache_root = tempfile.mkdtemp()
616
elif len(revision) > 1:
617
raise BzrCommandError('bzr branch --revision takes exactly 1 revision value')
621
br_from = find_cached_branch(from_location, cache_root)
623
if e.errno == errno.ENOENT:
624
raise BzrCommandError('Source location "%s" does not'
625
' exist.' % to_location)
629
if to_location is None:
630
to_location = os.path.basename(from_location.rstrip("/\\"))
633
os.mkdir(to_location)
635
if e.errno == errno.EEXIST:
636
raise BzrCommandError('Target directory "%s" already'
637
' exists.' % to_location)
638
if e.errno == errno.ENOENT:
639
raise BzrCommandError('Parent of "%s" does not exist.' %
643
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)
660
merge((to_location, -1), (to_location, 0), this_dir=to_location,
661
check_clean=False, ignore_zero=True)
662
from_location = pull_loc(br_from)
663
br_to.controlfile("x-pull", "wb").write(from_location + "\n")
668
def pull_loc(branch):
669
# TODO: Should perhaps just make attribute be 'base' in
670
# RemoteBranch and Branch?
671
if hasattr(branch, "baseurl"):
672
return branch.baseurl
386
678
class cmd_renames(Command):
387
679
"""Show list of renamed files.
456
747
takes_args = ['filename']
457
748
def run(self, filename):
749
b = find_branch(filename)
459
750
inv = b.inventory
460
751
fid = inv.path2id(b.relpath(filename))
462
bailout("%r is not a versioned file" % filename)
753
raise BzrError("%r is not a versioned file" % filename)
463
754
for fip in inv.get_idpath(fid):
467
758
class cmd_revision_history(Command):
468
759
"""Display list of revision ids on this branch."""
470
for patchid in Branch('.').revision_history():
762
for patchid in find_branch('.').revision_history():
474
766
class cmd_directories(Command):
475
767
"""Display list of versioned directories in this branch."""
477
for name, ie in Branch('.').read_working_inventory().directories():
769
for name, ie in find_branch('.').read_working_inventory().directories():
525
818
takes_args = ['file*']
526
819
takes_options = ['revision', 'diff-options']
820
aliases = ['di', 'dif']
529
822
def run(self, revision=None, file_list=None, diff_options=None):
530
823
from bzrlib.diff import show_diff
531
from bzrlib import find_branch
534
b = find_branch(file_list[0], lock_mode='r')
826
b = find_branch(file_list[0])
535
827
file_list = [b.relpath(f) for f in file_list]
536
828
if file_list == ['']:
537
829
# just pointing to top-of-tree
540
b = Branch('.', lock_mode='r')
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]
542
show_diff(b, revision, specific_files=file_list,
841
show_diff(b, base_rev, specific_files=file_list,
543
842
external_diff_options=diff_options)
573
872
"""List files modified in working tree."""
578
inv = b.read_working_inventory()
579
sc = statcache.update_cache(b, inv)
580
basis = b.basis_tree()
581
basis_inv = basis.inventory
583
# We used to do this through iter_entries(), but that's slow
584
# when most of the files are unmodified, as is usually the
585
# case. So instead we iterate by inventory entry, and only
586
# calculate paths as necessary.
588
for file_id in basis_inv:
589
cacheentry = sc.get(file_id)
590
if not cacheentry: # deleted
592
ie = basis_inv[file_id]
593
if cacheentry[statcache.SC_SHA1] != ie.text_sha1:
594
path = inv.id2path(file_id)
875
from bzrlib.diff import compare_trees
878
td = compare_trees(b.basis_tree(), b.working_tree())
880
for path, id, kind in td.modified:
634
919
-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.
637
925
TODO: Make --revision support uuid: and hash: [future tag:] notation.
641
929
takes_args = ['filename?']
642
takes_options = ['forward', 'timezone', 'verbose', 'show-ids', 'revision']
930
takes_options = ['forward', 'timezone', 'verbose', 'show-ids', 'revision','long', 'message']
644
932
def run(self, filename=None, timezone='original',
649
from bzrlib import show_log, find_branch
939
from bzrlib.branch import find_branch
940
from bzrlib.log import log_formatter, show_log
652
943
direction = (forward and 'forward') or 'reverse'
655
b = find_branch(filename, lock_mode='r')
946
b = find_branch(filename)
656
947
fp = b.relpath(filename)
658
949
file_id = b.read_working_inventory().path2id(fp)
660
951
file_id = None # points to branch root
662
b = find_branch('.', lock_mode='r')
666
revision = [None, None]
667
elif isinstance(revision, int):
668
revision = [revision, revision]
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]
673
assert len(revision) == 2
965
raise BzrCommandError('bzr log --revision takes one or two values.')
675
972
mutter('encoding log as %r' % bzrlib.user_encoding)
676
outf = codecs.getwriter(bzrlib.user_encoding)(sys.stdout)
679
show_timezone=timezone,
974
# use 'replace' so that we don't abort if trying to write out
975
# in e.g. the default C locale.
976
outf = codecs.getwriter(bzrlib.user_encoding)(sys.stdout, errors='replace')
982
lf = log_formatter(log_format,
985
show_timezone=timezone)
683
991
direction=direction,
684
start_revision=revision[0],
685
end_revision=revision[1])
823
1133
except ValueError:
824
1134
raise BzrCommandError("not a valid revision-number: %r" % revno)
826
print Branch('.').lookup_revision(revno)
1136
print find_branch('.').lookup_revision(revno)
829
1139
class cmd_export(Command):
830
1140
"""Export past revision to destination directory.
832
If no revision is specified this exports the last committed revision."""
1142
If no revision is specified this exports the last committed revision.
1144
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).
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."""
1150
# TODO: list known exporters
833
1151
takes_args = ['dest']
834
takes_options = ['revision']
835
def run(self, dest, revision=None):
838
rh = b.revision_history()[-1]
1152
takes_options = ['revision', 'format', 'root']
1153
def run(self, dest, revision=None, format=None, root=None):
1155
b = find_branch('.')
1156
if revision is None:
1157
rev_id = b.last_patch()
840
rh = b.lookup_revision(int(revision))
841
t = b.revision_tree(rh)
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"):
1173
t.export(dest, format, root)
845
1176
class cmd_cat(Command):
879
1212
TODO: Strict commit that fails if there are unknown or deleted files.
881
1214
takes_args = ['selected*']
882
takes_options = ['message', 'file', 'verbose']
1215
takes_options = ['message', 'file', 'verbose', 'unchanged']
883
1216
aliases = ['ci', 'checkin']
885
def run(self, message=None, file=None, verbose=True, selected_list=None):
886
from bzrlib.commit import commit
1218
def run(self, message=None, file=None, verbose=True, selected_list=None,
1220
from bzrlib.errors import PointlessCommit
1221
from bzrlib.osutils import get_text_message
888
1223
## Warning: shadows builtin file()
889
1224
if not message and not file:
890
raise BzrCommandError("please specify a commit message",
891
["use either --message or --file"])
1227
catcher = cStringIO.StringIO()
1228
sys.stdout = catcher
1229
cmd_status({"file_list":selected_list}, {})
1230
info = catcher.getvalue()
1232
message = get_text_message(info)
1235
raise BzrCommandError("please specify a commit message",
1236
["use either --message or --file"])
892
1237
elif message and file:
893
1238
raise BzrCommandError("please specify either --message or --file")
906
1260
This command checks various invariants about the branch storage to
907
1261
detect data corruption or bzr bugs.
909
takes_args = ['dir?']
910
def run(self, dir='.'):
912
bzrlib.check.check(Branch(dir))
1263
If given the --update flag, it will update some optional fields
1264
to help ensure data consistency.
1266
takes_args = ['dir?']
1268
def run(self, dir='.'):
1269
from bzrlib.check import check
1270
check(find_branch(dir))
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
class cmd_upgrade(Command):
1296
"""Upgrade branch storage to current format.
1298
This should normally be used only after the check command tells
1301
takes_args = ['dir?']
1303
def run(self, dir='.'):
1304
from bzrlib.upgrade import upgrade
1305
upgrade(find_branch(dir))
927
1320
class cmd_selftest(Command):
928
1321
"""Run internal test suite"""
931
failures, tests = 0, 0
933
import doctest, bzrlib.store
934
bzrlib.trace.verbose = False
936
for m in bzrlib.store, bzrlib.inventory, bzrlib.branch, bzrlib.osutils, \
937
bzrlib.tree, bzrlib.commands, bzrlib.add:
938
mf, mt = doctest.testmod(m)
941
print '%-40s %3d tests' % (m.__name__, mt),
943
print '%3d FAILED!' % mf
947
print '%-40s %3d tests' % ('total', tests),
949
print '%3d FAILED!' % failures
1323
takes_options = ['verbose']
1324
def run(self, verbose=False):
1325
from bzrlib.selftest import selftest
1326
return int(not selftest(verbose=verbose))
957
1329
class cmd_version(Command):
958
"""Show version of bzr"""
1330
"""Show version of bzr."""
962
1334
def show_version():
963
1335
print "bzr (bazaar-ng) %s" % bzrlib.__version__
1336
# is bzrlib itself in a branch?
1337
bzrrev = bzrlib.get_bzr_revision()
1339
print " (bzr checkout, revision %d {%s})" % bzrrev
964
1340
print bzrlib.__copyright__
965
1341
print "http://bazaar-ng.org/"
976
1352
print "it sure does!"
978
1354
def parse_spec(spec):
1356
>>> parse_spec(None)
1358
>>> parse_spec("./")
1360
>>> parse_spec("../@")
1362
>>> parse_spec("../f/@35")
1364
>>> parse_spec('./@revid:john@arbash-meinel.com-20050711044610-3ca0327c6a222f67')
1365
['.', 'revid:john@arbash-meinel.com-20050711044610-3ca0327c6a222f67']
979
1369
if '/@' in spec:
980
1370
parsed = spec.split('/@')
981
1371
assert len(parsed) == 2
982
1372
if parsed[1] == "":
985
parsed[1] = int(parsed[1])
1376
parsed[1] = int(parsed[1])
1378
pass # We can allow stuff like ./@revid:blahblahblah
1380
assert parsed[1] >=0
988
1382
parsed = [spec, None]
991
1387
class cmd_merge(Command):
992
"""Perform a three-way merge of trees."""
993
takes_args = ['other_spec', 'base_spec']
995
def run(self, other_spec, base_spec):
996
merge.merge(parse_spec(other_spec), parse_spec(base_spec))
1388
"""Perform a three-way merge of trees.
1390
The SPEC parameters are working tree or revision specifiers. Working trees
1391
are specified using standard paths or urls. No component of a directory
1392
path may begin with '@'.
1394
Working tree examples: '.', '..', 'foo@', but NOT 'foo/@bar'
1396
Revisions are specified using a dirname/@revno pair, where dirname is the
1397
branch directory and revno is the revision within that branch. If no revno
1398
is specified, the latest revision is used.
1400
Revision examples: './@127', 'foo/@', '../@1'
1402
The OTHER_SPEC parameter is required. If the BASE_SPEC parameter is
1403
not supplied, the common ancestor of OTHER_SPEC the current branch is used
1406
merge refuses to run if there are any uncommitted changes, unless
1409
takes_args = ['other_spec', 'base_spec?']
1410
takes_options = ['force', 'merge-type']
1412
def run(self, other_spec, base_spec=None, force=False, merge_type=None):
1413
from bzrlib.merge import merge
1414
from bzrlib.merge_core import ApplyMerge3
1415
if merge_type is None:
1416
merge_type = ApplyMerge3
1417
merge(parse_spec(other_spec), parse_spec(base_spec),
1418
check_clean=(not force), merge_type=merge_type)
1422
class cmd_revert(Command):
1423
"""Restore selected files from a previous revision.
1425
takes_args = ['file+']
1426
def run(self, file_list):
1427
from bzrlib.branch import find_branch
1432
b = find_branch(file_list[0])
1434
b.revert([b.relpath(f) for f in file_list])
1437
class cmd_merge_revert(Command):
1438
"""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.
1443
takes_options = ['revision', 'no-backup']
1445
def run(self, revision=None, no_backup=False):
1446
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('.'),
1454
backup_files=not no_backup)
998
1457
class cmd_assert_fail(Command):
999
1458
"""Test reporting of assertion failures"""
1072
1546
(['status'], {'all': True})
1073
1547
>>> parse_args('commit --message=biter'.split())
1074
1548
(['commit'], {'message': u'biter'})
1549
>>> parse_args('log -r 500'.split())
1550
(['log'], {'revision': [500]})
1551
>>> parse_args('log -r500..600'.split())
1552
(['log'], {'revision': [500, 600]})
1553
>>> parse_args('log -vr500..600'.split())
1554
(['log'], {'verbose': True, 'revision': [500, 600]})
1555
>>> parse_args('log -rv500..600'.split()) #the r takes an argument
1556
(['log'], {'revision': ['v500', 600]})
1092
1574
optname = a[2:]
1093
1575
if optname not in OPTIONS:
1094
bailout('unknown long option %r' % a)
1576
raise BzrError('unknown long option %r' % a)
1096
1578
shortopt = a[1:]
1097
if shortopt not in SHORT_OPTIONS:
1098
bailout('unknown short option %r' % a)
1099
optname = SHORT_OPTIONS[shortopt]
1579
if shortopt in SHORT_OPTIONS:
1580
# Multi-character options must have a space to delimit
1582
optname = SHORT_OPTIONS[shortopt]
1584
# Single character short options, can be chained,
1585
# and have their value appended to their name
1587
if shortopt not in SHORT_OPTIONS:
1588
# We didn't find the multi-character name, and we
1589
# didn't find the single char name
1590
raise BzrError('unknown short option %r' % a)
1591
optname = SHORT_OPTIONS[shortopt]
1594
# There are extra things on this option
1595
# see if it is the value, or if it is another
1597
optargfn = OPTIONS[optname]
1598
if optargfn is None:
1599
# This option does not take an argument, so the
1600
# next entry is another short option, pack it back
1602
argv.insert(0, '-' + a[2:])
1604
# This option takes an argument, so pack it
1101
1608
if optname in opts:
1102
1609
# XXX: Do we ever want to support this, e.g. for -r?
1103
bailout('repeated option %r' % a)
1610
raise BzrError('repeated option %r' % a)
1105
1612
optargfn = OPTIONS[optname]
1107
1614
if optarg == None:
1109
bailout('option %r needs an argument' % a)
1616
raise BzrError('option %r needs an argument' % a)
1111
1618
optarg = argv.pop(0)
1112
1619
opts[optname] = optargfn(optarg)
1114
1621
if optarg != None:
1115
bailout('option %r takes no argument' % optname)
1622
raise BzrError('option %r takes no argument' % optname)
1116
1623
opts[optname] = True
1676
def _parse_master_args(argv):
1677
"""Parse the arguments that always go with the original command.
1678
These are things like bzr --no-plugins, etc.
1680
There are now 2 types of option flags. Ones that come *before* the command,
1681
and ones that come *after* the command.
1682
Ones coming *before* the command are applied against all possible commands.
1683
And are generally applied before plugins are loaded.
1685
The current list are:
1686
--builtin Allow plugins to load, but don't let them override builtin commands,
1687
they will still be allowed if they do not override a builtin.
1688
--no-plugins Don't load any plugins. This lets you get back to official source
1690
--profile Enable the hotspot profile before running the command.
1691
For backwards compatibility, this is also a non-master option.
1692
--version Spit out the version of bzr that is running and exit.
1693
This is also a non-master option.
1694
--help Run help and exit, also a non-master option (I think that should stay, though)
1696
>>> argv, opts = _parse_master_args(['--test'])
1697
Traceback (most recent call last):
1699
BzrCommandError: Invalid master option: 'test'
1700
>>> argv, opts = _parse_master_args(['--version', 'command'])
1703
>>> print opts['version']
1705
>>> argv, opts = _parse_master_args(['--profile', 'command', '--more-options'])
1707
['command', '--more-options']
1708
>>> print opts['profile']
1710
>>> argv, opts = _parse_master_args(['--no-plugins', 'command'])
1713
>>> print opts['no-plugins']
1715
>>> print opts['profile']
1717
>>> argv, opts = _parse_master_args(['command', '--profile'])
1719
['command', '--profile']
1720
>>> print opts['profile']
1723
master_opts = {'builtin':False,
1731
if arg[:2] != '--': # at the first non-option, we return the rest
1733
arg = arg[2:] # Remove '--'
1734
if arg not in master_opts:
1735
# We could say that this is not an error, that we should
1736
# just let it be handled by the main section instead
1737
raise BzrCommandError('Invalid master option: %r' % arg)
1738
argv.pop(0) # We are consuming this entry
1739
master_opts[arg] = True
1740
return argv, master_opts
1170
1744
def run_bzr(argv):
1171
1745
"""Execute a command.
1173
1747
This is similar to main(), but without all the trappings for
1174
1748
logging and error handling.
1751
The command-line arguments, without the program name.
1753
Returns a command status or raises an exception.
1176
1755
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
1179
args, opts = parse_args(argv[1:])
1187
elif 'version' in opts:
1190
1782
cmd = str(args.pop(0))
1191
1783
except IndexError:
1784
print >>sys.stderr, "please try 'bzr help' for help"
1197
canonical_cmd, cmd_class = get_cmd_class(cmd)
1787
plugins_override = not (master_opts['builtin'])
1788
canonical_cmd, cmd_class = get_cmd_class(cmd, plugins_override=plugins_override)
1790
profile = master_opts['profile']
1791
# For backwards compatibility, I would rather stick with --profile being a
1792
# master/global option
1200
1793
if 'profile' in opts:
1202
1795
del opts['profile']
1206
1797
# check options are reasonable
1207
1798
allowed = cmd_class.takes_options