25
28
* Metadata format is not stable yet -- you may need to
26
29
discard history in the future.
31
* No handling of subdirectories, symlinks or any non-text files.
28
33
* Insufficient error handling.
30
35
* Many commands unimplemented or partially implemented.
55
60
Show summary of pending changes.
57
62
Make a file not versioned.
59
Show statistics about this branch.
65
# not currently working:
67
# Run internal consistency checks.
69
# Show some information about this branch.
73
__copyright__ = "Copyright 2005 Canonical Development Ltd."
74
__author__ = "Martin Pool <mbp@canonical.com>"
75
__docformat__ = "restructuredtext en"
65
79
import sys, os, random, time, sha, sets, types, re, shutil, tempfile
101
116
## TODO: Perhaps make UUIDs predictable in test mode to make it easier
102
117
## to compare output?
104
## TODO: Some kind of global code to generate the right Branch object
105
## to work on. Almost, but not quite all, commands need one, and it
106
## can be taken either from their parameters or their working
109
## TODO: rename command, needed soon: check destination doesn't exist
110
## either in working copy or tree; move working copy; update
111
## inventory; write out
113
## TODO: move command; check destination is a directory and will not
116
## TODO: command to show renames, one per line, as to->from
119
## TODO: Is ElementTree really all that much better for our purposes?
120
## Perhaps using the standard MiniDOM would be enough?
127
######################################################################
121
131
def cmd_status(all=False):
137
147
Branch('.').get_revision(revision_id).write_xml(sys.stdout)
150
def cmd_get_inventory(inventory_id):
151
"""Return inventory in XML by hash"""
152
Branch('.').get_inventory(inventory_hash).write_xml(sys.stdout)
155
def cmd_get_revision_inventory(revision_id):
156
"""Output inventory for a revision."""
158
b.get_revision_inventory(revision_id).write_xml(sys.stdout)
140
161
def cmd_get_file_text(text_id):
141
162
"""Get contents of a file by hash."""
142
163
sf = Branch('.').text_store[text_id]
153
174
print Branch('.').revno()
157
177
def cmd_add(file_list, verbose=False):
158
"""Add specified files or directories.
160
In non-recursive mode, all the named items are added, regardless
161
of whether they were previously ignored. A warning is given if
162
any of the named files are already versioned.
164
In recursive mode (the default), files are treated the same way
165
but the behaviour for directories is different. Directories that
166
are already versioned do not give a warning. All directories,
167
whether already versioned or not, are searched for files or
168
subdirectories that are neither versioned or ignored, and these
169
are added. This search proceeds recursively into versioned
172
Therefore simply saying 'bzr add .' will version all files that
173
are currently unknown.
178
"""Add specified files.
180
Fails if the files are already added.
175
bzrlib.add.smart_add(file_list, verbose)
178
def cmd_relpath(filename):
179
"""Show path of file relative to root"""
180
print Branch(filename).relpath(filename)
182
Branch('.').add(file_list, verbose=verbose)
183
185
def cmd_inventory(revision=None):
199
"""info: Show statistical information for this branch
203
info.show_info(Branch('.'))
202
print 'branch format:', b.controlfile('branch-format', 'r').readline().rstrip('\n')
203
print 'revision number:', b.revno()
204
print 'number of versioned files:', len(b.read_working_inventory())
207
207
def cmd_remove(file_list, verbose=False):
208
b = Branch(file_list[0])
209
b.remove([b.relpath(f) for f in file_list], verbose=verbose)
208
Branch('.').remove(file_list, verbose=verbose)
213
212
def cmd_file_id(filename):
215
i = b.inventory.path2id(b.relpath(filename))
213
i = Branch('.').read_working_inventory().path2id(filename)
217
215
bailout("%s is not a versioned file" % filename)
249
247
def cmd_diff(revision=None):
250
"""bzr diff: Show differences in working tree.
252
usage: bzr diff [-r REV]
255
Show changes since REV, rather than predecessor.
257
TODO: Given two revision arguments, show the difference between them.
259
TODO: Allow diff across branches.
261
TODO: Option to use external diff command; could be GNU diff, wdiff,
264
TODO: Diff selected files.
267
## TODO: Shouldn't be in the cmd function.
248
"""Show diff from basis to working copy.
250
:todo: Take one or two revision arguments, look up those trees,
253
:todo: Allow diff across branches.
255
:todo: Mangle filenames in diff to be more relevant.
257
:todo: Shouldn't be in the cmd function.
342
def cmd_deleted(show_ids=False):
343
"""List files deleted in the working tree.
345
TODO: Show files deleted since a previous revision, or between two revisions.
349
new = b.working_tree()
351
for path, ie in old.inventory.iter_entries():
352
if not new.has_id(ie.file_id):
354
print '%-50s %s' % (path, ie.file_id)
361
def cmd_root(filename=None):
362
"""Print the branch root."""
363
print bzrlib.branch.find_branch_root(filename)
366
def cmd_log(timezone='original'):
367
334
"""Show log of this branch.
369
336
:todo: Options for utc; to show ids; to limit range; etc.
371
Branch('.').write_log(show_timezone=timezone)
338
Branch('.').write_log()
374
341
def cmd_ls(revision=None, verbose=False):
407
def cmd_ignored(verbose=True):
408
"""List ignored files and the patterns that matched them.
410
tree = Branch('.').working_tree()
411
for path, file_class, kind, id in tree.list_files():
412
if file_class != 'I':
414
## XXX: Slightly inefficient since this was already calculated
415
pat = tree.is_ignored(path)
416
print '%-50s %s' % (path, pat)
419
373
def cmd_lookup_revision(revno):
421
375
revno = int(revno)
444
398
"""Print a newly-generated UUID."""
445
print bzrlib.osutils.uuid()
449
def cmd_local_time_offset():
450
print bzrlib.osutils.local_time_offset()
454
def cmd_commit(message=None, verbose=False):
455
"""Commit changes to a new revision.
458
Description of changes in this revision; free form text.
459
It is recommended that the first line be a single-sentence
462
Show status of changed files,
464
TODO: Commit only selected files.
466
TODO: Run hooks on tree to-be-committed, and after commit.
468
TODO: Strict commit that fails if there are unknown or deleted files.
472
bailout("please specify a commit message")
403
def cmd_commit(message, verbose=False):
473
404
Branch('.').commit(message, verbose=verbose)
476
def cmd_check(dir='.'):
477
"""check: Consistency check of branch history.
479
usage: bzr check [-v] [BRANCH]
482
--verbose, -v Show progress of checking.
484
This command checks various invariants about the branch storage to
485
detect data corruption or bzr bugs.
488
bzrlib.check.check(Branch(dir, find_root=False))
408
"""Check consistency of the branch."""
491
412
def cmd_is(pred, *rest):
516
437
print bzrlib.branch._gen_revision_id(time.time())
519
def cmd_selftest(verbose=False):
520
"""Run internal test suite"""
441
"""Run internal doctest suite"""
521
442
## -v, if present, is seen by doctest; the argument is just here
522
443
## so our parser doesn't complain
524
445
## TODO: --verbose option
526
failures, tests = 0, 0
528
import doctest, bzrlib.store, bzrlib.tests
447
import bzr, doctest, bzrlib.store
529
448
bzrlib.trace.verbose = False
531
for m in bzrlib.store, bzrlib.inventory, bzrlib.branch, bzrlib.osutils, \
532
bzrlib.tree, bzrlib.tests, bzrlib.commands, bzrlib.add:
533
mf, mt = doctest.testmod(m)
536
print '%-40s %3d tests' % (m.__name__, mt),
538
print '%3d FAILED!' % mf
542
print '%-40s %3d tests' % ('total', tests),
544
print '%3d FAILED!' % failures
551
cmd_doctest = cmd_selftest
450
doctest.testmod(bzrlib.store)
451
doctest.testmod(bzrlib.inventory)
452
doctest.testmod(bzrlib.branch)
453
doctest.testmod(bzrlib.osutils)
454
doctest.testmod(bzrlib.tree)
456
# more strenuous tests;
458
doctest.testmod(bzrlib.tests)
554
461
######################################################################
558
def cmd_help(topic=None):
563
# otherwise, maybe the name of a command?
565
cmdfn = globals()['cmd_' + topic.replace('-', '_')]
567
bailout("no help for %r" % topic)
571
bailout("sorry, no detailed help yet for %r" % topic)
466
# TODO: Specific help for particular commands
578
470
def cmd_version():
579
print "bzr (bazaar-ng) %s" % bzrlib.__version__
580
print bzrlib.__copyright__
471
print "bzr (bazaar-ng) %s" % __version__
581
473
print "http://bazaar-ng.org/"
623
513
'add': ['verbose'],
624
514
'commit': ['message', 'verbose'],
625
'deleted': ['show-ids'],
626
515
'diff': ['revision'],
627
516
'inventory': ['revision'],
629
517
'ls': ['revision', 'verbose'],
630
520
'remove': ['verbose'],
636
526
'add': ['file+'],
639
'export': ['revno', 'dest'],
640
529
'file-id': ['filename'],
641
530
'get-file-text': ['text_id'],
642
531
'get-inventory': ['inventory_id'],
643
532
'get-revision': ['revision_id'],
644
533
'get-revision-inventory': ['revision_id'],
648
535
'lookup-revision': ['revno'],
649
'relpath': ['filename'],
536
'export': ['revno', 'dest'],
650
537
'remove': ['file+'],
651
'root': ['filename?'],
661
547
lookup table, something about the available options, what optargs
662
548
they take, and which commands will accept them.
664
>>> parse_args('--help'.split())
550
>>> parse_args('bzr --help'.split())
665
551
([], {'help': True})
666
>>> parse_args('--version'.split())
552
>>> parse_args('bzr --version'.split())
667
553
([], {'version': True})
668
>>> parse_args('status --all'.split())
554
>>> parse_args('bzr status --all'.split())
669
555
(['status'], {'all': True})
670
>>> parse_args('commit --message=biter'.split())
671
(['commit'], {'message': u'biter'})
676
560
# TODO: Maybe handle '--' to end options?
683
567
mutter(" got option %r" % a)
685
optname, optarg = a[2:].split('=', 1)
688
569
if optname not in OPTIONS:
689
570
bailout('unknown long option %r' % a)
696
577
if optname in opts:
697
578
# XXX: Do we ever want to support this, e.g. for -r?
698
579
bailout('repeated option %r' % a)
700
580
optargfn = OPTIONS[optname]
704
bailout('option %r needs an argument' % a)
707
opts[optname] = optargfn(optarg)
583
bailout('option %r needs an argument' % a)
584
opts[optname] = optargfn(it.next())
585
mutter(" option argument %r" % opts[optname])
710
bailout('option %r takes no argument' % optname)
587
# takes no option argument
711
588
opts[optname] = True
590
bailout('unknown short option %r' % a)
773
649
logging and error handling.
776
args, opts = parse_args(argv[1:])
652
args, opts = parse_args(argv)
777
653
if 'help' in opts:
778
654
# TODO: pass down other arguments in case they asked for
779
655
# help on a command name?
787
663
log_error('usage: bzr COMMAND\n')
788
664
log_error(' try "bzr help"\n')
792
668
cmd_handler = globals()['cmd_' + cmd.replace('-', '_')]
794
670
bailout("unknown command " + `cmd`)
797
if 'profile' in opts:
672
# TODO: special --profile option to turn on the Python profiler
803
674
# check options are reasonable
804
675
allowed = cmd_options.get(cmd, [])
807
678
bailout("option %r is not allowed for command %r"
810
# mix arguments and options into one dictionary
811
681
cmdargs = _match_args(cmd, args)
812
for k, v in opts.items():
813
cmdargs[k.replace('-', '_')] = v
817
prof = hotshot.Profile('.bzr.profile')
818
ret = prof.runcall(cmd_handler, **cmdargs) or 0
822
stats = hotshot.stats.load('.bzr.profile')
824
stats.sort_stats('cumulative', 'calls')
825
stats.print_stats(20)
827
return cmd_handler(**cmdargs) or 0
684
ret = cmd_handler(**cmdargs) or 0
835
692
## TODO: If the arguments are wrong, give a usage message rather
836
693
## than just a backtrace.
838
bzrlib.trace.create_tracefile(argv)
696
t = bzrlib.trace._tracefile
697
t.write('-' * 60 + '\n')
698
t.write('bzr invoked at %s\n' % format_date(time.time()))
699
t.write(' by %s on %s\n' % (bzrlib.osutils.username(), socket.gethostname()))
700
t.write(' arguments: %r\n' % argv)
702
starttime = os.times()[4]
705
t.write(' platform: %s\n' % platform.platform())
706
t.write(' python: %s\n' % platform.python_version())
841
708
ret = run_bzr(argv)
711
mutter("finished, %.3fu/%.3fs cpu, %.3fu/%.3fs cum"
713
mutter(" %.3f elapsed" % (times[4] - starttime))
843
716
except BzrError, e:
844
717
log_error('bzr: error: ' + e.args[0] + '\n')