~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/revisionspec.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2009-04-09 20:23:07 UTC
  • mfrom: (4265.1.4 bbc-merge)
  • Revision ID: pqm@pqm.ubuntu.com-20090409202307-n0depb16qepoe21o
(jam) Change _fetch_uses_deltas = False for CHK repos until we can
        write a better fix.

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):
 
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)
 
162
        else:
 
163
            for spectype in SPEC_TYPES:
167
164
                trace.mutter('Returning RevisionSpec %s for %s',
168
165
                             spectype.__name__, spec)
169
 
                return spectype(spec, _internal=True)
170
 
        else:
 
166
                if spec.startswith(spectype.prefix):
 
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
201
198
 
202
199
    def _match_on(self, branch, revs):
203
200
        trace.mutter('Returning RevisionSpec._match_on: None')
204
 
        return RevisionInfo(branch, 0, None)
 
201
        return RevisionInfo(branch, None, None)
205
202
 
206
203
    def _match_on_and_check(self, branch, revs):
207
204
        info = self._match_on(branch, revs)
208
205
        if info:
209
206
            return info
210
 
        elif info == (0, None):
211
 
            # special case - the empty tree
 
207
        elif info == (None, None):
 
208
            # special case - nothing supplied
212
209
            return info
213
210
        elif self.prefix:
214
211
            raise errors.InvalidRevisionSpec(self.user_spec, branch)
217
214
 
218
215
    def in_history(self, branch):
219
216
        if branch:
220
 
            revs = branch.revision_history()
 
217
            if self.wants_revision_history:
 
218
                revs = branch.revision_history()
 
219
            else:
 
220
                revs = None
221
221
        else:
222
222
            # this should never trigger.
223
223
            # TODO: make it a deprecated code path. RBC 20060928
233
233
    # will do what you expect.
234
234
    in_store = in_history
235
235
    in_branch = in_store
236
 
        
 
236
 
 
237
    def as_revision_id(self, context_branch):
 
238
        """Return just the revision_id for this revisions spec.
 
239
 
 
240
        Some revision specs require a context_branch to be able to determine
 
241
        their value. Not all specs will make use of it.
 
242
        """
 
243
        return self._as_revision_id(context_branch)
 
244
 
 
245
    def _as_revision_id(self, context_branch):
 
246
        """Implementation of as_revision_id()
 
247
 
 
248
        Classes should override this function to provide appropriate
 
249
        functionality. The default is to just call '.in_history().rev_id'
 
250
        """
 
251
        return self.in_history(context_branch).rev_id
 
252
 
 
253
    def as_tree(self, context_branch):
 
254
        """Return the tree object for this revisions spec.
 
255
 
 
256
        Some revision specs require a context_branch to be able to determine
 
257
        the revision id and access the repository. Not all specs will make
 
258
        use of it.
 
259
        """
 
260
        return self._as_tree(context_branch)
 
261
 
 
262
    def _as_tree(self, context_branch):
 
263
        """Implementation of as_tree().
 
264
 
 
265
        Classes should override this function to provide appropriate
 
266
        functionality. The default is to just call '.as_revision_id()'
 
267
        and get the revision tree from context_branch's repository.
 
268
        """
 
269
        revision_id = self.as_revision_id(context_branch)
 
270
        return context_branch.repository.revision_tree(revision_id)
 
271
 
237
272
    def __repr__(self):
238
273
        # this is mostly for helping with testing
239
274
        return '<%s %s>' % (self.__class__.__name__,
240
275
                              self.user_spec)
241
 
    
 
276
 
242
277
    def needs_branch(self):
243
278
        """Whether this revision spec needs a branch.
244
279
 
248
283
 
249
284
    def get_branch(self):
250
285
        """When the revision specifier contains a branch location, return it.
251
 
        
 
286
 
252
287
        Otherwise, return None.
