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.
19
import sys, os, time, os.path
27
from bzrlib.trace import mutter, note, log_error, warning
28
from bzrlib.errors import BzrError, BzrCheckError, BzrCommandError
29
from bzrlib.branch import find_branch
30
from bzrlib import BZRDIR
36
def register_command(cmd):
37
"Utility function to help register a command"
40
if k.startswith("cmd_"):
41
k_unsquished = _unsquish_command_name(k)
44
if not plugin_cmds.has_key(k_unsquished):
45
plugin_cmds[k_unsquished] = cmd
47
log_error('Two plugins defined the same command: %r' % k)
48
log_error('Not loading the one in %r' % sys.modules[cmd.__module__])
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, \
51
32
def _squish_command_name(cmd):
56
37
assert cmd.startswith("cmd_")
57
38
return cmd[4:].replace('_','-')
60
def _parse_revision_str(revstr):
61
"""This handles a revision string -> revno.
63
This always returns a list. The list will have one element for
65
It supports integers directly, but everything else it
66
defers for passing to Branch.get_revision_info()
68
>>> _parse_revision_str('234')
70
>>> _parse_revision_str('234..567')
72
>>> _parse_revision_str('..')
74
>>> _parse_revision_str('..234')
76
>>> _parse_revision_str('234..')
78
>>> _parse_revision_str('234..456..789') # Maybe this should be an error
80
>>> _parse_revision_str('234....789') # Error?
82
>>> _parse_revision_str('revid:test@other.com-234234')
83
['revid:test@other.com-234234']
84
>>> _parse_revision_str('revid:test@other.com-234234..revid:test@other.com-234235')
85
['revid:test@other.com-234234', 'revid:test@other.com-234235']
86
>>> _parse_revision_str('revid:test@other.com-234234..23')
87
['revid:test@other.com-234234', 23]
88
>>> _parse_revision_str('date:2005-04-12')
90
>>> _parse_revision_str('date:2005-04-12 12:24:33')
91
['date:2005-04-12 12:24:33']
92
>>> _parse_revision_str('date:2005-04-12T12:24:33')
93
['date:2005-04-12T12:24:33']
94
>>> _parse_revision_str('date:2005-04-12,12:24:33')
95
['date:2005-04-12,12:24:33']
96
>>> _parse_revision_str('-5..23')
98
>>> _parse_revision_str('-5')
100
>>> _parse_revision_str('123a')
102
>>> _parse_revision_str('abc')
106
old_format_re = re.compile('\d*:\d*')
107
m = old_format_re.match(revstr)
109
warning('Colon separator for revision numbers is deprecated.'
112
for rev in revstr.split(':'):
114
revs.append(int(rev))
119
for x in revstr.split('..'):
130
def get_merge_type(typestring):
131
"""Attempt to find the merge class/factory associated with a string."""
132
from merge import merge_types
134
return merge_types[typestring][0]
136
templ = '%s%%7s: %%s' % (' '*12)
137
lines = [templ % (f[0], f[1][1]) for f in merge_types.iteritems()]
138
type_list = '\n'.join(lines)
139
msg = "No known merge type %s. Supported types are:\n%s" %\
140
(typestring, type_list)
141
raise BzrCommandError(msg)
144
def get_merge_type(typestring):
145
"""Attempt to find the merge class/factory associated with a string."""
146
from merge import merge_types
148
return merge_types[typestring][0]
150
templ = '%s%%7s: %%s' % (' '*12)
151
lines = [templ % (f[0], f[1][1]) for f in merge_types.iteritems()]
152
type_list = '\n'.join(lines)
153
msg = "No known merge type %s. Supported types are:\n%s" %\
154
(typestring, type_list)
155
raise BzrCommandError(msg)
159
def _get_cmd_dict(plugins_override=True):
41
"""Return canonical name and class for all registered commands."""
161
42
for k, v in globals().iteritems():
162
43
if k.startswith("cmd_"):
163
d[_unsquish_command_name(k)] = v
164
# If we didn't load plugins, the plugin_cmds dict will be empty
166
d.update(plugin_cmds)
168
d2 = plugin_cmds.copy()
174
def get_all_cmds(plugins_override=True):
175
"""Return canonical name and class for all registered commands."""
176
for k, v in _get_cmd_dict(plugins_override=plugins_override).iteritems():
180
def get_cmd_class(cmd, plugins_override=True):
44
yield _unsquish_command_name(k), v
46
def get_cmd_class(cmd):
181
47
"""Return the canonical name and command class for a command.
183
49
cmd = str(cmd) # not unicode
185
51
# first look up this command under the specified name
186
cmds = _get_cmd_dict(plugins_override=plugins_override)
188
return cmd, cmds[cmd]
53
return cmd, globals()[_squish_command_name(cmd)]
192
57
# look for any command which claims this as an alias
193
for cmdname, cmdclass in cmds.iteritems():
58
for cmdname, cmdclass in get_all_cmds():
194
59
if cmd in cmdclass.aliases:
195
60
return cmdname, cmdclass
197
cmdclass = ExternalCommand.find_command(cmd)
201
raise BzrCommandError("unknown command %r" % cmd)
204
class Command(object):
62
raise BzrCommandError("unknown command %r" % cmd)
205
66
"""Base class for commands.
207
68
The docstring for an actual command should give a single-line
256
class ExternalCommand(Command):
257
"""Class to wrap external commands.
259
We cheat a little here, when get_cmd_class() calls us we actually
260
give it back an object we construct that has the appropriate path,
261
help, options etc for the specified command.
263
When run_bzr() tries to instantiate that 'class' it gets caught by
264
the __call__ method, which we override to call the Command.__init__
265
method. That then calls our run method which is pretty straight
268
The only wrinkle is that we have to map bzr's dictionary of options
269
and arguments back into command line options and arguments for the
273
def find_command(cls, cmd):
275
bzrpath = os.environ.get('BZRPATH', '')
277
for dir in bzrpath.split(os.pathsep):
278
path = os.path.join(dir, cmd)
279
if os.path.isfile(path):
280
return ExternalCommand(path)
284
find_command = classmethod(find_command)
286
def __init__(self, path):
289
pipe = os.popen('%s --bzr-usage' % path, 'r')
290
self.takes_options = pipe.readline().split()
292
for opt in self.takes_options:
293
if not opt in OPTIONS:
294
raise BzrError("Unknown option '%s' returned by external command %s"
297
# TODO: Is there any way to check takes_args is valid here?
298
self.takes_args = pipe.readline().split()
300
if pipe.close() is not None:
301
raise BzrError("Failed funning '%s --bzr-usage'" % path)
303
pipe = os.popen('%s --bzr-help' % path, 'r')
304
self.__doc__ = pipe.read()
305
if pipe.close() is not None:
306
raise BzrError("Failed funning '%s --bzr-help'" % path)
308
def __call__(self, options, arguments):
309
Command.__init__(self, options, arguments)
312
def run(self, **kargs):
319
optname = name.replace('_','-')
321
if OPTIONS.has_key(optname):
323
opts.append('--%s' % optname)
324
if value is not None and value is not True:
325
opts.append(str(value))
327
# it's an arg, or arg list
328
if type(value) is not list:
334
self.status = os.spawnv(os.P_WAIT, self.path, [self.path] + opts + args)
338
115
class cmd_status(Command):
339
116
"""Display status summary.
341
This reports on versioned and unknown files, reporting them
342
grouped by state. Possible states are:
345
Versioned in the working copy but not in the previous revision.
348
Versioned in the previous revision but removed or deleted
352
Path of this file changed from the previous revision;
353
the text may also have changed. This includes files whose
354
parent directory was renamed.
357
Text has changed since the previous revision.
360
Nothing about this file has changed since the previous revision.
361
Only shown with --all.
364
Not versioned and not matching an ignore pattern.
366
To see ignored files use 'bzr ignored'. For details in the
367
changes to file texts, use 'bzr diff'.
369
If no arguments are specified, the status of the entire working
370
directory is shown. Otherwise, only the status of the specified
371
files or directories is reported. If a directory is given, status
372
is reported for everything inside that directory.
374
If a revision is specified, the changes since that revision are shown.
118
For each file there is a single line giving its file state and name.
119
The name is that in the current revision unless it is deleted or
120
missing, in which case the old name is shown.
376
takes_args = ['file*']
377
takes_options = ['all', 'show-ids', 'revision']
122
takes_options = ['all']
378
123
aliases = ['st', 'stat']
380
def run(self, all=False, show_ids=False, file_list=None):
382
b = find_branch(file_list[0])
383
file_list = [b.relpath(x) for x in file_list]
384
# special case: only one path was given and it's the root
386
if file_list == ['']:
391
from bzrlib.status import show_status
392
show_status(b, show_unchanged=all, show_ids=show_ids,
393
specific_files=file_list)
125
def run(self, all=False):
126
#import bzrlib.status
127
#bzrlib.status.tree_status(Branch('.'))
128
Branch('.').show_status(show_all=all)
396
131
class cmd_cat_revision(Command):
447
159
whether already versioned or not, are searched for files or
448
160
subdirectories that are neither versioned or ignored, and these
449
161
are added. This search proceeds recursively into versioned
450
directories. If no names are given '.' is assumed.
452
Therefore simply saying 'bzr add' will version all files that
164
Therefore simply saying 'bzr add .' will version all files that
453
165
are currently unknown.
455
167
TODO: Perhaps adding a file whose directly is not versioned should
456
168
recursively add that parent, rather than giving an error?
458
takes_args = ['file*']
459
takes_options = ['verbose', 'no-recurse']
170
takes_args = ['file+']
171
takes_options = ['verbose']
461
def run(self, file_list, verbose=False, no_recurse=False):
462
from bzrlib.add import smart_add
463
smart_add(file_list, verbose, not no_recurse)
467
class cmd_mkdir(Command):
468
"""Create a new versioned directory.
470
This is equivalent to creating the directory and then adding it.
472
takes_args = ['dir+']
474
def run(self, dir_list):
481
b.add([d], verbose=True)
173
def run(self, file_list, verbose=False):
174
bzrlib.add.smart_add(file_list, verbose)
484
177
class cmd_relpath(Command):
485
178
"""Show path of a file relative to root"""
486
takes_args = ['filename']
179
takes_args = ('filename')
489
def run(self, filename):
490
print find_branch(filename).relpath(filename)
182
print Branch(self.args['filename']).relpath(filename)
494
186
class cmd_inventory(Command):
495
187
"""Show inventory of the current working copy or a revision."""
496
takes_options = ['revision', 'show-ids']
188
takes_options = ['revision']
498
def run(self, revision=None, show_ids=False):
190
def run(self, revision=None):
500
192
if revision == None:
501
193
inv = b.read_working_inventory()
503
if len(revision) > 1:
504
raise BzrCommandError('bzr inventory --revision takes'
505
' exactly one revision identifier')
506
inv = b.get_revision_inventory(b.lookup_revision(revision[0]))
195
inv = b.get_revision_inventory(b.lookup_revision(revision))
508
for path, entry in inv.entries():
510
print '%-50s %s' % (path, entry.file_id)
197
for path, entry in inv.iter_entries():
198
print '%-50s %s' % (entry.file_id, path)
515
201
class cmd_move(Command):
545
230
takes_args = ['from_name', 'to_name']
547
232
def run(self, from_name, to_name):
549
234
b.rename_one(b.relpath(from_name), b.relpath(to_name))
553
class cmd_mv(Command):
554
"""Move or rename a file.
557
bzr mv OLDNAME NEWNAME
558
bzr mv SOURCE... DESTINATION
560
If the last argument is a versioned directory, all the other names
561
are moved into it. Otherwise, there must be exactly two arguments
562
and the file is changed to a new name, which must not already exist.
564
Files cannot be moved between branches.
566
takes_args = ['names*']
567
def run(self, names_list):
568
if len(names_list) < 2:
569
raise BzrCommandError("missing file argument")
570
b = find_branch(names_list[0])
572
rel_names = [b.relpath(x) for x in names_list]
574
if os.path.isdir(names_list[-1]):
575
# move into existing directory
576
b.move(rel_names[:-1], rel_names[-1])
578
if len(names_list) != 2:
579
raise BzrCommandError('to mv multiple files the destination '
580
'must be a versioned directory')
581
b.move(rel_names[0], rel_names[1])
586
class cmd_pull(Command):
587
"""Pull any changes from another branch into the current one.
589
If the location is omitted, the last-used location will be used.
590
Both the revision history and the working directory will be
593
This command only works on branches that have not diverged. Branches are
594
considered diverged if both branches have had commits without first
595
pulling from the other.
597
If branches have diverged, you can use 'bzr merge' to pull the text changes
598
from one into the other.
600
takes_args = ['location?']
602
def run(self, location=None):
603
from bzrlib.merge import merge
605
from shutil import rmtree
608
br_to = find_branch('.')
611
stored_loc = br_to.controlfile("x-pull", "rb").read().rstrip('\n')
613
if e.errno != errno.ENOENT:
616
if stored_loc is None:
617
raise BzrCommandError("No pull location known or specified.")
619
print "Using last location: %s" % stored_loc
620
location = stored_loc
621
cache_root = tempfile.mkdtemp()
622
from bzrlib.branch import DivergedBranches
623
br_from = find_branch(location)
624
location = pull_loc(br_from)
625
old_revno = br_to.revno()
627
from branch import find_cached_branch, DivergedBranches
628
br_from = find_cached_branch(location, cache_root)
629
location = pull_loc(br_from)
630
old_revno = br_to.revno()
632
br_to.update_revisions(br_from)
633
except DivergedBranches:
634
raise BzrCommandError("These branches have diverged."
637
merge(('.', -1), ('.', old_revno), check_clean=False)
638
if location != stored_loc:
639
br_to.controlfile("x-pull", "wb").write(location + "\n")
645
class cmd_branch(Command):
646
"""Create a new copy of a branch.
648
If the TO_LOCATION is omitted, the last component of the FROM_LOCATION will
649
be used. In other words, "branch ../foo/bar" will attempt to create ./bar.
651
To retrieve the branch as of a particular revision, supply the --revision
652
parameter, as in "branch foo/bar -r 5".
654
takes_args = ['from_location', 'to_location?']
655
takes_options = ['revision']
656
aliases = ['get', 'clone']
658
def run(self, from_location, to_location=None, revision=None):
660
from bzrlib.merge import merge
661
from bzrlib.branch import DivergedBranches, \
662
find_cached_branch, Branch
663
from shutil import rmtree
664
from meta_store import CachedStore
666
cache_root = tempfile.mkdtemp()
670
elif len(revision) > 1:
671
raise BzrCommandError('bzr branch --revision takes exactly 1 revision value')
675
br_from = find_cached_branch(from_location, cache_root)
677
if e.errno == errno.ENOENT:
678
raise BzrCommandError('Source location "%s" does not'
679
' exist.' % to_location)
683
if to_location is None:
684
to_location = os.path.basename(from_location.rstrip("/\\"))
687
os.mkdir(to_location)
689
if e.errno == errno.EEXIST:
690
raise BzrCommandError('Target directory "%s" already'
691
' exists.' % to_location)
692
if e.errno == errno.ENOENT:
693
raise BzrCommandError('Parent of "%s" does not exist.' %
697
br_to = Branch(to_location, init=True)
699
br_to.set_root_id(br_from.get_root_id())
702
if revision[0] is None:
703
revno = br_from.revno()
705
revno, rev_id = br_from.get_revision_info(revision[0])
707
br_to.update_revisions(br_from, stop_revision=revno)
708
except bzrlib.errors.NoSuchRevision:
710
msg = "The branch %s has no revision %d." % (from_location,
712
raise BzrCommandError(msg)
714
merge((to_location, -1), (to_location, 0), this_dir=to_location,
715
check_clean=False, ignore_zero=True)
716
from_location = pull_loc(br_from)
717
br_to.controlfile("x-pull", "wb").write(from_location + "\n")
722
def pull_loc(branch):
723
# TODO: Should perhaps just make attribute be 'base' in
724
# RemoteBranch and Branch?
725
if hasattr(branch, "baseurl"):
726
return branch.baseurl
732
238
class cmd_renames(Command):
733
239
"""Show list of renamed files.
867
369
TODO: This probably handles non-Unix newlines poorly.
875
372
takes_args = ['file*']
876
takes_options = ['revision', 'diff-options']
877
aliases = ['di', 'dif']
373
takes_options = ['revision']
879
def run(self, revision=None, file_list=None, diff_options=None):
376
def run(self, revision=None, file_list=None):
880
377
from bzrlib.diff import show_diff
883
b = find_branch(file_list[0])
884
file_list = [b.relpath(f) for f in file_list]
885
if file_list == ['']:
886
# just pointing to top-of-tree
891
if revision is not None:
892
if len(revision) == 1:
893
show_diff(b, revision[0], specific_files=file_list,
894
external_diff_options=diff_options)
895
elif len(revision) == 2:
896
show_diff(b, revision[0], specific_files=file_list,
897
external_diff_options=diff_options,
898
revision2=revision[1])
900
raise BzrCommandError('bzr diff --revision takes exactly one or two revision identifiers')
902
show_diff(b, None, specific_files=file_list,
903
external_diff_options=diff_options)
379
show_diff(Branch('.'), revision, file_list)
908
382
class cmd_deleted(Command):
968
409
takes_args = ['filename?']
969
410
def run(self, filename=None):
970
411
"""Print the branch root."""
971
b = find_branch(filename)
972
print getattr(b, 'base', None) or getattr(b, 'baseurl')
412
print bzrlib.branch.find_branch_root(filename)
975
416
class cmd_log(Command):
976
417
"""Show log of this branch.
978
To request a range of logs, you can use the command -r begin:end
979
-r revision requests a specific revision, -r :end or -r begin: are
982
--message allows you to give a regular expression, which will be evaluated
983
so that only matching entries will be displayed.
985
TODO: Make --revision support uuid: and hash: [future tag:] notation.
419
TODO: Option to limit range.
421
TODO: Perhaps show most-recent first with an option for last.
989
423
takes_args = ['filename?']
990
takes_options = ['forward', 'timezone', 'verbose', 'show-ids', 'revision',
991
'long', 'message', 'short',]
993
def run(self, filename=None, timezone='original',
1001
from bzrlib.branch import find_branch
1002
from bzrlib.log import log_formatter, show_log
1005
direction = (forward and 'forward') or 'reverse'
424
takes_options = ['timezone', 'verbose', 'show-ids']
425
def run(self, filename=None, timezone='original', verbose=False, show_ids=False):
426
b = Branch((filename or '.'), lock_mode='r')
1008
b = find_branch(filename)
1009
fp = b.relpath(filename)
1011
file_id = b.read_working_inventory().path2id(fp)
1013
file_id = None # points to branch root
1015
b = find_branch('.')
1018
if revision is None:
1021
elif len(revision) == 1:
1022
rev1 = rev2 = b.get_revision_info(revision[0])[0]
1023
elif len(revision) == 2:
1024
rev1 = b.get_revision_info(revision[0])[0]
1025
rev2 = b.get_revision_info(revision[1])[0]
1027
raise BzrCommandError('bzr log --revision takes one or two values.')
1034
mutter('encoding log as %r' % bzrlib.user_encoding)
1036
# use 'replace' so that we don't abort if trying to write out
1037
# in e.g. the default C locale.
1038
outf = codecs.getwriter(bzrlib.user_encoding)(sys.stdout, errors='replace')
1043
log_format = 'short'
1044
lf = log_formatter(log_format,
1047
show_timezone=timezone)
1053
direction=direction,
1054
start_revision=rev1,
428
filename = b.relpath(filename)
429
bzrlib.show_log(b, filename,
430
show_timezone=timezone,
1060
436
class cmd_touching_revisions(Command):
1061
"""Return revision-ids which affected a particular file.
1063
A more user-friendly interface is "bzr log FILE"."""
437
"""Return revision-ids which affected a particular file."""
1065
439
takes_args = ["filename"]
1066
440
def run(self, filename):
1067
b = find_branch(filename)
441
b = Branch(filename, lock_mode='r')
1068
442
inv = b.read_working_inventory()
1069
443
file_id = inv.path2id(b.relpath(filename))
1070
444
for revno, revision_id, what in bzrlib.log.find_touching_revisions(b, file_id):
1102
476
class cmd_unknowns(Command):
1103
"""List unknown files."""
477
"""List unknown files"""
1105
from bzrlib.osutils import quotefn
1106
for f in find_branch('.').unknowns():
479
for f in Branch('.').unknowns():
1107
480
print quotefn(f)
1111
484
class cmd_ignore(Command):
1112
"""Ignore a command or pattern.
1114
To remove patterns from the ignore list, edit the .bzrignore file.
1116
If the pattern contains a slash, it is compared to the whole path
1117
from the branch root. Otherwise, it is comapred to only the last
1118
component of the path.
1120
Ignore patterns are case-insensitive on case-insensitive systems.
1122
Note: wildcards must be quoted from the shell on Unix.
1125
bzr ignore ./Makefile
1126
bzr ignore '*.class'
485
"""Ignore a command or pattern"""
1128
486
takes_args = ['name_pattern']
1130
488
def run(self, name_pattern):
1131
from bzrlib.atomicfile import AtomicFile
1134
b = find_branch('.')
1135
ifn = b.abspath('.bzrignore')
1137
if os.path.exists(ifn):
1140
igns = f.read().decode('utf-8')
1146
# TODO: If the file already uses crlf-style termination, maybe
1147
# we should use that for the newly added lines?
1149
if igns and igns[-1] != '\n':
1151
igns += name_pattern + '\n'
1154
f = AtomicFile(ifn, 'wt')
1155
f.write(igns.encode('utf-8'))
491
# XXX: This will fail if it's a hardlink; should use an AtomicFile class.
492
f = open(b.abspath('.bzrignore'), 'at')
493
f.write(name_pattern + '\n')
1160
496
inv = b.working_tree().inventory
1161
497
if inv.path2id('.bzrignore'):
1195
529
except ValueError:
1196
530
raise BzrCommandError("not a valid revision-number: %r" % revno)
1198
print find_branch('.').lookup_revision(revno)
532
print Branch('.').lookup_revision(revno)
1201
535
class cmd_export(Command):
1202
536
"""Export past revision to destination directory.
1204
If no revision is specified this exports the last committed revision.
1206
Format may be an "exporter" name, such as tar, tgz, tbz2. If none is
1207
given, try to find the format with the extension. If no extension
1208
is found exports to a directory (equivalent to --format=dir).
1210
Root may be the top directory for tar, tgz and tbz2 formats. If none
1211
is given, the top directory will be the root name of the file."""
1212
# TODO: list known exporters
538
If no revision is specified this exports the last committed revision."""
1213
539
takes_args = ['dest']
1214
takes_options = ['revision', 'format', 'root']
1215
def run(self, dest, revision=None, format=None, root=None):
1217
b = find_branch('.')
1218
if revision is None:
1219
rev_id = b.last_patch()
540
takes_options = ['revision']
541
def run(self, dest, revno=None):
544
rh = b.revision_history[-1]
1221
if len(revision) != 1:
1222
raise BzrError('bzr export --revision takes exactly 1 argument')
1223
revno, rev_id = b.get_revision_info(revision[0])
1224
t = b.revision_tree(rev_id)
1225
root, ext = os.path.splitext(dest)
1227
if ext in (".tar",):
1229
elif ext in (".gz", ".tgz"):
1231
elif ext in (".bz2", ".tbz2"):
1235
t.export(dest, format, root)
546
rh = b.lookup_revision(int(revno))
547
t = b.revision_tree(rh)
1238
551
class cmd_cat(Command):
1261
572
class cmd_commit(Command):
1262
573
"""Commit changes into a new revision.
1264
If no arguments are given, the entire tree is committed.
1266
If selected files are specified, only changes to those files are
1267
committed. If a directory is specified then the directory and everything
1268
within it is committed.
1270
A selected-file commit may fail in some cases where the committed
1271
tree would be invalid, such as trying to commit a file in a
1272
newly-added directory that is not itself committed.
575
TODO: Commit only selected files.
1274
577
TODO: Run hooks on tree to-be-committed, and after commit.
1276
579
TODO: Strict commit that fails if there are unknown or deleted files.
1278
takes_args = ['selected*']
1279
takes_options = ['message', 'file', 'verbose', 'unchanged']
581
takes_options = ['message', 'file', 'verbose']
1280
582
aliases = ['ci', 'checkin']
1282
# TODO: Give better message for -s, --summary, used by tla people
1284
def run(self, message=None, file=None, verbose=True, selected_list=None,
1286
from bzrlib.errors import PointlessCommit
1287
from bzrlib.osutils import get_text_message
584
def run(self, message=None, file=None, verbose=False):
1289
585
## Warning: shadows builtin file()
1290
586
if not message and not file:
1291
# FIXME: Ugly; change status code to send to a provided function?
1295
catcher = cStringIO.StringIO()
1296
sys.stdout = catcher
1297
cmd_status({"file_list":selected_list}, {})
1298
info = catcher.getvalue()
1300
message = get_text_message(info)
1303
raise BzrCommandError("please specify a commit message",
1304
["use either --message or --file"])
587
raise BzrCommandError("please specify a commit message",
588
["use either --message or --file"])
1305
589
elif message and file:
1306
590
raise BzrCommandError("please specify either --message or --file")
1330
602
This command checks various invariants about the branch storage to
1331
603
detect data corruption or bzr bugs.
1333
If given the --update flag, it will update some optional fields
1334
to help ensure data consistency.
1336
takes_args = ['dir?']
1338
def run(self, dir='.'):
1339
from bzrlib.check import check
1340
check(find_branch(dir))
1344
class cmd_scan_cache(Command):
1347
from bzrlib.hashcache import HashCache
1354
print '%6d stats' % c.stat_count
1355
print '%6d in hashcache' % len(c._cache)
1356
print '%6d files removed from cache' % c.removed_count
1357
print '%6d hashes updated' % c.update_count
1358
print '%6d files changed too recently to cache' % c.danger_count
1365
class cmd_upgrade(Command):
1366
"""Upgrade branch storage to current format.
1368
This should normally be used only after the check command tells
1371
takes_args = ['dir?']
1373
def run(self, dir='.'):
1374
from bzrlib.upgrade import upgrade
1375
upgrade(find_branch(dir))
605
takes_args = ['dir?']
606
def run(self, dir='.'):
608
bzrlib.check.check(Branch(dir, find_root=False))
1381
614
takes_options = ['email']
1383
616
def run(self, email=False):
1385
b = bzrlib.branch.find_branch('.')
1390
print bzrlib.osutils.user_email(b)
618
print bzrlib.osutils.user_email()
1392
print bzrlib.osutils.username(b)
620
print bzrlib.osutils.username()
1395
623
class cmd_selftest(Command):
1396
624
"""Run internal test suite"""
1398
takes_options = ['verbose']
1399
def run(self, verbose=False):
1400
from bzrlib.selftest import selftest
1401
return int(not selftest(verbose=verbose))
627
failures, tests = 0, 0
629
import doctest, bzrlib.store, bzrlib.tests
630
bzrlib.trace.verbose = False
632
for m in bzrlib.store, bzrlib.inventory, bzrlib.branch, bzrlib.osutils, \
633
bzrlib.tree, bzrlib.tests, bzrlib.commands, bzrlib.add:
634
mf, mt = doctest.testmod(m)
637
print '%-40s %3d tests' % (m.__name__, mt),
639
print '%3d FAILED!' % mf
643
print '%-40s %3d tests' % ('total', tests),
645
print '%3d FAILED!' % failures
1404
651
class cmd_version(Command):
1405
"""Show version of bzr."""
652
"""Show version of bzr"""
1409
656
def show_version():
1410
657
print "bzr (bazaar-ng) %s" % bzrlib.__version__
1411
# is bzrlib itself in a branch?
1412
bzrrev = bzrlib.get_bzr_revision()
1414
print " (bzr checkout, revision %d {%s})" % bzrrev
1415
658
print bzrlib.__copyright__
1416
659
print "http://bazaar-ng.org/"
1427
670
print "it sure does!"
1429
def parse_spec(spec):
1431
>>> parse_spec(None)
1433
>>> parse_spec("./")
1435
>>> parse_spec("../@")
1437
>>> parse_spec("../f/@35")
1439
>>> parse_spec('./@revid:john@arbash-meinel.com-20050711044610-3ca0327c6a222f67')
1440
['.', 'revid:john@arbash-meinel.com-20050711044610-3ca0327c6a222f67']
1445
parsed = spec.split('/@')
1446
assert len(parsed) == 2
1451
parsed[1] = int(parsed[1])
1453
pass # We can allow stuff like ./@revid:blahblahblah
1455
assert parsed[1] >=0
1457
parsed = [spec, None]
1462
class cmd_merge(Command):
1463
"""Perform a three-way merge.
1465
The branch is the branch you will merge from. By default, it will merge
1466
the latest revision. If you specify a revision, that revision will be
1467
merged. If you specify two revisions, the first will be used as a BASE,
1468
and the second one as OTHER. Revision numbers are always relative to the
1473
To merge the latest revision from bzr.dev
1474
bzr merge ../bzr.dev
1476
To merge changes up to and including revision 82 from bzr.dev
1477
bzr merge -r 82 ../bzr.dev
1479
To merge the changes introduced by 82, without previous changes:
1480
bzr merge -r 81..82 ../bzr.dev
1482
merge refuses to run if there are any uncommitted changes, unless
1485
takes_args = ['branch?']
1486
takes_options = ['revision', 'force', 'merge-type']
1488
def run(self, branch='.', revision=None, force=False,
1490
from bzrlib.merge import merge
1491
from bzrlib.merge_core import ApplyMerge3
1492
if merge_type is None:
1493
merge_type = ApplyMerge3
1495
if revision is None or len(revision) < 1:
1497
other = (branch, -1)
1499
if len(revision) == 1:
1500
other = (branch, revision[0])
1503
assert len(revision) == 2
1504
if None in revision:
1505
raise BzrCommandError(
1506
"Merge doesn't permit that revision specifier.")
1507
base = (branch, revision[0])
1508
other = (branch, revision[1])
1510
merge(other, base, check_clean=(not force), merge_type=merge_type)
1513
class cmd_revert(Command):
1514
"""Reverse all changes since the last commit.
1516
Only versioned files are affected. Specify filenames to revert only
1517
those files. By default, any files that are changed will be backed up
1518
first. Backup files have a '~' appended to their name.
1520
takes_options = ['revision', 'no-backup']
1521
takes_args = ['file*']
1522
aliases = ['merge-revert']
1524
def run(self, revision=None, no_backup=False, file_list=None):
1525
from bzrlib.merge import merge
1526
if file_list is not None:
1527
if len(file_list) == 0:
1528
raise BzrCommandError("No files specified")
1529
if revision is None:
1531
elif len(revision) != 1:
1532
raise BzrCommandError('bzr revert --revision takes exactly 1 argument')
1533
merge(('.', revision[0]), parse_spec('.'),
1536
backup_files=not no_backup,
1537
file_list=file_list)
1540
673
class cmd_assert_fail(Command):
1541
674
"""Test reporting of assertion failures"""
1556
689
help.help(topic)
1559
class cmd_shell_complete(Command):
1560
"""Show appropriate completions for context.
1562
For a list of all available commands, say 'bzr shell-complete'."""
1563
takes_args = ['context?']
1567
def run(self, context=None):
1568
import shellcomplete
1569
shellcomplete.shellcomplete(context)
1572
class cmd_missing(Command):
1573
"""What is missing in this branch relative to other branch.
1575
takes_args = ['remote?']
1576
aliases = ['mis', 'miss']
1577
# We don't have to add quiet to the list, because
1578
# unknown options are parsed as booleans
1579
takes_options = ['verbose', 'quiet']
1581
def run(self, remote=None, verbose=False, quiet=False):
1582
from bzrlib.branch import find_branch, DivergedBranches
1583
from bzrlib.errors import BzrCommandError
1584
from bzrlib.missing import get_parent, show_missing
1586
if verbose and quiet:
1587
raise BzrCommandError('Cannot pass both quiet and verbose')
1589
b = find_branch('.')
1590
parent = get_parent(b)
1593
raise BzrCommandError("No missing location known or specified.")
1596
print "Using last location: %s" % parent
1598
elif parent is None:
1599
# We only update x-pull if it did not exist, missing should not change the parent
1600
b.controlfile('x-pull', 'wb').write(remote + '\n')
1601
br_remote = find_branch(remote)
1603
return show_missing(b, br_remote, verbose=verbose, quiet=quiet)
1606
class cmd_plugins(Command):
1610
import bzrlib.plugin
1611
from inspect import getdoc
1612
from pprint import pprint
1613
for plugin in bzrlib.plugin.all_plugins:
1614
print plugin.__path__[0]
1617
print '\t', d.split('\n')[0]
1619
#pprint(bzrlib.plugin.all_plugins)
692
######################################################################
1623
696
# list of all available options; the rhs can be either None for an
1704
755
if optname not in OPTIONS:
1705
raise BzrError('unknown long option %r' % a)
756
bailout('unknown long option %r' % a)
1707
758
shortopt = a[1:]
1708
if shortopt in SHORT_OPTIONS:
1709
# Multi-character options must have a space to delimit
1711
optname = SHORT_OPTIONS[shortopt]
1713
# Single character short options, can be chained,
1714
# and have their value appended to their name
1716
if shortopt not in SHORT_OPTIONS:
1717
# We didn't find the multi-character name, and we
1718
# didn't find the single char name
1719
raise BzrError('unknown short option %r' % a)
1720
optname = SHORT_OPTIONS[shortopt]
1723
# There are extra things on this option
1724
# see if it is the value, or if it is another
1726
optargfn = OPTIONS[optname]
1727
if optargfn is None:
1728
# This option does not take an argument, so the
1729
# next entry is another short option, pack it back
1731
argv.insert(0, '-' + a[2:])
1733
# This option takes an argument, so pack it
759
if shortopt not in SHORT_OPTIONS:
760
bailout('unknown short option %r' % a)
761
optname = SHORT_OPTIONS[shortopt]
1737
763
if optname in opts:
1738
764
# XXX: Do we ever want to support this, e.g. for -r?
1739
raise BzrError('repeated option %r' % a)
765
bailout('repeated option %r' % a)
1741
767
optargfn = OPTIONS[optname]
1743
769
if optarg == None:
1745
raise BzrError('option %r needs an argument' % a)
771
bailout('option %r needs an argument' % a)
1747
773
optarg = argv.pop(0)
1748
774
opts[optname] = optargfn(optarg)
1750
776
if optarg != None:
1751
raise BzrError('option %r takes no argument' % optname)
777
bailout('option %r takes no argument' % optname)
1752
778
opts[optname] = True
1809
835
This is similar to main(), but without all the trappings for
1810
836
logging and error handling.
1813
The command-line arguments, without the program name from argv[0]
1815
Returns a command status or raises an exception.
1817
Special master options: these must come before the command because
1818
they control how the command is interpreted.
1821
Do not load plugin modules at all
1824
Only use builtin commands. (Plugins are still allowed to change
1828
Run under the Python profiler.
1831
838
argv = [a.decode(bzrlib.user_encoding) for a in argv]
1833
opt_profile = opt_no_plugins = opt_builtin = False
1835
# --no-plugins is handled specially at a very early stage. We need
1836
# to load plugins before doing other command parsing so that they
1837
# can override commands, but this needs to happen first.
1840
if a == '--profile':
1842
elif a == '--no-plugins':
1843
opt_no_plugins = True
1844
elif a == '--builtin':
1850
if not opt_no_plugins:
1851
from bzrlib.plugin import load_plugins
1854
args, opts = parse_args(argv)
1857
from bzrlib.help import help
1864
if 'version' in opts:
1869
print >>sys.stderr, "please try 'bzr help' for help"
841
args, opts = parse_args(argv[1:])
849
elif 'version' in opts:
852
cmd = str(args.pop(0))
854
log_error('usage: bzr COMMAND')
855
log_error(' try "bzr help"')
1872
cmd = str(args.pop(0))
1874
canonical_cmd, cmd_class = \
1875
get_cmd_class(cmd, plugins_override=not opt_builtin)
858
canonical_cmd, cmd_class = get_cmd_class(cmd)
861
if 'profile' in opts:
1877
867
# check options are reasonable
1878
868
allowed = cmd_class.takes_options