~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/commands.py

  • Committer: Martin Pool
  • Date: 2005-07-07 10:31:36 UTC
  • Revision ID: mbp@sourcefrog.net-20050707103135-9b4d911d8df6e880
- fix pwk help

Show diffs side-by-side

added added

removed removed

Lines of Context:
19
19
import sys, os
20
20
 
21
21
import bzrlib
22
 
from bzrlib.trace import mutter, note, log_error, warning
 
22
from bzrlib.trace import mutter, note, log_error
23
23
from bzrlib.errors import BzrError, BzrCheckError, BzrCommandError
24
24
from bzrlib.branch import find_branch
25
25
from bzrlib import BZRDIR
51
51
    assert cmd.startswith("cmd_")
52
52
    return cmd[4:].replace('_','-')
53
53
 
54
 
 
55
54
def _parse_revision_str(revstr):
56
 
    """This handles a revision string -> revno.
57
 
 
58
 
    This always returns a list.  The list will have one element for 
59
 
 
60
 
    It supports integers directly, but everything else it
61
 
    defers for passing to Branch.get_revision_info()
62
 
 
63
 
    >>> _parse_revision_str('234')
64
 
    [234]
65
 
    >>> _parse_revision_str('234..567')
66
 
    [234, 567]
67
 
    >>> _parse_revision_str('..')
68
 
    [None, None]
69
 
    >>> _parse_revision_str('..234')
70
 
    [None, 234]
71
 
    >>> _parse_revision_str('234..')
72
 
    [234, None]
73
 
    >>> _parse_revision_str('234..456..789') # Maybe this should be an error
74
 
    [234, 456, 789]
75
 
    >>> _parse_revision_str('234....789') # Error?
76
 
    [234, None, 789]
77
 
    >>> _parse_revision_str('revid:test@other.com-234234')
78
 
    ['revid:test@other.com-234234']
79
 
    >>> _parse_revision_str('revid:test@other.com-234234..revid:test@other.com-234235')
80
 
    ['revid:test@other.com-234234', 'revid:test@other.com-234235']
81
 
    >>> _parse_revision_str('revid:test@other.com-234234..23')
82
 
    ['revid:test@other.com-234234', 23]
83
 
    >>> _parse_revision_str('date:2005-04-12')
84
 
    ['date:2005-04-12']
85
 
    >>> _parse_revision_str('date:2005-04-12 12:24:33')
86
 
    ['date:2005-04-12 12:24:33']
87
 
    >>> _parse_revision_str('date:2005-04-12T12:24:33')
88
 
    ['date:2005-04-12T12:24:33']
89
 
    >>> _parse_revision_str('date:2005-04-12,12:24:33')
90
 
    ['date:2005-04-12,12:24:33']
91
 
    >>> _parse_revision_str('-5..23')
92
 
    [-5, 23]
93
 
    >>> _parse_revision_str('-5')
94
 
    [-5]
95
 
    >>> _parse_revision_str('123a')
96
 
    ['123a']
97
 
    >>> _parse_revision_str('abc')
98
 
    ['abc']
 
55
    """This handles a revision string -> revno. 
 
56
 
 
57
    There are several possibilities:
 
58
 
 
59
        '234'       -> 234
 
60
        '234:345'   -> [234, 345]
 
61
        ':234'      -> [None, 234]
 
62
        '234:'      -> [234, None]
 
63
 
 
64
    In the future we will also support:
 
65
        'uuid:blah-blah-blah'   -> ?
 
66
        'hash:blahblahblah'     -> ?
 
67
        potentially:
 
68
        'tag:mytag'             -> ?
