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
17
from __future__ import absolute_import
18
20
from .lazy_import import lazy_import
19
21
lazy_import(globals(), """
40
class InvalidRevisionSpec(errors.BzrError):
42
_fmt = ("Requested revision: '%(spec)s' does not exist in branch:"
43
" %(branch_url)s%(extra)s")
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))
49
self.extra = '\n' + str(extra)
54
class InvalidRevisionSpec(errors.BzrError):
56
_fmt = ("Requested revision: '%(spec)s' does not exist in branch:"
57
" %(branch_url)s%(extra)s")
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))
63
self.extra = '\n' + str(extra)
68
42
class RevisionInfo(object):
69
43
"""The results of applying a revision specification to a branch."""
167
dwim_catchable_exceptions = (InvalidRevisionSpec,)
141
dwim_catchable_exceptions = (errors.InvalidRevisionSpec,)
168
142
"""Exceptions that RevisionSpec_dwim._match_on will catch.
170
144
If the revspec is part of ``dwim_revspecs``, it may be tried with an
224
198
# special case - nothing supplied
226
200
elif self.prefix:
227
raise InvalidRevisionSpec(self.user_spec, branch)
201
raise errors.InvalidRevisionSpec(self.user_spec, branch)
229
raise InvalidRevisionSpec(self.spec, branch)
203
raise errors.InvalidRevisionSpec(self.spec, branch)
231
205
def in_history(self, branch):
232
206
return self._match_on_and_check(branch, revs=None)
341
315
# Well, I dunno what it is. Note that we don't try to keep track of the
342
316
# first of last exception raised during the DWIM tries as none seems
343
317
# really relevant.
344
raise InvalidRevisionSpec(self.spec, branch)
318
raise errors.InvalidRevisionSpec(self.spec, branch)
347
321
def append_possible_revspec(cls, revspec):
402
376
if revno_spec == '':
403
377
if not branch_spec:
404
raise InvalidRevisionSpec(
405
self.user_spec, branch,
406
'cannot have an empty revno and no branch')
378
raise errors.InvalidRevisionSpec(self.user_spec,
379
branch, 'cannot have an empty revno and no branch')
417
390
match_revno = tuple((int(number)
418
391
for number in revno_spec.split('.')))
419
392
except ValueError as e:
420
raise InvalidRevisionSpec(self.user_spec, branch, e)
393
raise errors.InvalidRevisionSpec(self.user_spec, branch, e)
430
403
revision_id = branch.dotted_revno_to_revision_id(match_revno,
431
404
_cache_reverse=True)
432
405
except (errors.NoSuchRevision, errors.RevnoOutOfBounds):
433
raise InvalidRevisionSpec(self.user_spec, branch)
406
raise errors.InvalidRevisionSpec(self.user_spec, branch)
435
408
# there is no traditional 'revno' for dotted-decimal revnos.
436
409
# so for API compatibility we return None.
448
421
revision_id = branch.get_rev_id(revno)
449
422
except (errors.NoSuchRevision, errors.RevnoOutOfBounds):
450
raise InvalidRevisionSpec(self.user_spec, branch)
423
raise errors.InvalidRevisionSpec(self.user_spec, branch)
451
424
return branch, revno, revision_id
453
426
def _as_revision_id(self, context_branch):
531
504
offset = int(self.spec)
532
505
except ValueError as e:
533
raise InvalidRevisionSpec(self.user_spec, context_branch, e)
506
raise errors.InvalidRevisionSpec(self.user_spec, context_branch, e)
536
raise InvalidRevisionSpec(
537
self.user_spec, context_branch,
538
'you must supply a positive value')
509
raise errors.InvalidRevisionSpec(self.user_spec, context_branch,
510
'you must supply a positive value')
540
512
revno = last_revno - offset + 1
542
514
revision_id = context_branch.get_rev_id(revno)
543
515
except (errors.NoSuchRevision, errors.RevnoOutOfBounds):
544
raise InvalidRevisionSpec(self.user_spec, context_branch)
516
raise errors.InvalidRevisionSpec(self.user_spec, context_branch)
545
517
return revno, revision_id
547
519
def _as_revision_id(self, context_branch):
578
550
def _match_on(self, branch, revs):
579
551
r = RevisionSpec.from_string(self.spec)._match_on(branch, revs)
581
raise InvalidRevisionSpec(
582
self.user_spec, branch,
583
'cannot go before the null: revision')
553
raise errors.InvalidRevisionSpec(self.user_spec, branch,
554
'cannot go before the null: revision')
584
555
if r.revno is None:
585
556
# We need to use the repository history here
586
557
rev = branch.repository.get_revision(r.rev_id)
595
566
revision_id = branch.get_rev_id(revno, revs)
596
567
except (errors.NoSuchRevision, errors.RevnoOutOfBounds):
597
raise InvalidRevisionSpec(self.user_spec, branch)
568
raise errors.InvalidRevisionSpec(self.user_spec,
598
570
return RevisionInfo(branch, revno, revision_id)
600
572
def _as_revision_id(self, context_branch):
601
573
base_revision_id = RevisionSpec.from_string(
602
574
self.spec)._as_revision_id(context_branch)
603
575
if base_revision_id == revision.NULL_REVISION:
604
raise InvalidRevisionSpec(
605
self.user_spec, context_branch,
606
'cannot go before the null: revision')
576
raise errors.InvalidRevisionSpec(self.user_spec, context_branch,
577
'cannot go before the null: revision')
607
578
context_repo = context_branch.repository
608
579
with context_repo.lock_read():
609
580
parent_map = context_repo.get_parent_map([base_revision_id])
610
581
if base_revision_id not in parent_map:
611
582
# Ghost, or unknown revision id
612
raise InvalidRevisionSpec(
613
self.user_spec, context_branch, 'cannot find the matching revision')
583
raise errors.InvalidRevisionSpec(self.user_spec, context_branch,
584
'cannot find the matching revision')
614
585
parents = parent_map[base_revision_id]
615
586
if len(parents) < 1:
616
raise InvalidRevisionSpec(
617
self.user_spec, context_branch, 'No parents for revision.')
587
raise errors.InvalidRevisionSpec(self.user_spec, context_branch,
588
'No parents for revision.')
618
589
return parents[0]
705
676
m = self._date_regex.match(self.spec)
706
677
if not m or (not m.group('date') and not m.group('time')):
707
raise InvalidRevisionSpec(
708
self.user_spec, branch, 'invalid date')
678
raise errors.InvalidRevisionSpec(self.user_spec,
679
branch, 'invalid date')
711
682
if m.group('date'):
728
699
hour, minute, second = 0, 0, 0
729
700
except ValueError:
730
raise InvalidRevisionSpec(
731
self.user_spec, branch, 'invalid date')
701
raise errors.InvalidRevisionSpec(self.user_spec,
702
branch, 'invalid date')
733
704
dt = datetime.datetime(year=year, month=month, day=day,
734
705
hour=hour, minute=minute, second=second)
735
706
with branch.lock_read():
736
707
rev = bisect.bisect(_RevListToTimestamps(branch), dt, 1)
737
708
if rev == branch.revno():
738
raise InvalidRevisionSpec(self.user_spec, branch)
709
raise errors.InvalidRevisionSpec(self.user_spec, branch)
739
710
return RevisionInfo(branch, rev)
910
881
def _raise_invalid(self, numstring, context_branch):
911
raise InvalidRevisionSpec(
912
self.user_spec, context_branch,
913
'No such line: %s' % numstring)
882
raise errors.InvalidRevisionSpec(self.user_spec, context_branch,
883
'No such line: %s' % numstring)
915
885
def _as_revision_id(self, context_branch):
916
886
path, numstring = self.spec.rsplit(':', 1)
921
891
tree, file_path = workingtree.WorkingTree.open_containing(path)
922
892
with tree.lock_read():
923
893
if not tree.has_filename(file_path):
924
raise InvalidRevisionSpec(
925
self.user_spec, context_branch,
926
"File '%s' is not versioned." % file_path)
894
raise errors.InvalidRevisionSpec(self.user_spec,
895
context_branch, "File '%s' is not versioned." %
927
897
revision_ids = [r for (r, l) in tree.annotate_iter(file_path)]
929
899
revision_id = revision_ids[index]
930
900
except IndexError:
931
901
self._raise_invalid(numstring, context_branch)
932
902
if revision_id == revision.CURRENT_REVISION:
933
raise InvalidRevisionSpec(
934
self.user_spec, context_branch,
935
'Line %s has not been committed.' % numstring)
903
raise errors.InvalidRevisionSpec(self.user_spec, context_branch,
904
'Line %s has not been committed.' % numstring)
936
905
return revision_id
956
925
result = graph.find_lefthand_merger(revision_id,
957
926
context_branch.last_revision())
958
927
if result is None:
959
raise InvalidRevisionSpec(self.user_spec, context_branch)
928
raise errors.InvalidRevisionSpec(self.user_spec, context_branch)