~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/commands.py

  • Committer: Robert Collins
  • Date: 2005-10-17 11:41:07 UTC
  • mfrom: (1442.1.60)
  • Revision ID: robertc@robertcollins.net-20051017114107-f5586285d825c105
Merge in first part of GPG support.

This adds check_signatures config support, triams back the transport api
to be leaner and easier to hook in suffixes - non primary streams in the store
associated with the fileid that primary data is stored in, a gpg module which
will encapsulate all signing and checking operations.

Show diffs side-by-side

added added

removed removed

Lines of Context:
24
24
# Those objects can specify the expected type of the argument, which
25
25
# would help with validation and shell completion.
26
26
 
27
 
 
 
27
# TODO: "--profile=cum", to change sort order.  Is there any value in leaving
 
28
# the profile output behind so it can be interactively examined?
28
29
 
29
30
import sys
30
31
import os
34
35
import bzrlib
35
36
import bzrlib.trace
36
37
from bzrlib.trace import mutter, note, log_error, warning
37
 
from bzrlib.errors import BzrError, BzrCheckError, BzrCommandError
38
 
from bzrlib.branch import find_branch
 
38
from bzrlib.errors import BzrError, BzrCheckError, BzrCommandError, NotBranchError
 
39
from bzrlib.revisionspec import RevisionSpec
39
40
from bzrlib import BZRDIR
40
41
 
41
42
plugin_cmds = {}
69
70
def _parse_revision_str(revstr):
70
71
    """This handles a revision string -> revno.
71
72
 
72
 
    This always returns a list.  The list will have one element for 
73
 
 
74
 
    It supports integers directly, but everything else it
75
 
    defers for passing to Branch.get_revision_info()
 
73
    This always returns a list.  The list will have one element for
 
74
    each revision specifier supplied.
76
75
 
77
76
    >>> _parse_revision_str('234')
78
 
    [234]
 
77
    [<RevisionSpec_int 234>]
79
78
    >>> _parse_revision_str('234..567')
80
 
    [234, 567]
 
79
    [<RevisionSpec_int 234>, <RevisionSpec_int 567>]
81
80
    >>> _parse_revision_str('..')
82
 
    [None, None]
 
81
    [<RevisionSpec None>, <RevisionSpec None>]
83
82
    >>> _parse_revision_str('..234')
84
 
    [None, 234]
 
83
    [<RevisionSpec None>, <RevisionSpec_int 234>]
85
84
    >>> _parse_revision_str('234..')
86
 
    [234, None]
 
85
    [<RevisionSpec_int 234>, <RevisionSpec None>]
87
86
    >>> _parse_revision_str('234..456..789') # Maybe this should be an error
88
 
    [234, 456, 789]
89
 
    >>> _parse_revision_str('234....789') # Error?
90
 
    [234, None, 789]
 
87
    [<RevisionSpec_int 234>, <RevisionSpec_int 456>, <RevisionSpec_int 789>]
 
88
    >>> _parse_revision_str('234....789') #Error ?
 
89
    [<RevisionSpec_int 234>, <RevisionSpec None>, <RevisionSpec_int 789>]
91
90
    >>> _parse_revision_str('revid:test@other.com-234234')
92
 
    ['revid:test@other.com-234234']
 
91
    [<RevisionSpec_revid revid:test@other.com-234234>]
93
92
    >>> _parse_revision_str('revid:test@other.com-234234..revid:test@other.com-234235')
94
 
    ['revid:test@other.com-234234', 'revid:test@other.com-234235']
 
93
    [<RevisionSpec_revid revid:test@other.com-234234>, <RevisionSpec_revid revid:test@other.com-234235>]
95
94
    >>> _parse_revision_str('revid:test@other.com-234234..23')
96
 
    ['revid:test@other.com-234234', 23]
 
95
    [<RevisionSpec_revid revid:test@other.com-234234>, <RevisionSpec_int 23>]
97
96
    >>> _parse_revision_str('date:2005-04-12')
98
 
    ['date:2005-04-12']
 
97
    [<RevisionSpec_date date:2005-04-12>]
99
98
    >>> _parse_revision_str('date:2005-04-12 12:24:33')
100
 
    ['date:2005-04-12 12:24:33']
 
99
    [<RevisionSpec_date date:2005-04-12 12:24:33>]
101
100
    >>> _parse_revision_str('date:2005-04-12T12:24:33')
102
 
    ['date:2005-04-12T12:24:33']
 
101
    [<RevisionSpec_date date:2005-04-12T12:24:33>]
103
102
    >>> _parse_revision_str('date:2005-04-12,12:24:33')
104
 
    ['date:2005-04-12,12:24:33']
 
103
    [<RevisionSpec_date date:2005-04-12,12:24:33>]
105
104
    >>> _parse_revision_str('-5..23')
106
 
    [-5, 23]
 
105
    [<RevisionSpec_int -5>, <RevisionSpec_int 23>]
107
106
    >>> _parse_revision_str('-5')
108
 
    [-5]
 
107
    [<RevisionSpec_int -5>]
109
108
    >>> _parse_revision_str('123a')
110
 
    ['123a']
 
109
    Traceback (most recent call last):
 
110
      ...
 
111
    BzrError: No namespace registered for string: '123a'
111
112
    >>> _parse_revision_str('abc')
112
 
    ['abc']
 
113
    Traceback (most recent call last):
 
114
      ...
 
115
    BzrError: No namespace registered for string: 'abc'
 
116
    >>> _parse_revision_str('branch:../branch2')
 
117
    [<RevisionSpec_branch branch:../branch2>]
113
118
    """
