~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/revisionspec.py

  • Committer: John Arbash Meinel
  • Date: 2010-02-17 17:11:16 UTC
  • mfrom: (4797.2.17 2.1)
  • mto: (4797.2.18 2.1)
  • mto: This revision was merged to the branch mainline in revision 5055.
  • Revision ID: john@arbash-meinel.com-20100217171116-h7t9223ystbnx5h8
merge bzr.2.1 in preparation for NEWS entry.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006, 2007 Canonical Ltd
 
1
# Copyright (C) 2005-2010 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
113
113
        return RevisionInfo(branch, revno, revision_id)
114
114
 
115
115
 
116
 
# classes in this list should have a "prefix" attribute, against which
117
 
# string specs are matched
118
116
_revno_regex = None
119
117
 
120
118
 
123
121
 
124
122
    help_txt = """A parsed revision specification.
125
123
 
126
 
    A revision specification can be an integer, in which case it is
127
 
    assumed to be a revno (though this will translate negative values
128
 
    into positive ones); or it can be a string, in which case it is
129
 
    parsed for something like 'date:' or 'revid:' etc.
 
124
    A revision specification is a string, which may be unambiguous about
 
125
    what it represents by giving a prefix like 'date:' or 'revid:' etc,
 
126
    or it may have no prefix, in which case it's tried against several
 
127
    specifier types in sequence to determine what the user meant.
130
128
 
131
129
    Revision specs are an UI element, and they have been moved out
132
130
    of the branch class to leave "back-end" classes unaware of such
139
137
 
140
138
    prefix = None
141
139
    wants_revision_history = True
 
140
    dwim_catchable_exceptions = (errors.InvalidRevisionSpec,)
 
141
    """Exceptions that RevisionSpec_dwim._match_on will catch.
 
142
 
 
143
    If the revspec is part of ``dwim_revspecs``, it may be tried with an
 
144
    invalid revspec and raises some exception. The exceptions mentioned here
 
145
    will not be reported to the user but simply ignored without stopping the
 
146
    dwim processing.
 
147
    """
142
148
 
143
149
    @staticmethod
144
150
    def from_string(spec):
165
171
                    trace.mutter('Returning RevisionSpec %s for %s',
166
172
                                 spectype.__name__, spec)
167
173
                    return spectype(spec, _internal=True)
168
 
            # RevisionSpec_revno is special cased, because it is the only
169
 
            # one that directly handles plain integers
170
 
            # TODO: This should not be special cased rather it should be
171
 
            # a method invocation on spectype.canparse()
172
 
            global _revno_regex
173
 
            if _revno_regex is None:
174
 
                _revno_regex = re.compile(r'^(?:(\d+(\.\d+)*)|-\d+)(:.*)?$')
175
 
            if _revno_regex.match(spec) is not None:
176
 
                return RevisionSpec_revno(spec, _internal=True)
177
 
 
178
 
            raise errors.NoSuchRevisionSpec(spec)
 
174
            # Otherwise treat it as a DWIM, build the RevisionSpec object and
 
175
            # wait for _match_on to be called.
 
176
            return RevisionSpec_dwim(spec, _internal=True)
179
177
 
180
178
    def __init__(self, spec, _internal=False):
181
179
        """Create a RevisionSpec referring to the Null revision.
290
288
 
291
289
# private API
292
290
 
 
291
class RevisionSpec_dwim(RevisionSpec):
 
292
    """Provides a DWIMish revision specifier lookup.
 
293
 
 
294
    Note that this does not go in the revspec_registry because by definition
 
295
    there is no prefix to identify it.  It's solely called from
 
296
    RevisionSpec.from_string() because the DWIMification happen when _match_on
 
297
    is called so the string describing the revision is kept here until needed.
 
298
    """
 
299
 
 
300
    help_txt = None
 
301
    # We don't need to build the revision history ourself, that's delegated to
 
302
    # each revspec we try.
 
303
    wants_revision_history = False
 
304
 
 
305
    def _try_spectype(self, rstype, branch):
 