99
69
    """
100
 
    import re
101
 
    old_format_re = re.compile('\d*:\d*')
102
 
    m = old_format_re.match(revstr)
103
 
    if m:
104
 
        warning('Colon separator for revision numbers is deprecated.'
105
 
                ' Use .. instead')
106
 
        revs = []
107
 
        for rev in revstr.split(':'):
108
 
            if rev:
109
 
                revs.append(int(rev))
110
 
            else:
111
 
                revs.append(None)
112
 
        return revs
113
 
    revs = []
114
 
    for x in revstr.split('..'):
115
 
        if not x:
116
 
            revs.append(None)
117
 
        else:
118
 
            try:
119
 
                revs.append(int(x))
120
 
            except ValueError:
121
 
                revs.append(x)
 
70
    if revstr.find(':') != -1:
 
71
        revs = revstr.split(':')
 
72
        if len(revs) > 2:
 
73
            raise ValueError('More than 2 pieces not supported for --revision: %r' % revstr)
 
74
 
 
75
        if not revs[0]:
 
76
            revs[0] = None
 
77
        else:
 
78
            revs[0] = int(revs[0])
 
79
 
 
80
        if not revs[1]:
 
81
            revs[1] = None
 
82
        else:
 
83
            revs[1] = int(revs[1])
 
84
    else:
 
85
        revs = int(revstr)
122
86
    return revs
123
87
 
124
88
 
332
296
    directory is shown.  Otherwise, only the status of the specified
333
297
    files or directories is reported.  If a directory is given, status
334
298
    is reported for everything inside that directory.
335
 
 
336
 
    If a revision is specified, the changes since that revision are shown.
337
299
    """
338
300
    takes_args = ['file*']
339
 
    takes_options = ['all', 'show-ids', 'revision']
 
301
    takes_options = ['all', 'show-ids']
340
302
    aliases = ['st', 'stat']
341
303
    
342
304
    def run(self, all=False, show_ids=False, file_list=None):
349
311
                file_list = None
350
312
        else:
351
313
            b = find_branch('.')
352
 
            
353
 
        from bzrlib.status import show_status
354
 
        show_status(b, show_unchanged=all, show_ids=show_ids,
355
 
                    specific_files=file_list)
 
314
        import status
 
315
        status.show_status(b, show_unchanged=all, show_ids=show_ids,
 
316
                           specific_files=file_list)
356
317
 
357
318
 
358
319
class cmd_cat_revision(Command):
373
334
    def run(self):
374
335
        print find_branch('.').revno()
375
336
 
376
 
class cmd_revision_info(Command):
377
 
    """Show revision number and revision id for a given revision identifier.
378
 
    """
379
 
    hidden = True
380
 
    takes_args = ['revision_info*']
381
 
    takes_options = ['revision']
382
 
    def run(self, revision=None, revision_info_list=None):
383
 
        from bzrlib.branch import find_branch
384
 
 
385
 
        revs = []
386
 
        if revision is not None:
387
 
            revs.extend(revision)
388
 
        if revision_info_list is not None:
389
 
            revs.extend(revision_info_list)
390
 
        if len(revs) == 0:
391
 
            raise BzrCommandError('You must supply a revision identifier')
392
 
 
393
 
        b = find_branch('.')
394
 
 
395
 
        for rev in revs:
396
 
            print '%4d %s' % b.get_revision_info(rev)
397
 
 
398
337
    
