~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/builtins.py

  • Committer: Robert Collins
  • Date: 2005-10-17 21:57:32 UTC
  • mto: This revision was merged to the branch mainline in revision 1462.
  • Revision ID: robertc@robertcollins.net-20051017215732-08f487800e726748
Allow creation of testaments from uncommitted data, and use that to get signatures before committing revisions.

Show diffs side-by-side

added added

removed removed

Lines of Context:
19
19
import os
20
20
 
21
21
import bzrlib
 
22
from bzrlib import BZRDIR
 
23
from bzrlib.commands import Command
 
24
from bzrlib.branch import Branch
 
25
from bzrlib.errors import BzrError, BzrCheckError, BzrCommandError, NotBranchError
 
26
from bzrlib.errors import DivergedBranches
 
27
from bzrlib.option import Option
 
28
from bzrlib.revisionspec import RevisionSpec
22
29
import bzrlib.trace
23
30
from bzrlib.trace import mutter, note, log_error, warning
24
 
from bzrlib.errors import BzrError, BzrCheckError, BzrCommandError, NotBranchError
25
 
from bzrlib.errors import DivergedBranches
26
 
from bzrlib.branch import Branch
27
 
from bzrlib import BZRDIR
28
 
from bzrlib.commands import Command
 
31
from bzrlib.workingtree import WorkingTree
29
32
 
30
33
 
31
34
class cmd_status(Command):
77
80
    def run(self, all=False, show_ids=False, file_list=None, revision=None):
78
81
        if file_list:
79
82
            b = Branch.open_containing(file_list[0])
80
 
            file_list = [b.relpath(x) for x in file_list]
 
83
            tree = WorkingTree(b.base, b)
 
84
            file_list = [tree.relpath(x) for x in file_list]
81
85
            # special case: only one path was given and it's the root
82
86
            # of the branch
83
87
            if file_list == ['']:
102
106
    takes_options = ['revision']
103
107
    
104
108
    def run(self, revision_id=None, revision=None):
105
 
        from bzrlib.revisionspec import RevisionSpec
106
109
 
107
110
        if revision_id is not None and revision is not None:
108
111
            raise BzrCommandError('You can only supply one of revision_id or --revision')
134
137
    takes_args = ['revision_info*']
135
138
    takes_options = ['revision']
136
139
    def run(self, revision=None, revision_info_list=[]):
137
 
        from bzrlib.revisionspec import RevisionSpec
138
140
 
139
141
        revs = []
140
142
        if revision is not None:
214
216
    hidden = True
215
217
    
216
218
    def run(self, filename):
217
 
        print Branch.open_containing(filename).relpath(filename)
218
 
 
 
219
        branch = Branch.open_containing(filename)
 
220
        print WorkingTree(branch.base, branch).relpath(filename)
219
221
 
220
222
 
221
223
class cmd_inventory(Command):
252
254
        b = Branch.open_containing('.')
253
255
 
254
256
        # TODO: glob expansion on windows?
255
 
        b.move([b.relpath(s) for s in source_list], b.relpath(dest))
 
257
        tree = WorkingTree(b.base, b)
 
258
        b.move([tree.relpath(s) for s in source_list], tree.relpath(dest))
256
259
 
257
260
 
258
261
class cmd_rename(Command):
273
276
    
274
277
    def run(self, from_name, to_name):
275
278
        b = Branch.open_containing('.')
276
 
        b.rename_one(b.relpath(from_name), b.relpath(to_name))
277
 
 
 
279
        tree = WorkingTree(b.base, b)
 
280
        b.rename_one(tree.relpath(from_name), tree.relpath(to_name))
278
281
 
279
282
 
280
283
class cmd_mv(Command):
295
298
        if len(names_list) < 2:
296
299
            raise BzrCommandError("missing file argument")
297
300
        b = Branch.open_containing(names_list[0])
298
 
 
299
 
        rel_names = [b.relpath(x) for x in names_list]
 
301
        tree = WorkingTree(b.base, b)
 
302
        rel_names = [tree.relpath(x) for x in names_list]
300
303
        
301
304
        if os.path.isdir(names_list[-1]):
