~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-01 04:38:28 UTC
  • Revision ID: mbp@sourcefrog.net-20050401043828-4162a7fb07e43579
fix test case breakage

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#! /usr/bin/python
2
 
 
3
 
 
4
1
# Copyright (C) 2004, 2005 by Martin Pool
5
2
# Copyright (C) 2005 by Canonical Ltd
6
3
 
28
25
* Metadata format is not stable yet -- you may need to
29
26
  discard history in the future.
30
27
 
31
 
* No handling of subdirectories, symlinks or any non-text files.
32
 
 
33
28
* Insufficient error handling.
34
29
 
35
30
* Many commands unimplemented or partially implemented.
40
35
 
41
36
Interesting commands::
42
37
 
43
 
  bzr help
44
 
       Show summary help screen
 
38
  bzr help [COMMAND]
 
39
       Show help screen
45
40
  bzr version
46
41
       Show software version/licence/non-warranty.
47
42
  bzr init
60
55
       Show summary of pending changes.
61
56
  bzr remove FILE...
62
57
       Make a file not versioned.
 
58
  bzr info
 
59
       Show statistics about this branch.
63
60
"""
64
61
 
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'
 
62
 
75
63
 
76
64
 
77
65
import sys, os, random, time, sha, sets, types, re, shutil, tempfile
118
106
## can be taken either from their parameters or their working
119
107
## directory.
120
108
 
 
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
 
112
 
 
113
## TODO: move command; check destination is a directory and will not
 
114
## clash; move it.
 
115
 
 
116
## TODO: command to show renames, one per line, as to->from
 
117
 
 
118
 
121
119
 
122
120
 
123
121
def cmd_status(all=False):
155
153
    print Branch('.').revno()
156
154
    
157
155
 
 
156
    
158
157
def cmd_add(file_list, verbose=False):
159
 
    """Add specified files.
 
158
    """Add specified files or directories.
 
159
 
 
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.
 
163
 
 
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
 
170
    directories.
 
171
 
 
172
    Therefore simply saying 'bzr add .' will version all files that
 
173
    are currently unknown.
 
174
    """
 
175
    bzrlib.add.smart_add(file_list, verbose)
160
176
    
161
 
    Fails if the files are already added.
162
 
    """
163
 
    Branch('.').add(file_list, verbose=verbose)
 
177
 
 
178
def cmd_relpath(filename):
 
179
    """Show path of file relative to root"""
 
180
    print Branch(filename).relpath(filename)
164
181
 
165
182
 
166
183
def cmd_inventory(revision=None):
179
196
 
180
197
 
181
198
def cmd_info():
182
 
    b = Branch('.')
183
 
    print 'branch format:', b.controlfile('branch-format', 'r').readline().rstrip('\n')
184
 
 
185
 
    def plural(n, base='', pl=None):
186
 
        if n == 1:
187
 
            return base
188
 
        elif pl is not None:
189
 
            return pl
190
 
        else:
191
 
            return 's'
192
 
 
193
 
    count_version_dirs = 0
194
 
 
195
 
    count_status = {'A': 0, 'D': 0, 'M': 0, 'R': 0, '?': 0, 'I': 0, '.': 0}
196
 
    for st_tup in bzrlib.diff_trees(b.basis_tree(), b.working_tree()):
197
 
        fs = st_tup[0]
198
 
        count_status[fs] += 1
199
 
        if fs not in ['I', '?'] and st_tup[4] == 'directory':
200
 
            count_version_dirs += 1
201
 
 
202
 
    print
203
 
    print 'in the working tree:'
204
 
    for name, fs in (('unchanged', '.'),
205
 
                     ('modified', 'M'), ('added', 'A'), ('removed', 'D'),
206
 
                     ('renamed', 'R'), ('unknown', '?'), ('ignored', 'I'),
207
 
                     ):
208
 
        print '  %5d %s' % (count_status[fs], name)
209
 
    print '  %5d versioned subdirector%s' % (count_version_dirs,
210
 
                                             plural(count_version_dirs, 'y', 'ies'))
211
 
 
212
 
    print
213
 
    print 'branch history:'
214
 
    history = b.revision_history()
215
 
    revno = len(history)
216
 
    print '  %5d revision%s' % (revno, plural(revno))
217
 
    committers = Set()
218
 
    for rev in history:
219
 
        committers.add(b.get_revision(rev).committer)
220
 
    print '  %5d committer%s' % (len(committers), plural(len(committers)))
221
 
    if revno > 0:
222
 
        firstrev = b.get_revision(history[0])
223
 
        age = int((time.time() - firstrev.timestamp) / 3600 / 24)
224
 
        print '  %5d day%s old' % (age, plural(age))
225
 
        print '  first revision: %s' % format_date(firstrev.timestamp,
226
 
                                                 firstrev.timezone)
227
 
 
228
 
        lastrev = b.get_revision(history[-1])
229
 
        print '  latest revision: %s' % format_date(lastrev.timestamp,
230
 
                                                    lastrev.timezone)
231
 
        
 
199
    """info: Show statistical information for this branch
 
