~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/revisionspec.py

  • Committer: John Arbash Meinel
  • Date: 2009-08-25 18:45:40 UTC
  • mto: (4634.6.15 2.0)
  • mto: This revision was merged to the branch mainline in revision 4667.
  • Revision ID: john@arbash-meinel.com-20090825184540-6dn3xjq62xhgj2gq
Add support for skipping ghost nodes.

Show diffs side-by-side

added added

removed removed

Lines of Context:
12
12
#
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
 
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
 
 
17
 
 
 
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
16
 
 
17
 
 
18
import re
 
19
 
 
20
from bzrlib.lazy_import import lazy_import
 
21
lazy_import(globals(), """
18
22
import bisect
19
23
import datetime
20
 
import re
 
24
""")
21
25
 
22
26
from bzrlib import (
23
27
    errors,
24
28
    osutils,
 
29
    registry,
25
30
    revision,
26
31
    symbol_versioning,
27
32
    trace,
28
 
    tsort,
29
33
    )
30
34
 
31
35
 
100
104
 
101
105
        Use this if you don't know or care what the revno is.
102
106
        """
 
107
        if revision_id == revision.NULL_REVISION:
 
108
            return RevisionInfo(branch, 0, revision_id)
103
109
        try:
104
110
            revno = revs.index(revision_id) + 1
105
111
        except ValueError:
109
115
 
110
116
# classes in this list should have a "prefix" attribute, against which
111
117
# string specs are matched
112
 
SPEC_TYPES = []
113
118
_revno_regex = None
114
119
 
115
120
 
133
138
    """
134
139
 
135
140
    prefix = None
136
 
 
137
 
    def __new__(cls, spec, _internal=False):
138
 
        if _internal:
139
 
            return object.__new__(cls, spec, _internal=_internal)
140
 
 
141
 
        symbol_versioning.warn('Creating a RevisionSpec directly has'
142
 
                               ' been deprecated in version 0.11. Use'
143
 
                               ' RevisionSpec.from_string()'
144
 
                               ' instead.',
145
 
                               DeprecationWarning, stacklevel=2)
146
 
        return RevisionSpec.from_string(spec)
 
141
    wants_revision_history = True
147
142
 
148
143
    @staticmethod
149
144
    def from_string(spec):
158
153
 
159
154
        if spec is None:
160
155
            return RevisionSpec(None, _internal=True)
161
 
 
162
 
        assert isinstance(spec, basestring), \
163
 
            "You should only supply strings not %s" % (type(spec),)
164
 
 
165
 
        for spectype in SPEC_TYPES:
166
 
            if spec.startswith(spectype.prefix):
167
 
                trace.mutter('Returning RevisionSpec %s for %s',
168
 
                             spectype.__name__, spec)
169
 
                return spectype(spec, _internal=True)
 
156
        match = revspec_registry.get_prefix(spec)
 
157
        if match is not None:
 
158
            spectype, specsuffix = match
 
159
            trace.mutter('Returning RevisionSpec %s for %s',
 
160
                         spectype.__name__, spec)
 
161
            return spectype(spec, _internal=True)
170
162
        else:
 
163
            for spectype in SPEC_TYPES:
 
164
                if spec.startswith(spectype.prefix):
 
165
                    trace.mutter('Returning RevisionSpec %s for %s',
 
166
                                 spectype.__name__, spec)
 
167
                    return spectype(spec, _internal=True)
171
168
            # RevisionSpec_revno is special cased, because it is the only
172
169
            # one that directly handles plain integers
173
170
            # TODO: This should not be special cased rather it should be
188
185
            called directly. Only from RevisionSpec.from_string()