399
338
class cmd_add(Command):
400
339
    """Add specified files or directories.
462
401
        if revision == None:
463
402
            inv = b.read_working_inventory()
464
403
        else:
465
 
            if len(revision) > 1:
466
 
                raise BzrCommandError('bzr inventory --revision takes'
467
 
                    ' exactly one revision identifier')
468
 
            inv = b.get_revision_inventory(b.lookup_revision(revision[0]))
 
404
            inv = b.get_revision_inventory(b.lookup_revision(revision))
469
405
 
470
406
        for path, entry in inv.entries():
471
407
            if show_ids:
593
529
        from meta_store import CachedStore
594
530
        import tempfile
595
531
        cache_root = tempfile.mkdtemp()
596
 
 
597
 
        if revision is None:
598
 
            revision = [None]
599
 
        elif len(revision) > 1:
600
 
            raise BzrCommandError('bzr branch --revision takes exactly 1 revision value')
601
 
 
602
532
        try:
603
533
            try:
604
534
                br_from = find_cached_branch(from_location, cache_root)
625
555
                    raise
626
556
            br_to = Branch(to_location, init=True)
627
557
 
628
 
            br_to.set_root_id(br_from.get_root_id())
629
 
 
630
 
            if revision:
631
 
                if revision[0] is None:
632
 
                    revno = br_from.revno()
633
 
                else:
634
 
                    revno, rev_id = br_from.get_revision_info(revision[0])
635
 
                try:
636
 
                    br_to.update_revisions(br_from, stop_revision=revno)
637
 
                except NoSuchRevision:
638
 
                    rmtree(to_location)
639
 
                    msg = "The branch %s has no revision %d." % (from_location,
640
 
                                                                 revno)
641
 
                    raise BzrCommandError(msg)
642
 
            
 
558
            try:
 
559
                br_to.update_revisions(br_from, stop_revision=revision)
 
560
            except NoSuchRevision:
 
561
                rmtree(to_location)
 
562
                msg = "The branch %s has no revision %d." % (from_location,
 
563
                                                             revision)
 
564
                raise BzrCommandError(msg)
643
565
            merge((to_location, -1), (to_location, 0), this_dir=to_location,
644
566
                  check_clean=False, ignore_zero=True)
645
567
            from_location = pull_loc(br_from)
813
735
                file_list = None
814
736
        else:
815
737
            b = find_branch('.')
816
 
 
817
 
        # TODO: Make show_diff support taking 2 arguments
818
 
        base_rev = None
819
 
        if revision is not None:
820
 
            if len(revision) != 1:
821
 
                raise BzrCommandError('bzr diff --revision takes exactly one revision identifier')
822
 
            base_rev = revision[0]
823
738
    
824
 
        show_diff(b, base_rev, specific_files=file_list,
 
739
        show_diff(b, revision, specific_files=file_list,
825
740
                  external_diff_options=diff_options)
826
741
 
827
742
 
855
770
    """List files modified in working tree."""
856
771
    hidden = True
857
772
    def run(self):
858
 
        from bzrlib.diff import compare_trees
859
 
 
 
773
        from bzrlib.statcache import update_cache, SC_SHA1
860
774
        b = find_branch('.')
861
 
        td = compare_trees(b.basis_tree(), b.working_tree())
 
775
        inv = b.read_working_inventory()
 
776
        sc = update_cache(b, inv)
 
777
        basis = b.basis_tree()
 
778
        basis_inv = basis.inventory
 
779
        
 
780
        # We used to do this through iter_entries(), but that's slow
 
781
        # when most of the files are unmodified, as is usually the
 
782
        # case.  So instead we iterate by inventory entry, and only
 
783
        # calculate paths as necessary.
862
784
 
863
 
        for path, id, kind in td.modified:
864
 
            print path
 
785
        for file_id in basis_inv:
 
786
            cacheentry = sc.get(file_id)
 
787
            if not cacheentry:                 # deleted
 
788
                continue
 
789
            ie = basis_inv[file_id]
 
790
            if cacheentry[SC_SHA1] != ie.text_sha1:
 
791
                path = inv.id2path(file_id)
 
792
                print path
865
793
 
866
794
 
867
795
 
902
830
    -r revision requests a specific revision, -r :end or -r begin: are
903
831
    also valid.
904
832
 
905
 
    --message allows you to give a regular expression, which will be evaluated
906
 
    so that only matching entries will be displayed.
907
 
 
908
833
    TODO: Make --revision support uuid: and hash: [future tag:] notation.
909
834
  
910
835
    """
911
836
 
912
837
    takes_args = ['filename?']
913
 
    takes_options = ['forward', 'timezone', 'verbose', 'show-ids', 'revision','long', 'message']
 
838
    takes_options = ['forward', 'timezone', 'verbose', 'show-ids', 'revision','long']
914
839
    
