scmutil: move revsingle/pair/range from cmdutil
authorMatt Mackall <mpm@selenic.com>
Fri, 13 May 2011 14:06:28 -0500
changeset 14319 b33f3e35efb0
parent 14318 1f46be4689ed
child 14320 3438417a6657
scmutil: move revsingle/pair/range from cmdutil This allows users at levels below the command layer to avoid import loops.
hgext/extdiff.py
hgext/graphlog.py
hgext/mq.py
hgext/patchbomb.py
hgext/transplant.py
mercurial/cmdutil.py
mercurial/commands.py
mercurial/scmutil.py
tests/autodiff.py
--- a/hgext/extdiff.py	Fri May 13 12:57:27 2011 -0500
+++ b/hgext/extdiff.py	Fri May 13 14:06:28 2011 -0500
@@ -123,10 +123,10 @@
         msg = _('cannot specify --rev and --change at the same time')
         raise util.Abort(msg)
     elif change:
-        node2 = cmdutil.revsingle(repo, change, None).node()
+        node2 = scmutil.revsingle(repo, change, None).node()
         node1a, node1b = repo.changelog.parents(node2)
     else:
-        node1a, node2 = cmdutil.revpair(repo, revs)
+        node1a, node2 = scmutil.revpair(repo, revs)
         if not revs:
             node1b = repo.dirstate.p2()
         else:
