836
841
commit(self, *args, **kw)
839
def lookup_revision(self, revno):
840
"""Return revision hash for revision number."""
845
# list is 0-based; revisions are 1-based
846
return self.revision_history()[revno-1]
848
raise BzrError("no such revision %s" % revno)
844
def lookup_revision(self, revision):
845
"""Return the revision identifier for a given revision information."""
846
revno, info = self.get_revision_info(revision)
849
def get_revision_info(self, revision):
850
"""Return (revno, revision id) for revision identifier.
852
revision can be an integer, in which case it is assumed to be revno (though
853
this will translate negative values into positive ones)
854
revision can also be a string, in which case it is parsed for something like
855
'date:' or 'revid:' etc.
860
try:# Convert to int if possible
861
revision = int(revision)
864
revs = self.revision_history()
865
if isinstance(revision, int):
868
# Mabye we should do this first, but we don't need it if revision == 0
870
revno = len(revs) + revision + 1
873
elif isinstance(revision, basestring):
874
for prefix, func in Branch.REVISION_NAMESPACES.iteritems():
875
if revision.startswith(prefix):
876
revno = func(self, revs, revision)
879
raise BzrError('No namespace registered for string: %r' % revision)
881
if revno is None or revno <= 0 or revno > len(revs):
882
raise BzrError("no such revision %s" % revision)
883
return revno, revs[revno-1]
885
def _namespace_revno(self, revs, revision):
886
"""Lookup a revision by revision number"""
887
assert revision.startswith('revno:')
889
return int(revision[6:])
892
REVISION_NAMESPACES['revno:'] = _namespace_revno
894
def _namespace_revid(self, revs, revision):
895
assert revision.startswith('revid:')
897
return revs.index(revision[6:]) + 1
900
REVISION_NAMESPACES['revid:'] = _namespace_revid
902
def _namespace_last(self, revs, revision):
903
assert revision.startswith('last:')
905
offset = int(revision[5:])
910
raise BzrError('You must supply a positive value for --revision last:XXX')
911
return len(revs) - offset + 1
912
REVISION_NAMESPACES['last:'] = _namespace_last
914
def _namespace_tag(self, revs, revision):
915
assert revision.startswith('tag:')
916
raise BzrError('tag: namespace registered, but not implemented.')
917
REVISION_NAMESPACES['tag:'] = _namespace_tag
919
def _namespace_date(self, revs, revision):
920
assert revision.startswith('date:')
922
# Spec for date revisions:
924
# value can be 'yesterday', 'today', 'tomorrow' or a YYYY-MM-DD string.
925
# it can also start with a '+/-/='. '+' says match the first
926
# entry after the given date. '-' is match the first entry before the date
927
# '=' is match the first entry after, but still on the given date.
929
# +2005-05-12 says find the first matching entry after May 12th, 2005 at 0:00
930
# -2005-05-12 says find the first matching entry before May 12th, 2005 at 0:00
931
# =2005-05-12 says find the first match after May 12th, 2005 at 0:00 but before
932
# May 13th, 2005 at 0:00
934
# So the proper way of saying 'give me all entries for today' is:
935
# -r {date:+today}:{date:-tomorrow}
936
# The default is '=' when not supplied
939
if val[:1] in ('+', '-', '='):
940
match_style = val[:1]
943
today = datetime.datetime.today().replace(hour=0,minute=0,second=0,microsecond=0)
944
if val.lower() == 'yesterday':
945
dt = today - datetime.timedelta(days=1)
946
elif val.lower() == 'today':
948
elif val.lower() == 'tomorrow':
949
dt = today + datetime.timedelta(days=1)
951
# This should be done outside the function to avoid recompiling it.
952
_date_re = re.compile(
953
r'(?P<date>(?P<year>\d\d\d\d)-(?P<month>\d\d)-(?P<day>\d\d))?'
955
r'(?P<time>(?P<hour>\d\d):(?P<minute>\d\d)(:(?P<second>\d\d))?)?'
957
m = _date_re.match(val)
958
if not m or (not m.group('date') and not m.group('time')):
959
raise BzrError('Invalid revision date %r' % revision)
962
year, month, day = int(m.group('year')), int(m.group('month')), int(m.group('day'))
964
year, month, day = today.year, today.month, today.day
966
hour = int(m.group('hour'))
967
minute = int(m.group('minute'))
968
if m.group('second'):
969
second = int(m.group('second'))
973
hour, minute, second = 0,0,0
975
dt = datetime.datetime(year=year, month=month, day=day,
976
hour=hour, minute=minute, second=second)
980
if match_style == '-':
982
elif match_style == '=':
983
last = dt + datetime.timedelta(days=1)
986
for i in range(len(revs)-1, -1, -1):
987
r = self.get_revision(revs[i])
988
# TODO: Handle timezone.
989
dt = datetime.datetime.fromtimestamp(r.timestamp)
990
if first >= dt and (last is None or dt >= last):
993
for i in range(len(revs)):
994
r = self.get_revision(revs[i])
995
# TODO: Handle timezone.
996
dt = datetime.datetime.fromtimestamp(r.timestamp)
997
if first <= dt and (last is None or dt <= last):
999
REVISION_NAMESPACES['date:'] = _namespace_date
851
1001
def revision_tree(self, revision_id):
852
1002
"""Return Tree for a revision on this branch.