~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/commands.py

  • Committer: mbp at sourcefrog
  • Date: 2005-04-11 01:58:58 UTC
  • Revision ID: mbp@sourcefrog.net-20050411015857-f781b0d325632cf5cacd2481
- more output from test.sh
- write revison-history in a way that is hardlink-safe

Show diffs side-by-side

added added

removed removed

Lines of Context:
45
45
       Make files versioned.
46
46
  bzr log
47
47
       Show revision history.
48
 
  bzr diff
 
48
  bzr diff [FILE...]
49
49
       Show changes from last revision to working copy.
50
50
  bzr commit -m 'MESSAGE'
51
51
       Store current state as new revision.
62
62
 
63
63
 
64
64
 
65
 
import sys, os, random, time, sha, sets, types, re, shutil, tempfile
66
 
import traceback, socket, fnmatch, difflib
67
 
from os import path
 
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
70
68
from stat import *
71
69
from glob import glob
 
70
from inspect import getdoc
72
71
 
73
72
import bzrlib
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
127
126
 
128
127
    :todo: Don't show unchanged files unless ``--all`` is given?
129
128
    """
 
129
    #import bzrlib.status
 
130
    #bzrlib.status.tree_status(Branch('.'))
130
131
    Branch('.').show_status(show_all=all)
131
132
 
132
133
 
180
181
    print Branch(filename).relpath(filename)
181
182
 
182
183
 
 
184
 
183
185
def cmd_inventory(revision=None):
184
186
    """Show inventory of the current working copy."""
185
187
    ## TODO: Also optionally show a previous inventory
195
197
 
196
198
 
197
199
 
 
200
# TODO: Maybe a 'mv' command that has the combined move/rename
 
201
# special behaviour of Unix?
 
202
 
 
203
def cmd_move(source_list, dest):
 
204
    b = Branch('.')
 
205
 
 
206
    b.move([b.relpath(s) for s in source_list], b.relpath(dest))
 
207
 
 
208
 
 
209
 
 
210
def cmd_rename(from_name, to_name):
 
211
    """Change the name of an entry.
 
212
 
 
213
    usage: bzr rename FROM_NAME TO_NAME
 
214
 
 
215
    examples:
 
216
      bzr rename frob.c frobber.c
 
217
      bzr rename src/frob.c lib/frob.c
 
218
 
 
219
    It is an error if the destination name exists.
 
220
 
 
221
    See also the 'move' command, which moves files into a different
 
222
    directory without changing their name.
 
223
 
 
224
    TODO: Some way to rename multiple files without invoking bzr for each
 
225
    one?"""
 
226
    b = Branch('.')
 
227
    b.rename_one(b.relpath(from_name), b.relpath(to_name))
 
228
    
 
229
 
 
230
 
 
231
 
 
232
def cmd_renames(dir='.'):
 
233
    """Show list of renamed files.
 
234
 
 
235
    usage: bzr renames [BRANCH]
 
236
 
 
237
    TODO: Option to show renames between two historical versions.
 
238
 
 
239
    TODO: Only show renames under dir, rather than in the whole branch.
 
240
    """
 
241
    b = Branch(dir)
 
242
    old_inv = b.basis_tree().inventory
 
243
    new_inv = b.read_working_inventory()
 
244
    
 
245
    renames = list(bzrlib.tree.find_renames(old_inv, new_inv))
 
246
    renames.sort()
 
247
    for old_name, new_name in renames:
 
248
        print "%s => %s" % (old_name, new_name)        
 
249
 
 
250
 
 
251
 
198
252
def cmd_info():
199
253
    """info: Show statistical information for this branch
200
254
 
201
 
usage: bzr info"""
 
255
    usage: bzr info"""
202
256
    import info
203
257
    info.show_info(Branch('.'))        
204
258
    
211
265
 
212
266
 
213
267
def cmd_file_id(filename):
 
268
    """Print file_id of a particular file or directory.
 
269
 
 
270
    usage: bzr file-id FILE
 
271
 
 
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
 
274
    moved or renamed.
 
275
    """
214
276
    b = Branch(filename)
215
277
    i = b.inventory.path2id(b.relpath(filename))
216
 
    if i is None:
217
 
        bailout("%s is not a versioned file" % filename)
 