--- a/hgext/graphlog.py	Fri May 13 12:57:27 2011 -0500
+++ b/hgext/graphlog.py	Fri May 13 14:06:28 2011 -0500
@@ -12,11 +12,11 @@
 revision graph is also shown.
 '''
 
-from mercurial.cmdutil import revrange, show_changeset
+from mercurial.cmdutil import show_changeset
 from mercurial.commands import templateopts
 from mercurial.i18n import _
 from mercurial.node import nullrev
-from mercurial import cmdutil, commands, extensions
+from mercurial import cmdutil, commands, extensions, scmutil
 from mercurial import hg, util, graphmod
 
 cmdtable = {}
@@ -227,7 +227,7 @@
 
 def get_revs(repo, rev_opt):
     if rev_opt:
-        revs = revrange(repo, rev_opt)
+        revs = scmutil.revrange(repo, rev_opt)
         if len(revs) == 0:
             return (nullrev, nullrev)
         return (max(revs), min(revs))
@@ -324,7 +324,7 @@
 
     check_unsupported_flags(pats, opts)
 
-    revs = sorted(revrange(repo, [revset(pats, opts)]), reverse=1)
+    revs = sorted(scmutil.revrange(repo, [revset(pats, opts)]), reverse=1)
     limit = cmdutil.loglimit(opts)
     if limit is not None:
         revs = revs[:limit]
--- a/hgext/mq.py	Fri May 13 12:57:27 2011 -0500
+++ b/hgext/mq.py	Fri May 13 14:06:28 2011 -0500
@@ -46,7 +46,7 @@
 from mercurial.node import bin, hex, short, nullid, nullrev
 from mercurial.lock import release
 from mercurial import commands, cmdutil, hg, scmutil, util, revset
-from mercurial import repair, extensions, url, error
+from mercurial import repair, extensions, url, error, scmutil
 from mercurial import patch as patchmod
 import os, sys, re, errno, shutil
 
@@ -815,7 +815,7 @@
         if opts.get('rev'):
             if not self.applied:
                 raise util.Abort(_('no patches applied'))
-            revs = cmdutil.revrange(repo, opts.get('rev'))
+            revs = scmutil.revrange(repo, opts.get('rev'))
             if len(revs) > 1 and revs[0] > revs[1]:
                 revs.reverse()
             revpatches = self._revpatches(repo, revs)
@@ -1748,7 +1748,7 @@
             if files:
                 raise util.Abort(_('option "-r" not valid when importing '
                                    'files'))
-            rev = cmdutil.revrange(repo, rev)
+            rev = scmutil.revrange(repo, rev)
             rev.sort(reverse=True)
         if (len(files) > 1 or len(rev) > 1) and patchname:
             raise util.Abort(_('option "-n" not valid when importing multiple '
@@ -2736,7 +2736,7 @@
         backup = 'none'
 
     cl = repo.changelog
-    revs = set(cmdutil.revrange(repo, revs))
+    revs = set(scmutil.revrange(repo, revs))
     if not revs:
         raise util.Abort(_('empty revision set'))
 
@@ -2928,7 +2928,7 @@
         ui.status(_('no patches applied\n'))
         return 0
 
-    revs = cmdutil.revrange(repo, revrange)
+    revs = scmutil.revrange(repo, revrange)
     q.finish(repo, revs)
     q.save_dirty()
     return 0
--- a/hgext/patchbomb.py	Fri May 13 12:57:27 2011 -0500
+++ b/hgext/patchbomb.py	Fri May 13 14:06:28 2011 -0500
@@ -49,6 +49,7 @@
 import email.MIMEMultipart, email.MIMEBase
 import email.Utils, email.Encoders, email.Generator
 from mercurial import cmdutil, commands, hg, mail, patch, util, discovery
+from mercurial import scmutil
 from mercurial.i18n import _
 from mercurial.node import bin
 
@@ -286,7 +287,7 @@
         return [str(repo.changelog.rev(r)) for r in o]
 
     def getpatches(revs):
-        for r in cmdutil.revrange(repo, revs):
+        for r in scmutil.revrange(repo, revs):
             output = cStringIO.StringIO()
             cmdutil.export(repo, [r], fp=output,
                          opts=patch.diffopts(ui, opts))
--- a/hgext/transplant.py	Fri May 13 12:57:27 2011 -0500
+++ b/hgext/transplant.py	Fri May 13 14:06:28 2011 -0500
@@ -15,8 +15,8 @@
 
 from mercurial.i18n import _
 import os, tempfile
-from mercurial import bundlerepo, cmdutil, hg, merge, match
-from mercurial import patch, revlog, scmutil, util, error
+from mercurial import bundlerepo, hg, merge, match
+from mercurial import patch, revlog, scmutil, util, error, cmdutil
 from mercurial import revset, templatekw
 
 cmdtable = {}
@@ -578,14 +578,14 @@
         tf = tp.transplantfilter(repo, source, p1)
         if opts.get('prune'):
             prune = [source.lookup(r)
-                     for r in cmdutil.revrange(source, opts.get('prune'))]
+                     for r in scmutil.revrange(source, opts.get('prune'))]
             matchfn = lambda x: tf(x) and x not in prune
         else:
             matchfn = tf
         merges = map(source.lookup, opts.get('merge', ()))
         revmap = {}
         if revs:
-            for r in cmdutil.revrange(source, revs):
+            for r in scmutil.revrange(source, revs):
                 revmap[int(r)] = source.lookup(r)
         elif opts.get('all') or not merges:
             if source != repo:
--- a/mercurial/cmdutil.py	Fri May 13 12:57:27 2011 -0500
+++ b/mercurial/cmdutil.py	Fri May 13 14:06:28 2011 -0500
@@ -10,7 +10,7 @@
 import os, sys, errno, re, tempfile
 import util, scmutil, templater, patch, error, templatekw, wdutil
 import match as matchmod
-import revset, subrepo
+import subrepo
 
 expandpats = wdutil.expandpats
 match = wdutil.match
@@ -19,8 +19,6 @@
 addremove = wdutil.addremove
 dirstatecopy = wdutil.dirstatecopy
 
-revrangesep = ':'
-
 def parsealiases(cmd):
     return cmd.lstrip("^").split("|")
 
@@ -118,77 +116,6 @@
         limit = None
     return limit
 
-def revsingle(repo, revspec, default='.'):
-    if not revspec:
-        return repo[default]
-
-    l = revrange(repo, [revspec])
-    if len(l) < 1:
-        raise util.Abort(_('empty revision set'))
-    return repo[l[-1]]
-
-def revpair(repo, revs):
-    if not revs:
-        return repo.dirstate.p1(), None
-
-    l = revrange(repo, revs)
-
-    if len(l) == 0:
-        return repo.dirstate.p1(), None
-
-    if len(l) == 1:
-        return repo.lookup(l[0]), None
-
-    return repo.lookup(l[0]), repo.lookup(l[-1])
-
-def revrange(repo, revs):
-    """Yield revision as strings from a list of revision specifications."""
-
-    def revfix(repo, val, defval):
-        if not val and val != 0 and defval is not None:
-            return defval
-        return repo.changelog.rev(repo.lookup(val))
-
-    seen, l = set(), []
-    for spec in revs:
-        # attempt to parse old-style ranges first to deal with
-        # things like old-tag which contain query metacharacters
-        try:
-            if isinstance(spec, int):
-                seen.add(spec)
-                l.append(spec)
-                continue
-
-            if revrangesep in spec:
-                start, end = spec.split(revrangesep, 1)
-                start = revfix(repo, start, 0)
-                end = revfix(repo, end, len(repo) - 1)
-                step = start > end and -1 or 1
-                for rev in xrange(start, end + step, step):
-                    if rev in seen:
-                        continue
-                    seen.add(rev)
-                    l.append(rev)
-                continue
-            elif spec and spec in repo: # single unquoted rev
-                rev = revfix(repo, spec, None)
-                if rev in seen:
-                    continue
-                seen.add(rev)
-                l.append(rev)
-                continue
-        except error.RepoLookupError:
-            pass
-
-        # fall through to new-style queries if old-style fails
-        m = revset.match(repo.ui, spec)
-        for r in m(repo, range(len(repo))):
-            if r not in seen:
-                l.append(r)
-        seen.update(l)
-
-    return l
-
 def makefilename(repo, pat, node,
                   total=None, seqno=None, revwidth=None, pathname=None):
     node_expander = {
@@ -974,7 +901,7 @@
         defrange = '%s:0' % repo['.'].rev()
     else:
         defrange = '-1:0'
-    revs = revrange(repo, opts['rev'] or [defrange])
+    revs = scmutil.revrange(repo, opts['rev'] or [defrange])
     if not revs:
         return []
     wanted = set()
--- a/mercurial/commands.py	Fri May 13 12:57:27 2011 -0500
+++ b/mercurial/commands.py	Fri May 13 14:06:28 2011 -0500
@@ -261,7 +261,7 @@
     def bad(x, y):
         raise util.Abort("%s: %s" % (x, y))
 
-    ctx = cmdutil.revsingle(repo, opts.get('rev'))
+    ctx = scmutil.revsingle(repo, opts.get('rev'))
     m = cmdutil.match(repo, pats, opts)
     m.bad = bad
     follow = not opts.get('no_follow')
@@ -322,7 +322,7 @@
     Returns 0 on success.
     '''
 
