~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/revisionspec.py

  • Committer: Martin Packman
  • Date: 2011-12-08 19:00:14 UTC
  • mto: This revision was merged to the branch mainline in revision 6359.
  • Revision ID: martin.packman@canonical.com-20111208190014-mi8jm6v7jygmhb0r
Use --include-duplicates for make update-pot which already combines multiple msgid strings prettily

Show diffs side-by-side

added added

removed removed

Lines of Context:
38
38
    )
39
39
 
40
40
 
41
 
_marker = []
42
 
 
43
 
 
44
41
class RevisionInfo(object):
45
42
    """The results of applying a revision specification to a branch."""
46
43
 
58
55
    or treat the result as a tuple.
59
56
    """
60
57
 
61
 
    def __init__(self, branch, revno, rev_id=_marker):
 
58
    def __init__(self, branch, revno=None, rev_id=None):
62
59
        self.branch = branch
63
 
        self.revno = revno
64
 
        if rev_id is _marker:
 
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:
65
64
            # allow caller to be lazy
66
 
            if self.revno is None:
67
 
                self.rev_id = None
68
 
            else:
69
 
                self.rev_id = branch.get_rev_id(self.revno)
70
 
        else:
71
 
            self.rev_id = rev_id
 
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
72
76
 
73
77
    def __nonzero__(self):
74
78
        # first the easy ones...
104
108
            self.revno, self.rev_id, self.branch)
105
109
 
106
110
    @staticmethod
107
 
    def from_revision_id(branch, revision_id, revs):
 
111
    def from_revision_id(branch, revision_id, revs=symbol_versioning.DEPRECATED_PARAMETER):
108
112
        """Construct a RevisionInfo given just the id.
109
113
 
110
114
        Use this if you don't know or care what the revno is.
111
115
        """
112
 
        if revision_id == revision.NULL_REVISION:
113
 
            return RevisionInfo(branch, 0, revision_id)
114
 
        try:
115
 
            revno = revs.index(revision_id) + 1
116
 
        except ValueError:
117
 
            revno = None
118
 
        return RevisionInfo(branch, revno, revision_id)
 
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)
119
122
 
120
123
 
121
124
class RevisionSpec(object):
138
141
    """
139
142
 
140
143
    prefix = None
141
 
    wants_revision_history = True
 
144
    # wants_revision_history has been deprecated in 2.5.
 
145
    wants_revision_history = False
142
146
    dwim_catchable_exceptions = (errors.InvalidRevisionSpec,)
143
147
    """Exceptions that RevisionSpec_dwim._match_on will catch.
144
148
 
209
213
    def in_history(self, branch):
210
214
        if branch:
211
215
            if self.wants_revision_history:
212
 
                # TODO: avoid looking at all of history
 
216
                symbol_versioning.warn(
 
217
                    "RevisionSpec.wants_revision_history was "
 
218
                    "deprecated in 2.5 (%s)." % self.__class__.__name__,
 
219
                    DeprecationWarning)
213
220
                branch.lock_read()
214
221
                try:
215
222
                    graph = branch.repository.get_graph()
303
310
    """
304
311
 
305
312
    help_txt = None
306
 
    # We don't need to build the revision history ourself, that's delegated to
307
 
    # each revspec we try.
308
 
    wants_revision_history = False
309
313
 
310
314
    _revno_regex = lazy_regex.lazy_compile(r'^(?:(\d+(\.\d+)*)|-\d+)(:.*)?$')
311
315
 
389
393
                                   your history is very long.
