833
859
commit(self, *args, **kw)
836
def lookup_revision(self, revno):
837
"""Return revision hash for revision number."""
842
# list is 0-based; revisions are 1-based
843
return self.revision_history()[revno-1]
845
raise BzrError("no such revision %s" % revno)
862
def lookup_revision(self, revision):
863
"""Return the revision identifier for a given revision information."""
864
revno, info = self.get_revision_info(revision)
867
def get_revision_info(self, revision):
868
"""Return (revno, revision id) for revision identifier.
870
revision can be an integer, in which case it is assumed to be revno (though
871
this will translate negative values into positive ones)
872
revision can also be a string, in which case it is parsed for something like
873
'date:' or 'revid:' etc.
878
try:# Convert to int if possible
879
revision = int(revision)
882
revs = self.revision_history()
883
if isinstance(revision, int):
886
# Mabye we should do this first, but we don't need it if revision == 0
888
revno = len(revs) + revision + 1
891
elif isinstance(revision, basestring):
892
for prefix, func in Branch.REVISION_NAMESPACES.iteritems():
893
if revision.startswith(prefix):
894
revno = func(self, revs, revision)
897
raise BzrError('No namespace registered for string: %r' % revision)
899
if revno is None or revno <= 0 or revno > len(revs):
900
raise BzrError("no such revision %s" % revision)
901
return revno, revs[revno-1]
903
def _namespace_revno(self, revs, revision):
904
"""Lookup a revision by revision number"""
905
assert revision.startswith('revno:')
907
return int(revision[6:])
910
REVISION_NAMESPACES['revno:'] = _namespace_revno
912
def _namespace_revid(self, revs, revision):
913
assert revision.startswith('revid:')
915
return revs.index(revision[6:]) + 1
918
REVISION_NAMESPACES['revid:'] = _namespace_revid
920
def _namespace_last(self, revs, revision):
921
assert revision.startswith('last:')
923
offset = int(revision[5:])
928
raise BzrError('You must supply a positive value for --revision last:XXX')
929
return len(revs) - offset + 1
930
REVISION_NAMESPACES['last:'] = _namespace_last
932
def _namespace_tag(self, revs, revision):
933
assert revision.startswith('tag:')
934
raise BzrError('tag: namespace registered, but not implemented.')
935
REVISION_NAMESPACES['tag:'] = _namespace_tag
937
def _namespace_date(self, revs, revision):
938
assert revision.startswith('date:')
940
# Spec for date revisions:
942
# value can be 'yesterday', 'today', 'tomorrow' or a YYYY-MM-DD string.
943
# it can also start with a '+/-/='. '+' says match the first
944
# entry after the given date. '-' is match the first entry before the date
945
# '=' is match the first entry after, but still on the given date.
947
# +2005-05-12 says find the first matching entry after May 12th, 2005 at 0:00
948
# -2005-05-12 says find the first matching entry before May 12th, 2005 at 0:00
949
# =2005-05-12 says find the first match after May 12th, 2005 at 0:00 but before
950
# May 13th, 2005 at 0:00
952
# So the proper way of saying 'give me all entries for today' is:
953
# -r {date:+today}:{date:-tomorrow}
954
# The default is '=' when not supplied
957
if val[:1] in ('+', '-', '='):
958
match_style = val[:1]
961
today = datetime.datetime.today().replace(hour=0,minute=0,second=0,microsecond=0)
962
if val.lower() == 'yesterday':
963
dt = today - datetime.timedelta(days=1)
964
elif val.lower() == 'today':
966
elif val.lower() == 'tomorrow':
967
dt = today + datetime.timedelta(days=1)
970
# This should be done outside the function to avoid recompiling it.
971
_date_re = re.compile(
972
r'(?P<date>(?P<year>\d\d\d\d)-(?P<month>\d\d)-(?P<day>\d\d))?'
974
r'(?P<time>(?P<hour>\d\d):(?P<minute>\d\d)(:(?P<second>\d\d))?)?'
976
m = _date_re.match(val)
977
if not m or (not m.group('date') and not m.group('time')):
978
raise BzrError('Invalid revision date %r' % revision)
981
year, month, day = int(m.group('year')), int(m.group('month')), int(m.group('day'))
983
year, month, day = today.year, today.month, today.day
985
hour = int(m.group('hour'))
986
minute = int(m.group('minute'))
987
if m.group('second'):
988
second = int(m.group('second'))
992
hour, minute, second = 0,0,0
994
dt = datetime.datetime(year=year, month=month, day=day,
995
hour=hour, minute=minute, second=second)
999
if match_style == '-':
1001
elif match_style == '=':
1002
last = dt + datetime.timedelta(days=1)
1005
for i in range(len(revs)-1, -1, -1):
1006
r = self.get_revision(revs[i])
1007
# TODO: Handle timezone.
1008
dt = datetime.datetime.fromtimestamp(r.timestamp)
1009
if first >= dt and (last is None or dt >= last):
1012
for i in range(len(revs)):
1013
r = self.get_revision(revs[i])
1014
# TODO: Handle timezone.
1015
dt = datetime.datetime.fromtimestamp(r.timestamp)
1016
if first <= dt and (last is None or dt <= last):
1018
REVISION_NAMESPACES['date:'] = _namespace_date
848
1020
def revision_tree(self, revision_id):
849
1021
"""Return Tree for a revision on this branch.