-    ctx = cmdutil.revsingle(repo, opts.get('rev'))
+    ctx = scmutil.revsingle(repo, opts.get('rev'))
     if not ctx:
         raise util.Abort(_('no working directory: please specify a revision'))
     node = ctx.node()
@@ -390,7 +390,7 @@
         opts['date'] = util.parsedate(date)
 
     cmdutil.bailifchanged(repo)
-    node = cmdutil.revsingle(repo, rev).node()
+    node = scmutil.revsingle(repo, rev).node()
 
     op1, op2 = repo.dirstate.parents()
     a = repo.changelog.ancestor(op1, node)
@@ -573,7 +573,7 @@
                     raise util.Abort(_("%s killed") % command)
                 else:
                     transition = "bad"
-                ctx = cmdutil.revsingle(repo, rev)
+                ctx = scmutil.revsingle(repo, rev)
                 rev = None # clear for future iterations
                 state[transition].append(ctx.node())
                 ui.status(_('Changeset %d:%s: %s\n') % (ctx, ctx, transition))
@@ -591,7 +591,7 @@
     # update state
 
     if rev:
-        nodes = [repo.lookup(i) for i in cmdutil.revrange(repo, [rev])]
+        nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
     else:
         nodes = [repo.lookup('.')]
 
@@ -876,12 +876,12 @@
     """
     revs = None
     if 'rev' in opts:
-        revs = cmdutil.revrange(repo, opts['rev'])
+        revs = scmutil.revrange(repo, opts['rev'])
 
     if opts.get('all'):
         base = ['null']
     else:
-        base = cmdutil.revrange(repo, opts.get('base'))
+        base = scmutil.revrange(repo, opts.get('base'))
     if base:
         if dest:
             raise util.Abort(_("--base is incompatible with specifying "
@@ -935,7 +935,7 @@
 
     Returns 0 on success.
     """
-    ctx = cmdutil.revsingle(repo, opts.get('rev'))
+    ctx = scmutil.revsingle(repo, opts.get('rev'))
     err = 1
     m = cmdutil.match(repo, (file1,) + pats, opts)
     for abs in ctx.walk(m):
@@ -1831,7 +1831,7 @@
     _('[-r REV] [REV]'))
 def debugrebuildstate(ui, repo, rev="tip"):
     """rebuild the dirstate as it would look like for the given revision"""
-    ctx = cmdutil.revsingle(repo, rev)
+    ctx = scmutil.revsingle(repo, rev)
     wlock = repo.wlock()
     try:
         repo.dirstate.rebuild(ctx.node(), ctx.manifest())
@@ -1844,7 +1844,7 @@
 def debugrename(ui, repo, file1, *pats, **opts):
     """dump rename information"""
 
-    ctx = cmdutil.revsingle(repo, opts.get('rev'))
+    ctx = scmutil.revsingle(repo, opts.get('rev'))
     m = cmdutil.match(repo, (file1,) + pats, opts)
     for abs in ctx.walk(m):
         fctx = ctx[abs]
