/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to breezy/revisionspec.py

  • Committer: Breezy landing bot
  • Author(s): Colin Watson
  • Date: 2020-11-16 21:47:08 UTC
  • mfrom: (7521.1.1 remove-lp-workaround)
  • Revision ID: breezy.the.bot@gmail.com-20201116214708-jos209mgxi41oy15
Remove breezy.git workaround for bazaar.launchpad.net.

Merged from https://code.launchpad.net/~cjwatson/brz/remove-lp-workaround/+merge/393710

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
 
 
19
 
 
20
 
from bzrlib.lazy_import import lazy_import
 
17
 
 
18
from .lazy_import import lazy_import
21
19
lazy_import(globals(), """
22
20
import bisect
23
21
import datetime
24
22
 
25
 
from bzrlib import (
 
23
from breezy import (
26
24
    branch as _mod_branch,
27
 
    osutils,
 
25
    cache_utf8,
28
26
    revision,
29
 
    symbol_versioning,
30
27
    workingtree,
31
28
    )
32
 
from bzrlib.i18n import gettext
 
29
from breezy.i18n import gettext
33
30
""")
34
31
 
35
 
from bzrlib import (
 
32
from . import (
36
33
    errors,
37
34
    lazy_regex,
38
35
    registry,
40
37
    )
41
38
 
42
39
 
 
40
class InvalidRevisionSpec(errors.BzrError):
 
41
 
 
42
    _fmt = ("Requested revision: '%(spec)s' does not exist in branch:"
 
43
            " %(branch_url)s%(extra)s")
 
44
 
 
45
    def __init__(self, spec, branch, extra=None):
 
46
        errors.BzrError.__init__(self, branch=branch, spec=spec)
 
47
        self.branch_url = getattr(branch, 'user_url', str(branch))
 
48
        if extra:
 
49
            self.extra = '\n' + str(extra)
 
50
        else:
 
51
            self.extra = ''
 
52
 
 
53
 
 
54
class InvalidRevisionSpec(errors.BzrError):
 
55
 
 
56
    _fmt = ("Requested revision: '%(spec)s' does not exist in branch:"
 
57
            " %(branch_url)s%(extra)s")
 
58
 
 
59
    def __init__(self, spec, branch, extra=None):
 
60
        errors.BzrError.__init__(self, branch=branch, spec=spec)
 
61
        self.branch_url = getattr(branch, 'user_url', str(branch))
 
62
        if extra:
 
63
            self.extra = '\n' + str(extra)
 
64
        else:
 
65
            self.extra = ''
 
66
 
 
67
 
43
68
class RevisionInfo(object):
44
69
    """The results of applying a revision specification to a branch."""
45
70
 
71
96
        if not self._has_revno and self.rev_id is not None:
72
97
            try:
73
98
                self._revno = self.branch.revision_id_to_revno(self.rev_id)
74
 
            except errors.NoSuchRevision:
 
99
            except (errors.NoSuchRevision, errors.RevnoOutOfBounds):
75
100
                self._revno = None
76
101
            self._has_revno = True
77
102
        return self._revno
78
103
 
79
 
    def __nonzero__(self):
 
104
    def __bool__(self):
80
105
        if self.rev_id is None:
81
106
            return False
82
107
        # TODO: otherwise, it should depend on how I was built -
84
109
        # if it's in_store(branch), do the check below
85
110
        return self.branch.repository.has_revision(self.rev_id)
86
111
 
 
112
    __nonzero__ = __bool__
 
113
 
87
114
    def __len__(self):
88
115
        return 2
89
116
 
90
117
    def __getitem__(self, index):
91
 
        if index == 0: return self.revno
92
 
        if index == 1: return self.rev_id
 
118
        if index == 0:
 
119
            return self.revno
 
120
        if index == 1:
 
121
            return self.rev_id
93
122
        raise IndexError(index)
94
123
 
95
124
    def get(self):
98
127
    def __eq__(self, other):
99
128
        if type(other) not in (tuple, list, type(self)):
100
129
            return False
101
 
        if type(other) is type(self) and self.branch is not other.branch:
 
130
        if isinstance(other, type(self)) and self.branch is not other.branch:
102
131
            return False
103
132
        return tuple(self) == tuple(other)
104
133
 
105
134
    def __repr__(self):
106
 
        return '<bzrlib.revisionspec.RevisionInfo object %s, %s for %r>' % (
 
135
        return '<breezy.revisionspec.RevisionInfo object %s, %s for %r>' % (
107
136
            self.revno, self.rev_id, self.branch)
108
137
 
109
138
    @staticmethod
110
 
    def from_revision_id(branch, revision_id, revs=symbol_versioning.DEPRECATED_PARAMETER):
 
139
    def from_revision_id(branch, revision_id):
111
140
        """Construct a RevisionInfo given just the id.
112
141
 
113
142
        Use this if you don't know or care what the revno is.
114
143
        """
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
144
        return RevisionInfo(branch, revno=None, rev_id=revision_id)
121
145
 
122
146
 
140
164
    """
141
165
 
142
166
    prefix = None
143
 
    # wants_revision_history has been deprecated in 2.5.
144
 
    wants_revision_history = False
145
 
    dwim_catchable_exceptions = (errors.InvalidRevisionSpec,)
 
167
    dwim_catchable_exceptions = (InvalidRevisionSpec,)
146
168
    """Exceptions that RevisionSpec_dwim._match_on will catch.
147
169
 
148
170
    If the revspec is part of ``dwim_revspecs``, it may be tried with an
159
181
        :return: A RevisionSpec object that understands how to parse the
160
182
            supplied notation.
161
183
        """
162
 
        if not isinstance(spec, (type(None), basestring)):
163
 
            raise TypeError('error')
164
 
 
165
184
        if spec is None:
166
185
            return RevisionSpec(None, _internal=True)
 
186
        if not isinstance(spec, str):
 
187
            raise TypeError("revision spec needs to be text")
167
188
        match = revspec_registry.get_prefix(spec)
168
189
        if match is not None:
169
190
            spectype, specsuffix = match
183
204
            called directly. Only from RevisionSpec.from_string()
184
205
        """
185
206
        if not _internal:
186
 
            symbol_versioning.warn('Creating a RevisionSpec directly has'
187
 
                                   ' been deprecated in version 0.11. Use'
188
 
                                   ' RevisionSpec.from_string()'
189
 
                                   ' instead.',
190
 
                                   DeprecationWarning, stacklevel=2)
 
207
            raise AssertionError(
 
208
                'Creating a RevisionSpec directly is not supported. '
 
209
                'Use RevisionSpec.from_string() instead.')
191
210
        self.user_spec = spec
192
211
        if self.prefix and spec.startswith(self.prefix):
193
212
            spec = spec[len(self.prefix):]
205
224
            # special case - nothing supplied
206
225
            return info
207
226
        elif self.prefix:
208
 
            raise errors.InvalidRevisionSpec(self.user_spec, branch)
 
227
            raise InvalidRevisionSpec(self.user_spec, branch)
209
228
        else:
210
 
            raise errors.InvalidRevisionSpec(self.spec, branch)
 
229
            raise InvalidRevisionSpec(self.spec, branch)
211
230
 
212
231
    def in_history(self, branch):
213
 
        if branch:
214
 
            if self.wants_revision_history:
215
 
                symbol_versioning.warn(
216
 
                    "RevisionSpec.wants_revision_history was "
217
 
                    "deprecated in 2.5 (%s)." % self.__class__.__name__,
218
 
                    DeprecationWarning)
219
 
                branch.lock_read()
220
 
                try:
221
 
                    graph = branch.repository.get_graph()
222
 
                    revs = list(graph.iter_lefthand_ancestry(
223
 
                        branch.last_revision(), [revision.NULL_REVISION]))
224
 
                finally:
225
 
                    branch.unlock()
226
 
                revs.reverse()
227
 
            else:
228
 
                revs = None
229
 
        else:
230
 
            # this should never trigger.
231
 
            # TODO: make it a deprecated code path. RBC 20060928
232
 
            revs = None
233
 
        return self._match_on_and_check(branch, revs)
 
232
        return self._match_on_and_check(branch, revs=None)
234
233
 
235
234
        # FIXME: in_history is somewhat broken,
236
235
        # it will return non-history revisions in many
280
279
    def __repr__(self):
281
280
        # this is mostly for helping with testing
282
281
        return '<%s %s>' % (self.__class__.__name__,
283
 
                              self.user_spec)
 
282
                            self.user_spec)
284
283
 
285
284
    def needs_branch(self):
286
285
        """Whether this revision spec needs a branch.
339
338
            except rs_class.dwim_catchable_exceptions:
340
339
                pass
341
340
 
342
 
        # Try the old (deprecated) dwim list:
343
 
        for rs_class in dwim_revspecs:
344
 
            try:
345
 
                return self._try_spectype(rs_class, branch)
346
 
            except rs_class.dwim_catchable_exceptions:
347
 
                pass
348
 
 
349
341
        # Well, I dunno what it is. Note that we don't try to keep track of the
350
342
        # first of last exception raised during the DWIM tries as none seems
351
343
        # really relevant.
352
 
        raise errors.InvalidRevisionSpec(self.spec, branch)
 
344
        raise InvalidRevisionSpec(self.spec, branch)
353
345
 
354
346
    @classmethod
355
347
    def append_possible_revspec(cls, revspec):
405
397
            branch_spec = None
406
398
        else:
407
399
            revno_spec = self.spec[:loc]
408
 
            branch_spec = self.spec[loc+1:]
 
400
            branch_spec = self.spec[loc + 1:]
409
401
 
410
402
        if revno_spec == '':
411
403
            if not branch_spec:
412
 
                raise errors.InvalidRevisionSpec(self.user_spec,
413
 
                        branch, 'cannot have an empty revno and no branch')
 
404
                raise InvalidRevisionSpec(
 
405
                    self.user_spec, branch,
 
406
                    'cannot have an empty revno and no branch')
414
407
            revno = None
415
408
        else:
416
409
            try:
421
414
                # but the from_string method is a little primitive
422
415
                # right now - RBC 20060928
423
416
                try:
424
 
                    match_revno = tuple((int(number) for number in revno_spec.split('.')))
425
 
                except ValueError, e:
426
 
                    raise errors.InvalidRevisionSpec(self.user_spec, branch, e)
 
417
                    match_revno = tuple((int(number)
 
418
                                         for number in revno_spec.split('.')))
 
419
                except ValueError as e:
 
420
                    raise InvalidRevisionSpec(self.user_spec, branch, e)
427
421
 
428
422
                dotted = True
429
423
 
434
428
        if dotted:
435
429
            try:
436
430
                revision_id = branch.dotted_revno_to_revision_id(match_revno,
437
 
                    _cache_reverse=True)
438
 
            except errors.NoSuchRevision:
439
 
                raise errors.InvalidRevisionSpec(self.user_spec, branch)
 
431
                                                                 _cache_reverse=True)
 
432
            except (errors.NoSuchRevision, errors.RevnoOutOfBounds):
 
433
                raise InvalidRevisionSpec(self.user_spec, branch)
440
434
            else:
441
435
                # there is no traditional 'revno' for dotted-decimal revnos.
442
436
                # so for API compatibility we return None.
452
446
                    revno = last_revno + revno + 1
453
447
            try:
454
448
                revision_id = branch.get_rev_id(revno)
455
 
            except errors.NoSuchRevision:
456
 
                raise errors.InvalidRevisionSpec(self.user_spec, branch)
 
449
            except (errors.NoSuchRevision, errors.RevnoOutOfBounds):
 
450
                raise InvalidRevisionSpec(self.user_spec, branch)
457
451
        return branch, revno, revision_id
458
452
 
459
453
    def _as_revision_id(self, context_branch):
468
462
        if self.spec.find(':') == -1:
469
463
            return None
470
464
        else:
471
 
            return self.spec[self.spec.find(':')+1:]
 
465
            return self.spec[self.spec.find(':') + 1:]
 
466
 
472
467
 
473
468
# Old compatibility
474
469
RevisionSpec_int = RevisionSpec_revno
500
495
        # self.spec comes straight from parsing the command line arguments,
501
496
        # so we expect it to be a Unicode string. Switch it to the internal
502
497
        # representation.
503
 
        return osutils.safe_revision_id(self.spec, warn=False)
504
 
 
 
498
        if isinstance(self.spec, str):
 
499
            return cache_utf8.encode(self.spec)
 
500
        return self.spec
505
501
 
506
502
 
507
503
class RevisionSpec_last(RevisionSpec):
533
529
 
534
530
        try:
535
531
            offset = int(self.spec)
536
 
        except ValueError, e:
537
 
            raise errors.InvalidRevisionSpec(self.user_spec, context_branch, e)
 
532
        except ValueError as e:
 
533
            raise InvalidRevisionSpec(self.user_spec, context_branch, e)
538
534
 
539
535
        if offset <= 0:
540
 
            raise errors.InvalidRevisionSpec(self.user_spec, context_branch,
541
 
                                             'you must supply a positive value')
 
536
            raise InvalidRevisionSpec(
 
537
                self.user_spec, context_branch,
 
538
                'you must supply a positive value')
542
539
 
543
540
        revno = last_revno - offset + 1
544
541
        try:
545
542
            revision_id = context_branch.get_rev_id(revno)
546
 
        except errors.NoSuchRevision:
547
 
            raise errors.InvalidRevisionSpec(self.user_spec, context_branch)
 
543
        except (errors.NoSuchRevision, errors.RevnoOutOfBounds):
 
544
            raise InvalidRevisionSpec(self.user_spec, context_branch)
548
545
        return revno, revision_id
549
546
 
550
547
    def _as_revision_id(self, context_branch):
554
551
        return revision_id
555
552
 
556
553
 
557
 
 
558
554
class RevisionSpec_before(RevisionSpec):
559
555
    """Selects the parent of the revision specified."""
560
556
 
582
578
    def _match_on(self, branch, revs):
583
579
        r = RevisionSpec.from_string(self.spec)._match_on(branch, revs)
584
580
        if r.revno == 0:
585
 
            raise errors.InvalidRevisionSpec(self.user_spec, branch,
586
 
                                         'cannot go before the null: revision')
 
581
            raise InvalidRevisionSpec(
 
582
                self.user_spec, branch,
 
583
                'cannot go before the null: revision')
587
584
        if r.revno is None:
588
585
            # We need to use the repository history here
589
586
            rev = branch.repository.get_revision(r.rev_id)
596
593
            revno = r.revno - 1
597
594
            try:
598
595
                revision_id = branch.get_rev_id(revno, revs)
599
 
            except errors.NoSuchRevision:
600
 
                raise errors.InvalidRevisionSpec(self.user_spec,
601
 
                                                 branch)
 
596
            except (errors.NoSuchRevision, errors.RevnoOutOfBounds):
 
597
                raise InvalidRevisionSpec(self.user_spec, branch)
602
598
        return RevisionInfo(branch, revno, revision_id)
603
599
 
604
600
    def _as_revision_id(self, context_branch):
605
 
        base_revision_id = RevisionSpec.from_string(self.spec)._as_revision_id(context_branch)
 
601
        base_revision_id = RevisionSpec.from_string(
 
602
            self.spec)._as_revision_id(context_branch)
606
603
        if base_revision_id == revision.NULL_REVISION:
607
 
            raise errors.InvalidRevisionSpec(self.user_spec, context_branch,
608
 
                                         'cannot go before the null: revision')
 
604
            raise InvalidRevisionSpec(
 
605
                self.user_spec, context_branch,
 
606
                'cannot go before the null: revision')
609
607
        context_repo = context_branch.repository
610
 
        context_repo.lock_read()
611
 
        try:
 
608
        with context_repo.lock_read():
612
609
            parent_map = context_repo.get_parent_map([base_revision_id])
613
 
        finally:
614
 
            context_repo.unlock()
615
610
        if base_revision_id not in parent_map:
616
611
            # Ghost, or unknown revision id
617
 
            raise errors.InvalidRevisionSpec(self.user_spec, context_branch,
618
 
                'cannot find the matching revision')
 
612
            raise InvalidRevisionSpec(
 
613
                self.user_spec, context_branch, 'cannot find the matching revision')
619
614
        parents = parent_map[base_revision_id]
620
615
        if len(parents) < 1:
621
 
            raise errors.InvalidRevisionSpec(self.user_spec, context_branch,
622
 
                'No parents for revision.')
 
616
            raise InvalidRevisionSpec(
 
617
                self.user_spec, context_branch, 'No parents for revision.')
623
618
        return parents[0]
624
619
 
625
620
 
626
 
 
627
621
class RevisionSpec_tag(RevisionSpec):
628
622
    """Select a revision identified by tag name"""
629
623
 
638
632
    def _match_on(self, branch, revs):
639
633
        # Can raise tags not supported, NoSuchTag, etc
640
634
        return RevisionInfo.from_revision_id(branch,
641
 
            branch.tags.lookup_tag(self.spec))
 
635
                                             branch.tags.lookup_tag(self.spec))
642
636
 
643
637
    def _as_revision_id(self, context_branch):
644
638
        return context_branch.tags.lookup_tag(self.spec)
645
639
 
646
640
 
647
 
 
648
641
class _RevListToTimestamps(object):
649
642
    """This takes a list of revisions, and allows you to bisect by date"""
650
643
 
675
668
 
676
669
    One way to display all the changes since yesterday would be::
677
670
 
678
 
        bzr log -r date:yesterday..
 
671
        brz log -r date:yesterday..
679
672
 
680
673
    Examples::
681
674
 
685
678
    """
686
679
    prefix = 'date:'
687
680
    _date_regex = lazy_regex.lazy_compile(
688
 
            r'(?P<date>(?P<year>\d\d\d\d)-(?P<month>\d\d)-(?P<day>\d\d))?'
689
 
            r'(,|T)?\s*'
690
 
            r'(?P<time>(?P<hour>\d\d):(?P<minute>\d\d)(:(?P<second>\d\d))?)?'
 
681
        r'(?P<date>(?P<year>\d\d\d\d)-(?P<month>\d\d)-(?P<day>\d\d))?'
 
682
        r'(,|T)?\s*'
 
683
        r'(?P<time>(?P<hour>\d\d):(?P<minute>\d\d)(:(?P<second>\d\d))?)?'
691
684
        )
692
685
 
693
686
    def _match_on(self, branch, revs):
700
693
        #  XXX: This doesn't actually work
701
694
        #  So the proper way of saying 'give me all entries for today' is:
702
695
        #      -r date:yesterday..date:today
703
 
        today = datetime.datetime.fromordinal(datetime.date.today().toordinal())
 
696
        today = datetime.datetime.fromordinal(
 
697
            datetime.date.today().toordinal())
704
698
        if self.spec.lower() == 'yesterday':
705
699
            dt = today - datetime.timedelta(days=1)
706
700
        elif self.spec.lower() == 'today':
710
704
        else:
711
705
            m = self._date_regex.match(self.spec)
712
706
            if not m or (not m.group('date') and not m.group('time')):
713
 
                raise errors.InvalidRevisionSpec(self.user_spec,
714
 
                                                 branch, 'invalid date')
 
707
                raise InvalidRevisionSpec(
 
708
                    self.user_spec, branch, 'invalid date')
715
709
 
716
710
            try:
717
711
                if m.group('date'):
731
725
                    else:
732
726
                        second = 0
733
727
                else:
734
 
                    hour, minute, second = 0,0,0
 
728
                    hour, minute, second = 0, 0, 0
735
729
            except ValueError:
736
 
                raise errors.InvalidRevisionSpec(self.user_spec,
737
 
                                                 branch, 'invalid date')
 
730
                raise InvalidRevisionSpec(
 
731
                    self.user_spec, branch, 'invalid date')
738
732
 
739
733
            dt = datetime.datetime(year=year, month=month, day=day,
740
 
                    hour=hour, minute=minute, second=second)
741
 
        branch.lock_read()
742
 
        try:
 
734
                                   hour=hour, minute=minute, second=second)
 