253
288
        """
254
289
        return None
266
301
    A negative number will count from the end of the branch (-1 is the
267
302
    last revision, -2 the previous one). If the negative number is larger
268
303
    than the branch's history, the first revision is returned.
269
 
    examples:
270
 
      revno:1                   -> return the first revision
 
304
    Examples::
 
305
 
 
306
      revno:1                   -> return the first revision of this branch
271
307
      revno:3:/path/to/branch   -> return the 3rd revision of
272
308
                                   the branch '/path/to/branch'
273
309
      revno:-1                  -> The last revision in a branch.
277
313
                                   your history is very long.
278
314
    """
279
315
    prefix = 'revno:'
 
316
    wants_revision_history = False
280
317
 
281
318
    def _match_on(self, branch, revs):
282
319
        """Lookup a revision by revision number"""
 
320
        branch, revno, revision_id = self._lookup(branch, revs)
 
321
        return RevisionInfo(branch, revno, revision_id)
 
322
 
 
323
    def _lookup(self, branch, revs_or_none):
283
324
        loc = self.spec.find(':')
284
325
        if loc == -1:
285
326
            revno_spec = self.spec
299
340
                dotted = False
300
341
            except ValueError:
301
342
                # dotted decimal. This arguably should not be here
302
 
                # but the from_string method is a little primitive 
 
343
                # but the from_string method is a little primitive
303
344
                # right now - RBC 20060928
304
345
                try:
305
346
                    match_revno = tuple((int(number) for number in revno_spec.split('.')))
314
355
            # the branch object.
315
356
            from bzrlib.branch import Branch
316
357
            branch = Branch.open(branch_spec)
317
 
            # Need to use a new revision history
318
 
            # because we are using a specific branch
319
 
            revs = branch.revision_history()
 
358
            revs_or_none = None
320
359
 
321
360
        if dotted:
322
 
            branch.lock_read()
323
361
            try:
324
 
                last_rev = branch.last_revision()
325
 
                merge_sorted_revisions = tsort.merge_sort(
326
 
                    branch.repository.get_revision_graph(last_rev),
327
 
                    last_rev,
328
 
                    generate_revno=True)
329
 
                def match(item):
330
 
                    return item[3] == match_revno
331
 
                revisions = filter(match, merge_sorted_revisions)
332
 
            finally:
333
 
                branch.unlock()
334
 
            if len(revisions) != 1:
335
 
                return RevisionInfo(branch, None, None)
 
362
                revision_id = branch.dotted_revno_to_revision_id(match_revno,
 
363
                    _cache_reverse=True)
 
364
            except errors.NoSuchRevision:
 
365
                raise errors.InvalidRevisionSpec(self.user_spec, branch)
336
366
            else:
337
367
                # there is no traditional 'revno' for dotted-decimal revnos.
338
368
                # so for  API compatability we return None.
339
 
                return RevisionInfo(branch, None, revisions[0][1])
 
369
                return branch, None, revision_id
340
370
        else:
 
371
            last_revno, last_revision_id = branch.last_revision_info()
341
372
            if revno < 0:
342
373
                # if get_rev_id supported negative revnos, there would not be a
343
374
                # need for this special case.
344
 
                if (-revno) >= len(revs):
 
375
                if (-revno) >= last_revno:
345
376
                    revno = 1
346
377
                else:
347
 
                    revno = len(revs) + revno + 1
 
378
                    revno = last_revno + revno + 1
348
379
            try:
349
 
                revision_id = branch.get_rev_id(revno, revs)
 
380
                revision_id = branch.get_rev_id(revno, revs_or_none)
350
381
            except errors.NoSuchRevision:
351
382
                raise errors.InvalidRevisionSpec(self.user_spec, branch)
352
 
        return RevisionInfo(branch, revno, revision_id)
353
 
        
 
383
        return branch, revno, revision_id
 
384
 
 
385
    def _as_revision_id(self, context_branch):
 
386
        # We would have the revno here, but we don't really care
 
387
        branch, revno, revision_id = self._lookup(context_branch, None)
 
388
        return revision_id
 
389
 
354
390
    def needs_branch(self):
355
391
        return self.spec.find(':') == -1
356
392
 
360
396
        else:
361
397
            return self.spec[self.spec.find(':')+1:]
362
398
 
363
 
# Old compatibility 
 