@@ -2018,8 +2018,8 @@
     Returns 0 on success.
     """
 
-    r1 = cmdutil.revsingle(repo, rev1).node()
-    r2 = cmdutil.revsingle(repo, rev2, 'null').node()
+    r1 = scmutil.revsingle(repo, rev1).node()
+    r2 = scmutil.revsingle(repo, rev2, 'null').node()
 
     wlock = repo.wlock()
     try:
@@ -2064,7 +2064,7 @@
      _('revision to check'), _('REV'))],
     _('[-r REV] [REV]'))
 def debugsub(ui, repo, rev=None):
-    ctx = cmdutil.revsingle(repo, rev, None)
+    ctx = scmutil.revsingle(repo, rev, None)
     for k, v in sorted(ctx.substate.items()):
         ui.write('path %s\n' % k)
         ui.write(' source   %s\n' % v[0])
@@ -2150,10 +2150,10 @@
         msg = _('cannot specify --rev and --change at the same time')
         raise util.Abort(msg)
     elif change:
-        node2 = cmdutil.revsingle(repo, change, None).node()
+        node2 = scmutil.revsingle(repo, change, None).node()
         node1 = repo[node2].p1().node()
     else:
-        node1, node2 = cmdutil.revpair(repo, revs)
+        node1, node2 = scmutil.revpair(repo, revs)
 
     if reverse:
         node1, node2 = node2, node1
@@ -2211,7 +2211,7 @@
     changesets += tuple(opts.get('rev', []))
     if not changesets:
         raise util.Abort(_("export requires at least one changeset"))
-    revs = cmdutil.revrange(repo, changesets)
+    revs = scmutil.revrange(repo, changesets)
     if len(revs) > 1:
         ui.note(_('exporting patches:\n'))
     else:
@@ -2501,7 +2501,7 @@
 
     start = None
     if 'rev' in opts:
-        start = cmdutil.revsingle(repo, opts['rev'], None).node()
+        start = scmutil.revsingle(repo, opts['rev'], None).node()
 
     if opts.get('topo'):
         heads = [repo[h] for h in repo.heads(start)]
@@ -2944,7 +2944,7 @@
                 output.append("%s%s" %
                   ('+'.join([str(p.rev()) for p in parents]), changed))
         else:
-            ctx = cmdutil.revsingle(repo, rev)
+            ctx = scmutil.revsingle(repo, rev)
             if default or id:
                 output = [hexfunc(ctx.node())]
             if num:
@@ -3235,7 +3235,7 @@
     Returns 0 if a match is found, 1 otherwise.
     """
     end = opts.get('print0') and '\0' or '\n'
-    rev = cmdutil.revsingle(repo, opts.get('rev'), None).node()
+    rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
 
     ret = 1
     m = cmdutil.match(repo, pats, opts, default='relglob')
@@ -3312,7 +3312,7 @@
 
     endrev = None
     if opts.get('copies') and opts.get('rev'):
-        endrev = max(cmdutil.revrange(repo, opts.get('rev'))) + 1
+        endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
 
     df = False
     if opts["date"]:
@@ -3395,7 +3395,7 @@
         node = rev
 
     decor = {'l':'644 @ ', 'x':'755 * ', '':'644   '}
-    ctx = cmdutil.revsingle(repo, node)
+    ctx = scmutil.revsingle(repo, node)
     for f in ctx:
         if ui.debugflag:
             ui.write("%40s " % hex(ctx.manifest()[f]))
@@ -3471,7 +3471,7 @@
                                     "explicit revision"))
         node = parent == bheads[0] and bheads[-1] or bheads[0]
     else:
-        node = cmdutil.revsingle(repo, node).node()
+        node = scmutil.revsingle(repo, node).node()
 
     if opts.get('preview'):
         # find nodes that are ancestors of p2 but not of p1