735
        with branch.lock_read():
743
736
            rev = bisect.bisect(_RevListToTimestamps(branch), dt, 1)
744
 
        finally:
745
 
            branch.unlock()
746
737
        if rev == branch.revno():
747
 
            raise errors.InvalidRevisionSpec(self.user_spec, branch)
 
738
            raise InvalidRevisionSpec(self.user_spec, branch)
748
739
        return RevisionInfo(branch, rev)
749
740
 
750
741
 
751
 
 
752
742
class RevisionSpec_ancestor(RevisionSpec):
753
743
    """Selects a common ancestor with a second branch."""
754
744
 
786
776
 
787
777
    @staticmethod
788
778
    def _find_revision_id(branch, other_location):
789
 
        from bzrlib.branch import Branch
 
779
        from .branch import Branch
790
780
 
791
 
        branch.lock_read()
792
 
        try:
 
781
        with branch.lock_read():
793
782
            revision_a = revision.ensure_null(branch.last_revision())
794
783
            if revision_a == revision.NULL_REVISION:
795
784
                raise errors.NoCommits(branch)
796
785
            if other_location == '':
797
786
                other_location = branch.get_parent()
798
787
            other_branch = Branch.open(other_location)
799
 
            other_branch.lock_read()
800
 
            try:
 