302
305
            # move into existing directory
481
484
    
482
485
    def run(self, file_list, verbose=False):
483
486
        b = Branch.open_containing(file_list[0])
484
 
        b.remove([b.relpath(f) for f in file_list], verbose=verbose)
 
487
        tree = WorkingTree(b.base, b)
 
488
        b.remove([tree.relpath(f) for f in file_list], verbose=verbose)
485
489
 
486
490
 
487
491
class cmd_file_id(Command):
495
499
    takes_args = ['filename']
496
500
    def run(self, filename):
497
501
        b = Branch.open_containing(filename)
498
 
        i = b.inventory.path2id(b.relpath(filename))
 
502
        tree = WorkingTree(b.base, b)
 
503
        i = b.inventory.path2id(tree.relpath(filename))
499
504
        if i == None:
500
505
            raise BzrError("%r is not a versioned file" % filename)
501
506
        else:
512
517
    def run(self, filename):
513
518
        b = Branch.open_containing(filename)
514
519
        inv = b.inventory
515
 
        fid = inv.path2id(b.relpath(filename))
 
520
        tree = WorkingTree(b.base, b)
 
521
        fid = inv.path2id(tree.relpath(filename))
516
522
        if fid == None:
517
523
            raise BzrError("%r is not a versioned file" % filename)
518
524
        for fip in inv.get_idpath(fid):
597
603
 
598
604
        if file_list:
599
605
            b = Branch.open_containing(file_list[0])
600
 
            file_list = [b.relpath(f) for f in file_list]
 
606
            tree = WorkingTree(b.base, b)
 
607
            file_list = [tree.relpath(f) for f in file_list]
601
608
            if file_list == ['']:
602
609
                # just pointing to top-of-tree
603
610
                file_list = None
692
699
    To request a range of logs, you can use the command -r begin:end
693
700
    -r revision requests a specific revision, -r :end or -r begin: are
694
701
    also valid.
695
 
 
696
 
    --message allows you to give a regular expression, which will be evaluated
697
 
    so that only matching entries will be displayed.
