~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/commands.py

  • Committer: mbp at sourcefrog
  • Date: 2005-03-23 06:25:55 UTC
  • Revision ID: mbp@sourcefrog.net-20050323062555-5489339018d0c043
- import a subset of elementtree for easier installation

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#! /usr/bin/python
 
2
 
 
3
 
1
4
# Copyright (C) 2004, 2005 by Martin Pool
2
5
# Copyright (C) 2005 by Canonical Ltd
3
6
 
25
28
* Metadata format is not stable yet -- you may need to
26
29
  discard history in the future.
27
30
 
 
31
* No handling of subdirectories, symlinks or any non-text files.
 
32
 
28
33
* Insufficient error handling.
29
34
 
30
35
* Many commands unimplemented or partially implemented.
35
40
 
36
41
Interesting commands::
37
42
 
38
 
  bzr help [COMMAND]
39
 
       Show help screen
 
43
  bzr help
 
44
       Show summary help screen
40
45
  bzr version
41
46
       Show software version/licence/non-warranty.
42
47
  bzr init
55
60
       Show summary of pending changes.
56
61
  bzr remove FILE...
57
62
       Make a file not versioned.
58
 
  bzr info
59
 
       Show statistics about this branch.
60
63
"""
61
64
 
62
 
 
 
65
# not currently working:
 
66
#  bzr info
 
67
#       Show some information about this branch.
 
68
 
 
69
 
 
70
 
 
71
__copyright__ = "Copyright 2005 Canonical Development Ltd."
 
72
__author__ = "Martin Pool <mbp@canonical.com>"
 
73
__docformat__ = "restructuredtext en"
 
74
__version__ = '0.0.0'
63
75
 
64
76
 
65
77
import sys, os, random, time, sha, sets, types, re, shutil, tempfile
172
184
    Therefore simply saying 'bzr add .' will version all files that
173
185
    are currently unknown.
174
186
    """
175
 
    bzrlib.add.smart_add(file_list, verbose)
 
187
    if True:
 
188
        bzrlib.add.smart_add(file_list, verbose)
 
189
    else:
 
190
        # old way
 
191
        assert file_list
 
192
        b = Branch(file_list[0], find_root=True)
 
193
        b.add([b.relpath(f) for f in file_list], verbose=verbose)
 
194
 
176
195
    
177
196
 
178
197
def cmd_relpath(filename):
179
 
    """Show path of file relative to root"""
180
198
    print Branch(filename).relpath(filename)
181
199
 
182
200
 
183
 
 
184
201
def cmd_inventory(revision=None):
185
202
    """Show inventory of the current working copy."""
186
203
    ## TODO: Also optionally show a previous inventory
196
213
 
197
214
 
198
215
 
199
 
def cmd_mv(source_list, dest):
200
 
    b = Branch('.')
201
 
 
202
 
    b.rename([b.relpath(s) for s in source_list], b.relpath(dest))
203
 
 
204
 
 
205
 
 
206
 
def cmd_rename(from_name, to_name):
207
 
    """Change the name of an entry.
208
 
 
209
 
usage: bzr rename FROM_NAME TO_NAME
210
 
 
211
 
examples:
212
 
  bzr rename frob.c frobber.c
213
 
  bzr rename src/frob.c lib/frob.c
214
 
 
215
 
It is an error if the destination name exists.
216
 
 
217
 
See also the 'move' command, which moves files into a different
218
 
directory without changing their name.
219
 
 
220
 
TODO: Some way to rename multiple files without invoking bzr for each
221
 
one?"""
222
 
    b = Branch('.')
223
 
    b.rename_one(b.relpath(from_name), b.relpath(to_name))
224
 
    
225
 
 
226
 
 
227
 
 
228
 
def cmd_renames(dir='.'):
229
 
    """Show list of renamed files.
230
 
 
231
 
usage: bzr renames [BRANCH]
232
 
 
233
 
TODO: Option to show renames between two historical versions.
234
 
 
235
 
TODO: Only show renames under dir, rather than in the whole branch.
236
 
"""
237
 
    b = Branch(dir)