788
            with other_branch.lock_read():
801
789
                revision_b = revision.ensure_null(other_branch.last_revision())
802
790
                if revision_b == revision.NULL_REVISION:
803
791
                    raise errors.NoCommits(other_branch)
804
792
                graph = branch.repository.get_graph(other_branch.repository)
805
793
                rev_id = graph.find_unique_lca(revision_a, revision_b)
806
 
            finally:
807
 
                other_branch.unlock()
808
794
            if rev_id == revision.NULL_REVISION:
809
795
                raise errors.NoCommonAncestor(revision_a, revision_b)
810
796
            return rev_id
811
 
        finally:
812
 
            branch.unlock()
813
 
 
814
 
 
815
797
 
816
798
 
817
799
class RevisionSpec_branch(RevisionSpec):
829
811
    dwim_catchable_exceptions = (errors.NotBranchError,)
830
812
 
831
813
    def _match_on(self, branch, revs):
832
 
        from bzrlib.branch import Branch
 
814
        from .branch import Branch
833
815
        other_branch = Branch.open(self.spec)
834
816
        revision_b = other_branch.last_revision()
835
817
        if revision_b in (None, revision.NULL_REVISION):
845
827
        return RevisionInfo(branch, None, revision_b)
846
828
 
847
829
    def _as_revision_id(self, context_branch):
