~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/revisionspec.py

(gz) Never raise KnownFailure in tests,
 use knownFailure method instead (Martin [gz])

Show diffs side-by-side

added added

removed removed

Lines of Context:
27
27
    symbol_versioning,
28
28
    workingtree,
29
29
    )
30
 
from bzrlib.i18n import gettext
31
30
""")
32
31
 
33
32
from bzrlib import (
38
37
    )
39
38
 
40
39
 
 
40
_marker = []
 
41
 
 
42
 
41
43
class RevisionInfo(object):
42
44
    """The results of applying a revision specification to a branch."""
43
45
 
55
57
    or treat the result as a tuple.
56
58
    """
57
59
 
58
 
    def __init__(self, branch, revno=None, rev_id=None):
 
60
    def __init__(self, branch, revno, rev_id=_marker):
59
61
        self.branch = branch
60
 
        self._has_revno = (revno is not None)
61
 
        self._revno = revno
62
 
        self.rev_id = rev_id
63
 
        if self.rev_id is None and self._revno is not None:
 
62
        self.revno = revno
 
63
        if rev_id is _marker:
64
64
            # allow caller to be lazy
65
 
            self.rev_id = branch.get_rev_id(self._revno)
66
 
 
67
 
    @property
68
 
    def revno(self):
69
 
        if not self._has_revno and self.rev_id is not None:
70
 
            try:
71
 
                self._revno = self.branch.revision_id_to_revno(self.rev_id)
72
 
            except errors.NoSuchRevision:
73
 
                self._revno = None
74
 
            self._has_revno = True
75
 
        return self._revno
 
65
            if self.revno is None:
 
66
                self.rev_id = None
 
67
            else:
 
68
                self.rev_id = branch.get_rev_id(self.revno)
 
69
        else:
 
70
            self.rev_id = rev_id
76
71
 
77
72
    def __nonzero__(self):
78
73
        # first the easy ones...
108
103
            self.revno, self.rev_id, self.branch)
109
104
 
110
105
    @staticmethod
111
 
    def from_revision_id(branch, revision_id, revs=symbol_versioning.DEPRECATED_PARAMETER):
 
106
    def from_revision_id(branch, revision_id, revs):
112
107
        """Construct a RevisionInfo given just the id.
113
108
 
114
109
        Use this if you don't know or care what the revno is.
115
110
        """
116
 
        if symbol_versioning.deprecated_passed(revs):
117
 
            symbol_versioning.warn(
118
 
                'RevisionInfo.from_revision_id(revs) was deprecated in 2.5.',
119
 
                DeprecationWarning,
120
 
                stacklevel=2)
121
 
        return RevisionInfo(branch, revno=None, rev_id=revision_id)
 
111
        if revision_id == revision.NULL_REVISION:
 
112
            return RevisionInfo(branch, 0, revision_id)
 
113
        try:
 
114
            revno = revs.index(revision_id) + 1
 
115
        except ValueError:
 
116
            revno = None
 
117
        return RevisionInfo(branch, revno, revision_id)
122
118
 
123
119
 
124
120
class RevisionSpec(object):
141
137
    """
142
138
 
143
139
    prefix = None
144
 
    # wants_revision_history has been deprecated in 2.5.
145
 
    wants_revision_history = False
 
140
    wants_revision_history = True
146
141
    dwim_catchable_exceptions = (errors.InvalidRevisionSpec,)
147
142
    """Exceptions that RevisionSpec_dwim._match_on will catch.
148
143
 
213
208
    def in_history(self, branch):
214
209
        if branch:
215
210
            if self.wants_revision_history:
216
 
                symbol_versioning.warn(
217
 
                    "RevisionSpec.wants_revision_history was "
218
 
                    "deprecated in 2.5 (%s)." % self.__class__.__name__,
219
 
                    DeprecationWarning)
220
 
                branch.lock_read()
221
 
                try:
222
 
                    graph = branch.repository.get_graph()
223
 
                    revs = list(graph.iter_lefthand_ancestry(
224
 
                        branch.last_revision(), [revision.NULL_REVISION]))
225
 
                finally:
226
 
                    branch.unlock()
227
 
                revs.reverse()
 
211
                revs = branch.revision_history()
228
212
            else:
229
213
                revs = None
230
214
        else:
310
294
    """
311
295
 
312
296
    help_txt = None
 
297
    # We don't need to build the revision history ourself, that's delegated to
 
298
    # each revspec we try.
 
299
    wants_revision_history = False
313
300
 
314
301
    _revno_regex = lazy_regex.lazy_compile(r'^(?:(\d+(\.\d+)*)|-\d+)(:.*)?$')
315
302
 
393
380
                                   your history is very long.
394
381
    """