399
# Old compatibility
364
400
RevisionSpec_int = RevisionSpec_revno
365
401
 
366
 
SPEC_TYPES.append(RevisionSpec_revno)
367
402
 
368
403
 
369
404
class RevisionSpec_revid(RevisionSpec):
372
407
    help_txt = """Selects a revision using the revision id.
373
408
 
374
409
    Supply a specific revision id, that can be used to specify any
375
 
    revision id in the ancestry of the branch. 
 
410
    revision id in the ancestry of the branch.
376
411
    Including merges, and pending merges.
377
 
    examples:
 
412
    Examples::
 
413
 
378
414
      revid:aaaa@bbbb-123456789 -> Select revision 'aaaa@bbbb-123456789'
379
 
    """    
 
415
    """
 
416
 
380
417
    prefix = 'revid:'
381
418
 
382
419
    def _match_on(self, branch, revs):
386
423
        revision_id = osutils.safe_revision_id(self.spec, warn=False)
387
424
        return RevisionInfo.from_revision_id(branch, revision_id, revs)
388
425
 
389
 
SPEC_TYPES.append(RevisionSpec_revid)
 
426
    def _as_revision_id(self, context_branch):
 
427
        return osutils.safe_revision_id(self.spec, warn=False)
 
428
 
390
429
 
391
430
 
392
431
class RevisionSpec_last(RevisionSpec):
396
435
 
397
436
    Supply a positive number to get the nth revision from the end.
398
437
    This is the same as supplying negative numbers to the 'revno:' spec.
399
 
    examples:
 
438
    Examples::
 
439
 
400
440
      last:1        -> return the last revision
401
441
      last:3        -> return the revision 2 before the end.
402
 
    """    
 
442
    """
403
443
 
404
444
    prefix = 'last:'
405
445
 
406
446
    def _match_on(self, branch, revs):
 
447
        revno, revision_id = self._revno_and_revision_id(branch, revs)
 
448
        return RevisionInfo(branch, revno, revision_id)
 
449
 
 
450
    def _revno_and_revision_id(self, context_branch, revs_or_none):
 
451
        last_revno, last_revision_id = context_branch.last_revision_info()
 
452
 
407
453
        if self.spec == '':
408
 
            if not revs:
409
 
                raise errors.NoCommits(branch)
410
 
            return RevisionInfo(branch, len(revs), revs[-1])
 
454
            if not last_revno:
 
455
                raise errors.NoCommits(context_branch)
 
456
            return last_revno, last_revision_id
411
457
 
412
458
        try:
413
459
            offset = int(self.spec)
414
460
        except ValueError, e:
415
 
            raise errors.InvalidRevisionSpec(self.user_spec, branch, e)
 
461
            raise errors.InvalidRevisionSpec(self.user_spec, context_branch, e)
416
462
 
417
463
        if offset <= 0:
418
 
            raise errors.InvalidRevisionSpec(self.user_spec, branch,
 
464
            raise errors.InvalidRevisionSpec(self.user_spec, context_branch,
419
465
                                             'you must supply a positive value')
420
 
        revno = len(revs) - offset + 1
 
466
 
 
467
        revno = last_revno - offset + 1
421
468
        try:
422
 
            revision_id = branch.get_rev_id(revno, revs)
 
469
            revision_id = context_branch.get_rev_id(revno, revs_or_none)
423
470
        except errors.NoSuchRevision:
424
 
            raise errors.InvalidRevisionSpec(self.user_spec, branch)
425
 
        return RevisionInfo(branch, revno, revision_id)
426
 
 
427
 
SPEC_TYPES.append(RevisionSpec_last)
 
471
            raise errors.InvalidRevisionSpec(self.user_spec, context_branch)
 
472
        return revno, revision_id
 
473
 
 
474
    def _as_revision_id(self, context_branch):
 
475
        # We compute the revno as part of the process, but we don't really care
 
476
        # about it.
 
477
        revno, revision_id = self._revno_and_revision_id(context_branch, None)
 
478
        return revision_id
 
479
 
428
480
 
429
481
 
430
482
class RevisionSpec_before(RevisionSpec):
432
484
 
433
485
    help_txt = """Selects the parent of the revision specified.
