15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
# TODO: Split the command framework away from the actual commands.
20
# TODO: probably should say which arguments are candidates for glob
21
# expansion on windows and do that at the command level.
23
# TODO: Help messages for options.
25
# TODO: Define arguments by objects, rather than just using names.
26
# Those objects can specify the expected type of the argument, which
27
# would help with validation and shell completion.
30
# TODO: Help messages for options.
32
# TODO: Define arguments by objects, rather than just using names.
33
# Those objects can specify the expected type of the argument, which
34
# would help with validation and shell completion.
42
22
from bzrlib.trace import mutter, note, log_error, warning
43
23
from bzrlib.errors import BzrError, BzrCheckError, BzrCommandError
44
24
from bzrlib.branch import find_branch
145
def get_merge_type(typestring):
146
"""Attempt to find the merge class/factory associated with a string."""
147
from merge import merge_types
149
return merge_types[typestring][0]
151
templ = '%s%%7s: %%s' % (' '*12)
152
lines = [templ % (f[0], f[1][1]) for f in merge_types.iteritems()]
153
type_list = '\n'.join(lines)
154
msg = "No known merge type %s. Supported types are:\n%s" %\
155
(typestring, type_list)
156
raise BzrCommandError(msg)
159
def get_merge_type(typestring):
160
"""Attempt to find the merge class/factory associated with a string."""
161
from merge import merge_types
163
return merge_types[typestring][0]
165
templ = '%s%%7s: %%s' % (' '*12)
166
lines = [templ % (f[0], f[1][1]) for f in merge_types.iteritems()]
167
type_list = '\n'.join(lines)
168
msg = "No known merge type %s. Supported types are:\n%s" %\
169
(typestring, type_list)
170
raise BzrCommandError(msg)
174
126
def _get_cmd_dict(plugins_override=True):
271
220
class ExternalCommand(Command):
272
221
"""Class to wrap external commands.
274
We cheat a little here, when get_cmd_class() calls us we actually
275
give it back an object we construct that has the appropriate path,
276
help, options etc for the specified command.
278
When run_bzr() tries to instantiate that 'class' it gets caught by
279
the __call__ method, which we override to call the Command.__init__
280
method. That then calls our run method which is pretty straight
283
The only wrinkle is that we have to map bzr's dictionary of options
284
and arguments back into command line options and arguments for the
223
We cheat a little here, when get_cmd_class() calls us we actually give it back
224
an object we construct that has the appropriate path, help, options etc for the
227
When run_bzr() tries to instantiate that 'class' it gets caught by the __call__
228
method, which we override to call the Command.__init__ method. That then calls
229
our run method which is pretty straight forward.
231
The only wrinkle is that we have to map bzr's dictionary of options and arguments
232
back into command line options and arguments for the script.
288
235
def find_command(cls, cmd):
462
409
whether already versioned or not, are searched for files or
463
410
subdirectories that are neither versioned or ignored, and these
464
411
are added. This search proceeds recursively into versioned
465
directories. If no names are given '.' is assumed.
467
Therefore simply saying 'bzr add' will version all files that
414
Therefore simply saying 'bzr add .' will version all files that
468
415
are currently unknown.
470
417
TODO: Perhaps adding a file whose directly is not versioned should
471
418
recursively add that parent, rather than giving an error?
473
takes_args = ['file*']
420
takes_args = ['file+']
474
421
takes_options = ['verbose', 'no-recurse']
476
423
def run(self, file_list, verbose=False, no_recurse=False):
477
from bzrlib.add import smart_add, _PrintAddCallback
478
smart_add(file_list, verbose, not no_recurse,
479
callback=_PrintAddCallback)
424
from bzrlib.add import smart_add
425
smart_add(file_list, verbose, not no_recurse)
569
class cmd_mv(Command):
570
"""Move or rename a file.
573
bzr mv OLDNAME NEWNAME
574
bzr mv SOURCE... DESTINATION
576
If the last argument is a versioned directory, all the other names
577
are moved into it. Otherwise, there must be exactly two arguments
578
and the file is changed to a new name, which must not already exist.
580
Files cannot be moved between branches.
582
takes_args = ['names*']
583
def run(self, names_list):
584
if len(names_list) < 2:
585
raise BzrCommandError("missing file argument")
586
b = find_branch(names_list[0])
588
rel_names = [b.relpath(x) for x in names_list]
590
if os.path.isdir(names_list[-1]):
591
# move into existing directory
592
b.move(rel_names[:-1], rel_names[-1])
594
if len(names_list) != 2:
595
raise BzrCommandError('to mv multiple files the destination '
596
'must be a versioned directory')
597
b.move(rel_names[0], rel_names[1])
602
516
class cmd_pull(Command):
671
584
takes_args = ['from_location', 'to_location?']
672
585
takes_options = ['revision']
673
aliases = ['get', 'clone']
675
587
def run(self, from_location, to_location=None, revision=None):
676
from bzrlib.branch import copy_branch, find_cached_branch
589
from bzrlib.merge import merge
590
from bzrlib.branch import DivergedBranches, NoSuchRevision, \
591
find_cached_branch, Branch
679
592
from shutil import rmtree
593
from meta_store import CachedStore
680
595
cache_root = tempfile.mkdtemp()
599
elif len(revision) > 1:
600
raise BzrCommandError('bzr branch --revision takes exactly 1 revision value')
684
elif len(revision) > 1:
685
raise BzrCommandError(
686
'bzr branch --revision takes exactly 1 revision value')
688
604
br_from = find_cached_branch(from_location, cache_root)
689
605
except OSError, e:
709
copy_branch(br_from, to_location, revision[0])
710
except bzrlib.errors.NoSuchRevision:
712
msg = "The branch %s has no revision %d." % (from_location, revision[0])
713
raise BzrCommandError(msg)
626
br_to = Branch(to_location, init=True)
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)
643
merge((to_location, -1), (to_location, 0), this_dir=to_location,
644
check_clean=False, ignore_zero=True)
645
from_location = pull_loc(br_from)
646
br_to.controlfile("x-pull", "wb").write(from_location + "\n")
715
648
rmtree(cache_root)
651
def pull_loc(branch):
652
# TODO: Should perhaps just make attribute be 'base' in
653
# RemoteBranch and Branch?
654
if hasattr(branch, "baseurl"):
655
return branch.baseurl
718
661
class cmd_renames(Command):
719
662
"""Show list of renamed files.
1367
1273
takes_options = ['email']
1369
1275
def run(self, email=False):
1371
b = bzrlib.branch.find_branch('.')
1376
print bzrlib.osutils.user_email(b)
1277
print bzrlib.osutils.user_email()
1378
print bzrlib.osutils.username(b)
1279
print bzrlib.osutils.username()
1381
1282
class cmd_selftest(Command):
1382
1283
"""Run internal test suite"""
1384
takes_options = ['verbose', 'pattern']
1385
def run(self, verbose=False, pattern=".*"):
1387
1286
from bzrlib.selftest import selftest
1388
# we don't want progress meters from the tests to go to the
1389
# real output; and we don't want log messages cluttering up
1391
save_ui = bzrlib.ui.ui_factory
1392
bzrlib.trace.info('running tests...')
1393
bzrlib.trace.disable_default_logging()
1395
bzrlib.ui.ui_factory = bzrlib.ui.SilentUIFactory()
1396
result = selftest(verbose=verbose, pattern=pattern)
1398
bzrlib.trace.info('tests passed')
1400
bzrlib.trace.info('tests failed')
1401
return int(not result)
1403
bzrlib.trace.enable_default_logging()
1404
bzrlib.ui.ui_factory = save_ui
1287
return int(not selftest())
1407
1290
class cmd_version(Command):
1465
class cmd_find_merge_base(Command):
1466
"""Find and print a base revision for merging two branches.
1468
TODO: Options to specify revisions on either side, as if
1469
merging only part of the history.
1471
takes_args = ['branch', 'other']
1474
def run(self, branch, other):
1475
branch1 = find_branch(branch)
1476
branch2 = find_branch(other)
1478
base_revno, base_revid = branch1.common_ancestor(branch2)
1480
if base_revno is None:
1481
raise bzrlib.errors.UnrelatedBranches()
1483
print 'merge base is revision %s' % base_revid
1484
print ' r%-6d in %s' % (base_revno, branch)
1486
other_revno = branch2.revision_id_to_revno(base_revid)
1488
print ' r%-6d in %s' % (other_revno, other)
1492
1348
class cmd_merge(Command):
1493
"""Perform a three-way merge.
1495
The branch is the branch you will merge from. By default, it will merge
1496
the latest revision. If you specify a revision, that revision will be
1497
merged. If you specify two revisions, the first will be used as a BASE,
1498
and the second one as OTHER. Revision numbers are always relative to the
1503
To merge the latest revision from bzr.dev
1504
bzr merge ../bzr.dev
1506
To merge changes up to and including revision 82 from bzr.dev
1507
bzr merge -r 82 ../bzr.dev
1509
To merge the changes introduced by 82, without previous changes:
1510
bzr merge -r 81..82 ../bzr.dev
1349
"""Perform a three-way merge of trees.
1351
The SPEC parameters are working tree or revision specifiers. Working trees
1352
are specified using standard paths or urls. No component of a directory
1353
path may begin with '@'.
1355
Working tree examples: '.', '..', 'foo@', but NOT 'foo/@bar'
1357
Revisions are specified using a dirname/@revno pair, where dirname is the
1358
branch directory and revno is the revision within that branch. If no revno
1359
is specified, the latest revision is used.
1361
Revision examples: './@127', 'foo/@', '../@1'
1363
The OTHER_SPEC parameter is required. If the BASE_SPEC parameter is
1364
not supplied, the common ancestor of OTHER_SPEC the current branch is used
1512
1367
merge refuses to run if there are any uncommitted changes, unless
1513
1368
--force is given.
1515
takes_args = ['branch?']
1516
takes_options = ['revision', 'force', 'merge-type']
1370
takes_args = ['other_spec', 'base_spec?']
1371
takes_options = ['force']
1518
def run(self, branch='.', revision=None, force=False,
1373
def run(self, other_spec, base_spec=None, force=False):
1520
1374
from bzrlib.merge import merge
1521
from bzrlib.merge_core import ApplyMerge3
1522
if merge_type is None:
1523
merge_type = ApplyMerge3
1375
merge(parse_spec(other_spec), parse_spec(base_spec),
1376
check_clean=(not force))
1525
if revision is None or len(revision) < 1:
1527
other = [branch, -1]
1529
if len(revision) == 1:
1530
other = [branch, revision[0]]
1533
assert len(revision) == 2
1534
if None in revision:
1535
raise BzrCommandError(
1536
"Merge doesn't permit that revision specifier.")
1537
base = (branch, revision[0])
1538
other = (branch, revision[1])
1540
merge(other, base, check_clean=(not force), merge_type=merge_type)
1543
1380
class cmd_revert(Command):
1381
"""Restore selected files from a previous revision.
1383
takes_args = ['file+']
1384
def run(self, file_list):
1385
from bzrlib.branch import find_branch
1390
b = find_branch(file_list[0])
1392
b.revert([b.relpath(f) for f in file_list])
1395
class cmd_merge_revert(Command):
1544
1396
"""Reverse all changes since the last commit.
1546
Only versioned files are affected. Specify filenames to revert only
1547
those files. By default, any files that are changed will be backed up
1548
first. Backup files have a '~' appended to their name.
1398
Only versioned files are affected.
1400
TODO: Store backups of any files that will be reverted, so
1401
that the revert can be undone.
1550
takes_options = ['revision', 'no-backup']
1551
takes_args = ['file*']
1552
aliases = ['merge-revert']
1403
takes_options = ['revision']
1554
def run(self, revision=None, no_backup=False, file_list=None):
1405
def run(self, revision=None):
1555
1406
from bzrlib.merge import merge
1556
from bzrlib.branch import Branch
1557
if file_list is not None:
1558
if len(file_list) == 0:
1559
raise BzrCommandError("No files specified")
1560
1407
if revision is None:
1561
1408
revision = [-1]
1562
1409
elif len(revision) != 1:
1563
raise BzrCommandError('bzr revert --revision takes exactly 1 argument')
1410
raise BzrCommandError('bzr merge-revert --revision takes exactly 1 argument')
1564
1411
merge(('.', revision[0]), parse_spec('.'),
1565
1412
check_clean=False,
1567
backup_files=not no_backup,
1568
file_list=file_list)
1570
Branch('.').set_pending_merges([])
1573
1416
class cmd_assert_fail(Command):
1581
1424
"""Show help on a command or other topic.
1583
1426
For a list of all available commands, say 'bzr help commands'."""
1584
takes_options = ['long']
1585
1427
takes_args = ['topic?']
1586
1428
aliases = ['?']
1588
def run(self, topic=None, long=False):
1430
def run(self, topic=None):
1590
if topic is None and long:
1592
1432
help.help(topic)
1595
class cmd_shell_complete(Command):
1596
"""Show appropriate completions for context.
1598
For a list of all available commands, say 'bzr shell-complete'."""
1599
takes_args = ['context?']
1603
def run(self, context=None):
1604
import shellcomplete
1605
shellcomplete.shellcomplete(context)
1608
class cmd_missing(Command):
1609
"""What is missing in this branch relative to other branch.
1611
takes_args = ['remote?']
1612
aliases = ['mis', 'miss']
1613
# We don't have to add quiet to the list, because
1614
# unknown options are parsed as booleans
1615
takes_options = ['verbose', 'quiet']
1617
def run(self, remote=None, verbose=False, quiet=False):
1618
from bzrlib.branch import find_branch, DivergedBranches
1619
from bzrlib.errors import BzrCommandError
1620
from bzrlib.missing import get_parent, show_missing
1622
if verbose and quiet:
1623
raise BzrCommandError('Cannot pass both quiet and verbose')
1625
b = find_branch('.')
1626
parent = get_parent(b)
1629
raise BzrCommandError("No missing location known or specified.")
1632
print "Using last location: %s" % parent
1634
elif parent is None:
1635
# We only update x-pull if it did not exist, missing should not change the parent
1636
b.controlfile('x-pull', 'wb').write(remote + '\n')
1637
br_remote = find_branch(remote)
1639
return show_missing(b, br_remote, verbose=verbose, quiet=quiet)
1643
1437
class cmd_plugins(Command):
1633
def _parse_master_args(argv):
1634
"""Parse the arguments that always go with the original command.
1635
These are things like bzr --no-plugins, etc.
1637
There are now 2 types of option flags. Ones that come *before* the command,
1638
and ones that come *after* the command.
1639
Ones coming *before* the command are applied against all possible commands.
1640
And are generally applied before plugins are loaded.
1642
The current list are:
1643
--builtin Allow plugins to load, but don't let them override builtin commands,
1644
they will still be allowed if they do not override a builtin.
1645
--no-plugins Don't load any plugins. This lets you get back to official source
1647
--profile Enable the hotspot profile before running the command.
1648
For backwards compatibility, this is also a non-master option.
1649
--version Spit out the version of bzr that is running and exit.
1650
This is also a non-master option.
1651
--help Run help and exit, also a non-master option (I think that should stay, though)
1653
>>> argv, opts = _parse_master_args(['bzr', '--test'])
1654
Traceback (most recent call last):
1656
BzrCommandError: Invalid master option: 'test'
1657
>>> argv, opts = _parse_master_args(['bzr', '--version', 'command'])
1660
>>> print opts['version']
1662
>>> argv, opts = _parse_master_args(['bzr', '--profile', 'command', '--more-options'])
1664
['command', '--more-options']
1665
>>> print opts['profile']
1667
>>> argv, opts = _parse_master_args(['bzr', '--no-plugins', 'command'])
1670
>>> print opts['no-plugins']
1672
>>> print opts['profile']
1674
>>> argv, opts = _parse_master_args(['bzr', 'command', '--profile'])
1676
['command', '--profile']
1677
>>> print opts['profile']
1680
master_opts = {'builtin':False,
1687
# This is the point where we could hook into argv[0] to determine
1688
# what front-end is supposed to be run
1689
# For now, we are just ignoring it.
1690
cmd_name = argv.pop(0)
1692
if arg[:2] != '--': # at the first non-option, we return the rest
1694
arg = arg[2:] # Remove '--'
1695
if arg not in master_opts:
1696
# We could say that this is not an error, that we should
1697
# just let it be handled by the main section instead
1698
raise BzrCommandError('Invalid master option: %r' % arg)
1699
argv.pop(0) # We are consuming this entry
1700
master_opts[arg] = True
1701
return argv, master_opts
1844
1705
def run_bzr(argv):
1845
1706
"""Execute a command.
1847
1708
This is similar to main(), but without all the trappings for
1848
1709
logging and error handling.
1851
The command-line arguments, without the program name from argv[0]
1853
Returns a command status or raises an exception.
1855
Special master options: these must come before the command because
1856
they control how the command is interpreted.
1859
Do not load plugin modules at all
1862
Only use builtin commands. (Plugins are still allowed to change
1866
Run under the Python profiler.
1869
1711
argv = [a.decode(bzrlib.user_encoding) for a in argv]
1871
opt_profile = opt_no_plugins = opt_builtin = False
1873
# --no-plugins is handled specially at a very early stage. We need
1874
# to load plugins before doing other command parsing so that they
1875
# can override commands, but this needs to happen first.
1878
if a == '--profile':
1880
elif a == '--no-plugins':
1881
opt_no_plugins = True
1882
elif a == '--builtin':
1888
if not opt_no_plugins:
1889
from bzrlib.plugin import load_plugins
1892
args, opts = parse_args(argv)
1895
from bzrlib.help import help
1902
if 'version' in opts:
1907
from bzrlib.help import help
1911
cmd = str(args.pop(0))
1913
canonical_cmd, cmd_class = \
1914
get_cmd_class(cmd, plugins_override=not opt_builtin)
1714
# some options like --builtin and --no-plugins have special effects
1715
argv, master_opts = _parse_master_args(argv)
1716
if not master_opts['no-plugins']:
1717
from bzrlib.plugin import load_plugins
1720
args, opts = parse_args(argv)
1722
if master_opts['help']:
1723
from bzrlib.help import help
1731
from bzrlib.help import help
1737
elif 'version' in opts:
1740
elif args and args[0] == 'builtin':
1741
include_plugins=False
1743
cmd = str(args.pop(0))
1750
plugins_override = not (master_opts['builtin'])
1751
canonical_cmd, cmd_class = get_cmd_class(cmd, plugins_override=plugins_override)
1753
profile = master_opts['profile']
1754
# For backwards compatibility, I would rather stick with --profile being a
1755
# master/global option
1756
if 'profile' in opts:
1916
1760
# check options are reasonable
1917
1761
allowed = cmd_class.takes_options
1951
1795
return cmd_class(cmdopts, cmdargs).status
1798
def _report_exception(summary, quiet=False):
1800
log_error('bzr: ' + summary)
1801
bzrlib.trace.log_exception()
1804
tb = sys.exc_info()[2]
1805
exinfo = traceback.extract_tb(tb)
1807
sys.stderr.write(' at %s:%d in %s()\n' % exinfo[-1][:3])
1808
sys.stderr.write(' see ~/.bzr.log for debug information\n')
1954
1812
def main(argv):
1956
bzrlib.trace.log_startup(argv)
1957
bzrlib.ui.ui_factory = bzrlib.ui.TextUIFactory()
1814
bzrlib.trace.open_tracefile(argv)
1961
return run_bzr(argv[1:])
1963
# do this here inside the exception wrappers to catch EPIPE
1965
except BzrCommandError, e:
1966
# command line syntax error, etc
1970
bzrlib.trace.log_exception()
1972
except AssertionError, e:
1973
bzrlib.trace.log_exception('assertion failed: ' + str(e))
1975
except KeyboardInterrupt, e:
1976
bzrlib.trace.note('interrupted')
1978
except Exception, e:
1980
if (isinstance(e, IOError)
1981
and hasattr(e, 'errno')
1982
and e.errno == errno.EPIPE):
1983
bzrlib.trace.note('broken pipe')
1986
bzrlib.trace.log_exception()
1819
return run_bzr(argv)
1821
# do this here inside the exception wrappers to catch EPIPE
1824
quiet = isinstance(e, (BzrCommandError))
1825
_report_exception('error: ' + e.args[0], quiet=quiet)
1828
# some explanation or hints
1831
except AssertionError, e:
1832
msg = 'assertion failed'
1834
msg += ': ' + str(e)
1835
_report_exception(msg)
1837
except KeyboardInterrupt, e:
1838
_report_exception('interrupted', quiet=True)
1840
except Exception, e:
1843
if (isinstance(e, IOError)
1844
and hasattr(e, 'errno')
1845
and e.errno == errno.EPIPE):
1849
msg = str(e).rstrip('\n')
1850
_report_exception(msg, quiet)
1853
bzrlib.trace.close_trace()
1990
1856
if __name__ == '__main__':