65
import sys, os, random, time, sha, sets, types, re, shutil, tempfile
66
import traceback, socket, fnmatch, difflib
65
import sys, os, time, types, shutil, tempfile, traceback, fnmatch, difflib, os.path
68
66
from sets import Set
69
67
from pprint import pprint
71
69
from glob import glob
70
from inspect import getdoc
74
73
from bzrlib.store import ImmutableStore
75
74
from bzrlib.trace import mutter, note, log_error
76
from bzrlib.errors import bailout, BzrError
75
from bzrlib.errors import bailout, BzrError, BzrCheckError
77
76
from bzrlib.osutils import quotefn, pumpfile, isdir, isfile
78
77
from bzrlib.tree import RevisionTree, EmptyTree, WorkingTree, Tree
79
78
from bzrlib.revision import Revision
200
# TODO: Maybe a 'mv' command that has the combined move/rename
201
# special behaviour of Unix?
203
def cmd_move(source_list, dest):
206
b.move([b.relpath(s) for s in source_list], b.relpath(dest))
210
def cmd_rename(from_name, to_name):
211
"""Change the name of an entry.
213
usage: bzr rename FROM_NAME TO_NAME
216
bzr rename frob.c frobber.c
217
bzr rename src/frob.c lib/frob.c
219
It is an error if the destination name exists.
221
See also the 'move' command, which moves files into a different
222
directory without changing their name.
224
TODO: Some way to rename multiple files without invoking bzr for each
227
b.rename_one(b.relpath(from_name), b.relpath(to_name))
232
def cmd_renames(dir='.'):
233
"""Show list of renamed files.
235
usage: bzr renames [BRANCH]
237
TODO: Option to show renames between two historical versions.
239
TODO: Only show renames under dir, rather than in the whole branch.
242
old_inv = b.basis_tree().inventory
243
new_inv = b.read_working_inventory()
245
renames = list(bzrlib.tree.find_renames(old_inv, new_inv))
247
for old_name, new_name in renames:
248
print "%s => %s" % (old_name, new_name)
199
253
"""info: Show statistical information for this branch
203
257
info.show_info(Branch('.'))
213
267
def cmd_file_id(filename):
268
"""Print file_id of a particular file or directory.
270
usage: bzr file-id FILE
272
The file_id is assigned when the file is first added and remains the
273
same through all revisions where the file exists, even when it is
214
276
b = Branch(filename)
215
277
i = b.inventory.path2id(b.relpath(filename))
217
bailout("%s is not a versioned file" % filename)
279
bailout("%r is not a versioned file" % filename)
222
def cmd_find_filename(fileid):
223
n = find_filename(fileid)
225
bailout("%s is not a live file id" % fileid)
284
def cmd_file_id_path(filename):
285
"""Print path of file_ids to a file or directory.
287
usage: bzr file-id-path FILE
289
This prints one line for each directory down to the target,
290
starting at the branch root."""
293
fid = inv.path2id(b.relpath(filename))
295
bailout("%r is not a versioned file" % filename)
296
for fip in inv.get_idpath(fid):
230
300
def cmd_revision_history():
246
328
Branch('.', init=True)
249
def cmd_diff(revision=None):
331
def cmd_diff(revision=None, file_list=None):
250
332
"""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.
334
usage: bzr diff [-r REV] [FILE...]
337
Show changes since REV, rather than predecessor.
339
If files are listed, only the changes in those files are listed.
340
Otherwise, all changes for the tree are listed.
342
TODO: Given two revision arguments, show the difference between them.
344
TODO: Allow diff across branches.
346
TODO: Option to use external diff command; could be GNU diff, wdiff,
349
TODO: If a directory is given, diff everything under that.
351
TODO: Selected-file diff is inefficient and doesn't show you deleted files.
267
354
## TODO: Shouldn't be in the cmd function.
274
361
old_tree = b.revision_tree(b.lookup_revision(revision))
276
363
new_tree = b.working_tree()
277
old_inv = old_tree.inventory
278
new_inv = new_tree.inventory
280
365
# TODO: Options to control putting on a prefix or suffix, perhaps as a format string
290
375
# be usefully made into a much faster special case.
292
377
# TODO: Better to return them in sorted order I think.
379
# FIXME: If given a file list, compare only those files rather
380
# than comparing everything and then throwing stuff away.
294
382
for file_state, fid, old_name, new_name, kind in bzrlib.diff_trees(old_tree, new_tree):
384
if file_list and new_name not in file_list:
297
387
# Don't show this by default; maybe do it if an option is passed
298
388
# idlabel = ' {%s}' % fid
301
391
# FIXME: Something about the diff format makes patch unhappy
302
392
# with newly-added files.
304
def diffit(*a, **kw):
305
sys.stdout.writelines(difflib.unified_diff(*a, **kw))
394
def diffit(oldlines, newlines, **kw):
395
# FIXME: difflib is wrong if there is no trailing newline.
397
# Special workaround for Python2.3, where difflib fails if
398
# both sequences are empty.
399
if oldlines or newlines:
400
sys.stdout.writelines(difflib.unified_diff(oldlines, newlines, **kw))
308
403
if file_state in ['.', '?', 'I']:
342
437
def cmd_deleted(show_ids=False):
343
438
"""List files deleted in the working tree.
345
TODO: Show files deleted since a previous revision, or between two revisions.
440
TODO: Show files deleted since a previous revision, or between two revisions.
348
443
old = b.basis_tree()
349
444
new = b.working_tree()
446
## TODO: Much more efficient way to do this: read in new
447
## directories with readdir, rather than stating each one. Same
448
## level of effort but possibly much less IO. (Or possibly not,
449
## if the directories are very large...)
351
451
for path, ie in old.inventory.iter_entries():
352
452
if not new.has_id(ie.file_id):
354
454
print '%-50s %s' % (path, ie.file_id)
460
def cmd_parse_inventory():
463
cElementTree.ElementTree().parse(file('.bzr/inventory'))
467
def cmd_load_inventory():
468
"""Load inventory for timing purposes"""
469
Branch('.').basis_tree().inventory
472
def cmd_dump_inventory():
473
Branch('.').read_working_inventory().write_xml(sys.stdout)
476
def cmd_dump_new_inventory():
477
import bzrlib.newinventory
478
inv = Branch('.').basis_tree().inventory
479
bzrlib.newinventory.write_inventory(inv, sys.stdout)
482
def cmd_load_new_inventory():
483
import bzrlib.newinventory
484
bzrlib.newinventory.read_new_inventory(sys.stdin)
487
def cmd_dump_slacker_inventory():
488
import bzrlib.newinventory
489
inv = Branch('.').basis_tree().inventory
490
bzrlib.newinventory.write_slacker_inventory(inv, sys.stdout)
361
494
def cmd_root(filename=None):
362
495
"""Print the branch root."""
407
def cmd_ignored(verbose=True):
408
541
"""List ignored files and the patterns that matched them.
410
543
tree = Branch('.').working_tree()
411
for path, file_class, kind, id in tree.list_files():
544
for path, file_class, kind, file_id in tree.list_files():
412
545
if file_class != 'I':
414
547
## XXX: Slightly inefficient since this was already calculated
434
567
t = b.revision_tree(rh)
570
def cmd_cat(revision, filename):
571
"""Print file to stdout."""
573
b.print_file(b.relpath(filename), int(revision))
439
576
######################################################################
454
591
def cmd_commit(message=None, verbose=False):
455
592
"""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.
595
Description of changes in this revision; free form text.
596
It is recommended that the first line be a single-sentence
599
Show status of changed files,
601
TODO: Commit only selected files.
603
TODO: Run hooks on tree to-be-committed, and after commit.
605
TODO: Strict commit that fails if there are unknown or deleted files.
472
609
bailout("please specify a commit message")
476
613
def cmd_check(dir='.'):
477
614
"""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.
616
usage: bzr check [-v] [BRANCH]
619
--verbose, -v Show progress of checking.
621
This command checks various invariants about the branch storage to
622
detect data corruption or bzr bugs.
487
624
import bzrlib.check
488
625
bzrlib.check.check(Branch(dir, find_root=False))
514
651
def cmd_gen_revision_id():
516
652
print bzrlib.branch._gen_revision_id(time.time())
519
def cmd_selftest(verbose=False):
520
656
"""Run internal test suite"""
521
657
## -v, if present, is seen by doctest; the argument is just here
522
658
## so our parser doesn't complain
636
773
'add': ['file+'],
639
777
'export': ['revno', 'dest'],
640
778
'file-id': ['filename'],
779
'file-id-path': ['filename'],
641
780
'get-file-text': ['text_id'],
642
781
'get-inventory': ['inventory_id'],
643
782
'get-revision': ['revision_id'],
648
787
'lookup-revision': ['revno'],
788
'move': ['source$', 'dest'],
649
789
'relpath': ['filename'],
650
790
'remove': ['file+'],
791
'rename': ['from_name', 'to_name'],
651
793
'root': ['filename?'],
740
882
if ap[-1] == '?':
742
884
argdict[argname] = args.pop(0)
885
elif ap[-1] == '*': # all remaining arguments
887
argdict[argname + '_list'] = args[:]
890
argdict[argname + '_list'] = None
745
891
elif ap[-1] == '+':
747
893
bailout("command %r needs one or more %s"
750
896
argdict[argname + '_list'] = args[:]
898
elif ap[-1] == '$': # all but one
900
bailout("command %r needs one or more %s"
901
% (cmd, argname.upper()))
902
argdict[argname + '_list'] = args[:-1]
753
905
# just a plain arg
807
962
bailout("option %r is not allowed for command %r"
965
# TODO: give an error if there are any mandatory options which are
966
# not specified? Or maybe there shouldn't be any "mandatory
967
# options" (it is an oxymoron)
810
969
# mix arguments and options into one dictionary
811
970
cmdargs = _match_args(cmd, args)
812
971
for k, v in opts.items():
845
1006
if len(e.args) > 1:
846
1007
for h in e.args[1]:
847
1008
log_error(' ' + h + '\n')
1009
traceback.print_exc(None, bzrlib.trace._tracefile)
1010
log_error('(see $HOME/.bzr.log for debug information)\n')
849
1012
except Exception, e:
850
1013
log_error('bzr: exception: %s\n' % e)
851
log_error(' see .bzr.log for details\n')
1014
log_error('(see $HOME/.bzr.log for debug information)\n')
852
1015
traceback.print_exc(None, bzrlib.trace._tracefile)
853
traceback.print_exc(None, sys.stderr)
1016
## traceback.print_exc(None, sys.stderr)
856
1019
# TODO: Maybe nicer handling of IOError?