~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/revisionspec.py

  • Committer: Jelmer Vernooij
  • Date: 2012-02-18 16:55:04 UTC
  • mfrom: (6437.23.10 2.5)
  • mto: This revision was merged to the branch mainline in revision 6469.
  • Revision ID: jelmer@samba.org-20120218165504-c9oe5c5ue805y8wp
Merge bzr/2.5.

Show diffs side-by-side

added added

removed removed

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