238
 
    old_inv = b.basis_tree().inventory
239
 
    new_inv = b.read_working_inventory()
240
 
    
241
 
    renames = list(bzrlib.tree.find_renames(old_inv, new_inv))
242
 
    renames.sort()
243
 
    for old_name, new_name in renames:
244
 
        print "%s => %s" % (old_name, new_name)        
245
 
 
246
 
 
247
 
 
248
216
def cmd_info():
249
 
    """info: Show statistical information for this branch
250
 
 
251
 
usage: bzr info"""
252
 
    import info
253
 
    info.show_info(Branch('.'))        
 
217
    b = Branch('.')
 
218
    print 'branch format:', b.controlfile('branch-format', 'r').readline().rstrip('\n')
 
219
 
 
220
    def plural(n, base='', pl=None):
 
221
        if n == 1:
 
222
            return base
 
223
        elif pl is not None:
 
224
            return pl
 
225
        else:
 
226
            return 's'
 
227
 
 
228
    count_version_dirs = 0
 
229
 
 
230
    count_status = {'A': 0, 'D': 0, 'M': 0, 'R': 0, '?': 0, 'I': 0, '.': 0}
 
231
    for st_tup in bzrlib.diff_trees(b.basis_tree(), b.working_tree()):
 
232
        fs = st_tup[0]
 
233
        count_status[fs] += 1
 
234
        if fs not in ['I', '?'] and st_tup[4] == 'directory':
 
235
            count_version_dirs += 1
 
236
 
 
237
    print
 
238
    print 'in the working tree:'
 
239
    for name, fs in (('unchanged', '.'),
 
240
                     ('modified', 'M'), ('added', 'A'), ('removed', 'D'),
 
241
                     ('renamed', 'R'), ('unknown', '?'), ('ignored', 'I'),
 
242
                     ):
 
243
        print '  %5d %s' % (count_status[fs], name)
 
244
    print '  %5d versioned subdirector%s' % (count_version_dirs,
 
245
                                             plural(count_version_dirs, 'y', 'ies'))
 
246
 
 
247
    print
 
248
    print 'branch history:'
 
249
    history = b.revision_history()
 
250
    revno = len(history)
 
251
    print '  %5d revision%s' % (revno, plural(revno))
 
252
    committers = Set()
 
253
    for rev in history:
 
254
        committers.add(b.get_revision(rev).committer)
 
255
    print '  %5d committer%s' % (len(committers), plural(len(committers)))
 
256
    if revno > 0:
 
257
        firstrev = b.get_revision(history[0])
 
258
        age = int((time.time() - firstrev.timestamp) / 3600 / 24)
 
259
        print '  %5d day%s old' % (age, plural(age))
 
260
        print '  first revision: %s' % format_date(firstrev.timestamp,
 
261
                                                 firstrev.timezone)
 
262
 
 
263
        lastrev = b.get_revision(history[-1])
 
264
        print '  latest revision: %s' % format_date(lastrev.timestamp,
 
265
                                                    lastrev.timezone)
 
266
        
254
267
    
255
268
 
256
269
 
282
295
        print patchid
283
296
 
284
297
 
285
 
def cmd_directories():
286
 
    for name, ie in Branch('.').read_working_inventory().directories():
287
 
        if name == '':
288
 
            print '.'
289
 
        else:
290
 
            print name
291
 
 
292
 
 
293
 
def cmd_missing():
294
 
    for name, ie in Branch('.').working_tree().missing():
295
 
        print name
296
 
 
297
298
 
298
299
def cmd_init():
299
300
    # TODO: Check we're not already in a working directory?  At the
309
310
 
310
311
 