278
    if i == None:
 
279
        bailout("%r is not a versioned file" % filename)
218
280
    else:
219
281
        print i
220
282
 
221
283
 
222
 
def cmd_find_filename(fileid):
223
 
    n = find_filename(fileid)
224
 
    if n is None:
225
 
        bailout("%s is not a live file id" % fileid)
226
 
    else:
227
 
        print n
 
284
def cmd_file_id_path(filename):
 
285
    """Print path of file_ids to a file or directory.
 
286
 
 
287
    usage: bzr file-id-path FILE
 
288
 
 
289
    This prints one line for each directory down to the target,
 
290
    starting at the branch root."""
 
291
    b = Branch(filename)
 
292
    inv = b.inventory
 
293
    fid = inv.path2id(b.relpath(filename))
 
294
    if fid == None:
 
295
        bailout("%r is not a versioned file" % filename)
 
296
    for fip in inv.get_idpath(fid):
 
297
        print fip
228
298
 
229
299
 
230
300
def cmd_revision_history():
232
302
        print patchid
233
303
 
234
304
 
 
305
def cmd_directories():
 
306
    for name, ie in Branch('.').read_working_inventory().directories():
 
307
        if name == '':
 
308
            print '.'
 
309
        else:
 
310
            print name
 
311
 
 
312
 
 
313
def cmd_missing():
 
314
    for name, ie in Branch('.').working_tree().missing():
 
315
        print name
 
316
 
235
317
 
236
318
def cmd_init():
237
319
    # TODO: Check we're not already in a working directory?  At the
246
328
    Branch('.', init=True)
247
329
 
248
330
 
249
 
def cmd_diff(revision=None):
 
331
def cmd_diff(revision=None, file_list=None):
250
332
    """bzr diff: Show differences in working tree.
251
333
    
252
 
usage: bzr diff [-r REV]
253
 
 
254
 
--revision REV
255
 
    Show changes since REV, rather than predecessor.
256
 
 
257
 
TODO: Given two revision arguments, show the difference between them.
258
 
 
259
 
TODO: Allow diff across branches.
260
 
 
261
 
TODO: Option to use external diff command; could be GNU diff, wdiff,
262
 
or a graphical diff.
263
 
 
264
 
TODO: Diff selected files.
 
334
    usage: bzr diff [-r REV] [FILE...]
 
335
 
 
336
    --revision REV
 
337
         Show changes since REV, rather than predecessor.
 
338
 
 
339
    If files are listed, only the changes in those files are listed.
 
340
    Otherwise, all changes for the tree are listed.
 
341
 
 
342
    TODO: Given two revision arguments, show the difference between them.
 
343
 
 
344
    TODO: Allow diff across branches.
 
345
 
 
346
    TODO: Option to use external diff command; could be GNU diff, wdiff,
 
347
          or a graphical diff.
 
348
 
 
349
    TODO: If a directory is given, diff everything under that.
 
350
 
 
351
    TODO: Selected-file diff is inefficient and doesn't show you deleted files.
265
352
"""
266
353
 
267
354
    ## TODO: Shouldn't be in the cmd function.
274
361
        old_tree = b.revision_tree(b.lookup_revision(revision))
275
362
        
276
363
    new_tree = b.working_tree()
277
 
    old_inv = old_tree.inventory
278
 
    new_inv = new_tree.inventory
279
364
 
280
365
    # TODO: Options to control putting on a prefix or suffix, perhaps as a format string
281
366
    old_label = ''
290
375
    # be usefully made into a much faster special case.
291
376
 
292
377
    # TODO: Better to return them in sorted order I think.
 
378
 
 
379
    # FIXME: If given a file list, compare only those files rather
 
380
    # than comparing everything and then throwing stuff away.
293
381
    
294
382
    for file_state, fid, old_name, new_name, kind in bzrlib.diff_trees(old_tree, new_tree):
295
 
        d = None
296
383
 
 
384
        if file_list and new_name not in file_list:
 
385
            continue
 
386
        
297
387
        # Don't show this by default; maybe do it if an option is passed
298
388
        # idlabel = '      {%s}' % fid
299
389
        idlabel = ''
301
391
        # FIXME: Something about the diff format makes patch unhappy