189
186
        """
190
187
        if not _internal:
191
 
            # XXX: Update this after 0.10 is released
192
188
            symbol_versioning.warn('Creating a RevisionSpec directly has'
193
189
                                   ' been deprecated in version 0.11. Use'
194
190
                                   ' RevisionSpec.from_string()'
201
197
 
202
198
    def _match_on(self, branch, revs):
203
199
        trace.mutter('Returning RevisionSpec._match_on: None')
204
 
        return RevisionInfo(branch, 0, None)
 
200
        return RevisionInfo(branch, None, None)
205
201
 
206
202
    def _match_on_and_check(self, branch, revs):
207
203
        info = self._match_on(branch, revs)
208
204
        if info:
209
205
            return info
210
 
        elif info == (0, None):
211
 
            # special case - the empty tree
 
206
        elif info == (None, None):
 
207
            # special case - nothing supplied
212
208
            return info
213
209
        elif self.prefix:
214
210
            raise errors.InvalidRevisionSpec(self.user_spec, branch)
217
213
 
218
214
    def in_history(self, branch):
219
215
        if branch:
220
 
            revs = branch.revision_history()
 
216
            if self.wants_revision_history:
 
217
                revs = branch.revision_history()
 
218
            else:
 
219
                revs = None
221
220
        else:
222
221
            # this should never trigger.
223
222
            # TODO: make it a deprecated code path. RBC 20060928
233
232
    # will do what you expect.
234
233
    in_store = in_history
235
234
    in_branch = in_store
236
 
        
 
235
 
 
236
    def as_revision_id(self, context_branch):
 
237
        """Return just the revision_id for this revisions spec.
 
238
 
 
239
        Some revision specs require a context_branch to be able to determine
 
240
        their value. Not all specs will make use of it.
 
241
        """
 
242
        return self._as_revision_id(context_branch)
 
243
 
 
244
    def _as_revision_id(self, context_branch):
 
245
        """Implementation of as_revision_id()
 
246
 
 
247
        Classes should override this function to provide appropriate
 
248
        functionality. The default is to just call '.in_history().rev_id'
 
249
        """
 
250
        return self.in_history(context_branch).rev_id
 
251
 
 
252
    def as_tree(self, context_branch):
 
253
        """Return the tree object for this revisions spec.
 
254
 
 
255
        Some revision specs require a context_branch to be able to determine
 
256
        the revision id and access the repository. Not all specs will make
 
257
        use of it.
 
258
        """
 
259
        return self._as_tree(context_branch)
 
260
 
 
261
    def _as_tree(self, context_branch):
 
262
        """Implementation of as_tree().
 
263
 
 
264
        Classes should override this function to provide appropriate
 
265
        functionality. The default is to just call '.as_revision_id()'
 
266
        and get the revision tree from context_branch's repository.
 
267
        """
 
268
        revision_id = self.as_revision_id(context_branch)
 
269
        return context_branch.repository.revision_tree(revision_id)
 
270
 
237
271
    def __repr__(self):
238
272
        # this is mostly for helping with testing
239
273
        return '<%s %s>' % (self.__class__.__name__,
240
274
                              self.user_spec)
241
 
    
 
275
 
242
276
    def needs_branch(self):
243
277
        """Whether this revision spec needs a branch.
244
278
 
248
282
 
249
283
    def get_branch(self):
250
284
        """When the revision specifier contains a branch location, return it.
251
 
        
 
285
 
252
286
        Otherwise, return None.
253
287
        """
254
288
        return None
268
302
    than the branch's history, the first revision is returned.
269
303
    Examples::
270
304
 
271
 
      revno:1                   -> return the first revision
 
305
      revno:1                   -> return the first revision of this branch
272
306
      revno:3:/path/to/branch   -> return the 3rd revision of
273
307
                                   the branch '/path/to/branch'
274
308
      revno:-1                  -> The last revision in a branch.
278
312
                                   your history is very long.
