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)
40
68
class RevisionInfo(object):
41
69
"""The results of applying a revision specification to a branch."""
139
dwim_catchable_exceptions = (errors.InvalidRevisionSpec,)
167
dwim_catchable_exceptions = (InvalidRevisionSpec,)
140
168
"""Exceptions that RevisionSpec_dwim._match_on will catch.
142
170
If the revspec is part of ``dwim_revspecs``, it may be tried with an
196
224
# special case - nothing supplied
198
226
elif self.prefix:
199
raise errors.InvalidRevisionSpec(self.user_spec, branch)
227
raise InvalidRevisionSpec(self.user_spec, branch)
201
raise errors.InvalidRevisionSpec(self.spec, branch)
229
raise InvalidRevisionSpec(self.spec, branch)
203
231
def in_history(self, branch):
204
232
return self._match_on_and_check(branch, revs=None)
313
341
# Well, I dunno what it is. Note that we don't try to keep track of the
314
342
# first of last exception raised during the DWIM tries as none seems
315
343
# really relevant.
316
raise errors.InvalidRevisionSpec(self.spec, branch)
344
raise InvalidRevisionSpec(self.spec, branch)
319
347
def append_possible_revspec(cls, revspec):
374
402
if revno_spec == '':
375
403
if not branch_spec:
376
raise errors.InvalidRevisionSpec(self.user_spec,
377
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')
388
417
match_revno = tuple((int(number)
389
418
for number in revno_spec.split('.')))
390
419
except ValueError as e:
391
raise errors.InvalidRevisionSpec(self.user_spec, branch, e)
420
raise InvalidRevisionSpec(self.user_spec, branch, e)
401
430
revision_id = branch.dotted_revno_to_revision_id(match_revno,
402
431
_cache_reverse=True)
403
432
except (errors.NoSuchRevision, errors.RevnoOutOfBounds):
404
raise errors.InvalidRevisionSpec(self.user_spec, branch)
433
raise InvalidRevisionSpec(self.user_spec, branch)
406
435
# there is no traditional 'revno' for dotted-decimal revnos.
407
436
# so for API compatibility we return None.
419
448
revision_id = branch.get_rev_id(revno)
420
449
except (errors.NoSuchRevision, errors.RevnoOutOfBounds):
421
raise errors.InvalidRevisionSpec(self.user_spec, branch)
450
raise InvalidRevisionSpec(self.user_spec, branch)
422
451
return branch, revno, revision_id
424
453
def _as_revision_id(self, context_branch):
502
531
offset = int(self.spec)
503
532
except ValueError as e:
504
raise errors.InvalidRevisionSpec(self.user_spec, context_branch, e)
533
raise InvalidRevisionSpec(self.user_spec, context_branch, e)
507
raise errors.InvalidRevisionSpec(self.user_spec, context_branch,
508
'you must supply a positive value')
536
raise InvalidRevisionSpec(
537
self.user_spec, context_branch,
538
'you must supply a positive value')
510
540
revno = last_revno - offset + 1
512
542
revision_id = context_branch.get_rev_id(revno)
513
543
except (errors.NoSuchRevision, errors.RevnoOutOfBounds):
514
raise errors.InvalidRevisionSpec(self.user_spec, context_branch)
544
raise InvalidRevisionSpec(self.user_spec, context_branch)
515
545
return revno, revision_id
517
547
def _as_revision_id(self, context_branch):
548
578
def _match_on(self, branch, revs):
549
579
r = RevisionSpec.from_string(self.spec)._match_on(branch, revs)
551
raise errors.InvalidRevisionSpec(self.user_spec, branch,
552
'cannot go before the null: revision')
581
raise InvalidRevisionSpec(
582
self.user_spec, branch,
583
'cannot go before the null: revision')
553
584
if r.revno is None:
554
585
# We need to use the repository history here
555
586
rev = branch.repository.get_revision(r.rev_id)
564
595
revision_id = branch.get_rev_id(revno, revs)
565
596
except (errors.NoSuchRevision, errors.RevnoOutOfBounds):
566
raise errors.InvalidRevisionSpec(self.user_spec,
597
raise InvalidRevisionSpec(self.user_spec, branch)
568
598
return RevisionInfo(branch, revno, revision_id)
570
600
def _as_revision_id(self, context_branch):
571
601
base_revision_id = RevisionSpec.from_string(
572
602
self.spec)._as_revision_id(context_branch)
573
603
if base_revision_id == revision.NULL_REVISION:
574
raise errors.InvalidRevisionSpec(self.user_spec, context_branch,
575
'cannot go before the null: revision')
604
raise InvalidRevisionSpec(
605
self.user_spec, context_branch,
606
'cannot go before the null: revision')
576
607
context_repo = context_branch.repository
577
608
with context_repo.lock_read():
578
609
parent_map = context_repo.get_parent_map([base_revision_id])
579
610
if base_revision_id not in parent_map:
580
611
# Ghost, or unknown revision id
581
raise errors.InvalidRevisionSpec(self.user_spec, context_branch,
582
'cannot find the matching revision')
612
raise InvalidRevisionSpec(
613
self.user_spec, context_branch, 'cannot find the matching revision')
583
614
parents = parent_map[base_revision_id]
584
615
if len(parents) < 1:
585
raise errors.InvalidRevisionSpec(self.user_spec, context_branch,
586
'No parents for revision.')
616
raise InvalidRevisionSpec(
617
self.user_spec, context_branch, 'No parents for revision.')
587
618
return parents[0]
674
705
m = self._date_regex.match(self.spec)
675
706
if not m or (not m.group('date') and not m.group('time')):
676
raise errors.InvalidRevisionSpec(self.user_spec,
677
branch, 'invalid date')
707
raise InvalidRevisionSpec(
708
self.user_spec, branch, 'invalid date')
680
711
if m.group('date'):
697
728
hour, minute, second = 0, 0, 0
698
729
except ValueError:
699
raise errors.InvalidRevisionSpec(self.user_spec,
700
branch, 'invalid date')
730
raise InvalidRevisionSpec(
731
self.user_spec, branch, 'invalid date')
702
733
dt = datetime.datetime(year=year, month=month, day=day,
703
734
hour=hour, minute=minute, second=second)
704
735
with branch.lock_read():
705
736
rev = bisect.bisect(_RevListToTimestamps(branch), dt, 1)
706
737
if rev == branch.revno():
707
raise errors.InvalidRevisionSpec(self.user_spec, branch)
738
raise InvalidRevisionSpec(self.user_spec, branch)
708
739
return RevisionInfo(branch, rev)
879
910
def _raise_invalid(self, numstring, context_branch):
880
raise errors.InvalidRevisionSpec(self.user_spec, context_branch,
881
'No such line: %s' % numstring)
911
raise InvalidRevisionSpec(
912
self.user_spec, context_branch,
913
'No such line: %s' % numstring)
883
915
def _as_revision_id(self, context_branch):
884
916
path, numstring = self.spec.rsplit(':', 1)
889
921
tree, file_path = workingtree.WorkingTree.open_containing(path)
890
922
with tree.lock_read():
891
923
if not tree.has_filename(file_path):
892
raise errors.InvalidRevisionSpec(self.user_spec,
893
context_branch, "File '%s' is not versioned." %
924
raise InvalidRevisionSpec(
925
self.user_spec, context_branch,
926
"File '%s' is not versioned." % file_path)
895
927
revision_ids = [r for (r, l) in tree.annotate_iter(file_path)]
897
929
revision_id = revision_ids[index]
898
930
except IndexError:
899
931
self._raise_invalid(numstring, context_branch)
900
932
if revision_id == revision.CURRENT_REVISION:
901
raise errors.InvalidRevisionSpec(self.user_spec, context_branch,
902
'Line %s has not been committed.' % numstring)
933
raise InvalidRevisionSpec(
934
self.user_spec, context_branch,
935
'Line %s has not been committed.' % numstring)
903
936
return revision_id
923
956
result = graph.find_lefthand_merger(revision_id,
924
957
context_branch.last_revision())
925
958
if result is None:
926
raise errors.InvalidRevisionSpec(self.user_spec, context_branch)
959
raise InvalidRevisionSpec(self.user_spec, context_branch)