302
392
        # with newly-added files.
303
393
 
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.
 
396
 
 
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))
306
401
            print
307
402
        
308
403
        if file_state in ['.', '?', 'I']:
342
437
def cmd_deleted(show_ids=False):
343
438
    """List files deleted in the working tree.
344
439
 
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.
346
441
    """
347
442
    b = Branch('.')
348
443
    old = b.basis_tree()
349
444
    new = b.working_tree()
350
445
 
 
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...)
 
450
 
351
451
    for path, ie in old.inventory.iter_entries():
352
452
        if not new.has_id(ie.file_id):
353
453
            if show_ids:
354
454
                print '%-50s %s' % (path, ie.file_id)
355
455
            else:
356
456
                print path
357
 
                
358
 
    
359
 
 
 
457
 
 
458
 
 
459
 
 
460
def cmd_parse_inventory():
 
461
    import cElementTree
 
462
    
 
463
    cElementTree.ElementTree().parse(file('.bzr/inventory'))
 
464
 
 
465
 
 
466
 
 
467
def cmd_load_inventory():
 
468
    """Load inventory for timing purposes"""
 
469
    Branch('.').basis_tree().inventory
 
470
 
 
471
 
 
472
def cmd_dump_inventory():
 
473
    Branch('.').read_working_inventory().write_xml(sys.stdout)
 
474
 
 
475
 
 
476
def cmd_dump_new_inventory():
 
477
    import bzrlib.newinventory
 
478
    inv = Branch('.').basis_tree().inventory
 
479
    bzrlib.newinventory.write_inventory(inv, sys.stdout)
 
480
 
 
481
 
 
482
def cmd_load_new_inventory():
 
483
    import bzrlib.newinventory
 
484
    bzrlib.newinventory.read_new_inventory(sys.stdin)
 
485
                
 
486
    
 
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)
 
491
                
 
492
    
360
493
 
361
494
def cmd_root(filename=None):
362
495
    """Print the branch root."""
404
537
 
405
538
 
406
539
 
407
 
def cmd_ignored(verbose=True):
 
540
def cmd_ignored():
408
541
    """List ignored files and the patterns that matched them.
409
542
      """
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':
413
546
            continue
414
547
        ## XXX: Slightly inefficient since this was already calculated
434
567
    t = b.revision_tree(rh)
435
568
    t.export(dest)
436
569
 
 
570
def cmd_cat(revision, filename):
 
571
    """Print file to stdout."""
 
572
    b = Branch('.')
 
573
    b.print_file(b.relpath(filename), int(revision))
437
574
 
438
575
 
439
576
######################################################################
454
591
def cmd_commit(message=None, verbose=False):
455
592
    """Commit changes to a new revision.
456
593
 
457
 
--message MESSAGE
458
 
    Description of changes in this revision; free form text.
459
 
    It is recommended that the first line be a single-sentence
460
 
    summary.
461
 
--verbose
462
 
    Show status of changed files,
463
 
 
464
 
TODO: Commit only selected files.
465
 
 
466
 
TODO: Run hooks on tree to-be-committed, and after commit.
467
 
 
468
 
TODO: Strict commit that fails if there are unknown or deleted files.
469
 
"""
 
594
    --message MESSAGE
 
595
        Description of changes in this revision; free form text.
 
596
        It is recommended that the first line be a single-sentence
 
597
        summary.
 
598
    --verbose
 
599
        Show status of changed files,
 
600
 
 
601
    TODO: Commit only selected files.
 
602
 
 
603
    TODO: Run hooks on tree to-be-committed, and after commit.
 
604
 
 
605
    TODO: Strict commit that fails if there are unknown or deleted files.
 
606
    """
470
607
 
471
608
    if not message:
472
609
        bailout("please specify a commit message")
476
613
def cmd_check(dir='.'):
477
614
    """check: Consistency check of branch history.
478
615
 
479
 
usage: bzr check [-v] [BRANCH]
480
 
 
481
 
options:
482
 
  --verbose, -v         Show progress of checking.
483
 
 
484
 
This command checks various invariants about the branch storage to
485
 
detect data corruption or bzr bugs.
486
 