311
312
def cmd_diff(revision=None):
312
 
    """bzr diff: Show differences in working tree.
313
 
    
314
 
usage: bzr diff [-r REV]
315
 
 
316
 
--revision REV
317
 
    Show changes since REV, rather than predecessor.
318
 
 
319
 
TODO: Given two revision arguments, show the difference between them.
320
 
 
321
 
TODO: Allow diff across branches.
322
 
 
323
 
TODO: Option to use external diff command; could be GNU diff, wdiff,
324
 
or a graphical diff.
325
 
 
326
 
TODO: Diff selected files.
327
 
"""
328
 
 
329
 
    ## TODO: Shouldn't be in the cmd function.
 
313
    """Show diff from basis to working copy.
 
314
 
 
315
    :todo: Take one or two revision arguments, look up those trees,
 
316
           and diff them.
 
317
 
 
318
    :todo: Allow diff across branches.
 
319
 
 
320
    :todo: Mangle filenames in diff to be more relevant.
 
321
 
 
322
    :todo: Shouldn't be in the cmd function.
 
323
    """
330
324
 
331
325
    b = Branch('.')
332
326
 
363
357
        # FIXME: Something about the diff format makes patch unhappy
364
358
        # with newly-added files.
365
359
 
366
 
        def diffit(oldlines, newlines, **kw):
367
 
            # FIXME: difflib is wrong if there is no trailing newline.
368
 
 
369
 
            # Special workaround for Python2.3, where difflib fails if
370
 
            # both sequences are empty.
371
 
            if oldlines or newlines:
372
 
                sys.stdout.writelines(difflib.unified_diff(oldlines, newlines, **kw))
 
360
        def diffit(*a, **kw):
 
361
            sys.stdout.writelines(difflib.unified_diff(*a, **kw))
373
362
            print
374
363
        
375
364
        if file_state in ['.', '?', 'I']:
406
395
 
407
396
 
408
397
 
409
 
def cmd_deleted(show_ids=False):
410
 
    """List files deleted in the working tree.
411
 
 
412
 
TODO: Show files deleted since a previous revision, or between two revisions.
413
 
    """
414
 
    b = Branch('.')
415
 
    old = b.basis_tree()
416
 
    new = b.working_tree()
417
 
 
418
 
    ## TODO: Much more efficient way to do this: read in new
419
 
    ## directories with readdir, rather than stating each one.  Same
420
 
    ## level of effort but possibly much less IO.  (Or possibly not,
421
 
    ## if the directories are very large...)
422
 
 
423
 
    for path, ie in old.inventory.iter_entries():
424
 
        if not new.has_id(ie.file_id):
425
 
            if show_ids:
426
 
                print '%-50s %s' % (path, ie.file_id)
427
 
            else:
428
 
                print path
429
 
 
430
 
 
431
 
 
432
 
def cmd_parse_inventory():
433
 
    import cElementTree
434
 
    
435
 
    cElementTree.ElementTree().parse(file('.bzr/inventory'))
436
 
 
437
 
 
438
 
 
439
 
def cmd_load_inventory():
440
 
    inv = Branch('.').basis_tree().inventory
441
 
 
442
 
 
443
 
 
444
 
def cmd_dump_new_inventory():
445
 
    import bzrlib.newinventory
446
 
    inv = Branch('.').basis_tree().inventory
447
 
    bzrlib.newinventory.write_inventory(inv, sys.stdout)
448
 
 
449
 
 
450
 
def cmd_load_new_inventory():
451
 
    import bzrlib.newinventory
452
 
    bzrlib.newinventory.read_new_inventory(sys.stdin)
453
 
                
454
 
    
455
 
def cmd_dump_slacker_inventory():
456
 
    import bzrlib.newinventory
457
 
    inv = Branch('.').basis_tree().inventory
458
 
    bzrlib.newinventory.write_slacker_inventory(inv, sys.stdout)
459
 
                
460
 
    
461
 
 
462
398
def cmd_root(filename=None):
463
399
    """Print the branch root."""
464
400
    print bzrlib.branch.find_branch_root(filename)
504
440
        print quotefn(f)
505
441
 
506
442
 
507
 
 
508
 
def cmd_ignored(verbose=True):
509
 
    """List ignored files and the patterns that matched them.
510
 
      """