114
119
    import re
115
120
    old_format_re = re.compile('\d*:\d*')
116
121
    m = old_format_re.match(revstr)
 
122
    revs = []
117
123
    if m:
118
124
        warning('Colon separator for revision numbers is deprecated.'
119
125
                ' Use .. instead')
120
 
        revs = []
121
126
        for rev in revstr.split(':'):
122
127
            if rev:
123
 
                revs.append(int(rev))
124
 
            else:
125
 
                revs.append(None)
126
 
        return revs
127
 
    revs = []
128
 
    for x in revstr.split('..'):
129
 
        if not x:
130
 
            revs.append(None)
131
 
        else:
132
 
            try:
133
 
                revs.append(int(x))
134
 
            except ValueError:
135
 
                revs.append(x)
 
128
                revs.append(RevisionSpec(int(rev)))
 
129
            else:
 
130
                revs.append(RevisionSpec(None))
 
131
    else:
 
132
        next_prefix = None
 
133
        for x in revstr.split('..'):
 
134
            if not x:
 
135
                revs.append(RevisionSpec(None))
 
136
            elif x[-1] == ':':
 
137
                # looks like a namespace:.. has happened
 
138
                next_prefix = x + '..'
 
139
            else:
 
140
                if next_prefix is not None:
 
141
                    x = next_prefix + x
 
142
                revs.append(RevisionSpec(x))
 
143
                next_prefix = None
 
144
        if next_prefix is not None:
 
145
            revs.append(RevisionSpec(next_prefix))
136
146
    return revs
137
147
 
138
148
 
139
 
def get_merge_type(typestring):
140
 
    """Attempt to find the merge class/factory associated with a string."""
141
 
    from merge import merge_types
142
 
    try:
143
 
        return merge_types[typestring][0]
144
 
    except KeyError:
145
 
        templ = '%s%%7s: %%s' % (' '*12)
146
 
        lines = [templ % (f[0], f[1][1]) for f in merge_types.iteritems()]
147
 
        type_list = '\n'.join(lines)
148
 
        msg = "No known merge type %s. Supported types are:\n%s" %\
149
 
            (typestring, type_list)
150
 
        raise BzrCommandError(msg)
151
 
    
152
 
 
153
149
def _builtin_commands():
154
150
    import bzrlib.builtins
155
151
    r = {}
342
338
    return parsed
343
339
 
344
340
 
345
 
 
346
 
 
347
341
# list of all available options; the rhs can be either None for an
348
342
# option that takes no argument, or a constructor function that checks
349
343
# the type.
350
344
OPTIONS = {
351
345
    'all':                    None,
 
346
    'basis':                  str,
352
347
    'diff-options':           str,
353
348
    'help':                   None,
354
349
    'file':                   unicode,
355
350
    'force':                  None,
356
351
    'format':                 unicode,
357
352
    'forward':                None,
 
353
    'quiet':                  None,
358
354
    'message':                unicode,
359
355
    'no-recurse':             None,
360
356
    'profile':                None,
370
366
    'long':                   None,
371
367
    'root':                   str,
372
368
    'no-backup':              None,
373
 
    'merge-type':             get_merge_type,
374
369
    'pattern':                str,
 
370
    'remember':               None,
375
371
    }