200
 
 
201
usage: bzr info"""
 
202
    import info
 
203
    info.show_info(Branch('.'))        
232
204
    
233
205
 
234
206
 
235
207
def cmd_remove(file_list, verbose=False):
236
 
    Branch('.').remove(file_list, verbose=verbose)
 
208
    b = Branch(file_list[0])
 
209
    b.remove([b.relpath(f) for f in file_list], verbose=verbose)
237
210
 
238
211
 
239
212
 
240
213
def cmd_file_id(filename):
241
 
    i = Branch('.').read_working_inventory().path2id(filename)
 
214
    b = Branch(filename)
 
215
    i = b.inventory.path2id(b.relpath(filename))
242
216
    if i is None:
243
217
        bailout("%s is not a versioned file" % filename)
244
218
    else:
258
232
        print patchid
259
233
 
260
234
 
 
235
def cmd_directories():
 
236
    for name, ie in Branch('.').read_working_inventory().directories():
 
237
        if name == '':
 
238
            print '.'
 
239
        else:
 
240
            print name
 
241
 
 
242
 
 
243
def cmd_missing():
 
244
    for name, ie in Branch('.').working_tree().missing():
 
245
        print name
 
246
 
261
247
 
262
248
def cmd_init():
263
249
    # TODO: Check we're not already in a working directory?  At the
273
259
 
274
260
 
275
261
def cmd_diff(revision=None):
276
 
    """Show diff from basis to working copy.
277
 
 
278
 
    :todo: Take one or two revision arguments, look up those trees,
279
 
           and diff them.
280
 
 
281
 
    :todo: Allow diff across branches.
282
 
 
283
 
    :todo: Mangle filenames in diff to be more relevant.
284
 
 
285
 
    :todo: Shouldn't be in the cmd function.
286
 
    """
 
262
    """bzr diff: Show differences in working tree.
 
263
    
 
264
usage: bzr diff [-r REV]
 
265
 
 
266
--revision REV
 
267
    Show changes since REV, rather than predecessor.
 
268
 
 
269
TODO: Given two revision arguments, show the difference between them.
 
270
 
 
271
TODO: Allow diff across branches.
 
272
 
 
273
TODO: Option to use external diff command; could be GNU diff, wdiff,
 
274
or a graphical diff.
 
275
 
 
276
TODO: Diff selected files.
 
277
"""
 
278
 
 
279
    ## TODO: Shouldn't be in the cmd function.
287
280
 
288
281
    b = Branch('.')
289
282
 
358
351
 
359
352
 
360
353
 
 
354
def cmd_deleted(show_ids=False):
 
355
    """List files deleted in the working tree.
 
356
 
 
357
TODO: Show files deleted since a previous revision, or between two revisions.
 
