Patchwork [5,of,5] cmdutil: reimplement finddate() without using walkchangerevs()

login
register
mail settings
Submitter Yuya Nishihara
Date Sept. 13, 2020, 10:24 a.m.
Message ID <4fb5c797b598ed7c1314.1599992655@mimosa>
Download mbox | patch
Permalink /patch/47153/
State Accepted
Headers show

Comments

Yuya Nishihara - Sept. 13, 2020, 10:24 a.m.
# HG changeset patch
# User Yuya Nishihara <yuya@tcha.org>
# Date 1599987144 -32400
#      Sun Sep 13 17:52:24 2020 +0900
# Node ID 4fb5c797b598ed7c13147011fdccca49ca638a0d
# Parent  feed6e5c69c48b703c9cc3eba48180363ae6ce30
cmdutil: reimplement finddate() without using walkchangerevs()

It's simpler and slightly faster maybe because a fewer Python ops would
run.

Unscientific benchmark:

  $ python -m timeit \
    -s 'from mercurial import hg, ui, cmdutil; repo = hg.repository(ui.ui())' \
    'cmdutil.finddate(repo.ui, repo, "<2008-01-01")'
  (orig) 10 loops, best of 3: 1.45 sec per loop
  (new)  10 loops, best of 3: 1.25 sec per loop

Now "hg churn" and "hg grep" are the only users of walkchangerevs(), which
I want to refactor and fix bugs.

Patch

diff --git a/mercurial/cmdutil.py b/mercurial/cmdutil.py
--- a/mercurial/cmdutil.py
+++ b/mercurial/cmdutil.py
@@ -2230,26 +2230,17 @@  def showmarker(fm, marker, index=None):
 
 def finddate(ui, repo, date):
     """Find the tipmost changeset that matches the given date spec"""
-
-    df = dateutil.matchdate(date)
-    m = scmutil.matchall(repo)
-    results = {}
-
-    def prep(ctx, fns):
-        d = ctx.date()
-        if df(d[0]):
-            results[ctx.rev()] = d
-
-    for ctx in walkchangerevs(repo, m, {b'rev': None}, prep):
-        rev = ctx.rev()
-        if rev in results:
-            ui.status(
-                _(b"found revision %d from %s\n")
-                % (rev, dateutil.datestr(results[rev]))
-            )
-            return b'%d' % rev
-
-    raise error.Abort(_(b"revision matching date not found"))
+    mrevs = repo.revs(b'date(%s)', date)
+    try:
+        rev = mrevs.max()
+    except ValueError:
+        raise error.Abort(_(b"revision matching date not found"))
+
+    ui.status(
+        _(b"found revision %d from %s\n")
+        % (rev, dateutil.datestr(repo[rev].date()))
+    )
+    return b'%d' % rev
 
 
 def increasingwindows(windowsize=8, sizelimit=512):