@@ -3543,7 +3543,7 @@
     Returns 0 on success.
     """
 
-    ctx = cmdutil.revsingle(repo, opts.get('rev'), None)
+    ctx = scmutil.revsingle(repo, opts.get('rev'), None)
 
     if file_:
         m = cmdutil.match(repo, (file_,), opts)
@@ -4074,7 +4074,7 @@
         raise util.Abort(_('no files or directories specified; '
                            'use --all to revert the whole repo'))
 
-    ctx = cmdutil.revsingle(repo, opts.get('rev'))
+    ctx = scmutil.revsingle(repo, opts.get('rev'))
     node = ctx.node()
     mf = ctx.manifest()
     if node == parent:
@@ -4519,7 +4519,7 @@
         node2 = repo.lookup(change)
         node1 = repo[node2].p1().node()
     else:
-        node1, node2 = cmdutil.revpair(repo, revs)
+        node1, node2 = scmutil.revpair(repo, revs)
 
     cwd = (pats and repo.getcwd()) or ''
     end = opts.get('print0') and '\0' or '\n'
@@ -4810,7 +4810,7 @@
         bheads = repo.branchheads()
         if not opts.get('force') and bheads and p1 not in bheads:
             raise util.Abort(_('not at a branch head (use -f to force)'))
-    r = cmdutil.revsingle(repo, rev_).node()
+    r = scmutil.revsingle(repo, rev_).node()
 
     if not message:
         # we don't translate commit messages
@@ -4961,7 +4961,7 @@
 
     # if we defined a bookmark, we have to remember the original bookmark name
     brev = rev
-    rev = cmdutil.revsingle(repo, rev, rev).rev()
+    rev = scmutil.revsingle(repo, rev, rev).rev()
 
     if check and clean:
         raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
--- a/mercurial/scmutil.py	Fri May 13 12:57:27 2011 -0500
+++ b/mercurial/scmutil.py	Fri May 13 14:06:28 2011 -0500
@@ -6,7 +6,7 @@
 # GNU General Public License version 2 or any later version.
 
 from i18n import _
-import util, error, osutil
+import util, error, osutil, revset
 import os, errno, stat, sys
 
 def checkfilename(f):
@@ -463,3 +463,76 @@
             path.append(os.path.join(userprofile, 'mercurial.ini'))
             path.append(os.path.join(userprofile, '.hgrc'))
         return path
+
+def revsingle(repo, revspec, default='.'):
+    if not revspec:
+        return repo[default]
+
+    l = revrange(repo, [revspec])
+    if len(l) < 1:
+        raise util.Abort(_('empty revision set'))
+    return repo[l[-1]]
+
+def revpair(repo, revs):
+    if not revs:
+        return repo.dirstate.p1(), None
+
+    l = revrange(repo, revs)
+
+    if len(l) == 0:
+        return repo.dirstate.p1(), None
+
+    if len(l) == 1:
+        return repo.lookup(l[0]), None
+
+    return repo.lookup(l[0]), repo.lookup(l[-1])
+
+_revrangesep = ':'
+
+def revrange(repo, revs):
+    """Yield revision as strings from a list of revision specifications."""
+
+    def revfix(repo, val, defval):
+        if not val and val != 0 and defval is not None:
+            return defval
+        return repo.changelog.rev(repo.lookup(val))
+
+    seen, l = set(), []
+    for spec in revs:
+        # attempt to parse old-style ranges first to deal with
+        # things like old-tag which contain query metacharacters
+        try:
+            if isinstance(spec, int):
+                seen.add(spec)
+                l.append(spec)
+                continue
+
+            if _revrangesep in spec:
+                start, end = spec.split(_revrangesep, 1)
+                start = revfix(repo, start, 0)
+                end = revfix(repo, end, len(repo) - 1)
+                step = start > end and -1 or 1
+                for rev in xrange(start, end + step, step):
+                    if rev in seen:
+                        continue
+                    seen.add(rev)
+                    l.append(rev)
+                continue
+            elif spec and spec in repo: # single unquoted rev
+                rev = revfix(repo, spec, None)
+                if rev in seen:
+                    continue
+                seen.add(rev)
+                l.append(rev)
+                continue
+        except error.RepoLookupError:
+            pass
+
+        # fall through to new-style queries if old-style fails
+        m = revset.match(repo.ui, spec)
+        for r in m(repo, range(len(repo))):
+            if r not in seen:
+                l.append(r)
+        seen.update(l)
+
+    return l
--- a/tests/autodiff.py	Fri May 13 12:57:27 2011 -0500
+++ b/tests/autodiff.py	Fri May 13 14:06:28 2011 -0500
@@ -1,7 +1,7 @@
 # Extension dedicated to test patch.diff() upgrade modes
 #
 #
-from mercurial import cmdutil, patch, util
+from mercurial import cmdutil, scmutil, patch, util
 
 def autodiff(ui, repo, *pats, **opts):
     diffopts = patch.diffopts(ui, opts)
@@ -28,7 +28,7 @@
     else:
         raise util.Abort('--git must be yes, no or auto')
 
-    node1, node2 = cmdutil.revpair(repo, [])
+    node1, node2 = scmutil.revpair(repo, [])
     m = cmdutil.match(repo, pats, opts)
     it = patch.diff(repo, node1, node2, match=m, opts=diffopts,
                     losedatafn=losedatafn)