60
55
Show summary of pending changes.
62
57
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"
79
65
import sys, os, random, time, sha, sets, types, re, shutil, tempfile
115
101
## TODO: Perhaps make UUIDs predictable in test mode to make it easier
116
102
## to compare output?
121
######################################################################
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
125
121
def cmd_status(all=False):
141
137
Branch('.').get_revision(revision_id).write_xml(sys.stdout)
144
def cmd_get_inventory(inventory_id):
145
"""Return inventory in XML by hash"""
146
Branch('.').get_inventory(inventory_hash).write_xml(sys.stdout)
149
def cmd_get_revision_inventory(revision_id):
150
"""Output inventory for a revision."""
152
b.get_revision_inventory(revision_id).write_xml(sys.stdout)
155
140
def cmd_get_file_text(text_id):
156
141
"""Get contents of a file by hash."""
157
142
sf = Branch('.').text_store[text_id]
168
153
print Branch('.').revno()
171
157
def cmd_add(file_list, verbose=False):
172
"""Add specified files.
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.
175
bzrlib.add.smart_add(file_list, verbose)
174
Fails if the files are already added.
176
Branch('.').add(file_list, verbose=verbose)
178
def cmd_relpath(filename):
179
"""Show path of file relative to root"""
180
print Branch(filename).relpath(filename)
179
184
def cmd_inventory(revision=None):
199
def cmd_mv(source_list, dest):
202
b.rename([b.relpath(s) for s in source_list], b.relpath(dest))
196
print 'branch format:', b.controlfile('branch-format', 'r').readline().rstrip('\n')
198
def plural(n, base='', pl=None):
206
count_version_dirs = 0
208
count_status = {'A': 0, 'D': 0, 'M': 0, 'R': 0, '?': 0, 'I': 0, '.': 0}
209
for st_tup in bzrlib.diff_trees(b.basis_tree(), b.working_tree()):
211
count_status[fs] += 1
212
if fs not in ['I', '?'] and st_tup[4] == 'directory':
213
count_version_dirs += 1
216
print 'in the working tree:'
217
for name, fs in (('unchanged', '.'),
218
('modified', 'M'), ('added', 'A'), ('removed', 'D'),
219
('renamed', 'R'), ('unknown', '?'), ('ignored', 'I'),
221
print ' %5d %s' % (count_status[fs], name)
222
print ' %5d versioned subdirector%s' % (count_version_dirs,
223
plural(count_version_dirs, 'y', 'ies'))
226
print 'branch history:'
227
history = b.revision_history()
229
print ' %5d revision%s' % (revno, plural(revno))
232
committers.add(b.get_revision(rev).committer)
233
print ' %5d committer%s' % (len(committers), plural(len(committers)))
235
firstrev = b.get_revision(history[0])
236
age = int((time.time() - firstrev.timestamp) / 3600 / 24)
237
print ' %5d day%s old' % (age, plural(age))
238
print ' first revision: %s' % format_date(firstrev.timestamp,
241
lastrev = b.get_revision(history[-1])
242
print ' latest revision: %s' % format_date(lastrev.timestamp,
207
"""info: Show statistical information for this branch
211
info.show_info(Branch('.'))
248
215
def cmd_remove(file_list, verbose=False):
249
Branch('.').remove(file_list, verbose=verbose)
216
b = Branch(file_list[0])
217
b.remove([b.relpath(f) for f in file_list], verbose=verbose)
253
221
def cmd_file_id(filename):
254
i = Branch('.').read_working_inventory().path2id(filename)
223
i = b.inventory.path2id(b.relpath(filename))
256
225
bailout("%s is not a versioned file" % filename)
288
269
def cmd_diff(revision=None):
289
"""Show diff from basis to working copy.
291
:todo: Take one or two revision arguments, look up those trees,
294
:todo: Allow diff across branches.
296
:todo: Mangle filenames in diff to be more relevant.
298
:todo: Shouldn't be in the cmd function.
270
"""bzr diff: Show differences in working tree.
272
usage: bzr diff [-r REV]
275
Show changes since REV, rather than predecessor.
277
TODO: Given two revision arguments, show the difference between them.
279
TODO: Allow diff across branches.
281
TODO: Option to use external diff command; could be GNU diff, wdiff,
284
TODO: Diff selected files.
287
## TODO: Shouldn't be in the cmd function.
333
321
# FIXME: Something about the diff format makes patch unhappy
334
322
# with newly-added files.
336
def diffit(*a, **kw):
337
sys.stdout.writelines(difflib.unified_diff(*a, **kw))
324
def diffit(oldlines, newlines, **kw):
325
# FIXME: difflib is wrong if there is no trailing newline.
327
# Special workaround for Python2.3, where difflib fails if
328
# both sequences are empty.
329
if oldlines or newlines:
330
sys.stdout.writelines(difflib.unified_diff(oldlines, newlines, **kw))
340
333
if file_state in ['.', '?', 'I']:
367
def cmd_deleted(show_ids=False):
368
"""List files deleted in the working tree.
370
TODO: Show files deleted since a previous revision, or between two revisions.
374
new = b.working_tree()
376
## TODO: Much more efficient way to do this: read in new
377
## directories with readdir, rather than stating each one. Same
378
## level of effort but possibly much less IO. (Or possibly not,
379
## if the directories are very large...)
381
for path, ie in old.inventory.iter_entries():
382
if not new.has_id(ie.file_id):
384
print '%-50s %s' % (path, ie.file_id)
390
def cmd_parse_inventory():
393
cElementTree.ElementTree().parse(file('.bzr/inventory'))
397
def cmd_load_inventory():
398
inv = Branch('.').basis_tree().inventory
402
def cmd_dump_new_inventory():
403
import bzrlib.newinventory
404
inv = Branch('.').basis_tree().inventory
405
bzrlib.newinventory.write_inventory(inv, sys.stdout)
408
def cmd_load_new_inventory():
409
import bzrlib.newinventory
410
bzrlib.newinventory.read_new_inventory(sys.stdin)
413
def cmd_dump_slacker_inventory():
414
import bzrlib.newinventory
415
inv = Branch('.').basis_tree().inventory
416
bzrlib.newinventory.write_slacker_inventory(inv, sys.stdout)
420
def cmd_root(filename=None):
421
"""Print the branch root."""
422
print bzrlib.branch.find_branch_root(filename)
374
425
def cmd_log(timezone='original'):
375
426
"""Show log of this branch.
466
def cmd_ignored(verbose=True):
467
"""List ignored files and the patterns that matched them.
469
tree = Branch('.').working_tree()
470
for path, file_class, kind, id in tree.list_files():
471
if file_class != 'I':
473
## XXX: Slightly inefficient since this was already calculated
474
pat = tree.is_ignored(path)
475
print '%-50s %s' % (path, pat)
414
478
def cmd_lookup_revision(revno):
416
480
revno = int(revno)
449
def cmd_commit(message, verbose=False):
513
def cmd_commit(message=None, verbose=False):
514
"""Commit changes to a new revision.
517
Description of changes in this revision; free form text.
518
It is recommended that the first line be a single-sentence
521
Show status of changed files,
523
TODO: Commit only selected files.
525
TODO: Run hooks on tree to-be-committed, and after commit.
527
TODO: Strict commit that fails if there are unknown or deleted files.
531
bailout("please specify a commit message")
450
532
Branch('.').commit(message, verbose=verbose)
454
"""Check consistency of the branch."""
535
def cmd_check(dir='.'):
536
"""check: Consistency check of branch history.
538
usage: bzr check [-v] [BRANCH]
541
--verbose, -v Show progress of checking.
543
This command checks various invariants about the branch storage to
544
detect data corruption or bzr bugs.
547
bzrlib.check.check(Branch(dir, find_root=False))
458
550
def cmd_is(pred, *rest):
483
575
print bzrlib.branch._gen_revision_id(time.time())
487
"""Run internal doctest suite"""
578
def cmd_selftest(verbose=False):
579
"""Run internal test suite"""
488
580
## -v, if present, is seen by doctest; the argument is just here
489
581
## so our parser doesn't complain
491
583
## TODO: --verbose option
585
failures, tests = 0, 0
493
import bzr, doctest, bzrlib.store
587
import doctest, bzrlib.store, bzrlib.tests
494
588
bzrlib.trace.verbose = False
496
doctest.testmod(bzrlib.store)
497
doctest.testmod(bzrlib.inventory)
498
doctest.testmod(bzrlib.branch)
499
doctest.testmod(bzrlib.osutils)
500
doctest.testmod(bzrlib.tree)
502
# more strenuous tests;
504
doctest.testmod(bzrlib.tests)
590
for m in bzrlib.store, bzrlib.inventory, bzrlib.branch, bzrlib.osutils, \
591
bzrlib.tree, bzrlib.tests, bzrlib.commands, bzrlib.add:
592
mf, mt = doctest.testmod(m)
595
print '%-40s %3d tests' % (m.__name__, mt),
597
print '%3d FAILED!' % mf
601
print '%-40s %3d tests' % ('total', tests),
603
print '%3d FAILED!' % failures
610
cmd_doctest = cmd_selftest
507
613
######################################################################
512
# TODO: Specific help for particular commands
617
def cmd_help(topic=None):
622
# otherwise, maybe the name of a command?
624
cmdfn = globals()['cmd_' + topic.replace('-', '_')]
626
bailout("no help for %r" % topic)
630
bailout("sorry, no detailed help yet for %r" % topic)
516
637
def cmd_version():
517
print "bzr (bazaar-ng) %s" % __version__
638
print "bzr (bazaar-ng) %s" % bzrlib.__version__
639
print bzrlib.__copyright__
519
640
print "http://bazaar-ng.org/"
573
695
'add': ['file+'],
698
'export': ['revno', 'dest'],
576
699
'file-id': ['filename'],
577
700
'get-file-text': ['text_id'],
578
701
'get-inventory': ['inventory_id'],
579
702
'get-revision': ['revision_id'],
580
703
'get-revision-inventory': ['revision_id'],
582
707
'lookup-revision': ['revno'],
583
'export': ['revno', 'dest'],
708
'mv': ['source$', 'dest'],
709
'relpath': ['filename'],
584
710
'remove': ['file+'],
711
'root': ['filename?'],
594
721
lookup table, something about the available options, what optargs
595
722
they take, and which commands will accept them.
597
>>> parse_args('bzr --help'.split())
724
>>> parse_args('--help'.split())
598
725
([], {'help': True})
599
>>> parse_args('bzr --version'.split())
726
>>> parse_args('--version'.split())
600
727
([], {'version': True})
601
>>> parse_args('bzr status --all'.split())
728
>>> parse_args('status --all'.split())
602
729
(['status'], {'all': True})
603
>>> parse_args('bzr commit --message=biter'.split())
730
>>> parse_args('commit --message=biter'.split())
604
731
(['commit'], {'message': u'biter'})
719
856
log_error('usage: bzr COMMAND\n')
720
857
log_error(' try "bzr help"\n')
724
861
cmd_handler = globals()['cmd_' + cmd.replace('-', '_')]
726
863
bailout("unknown command " + `cmd`)
728
# TODO: special --profile option to turn on the Python profiler
866
if 'profile' in opts:
730
872
# check options are reasonable
731
873
allowed = cmd_options.get(cmd, [])
734
876
bailout("option %r is not allowed for command %r"
879
# mix arguments and options into one dictionary
737
880
cmdargs = _match_args(cmd, args)
740
ret = cmd_handler(**cmdargs) or 0
881
for k, v in opts.items():
882
cmdargs[k.replace('-', '_')] = v
886
prof = hotshot.Profile('.bzr.profile')
887
ret = prof.runcall(cmd_handler, **cmdargs) or 0
891
stats = hotshot.stats.load('.bzr.profile')
893
stats.sort_stats('time')
894
stats.print_stats(20)
896
return cmd_handler(**cmdargs) or 0
748
904
## TODO: If the arguments are wrong, give a usage message rather
749
905
## than just a backtrace.
907
bzrlib.trace.create_tracefile(argv)
752
t = bzrlib.trace._tracefile
753
t.write('-' * 60 + '\n')
754
t.write('bzr invoked at %s\n' % format_date(time.time()))
755
t.write(' by %s on %s\n' % (bzrlib.osutils.username(), socket.gethostname()))
756
t.write(' arguments: %r\n' % argv)
758
starttime = os.times()[4]
761
t.write(' platform: %s\n' % platform.platform())
762
t.write(' python: %s\n' % platform.python_version())
764
910
ret = run_bzr(argv)
767
mutter("finished, %.3fu/%.3fs cpu, %.3fu/%.3fs cum"
769
mutter(" %.3f elapsed" % (times[4] - starttime))
772
912
except BzrError, e:
773
913
log_error('bzr: error: ' + e.args[0] + '\n')