358
    """
 
359
    b = Branch('.')
 
360
    old = b.basis_tree()
 
361
    new = b.working_tree()
 
362
 
 
363
    ## TODO: Much more efficient way to do this: read in new
 
364
    ## directories with readdir, rather than stating each one.  Same
 
365
    ## level of effort but possibly much less IO.  (Or possibly not,
 
366
    ## if the directories are very large...)
 
367
 
 
368
    for path, ie in old.inventory.iter_entries():
 
369
        if not new.has_id(ie.file_id):
 
370
            if show_ids:
 
371
                print '%-50s %s' % (path, ie.file_id)
 
372
            else:
 
373
                print path
 
374
 
 
375
 
 
376
 
 
377
def cmd_parse_inventory():
 
378
    import cElementTree
 
379
    
 
380
    cElementTree.ElementTree().parse(file('.bzr/inventory'))
 
381
 
 
382
 
 
383
 
 
384
def cmd_load_inventory():
 
385
    inv = Branch('.').basis_tree().inventory
 
386
 
 
387
 
 
388
 
 
389
def cmd_dump_new_inventory():
 
390
    import bzrlib.newinventory
 
391
    inv = Branch('.').basis_tree().inventory
 
392
    bzrlib.newinventory.write_inventory(inv, sys.stdout)
 
393
 
 
394
 
 
395
def cmd_load_new_inventory():
 
396
    import bzrlib.newinventory
 
397
    bzrlib.newinventory.read_new_inventory(sys.stdin)
 
398
                
 
399
    
 
400
def cmd_dump_slacker_inventory():
 
401
    import bzrlib.newinventory
 
402
    inv = Branch('.').basis_tree().inventory
 
403
    bzrlib.newinventory.write_slacker_inventory(inv, sys.stdout)
 
404
                
 
405
    
 
406
 
 
407
def cmd_root(filename=None):
 
408
    """Print the branch root."""
 
409
    print bzrlib.branch.find_branch_root(filename)
 
410
    
 
411
 
361
412
def cmd_log(timezone='original'):
362
413
    """Show log of this branch.
363
414
 
398
449
        print quotefn(f)
399
450
 
400
451
 
 
452
 
 
453
def cmd_ignored(verbose=True):
 
454
    """List ignored files and the patterns that matched them.
 
455
      """
 
456
    tree = Branch('.').working_tree()
 
457
    for path, file_class, kind, id in tree.list_files():
 
458
        if file_class != 'I':
 
459
            continue
 
460
        ## XXX: Slightly inefficient since this was already calculated
 
461
        pat = tree.is_ignored(path)
 
462
        print '%-50s %s' % (path, pat)
 
463
 
 
464
 
401
465
def cmd_lookup_revision(revno):
402
466
    try:
403
467
        revno = int(revno)
424
488
 
425
489
def cmd_uuid():
426
490
    """Print a newly-generated UUID."""
427
 
    print uuid()
 
491
    print bzrlib.osutils.uuid()
428
492
 
429
493
 
430
494
 
433
497
 
434
498
 
435
499
 
436
 
def cmd_commit(message, verbose=False):
 
500
def cmd_commit(message=None, verbose=False):
 
501
    """Commit changes to a new revision.
 
502
 
 
503
--message MESSAGE
 
504
    Description of changes in this revision; free form text.
 
505
    It is recommended that the first line be a single-sentence
 
506
    summary.
 
507
--verbose
 
508
    Show status of changed files,
 
509
 
 
510
TODO: Commit only selected files.
 
511
 
 
512
TODO: Run hooks on tree to-be-committed, and after commit.
 
513
 
 
514
TODO: Strict commit that fails if there are unknown or deleted files.
 
515
"""
 
516
 
 
517
    if not message:
 
518
        bailout("please specify a commit message")
437
519
    Branch('.').commit(message, verbose=verbose)
438
520
 
439
521
 
440
 
def cmd_check():
441
 
    """Check consistency of the branch."""
442
 
    check()
 
522
def cmd_check(dir='.'):
 
523
    """check: Consistency check of branch history.
 
524
 
 
525
usage: bzr check [-v] [BRANCH]
 
526
 
 
527
options:
 
528
  --verbose, -v         Show progress of checking.
 
529
 
 
530
This command checks various invariants about the branch storage to
 
531
detect data corruption or bzr bugs.
 
532
"""
 
533
    import bzrlib.check
 
534
    bzrlib.check.check(Branch(dir, find_root=False))
443
535
 
444
536
 
445
537
def cmd_is(pred, *rest):
470
562
    print bzrlib.branch._gen_revision_id(time.time())
471
563
 
472
564
 
473
 
def cmd_doctest():
474
 
    """Run internal doctest suite"""
 
565
def cmd_selftest(verbose=False):
 
566
    """Run internal test suite"""
475
567
    ## -v, if present, is seen by doctest; the argument is just here
476
568
    ## so our parser doesn't complain
477
569
 
478
570
    ## TODO: --verbose option
 
571
 
 
572
    failures, tests = 0, 0
479
573
    