306
        rs = rstype(self.spec, _internal=True)
 
307
        # Hit in_history to find out if it exists, or we need to try the
 
308
        # next type.
 
309
        return rs.in_history(branch)
 
310
 
 
311
    def _match_on(self, branch, revs):
 
312
        """Run the lookup and see what we can get."""
 
313
 
 
314
        # First, see if it's a revno
 
315
        global _revno_regex
 
316
        if _revno_regex is None:
 
317
            _revno_regex = re.compile(r'^(?:(\d+(\.\d+)*)|-\d+)(:.*)?$')
 
318
        if _revno_regex.match(self.spec) is not None:
 
319
            try:
 
320
                return self._try_spectype(RevisionSpec_revno, branch)
 
321
            except RevisionSpec_revno.dwim_catchable_exceptions:
 
322
                pass
 
323
 
 
324
        # Next see what has been registered
 
325
        for rs_class in dwim_revspecs:
 
326
            try:
 
327
                return self._try_spectype(rs_class, branch)
 
328
            except rs_class.dwim_catchable_exceptions:
 
329
                pass
 
330
 
 
331
        # Well, I dunno what it is. Note that we don't try to keep track of the
 
332
        # first of last exception raised during the DWIM tries as none seems
 
333
        # really relevant.
 
334
        raise errors.InvalidRevisionSpec(self.spec, branch)
 
335
 
 
336
 
293
337
class RevisionSpec_revno(RevisionSpec):
294
338
    """Selects a revision using a number."""
295
339
 
296
340
    help_txt = """Selects a revision using a number.
297
341
 
298
342
    Use an integer to specify a revision in the history of the branch.
299
 
    Optionally a branch can be specified. The 'revno:' prefix is optional.
300
 
    A negative number will count from the end of the branch (-1 is the
301
 
    last revision, -2 the previous one). If the negative number is larger
302
 
    than the branch's history, the first revision is returned.
 
343
    Optionally a branch can be specified.  A negative number will count
 
344
    from the end of the branch (-1 is the last revision, -2 the previous
 
345
    one). If the negative number is larger than the branch's history, the
 
346
    first revision is returned.
303
347
    Examples::
304
348
 
305
349
      revno:1                   -> return the first revision of this branch
561
605
    """
562
606
 
563
607
    prefix = 'tag:'
 
608
    dwim_catchable_exceptions = (errors.NoSuchTag, errors.TagsNotSupported)
564
609
 
565
610
    def _match_on(self, branch, revs):
566
611
        # Can raise tags not supported, NoSuchTag, etc
760
805
      branch:/path/to/branch
761
806
    """
762
807
    prefix = 'branch:'
 
808
    dwim_catchable_exceptions = (errors.NotBranchError,)
763
809
 
764
810
    def _match_on(self, branch, revs):
765
811
        from bzrlib.branch import Branch
838
884
            self._get_submit_location(context_branch))
839
885
 
840
886
 
 
887
# The order in which we want to DWIM a revision spec without any prefix.
 
888
# revno is always tried first and isn't listed here, this is used by
 
889
# RevisionSpec_dwim._match_on
 
890
dwim_revspecs = [
 
891
    RevisionSpec_tag, # Let's try for a tag
 
892
    RevisionSpec_revid, # Maybe it's a revid?
 
893
    RevisionSpec_date, # Perhaps a date?
 
894
    RevisionSpec_branch, # OK, last try, maybe it's a branch
 
895
    ]
 
896
 
 
897
 
841
898
revspec_registry = registry.Registry()
842
899
def _register_revspec(revspec):
843
900
    revspec_registry.register(revspec.prefix, revspec)
852
909
_register_revspec(RevisionSpec_branch)
853
910
_register_revspec(RevisionSpec_submit)
854
911
 
 
912
# classes in this list should have a "prefix" attribute, against which
 
913
# string specs are matched
855
914
SPEC_TYPES = symbol_versioning.deprecated_list(
856
915
    symbol_versioning.deprecated_in((1, 12, 0)), "SPEC_TYPES", [])