511
 
    tree = Branch('.').working_tree()
512
 
    for path, file_class, kind, id in tree.list_files():
513
 
        if file_class != 'I':
514
 
            continue
515
 
        ## XXX: Slightly inefficient since this was already calculated
516
 
        pat = tree.is_ignored(path)
517
 
        print '%-50s %s' % (path, pat)
518
 
 
519
 
 
520
443
def cmd_lookup_revision(revno):
521
444
    try:
522
445
        revno = int(revno)
553
476
 
554
477
 
555
478
def cmd_commit(message=None, verbose=False):
556
 
    """Commit changes to a new revision.
557
 
 
558
 
--message MESSAGE
559
 
    Description of changes in this revision; free form text.
560
 
    It is recommended that the first line be a single-sentence
561
 
    summary.
562
 
--verbose
563
 
    Show status of changed files,
564
 
 
565
 
TODO: Commit only selected files.
566
 
 
567
 
TODO: Run hooks on tree to-be-committed, and after commit.
568
 
 
569
 
TODO: Strict commit that fails if there are unknown or deleted files.
570
 
"""
571
 
 
572
479
    if not message:
573
480
        bailout("please specify a commit message")
574
481
    Branch('.').commit(message, verbose=verbose)
575
482
 
576
483
 
577
 
def cmd_check(dir='.'):
578
 
    """check: Consistency check of branch history.
579
 
 
580
 
usage: bzr check [-v] [BRANCH]
581
 
 
582
 
options:
583
 
  --verbose, -v         Show progress of checking.
584
 
 
585
 
This command checks various invariants about the branch storage to
586
 
detect data corruption or bzr bugs.
587
 
"""
588
 
    import bzrlib.check
589
 
    bzrlib.check.check(Branch(dir, find_root=False))
 
484
def cmd_check():
 
485
    """Check consistency of the branch."""
 
486
    check()
590
487
 
591
488
 
592
489
def cmd_is(pred, *rest):
656
553
# help
657
554
 
658
555
 
659
 
def cmd_help(topic=None):
660
 
    if topic == None:
661
 
        print __doc__
662
 
        return
663
 
 
664
 
    # otherwise, maybe the name of a command?
665
 
    try:
666
 
        cmdfn = globals()['cmd_' + topic.replace('-', '_')]
667
 
    except KeyError:
668
 
        bailout("no help for %r" % topic)
669
 
 
670
 
    doc = cmdfn.__doc__
671
 
    if doc == None:
672
 
        bailout("sorry, no detailed help yet for %r" % topic)
673
 
 
674
 
    print doc
675
 
        
676
 
 
 
556
def cmd_help():
 
557
    # TODO: Specific help for particular commands
 
558
    print __doc__
677
559
 
678
560
 
679
561
def cmd_version():
680
 
    print "bzr (bazaar-ng) %s" % bzrlib.__version__
681
 
    print bzrlib.__copyright__
 
562
    print "bzr (bazaar-ng) %s" % __version__
 
563
    print __copyright__
682
564
    print "http://bazaar-ng.org/"
683
565
    print
684
566
    print \
704
586
    'all':                    None,
705
587
    'help':                   None,
706
588
    'message':                unicode,
707
 
    'profile':                None,
708
589
    'revision':               int,
709
590
    'show-ids':               None,
710
591
    'timezone':               str,