434
486
 
435
 
    Supply any revision spec to return the parent of that revision.
 
487
    Supply any revision spec to return the parent of that revision.  This is
 
488
    mostly useful when inspecting revisions that are not in the revision history
 
489
    of a branch.
 
490
 
436
491
    It is an error to request the parent of the null revision (before:0).
437
 
    This is mostly useful when inspecting revisions that are not in the
438
 
    revision history of a branch.
439
 
 
440
 
    examples:
 
492
 
 
493
    Examples::
 
494
 
441
495
      before:1913    -> Return the parent of revno 1913 (revno 1912)
442
496
      before:revid:aaaa@bbbb-1234567890  -> return the parent of revision
443
497
                                            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)
 
498
      bzr diff -r before:1913..1913
 
499
            -> Find the changes between revision 1913 and its parent (1912).
 
500
               (What changes did revision 1913 introduce).
 
501
               This is equivalent to:  bzr diff -c 1913
447
502
    """
448
503
 
449
504
    prefix = 'before:'
450
 
    
 
505
 
451
506
    def _match_on(self, branch, revs):
452
507
        r = RevisionSpec.from_string(self.spec)._match_on(branch, revs)
453
508
        if r.revno == 0:
458
513
            rev = branch.repository.get_revision(r.rev_id)
459
514
            if not rev.parent_ids:
460
515
                revno = 0
461
 
                revision_id = None
 
516
                revision_id = revision.NULL_REVISION
462
517
            else:
463
518
                revision_id = rev.parent_ids[0]
464
519
                try:
474
529
                                                 branch)
475
530
        return RevisionInfo(branch, revno, revision_id)
476
531
 
477
 
SPEC_TYPES.append(RevisionSpec_before)
 
532
    def _as_revision_id(self, context_branch):
 
533
        base_revspec = RevisionSpec.from_string(self.spec)
 
534
        base_revision_id = base_revspec.as_revision_id(context_branch)
 
535
        if base_revision_id == revision.NULL_REVISION:
 
536
            raise errors.InvalidRevisionSpec(self.user_spec, context_branch,
 
537
                                         'cannot go before the null: revision')
 
538
        context_repo = context_branch.repository
 
539
        context_repo.lock_read()
 
540
        try:
 
541
            parent_map = context_repo.get_parent_map([base_revision_id])
 
542
        finally:
 
543
            context_repo.unlock()
 
544
        if base_revision_id not in parent_map:
 
545
            # Ghost, or unknown revision id
 
546
            raise errors.InvalidRevisionSpec(self.user_spec, context_branch,
 
547
                'cannot find the matching revision')
 
548
        parents = parent_map[base_revision_id]
 
549
        if len(parents) < 1:
 
550
            raise errors.InvalidRevisionSpec(self.user_spec, context_branch,
 
551
                'No parents for revision.')
 
552
        return parents[0]
 
553
 
478
554
 
479
555
 
480
556
class RevisionSpec_tag(RevisionSpec):
493
569
            branch.tags.lookup_tag(self.spec),
494
570
            revs)
495
571
 
496
 
SPEC_TYPES.append(RevisionSpec_tag)
 
572
    def _as_revision_id(self, context_branch):
 
573
        return context_branch.tags.lookup_tag(self.spec)
 
574
 
497
575
 
498
576
 
499
577
class _RevListToTimestamps(object):
525
603
    Matches the first entry after a given date (either at midnight or
526
604
    at a specified time).
527
605
 
528
 
    One way to display all the changes since yesterday would be:
529
 
        bzr log -r date:yesterday..-1
530
 
 
531
 
    examples:
 
606
    One way to display all the changes since yesterday would be::
 
607
 
 
608
        bzr log -r date:yesterday..
 
609
 
 
610
    Examples::
 
611
 
532
612
      date:yesterday            -> select the first revision since yesterday
533
613
      date:2006-08-14,17:10:14  -> select the first revision after
534
614
                                   August 14th, 2006 at 5:10pm.
535
 
    """    
 