390
394
    """
391
395
    prefix = 'revno:'
392
 
    wants_revision_history = False
393
396
 
394
397
    def _match_on(self, branch, revs):
395
398
        """Lookup a revision by revision number"""
396
 
        branch, revno, revision_id = self._lookup(branch, revs)
 
399
        branch, revno, revision_id = self._lookup(branch)
397
400
        return RevisionInfo(branch, revno, revision_id)
398
401
 
399
 
    def _lookup(self, branch, revs_or_none):
 
402
    def _lookup(self, branch):
400
403
        loc = self.spec.find(':')
401
404
        if loc == -1:
402
405
            revno_spec = self.spec
426
429
                dotted = True
427
430
 
428
431
        if branch_spec:
429
 
            # the user has override the branch to look in.
430
 
            # we need to refresh the revision_history map and
431
 
            # the branch object.
432
 
            from bzrlib.branch import Branch
433
 
            branch = Branch.open(branch_spec)
434
 
            revs_or_none = None
 
432
            # the user has overriden the branch to look in.
 
433
            branch = _mod_branch.Branch.open(branch_spec)
435
434
 
436
435
        if dotted:
437
436
            try:
441
440
                raise errors.InvalidRevisionSpec(self.user_spec, branch)
442
441
            else:
443
442
                # there is no traditional 'revno' for dotted-decimal revnos.
444
 
                # so for  API compatability we return None.
 
443
                # so for API compatibility we return None.
445
444
                return branch, None, revision_id
446
445
        else:
447
446
            last_revno, last_revision_id = branch.last_revision_info()
453
452
                else:
454
453
                    revno = last_revno + revno + 1
455
454
            try:
456
 
                revision_id = branch.get_rev_id(revno, revs_or_none)
 
455
                revision_id = branch.get_rev_id(revno)
457
456
            except errors.NoSuchRevision:
458
457
                raise errors.InvalidRevisionSpec(self.user_spec, branch)
459
458
        return branch, revno, revision_id
460
459
 
461
460
    def _as_revision_id(self, context_branch):
462
461
        # We would have the revno here, but we don't really care
463
 
        branch, revno, revision_id = self._lookup(context_branch, None)
 
462
        branch, revno, revision_id = self._lookup(context_branch)
464
463
        return revision_id
465
464
 
466
465
    def needs_branch(self):
476
475
RevisionSpec_int = RevisionSpec_revno
477
476
 
478
477
 
479
 
 
480
478
class RevisionIDSpec(RevisionSpec):
481
479
 
482
480
    def _match_on(self, branch, revs):
483
481
        revision_id = self.as_revision_id(branch)
484
 
        return RevisionInfo.from_revision_id(branch, revision_id, revs)
 
482
        return RevisionInfo.from_revision_id(branch, revision_id)
485
483
 
486
484
 
487
485
class RevisionSpec_revid(RevisionIDSpec):
523
521
    prefix = 'last:'
524
522
 
525
523
    def _match_on(self, branch, revs):
526
 
        revno, revision_id = self._revno_and_revision_id(branch, revs)
 
524
        revno, revision_id = self._revno_and_revision_id(branch)
527
525
        return RevisionInfo(branch, revno, revision_id)
528
526
 
529
 
    def _revno_and_revision_id(self, context_branch, revs_or_none):
 
527
    def _revno_and_revision_id(self, context_branch):
530
528
        last_revno, last_revision_id = context_branch.last_revision_info()
531
529
 
532
530
        if self.spec == '':
545
543
 
546
544
        revno = last_revno - offset + 1
547
545
        try:
548
 
            revision_id = context_branch.get_rev_id(revno, revs_or_none)
 
546
            revision_id = context_branch.get_rev_id(revno)
549
547
        except errors.NoSuchRevision:
550
548
            raise errors.InvalidRevisionSpec(self.user_spec, context_branch)
551
549
        return revno, revision_id
553
551
    def _as_revision_id(self, context_branch):
554
552
        # We compute the revno as part of the process, but we don't really care
555
553
        # about it.
556
 
        revno, revision_id = self._revno_and_revision_id(context_branch, None)
 
554
        revno, revision_id = self._revno_and_revision_id(context_branch)
557
555
        return revision_id
558
556
 
559
557
 
591
589
            # We need to use the repository history here
592
590
            rev = branch.repository.get_revision(r.rev_id)
593
591
            if not rev.parent_ids:
594
 
                revno = 0
595
592
                revision_id = revision.NULL_REVISION
596
593
            else:
597
594
                revision_id = rev.parent_ids[0]
598
 
                try:
599
 
                    revno = revs.index(revision_id) + 1
600
 
                except ValueError:
601
 
                    revno = None
 
595
            revno = None
602
596
        else:
603
597
            revno = r.revno - 1
604
598
            try:
609
603
        return RevisionInfo(branch, revno, revision_id)
610
604
 
611
605
    def _as_revision_id(self, context_branch):
612
 
        base_revspec = RevisionSpec.from_string(self.spec)
613
 
        base_revision_id = base_revspec.as_revision_id(context_branch)
 
606
        base_revision_id = RevisionSpec.from_string(self.spec)._as_revision_id(context_branch)
614
607
        if base_revision_id == revision.NULL_REVISION:
615
608
            raise errors.InvalidRevisionSpec(self.user_spec, context_branch,
616
609
                                         'cannot go before the null: revision')
646
639
    def _match_on(self, branch, revs):
647
640
        # Can raise tags not supported, NoSuchTag, etc
648
641
        return RevisionInfo.from_revision_id(branch,
649
 
            branch.tags.lookup_tag(self.spec),
650
 
            revs)
 
642
            branch.tags.lookup_tag(self.spec))
651
643
 
652
644
    def _as_revision_id(self, context_branch):
653
645
        return context_branch.tags.lookup_tag(self.spec)
657
649
class _RevListToTimestamps(object):
658
650
    """This takes a list of revisions, and allows you to bisect by date"""
659
651
 
660
 
    __slots__ = ['revs', 'branch']
 
652
    __slots__ = ['branch']
661
653
 
662
 
    def __init__(self, revs, branch):
663
 
        self.revs = revs
 
654
    def __init__(self, branch):
664
655
        self.branch = branch
665
656
 
666
657
    def __getitem__(self, index):
667
658
        """Get the date of the index'd item"""