848
 
        from bzrlib.branch import Branch
 
830
        from .branch import Branch
849
831
        other_branch = Branch.open(self.spec)
850
832
        last_revision = other_branch.last_revision()
851
833
        last_revision = revision.ensure_null(last_revision)
855
837
        return last_revision
856
838
 
857
839
    def _as_tree(self, context_branch):
858
 
        from bzrlib.branch import Branch
 
840
        from .branch import Branch
859
841
        other_branch = Branch.open(self.spec)
860
842
        last_revision = other_branch.last_revision()
861
843
        last_revision = revision.ensure_null(last_revision)
870
852
        return self.spec
871
853
 
872
854
 
873
 
 
874
855
class RevisionSpec_submit(RevisionSpec_ancestor):
875
856
    """Selects a common ancestor with a submit branch."""
876
857
 
901
882
        if submit_location is None:
902
883
            raise errors.NoSubmitBranch(branch)
903
884
        trace.note(gettext('Using {0} {1}').format(location_type,
904
 
                                                        submit_location))
 
885
                                                   submit_location))
905
886
        return submit_location
906
887
 
907
888
    def _match_on(self, branch, revs):
908
889
        trace.mutter('matching ancestor: on: %s, %s', self.spec, branch)
909
890
        return self._find_revision_info(branch,
910
 
            self._get_submit_location(branch))
 