395
382
    prefix = 'revno:'
 
383
    wants_revision_history = False
396
384
 
397
385
    def _match_on(self, branch, revs):
398
386
        """Lookup a revision by revision number"""
399
 
        branch, revno, revision_id = self._lookup(branch)
 
387
        branch, revno, revision_id = self._lookup(branch, revs)
400
388
        return RevisionInfo(branch, revno, revision_id)
401
389
 
402
 
    def _lookup(self, branch):
 
390
    def _lookup(self, branch, revs_or_none):
403
391
        loc = self.spec.find(':')
404
392
        if loc == -1:
405
393
            revno_spec = self.spec
429
417
                dotted = True
430
418
 
431
419
        if branch_spec:
432
 
            # the user has overriden the branch to look in.
433
 
            branch = _mod_branch.Branch.open(branch_spec)
 
420
            # the user has override the branch to look in.
 
421
            # we need to refresh the revision_history map and
 
422
            # the branch object.
 
423
            from bzrlib.branch import Branch
 
424
            branch = Branch.open(branch_spec)
 
425
            revs_or_none = None
434
426
 
435
427
        if dotted:
436
428
            try:
440
432
                raise errors.InvalidRevisionSpec(self.user_spec, branch)
441
433
            else:
442
434
                # there is no traditional 'revno' for dotted-decimal revnos.
443
 
                # so for API compatibility we return None.
 
435
                # so for  API compatability we return None.
444
436
                return branch, None, revision_id
445
437
        else:
446
438
            last_revno, last_revision_id = branch.last_revision_info()
452
444
                else:
453
445
                    revno = last_revno + revno + 1
454
446
            try:
455
 
                revision_id = branch.get_rev_id(revno)
 
447
                revision_id = branch.get_rev_id(revno, revs_or_none)
456
448
            except errors.NoSuchRevision:
457
449
                raise errors.InvalidRevisionSpec(self.user_spec, branch)
458
450
        return branch, revno, revision_id
459
451
 
460
452
    def _as_revision_id(self, context_branch):
461
453
        # We would have the revno here, but we don't really care
462
 
        branch, revno, revision_id = self._lookup(context_branch)
 
454
        branch, revno, revision_id = self._lookup(context_branch, None)
463
455
        return revision_id
464
456
 
465
457
    def needs_branch(self):
475
467
RevisionSpec_int = RevisionSpec_revno
476
468
 
477
469
 
 
470
 
478
471
class RevisionIDSpec(RevisionSpec):
479
472
 
480
473
    def _match_on(self, branch, revs):
481
474
        revision_id = self.as_revision_id(branch)
482
 
        return RevisionInfo.from_revision_id(branch, revision_id)
 
475
        return RevisionInfo.from_revision_id(branch, revision_id, revs)
483
476
 
484
477
 
485
478
class RevisionSpec_revid(RevisionIDSpec):
521
514
    prefix = 'last:'
522
515
 
523
516
    def _match_on(self, branch, revs):
524
 
        revno, revision_id = self._revno_and_revision_id(branch)
 
517
        revno, revision_id = self._revno_and_revision_id(branch, revs)
525
518
        return RevisionInfo(branch, revno, revision_id)
526
519
 
527
 
    def _revno_and_revision_id(self, context_branch):
 
520
    def _revno_and_revision_id(self, context_branch, revs_or_none):
528
521
        last_revno, last_revision_id = context_branch.last_revision_info()
529
522
 
530
523
        if self.spec == '':
543
536
 
544
537
        revno = last_revno - offset + 1
545
538
        try:
546
 
            revision_id = context_branch.get_rev_id(revno)
 
539
            revision_id = context_branch.get_rev_id(revno, revs_or_none)
547
540
        except errors.NoSuchRevision:
548
541
            raise errors.InvalidRevisionSpec(self.user_spec, context_branch)
549
542
        return revno, revision_id
551
544
    def _as_revision_id(self, context_branch):
552
545
        # We compute the revno as part of the process, but we don't really care
553
546
        # about it.
554
 
        revno, revision_id = self._revno_and_revision_id(context_branch)
 
547
        revno, revision_id = self._revno_and_revision_id(context_branch, None)
555
548
        return revision_id
556
549
 
557
550
 
589
582
            # We need to use the repository history here
590
583
            rev = branch.repository.get_revision(r.rev_id)
591
584
            if not rev.parent_ids:
 
585
                revno = 0
592
586
                revision_id = revision.NULL_REVISION