615
    """
536
616
    prefix = 'date:'
537
617
    _date_re = re.compile(
538
618
            r'(?P<date>(?P<year>\d\d\d\d)-(?P<month>\d\d)-(?P<day>\d\d))?'
594
674
        finally:
595
675
            branch.unlock()
596
676
        if rev == len(revs):
597
 
            return RevisionInfo(branch, None)
 
677
            raise errors.InvalidRevisionSpec(self.user_spec, branch)
598
678
        else:
599
679
            return RevisionInfo(branch, rev + 1)
600
680
 
601
 
SPEC_TYPES.append(RevisionSpec_date)
602
681
 
603
682
 
604
683
class RevisionSpec_ancestor(RevisionSpec):
616
695
    that your branch introduces, while excluding the changes that you
617
696
    have not merged from the remote branch.
618
697
 
619
 
    examples:
 
698
    Examples::
 
699
 
620
700
      ancestor:/path/to/branch
621
701
      $ bzr diff -r ancestor:../../mainline/branch
622
702
    """
626
706
        trace.mutter('matching ancestor: on: %s, %s', self.spec, branch)
627
707
        return self._find_revision_info(branch, self.spec)
628
708
 
 
709
    def _as_revision_id(self, context_branch):
 
710
        return self._find_revision_id(context_branch, self.spec)
 
711
 
629
712
    @staticmethod
630
713
    def _find_revision_info(branch, other_location):
631
 
        from bzrlib.branch import Branch
632
 
 
633
 
        other_branch = Branch.open(other_location)
634
 
        revision_a = branch.last_revision()
635
 
        revision_b = other_branch.last_revision()
636
 
        for r, b in ((revision_a, branch), (revision_b, other_branch)):
637
 
            if r in (None, revision.NULL_REVISION):
638
 
                raise errors.NoCommits(b)
639
 
        revision_source = revision.MultipleRevisionSources(
640
 
                branch.repository, other_branch.repository)
641
 
        rev_id = revision.common_ancestor(revision_a, revision_b,
642
 
                                          revision_source)
 
714
        revision_id = RevisionSpec_ancestor._find_revision_id(branch,
 
715
                                                              other_location)
643
716
        try:
644
 
            revno = branch.revision_id_to_revno(rev_id)
 
717
            revno = branch.revision_id_to_revno(revision_id)
645
718
        except errors.NoSuchRevision:
646
719
            revno = None
647
 
        return RevisionInfo(branch, revno, rev_id)
648
 
 
649
 
 
650
 
SPEC_TYPES.append(RevisionSpec_ancestor)
 
720
        return RevisionInfo(branch, revno, revision_id)
 
721
 
 
722
    @staticmethod
 
723
    def _find_revision_id(branch, other_location):
 
724
        from bzrlib.branch import Branch
 
725
 
 
726
        branch.lock_read()
 
727
        try:
 
728
            revision_a = revision.ensure_null(branch.last_revision())
 
729
            if revision_a == revision.NULL_REVISION:
 
730
                raise errors.NoCommits(branch)
 
731
            if other_location == '':
 
732
                other_location = branch.get_parent()
 
733
            other_branch = Branch.open(other_location)
 
734
            other_branch.lock_read()
 
735
            try:
 
736
                revision_b = revision.ensure_null(other_branch.last_revision())
 
737
                if revision_b == revision.NULL_REVISION:
 
738
                    raise errors.NoCommits(other_branch)
 
739
                graph = branch.repository.get_graph(other_branch.repository)
 
740
                rev_id = graph.find_unique_lca(revision_a, revision_b)
 
741
            finally:
 
742
                other_branch.unlock()
 
743
            if rev_id == revision.NULL_REVISION:
 
744
                raise errors.NoCommonAncestor(revision_a, revision_b)
 
745
            return rev_id
 
746
        finally:
 
747
            branch.unlock()
 
748
 
 
749
 
651
750
 
652
751
 
653
752
class RevisionSpec_branch(RevisionSpec):
657
756
 
658
757
    Supply the path to a branch to select its last revision.
659
758
 
660
 
    examples:
 
759
    Examples::
 
760
 
661
761
      branch:/path/to/branch