480
 
    import bzr, doctest, bzrlib.store
 
574
    import doctest, bzrlib.store, bzrlib.tests
481
575
    bzrlib.trace.verbose = False
482
 
    doctest.testmod(bzr)
483
 
    doctest.testmod(bzrlib.store)
484
 
    doctest.testmod(bzrlib.inventory)
485
 
    doctest.testmod(bzrlib.branch)
486
 
    doctest.testmod(bzrlib.osutils)
487
 
    doctest.testmod(bzrlib.tree)
488
 
 
489
 
    # more strenuous tests;
490
 
    import bzrlib.tests
491
 
    doctest.testmod(bzrlib.tests)
 
576
 
 
577
    for m in bzrlib.store, bzrlib.inventory, bzrlib.branch, bzrlib.osutils, \
 
578
        bzrlib.tree, bzrlib.tests, bzrlib.commands, bzrlib.add:
 
579
        mf, mt = doctest.testmod(m)
 
580
        failures += mf
 
581
        tests += mt
 
582
        print '%-40s %3d tests' % (m.__name__, mt),
 
583
        if mf:
 
584
            print '%3d FAILED!' % mf
 
585
        else:
 
586
            print
 
587
 
 
588
    print '%-40s %3d tests' % ('total', tests),
 
589
    if failures:
 
590
        print '%3d FAILED!' % failures
 
591
    else:
 
592
        print
 
593
 
 
594
 
 
595
 
 
596
# deprecated
 
597
cmd_doctest = cmd_selftest
492
598
 
493
599
 
494
600
######################################################################
495
601
# help
496
602
 
497
603
 
498
 
def cmd_help():
499
 
    # TODO: Specific help for particular commands
500
 
    print __doc__
 
604
def cmd_help(topic=None):
 
605
    if topic == None:
 
606
        print __doc__
 
607
        return
 
608
 
 
609
    # otherwise, maybe the name of a command?
 
610
    try:
 
611
        cmdfn = globals()['cmd_' + topic.replace('-', '_')]
 
612
    except KeyError:
 
613
        bailout("no help for %r" % topic)
 
614
 
 
615
    doc = cmdfn.__doc__
 
616
    if doc == None:
 
617
        bailout("sorry, no detailed help yet for %r" % topic)
 
618
 
 
619
    print doc
 
620
        
 
621
 
501
622
 
502
623
 
503
624
def cmd_version():
504
 
    print "bzr (bazaar-ng) %s" % __version__
505
 
    print __copyright__
 
625
    print "bzr (bazaar-ng) %s" % bzrlib.__version__
 
626
    print bzrlib.__copyright__
506
627
    print "http://bazaar-ng.org/"
507
628
    print
508
629
    print \
528
649
    'all':                    None,
529
650
    'help':                   None,
530
651
    'message':                unicode,
 
652
    'profile':                None,
531
653
    'revision':               int,
532
654
    'show-ids':               None,
533
655
    'timezone':               str,