279
313
    """
280
314
    prefix = 'revno:'
 
315
    wants_revision_history = False
281
316
 
282
317
    def _match_on(self, branch, revs):
283
318
        """Lookup a revision by revision number"""
 
319
        branch, revno, revision_id = self._lookup(branch, revs)
 
320
        return RevisionInfo(branch, revno, revision_id)
 
321
 
 
322
    def _lookup(self, branch, revs_or_none):
284
323
        loc = self.spec.find(':')
285
324
        if loc == -1:
286
325
            revno_spec = self.spec
300
339
                dotted = False
301
340
            except ValueError:
302
341
                # dotted decimal. This arguably should not be here
303
 
                # but the from_string method is a little primitive 
 
342
                # but the from_string method is a little primitive
304
343
                # right now - RBC 20060928
305
344
                try:
306
345
                    match_revno = tuple((int(number) for number in revno_spec.split('.')))
315
354
            # the branch object.
316
355
            from bzrlib.branch import Branch
317
356
            branch = Branch.open(branch_spec)
318
 
            # Need to use a new revision history
319
 
            # because we are using a specific branch
320
 
            revs = branch.revision_history()
 
357
            revs_or_none = None
321
358
 
322
359
        if dotted:
323
 
            branch.lock_read()
324
360
            try:
325
 
                revision_id_to_revno = branch.get_revision_id_to_revno_map()
326
 
                revisions = [revision_id for revision_id, revno
327
 
                             in revision_id_to_revno.iteritems()
328
 
                             if revno == match_revno]
329
 
            finally:
330
 
                branch.unlock()
331
 
            if len(revisions) != 1:
332
 
                return RevisionInfo(branch, None, None)
 
361
                revision_id = branch.dotted_revno_to_revision_id(match_revno,
 
362
                    _cache_reverse=True)
 
363
            except errors.NoSuchRevision:
 
364
                raise errors.InvalidRevisionSpec(self.user_spec, branch)
333
365
            else:
334
366
                # there is no traditional 'revno' for dotted-decimal revnos.
335
367
                # so for  API compatability we return None.
336
 
                return RevisionInfo(branch, None, revisions[0])
 
368
                return branch, None, revision_id
337
369
        else:
 
370
            last_revno, last_revision_id = branch.last_revision_info()
338
371
            if revno < 0:
339
372
                # if get_rev_id supported negative revnos, there would not be a
340
373
                # need for this special case.
341
 
                if (-revno) >= len(revs):
 
374
                if (-revno) >= last_revno:
342
375
                    revno = 1
343
376
                else:
344
 
                    revno = len(revs) + revno + 1
 
377
                    revno = last_revno + revno + 1
345
378
            try:
346
 
                revision_id = branch.get_rev_id(revno, revs)
 
379
                revision_id = branch.get_rev_id(revno, revs_or_none)
347
380
            except errors.NoSuchRevision:
348
381
                raise errors.InvalidRevisionSpec(self.user_spec, branch)
349
 
        return RevisionInfo(branch, revno, revision_id)
350
 
        
 
382
        return branch, revno, revision_id
 
383
 
 
384
    def _as_revision_id(self, context_branch):
 
385
        # We would have the revno here, but we don't really care
 
386
        branch, revno, revision_id = self._lookup(context_branch, None)
 
387
        return revision_id
 
388
 
351
389
    def needs_branch(self):
352
390
        return self.spec.find(':') == -1
353
391
 
357
395
        else:
358
396
            return self.spec[self.spec.find(':')+1:]
359
397
 
360
 
# Old compatibility 
 
398
# Old compatibility
361
399
RevisionSpec_int = RevisionSpec_revno
362
400
 
363
 
SPEC_TYPES.append(RevisionSpec_revno)
364
401
 
365
402
 
366
403
class RevisionSpec_revid(RevisionSpec):
369
406
    help_txt = """Selects a revision using the revision id.
370
407
 
371
408
    Supply a specific revision id, that can be used to specify any
372
 
    revision id in the ancestry of the branch. 
 
409
    revision id in the ancestry of the branch.
373
410
    Including merges, and pending merges.
374
411
    Examples::
375
412
 
376
413
      revid:aaaa@bbbb-123456789 -> Select revision 'aaaa@bbbb-123456789'
377
 
    """    
 
414
    """
 
415
 
378
416
    prefix = 'revid:'
379
417
 
380
418
    def _match_on(self, branch, revs):
384
422
        revision_id = osutils.safe_revision_id(self.spec, warn=False)
385
423
        return RevisionInfo.from_revision_id(branch, revision_id, revs)
386
424
 
387
 
SPEC_TYPES.append(RevisionSpec_revid)
 
425
    def _as_revision_id(self, context_branch):
 
426
        return osutils.safe_revision_id(self.spec, warn=False)
 
427
 
388
428
 
389
429
 
390
430
class RevisionSpec_last(RevisionSpec):
398
438
 
399
439
      last:1        -> return the last revision
400
440
      last:3        -> return the revision 2 before the end.
401
 
    """    
 
441
    """
402
442
 
403
443
    prefix = 'last:'
404
444
 
405
445
    def _match_on(self, branch, revs):
 
446
        revno, revision_id = self._revno_and_revision_id(branch, revs)
 
447
        return RevisionInfo(branch, revno, revision_id)
 
448
 
 
449
    def _revno_and_revision_id(self, context_branch, revs_or_none):
 
450
        last_revno, last_revision_id = context_branch.last_revision_info()
 
451
 
406
452
        if self.spec == '':
407
 
            if not revs:
408
 
                raise errors.NoCommits(branch)
409
 
            return RevisionInfo(branch, len(revs), revs[-1])
 
453
            if not last_revno:
 