915
840
    def run(self, filename=None, timezone='original',
916
841
            verbose=False,
917
842
            show_ids=False,
918
843
            forward=False,
919
844
            revision=None,
920
 
            message=None,
921
845
            long=False):
922
846
        from bzrlib.branch import find_branch
923
847
        from bzrlib.log import log_formatter, show_log
936
860
            b = find_branch('.')
937
861
            file_id = None
938
862
 
939
 
        if revision is None:
940
 
            rev1 = None
941
 
            rev2 = None
942
 
        elif len(revision) == 1:
943
 
            rev1 = rev2 = b.get_revision_info(revision[0])[0]
944
 
        elif len(revision) == 2:
945
 
            rev1 = b.get_revision_info(revision[0])[0]
946
 
            rev2 = b.get_revision_info(revision[1])[0]
 
863
        if revision == None:
 
864
            revision = [None, None]
 
865
        elif isinstance(revision, int):
 
866
            revision = [revision, revision]
947
867
        else:
948
 
            raise BzrCommandError('bzr log --revision takes one or two values.')
949
 
 
950
 
        if rev1 == 0:
951
 
            rev1 = None
952
 
        if rev2 == 0:
953
 
            rev2 = None
 
868
            # pair of revisions?
 
869
            pass
 
870
            
 
871
        assert len(revision) == 2
954
872
 
955
873
        mutter('encoding log as %r' % bzrlib.user_encoding)
956
874
 
972
890
                 file_id,
973
891
                 verbose=verbose,
974
892
                 direction=direction,
975
 
                 start_revision=rev1,
976
 
                 end_revision=rev2,
977
 
                 search=message)
 
893
                 start_revision=revision[0],
 
894
                 end_revision=revision[1])
978
895
 
979
896
 
980
897
 
1125
1042
    If no revision is specified this exports the last committed revision.
1126
1043
 
1127
1044
    Format may be an "exporter" name, such as tar, tgz, tbz2.  If none is
1128
 
    given, try to find the format with the extension. If no extension
1129
 
    is found exports to a directory (equivalent to --format=dir).
 
1045
    given, exports to a directory (equivalent to --format=dir).
1130
1046
 
1131
 
    Root may be the top directory for tar, tgz and tbz2 formats. If none
1132
 
    is given, the top directory will be the root name of the file."""
 
1047
    Root may be the top directory for tar, tgz and tbz2 formats."""
1133
1048
    # TODO: list known exporters
1134
1049
    takes_args = ['dest']
1135
1050
    takes_options = ['revision', 'format', 'root']
1136
 
    def run(self, dest, revision=None, format=None, root=None):
1137
 
        import os.path
 
1051
    def run(self, dest, revision=None, format='dir', root=None):
1138
1052
        b = find_branch('.')
1139
 
        if revision is None:
1140
 
            rev_id = b.last_patch()
 
1053
        if revision == None:
 
1054
            rh = b.revision_history()[-1]
1141
1055
        else:
1142
 
            if len(revision) != 1:
1143
 
                raise BzrError('bzr export --revision takes exactly 1 argument')
1144
 
            revno, rev_id = b.get_revision_info(revision[0])
1145
 
        t = b.revision_tree(rev_id)
1146
 
        root, ext = os.path.splitext(dest)
1147
 
        if not format:
1148
 
            if ext in (".tar",):
1149
 
                format = "tar"
1150
 
            elif ext in (".gz", ".tgz"):
1151
 
                format = "tgz"
1152
 
            elif ext in (".bz2", ".tbz2"):
1153
 
                format = "tbz2"
1154
 
            else:
1155
 
                format = "dir"
 
1056
            rh = b.lookup_revision(int(revision))
 
1057
        t = b.revision_tree(rh)
1156
1058
        t.export(dest, format, root)
1157
1059
 
1158
1060
 
1165
1067
    def run(self, filename, revision=None):
1166
1068
        if revision == None:
1167
1069
            raise BzrCommandError("bzr cat requires a revision number")