546
668
cmd_options = {
547
669
    'add':                    ['verbose'],
548
670
    'commit':                 ['message', 'verbose'],
 
671
    'deleted':                ['show-ids'],
549
672
    'diff':                   ['revision'],
550
673
    'inventory':              ['revision'],
551
 
    'log':                    ['show-ids', 'timezone'],
 
674
    'log':                    ['timezone'],
552
675
    'ls':                     ['revision', 'verbose'],
553
676
    'remove':                 ['verbose'],
554
677
    'status':                 ['all'],
556
679
 
557
680
 
558
681
cmd_args = {
559
 
    'init':                   [],
560
682
    'add':                    ['file+'],
561
683
    'commit':                 [],
562
684
    'diff':                   [],
 
685
    'export':                 ['revno', 'dest'],
563
686
    'file-id':                ['filename'],
564
687
    'get-file-text':          ['text_id'],
565
688
    'get-inventory':          ['inventory_id'],
566
689
    'get-revision':           ['revision_id'],
567
690
    'get-revision-inventory': ['revision_id'],
 
691
    'help':                   ['topic?'],
 
692
    'init':                   [],
568
693
    'log':                    [],
569
694
    'lookup-revision':        ['revno'],
570
 
    'export':                 ['revno', 'dest'],
 
695
    'relpath':                ['filename'],
571
696
    'remove':                 ['file+'],
 
697
    'root':                   ['filename?'],
572
698
    'status':                 [],
573
699
    }
574
700
 
625
751
                    else:
626
752
                        optarg = argv.pop(0)
627
753
                opts[optname] = optargfn(optarg)
628
 
                mutter("    option argument %r" % opts[optname])
629
754
            else:
630
755
                if optarg != None:
631
756
                    bailout('option %r takes no argument' % optname)
655
780
    # TODO: Need a way to express 'cp SRC... DEST', where it matches
656
781
    # all but one.
657
782
 
 
783
    # step through args and argform, allowing appropriate 0-many matches
658
784
    for ap in argform:
659
785
        argname = ap[:-1]
660
786
        if ap[-1] == '?':
661
 
            assert 0
 
787
            if args:
 
788
                argdict[argname] = args.pop(0)
662
789
        elif ap[-1] == '*':
663
790
            assert 0
664
791
        elif ap[-1] == '+':
706
833
        log_error('usage: bzr COMMAND\n')
707
834
        log_error('  try "bzr help"\n')
708
835
        return 1
709
 
            
 
836
 
710
837
    try:
711
838
        cmd_handler = globals()['cmd_' + cmd.replace('-', '_')]
712
839
    except KeyError:
713
840
        bailout("unknown command " + `cmd`)
714
841
 
715
 
    # TODO: special --profile option to turn on the Python profiler
 
842
    # global option
 
843
    if 'profile' in opts:
 
844
        profile = True
 
845
        del opts['profile']
 
846
    else:
 
847
        profile = False
716
848
 
717
849
    # check options are reasonable
718
850
    allowed = cmd_options.get(cmd, [])
721
853
            bailout("option %r is not allowed for command %r"
722
854
                    % (oname, cmd))
723
855
 
 
856
    # mix arguments and options into one dictionary
724
857
    cmdargs = _match_args(cmd, args)
725
 
    cmdargs.update(opts)
726
 
 
727
 
    ret = cmd_handler(**cmdargs) or 0
 
858
    for k, v in opts.items():
 
859
        cmdargs[k.replace('-', '_')] = v
 
860
 
 
861
    if profile:
 
862
        import hotshot
 
863
        prof = hotshot.Profile('.bzr.profile')
 
864
        ret = prof.runcall(cmd_handler, **cmdargs) or 0
 
865
        prof.close()
 
866
 
 
867
        import hotshot.stats
 
868
        stats = hotshot.stats.load('.bzr.profile')
 
869
        #stats.strip_dirs()
 
870
        stats.sort_stats('time')
 
871
        stats.print_stats(20)
 
872
    else:
 
873
        return cmd_handler(**cmdargs) or 0
728
874
 
729
875
 
730
876
 
735
881
    ## TODO: If the arguments are wrong, give a usage message rather
736
882
    ## than just a backtrace.
737
883
 
 
884
    bzrlib.trace.create_tracefile(argv)
 
885
    
738
886
    try:
739
 
        # TODO: Lift into separate function in trace.py
740
 
        # TODO: Also show contents of /etc/lsb-release, if it can be parsed.
741
 
        #       Perhaps that should eventually go into the platform library?
742
 
        # TODO: If the file doesn't exist, add a note describing it.
743
 
        t = bzrlib.trace._tracefile
744
 
        t.write('-' * 60 + '\n')
745
 
        t.write('bzr invoked at %s\n' % format_date(time.time()))
746
 
        t.write('  by %s on %s\n' % (bzrlib.osutils.username(), socket.getfqdn()))
747
 
        t.write('  arguments: %r\n' % argv)
748
 
 
749
 
        starttime = os.times()[4]
750
 
 
751
 
        import platform
752
 
        t.write('  platform: %s\n' % platform.platform())
753
 
        t.write('  python: %s\n' % platform.python_version())
754
 
 
755
887
        ret = run_bzr(argv)
756
 
        
757
 
        times = os.times()
758
 
        mutter("finished, %.3fu/%.3fs cpu, %.3fu/%.3fs cum"
759
 
               % times[:4])
760
 
        mutter("    %.3f elapsed" % (times[4] - starttime))
761
 
 
762
888
        return ret
763
889
    except BzrError, e:
764
890
        log_error('bzr: error: ' + e.args[0] + '\n')