454
                raise errors.NoCommits(context_branch)
 
455
            return last_revno, last_revision_id
410
456
 
411
457
        try:
412
458
            offset = int(self.spec)
413
459
        except ValueError, e:
414
 
            raise errors.InvalidRevisionSpec(self.user_spec, branch, e)
 
460
            raise errors.InvalidRevisionSpec(self.user_spec, context_branch, e)
415
461
 
416
462
        if offset <= 0:
417
 
            raise errors.InvalidRevisionSpec(self.user_spec, branch,
 
463
            raise errors.InvalidRevisionSpec(self.user_spec, context_branch,
418
464
                                             'you must supply a positive value')
419
 
        revno = len(revs) - offset + 1
 
465
 
 
466
        revno = last_revno - offset + 1
420
467
        try:
421
 
            revision_id = branch.get_rev_id(revno, revs)
 
468
            revision_id = context_branch.get_rev_id(revno, revs_or_none)
422
469
        except errors.NoSuchRevision:
423
 
            raise errors.InvalidRevisionSpec(self.user_spec, branch)
424
 
        return RevisionInfo(branch, revno, revision_id)
425
 
 
426
 
SPEC_TYPES.append(RevisionSpec_last)
 
470
            raise errors.InvalidRevisionSpec(self.user_spec, context_branch)
 
471
        return revno, revision_id
 
472
 
 
473
    def _as_revision_id(self, context_branch):
 
474
        # We compute the revno as part of the process, but we don't really care
 
475
        # about it.
 
476
        revno, revision_id = self._revno_and_revision_id(context_branch, None)
 
477
        return revision_id
 
478
 
427
479
 
428
480
 
429
481
class RevisionSpec_before(RevisionSpec):
431
483
 
432
484
    help_txt = """Selects the parent of the revision specified.
433
485
 
434
 
    Supply any revision spec to return the parent of that revision.
 
486
    Supply any revision spec to return the parent of that revision.  This is
 
487
    mostly useful when inspecting revisions that are not in the revision history
 
488
    of a branch.
 
489
 
435
490
    It is an error to request the parent of the null revision (before:0).
436
 
    This is mostly useful when inspecting revisions that are not in the
437
 
    revision history of a branch.
438
491
 
439
492
    Examples::
440
493
 
441
494
      before:1913    -> Return the parent of revno 1913 (revno 1912)
442
495
      before:revid:aaaa@bbbb-1234567890  -> return the parent of revision
443
496
                                            aaaa@bbbb-1234567890
444
 
      bzr diff -r before:revid:aaaa..revid:aaaa
445
 
            -> Find the changes between revision 'aaaa' and its parent.
446
 
               (what changes did 'aaaa' introduce)
 
497
      bzr diff -r before:1913..1913
 
498
            -> Find the changes between revision 1913 and its parent (1912).
 
499
               (What changes did revision 1913 introduce).
 
500
               This is equivalent to:  bzr diff -c 1913
447
501
    """
448
502
 
449
503
    prefix = 'before:'
450
 
    
 
504
 
451
505
    def _match_on(self, branch, revs):
452
506
        r = RevisionSpec.from_string(self.spec)._match_on(branch, revs)
453
507
        if r.revno == 0:
474
528
                                                 branch)
475
529
        return RevisionInfo(branch, revno, revision_id)
476
530
 
477
 
SPEC_TYPES.append(RevisionSpec_before)
 
531
    def _as_revision_id(self, context_branch):
 
532
        base_revspec = RevisionSpec.from_string(self.spec)
 
533
        base_revision_id = base_revspec.as_revision_id(context_branch)
 
534
        if base_revision_id == revision.NULL_REVISION:
 
535
            raise errors.InvalidRevisionSpec(self.user_spec, context_branch,
 
536
                                         'cannot go before the null: revision')
 
537
        context_repo = context_branch.repository
 
538
        context_repo.lock_read()
 
539
        try:
 
540
            parent_map = context_repo.get_parent_map([base_revision_id])
 
541
        finally:
 
542
            context_repo.unlock()
 
543
        if base_revision_id not in parent_map:
 
544
            # Ghost, or unknown revision id
 
545
            raise errors.InvalidRevisionSpec(self.user_spec, context_branch,
 
546
                'cannot find the matching revision')
 
547
        parents = parent_map[base_revision_id]
 
548
        if len(parents) < 1:
 
549
            raise errors.InvalidRevisionSpec(self.user_spec, context_branch,
 
550
                'No parents for revision.')
 
