Merge lp:~jelmer/brz/fix-datetime into lp:brz

Proposed by Jelmer Vernooij
Status: Merged
Approved by: Jelmer Vernooij
Approved revision: no longer in the source branch.
Merge reported by: The Breezy Bot
Merged at revision: not available
Proposed branch: lp:~jelmer/brz/fix-datetime
Merge into: lp:brz
Diff against target: 253 lines (+111/-68)
3 files modified
breezy/revision.py (+5/-0)
breezy/revisionspec.py (+81/-59)
breezy/tests/test_revisionspec.py (+25/-9)
To merge this branch: bzr merge lp:~jelmer/brz/fix-datetime
Reviewer Review Type Date Requested Status
Jelmer Vernooij Approve
Review via email: mp+426105@code.launchpad.net

Commit message

Fix date: in git repositories.

Description of the change

Fix date: in git repositories.

To post a comment you must log in.
Revision history for this message
Jelmer Vernooij (jelmer) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'breezy/revision.py'
--- breezy/revision.py 2021-07-04 18:04:19 +0000
+++ breezy/revision.py 2022-07-03 21:23:15 +0000
@@ -75,6 +75,11 @@
75 def __repr__(self):75 def __repr__(self):
76 return "<Revision id %s>" % self.revision_id76 return "<Revision id %s>" % self.revision_id
7777
78 def datetime(self):
79 import datetime
80 # TODO: Handle timezone.
81 return datetime.datetime.fromtimestamp(self.timestamp)
82
78 def __eq__(self, other):83 def __eq__(self, other):
79 if not isinstance(other, Revision):84 if not isinstance(other, Revision):
80 return False85 return False
8186
=== modified file 'breezy/revisionspec.py'
--- breezy/revisionspec.py 2022-07-02 11:03:41 +0000
+++ breezy/revisionspec.py 2022-07-03 21:23:15 +0000
@@ -25,6 +25,7 @@
25 errors,25 errors,
26 lazy_regex,26 lazy_regex,
27 registry,27 registry,
28 revision as _mod_revision,
28 trace,29 trace,
29 )30 )
3031
@@ -641,13 +642,56 @@
641642
642 def __getitem__(self, index):643 def __getitem__(self, index):
643 """Get the date of the index'd item"""644 """Get the date of the index'd item"""
644 import datetime
645 r = self.branch.repository.get_revision(self.branch.get_rev_id(index))645 r = self.branch.repository.get_revision(self.branch.get_rev_id(index))
646 # TODO: Handle timezone.646 return r.datetime()
647 return datetime.datetime.fromtimestamp(r.timestamp)647
648648
649 def __len__(self):649_date_regex = lazy_regex.lazy_compile(
650 return self.branch.revno()650 r'(?P<date>(?P<year>\d\d\d\d)-(?P<month>\d\d)-(?P<day>\d\d))?'
651 r'(,|T)?\s*'
652 r'(?P<time>(?P<hour>\d\d):(?P<minute>\d\d)(:(?P<second>\d\d))?)?'
653 )
654
655
656def _parse_datespec(spec):
657 import datetime
658 # XXX: This doesn't actually work
659 # So the proper way of saying 'give me all entries for today' is:
660 # -r date:yesterday..date:today
661 today = datetime.datetime.fromordinal(
662 datetime.date.today().toordinal())
663 if spec.lower() == 'yesterday':
664 return today - datetime.timedelta(days=1)
665 elif spec.lower() == 'today':
666 return today
667 elif spec.lower() == 'tomorrow':
668 return today + datetime.timedelta(days=1)
669 else:
670 m = _date_regex.match(spec)
671 if not m or (not m.group('date') and not m.group('time')):
672 raise ValueError
673
674 if m.group('date'):
675 year = int(m.group('year'))
676 month = int(m.group('month'))
677 day = int(m.group('day'))
678 else:
679 year = today.year
680 month = today.month
681 day = today.day
682
683 if m.group('time'):
684 hour = int(m.group('hour'))
685 minute = int(m.group('minute'))
686 if m.group('second'):
687 second = int(m.group('second'))
688 else:
689 second = 0
690 else:
691 hour, minute, second = 0, 0, 0
692
693 return datetime.datetime(year=year, month=month, day=day,
694 hour=hour, minute=minute, second=second)
651695
652696
653class RevisionSpec_date(RevisionSpec):697class RevisionSpec_date(RevisionSpec):
@@ -671,11 +715,28 @@
671 August 14th, 2006 at 5:10pm.715 August 14th, 2006 at 5:10pm.
672 """716 """
673 prefix = 'date:'717 prefix = 'date:'
674 _date_regex = lazy_regex.lazy_compile(718
675 r'(?P<date>(?P<year>\d\d\d\d)-(?P<month>\d\d)-(?P<day>\d\d))?'719 def _scan_backwards(self, branch, dt):
676 r'(,|T)?\s*'720 with branch.lock_read():
677 r'(?P<time>(?P<hour>\d\d):(?P<minute>\d\d)(:(?P<second>\d\d))?)?'721 graph = branch.repository.get_graph()
678 )722 last_match = None
723 for revid in graph.iter_lefthand_ancestry(
724 branch.last_revision(), (_mod_revision.NULL_REVISION,)):
725 r = branch.repository.get_revision(revid)
726 if r.datetime() < dt:
727 if last_match is None:
728 raise InvalidRevisionSpec(self.user_spec, branch)
729 return RevisionInfo(branch, None, last_match)
730 last_match = revid
731 return RevisionInfo(branch, None, last_match)
732
733 def _bisect_backwards(self, branch, dt, hi):
734 import bisect
735 with branch.lock_read():
736 rev = bisect.bisect(_RevListToTimestamps(branch), dt, 1, hi)
737 if rev == branch.revno():
738 raise InvalidRevisionSpec(self.user_spec, branch)
739 return RevisionInfo(branch, rev)
679740
680 def _match_on(self, branch, revs):741 def _match_on(self, branch, revs):
681 """Spec for date revisions:742 """Spec for date revisions:
@@ -684,55 +745,16 @@
684 matches the first entry after a given date (either at midnight or745 matches the first entry after a given date (either at midnight or
685 at a specified time).746 at a specified time).
686 """747 """
687 import bisect748 try:
688 import datetime749 dt = _parse_datespec(self.spec)
689 # XXX: This doesn't actually work750 except ValueError:
690 # So the proper way of saying 'give me all entries for today' is:751 raise InvalidRevisionSpec(
691 # -r date:yesterday..date:today752 self.user_spec, branch, 'invalid date')
692 today = datetime.datetime.fromordinal(753 revno = branch.revno()
693 datetime.date.today().toordinal())754 if revno is None:
694 if self.spec.lower() == 'yesterday':755 return self._scan_backwards(branch, dt)
695 dt = today - datetime.timedelta(days=1)
696 elif self.spec.lower() == 'today':
697 dt = today
698 elif self.spec.lower() == 'tomorrow':
699 dt = today + datetime.timedelta(days=1)
700 else:756 else:
701 m = self._date_regex.match(self.spec)757 return self._bisect_backwards(branch, dt, revno)
702 if not m or (not m.group('date') and not m.group('time')):
703 raise InvalidRevisionSpec(
704 self.user_spec, branch, 'invalid date')
705
706 try:
707 if m.group('date'):
708 year = int(m.group('year'))
709 month = int(m.group('month'))
710 day = int(m.group('day'))
711 else:
712 year = today.year
713 month = today.month
714 day = today.day
715
716 if m.group('time'):
717 hour = int(m.group('hour'))
718 minute = int(m.group('minute'))
719 if m.group('second'):
720 second = int(m.group('second'))
721 else:
722 second = 0
723 else:
724 hour, minute, second = 0, 0, 0
725 except ValueError:
726 raise InvalidRevisionSpec(
727 self.user_spec, branch, 'invalid date')
728
729 dt = datetime.datetime(year=year, month=month, day=day,
730 hour=hour, minute=minute, second=second)
731 with branch.lock_read():
732 rev = bisect.bisect(_RevListToTimestamps(branch), dt, 1)
733 if rev == branch.revno():
734 raise InvalidRevisionSpec(self.user_spec, branch)
735 return RevisionInfo(branch, rev)
736758
737759
738class RevisionSpec_ancestor(RevisionSpec):760class RevisionSpec_ancestor(RevisionSpec):
739761
=== modified file 'breezy/tests/test_revisionspec.py'
--- breezy/tests/test_revisionspec.py 2020-07-28 02:11:05 +0000
+++ breezy/tests/test_revisionspec.py 2022-07-03 21:23:15 +0000
@@ -517,10 +517,10 @@
517 super(TestRevisionSpec, self).setUp()517 super(TestRevisionSpec, self).setUp()
518518
519 new_tree = self.make_branch_and_tree('new_tree')519 new_tree = self.make_branch_and_tree('new_tree')
520 new_tree.commit('Commit one', rev_id=b'new_r1',520 self.revid1 = new_tree.commit(
521 timestamp=time.time() - 60 * 60 * 24)521 'Commit one', timestamp=time.time() - 60 * 60 * 24)
522 new_tree.commit('Commit two', rev_id=b'new_r2')522 self.revid2 = new_tree.commit('Commit two')
523 new_tree.commit('Commit three', rev_id=b'new_r3')523 self.revid3 = new_tree.commit('Commit three')
524524
525 self.tree = new_tree525 self.tree = new_tree
526526
@@ -528,11 +528,11 @@
528 self.assertInvalid('date:tomorrow')528 self.assertInvalid('date:tomorrow')
529529
530 def test_today(self):530 def test_today(self):
531 self.assertInHistoryIs(2, b'new_r2', 'date:today')531 self.assertInHistoryIs(2, self.revid2, 'date:today')
532 self.assertInHistoryIs(1, b'new_r1', 'before:date:today')532 self.assertInHistoryIs(1, self.revid1, 'before:date:today')
533533
534 def test_yesterday(self):534 def test_yesterday(self):
535 self.assertInHistoryIs(1, b'new_r1', 'date:yesterday')535 self.assertInHistoryIs(1, self.revid1, 'date:yesterday')
536536
537 def test_invalid(self):537 def test_invalid(self):
538 self.assertInvalid('date:foobar', extra='\ninvalid date')538 self.assertInvalid('date:foobar', extra='\ninvalid date')
@@ -543,11 +543,27 @@
543543
544 def test_day(self):544 def test_day(self):
545 now = datetime.datetime.now()545 now = datetime.datetime.now()
546 self.assertInHistoryIs(2, b'new_r2',546 self.assertInHistoryIs(2, self.revid2,
547 'date:%04d-%02d-%02d' % (now.year, now.month, now.day))547 'date:%04d-%02d-%02d' % (now.year, now.month, now.day))
548548
549 def test_as_revision_id(self):549 def test_as_revision_id(self):
550 self.assertAsRevisionId(b'new_r2', 'date:today')550 self.assertAsRevisionId(self.revid2, 'date:today')
551
552
553class TestRevisionSpec_date_no_revno(TestRevisionSpec_date):
554
555 # some formats don't implement .revno(), so it triggers a different codepath
556
557 def get_in_history(self, revision_spec):
558 old_revno = self.overrideAttr(self.tree.branch, 'revno', lambda: None)
559 try:
560 return spec_in_history(revision_spec, self.tree.branch)
561 finally:
562 self.tree.branch.revno = old_revno
563
564 def test_today(self):
565 self.assertInHistoryIs(2, self.revid2, 'date:today')
566 # Drop before: since it messes with our monkeypatching of Branch.revno.
551567
552568
553class TestRevisionSpec_ancestor(TestRevisionSpec):569class TestRevisionSpec_ancestor(TestRevisionSpec):

Subscribers

People subscribed via source and target branches