1168
 
        elif len(revision) != 1:
1169
 
            raise BzrCommandError("bzr cat --revision takes exactly one number")
1170
1070
        b = find_branch('.')
1171
 
        b.print_file(b.relpath(filename), revision[0])
 
1071
        b.print_file(b.relpath(filename), int(revision))
1172
1072
 
1173
1073
 
1174
1074
class cmd_local_time_offset(Command):
1195
1095
    TODO: Strict commit that fails if there are unknown or deleted files.
1196
1096
    """
1197
1097
    takes_args = ['selected*']
1198
 
    takes_options = ['message', 'file', 'verbose', 'unchanged']
 
1098
    takes_options = ['message', 'file', 'verbose']
1199
1099
    aliases = ['ci', 'checkin']
1200
1100
 
1201
 
    def run(self, message=None, file=None, verbose=True, selected_list=None,
1202
 
            unchanged=False):
1203
 
        from bzrlib.errors import PointlessCommit
 
1101
    def run(self, message=None, file=None, verbose=True, selected_list=None):
 
1102
        from bzrlib.commit import commit
1204
1103
        from bzrlib.osutils import get_text_message
1205
1104
 
1206
1105
        ## Warning: shadows builtin file()
1225
1124
            message = codecs.open(file, 'rt', bzrlib.user_encoding).read()
1226
1125
 
1227
1126
        b = find_branch('.')
1228
 
 
1229
 
        try:
1230
 
            b.commit(message, verbose=verbose,
1231
 
                     specific_files=selected_list,
1232
 
                     allow_pointless=unchanged)
1233
 
        except PointlessCommit:
1234
 
            # FIXME: This should really happen before the file is read in;
1235
 
            # perhaps prepare the commit; get the message; then actually commit
1236
 
            raise BzrCommandError("no changes to commit",
1237
 
                                  ["use --unchanged to commit anyhow"])
 
1127
        commit(b, message, verbose=verbose, specific_files=selected_list)
1238
1128
 
1239
1129
 
1240
1130
class cmd_check(Command):
1254
1144
 
1255
1145
 
1256
1146
 
1257
 
class cmd_scan_cache(Command):
1258
 
    hidden = True
1259
 
    def run(self):
1260
 
        from bzrlib.hashcache import HashCache
1261
 
        import os
1262
 
 
1263
 
        c = HashCache('.')
1264
 
        c.read()
1265
 
        c.scan()
1266
 
            
1267
 
        print '%6d stats' % c.stat_count
1268
 
        print '%6d in hashcache' % len(c._cache)
1269
 
        print '%6d files removed from cache' % c.removed_count
1270
 
        print '%6d hashes updated' % c.update_count
1271
 
        print '%6d files changed too recently to cache' % c.danger_count
1272
 
 
1273
 
        if c.needs_write:
1274
 
            c.write()
1275
 
            
1276
 
 
1277
 
 
1278
1147
class cmd_upgrade(Command):
1279
1148
    """Upgrade branch storage to current format.
1280
1149
 
1303
1172
class cmd_selftest(Command):
1304
1173
    """Run internal test suite"""
1305
1174
    hidden = True
1306
 
    takes_options = ['verbose']
1307
 
    def run(self, verbose=False):
 
1175
    def run(self):
1308
1176
        from bzrlib.selftest import selftest
1309
 
        return int(not selftest(verbose=verbose))
 
1177
        return int(not selftest())
1310
1178
 
1311
1179
 
1312
1180
class cmd_version(Command):
1344
1212
    ['..', -1]
1345
1213
    >>> parse_spec("../f/@35")
1346
1214
    ['../f', 35]
1347
 
    >>> parse_spec('./@revid:john@arbash-meinel.com-20050711044610-3ca0327c6a222f67')
1348
 
    ['.', 'revid:john@arbash-meinel.com-20050711044610-3ca0327c6a222f67']