593
587
            else:
594
588
                revision_id = rev.parent_ids[0]
595
 
            revno = None
 
589
                try:
 
590
                    revno = revs.index(revision_id) + 1
 
591
                except ValueError:
 
592
                    revno = None
596
593
        else:
597
594
            revno = r.revno - 1
598
595
            try:
603
600
        return RevisionInfo(branch, revno, revision_id)
604
601
 
605
602
    def _as_revision_id(self, context_branch):
606
 
        base_revision_id = RevisionSpec.from_string(self.spec)._as_revision_id(context_branch)
 
603
        base_revspec = RevisionSpec.from_string(self.spec)
 
604
        base_revision_id = base_revspec.as_revision_id(context_branch)
607
605
        if base_revision_id == revision.NULL_REVISION:
608
606
            raise errors.InvalidRevisionSpec(self.user_spec, context_branch,
609
607
                                         'cannot go before the null: revision')
639
637
    def _match_on(self, branch, revs):
640
638
        # Can raise tags not supported, NoSuchTag, etc
641
639
        return RevisionInfo.from_revision_id(branch,
642
 
            branch.tags.lookup_tag(self.spec))
 
640
            branch.tags.lookup_tag(self.spec),
 
641
            revs)
643
642
 
644
643
    def _as_revision_id(self, context_branch):
645
644
        return context_branch.tags.lookup_tag(self.spec)
649
648
class _RevListToTimestamps(object):
650
649
    """This takes a list of revisions, and allows you to bisect by date"""
651
650
 
652
 
    __slots__ = ['branch']
 
651
    __slots__ = ['revs', 'branch']
653
652
 
654
 
    def __init__(self, branch):
 
653
    def __init__(self, revs, branch):
 
654
        self.revs = revs
655
655
        self.branch = branch
656
656
 
657
657
    def __getitem__(self, index):
658
658
        """Get the date of the index'd item"""
659
 
        r = self.branch.repository.get_revision(self.branch.get_rev_id(index))
 
659
        r = self.branch.repository.get_revision(self.revs[index])
660
660
        # TODO: Handle timezone.
661
661
        return datetime.datetime.fromtimestamp(r.timestamp)
662
662
 
663
663
    def __len__(self):
664
 
        return self.branch.revno()
 
664
        return len(self.revs)
665
665
 
666
666
 
667
667
class RevisionSpec_date(RevisionSpec):
741
741
                    hour=hour, minute=minute, second=second)
742
742
        branch.lock_read()
743
743
        try:
744
 
            rev = bisect.bisect(_RevListToTimestamps(branch), dt, 1)
 
744
            rev = bisect.bisect(_RevListToTimestamps(revs, branch), dt)
745
745
        finally:
746
746
            branch.unlock()
747
 
        if rev == branch.revno():
 
747
        if rev == len(revs):
748
748
            raise errors.InvalidRevisionSpec(self.user_spec, branch)
749
 
        return RevisionInfo(branch, rev)
 
749
        else:
 
750
            return RevisionInfo(branch, rev + 1)
750
751
 
751
752
 
752
753
 
783
784
    def _find_revision_info(branch, other_location):
784
785
        revision_id = RevisionSpec_ancestor._find_revision_id(branch,
785
786
                                                              other_location)
786
 
        return RevisionInfo(branch, None, revision_id)
 
787
        try:
 
788
            revno = branch.revision_id_to_revno(revision_id)
 
789
        except errors.NoSuchRevision:
 
790
            revno = None
 
791
        return RevisionInfo(branch, revno, revision_id)
787
792
 
788
793
    @staticmethod
789
794
    def _find_revision_id(branch, other_location):
843
848
                branch.fetch(other_branch, revision_b)
844
849
            except errors.ReadOnlyError:
845
850
                branch = other_branch
846
 
        return RevisionInfo(branch, None, revision_b)
 
851
        try:
 
852
            revno = branch.revision_id_to_revno(revision_b)
 
853
        except errors.NoSuchRevision:
 
854
            revno = None
 
855
        return RevisionInfo(branch, revno, revision_b)
847
856
 
848
857
    def _as_revision_id(self, context_branch):
849
858
        from bzrlib.branch import Branch
901
910
            location_type = 'parent branch'
902
911
        if submit_location is None:
903
912
            raise errors.NoSubmitBranch(branch)
904
 
        trace.note(gettext('Using {0} {1}').format(location_type,
905
 
                                                        submit_location))
 
913
        trace.note('Using %s %s', location_type, submit_location)
906
914
        return submit_location
907
915
 
908
916
    def _match_on(self, branch, revs):