698
702
    """
699
703
 
700
704
    # TODO: Make --revision support uuid: and hash: [future tag:] notation.
701
705
 
702
706
    takes_args = ['filename?']
703
 
    takes_options = ['forward', 'timezone', 'verbose', 'show-ids', 'revision',
704
 
                     'long', 'message', 'short',]
 
707
    takes_options = [Option('forward', 
 
708
                            help='show from oldest to newest'),
 
709
                     'timezone', 'verbose', 
 
710
                     'show-ids', 'revision',
 
711
                     Option('line', help='format with one line per revision'),
 
712
                     'long', 
 
713
                     Option('message',
 
714
                            help='show revisions whose message matches this regexp',
 
715
                            type=str),
 
716
                     Option('short', help='use moderately short format'),
 
717
                     ]
705
718
    
706
719
    def run(self, filename=None, timezone='original',
707
720
            verbose=False,
710
723
            revision=None,
711
724
            message=None,
712
725
            long=False,
713
 
            short=False):
 
726
            short=False,
 
727
            line=False):
714
728
        from bzrlib.log import log_formatter, show_log
715
729
        import codecs
716
 
 
 
730
        assert message is None or isinstance(message, basestring), \
 
731
            "invalid message argument %r" % message
717
732
        direction = (forward and 'forward') or 'reverse'
718
733
        
719
734
        if filename:
720
735
            b = Branch.open_containing(filename)
721
 
            fp = b.relpath(filename)
 
736
            tree = WorkingTree(b.base, b)
 
737
            fp = tree.relpath(filename)
722
738
            if fp:
723
739
                file_id = b.read_working_inventory().path2id(fp)
724
740
            else:
749
765
        # in e.g. the default C locale.
750
766
        outf = codecs.getwriter(bzrlib.user_encoding)(sys.stdout, errors='replace')
751
767
 
752
 
        if not short:
753
 
            log_format = 'long'
754
 
        else:
 
768
        log_format = 'long'
 
769
        if short:
755
770
            log_format = 'short'
 
771
        if line:
 
772
            log_format = 'line'
756
773
        lf = log_formatter(log_format,
757
774
                           show_ids=show_ids,
758
775
                           to_file=outf,
778
795
    def run(self, filename):
779
796
        b = Branch.open_containing(filename)
780
797
        inv = b.read_working_inventory()
781
 
        file_id = inv.path2id(b.relpath(filename))
 
798
        tree = WorkingTree(b.base, b)
 
799
        file_id = inv.path2id(tree.relpath(filename))
782
800
        for revno, revision_id, what in bzrlib.log.find_touching_revisions(b, file_id):
783
801
            print "%6d %s" % (revno, what)
784
802
 
960
978
        elif len(revision) != 1:
961
979
            raise BzrCommandError("bzr cat --revision takes exactly one number")
962
980
        b = Branch.open_containing('.')
963
 
        b.print_file(b.relpath(filename), revision[0].in_history(b).revno)
 
981
        tree = WorkingTree(b.base, b)
 
982
        b.print_file(tree.relpath(filename), revision[0].in_history(b).revno)
964
983
 
965
984
 
966
985
class cmd_local_time_offset(Command):
992
1011
    # XXX: verbose currently does nothing
993
1012
 
994
1013
    takes_args = ['selected*']
995
 
    takes_options = ['message', 'file', 'verbose', 'unchanged']
 
1014
    takes_options = ['message', 'verbose', 
 
1015
                     Option('unchanged',
 
1016
                            help='commit even if nothing has changed'),
 
1017
                     Option('file', type=str, 
 
1018
                            argname='msgfile',
 
1019
                            help='file containing commit message'),
 
1020
                     ]
996
1021
    aliases = ['ci', 'checkin']
997
1022
 
998
1023
    def run(self, message=None, file=None, verbose=True, selected_list=None,
1003
1028
        from cStringIO import StringIO
1004
1029
 
1005
1030
        b = Branch.open_containing('.')
 
1031
        tree = WorkingTree(b.base, b)
1006
1032
        if selected_list:
1007
 
            selected_list = [b.relpath(s) for s in selected_list]
1008
 
 
1009
 
            
 
1033
            selected_list = [tree.relpath(s) for s in selected_list]
1010
1034
        if message is None and not file:
1011
1035
            catcher = StringIO()
1012
1036
            show_status(b, specific_files=selected_list,
1047
1071
    detect data corruption or bzr bugs.
1048
1072
    """
1049
1073
    takes_args = ['dir?']
 
1074
    takes_options = ['verbose']
1050
1075
 
1051
 
    def run(self, dir='.'):
 
1076
    def run(self, dir='.', verbose=False):
1052
1077
        from bzrlib.check import check
1053
 
 
1054
 
        check(Branch.open_containing(dir))
 
1078
        check(Branch.open_containing(dir), verbose)
1055
1079
 
1056
1080
 
1057
1081
class cmd_scan_cache(Command):
1097
1121
    def run(self, email=False):
1098
1122
        try:
1099
1123
            b = bzrlib.branch.Branch.open_containing('.')
 
1124
            config = bzrlib.config.BranchConfig(b)
1100
1125
        except NotBranchError:
1101
 
            b = None
 
1126
            config = bzrlib.config.GlobalConfig()
1102
1127
        
1103
1128
        if email:
1104
 
            print bzrlib.config.user_email(b)
 
1129
            print config.user_email()
1105
1130
        else:
1106
 
            print bzrlib.config.username(b)
 
1131
            print config.username()
1107
1132
 
1108
1133
 
1109
1134
class cmd_selftest(Command):
1115
1140
    fail.
1116
1141
    
1117
1142
    If arguments are given, they are regular expressions that say
1118
 
    which tests should run."""
 
1143
    which tests should run.
 
1144
    """
1119
1145
    # TODO: --list should give a list of all available tests
1120
1146
    hidden = True
1121
1147
    takes_args = ['testspecs*']
1122
 
    takes_options = ['verbose']
1123
 
    def run(self, testspecs_list=None, verbose=False):
 
1148
    takes_options = ['verbose', 
 
1149
                     Option('one', help='stop when one test fails'),
 
1150
                    ]
 