551
        return parents[0]
 
552
 
478
553
 
479
554
 
480
555
class RevisionSpec_tag(RevisionSpec):
493
568
            branch.tags.lookup_tag(self.spec),
494
569
            revs)
495
570
 
496
 
SPEC_TYPES.append(RevisionSpec_tag)
 
571
    def _as_revision_id(self, context_branch):
 
572
        return context_branch.tags.lookup_tag(self.spec)
 
573
 
497
574
 
498
575
 
499
576
class _RevListToTimestamps(object):
527
604
 
528
605
    One way to display all the changes since yesterday would be::
529
606
 
530
 
        bzr log -r date:yesterday..-1
 
607
        bzr log -r date:yesterday..
531
608
 
532
609
    Examples::
533
610
 
534
611
      date:yesterday            -> select the first revision since yesterday
535
612
      date:2006-08-14,17:10:14  -> select the first revision after
536
613
                                   August 14th, 2006 at 5:10pm.
537
 
    """    
 
614
    """
538
615
    prefix = 'date:'
539
616
    _date_re = re.compile(
540
617
            r'(?P<date>(?P<year>\d\d\d\d)-(?P<month>\d\d)-(?P<day>\d\d))?'
596
673
        finally:
597
674
            branch.unlock()
598
675
        if rev == len(revs):
599
 
            return RevisionInfo(branch, None)
 
676
            raise errors.InvalidRevisionSpec(self.user_spec, branch)
600
677
        else:
601
678
            return RevisionInfo(branch, rev + 1)
602
679
 
603
 
SPEC_TYPES.append(RevisionSpec_date)
604
680
 
605
681
 
606
682
class RevisionSpec_ancestor(RevisionSpec):
629
705
        trace.mutter('matching ancestor: on: %s, %s', self.spec, branch)
630
706
        return self._find_revision_info(branch, self.spec)
631
707
 
 
708
    def _as_revision_id(self, context_branch):
 
709
        return self._find_revision_id(context_branch, self.spec)
 
710
 
632
711
    @staticmethod
633
712
    def _find_revision_info(branch, other_location):
 
713
        revision_id = RevisionSpec_ancestor._find_revision_id(branch,
 
714
                                                              other_location)
 
715
        try:
 
716
            revno = branch.revision_id_to_revno(revision_id)
 
717
        except errors.NoSuchRevision:
 
718
            revno = None
 
719
        return RevisionInfo(branch, revno, revision_id)
 
720
 
 
721
    @staticmethod
 
722
    def _find_revision_id(branch, other_location):
634
723
        from bzrlib.branch import Branch
635
724
 
636
 
        other_branch = Branch.open(other_location)
637
 
        revision_a = branch.last_revision()
638
 
        revision_b = other_branch.last_revision()
639
 
        for r, b in ((revision_a, branch), (revision_b, other_branch)):
640
 
            if r in (None, revision.NULL_REVISION):
641
 
                raise errors.NoCommits(b)
642
 
        revision_source = revision.MultipleRevisionSources(
643
 
                branch.repository, other_branch.repository)
644
 
        graph = branch.repository.get_graph(other_branch.repository)
645
 
        revision_a = revision.ensure_null(revision_a)
646
 
        revision_b = revision.ensure_null(revision_b)
647
 
        if revision.NULL_REVISION in (revision_a, revision_b):
648
 
            rev_id = revision.NULL_REVISION
649
 
        else:
650
 
            rev_id = graph.find_unique_lca(revision_a, revision_b)
 
725
        branch.lock_read()
 
726
        try:
 
727
            revision_a = revision.ensure_null(branch.last_revision())
 
728
            if revision_a == revision.NULL_REVISION:
 
729
                raise errors.NoCommits(branch)
 
730
            if other_location == '':
 
731
                other_location = branch.get_parent()
 
732
            other_branch = Branch.open(other_location)
 
733
            other_branch.lock_read()
 
734
            try:
 
735
                revision_b = revision.ensure_null(other_branch.last_revision())
 
736
                if revision_b == revision.NULL_REVISION:
 
737
                    raise errors.NoCommits(other_branch)
 
738
                graph = branch.repository.get_graph(other_branch.repository)
 
739
                rev_id = graph.find_unique_lca(revision_a, revision_b)
 
740
            finally:
 
741
                other_branch.unlock()
651
742
            if rev_id == revision.NULL_REVISION:
652
743
                raise errors.NoCommonAncestor(revision_a, revision_b)
653
 
        try:
654
 
            revno = branch.revision_id_to_revno(rev_id)
655
 
        except errors.NoSuchRevision:
656
 
            revno = None
657
 
        return RevisionInfo(branch, revno, rev_id)
658
 
 
659
 
 
660
 
SPEC_TYPES.append(RevisionSpec_ancestor)
 
744
            return rev_id
 
745
        finally:
 
746
            branch.unlock()
 
747
 
 
748
 
661
749
 
662
750
 
663
751
class RevisionSpec_branch(RevisionSpec):
686
774
        except errors.NoSuchRevision:
687
775
            revno = None
688
776
        return RevisionInfo(branch, revno, revision_b)
689
 
        
690
 
SPEC_TYPES.append(RevisionSpec_branch)
 
777
 
 
778
    def _as_revision_id(self, context_branch):
 
779
        from bzrlib.branch import Branch
 
780
        other_branch = Branch.open(self.spec)
 
781
        last_revision = other_branch.last_revision()
 
782
        last_revision = revision.ensure_null(last_revision)
 
783
        context_branch.fetch(other_branch, last_revision)
 
784
        if last_revision == revision.NULL_REVISION:
 
785
            raise errors.NoCommits(other_branch)
 
786
        return last_revision
 
787
 
 
788
    def _as_tree(self, context_branch):
 
789
        from bzrlib.branch import Branch
 
790
        other_branch = Branch.open(self.spec)
 
791
        last_revision = other_branch.last_revision()
 
792
        last_revision = revision.ensure_null(last_revision)
 
793
        if last_revision == revision.NULL_REVISION:
 
794
            raise errors.NoCommits(other_branch)
 
795
        return other_branch.repository.revision_tree(last_revision)
 
796
 
691
797
 
692
798
 
693
799
class RevisionSpec_submit(RevisionSpec_ancestor):
697
803
 
698
804
    Diffing against this shows all the changes that were made in this branch,
699
805
    and is a good predictor of what merge will do.  The submit branch is
700
 
    used by the bundle and merge directive comands.  If no submit branch
 
806
    used by the bundle and merge directive commands.  If no submit branch
701
807
    is specified, the parent branch is used instead.
702
808
 
703
809
    The common ancestor is the last revision that existed in both
711
817
 
712
818
    prefix = 'submit:'
713
819
 
714
 
    def _match_on(self, branch, revs):
715
 
        trace.mutter('matching ancestor: on: %s, %s', self.spec, branch)
 
820
    def _get_submit_location(self, branch):
716
821
        submit_location = branch.get_submit_branch()
717
822
        location_type = 'submit branch'
718
823
        if submit_location is None:
721
826
        if submit_location is None:
722
827
            raise errors.NoSubmitBranch(branch)
723
828
        trace.note('Using %s %s', location_type, submit_location)
724
 
        return self._find_revision_info(branch, submit_location)
725
 
 
726
 
 
727
 
SPEC_TYPES.append(RevisionSpec_submit)
 
829
        return submit_location
 
830
 
 
831
    def _match_on(self, branch, revs):
 
832
        trace.mutter('matching ancestor: on: %s, %s', self.spec, branch)
 
833
        return self._find_revision_info(branch,
 
834
            self._get_submit_location(branch))
 
835
 
 
836
    def _as_revision_id(self, context_branch):
 
837
        return self._find_revision_id(context_branch,
 
838
            self._get_submit_location(context_branch))
 
839
 
 
840
 
 
841
revspec_registry = registry.Registry()
 
842
def _register_revspec(revspec):
 
843
    revspec_registry.register(revspec.prefix, revspec)
 
844
 
 
845
_register_revspec(RevisionSpec_revno)
 
846
_register_revspec(RevisionSpec_revid)
 
847
_register_revspec(RevisionSpec_last)
 
848
_register_revspec(RevisionSpec_before)
 
849
_register_revspec(RevisionSpec_tag)
 
850
_register_revspec(RevisionSpec_date)
 
851
_register_revspec(RevisionSpec_ancestor)
 
852
_register_revspec(RevisionSpec_branch)
 
853
_register_revspec(RevisionSpec_submit)
 
854
 
 
855
SPEC_TYPES = symbol_versioning.deprecated_list(
 
856
    symbol_versioning.deprecated_in((1, 12, 0)), "SPEC_TYPES", [])