"""
 
616
    usage: bzr check [-v] [BRANCH]
 
617
 
 
618
    options:
 
619
      --verbose, -v         Show progress of checking.
 
620
 
 
621
    This command checks various invariants about the branch storage to
 
622
    detect data corruption or bzr bugs.
 
623
    """
487
624
    import bzrlib.check
488
625
    bzrlib.check.check(Branch(dir, find_root=False))
489
626
 
512
649
 
513
650
 
514
651
def cmd_gen_revision_id():
515
 
    import time
516
652
    print bzrlib.branch._gen_revision_id(time.time())
517
653
 
518
654
 
519
 
def cmd_selftest(verbose=False):
 
655
def cmd_selftest():
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
566
702
    except KeyError:
567
703
        bailout("no help for %r" % topic)
568
704
 
569
 
    doc = cmdfn.__doc__
 
705
    doc = getdoc(cmdfn)
570
706
    if doc == None:
571
707
        bailout("sorry, no detailed help yet for %r" % topic)
572
708
 
621
757
# listed take none.
622
758
cmd_options = {
623
759
    'add':                    ['verbose'],
 
760
    'cat':                    ['revision'],
624
761
    'commit':                 ['message', 'verbose'],
625
762
    'deleted':                ['show-ids'],
626
763
    'diff':                   ['revision'],
634
771
 
635
772
cmd_args = {
636
773
    'add':                    ['file+'],
 
774
    'cat':                    ['filename'],
637
775
    'commit':                 [],
638
 
    'diff':                   [],
 
776
    'diff':                   ['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'],
646
785
    'init':                   [],
647
786
    'log':                    [],
648
787
    'lookup-revision':        ['revno'],
 
788
    'move':                   ['source$', 'dest'],
649
789
    'relpath':                ['filename'],
650
790
    'remove':                 ['file+'],
 
791
    'rename':                 ['from_name', 'to_name'],
 
792
    'renames':                ['dir?'],
651
793
    'root':                   ['filename?'],
652
794
    'status':                 [],
653
795
    }
740
882
        if ap[-1] == '?':
741
883
            if args:
742
884
                argdict[argname] = args.pop(0)
743
 
        elif ap[-1] == '*':
744
 
            assert 0
 
885
        elif ap[-1] == '*': # all remaining arguments
 
886
            if args:
 
887
                argdict[argname + '_list'] = args[:]
 
888
                args = []
 
889
            else:
 
890
                argdict[argname + '_list'] = None
745
891
        elif ap[-1] == '+':
746
892
            if not args:
747
893
                bailout("command %r needs one or more %s"
749
895
            else:
750
896
                argdict[argname + '_list'] = args[:]
751
897
                args = []
 
898
        elif ap[-1] == '$': # all but one
 
899
            if len(args) < 2:
 
900
                bailout("command %r needs one or more %s"
 
901
                        % (cmd, argname.upper()))
 
902
            argdict[argname + '_list'] = args[:-1]
 
903
            args[:-1] = []                
752
904
        else:
753
905
            # just a plain arg
754
906
            argname = ap
777
929
        if 'help' in opts:
778
930
            # TODO: pass down other arguments in case they asked for
779
931
            # help on a command name?
780
 
            cmd_help()
 
932
            if args:
 
933
                cmd_help(args[0])
 
934
            else:
 
935
                cmd_help()
781
936
            return 0
782
937
        elif 'version' in opts:
783
938
            cmd_version()
807
962
            bailout("option %r is not allowed for command %r"
808
963
                    % (oname, cmd))
809
964
 
 
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)
 
968
 
810
969
    # mix arguments and options into one dictionary
811
970
    cmdargs = _match_args(cmd, args)
812
971
    for k, v in opts.items():
821
980
        import hotshot.stats
822
981
        stats = hotshot.stats.load('.bzr.profile')
823
982
        #stats.strip_dirs()
824
 
        stats.sort_stats('cumulative', 'calls')
 
983
        stats.sort_stats('time')
825
984
        stats.print_stats(20)
 
985
 
 
986
        return ret
826
987
    else:
827
988
        return cmd_handler(**cmdargs) or 0
828
989
 
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')
848
1011
        return 1
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)
854
1017
        return 1
855
1018
 
856
1019
    # TODO: Maybe nicer handling of IOError?