723
604
cmd_options = {
724
605
    'add':                    ['verbose'],
725
606
    'commit':                 ['message', 'verbose'],
726
 
    'deleted':                ['show-ids'],
727
607
    'diff':                   ['revision'],
728
608
    'inventory':              ['revision'],
729
 
    'log':                    ['timezone'],
 
609
    'log':                    ['show-ids', 'timezone'],
730
610
    'ls':                     ['revision', 'verbose'],
731
611
    'remove':                 ['verbose'],
732
612
    'status':                 ['all'],
734
614
 
735
615
 
736
616
cmd_args = {
 
617
    'init':                   [],
737
618
    'add':                    ['file+'],
738
619
    'commit':                 [],
739
620
    'diff':                   [],
740
 
    'export':                 ['revno', 'dest'],
741
621
    'file-id':                ['filename'],
 
622
    'root':                   ['filename?'],
 
623
    'relpath':                ['filename'],
742
624
    'get-file-text':          ['text_id'],
743
625
    'get-inventory':          ['inventory_id'],
744
626
    'get-revision':           ['revision_id'],
745
627
    'get-revision-inventory': ['revision_id'],
746
 
    'help':                   ['topic?'],
747
 
    'init':                   [],
748
628
    'log':                    [],
749
629
    'lookup-revision':        ['revno'],
750
 
    'mv':                     ['source$', 'dest'],
751
 
    'relpath':                ['filename'],
 
630
    'export':                 ['revno', 'dest'],
752
631
    'remove':                 ['file+'],
753
 
    'rename':                 ['from_name', 'to_name'],
754
 
    'renames':                ['dir?'],
755
 
    'root':                   ['filename?'],
756
632
    'status':                 [],
757
633
    }
758
634
 
809
685
                    else:
810
686
                        optarg = argv.pop(0)
811
687
                opts[optname] = optargfn(optarg)
 
688
                mutter("    option argument %r" % opts[optname])
812
689
            else:
813
690
                if optarg != None:
814
691
                    bailout('option %r takes no argument' % optname)
853
730
            else:
854
731
                argdict[argname + '_list'] = args[:]
855
732
                args = []
856
 
        elif ap[-1] == '$': # all but one
857
 
            if len(args) < 2:
858
 
                bailout("command %r needs one or more %s"
859
 
                        % (cmd, argname.upper()))
860
 
            argdict[argname + '_list'] = args[:-1]
861
 
            args[:-1] = []                
862
733
        else:
863
734
            # just a plain arg
864
735
            argname = ap
887
758
        if 'help' in opts:
888
759
            # TODO: pass down other arguments in case they asked for
889
760
            # help on a command name?
890
 
            if args:
891
 
                cmd_help(args[0])
892
 
            else:
893
 
                cmd_help()
 
761
            cmd_help()
894
762
            return 0
895
763
        elif 'version' in opts:
896
764
            cmd_version()
900
768
        log_error('usage: bzr COMMAND\n')
901
769
        log_error('  try "bzr help"\n')
902
770
        return 1
903
 
 
 
771
            
904
772
    try:
905
773
        cmd_handler = globals()['cmd_' + cmd.replace('-', '_')]
906
774
    except KeyError:
907
775
        bailout("unknown command " + `cmd`)
908
776
 
909
 
    # global option
910
 
    if 'profile' in opts:
911
 
        profile = True
912
 
        del opts['profile']
913
 
    else:
914
 
        profile = False
 
777
    # TODO: special --profile option to turn on the Python profiler
915
778
 
916
779
    # check options are reasonable
917
780
    allowed = cmd_options.get(cmd, [])
920
783
            bailout("option %r is not allowed for command %r"
921
784
                    % (oname, cmd))
922
785
 
923
 
    # mix arguments and options into one dictionary
924
786
    cmdargs = _match_args(cmd, args)
925
 
    for k, v in opts.items():
926
 
        cmdargs[k.replace('-', '_')] = v
927
 
 
928
 
    if profile:
929
 
        import hotshot
930
 
        prof = hotshot.Profile('.bzr.profile')
931
 
        ret = prof.runcall(cmd_handler, **cmdargs) or 0
932
 
        prof.close()
933
 
 
934
 
        import hotshot.stats
935
 
        stats = hotshot.stats.load('.bzr.profile')
936
 
        #stats.strip_dirs()
937
 
        stats.sort_stats('time')
938
 
        stats.print_stats(20)
939
 
    else:
940
 
        return cmd_handler(**cmdargs) or 0
 
787
    cmdargs.update(opts)
 
788
 
 
789
    ret = cmd_handler(**cmdargs) or 0
941
790
 
942
791
 
943
792