376
372
 
377
373
SHORT_OPTIONS = {
381
377
    'r':                      'revision',
382
378
    'v':                      'verbose',
383
379
    'l':                      'long',
 
380
    'q':                      'quiet',
384
381
}
385
382
 
386
383
 
403
400
    >>> parse_args('commit --message=biter'.split())
404
401
    (['commit'], {'message': u'biter'})
405
402
    >>> parse_args('log -r 500'.split())
406
 
    (['log'], {'revision': [500]})
 
403
    (['log'], {'revision': [<RevisionSpec_int 500>]})
407
404
    >>> parse_args('log -r500..600'.split())
408
 
    (['log'], {'revision': [500, 600]})
 
405
    (['log'], {'revision': [<RevisionSpec_int 500>, <RevisionSpec_int 600>]})
409
406
    >>> parse_args('log -vr500..600'.split())
410
 
    (['log'], {'verbose': True, 'revision': [500, 600]})
411
 
    >>> parse_args('log -rv500..600'.split()) #the r takes an argument
412
 
    (['log'], {'revision': ['v500', 600]})
 
407
    (['log'], {'verbose': True, 'revision': [<RevisionSpec_int 500>, <RevisionSpec_int 600>]})
 
408
    >>> parse_args('log -rrevno:500..600'.split()) #the r takes an argument
 
409
    (['log'], {'revision': [<RevisionSpec_revno revno:500>, <RevisionSpec_int 600>]})
413
410
    """
414
411
    args = []
415
412
    opts = {}
536
533
def apply_profiled(the_callable, *args, **kwargs):
537
534
    import hotshot
538
535
    import tempfile
 
536
    import hotshot.stats
539
537
    pffileno, pfname = tempfile.mkstemp()
540
538
    try:
541
539
        prof = hotshot.Profile(pfname)
543
541
            ret = prof.runcall(the_callable, *args, **kwargs) or 0
544
542
        finally:
545
543
            prof.close()
546
 
 
547
 
        import hotshot.stats
548
544
        stats = hotshot.stats.load(pfname)
549
 
        #stats.strip_dirs()
550
 
        stats.sort_stats('time')
 
545
        stats.strip_dirs()
 
546
        stats.sort_stats('cum')   # 'time'
551
547
        ## XXX: Might like to write to stderr or the trace file instead but
552
548
        ## print_stats seems hardcoded to stdout
553
549
        stats.print_stats(20)
554
 
 
555
550
        return ret
556
551
    finally:
557
552
        os.close(pffileno)
582
577
    --profile
583
578
        Run under the Python profiler.
584
579
    """
 
580
    # Load all of the transport methods
 
581
    import bzrlib.transport.local, bzrlib.transport.http
585
582
    
586
583
    argv = [a.decode(bzrlib.user_encoding) for a in argv]
587
584
 
635
632
    bzrlib.trace.log_startup(argv)
636
633
    bzrlib.ui.ui_factory = bzrlib.ui.TextUIFactory()
637
634
 
 
635
    return run_bzr_catch_errors(argv[1:])
 
636
 
 
637
 
 
638
def run_bzr_catch_errors(argv):
638
639
    try:
639
640
        try:
640
 
            return run_bzr(argv[1:])
 
641
            return run_bzr(argv)
641
642
        finally:
642
643
            # do this here inside the exception wrappers to catch EPIPE
643
644
            sys.stdout.flush()
652
653
        bzrlib.trace.log_exception('assertion failed: ' + str(e))
653
654
        return 3
654
655
    except KeyboardInterrupt, e:
655
 
        bzrlib.trace.note('interrupted')
 
656
        bzrlib.trace.log_exception('interrupted')
656
657
        return 2
657
658
    except Exception, e:
658
659
        import errno
662
663
            bzrlib.trace.note('broken pipe')
663
664
            return 2
664
665
        else:
 
666
            ## import pdb
 
667
            ## pdb.pm()
665
668
            bzrlib.trace.log_exception()
666
669
            return 2
667
670
 
668
 
 
669
671
if __name__ == '__main__':
670
672
    sys.exit(main(sys.argv))