662
762
    """
663
763
    prefix = 'branch:'
675
775
        except errors.NoSuchRevision:
676
776
            revno = None
677
777
        return RevisionInfo(branch, revno, revision_b)
678
 
        
679
 
SPEC_TYPES.append(RevisionSpec_branch)
 
778
 
 
779
    def _as_revision_id(self, context_branch):
 
780
        from bzrlib.branch import Branch
 
781
        other_branch = Branch.open(self.spec)
 
782
        last_revision = other_branch.last_revision()
 
783
        last_revision = revision.ensure_null(last_revision)
 
784
        context_branch.fetch(other_branch, last_revision)
 
785
        if last_revision == revision.NULL_REVISION:
 
786
            raise errors.NoCommits(other_branch)
 
787
        return last_revision
 
788
 
 
789
    def _as_tree(self, context_branch):
 
790
        from bzrlib.branch import Branch
 
791
        other_branch = Branch.open(self.spec)
 
792
        last_revision = other_branch.last_revision()
 
793
        last_revision = revision.ensure_null(last_revision)
 
794
        if last_revision == revision.NULL_REVISION:
 
795
            raise errors.NoCommits(other_branch)
 
796
        return other_branch.repository.revision_tree(last_revision)
 
797
 
680
798
 
681
799
 
682
800
class RevisionSpec_submit(RevisionSpec_ancestor):
686
804
 
687
805
    Diffing against this shows all the changes that were made in this branch,
688
806
    and is a good predictor of what merge will do.  The submit branch is
689
 
    used by the bundle and merge directive comands.  If no submit branch
 
807
    used by the bundle and merge directive commands.  If no submit branch
690
808
    is specified, the parent branch is used instead.
691
809
 
692
810
    The common ancestor is the last revision that existed in both
693
811
    branches. Usually this is the branch point, but it could also be
694
812
    a revision that was merged.
695
813
 
696
 
    examples:
 
814
    Examples::
 
815
 
697
816
      $ bzr diff -r submit:
698
817
    """
699
818
 
700
819
    prefix = 'submit:'
701
820
 
702
 
    def _match_on(self, branch, revs):
703
 
        trace.mutter('matching ancestor: on: %s, %s', self.spec, branch)
 
821
    def _get_submit_location(self, branch):
704
822
        submit_location = branch.get_submit_branch()
705
823
        location_type = 'submit branch'
706
824
        if submit_location is None:
709
827
        if submit_location is None:
710
828
            raise errors.NoSubmitBranch(branch)
711
829
        trace.note('Using %s %s', location_type, submit_location)
712
 
        return self._find_revision_info(branch, submit_location)
713
 
 
714
 
 
715
 
SPEC_TYPES.append(RevisionSpec_submit)
 
830
        return submit_location
 
831
 
 
832
    def _match_on(self, branch, revs):
 
833
        trace.mutter('matching ancestor: on: %s, %s', self.spec, branch)
 
834
        return self._find_revision_info(branch,
 
835
            self._get_submit_location(branch))
 
836
 
 
837
    def _as_revision_id(self, context_branch):
 
838
        return self._find_revision_id(context_branch,
 
839
            self._get_submit_location(context_branch))
 
840
 
 
841
 
 
842
revspec_registry = registry.Registry()
 
843
def _register_revspec(revspec):
 
844
    revspec_registry.register(revspec.prefix, revspec)
 
845
 
 
846
_register_revspec(RevisionSpec_revno)
 
847
_register_revspec(RevisionSpec_revid)
 
848
_register_revspec(RevisionSpec_last)
 
849
_register_revspec(RevisionSpec_before)
 
850
_register_revspec(RevisionSpec_tag)
 
851
_register_revspec(RevisionSpec_date)
 
852
_register_revspec(RevisionSpec_ancestor)
 
853
_register_revspec(RevisionSpec_branch)
 
854
_register_revspec(RevisionSpec_submit)
 
855
 
 
856
SPEC_TYPES = symbol_versioning.deprecated_list(
 
857
    symbol_versioning.deprecated_in((1, 12, 0)), "SPEC_TYPES", [])