15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
import sys, os, time, os.path
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.
23
from bzrlib.trace import mutter, note, log_error
24
from bzrlib.errors import bailout, BzrError, BzrCheckError, BzrCommandError
25
from bzrlib.osutils import quotefn, pumpfile, isdir, isfile
26
from bzrlib.tree import RevisionTree, EmptyTree, WorkingTree, Tree
27
from bzrlib.revision import Revision
28
from bzrlib import Branch, Inventory, InventoryEntry, ScratchBranch, BZRDIR, \
35
from bzrlib.trace import mutter, note, log_error, warning
36
from bzrlib.errors import BzrError, BzrCheckError, BzrCommandError
37
from bzrlib.branch import find_branch
38
from bzrlib import BZRDIR
44
def register_command(cmd):
45
"Utility function to help register a command"
48
if k.startswith("cmd_"):
49
k_unsquished = _unsquish_command_name(k)
52
if not plugin_cmds.has_key(k_unsquished):
53
plugin_cmds[k_unsquished] = cmd
55
log_error('Two plugins defined the same command: %r' % k)
56
log_error('Not loading the one in %r' % sys.modules[cmd.__module__])
32
59
def _squish_command_name(cmd):
37
64
assert cmd.startswith("cmd_")
38
65
return cmd[4:].replace('_','-')
41
"""Return canonical name and class for all registered commands."""
68
def _parse_revision_str(revstr):
69
"""This handles a revision string -> revno.
71
This always returns a list. The list will have one element for
73
It supports integers directly, but everything else it
74
defers for passing to Branch.get_revision_info()
76
>>> _parse_revision_str('234')
78
>>> _parse_revision_str('234..567')
80
>>> _parse_revision_str('..')
82
>>> _parse_revision_str('..234')
84
>>> _parse_revision_str('234..')
86
>>> _parse_revision_str('234..456..789') # Maybe this should be an error
88
>>> _parse_revision_str('234....789') # Error?
90
>>> _parse_revision_str('revid:test@other.com-234234')
91
['revid:test@other.com-234234']
92
>>> _parse_revision_str('revid:test@other.com-234234..revid:test@other.com-234235')
93
['revid:test@other.com-234234', 'revid:test@other.com-234235']
94
>>> _parse_revision_str('revid:test@other.com-234234..23')
95
['revid:test@other.com-234234', 23]
96
>>> _parse_revision_str('date:2005-04-12')
98
>>> _parse_revision_str('date:2005-04-12 12:24:33')
99
['date:2005-04-12 12:24:33']
100
>>> _parse_revision_str('date:2005-04-12T12:24:33')
101
['date:2005-04-12T12:24:33']
102
>>> _parse_revision_str('date:2005-04-12,12:24:33')
103
['date:2005-04-12,12:24:33']
104
>>> _parse_revision_str('-5..23')
106
>>> _parse_revision_str('-5')
108
>>> _parse_revision_str('123a')
110
>>> _parse_revision_str('abc')
114
old_format_re = re.compile('\d*:\d*')
115
m = old_format_re.match(revstr)
117
warning('Colon separator for revision numbers is deprecated.'
120
for rev in revstr.split(':'):
122
revs.append(int(rev))
127
for x in revstr.split('..'):
138
def get_merge_type(typestring):
139
"""Attempt to find the merge class/factory associated with a string."""
140
from merge import merge_types
142
return merge_types[typestring][0]
144
templ = '%s%%7s: %%s' % (' '*12)
145
lines = [templ % (f[0], f[1][1]) for f in merge_types.iteritems()]
146
type_list = '\n'.join(lines)
147
msg = "No known merge type %s. Supported types are:\n%s" %\
148
(typestring, type_list)
149
raise BzrCommandError(msg)
152
def get_merge_type(typestring):
153
"""Attempt to find the merge class/factory associated with a string."""
154
from merge import merge_types
156
return merge_types[typestring][0]
158
templ = '%s%%7s: %%s' % (' '*12)
159
lines = [templ % (f[0], f[1][1]) for f in merge_types.iteritems()]
160
type_list = '\n'.join(lines)
161
msg = "No known merge type %s. Supported types are:\n%s" %\
162
(typestring, type_list)
163
raise BzrCommandError(msg)
167
def _get_cmd_dict(plugins_override=True):
42
169
for k, v in globals().iteritems():
43
170
if k.startswith("cmd_"):
44
yield _unsquish_command_name(k), v
46
def get_cmd_class(cmd):
171
d[_unsquish_command_name(k)] = v
172
# If we didn't load plugins, the plugin_cmds dict will be empty
174
d.update(plugin_cmds)
176
d2 = plugin_cmds.copy()
182
def get_all_cmds(plugins_override=True):
183
"""Return canonical name and class for all registered commands."""
184
for k, v in _get_cmd_dict(plugins_override=plugins_override).iteritems():
188
def get_cmd_class(cmd, plugins_override=True):
47
189
"""Return the canonical name and command class for a command.
49
191
cmd = str(cmd) # not unicode
51
193
# first look up this command under the specified name
194
cmds = _get_cmd_dict(plugins_override=plugins_override)
53
return cmd, globals()[_squish_command_name(cmd)]
196
return cmd, cmds[cmd]
57
200
# look for any command which claims this as an alias
58
for cmdname, cmdclass in get_all_cmds():
201
for cmdname, cmdclass in cmds.iteritems():
59
202
if cmd in cmdclass.aliases:
60
203
return cmdname, cmdclass
118
264
class ExternalCommand(Command):
119
265
"""Class to wrap external commands.
121
We cheat a little here, when get_cmd_class() calls us we actually give it back
122
an object we construct that has the appropriate path, help, options etc for the
125
When run_bzr() tries to instantiate that 'class' it gets caught by the __call__
126
method, which we override to call the Command.__init__ method. That then calls
127
our run method which is pretty straight forward.
129
The only wrinkle is that we have to map bzr's dictionary of options and arguments
130
back into command line options and arguments for the script.
267
We cheat a little here, when get_cmd_class() calls us we actually
268
give it back an object we construct that has the appropriate path,
269
help, options etc for the specified command.
271
When run_bzr() tries to instantiate that 'class' it gets caught by
272
the __call__ method, which we override to call the Command.__init__
273
method. That then calls our run method which is pretty straight
276
The only wrinkle is that we have to map bzr's dictionary of options
277
and arguments back into command line options and arguments for the
133
281
def find_command(cls, cmd):
134
283
bzrpath = os.environ.get('BZRPATH', '')
136
for dir in bzrpath.split(':'):
285
for dir in bzrpath.split(os.pathsep):
137
286
path = os.path.join(dir, cmd)
138
287
if os.path.isfile(path):
139
288
return ExternalCommand(path)
145
294
def __init__(self, path):
148
# TODO: If either of these fail, we should detect that and
149
# assume that path is not really a bzr plugin after all.
151
297
pipe = os.popen('%s --bzr-usage' % path, 'r')
152
298
self.takes_options = pipe.readline().split()
300
for opt in self.takes_options:
301
if not opt in OPTIONS:
302
raise BzrError("Unknown option '%s' returned by external command %s"
305
# TODO: Is there any way to check takes_args is valid here?
153
306
self.takes_args = pipe.readline().split()
308
if pipe.close() is not None:
309
raise BzrError("Failed funning '%s --bzr-usage'" % path)
156
311
pipe = os.popen('%s --bzr-help' % path, 'r')
157
312
self.__doc__ = pipe.read()
313
if pipe.close() is not None:
314
raise BzrError("Failed funning '%s --bzr-help'" % path)
160
316
def __call__(self, options, arguments):
161
317
Command.__init__(self, options, arguments)
189
346
class cmd_status(Command):
190
347
"""Display status summary.
192
For each file there is a single line giving its file state and name.
193
The name is that in the current revision unless it is deleted or
194
missing, in which case the old name is shown.
349
This reports on versioned and unknown files, reporting them
350
grouped by state. Possible states are:
353
Versioned in the working copy but not in the previous revision.
356
Versioned in the previous revision but removed or deleted
360
Path of this file changed from the previous revision;
361
the text may also have changed. This includes files whose
362
parent directory was renamed.
365
Text has changed since the previous revision.
368
Nothing about this file has changed since the previous revision.
369
Only shown with --all.
372
Not versioned and not matching an ignore pattern.
374
To see ignored files use 'bzr ignored'. For details in the
375
changes to file texts, use 'bzr diff'.
377
If no arguments are specified, the status of the entire working
378
directory is shown. Otherwise, only the status of the specified
379
files or directories is reported. If a directory is given, status
380
is reported for everything inside that directory.
382
If a revision is specified, the changes since that revision are shown.
196
384
takes_args = ['file*']
197
takes_options = ['all']
385
takes_options = ['all', 'show-ids', 'revision']
198
386
aliases = ['st', 'stat']
200
def run(self, all=False, file_list=None):
201
b = Branch('.', lock_mode='r')
202
b.show_status(show_all=all, file_list=file_list)
388
def run(self, all=False, show_ids=False, file_list=None):
390
b = find_branch(file_list[0])
391
file_list = [b.relpath(x) for x in file_list]
392
# special case: only one path was given and it's the root
394
if file_list == ['']:
399
from bzrlib.status import show_status
400
show_status(b, show_unchanged=all, show_ids=show_ids,
401
specific_files=file_list)
205
404
class cmd_cat_revision(Command):
233
455
whether already versioned or not, are searched for files or
234
456
subdirectories that are neither versioned or ignored, and these
235
457
are added. This search proceeds recursively into versioned
458
directories. If no names are given '.' is assumed.
238
Therefore simply saying 'bzr add .' will version all files that
460
Therefore simply saying 'bzr add' will version all files that
239
461
are currently unknown.
241
463
TODO: Perhaps adding a file whose directly is not versioned should
242
464
recursively add that parent, rather than giving an error?
244
takes_args = ['file+']
245
takes_options = ['verbose']
466
takes_args = ['file*']
467
takes_options = ['verbose', 'no-recurse']
247
def run(self, file_list, verbose=False):
248
bzrlib.add.smart_add(file_list, verbose)
469
def run(self, file_list, verbose=False, no_recurse=False):
470
from bzrlib.add import smart_add
471
smart_add(file_list, verbose, not no_recurse)
475
class cmd_mkdir(Command):
476
"""Create a new versioned directory.
478
This is equivalent to creating the directory and then adding it.
480
takes_args = ['dir+']
482
def run(self, dir_list):
489
b.add([d], verbose=True)
251
492
class cmd_relpath(Command):
252
493
"""Show path of a file relative to root"""
253
494
takes_args = ['filename']
255
497
def run(self, filename):
256
print Branch(filename).relpath(filename)
498
print find_branch(filename).relpath(filename)
260
502
class cmd_inventory(Command):
261
503
"""Show inventory of the current working copy or a revision."""
262
takes_options = ['revision']
504
takes_options = ['revision', 'show-ids']
264
def run(self, revision=None):
506
def run(self, revision=None, show_ids=False):
266
508
if revision == None:
267
509
inv = b.read_working_inventory()
269
inv = b.get_revision_inventory(b.lookup_revision(revision))
511
if len(revision) > 1:
512
raise BzrCommandError('bzr inventory --revision takes'
513
' exactly one revision identifier')
514
inv = b.get_revision_inventory(b.lookup_revision(revision[0]))
271
for path, entry in inv.iter_entries():
272
print '%-50s %s' % (entry.file_id, path)
516
for path, entry in inv.entries():
518
print '%-50s %s' % (path, entry.file_id)
275
523
class cmd_move(Command):
304
553
takes_args = ['from_name', 'to_name']
306
555
def run(self, from_name, to_name):
308
557
b.rename_one(b.relpath(from_name), b.relpath(to_name))
561
class cmd_mv(Command):
562
"""Move or rename a file.
565
bzr mv OLDNAME NEWNAME
566
bzr mv SOURCE... DESTINATION
568
If the last argument is a versioned directory, all the other names
569
are moved into it. Otherwise, there must be exactly two arguments
570
and the file is changed to a new name, which must not already exist.
572
Files cannot be moved between branches.
574
takes_args = ['names*']
575
def run(self, names_list):
576
if len(names_list) < 2:
577
raise BzrCommandError("missing file argument")
578
b = find_branch(names_list[0])
580
rel_names = [b.relpath(x) for x in names_list]
582
if os.path.isdir(names_list[-1]):
583
# move into existing directory
584
b.move(rel_names[:-1], rel_names[-1])
586
if len(names_list) != 2:
587
raise BzrCommandError('to mv multiple files the destination '
588
'must be a versioned directory')
589
b.move(rel_names[0], rel_names[1])
594
class cmd_pull(Command):
595
"""Pull any changes from another branch into the current one.
597
If the location is omitted, the last-used location will be used.
598
Both the revision history and the working directory will be
601
This command only works on branches that have not diverged. Branches are
602
considered diverged if both branches have had commits without first
603
pulling from the other.
605
If branches have diverged, you can use 'bzr merge' to pull the text changes
606
from one into the other.
608
takes_args = ['location?']
610
def run(self, location=None):
611
from bzrlib.merge import merge
613
from shutil import rmtree
616
br_to = find_branch('.')
619
stored_loc = br_to.controlfile("x-pull", "rb").read().rstrip('\n')
621
if e.errno != errno.ENOENT:
624
if stored_loc is None:
625
raise BzrCommandError("No pull location known or specified.")
627
print "Using last location: %s" % stored_loc
628
location = stored_loc
629
cache_root = tempfile.mkdtemp()
630
from bzrlib.branch import DivergedBranches
631
br_from = find_branch(location)
632
location = pull_loc(br_from)
633
old_revno = br_to.revno()
635
from branch import find_cached_branch, DivergedBranches
636
br_from = find_cached_branch(location, cache_root)
637
location = pull_loc(br_from)
638
old_revno = br_to.revno()
640
br_to.update_revisions(br_from)
641
except DivergedBranches:
642
raise BzrCommandError("These branches have diverged."
645
merge(('.', -1), ('.', old_revno), check_clean=False)
646
if location != stored_loc:
647
br_to.controlfile("x-pull", "wb").write(location + "\n")
653
class cmd_branch(Command):
654
"""Create a new copy of a branch.
656
If the TO_LOCATION is omitted, the last component of the FROM_LOCATION will
657
be used. In other words, "branch ../foo/bar" will attempt to create ./bar.
659
To retrieve the branch as of a particular revision, supply the --revision
660
parameter, as in "branch foo/bar -r 5".
662
takes_args = ['from_location', 'to_location?']
663
takes_options = ['revision']
664
aliases = ['get', 'clone']
666
def run(self, from_location, to_location=None, revision=None):
668
from bzrlib.merge import merge
669
from bzrlib.branch import DivergedBranches, \
670
find_cached_branch, Branch
671
from shutil import rmtree
672
from meta_store import CachedStore
674
cache_root = tempfile.mkdtemp()
678
elif len(revision) > 1:
679
raise BzrCommandError('bzr branch --revision takes exactly 1 revision value')
683
br_from = find_cached_branch(from_location, cache_root)
685
if e.errno == errno.ENOENT:
686
raise BzrCommandError('Source location "%s" does not'
687
' exist.' % to_location)
691
if to_location is None:
692
to_location = os.path.basename(from_location.rstrip("/\\"))
695
os.mkdir(to_location)
697
if e.errno == errno.EEXIST:
698
raise BzrCommandError('Target directory "%s" already'
699
' exists.' % to_location)
700
if e.errno == errno.ENOENT:
701
raise BzrCommandError('Parent of "%s" does not exist.' %
705
br_to = Branch(to_location, init=True)
707
br_to.set_root_id(br_from.get_root_id())
710
if revision[0] is None:
711
revno = br_from.revno()
713
revno, rev_id = br_from.get_revision_info(revision[0])
715
br_to.update_revisions(br_from, stop_revision=revno)
716
except bzrlib.errors.NoSuchRevision:
718
msg = "The branch %s has no revision %d." % (from_location,
720
raise BzrCommandError(msg)
722
merge((to_location, -1), (to_location, 0), this_dir=to_location,
723
check_clean=False, ignore_zero=True)
724
from_location = pull_loc(br_from)
725
br_to.controlfile("x-pull", "wb").write(from_location + "\n")
730
def pull_loc(branch):
731
# TODO: Should perhaps just make attribute be 'base' in
732
# RemoteBranch and Branch?
733
if hasattr(branch, "baseurl"):
734
return branch.baseurl
312
740
class cmd_renames(Command):
313
741
"""Show list of renamed files.
443
875
TODO: This probably handles non-Unix newlines poorly.
446
883
takes_args = ['file*']
447
takes_options = ['revision']
884
takes_options = ['revision', 'diff-options']
885
aliases = ['di', 'dif']
450
def run(self, revision=None, file_list=None):
887
def run(self, revision=None, file_list=None, diff_options=None):
451
888
from bzrlib.diff import show_diff
453
show_diff(Branch('.'), revision, file_list)
891
b = find_branch(file_list[0])
892
file_list = [b.relpath(f) for f in file_list]
893
if file_list == ['']:
894
# just pointing to top-of-tree
899
if revision is not None:
900
if len(revision) == 1:
901
show_diff(b, revision[0], specific_files=file_list,
902
external_diff_options=diff_options)
903
elif len(revision) == 2:
904
show_diff(b, revision[0], specific_files=file_list,
905
external_diff_options=diff_options,
906
revision2=revision[1])
908
raise BzrCommandError('bzr diff --revision takes exactly one or two revision identifiers')
910
show_diff(b, None, specific_files=file_list,
911
external_diff_options=diff_options)
483
940
"""List files modified in working tree."""
488
inv = b.read_working_inventory()
489
sc = statcache.update_cache(b, inv)
490
basis = b.basis_tree()
491
basis_inv = basis.inventory
493
# We used to do this through iter_entries(), but that's slow
494
# when most of the files are unmodified, as is usually the
495
# case. So instead we iterate by inventory entry, and only
496
# calculate paths as necessary.
498
for file_id in basis_inv:
499
cacheentry = sc.get(file_id)
500
if not cacheentry: # deleted
502
ie = basis_inv[file_id]
503
if cacheentry[statcache.SC_SHA1] != ie.text_sha1:
504
path = inv.id2path(file_id)
943
from bzrlib.delta import compare_trees
946
td = compare_trees(b.basis_tree(), b.working_tree())
948
for path, id, kind in td.modified:
540
983
class cmd_log(Command):
541
984
"""Show log of this branch.
543
TODO: Option to limit range.
545
TODO: Perhaps show most-recent first with an option for last.
986
To request a range of logs, you can use the command -r begin:end
987
-r revision requests a specific revision, -r :end or -r begin: are
990
--message allows you to give a regular expression, which will be evaluated
991
so that only matching entries will be displayed.
993
TODO: Make --revision support uuid: and hash: [future tag:] notation.
547
997
takes_args = ['filename?']
548
takes_options = ['timezone', 'verbose', 'show-ids']
549
def run(self, filename=None, timezone='original', verbose=False, show_ids=False):
550
from branch import find_branch
551
b = find_branch((filename or '.'), lock_mode='r')
998
takes_options = ['forward', 'timezone', 'verbose', 'show-ids', 'revision',
999
'long', 'message', 'short',]
1001
def run(self, filename=None, timezone='original',
1009
from bzrlib.branch import find_branch
1010
from bzrlib.log import log_formatter, show_log
1013
direction = (forward and 'forward') or 'reverse'
553
filename = b.relpath(filename)
554
bzrlib.show_log(b, filename,
555
show_timezone=timezone,
1016
b = find_branch(filename)
1017
fp = b.relpath(filename)
1019
file_id = b.read_working_inventory().path2id(fp)
1021
file_id = None # points to branch root
1023
b = find_branch('.')
1026
if revision is None:
1029
elif len(revision) == 1:
1030
rev1 = rev2 = b.get_revision_info(revision[0])[0]
1031
elif len(revision) == 2:
1032
rev1 = b.get_revision_info(revision[0])[0]
1033
rev2 = b.get_revision_info(revision[1])[0]
1035
raise BzrCommandError('bzr log --revision takes one or two values.')
1042
mutter('encoding log as %r' % bzrlib.user_encoding)
1044
# use 'replace' so that we don't abort if trying to write out
1045
# in e.g. the default C locale.
1046
outf = codecs.getwriter(bzrlib.user_encoding)(sys.stdout, errors='replace')
1051
log_format = 'short'
1052
lf = log_formatter(log_format,
1055
show_timezone=timezone)
1061
direction=direction,
1062
start_revision=rev1,
561
1068
class cmd_touching_revisions(Command):
562
"""Return revision-ids which affected a particular file."""
1069
"""Return revision-ids which affected a particular file.
1071
A more user-friendly interface is "bzr log FILE"."""
564
1073
takes_args = ["filename"]
565
1074
def run(self, filename):
566
b = Branch(filename, lock_mode='r')
1075
b = find_branch(filename)
567
1076
inv = b.read_working_inventory()
568
1077
file_id = inv.path2id(b.relpath(filename))
569
1078
for revno, revision_id, what in bzrlib.log.find_touching_revisions(b, file_id):
687
1203
except ValueError:
688
1204
raise BzrCommandError("not a valid revision-number: %r" % revno)
690
print Branch('.').lookup_revision(revno)
1206
print find_branch('.').lookup_revision(revno)
693
1209
class cmd_export(Command):
694
1210
"""Export past revision to destination directory.
696
If no revision is specified this exports the last committed revision."""
1212
If no revision is specified this exports the last committed revision.
1214
Format may be an "exporter" name, such as tar, tgz, tbz2. If none is
1215
given, try to find the format with the extension. If no extension
1216
is found exports to a directory (equivalent to --format=dir).
1218
Root may be the top directory for tar, tgz and tbz2 formats. If none
1219
is given, the top directory will be the root name of the file."""
1220
# TODO: list known exporters
697
1221
takes_args = ['dest']
698
takes_options = ['revision']
699
def run(self, dest, revision=None):
702
rh = b.revision_history()[-1]
1222
takes_options = ['revision', 'format', 'root']
1223
def run(self, dest, revision=None, format=None, root=None):
1225
b = find_branch('.')
1226
if revision is None:
1227
rev_id = b.last_patch()
704
rh = b.lookup_revision(int(revision))
705
t = b.revision_tree(rh)
1229
if len(revision) != 1:
1230
raise BzrError('bzr export --revision takes exactly 1 argument')
1231
revno, rev_id = b.get_revision_info(revision[0])
1232
t = b.revision_tree(rev_id)
1233
root, ext = os.path.splitext(dest)
1235
if ext in (".tar",):
1237
elif ext in (".gz", ".tgz"):
1239
elif ext in (".bz2", ".tbz2"):
1243
t.export(dest, format, root)
709
1246
class cmd_cat(Command):
730
1269
class cmd_commit(Command):
731
1270
"""Commit changes into a new revision.
733
TODO: Commit only selected files.
1272
If no arguments are given, the entire tree is committed.
1274
If selected files are specified, only changes to those files are
1275
committed. If a directory is specified then the directory and everything
1276
within it is committed.
1278
A selected-file commit may fail in some cases where the committed
1279
tree would be invalid, such as trying to commit a file in a
1280
newly-added directory that is not itself committed.
735
1282
TODO: Run hooks on tree to-be-committed, and after commit.
737
1284
TODO: Strict commit that fails if there are unknown or deleted files.
739
takes_options = ['message', 'file', 'verbose']
1286
takes_args = ['selected*']
1287
takes_options = ['message', 'file', 'verbose', 'unchanged']
740
1288
aliases = ['ci', 'checkin']
742
def run(self, message=None, file=None, verbose=False):
1290
# TODO: Give better message for -s, --summary, used by tla people
1292
def run(self, message=None, file=None, verbose=True, selected_list=None,
1294
from bzrlib.errors import PointlessCommit
1295
from bzrlib.osutils import get_text_message
743
1297
## Warning: shadows builtin file()
744
1298
if not message and not file:
745
raise BzrCommandError("please specify a commit message",
746
["use either --message or --file"])
1299
# FIXME: Ugly; change status code to send to a provided function?
1303
catcher = cStringIO.StringIO()
1304
sys.stdout = catcher
1305
cmd_status({"file_list":selected_list}, {})
1306
info = catcher.getvalue()
1308
message = get_text_message(info)
1311
raise BzrCommandError("please specify a commit message",
1312
["use either --message or --file"])
747
1313
elif message and file:
748
1314
raise BzrCommandError("please specify either --message or --file")
760
1338
This command checks various invariants about the branch storage to
761
1339
detect data corruption or bzr bugs.
763
takes_args = ['dir?']
764
def run(self, dir='.'):
766
bzrlib.check.check(Branch(dir, find_root=False))
1341
If given the --update flag, it will update some optional fields
1342
to help ensure data consistency.
1344
takes_args = ['dir?']
1346
def run(self, dir='.'):
1347
from bzrlib.check import check
1349
check(find_branch(dir))
1352
class cmd_scan_cache(Command):
1355
from bzrlib.hashcache import HashCache
1362
print '%6d stats' % c.stat_count
1363
print '%6d in hashcache' % len(c._cache)
1364
print '%6d files removed from cache' % c.removed_count
1365
print '%6d hashes updated' % c.update_count
1366
print '%6d files changed too recently to cache' % c.danger_count
1373
class cmd_upgrade(Command):
1374
"""Upgrade branch storage to current format.
1376
This should normally be used only after the check command tells
1379
takes_args = ['dir?']
1381
def run(self, dir='.'):
1382
from bzrlib.upgrade import upgrade
1383
upgrade(find_branch(dir))
772
1389
takes_options = ['email']
774
1391
def run(self, email=False):
1393
b = bzrlib.branch.find_branch('.')
776
print bzrlib.osutils.user_email()
1398
print bzrlib.osutils.user_email(b)
778
print bzrlib.osutils.username()
1400
print bzrlib.osutils.username(b)
781
1403
class cmd_selftest(Command):
782
1404
"""Run internal test suite"""
785
failures, tests = 0, 0
787
import doctest, bzrlib.store, bzrlib.tests
788
bzrlib.trace.verbose = False
790
for m in bzrlib.store, bzrlib.inventory, bzrlib.branch, bzrlib.osutils, \
791
bzrlib.tree, bzrlib.tests, bzrlib.commands, bzrlib.add:
792
mf, mt = doctest.testmod(m)
795
print '%-40s %3d tests' % (m.__name__, mt),
797
print '%3d FAILED!' % mf
1406
takes_options = ['verbose']
1407
def run(self, verbose=False):
1409
from bzrlib.selftest import selftest
1411
# we don't want progress meters from the tests to go to the
1412
# real output; and we don't want log messages cluttering up
1415
save_ui = bzrlib.ui.ui_factory
1416
bzrlib.trace.info('running tests...')
1417
bzrlib.trace.disable_default_logging()
1419
bzrlib.ui.ui_factory = bzrlib.ui.SilentUIFactory()
1420
result = selftest(verbose=verbose)
1422
bzrlib.trace.info('tests passed')
801
print '%-40s %3d tests' % ('total', tests),
803
print '%3d FAILED!' % failures
1424
bzrlib.trace.info('tests failed')
1425
return int(not result)
1427
bzrlib.trace.enable_default_logging()
1428
bzrlib.ui.ui_factory = save_ui
809
1431
class cmd_version(Command):
810
"""Show version of bzr"""
1432
"""Show version of bzr."""
814
1436
def show_version():
815
1437
print "bzr (bazaar-ng) %s" % bzrlib.__version__
1438
# is bzrlib itself in a branch?
1439
bzrrev = bzrlib.get_bzr_revision()
1441
print " (bzr checkout, revision %d {%s})" % bzrrev
816
1442
print bzrlib.__copyright__
817
1443
print "http://bazaar-ng.org/"
828
1454
print "it sure does!"
1456
def parse_spec(spec):
1458
>>> parse_spec(None)
1460
>>> parse_spec("./")
1462
>>> parse_spec("../@")
1464
>>> parse_spec("../f/@35")
1466
>>> parse_spec('./@revid:john@arbash-meinel.com-20050711044610-3ca0327c6a222f67')
1467
['.', 'revid:john@arbash-meinel.com-20050711044610-3ca0327c6a222f67']
1472
parsed = spec.split('/@')
1473
assert len(parsed) == 2
1478
parsed[1] = int(parsed[1])
1480
pass # We can allow stuff like ./@revid:blahblahblah
1482
assert parsed[1] >=0
1484
parsed = [spec, None]
1489
class cmd_find_merge_base(Command):
1490
"""Find and print a base revision for merging two branches.
1492
TODO: Options to specify revisions on either side, as if
1493
merging only part of the history.
1495
takes_args = ['branch', 'other']
1498
def run(self, branch, other):
1499
branch1 = find_branch(branch)
1500
branch2 = find_branch(other)
1502
base_revno, base_revid = branch1.common_ancestor(branch2)
1504
if base_revno is None:
1505
raise bzrlib.errors.UnrelatedBranches()
1507
print 'merge base is revision %s' % base_revid
1508
print ' r%-6d in %s' % (base_revno, branch)
1510
other_revno = branch2.revision_id_to_revno(base_revid)
1512
print ' r%-6d in %s' % (other_revno, other)
1516
class cmd_merge(Command):
1517
"""Perform a three-way merge.
1519
The branch is the branch you will merge from. By default, it will merge
1520
the latest revision. If you specify a revision, that revision will be
1521
merged. If you specify two revisions, the first will be used as a BASE,
1522
and the second one as OTHER. Revision numbers are always relative to the
1527
To merge the latest revision from bzr.dev
1528
bzr merge ../bzr.dev
1530
To merge changes up to and including revision 82 from bzr.dev
1531
bzr merge -r 82 ../bzr.dev
1533
To merge the changes introduced by 82, without previous changes:
1534
bzr merge -r 81..82 ../bzr.dev
1536
merge refuses to run if there are any uncommitted changes, unless
1539
takes_args = ['branch?']
1540
takes_options = ['revision', 'force', 'merge-type']
1542
def run(self, branch='.', revision=None, force=False,
1544
from bzrlib.merge import merge
1545
from bzrlib.merge_core import ApplyMerge3
1546
if merge_type is None:
1547
merge_type = ApplyMerge3
1549
if revision is None or len(revision) < 1:
1551
other = (branch, -1)
1553
if len(revision) == 1:
1554
other = (branch, revision[0])
1557
assert len(revision) == 2
1558
if None in revision:
1559
raise BzrCommandError(
1560
"Merge doesn't permit that revision specifier.")
1561
base = (branch, revision[0])
1562
other = (branch, revision[1])
1564
merge(other, base, check_clean=(not force), merge_type=merge_type)
1567
class cmd_revert(Command):
1568
"""Reverse all changes since the last commit.
1570
Only versioned files are affected. Specify filenames to revert only
1571
those files. By default, any files that are changed will be backed up
1572
first. Backup files have a '~' appended to their name.
1574
takes_options = ['revision', 'no-backup']
1575
takes_args = ['file*']
1576
aliases = ['merge-revert']
1578
def run(self, revision=None, no_backup=False, file_list=None):
1579
from bzrlib.merge import merge
1580
if file_list is not None:
1581
if len(file_list) == 0:
1582
raise BzrCommandError("No files specified")
1583
if revision is None:
1585
elif len(revision) != 1:
1586
raise BzrCommandError('bzr revert --revision takes exactly 1 argument')
1587
merge(('.', revision[0]), parse_spec('.'),
1590
backup_files=not no_backup,
1591
file_list=file_list)
831
1594
class cmd_assert_fail(Command):
832
1595
"""Test reporting of assertion failures"""
839
1602
"""Show help on a command or other topic.
841
1604
For a list of all available commands, say 'bzr help commands'."""
1605
takes_options = ['long']
842
1606
takes_args = ['topic?']
845
def run(self, topic=None):
1609
def run(self, topic=None, long=False):
1611
if topic is None and long:
847
1613
help.help(topic)
850
class cmd_update_stat_cache(Command):
851
"""Update stat-cache mapping inodes to SHA-1 hashes.
1616
class cmd_shell_complete(Command):
1617
"""Show appropriate completions for context.
1619
For a list of all available commands, say 'bzr shell-complete'."""
1620
takes_args = ['context?']
1624
def run(self, context=None):
1625
import shellcomplete
1626
shellcomplete.shellcomplete(context)
1629
class cmd_missing(Command):
1630
"""What is missing in this branch relative to other branch.
1632
takes_args = ['remote?']
1633
aliases = ['mis', 'miss']
1634
# We don't have to add quiet to the list, because
1635
# unknown options are parsed as booleans
1636
takes_options = ['verbose', 'quiet']
1638
def run(self, remote=None, verbose=False, quiet=False):
1639
from bzrlib.branch import find_branch, DivergedBranches
1640
from bzrlib.errors import BzrCommandError
1641
from bzrlib.missing import get_parent, show_missing
1643
if verbose and quiet:
1644
raise BzrCommandError('Cannot pass both quiet and verbose')
1646
b = find_branch('.')
1647
parent = get_parent(b)
1650
raise BzrCommandError("No missing location known or specified.")
1653
print "Using last location: %s" % parent
1655
elif parent is None:
1656
# We only update x-pull if it did not exist, missing should not change the parent
1657
b.controlfile('x-pull', 'wb').write(remote + '\n')
1658
br_remote = find_branch(remote)
1660
return show_missing(b, br_remote, verbose=verbose, quiet=quiet)
1664
class cmd_plugins(Command):
858
statcache.update_cache(b)
861
######################################################################
1668
import bzrlib.plugin
1669
from inspect import getdoc
1670
from pprint import pprint
1671
for plugin in bzrlib.plugin.all_plugins:
1672
print plugin.__path__[0]
1675
print '\t', d.split('\n')[0]
1677
#pprint(bzrlib.plugin.all_plugins)
865
1681
# list of all available options; the rhs can be either None for an
924
1762
if optname not in OPTIONS:
925
bailout('unknown long option %r' % a)
1763
raise BzrError('unknown long option %r' % a)
927
1765
shortopt = a[1:]
928
if shortopt not in SHORT_OPTIONS:
929
bailout('unknown short option %r' % a)
930
optname = SHORT_OPTIONS[shortopt]
1766
if shortopt in SHORT_OPTIONS:
1767
# Multi-character options must have a space to delimit
1769
optname = SHORT_OPTIONS[shortopt]
1771
# Single character short options, can be chained,
1772
# and have their value appended to their name
1774
if shortopt not in SHORT_OPTIONS:
1775
# We didn't find the multi-character name, and we
1776
# didn't find the single char name
1777
raise BzrError('unknown short option %r' % a)
1778
optname = SHORT_OPTIONS[shortopt]
1781
# There are extra things on this option
1782
# see if it is the value, or if it is another
1784
optargfn = OPTIONS[optname]
1785
if optargfn is None:
1786
# This option does not take an argument, so the
1787
# next entry is another short option, pack it back
1789
argv.insert(0, '-' + a[2:])
1791
# This option takes an argument, so pack it
932
1795
if optname in opts:
933
1796
# XXX: Do we ever want to support this, e.g. for -r?
934
bailout('repeated option %r' % a)
1797
raise BzrError('repeated option %r' % a)
936
1799
optargfn = OPTIONS[optname]
938
1801
if optarg == None:
940
bailout('option %r needs an argument' % a)
1803
raise BzrError('option %r needs an argument' % a)
942
1805
optarg = argv.pop(0)
943
1806
opts[optname] = optargfn(optarg)
945
1808
if optarg != None:
946
bailout('option %r takes no argument' % optname)
1809
raise BzrError('option %r takes no argument' % optname)
947
1810
opts[optname] = True
1004
1867
This is similar to main(), but without all the trappings for
1005
1868
logging and error handling.
1871
The command-line arguments, without the program name from argv[0]
1873
Returns a command status or raises an exception.
1875
Special master options: these must come before the command because
1876
they control how the command is interpreted.
1879
Do not load plugin modules at all
1882
Only use builtin commands. (Plugins are still allowed to change
1886
Run under the Python profiler.
1007
1889
argv = [a.decode(bzrlib.user_encoding) for a in argv]
1010
args, opts = parse_args(argv[1:])
1018
elif 'version' in opts:
1021
cmd = str(args.pop(0))
1023
log_error('usage: bzr COMMAND')
1024
log_error(' try "bzr help"')
1027
canonical_cmd, cmd_class = get_cmd_class(cmd)
1030
if 'profile' in opts:
1891
opt_profile = opt_no_plugins = opt_builtin = False
1893
# --no-plugins is handled specially at a very early stage. We need
1894
# to load plugins before doing other command parsing so that they
1895
# can override commands, but this needs to happen first.
1898
if a == '--profile':
1900
elif a == '--no-plugins':
1901
opt_no_plugins = True
1902
elif a == '--builtin':
1908
if not opt_no_plugins:
1909
from bzrlib.plugin import load_plugins
1912
args, opts = parse_args(argv)
1915
from bzrlib.help import help
1922
if 'version' in opts:
1927
from bzrlib.help import help
1931
cmd = str(args.pop(0))
1933
canonical_cmd, cmd_class = \
1934
get_cmd_class(cmd, plugins_override=not opt_builtin)
1036
1936
# check options are reasonable
1037
1937
allowed = cmd_class.takes_options
1068
1968
os.close(pffileno)
1069
1969
os.remove(pfname)
1071
cmdobj = cmd_class(cmdopts, cmdargs).status
1074
def _report_exception(summary, quiet=False):
1076
log_error('bzr: ' + summary)
1077
bzrlib.trace.log_exception()
1080
tb = sys.exc_info()[2]
1081
exinfo = traceback.extract_tb(tb)
1083
sys.stderr.write(' at %s:%d in %s()\n' % exinfo[-1][:3])
1084
sys.stderr.write(' see ~/.bzr.log for debug information\n')
1971
return cmd_class(cmdopts, cmdargs).status
1088
1974
def main(argv):
1091
bzrlib.open_tracefile(argv)
1977
bzrlib.trace.log_startup(argv)
1979
bzrlib.ui.ui_factory = bzrlib.ui.TextUIFactory()
1096
return run_bzr(argv)
1098
# do this here inside the exception wrappers to catch EPIPE
1101
quiet = isinstance(e, (BzrCommandError))
1102
_report_exception('error: ' + e.args[0], quiet=quiet)
1105
# some explanation or hints
1108
except AssertionError, e:
1109
msg = 'assertion failed'
1111
msg += ': ' + str(e)
1112
_report_exception(msg)
1114
except KeyboardInterrupt, e:
1115
_report_exception('interrupted', quiet=True)
1117
except Exception, e:
1119
if (isinstance(e, IOError)
1120
and hasattr(e, 'errno')
1121
and e.errno == errno.EPIPE):
1125
msg = str(e).rstrip('\n')
1126
_report_exception(msg, quiet)
1129
bzrlib.trace.close_trace()
1983
return run_bzr(argv[1:])
1985
# do this here inside the exception wrappers to catch EPIPE
1987
except BzrCommandError, e:
1988
# command line syntax error, etc
1992
bzrlib.trace.log_exception()
1994
except AssertionError, e:
1995
bzrlib.trace.log_exception('assertion failed: ' + str(e))
1997
except KeyboardInterrupt, e:
1998
bzrlib.trace.note('interrupted')
2000
except Exception, e:
2002
if (isinstance(e, IOError)
2003
and hasattr(e, 'errno')
2004
and e.errno == errno.EPIPE):
2005
bzrlib.trace.note('broken pipe')
2008
bzrlib.trace.log_exception()
1132
2012
if __name__ == '__main__':