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
20
18
from .lazy_import import lazy_import
21
19
lazy_import(globals(), """
74
68
if not self._has_revno and self.rev_id is not None:
76
70
self._revno = self.branch.revision_id_to_revno(self.rev_id)
77
except errors.NoSuchRevision:
71
except (errors.NoSuchRevision, errors.RevnoOutOfBounds):
79
73
self._has_revno = True
161
157
return RevisionSpec(None, _internal=True)
162
if not isinstance(spec, (str, text_type)):
158
if not isinstance(spec, str):
163
159
raise TypeError("revision spec needs to be text")
164
160
match = revspec_registry.get_prefix(spec)
165
161
if match is not None:
373
369
branch_spec = None
375
371
revno_spec = self.spec[:loc]
376
branch_spec = self.spec[loc+1:]
372
branch_spec = self.spec[loc + 1:]
378
374
if revno_spec == '':
379
375
if not branch_spec:
380
376
raise errors.InvalidRevisionSpec(self.user_spec,
381
branch, 'cannot have an empty revno and no branch')
377
branch, 'cannot have an empty revno and no branch')
389
385
# but the from_string method is a little primitive
390
386
# right now - RBC 20060928
392
match_revno = tuple((int(number) for number in revno_spec.split('.')))
388
match_revno = tuple((int(number)
389
for number in revno_spec.split('.')))
393
390
except ValueError as e:
394
391
raise errors.InvalidRevisionSpec(self.user_spec, branch, e)
404
401
revision_id = branch.dotted_revno_to_revision_id(match_revno,
406
except errors.NoSuchRevision:
403
except (errors.NoSuchRevision, errors.RevnoOutOfBounds):
407
404
raise errors.InvalidRevisionSpec(self.user_spec, branch)
409
406
# there is no traditional 'revno' for dotted-decimal revnos.
420
417
revno = last_revno + revno + 1
422
419
revision_id = branch.get_rev_id(revno)
423
except errors.NoSuchRevision:
420
except (errors.NoSuchRevision, errors.RevnoOutOfBounds):
424
421
raise errors.InvalidRevisionSpec(self.user_spec, branch)
425
422
return branch, revno, revision_id
468
466
# self.spec comes straight from parsing the command line arguments,
469
467
# so we expect it to be a Unicode string. Switch it to the internal
470
468
# representation.
471
if isinstance(self.spec, unicode):
469
if isinstance(self.spec, str):
472
470
return cache_utf8.encode(self.spec)
477
474
class RevisionSpec_last(RevisionSpec):
478
475
"""Selects the nth revision from the end."""
513
510
revno = last_revno - offset + 1
515
512
revision_id = context_branch.get_rev_id(revno)
516
except errors.NoSuchRevision:
513
except (errors.NoSuchRevision, errors.RevnoOutOfBounds):
517
514
raise errors.InvalidRevisionSpec(self.user_spec, context_branch)
518
515
return revno, revision_id
553
549
r = RevisionSpec.from_string(self.spec)._match_on(branch, revs)
555
551
raise errors.InvalidRevisionSpec(self.user_spec, branch,
556
'cannot go before the null: revision')
552
'cannot go before the null: revision')
557
553
if r.revno is None:
558
554
# We need to use the repository history here
559
555
rev = branch.repository.get_revision(r.rev_id)
566
562
revno = r.revno - 1
568
564
revision_id = branch.get_rev_id(revno, revs)
569
except errors.NoSuchRevision:
565
except (errors.NoSuchRevision, errors.RevnoOutOfBounds):
570
566
raise errors.InvalidRevisionSpec(self.user_spec,
572
568
return RevisionInfo(branch, revno, revision_id)
574
570
def _as_revision_id(self, context_branch):
575
base_revision_id = RevisionSpec.from_string(self.spec)._as_revision_id(context_branch)
571
base_revision_id = RevisionSpec.from_string(
572
self.spec)._as_revision_id(context_branch)
576
573
if base_revision_id == revision.NULL_REVISION:
577
574
raise errors.InvalidRevisionSpec(self.user_spec, context_branch,
578
'cannot go before the null: revision')
575
'cannot go before the null: revision')
579
576
context_repo = context_branch.repository
580
context_repo.lock_read()
577
with context_repo.lock_read():
582
578
parent_map = context_repo.get_parent_map([base_revision_id])
584
context_repo.unlock()
585
579
if base_revision_id not in parent_map:
586
580
# Ghost, or unknown revision id
587
581
raise errors.InvalidRevisionSpec(self.user_spec, context_branch,
588
'cannot find the matching revision')
582
'cannot find the matching revision')
589
583
parents = parent_map[base_revision_id]
590
584
if len(parents) < 1:
591
585
raise errors.InvalidRevisionSpec(self.user_spec, context_branch,
592
'No parents for revision.')
586
'No parents for revision.')
593
587
return parents[0]
597
590
class RevisionSpec_tag(RevisionSpec):
598
591
"""Select a revision identified by tag name"""
608
601
def _match_on(self, branch, revs):
609
602
# Can raise tags not supported, NoSuchTag, etc
610
603
return RevisionInfo.from_revision_id(branch,
611
branch.tags.lookup_tag(self.spec))
604
branch.tags.lookup_tag(self.spec))
613
606
def _as_revision_id(self, context_branch):
614
607
return context_branch.tags.lookup_tag(self.spec)
618
610
class _RevListToTimestamps(object):
619
611
"""This takes a list of revisions, and allows you to bisect by date"""
657
649
_date_regex = lazy_regex.lazy_compile(
658
r'(?P<date>(?P<year>\d\d\d\d)-(?P<month>\d\d)-(?P<day>\d\d))?'
660
r'(?P<time>(?P<hour>\d\d):(?P<minute>\d\d)(:(?P<second>\d\d))?)?'
650
r'(?P<date>(?P<year>\d\d\d\d)-(?P<month>\d\d)-(?P<day>\d\d))?'
652
r'(?P<time>(?P<hour>\d\d):(?P<minute>\d\d)(:(?P<second>\d\d))?)?'
663
655
def _match_on(self, branch, revs):
670
662
# XXX: This doesn't actually work
671
663
# So the proper way of saying 'give me all entries for today' is:
672
664
# -r date:yesterday..date:today
673
today = datetime.datetime.fromordinal(datetime.date.today().toordinal())
665
today = datetime.datetime.fromordinal(
666
datetime.date.today().toordinal())
674
667
if self.spec.lower() == 'yesterday':
675
668
dt = today - datetime.timedelta(days=1)
676
669
elif self.spec.lower() == 'today':
707
700
branch, 'invalid date')
709
702
dt = datetime.datetime(year=year, month=month, day=day,
710
hour=hour, minute=minute, second=second)
703
hour=hour, minute=minute, second=second)
711
704
with branch.lock_read():
712
705
rev = bisect.bisect(_RevListToTimestamps(branch), dt, 1)
713
706
if rev == branch.revno():
860
851
if submit_location is None:
861
852
raise errors.NoSubmitBranch(branch)
862
853
trace.note(gettext('Using {0} {1}').format(location_type,
864
855
return submit_location
866
857
def _match_on(self, branch, revs):
867
858
trace.mutter('matching ancestor: on: %s, %s', self.spec, branch)
868
859
return self._find_revision_info(branch,
869
self._get_submit_location(branch))
860
self._get_submit_location(branch))
871
862
def _as_revision_id(self, context_branch):
872
863
return self._find_revision_id(context_branch,
873
self._get_submit_location(context_branch))
864
self._get_submit_location(context_branch))
876
867
class RevisionSpec_annotate(RevisionIDSpec):
888
879
def _raise_invalid(self, numstring, context_branch):
889
880
raise errors.InvalidRevisionSpec(self.user_spec, context_branch,
890
'No such line: %s' % numstring)
881
'No such line: %s' % numstring)
892
883
def _as_revision_id(self, context_branch):
893
884
path, numstring = self.spec.rsplit(':', 1)
899
890
with tree.lock_read():
900
891
if not tree.has_filename(file_path):
901
892
raise errors.InvalidRevisionSpec(self.user_spec,
902
context_branch, "File '%s' is not versioned." %
893
context_branch, "File '%s' is not versioned." %
904
895
revision_ids = [r for (r, l) in tree.annotate_iter(file_path)]
906
897
revision_id = revision_ids[index]
908
899
self._raise_invalid(numstring, context_branch)
909
900
if revision_id == revision.CURRENT_REVISION:
910
901
raise errors.InvalidRevisionSpec(self.user_spec, context_branch,
911
'Line %s has not been committed.' % numstring)
902
'Line %s has not been committed.' % numstring)
912
903
return revision_id
945
936
RevisionSpec_dwim.append_possible_revspec(RevisionSpec_branch)
947
938
revspec_registry = registry.Registry()
948
941
def _register_revspec(revspec):
949
942
revspec_registry.register(revspec.prefix, revspec)
951
945
_register_revspec(RevisionSpec_revno)
952
946
_register_revspec(RevisionSpec_revid)
953
947
_register_revspec(RevisionSpec_last)