891
                                        self._get_submit_location(branch))
911
892
 
912
893
    def _as_revision_id(self, context_branch):
913
894
        return self._find_revision_id(context_branch,
914
 
            self._get_submit_location(context_branch))
 
895
                                      self._get_submit_location(context_branch))
915
896
 
916
897
 
917
898
class RevisionSpec_annotate(RevisionIDSpec):
927
908
    """
928
909
 
929
910
    def _raise_invalid(self, numstring, context_branch):
930
 
        raise errors.InvalidRevisionSpec(self.user_spec, context_branch,
 
911
        raise InvalidRevisionSpec(
 
912
            self.user_spec, context_branch,
931
913
            'No such line: %s' % numstring)
932
914
 
933
915
    def _as_revision_id(self, context_branch):
937
919
        except ValueError:
938
920
            self._raise_invalid(numstring, context_branch)
939
921
        tree, file_path = workingtree.WorkingTree.open_containing(path)
940
 
        tree.lock_read()
941
 
        try:
942
 
            file_id = tree.path2id(file_path)
943
 
            if file_id is None:
944
 
                raise errors.InvalidRevisionSpec(self.user_spec,
945
 
                    context_branch, "File '%s' is not versioned." %
946
 
                    file_path)
947
 
            revision_ids = [r for (r, l) in tree.annotate_iter(file_id)]
948
 
        finally:
949
 
            tree.unlock()
 
922
        with tree.lock_read():
 
923
            if not tree.has_filename(file_path):
 
924
                raise InvalidRevisionSpec(
 
925
                    self.user_spec, context_branch,
 
926
                    "File '%s' is not versioned." % file_path)
 
927
            revision_ids = [r for (r, l) in tree.annotate_iter(file_path)]
950
928
        try:
951
929
            revision_id = revision_ids[index]
952
930
        except IndexError:
953
931
            self._raise_invalid(numstring, context_branch)
954
932
        if revision_id == revision.CURRENT_REVISION:
955
 
            raise errors.InvalidRevisionSpec(self.user_spec, context_branch,
 
933
            raise InvalidRevisionSpec(
 
934
                self.user_spec, context_branch,
956
935
                'Line %s has not been committed.' % numstring)
957
936
        return revision_id
958
937
 
977
956
        result = graph.find_lefthand_merger(revision_id,
978
957
                                            context_branch.last_revision())
979
958
        if result is None:
980
 
            raise errors.InvalidRevisionSpec(self.user_spec, context_branch)
 
959
            raise InvalidRevisionSpec(self.user_spec, context_branch)
981
960
        return result
982
961
 
983
962
 
984
963
# The order in which we want to DWIM a revision spec without any prefix.
985
964
# revno is always tried first and isn't listed here, this is used by
986
965
# RevisionSpec_dwim._match_on
987
 
dwim_revspecs = symbol_versioning.deprecated_list(
988
 
    symbol_versioning.deprecated_in((2, 4, 0)), "dwim_revspecs", [])
989
 
 
990
966
RevisionSpec_dwim.append_possible_revspec(RevisionSpec_tag)
991
967
RevisionSpec_dwim.append_possible_revspec(RevisionSpec_revid)
992
968
RevisionSpec_dwim.append_possible_revspec(RevisionSpec_date)
993
969
RevisionSpec_dwim.append_possible_revspec(RevisionSpec_branch)
994
970
 
995
971
revspec_registry = registry.Registry()
 
972
 
 
973
 
996
974
def _register_revspec(revspec):
997
975
    revspec_registry.register(revspec.prefix, revspec)
998
976
 
 
977
 
999
978
_register_revspec(RevisionSpec_revno)
1000
979
_register_revspec(RevisionSpec_revid)
1001
980
_register_revspec(RevisionSpec_last)