1349
1215
    """
1350
1216
    if spec is None:
1351
1217
        return [None, None]
1355
1221
        if parsed[1] == "":
1356
1222
            parsed[1] = -1
1357
1223
        else:
1358
 
            try:
1359
 
                parsed[1] = int(parsed[1])
1360
 
            except ValueError:
1361
 
                pass # We can allow stuff like ./@revid:blahblahblah
1362
 
            else:
1363
 
                assert parsed[1] >=0
 
1224
            parsed[1] = int(parsed[1])
 
1225
            assert parsed[1] >=0
1364
1226
    else:
1365
1227
        parsed = [spec, None]
1366
1228
    return parsed
1424
1286
    """
1425
1287
    takes_options = ['revision']
1426
1288
 
1427
 
    def run(self, revision=None):
 
1289
    def run(self, revision=-1):
1428
1290
        from bzrlib.merge import merge
1429
 
        if revision is None:
1430
 
            revision = [-1]
1431
 
        elif len(revision) != 1:
1432
 
            raise BzrCommandError('bzr merge-revert --revision takes exactly 1 argument')
1433
 
        merge(('.', revision[0]), parse_spec('.'),
 
1291
        merge(('.', revision), parse_spec('.'),
1434
1292
              check_clean=False,
1435
1293
              ignore_zero=True)
1436
1294
 
1454
1312
        help.help(topic)
1455
1313
 
1456
1314
 
 
1315
class cmd_update_stat_cache(Command):
 
1316
    """Update stat-cache mapping inodes to SHA-1 hashes.
 
1317
 
 
1318
    For testing only."""
 
1319
    hidden = True
 
1320
    def run(self):
 
1321
        from bzrlib.statcache import update_cache
 
1322
        b = find_branch('.')
 
1323
        update_cache(b.base, b.read_working_inventory())
 
1324
 
1457
1325
 
1458
1326
 
1459
1327
class cmd_plugins(Command):
1461
1329
    hidden = True
1462
1330
    def run(self):
1463
1331
        import bzrlib.plugin
1464
 
        from inspect import getdoc
1465
1332
        from pprint import pprint
1466
 
        for plugin in bzrlib.plugin.all_plugins:
1467
 
            print plugin.__path__[0]
1468
 
            d = getdoc(plugin)
1469
 
            if d:
1470
 
                print '\t', d.split('\n')[0]
1471
 
 
1472
 
        #pprint(bzrlib.plugin.all_plugins)
 
1333
        pprint(bzrlib.plugin.all_plugins)
1473
1334
 
1474
1335
 
1475
1336
 
1493
1354
    'verbose':                None,
1494
1355
    'version':                None,
1495
1356
    'email':                  None,
1496
 
    'unchanged':              None,
1497
1357
    'update':                 None,
1498
1358
    'long':                   None,
1499
1359
    'root':                   str,
1526
1386
    >>> parse_args('commit --message=biter'.split())
1527
1387
    (['commit'], {'message': u'biter'})
1528
1388
    >>> parse_args('log -r 500'.split())
1529
 
    (['log'], {'revision': [500]})
1530
 
    >>> parse_args('log -r500..600'.split())
 
1389
    (['log'], {'revision': 500})
 
1390
    >>> parse_args('log -r500:600'.split())
1531
1391
    (['log'], {'revision': [500, 600]})
1532
 
    >>> parse_args('log -vr500..600'.split())
 
1392
    >>> parse_args('log -vr500:600'.split())
1533
1393
    (['log'], {'verbose': True, 'revision': [500, 600]})
1534
 
    >>> parse_args('log -rv500..600'.split()) #the r takes an argument
1535
 
    (['log'], {'revision': ['v500', 600]})
 
1394
    >>> parse_args('log -rv500:600'.split()) #the r takes an argument
 
1395
    Traceback (most recent call last):
 
1396
    ...
 
1397
    ValueError: invalid literal for int(): v500
1536
1398
    """
1537
1399
    args = []
1538
1400
    opts = {}