668
 
        r = self.branch.repository.get_revision(self.revs[index])
 
659
        r = self.branch.repository.get_revision(self.branch.get_rev_id(index))
669
660
        # TODO: Handle timezone.
670
661
        return datetime.datetime.fromtimestamp(r.timestamp)
671
662
 
672
663
    def __len__(self):
673
 
        return len(self.revs)
 
664
        return self.branch.revno()
674
665
 
675
666
 
676
667
class RevisionSpec_date(RevisionSpec):
750
741
                    hour=hour, minute=minute, second=second)
751
742
        branch.lock_read()
752
743
        try:
753
 
            rev = bisect.bisect(_RevListToTimestamps(revs, branch), dt)
 
744
            rev = bisect.bisect(_RevListToTimestamps(branch), dt, 1)
754
745
        finally:
755
746
            branch.unlock()
756
 
        if rev == len(revs):
 
747
        if rev == branch.revno():
757
748
            raise errors.InvalidRevisionSpec(self.user_spec, branch)
758
 
        else:
759
 
            return RevisionInfo(branch, rev + 1)
 
749
        return RevisionInfo(branch, rev)
760
750
 
761
751
 
762
752
 
793
783
    def _find_revision_info(branch, other_location):
794
784
        revision_id = RevisionSpec_ancestor._find_revision_id(branch,
795
785
                                                              other_location)
796
 
        try:
797
 
            revno = branch.revision_id_to_revno(revision_id)
798
 
        except errors.NoSuchRevision:
799
 
            revno = None
800
 
        return RevisionInfo(branch, revno, revision_id)
 
786
        return RevisionInfo(branch, None, revision_id)
801
787
 
802
788
    @staticmethod
803
789
    def _find_revision_id(branch, other_location):
857
843
                branch.fetch(other_branch, revision_b)
858
844
            except errors.ReadOnlyError:
859
845
                branch = other_branch
860
 
        try:
861
 
            revno = branch.revision_id_to_revno(revision_b)
862
 
        except errors.NoSuchRevision:
863
 
            revno = None
864
 
        return RevisionInfo(branch, revno, revision_b)
 
846
        return RevisionInfo(branch, None, revision_b)
865
847
 
866
848
    def _as_revision_id(self, context_branch):
867
849
        from bzrlib.branch import Branch