1151
 
 
1152
    def run(self, testspecs_list=None, verbose=False, one=False):
1124
1153
        import bzrlib.ui
1125
1154
        from bzrlib.selftest import selftest
1126
1155
        # we don't want progress meters from the tests to go to the
1135
1164
            else:
1136
1165
                pattern = ".*"
1137
1166
            result = selftest(verbose=verbose, 
1138
 
                              pattern=pattern)
 
1167
                              pattern=pattern,
 
1168
                              stop_on_failure=one)
1139
1169
            if result:
1140
1170
                bzrlib.trace.info('tests passed')
1141
1171
            else:
1445
1475
class cmd_annotate(Command):
1446
1476
    """Show the origin of each line in a file.
1447
1477
 
1448
 
    This prints out the given file with an annotation on the 
1449
 
    left side indicating which revision, author and date introduced the 
1450
 
    change.
 
1478
    This prints out the given file with an annotation on the left side
 
1479
    indicating which revision, author and date introduced the change.
 
1480
 
 
1481
    If the origin is the same for a run of consecutive lines, it is 
 
1482
    shown only at the top, unless the --all option is given.
1451
1483
    """
1452
1484
    # TODO: annotate directories; showing when each file was last changed
1453
1485
    # TODO: annotate a previous version of a file
 
1486
    # TODO: if the working copy is modified, show annotations on that 
 
1487
    #       with new uncommitted lines marked
1454
1488
    aliases = ['blame', 'praise']
1455
1489
    takes_args = ['filename']
 
1490
    takes_options = [Option('all', help='show annotations on all lines'),
 
1491
                     Option('long', help='show date in annotations'),
 
1492
                     ]
1456
1493
 
1457
 
    def run(self, filename):
 
1494
    def run(self, filename, all=False, long=False):
1458
1495
        from bzrlib.annotate import annotate_file
1459
1496
        b = Branch.open_containing(filename)
1460
1497
        b.lock_read()
1461
1498
        try:
1462
 
            rp = b.relpath(filename)
 
1499
            tree = WorkingTree(b.base, b)
 
1500
            rp = tree.relpath(filename)
1463
1501
            tree = b.revision_tree(b.last_revision())
1464
1502
            file_id = tree.inventory.path2id(rp)
1465
1503
            file_version = tree.inventory[file_id].revision
1466
 
            annotate_file(b, file_version, file_id, sys.stdout)
 
1504
            annotate_file(b, file_version, file_id, long, all, sys.stdout)
1467
1505
        finally:
1468
1506
            b.unlock()
1469
1507
 
 
1508
 
 
1509
class cmd_re_sign(Command):
 
1510
    """Create a digital signature for an existing revision."""
 
1511
    # TODO be able to replace existing ones.
 
1512
 
 
1513
    hidden = True # is this right ?
 
1514
    takes_args = ['revision_id?']
 
1515
    takes_options = ['revision']
 
1516
    
 
1517
    def run(self, revision_id=None, revision=None):
 
1518
        import bzrlib.config as config
 
1519
        import bzrlib.gpg as gpg
 
1520
        if revision_id is not None and revision is not None:
 
1521
            raise BzrCommandError('You can only supply one of revision_id or --revision')
 
1522
        if revision_id is None and revision is None:
 
1523
            raise BzrCommandError('You must supply either --revision or a revision_id')
 
1524
        b = Branch.open_containing('.')
 
1525
        gpg_strategy = gpg.GPGStrategy(config.BranchConfig(b))
 
1526
        if revision_id is not None:
 
1527
            b.sign_revision(revision_id, gpg_strategy)
 
1528
        elif revision is not None:
 
1529
            for rev in revision:
 
1530
                if rev is None:
 
1531
                    raise BzrCommandError('You cannot specify a NULL revision.')
 
1532
                revno, rev_id = rev.in_history(b)
 
1533
                b.sign_revision(rev_id, gpg_strategy)
 
1534
 
 
1535
 
1470
1536
# these get imported and then picked up by the scan for cmd_*
1471
1537
# TODO: Some more consistent way to split command definitions across files;
1472
1538
# we do need to load at least some information about them to know of