22
22
from bzrlib.trace import mutter, note, log_error
23
from bzrlib.errors import bailout, BzrError, BzrCheckError, BzrCommandError
23
from bzrlib.errors import BzrError, BzrCheckError, BzrCommandError
24
24
from bzrlib.osutils import quotefn
25
25
from bzrlib import Branch, Inventory, InventoryEntry, BZRDIR, \
32
def register_command(cmd):
33
"Utility function to help register a command"
36
if k.startswith("cmd_"):
37
k_unsquished = _unsquish_command_name(k)
40
if not plugin_cmds.has_key(k_unsquished):
41
plugin_cmds[k_unsquished] = cmd
43
log_error('Two plugins defined the same command: %r' % k)
44
log_error('Not loading the one in %r' % sys.modules[cmd.__module__])
29
47
def _squish_command_name(cmd):
30
48
return 'cmd_' + cmd.replace('-', '_')
72
"""Return canonical name and class for all registered commands."""
91
def _get_cmd_dict(plugins_override=True):
73
93
for k, v in globals().iteritems():
74
94
if k.startswith("cmd_"):
75
yield _unsquish_command_name(k), v
77
def get_cmd_class(cmd):
95
d[_unsquish_command_name(k)] = v
96
# If we didn't load plugins, the plugin_cmds dict will be empty
100
d2 = plugin_cmds.copy()
106
def get_all_cmds(plugins_override=True):
107
"""Return canonical name and class for all registered commands."""
108
for k, v in _get_cmd_dict(plugins_override=plugins_override).iteritems():
112
def get_cmd_class(cmd, plugins_override=True):
78
113
"""Return the canonical name and command class for a command.
80
115
cmd = str(cmd) # not unicode
82
117
# first look up this command under the specified name
118
cmds = _get_cmd_dict(plugins_override=plugins_override)
84
return cmd, globals()[_squish_command_name(cmd)]
120
return cmd, cmds[cmd]
88
124
# look for any command which claims this as an alias
89
for cmdname, cmdclass in get_all_cmds():
125
for cmdname, cmdclass in cmds.iteritems():
90
126
if cmd in cmdclass.aliases:
91
127
return cmdname, cmdclass
177
213
def __init__(self, path):
180
# TODO: If either of these fail, we should detect that and
181
# assume that path is not really a bzr plugin after all.
183
216
pipe = os.popen('%s --bzr-usage' % path, 'r')
184
217
self.takes_options = pipe.readline().split()
219
for opt in self.takes_options:
220
if not opt in OPTIONS:
221
raise BzrError("Unknown option '%s' returned by external command %s"
224
# TODO: Is there any way to check takes_args is valid here?
185
225
self.takes_args = pipe.readline().split()
227
if pipe.close() is not None:
228
raise BzrError("Failed funning '%s --bzr-usage'" % path)
188
230
pipe = os.popen('%s --bzr-help' % path, 'r')
189
231
self.__doc__ = pipe.read()
232
if pipe.close() is not None:
233
raise BzrError("Failed funning '%s --bzr-help'" % path)
192
235
def __call__(self, options, arguments):
193
236
Command.__init__(self, options, arguments)
319
363
bzrlib.add.smart_add(file_list, verbose, not no_recurse)
367
class cmd_mkdir(Command):
368
"""Create a new versioned directory.
370
This is equivalent to creating the directory and then adding it.
372
takes_args = ['dir+']
374
def run(self, dir_list):
383
b = bzrlib.branch.Branch(d)
384
b.add([d], verbose=True)
322
387
class cmd_relpath(Command):
323
388
"""Show path of a file relative to root"""
324
389
takes_args = ['filename']
414
479
if errno == errno.ENOENT:
416
481
if location is None:
417
location = stored_loc
419
raise BzrCommandError("No pull location known or specified.")
482
if stored_loc is None:
483
raise BzrCommandError("No pull location known or specified.")
485
print "Using last location: %s" % stored_loc
486
location = stored_loc
420
487
from branch import find_branch, DivergedBranches
421
488
br_from = find_branch(location)
422
489
location = pull_loc(br_from)
426
493
except DivergedBranches:
427
494
raise BzrCommandError("These branches have diverged. Try merge.")
429
merge(('.', -1), ('.', old_revno))
496
merge(('.', -1), ('.', old_revno), check_clean=False)
430
497
if location != stored_loc:
431
498
br_to.controlfile("x-pull", "wb").write(location + "\n")
435
502
class cmd_branch(Command):
436
503
"""Create a new copy of a branch.
438
If the TO_LOCATION is omitted, the last component of the
439
FROM_LOCATION will be used. In other words,
440
"branch ../foo/bar" will attempt to create ./bar.
505
If the TO_LOCATION is omitted, the last component of the FROM_LOCATION will
506
be used. In other words, "branch ../foo/bar" will attempt to create ./bar.
508
To retrieve the branch as of a particular revision, supply the --revision
509
parameter, as in "branch foo/bar -r 5".
442
511
takes_args = ['from_location', 'to_location?']
512
takes_options = ['revision']
444
def run(self, from_location, to_location=None):
514
def run(self, from_location, to_location=None, revision=None):
446
516
from bzrlib.merge import merge
517
from branch import find_branch, DivergedBranches, NoSuchRevision
518
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.' %
448
528
if to_location is None:
449
to_location = os.path.basename(from_location)
450
# FIXME: If there's a trailing slash, keep removing them
451
# until we find the right bit
529
to_location = os.path.basename(from_location.rstrip("/\\"))
454
532
os.mkdir(to_location)
464
542
br_to = Branch(to_location, init=True)
465
from branch import find_branch, DivergedBranches
467
br_from = find_branch(from_location)
469
if e.errno == errno.ENOENT:
470
raise BzrCommandError('Source location "%s" does not exist.' %
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)
475
553
from_location = pull_loc(br_from)
476
br_to.update_revisions(br_from)
477
merge((to_location, -1), (to_location, 0), this_dir=to_location,
479
554
br_to.controlfile("x-pull", "wb").write(from_location + "\n")
939
1014
class cmd_export(Command):
940
1015
"""Export past revision to destination directory.
942
If no revision is specified this exports the last committed revision."""
1017
If no revision is specified this exports the last committed revision.
1019
Format may be an "exporter" name, such as tar, tgz, tbz2. If none is
1020
given, exports to a directory (equivalent to --format=dir)."""
1021
# TODO: list known exporters
943
1022
takes_args = ['dest']
944
takes_options = ['revision']
945
def run(self, dest, revision=None):
1023
takes_options = ['revision', 'format']
1024
def run(self, dest, revision=None, format='dir'):
947
1026
if revision == None:
948
1027
rh = b.revision_history()[-1]
950
1029
rh = b.lookup_revision(int(revision))
951
1030
t = b.revision_tree(rh)
1031
t.export(dest, format)
955
1034
class cmd_cat(Command):
1016
1095
This command checks various invariants about the branch storage to
1017
1096
detect data corruption or bzr bugs.
1098
If given the --update flag, it will update some optional fields
1099
to help ensure data consistency.
1019
1101
takes_args = ['dir?']
1020
1103
def run(self, dir='.'):
1021
1104
import bzrlib.check
1022
1105
bzrlib.check.check(Branch(dir))
1109
class cmd_upgrade(Command):
1110
"""Upgrade branch storage to current format.
1112
This should normally be used only after the check command tells
1115
takes_args = ['dir?']
1117
def run(self, dir='.'):
1118
from bzrlib.upgrade import upgrade
1119
upgrade(Branch(dir))
1026
1123
class cmd_whoami(Command):
1027
1124
"""Show bzr user id."""
1028
1125
takes_options = ['email']
1222
1328
(['status'], {'all': True})
1223
1329
>>> parse_args('commit --message=biter'.split())
1224
1330
(['commit'], {'message': u'biter'})
1331
>>> parse_args('log -r 500'.split())
1332
(['log'], {'revision': 500})
1333
>>> parse_args('log -r500:600'.split())
1334
(['log'], {'revision': [500, 600]})
1335
>>> parse_args('log -vr500:600'.split())
1336
(['log'], {'verbose': True, 'revision': [500, 600]})
1337
>>> parse_args('log -rv500:600'.split()) #the r takes an argument
1338
Traceback (most recent call last):
1340
ValueError: invalid literal for int(): v500
1242
1358
optname = a[2:]
1243
1359
if optname not in OPTIONS:
1244
bailout('unknown long option %r' % a)
1360
raise BzrError('unknown long option %r' % a)
1246
1362
shortopt = a[1:]
1247
if shortopt not in SHORT_OPTIONS:
1248
bailout('unknown short option %r' % a)
1249
optname = SHORT_OPTIONS[shortopt]
1363
if shortopt in SHORT_OPTIONS:
1364
# Multi-character options must have a space to delimit
1366
optname = SHORT_OPTIONS[shortopt]
1368
# Single character short options, can be chained,
1369
# and have their value appended to their name
1371
if shortopt not in SHORT_OPTIONS:
1372
# We didn't find the multi-character name, and we
1373
# didn't find the single char name
1374
raise BzrError('unknown short option %r' % a)
1375
optname = SHORT_OPTIONS[shortopt]
1378
# There are extra things on this option
1379
# see if it is the value, or if it is another
1381
optargfn = OPTIONS[optname]
1382
if optargfn is None:
1383
# This option does not take an argument, so the
1384
# next entry is another short option, pack it back
1386
argv.insert(0, '-' + a[2:])
1388
# This option takes an argument, so pack it
1251
1392
if optname in opts:
1252
1393
# XXX: Do we ever want to support this, e.g. for -r?
1253
bailout('repeated option %r' % a)
1394
raise BzrError('repeated option %r' % a)
1255
1396
optargfn = OPTIONS[optname]
1257
1398
if optarg == None:
1259
bailout('option %r needs an argument' % a)
1400
raise BzrError('option %r needs an argument' % a)
1261
1402
optarg = argv.pop(0)
1262
1403
opts[optname] = optargfn(optarg)
1264
1405
if optarg != None:
1265
bailout('option %r takes no argument' % optname)
1406
raise BzrError('option %r takes no argument' % optname)
1266
1407
opts[optname] = True
1460
def _parse_master_args(argv):
1461
"""Parse the arguments that always go with the original command.
1462
These are things like bzr --no-plugins, etc.
1464
There are now 2 types of option flags. Ones that come *before* the command,
1465
and ones that come *after* the command.
1466
Ones coming *before* the command are applied against all possible commands.
1467
And are generally applied before plugins are loaded.
1469
The current list are:
1470
--builtin Allow plugins to load, but don't let them override builtin commands,
1471
they will still be allowed if they do not override a builtin.
1472
--no-plugins Don't load any plugins. This lets you get back to official source
1474
--profile Enable the hotspot profile before running the command.
1475
For backwards compatibility, this is also a non-master option.
1476
--version Spit out the version of bzr that is running and exit.
1477
This is also a non-master option.
1478
--help Run help and exit, also a non-master option (I think that should stay, though)
1480
>>> argv, opts = _parse_master_args(['bzr', '--test'])
1481
Traceback (most recent call last):
1483
BzrCommandError: Invalid master option: 'test'
1484
>>> argv, opts = _parse_master_args(['bzr', '--version', 'command'])
1487
>>> print opts['version']
1489
>>> argv, opts = _parse_master_args(['bzr', '--profile', 'command', '--more-options'])
1491
['command', '--more-options']
1492
>>> print opts['profile']
1494
>>> argv, opts = _parse_master_args(['bzr', '--no-plugins', 'command'])
1497
>>> print opts['no-plugins']
1499
>>> print opts['profile']
1501
>>> argv, opts = _parse_master_args(['bzr', 'command', '--profile'])
1503
['command', '--profile']
1504
>>> print opts['profile']
1507
master_opts = {'builtin':False,
1514
# This is the point where we could hook into argv[0] to determine
1515
# what front-end is supposed to be run
1516
# For now, we are just ignoring it.
1517
cmd_name = argv.pop(0)
1519
if arg[:2] != '--': # at the first non-option, we return the rest
1521
arg = arg[2:] # Remove '--'
1522
if arg not in master_opts:
1523
# We could say that this is not an error, that we should
1524
# just let it be handled by the main section instead
1525
raise BzrCommandError('Invalid master option: %r' % arg)
1526
argv.pop(0) # We are consuming this entry
1527
master_opts[arg] = True
1528
return argv, master_opts
1320
1532
def run_bzr(argv):
1321
1533
"""Execute a command.
1326
1538
argv = [a.decode(bzrlib.user_encoding) for a in argv]
1329
args, opts = parse_args(argv[1:])
1541
# some options like --builtin and --no-plugins have special effects
1542
argv, master_opts = _parse_master_args(argv)
1543
if not master_opts['no-plugins']:
1544
bzrlib.load_plugins()
1546
args, opts = parse_args(argv)
1548
if master_opts['help']:
1549
from bzrlib.help import help
1330
1556
if 'help' in opts:
1557
from bzrlib.help import help
1337
1563
elif 'version' in opts:
1566
elif args and args[0] == 'builtin':
1567
include_plugins=False
1340
1569
cmd = str(args.pop(0))
1341
1570
except IndexError:
1347
canonical_cmd, cmd_class = get_cmd_class(cmd)
1576
plugins_override = not (master_opts['builtin'])
1577
canonical_cmd, cmd_class = get_cmd_class(cmd, plugins_override=plugins_override)
1579
profile = master_opts['profile']
1580
# For backwards compatibility, I would rather stick with --profile being a
1581
# master/global option
1350
1582
if 'profile' in opts:
1352
1584
del opts['profile']
1356
1586
# check options are reasonable
1357
1587
allowed = cmd_class.takes_options