utils: move the `dirs` definition in pathutil (API)
authorPierre-Yves David <pierre-yves.david@octobus.net>
Wed, 06 Nov 2019 14:13:19 +0100
changeset 43523 c21aca51b392
parent 43522 ce96be208ea4
child 43524 a7c0c5b5a50f
utils: move the `dirs` definition in pathutil (API) Before this change, the `dirs` class was accessible through the `mercurial.util` module. That module is expected to stay free of scm specific content. The `pathutil` destination has been selection by Martin von Zweigbergk. This work is part of a refactoring to unify the revlog index and the nodemap. This unification prepare the use of a persistent nodemap. Differential Revision: https://phab.mercurial-scm.org/D7311
hgext/narrow/narrowcommands.py
hgext/uncommit.py
mercurial/cmdutil.py
mercurial/dirstate.py
mercurial/manifest.py
mercurial/match.py
mercurial/pathutil.py
mercurial/repair.py
mercurial/util.py
tests/test-dirs.py
--- a/hgext/narrow/narrowcommands.py	Wed Oct 23 12:15:42 2019 -0700
+++ b/hgext/narrow/narrowcommands.py	Wed Nov 06 14:13:19 2019 +0100
@@ -22,6 +22,7 @@
     hg,
     narrowspec,
     node,
+    pathutil,
     pycompat,
     registrar,
     repair,
@@ -277,7 +278,7 @@
                     todelete.append(f)
             elif f.startswith(b'meta/'):
                 dir = f[5:-13]
-                dirs = sorted(util.dirs({dir})) + [dir]
+                dirs = sorted(pathutil.dirs({dir})) + [dir]
                 include = True
                 for d in dirs:
                     visit = newmatch.visitdir(d)
--- a/hgext/uncommit.py	Wed Oct 23 12:15:42 2019 -0700
+++ b/hgext/uncommit.py	Wed Nov 06 14:13:19 2019 +0100
@@ -29,11 +29,11 @@
     error,
     node,
     obsutil,
+    pathutil,
     pycompat,
     registrar,
     rewriteutil,
     scmutil,
-    util,
 )
 
 cmdtable = {}
@@ -185,7 +185,7 @@
             # if not everything tracked in that directory can be
             # uncommitted.
             if badfiles:
-                badfiles -= {f for f in util.dirs(eligible)}
+                badfiles -= {f for f in pathutil.dirs(eligible)}
 
             for f in sorted(badfiles):
                 if f in s.clean:
--- a/mercurial/cmdutil.py	Wed Oct 23 12:15:42 2019 -0700
+++ b/mercurial/cmdutil.py	Wed Nov 06 14:13:19 2019 +0100
@@ -2606,7 +2606,7 @@
     progress.complete()
 
     # warn about failure to delete explicit files/dirs
-    deleteddirs = util.dirs(deleted)
+    deleteddirs = pathutil.dirs(deleted)
     files = m.files()
     progress = ui.makeprogress(
         _(b'deleting'), total=len(files), unit=_(b'files')
--- a/mercurial/dirstate.py	Wed Oct 23 12:15:42 2019 -0700
+++ b/mercurial/dirstate.py	Wed Nov 06 14:13:19 2019 +0100
@@ -1514,11 +1514,11 @@
 
     @propertycache
     def _dirs(self):
-        return util.dirs(self._map, b'r')
+        return pathutil.dirs(self._map, b'r')
 
     @propertycache
     def _alldirs(self):
-        return util.dirs(self._map)
+        return pathutil.dirs(self._map)
 
     def _opendirstatefile(self):
         fp, mode = txnutil.trypending(self._root, self._opener, self._filename)
--- a/mercurial/manifest.py	Wed Oct 23 12:15:42 2019 -0700
+++ b/mercurial/manifest.py	Wed Nov 06 14:13:19 2019 +0100
@@ -23,6 +23,7 @@
 from . import (
     error,
     mdiff,
+    pathutil,
     policy,
     pycompat,
     revlog,
@@ -494,7 +495,7 @@
 
     @propertycache
     def _dirs(self):
-        return util.dirs(self)
+        return pathutil.dirs(self)
 
     def dirs(self):
         return self._dirs
@@ -1104,7 +1105,7 @@
 
     @propertycache
     def _alldirs(self):
-        return util.dirs(self)
+        return pathutil.dirs(self)
 
     def dirs(self):
         return self._alldirs
--- a/mercurial/match.py	Wed Oct 23 12:15:42 2019 -0700
+++ b/mercurial/match.py	Wed Nov 06 14:13:19 2019 +0100
@@ -18,6 +18,7 @@
     encoding,
     error,
     pathutil,
+    pathutil,
     policy,
     pycompat,
     util,
@@ -598,7 +599,7 @@
 
     @propertycache
     def _dirs(self):
-        return set(util.dirs(self._fileset))
+        return set(pathutil.dirs(self._fileset))
 
     def visitdir(self, dir):
         dir = normalizerootdir(dir, b'visitdir')
@@ -629,9 +630,9 @@
         return b'<patternmatcher patterns=%r>' % pycompat.bytestr(self._pats)
 
 
-# This is basically a reimplementation of util.dirs that stores the children
-# instead of just a count of them, plus a small optional optimization to avoid
-# some directories we don't need.
+# This is basically a reimplementation of pathutil.dirs that stores the
+# children instead of just a count of them, plus a small optional optimization
+# to avoid some directories we don't need.
 class _dirchildren(object):
     def __init__(self, paths, onlyinclude=None):
         self._dirs = {}
@@ -763,7 +764,7 @@
 
     @propertycache
     def _dirs(self):
-        return set(util.dirs(self._fileset))
+        return set(pathutil.dirs(self._fileset))
 
     def visitdir(self, dir):
         dir = normalizerootdir(dir, b'visitdir')
@@ -1510,8 +1511,8 @@
     p = set()
     # Add the parents as non-recursive/exact directories, since they must be
     # scanned to get to either the roots or the other exact directories.
-    p.update(util.dirs(d))
-    p.update(util.dirs(r))
+    p.update(pathutil.dirs(d))
+    p.update(pathutil.dirs(r))
 
     # FIXME: all uses of this function convert these to sets, do so before
     # returning.
--- a/mercurial/pathutil.py	Wed Oct 23 12:15:42 2019 -0700
+++ b/mercurial/pathutil.py	Wed Nov 06 14:13:19 2019 +0100
@@ -9,10 +9,14 @@
 from . import (
     encoding,
     error,
+    policy,
     pycompat,
     util,
 )
 
+rustdirs = policy.importrust('dirstate', 'Dirs')
+parsers = policy.importmod('parsers')
+
 
 def _lowerclean(s):
     return encoding.hfsignoreclean(s.lower())
@@ -271,6 +275,58 @@
         return path
 
 
+class dirs(object):
+    '''a multiset of directory names from a set of file paths'''
+
+    def __init__(self, map, skip=None):
+        self._dirs = {}
+        addpath = self.addpath
+        if isinstance(map, dict) and skip is not None:
+            for f, s in pycompat.iteritems(map):
+                if s[0] != skip:
+                    addpath(f)
+        elif skip is not None:
+            raise error.ProgrammingError(
+                b"skip character is only supported with a dict source"
+            )
+        else:
+            for f in map:
+                addpath(f)
+
+    def addpath(self, path):
+        dirs = self._dirs
+        for base in util.finddirs(path):
+            if base.endswith(b'/'):
+                raise ValueError(
+                    "found invalid consecutive slashes in path: %r" % base
+                )
+            if base in dirs:
+                dirs[base] += 1
+                return
+            dirs[base] = 1
+
+    def delpath(self, path):
+        dirs = self._dirs
+        for base in util.finddirs(path):
+            if dirs[base] > 1:
+                dirs[base] -= 1
+                return
+            del dirs[base]
+
+    def __iter__(self):
+        return iter(self._dirs)
+
+    def __contains__(self, d):
+        return d in self._dirs
+
+
+if util.safehasattr(parsers, 'dirs'):
+    dirs = parsers.dirs
+
+if rustdirs is not None:
+    dirs = rustdirs
+
+
 # forward two methods from posixpath that do what we need, but we'd
 # rather not let our internals know that we're thinking in posix terms
 # - instead we'll let them be oblivious.
--- a/mercurial/repair.py	Wed Oct 23 12:15:42 2019 -0700
+++ b/mercurial/repair.py	Wed Nov 06 14:13:19 2019 +0100
@@ -24,6 +24,7 @@
     exchange,
     obsolete,
     obsutil,
+    pathutil,
     phases,
     pycompat,
     util,
@@ -476,7 +477,7 @@
         if b'treemanifest' in repo.requirements:
             # This logic is safe if treemanifest isn't enabled, but also
             # pointless, so we skip it if treemanifest isn't enabled.
-            for dir in util.dirs(seenfiles):
+            for dir in pathutil.dirs(seenfiles):
                 i = b'meta/%s/00manifest.i' % dir
                 d = b'meta/%s/00manifest.d' % dir
 
--- a/mercurial/util.py	Wed Oct 23 12:15:42 2019 -0700
+++ b/mercurial/util.py	Wed Nov 06 14:13:19 2019 +0100
@@ -57,11 +57,8 @@
     stringutil,
 )
 
-rustdirs = policy.importrust('dirstate', 'Dirs')
-
 base85 = policy.importmod('base85')
 osutil = policy.importmod('osutil')
-parsers = policy.importmod('parsers')
 
 b85decode = base85.b85decode
 b85encode = base85.b85encode
@@ -3494,58 +3491,6 @@
     f.flush()
 
 
-class dirs(object):
-    '''a multiset of directory names from a dirstate or manifest'''
-
-    def __init__(self, map, skip=None):
-        self._dirs = {}
-        addpath = self.addpath
-        if isinstance(map, dict) and skip is not None:
-            for f, s in pycompat.iteritems(map):
-                if s[0] != skip:
-                    addpath(f)
-        elif skip is not None:
-            raise error.ProgrammingError(
-                b"skip character is only supported with a dict source"
-            )
-        else:
-            for f in map:
-                addpath(f)
-
-    def addpath(self, path):
-        dirs = self._dirs
-        for base in finddirs(path):
-            if base.endswith(b'/'):
-                raise ValueError(
-                    "found invalid consecutive slashes in path: %r" % base
-                )
-            if base in dirs:
-                dirs[base] += 1
-                return
-            dirs[base] = 1
-
-    def delpath(self, path):
-        dirs = self._dirs
-        for base in finddirs(path):
-            if dirs[base] > 1:
-                dirs[base] -= 1
-                return
-            del dirs[base]
-
-    def __iter__(self):
-        return iter(self._dirs)
-
-    def __contains__(self, d):
-        return d in self._dirs
-
-
-if safehasattr(parsers, 'dirs'):
-    dirs = parsers.dirs
-
-if rustdirs is not None:
-    dirs = rustdirs
-
-
 def finddirs(path):
     pos = path.rfind(b'/')
     while pos != -1:
--- a/tests/test-dirs.py	Wed Oct 23 12:15:42 2019 -0700
+++ b/tests/test-dirs.py	Wed Nov 06 14:13:19 2019 +0100
@@ -4,7 +4,7 @@
 
 import silenttestrunner
 
-from mercurial import util
+from mercurial import pathutil
 
 
 class dirstests(unittest.TestCase):
@@ -13,13 +13,13 @@
             (b'a/a/a', [b'a', b'a/a', b'']),
             (b'alpha/beta/gamma', [b'', b'alpha', b'alpha/beta']),
         ]:
-            d = util.dirs({})
+            d = pathutil.dirs({})
             d.addpath(case)
             self.assertEqual(sorted(d), sorted(want))
 
     def testinvalid(self):
         with self.assertRaises(ValueError):
-            d = util.dirs({})
+            d = pathutil.dirs({})
             d.addpath(b'a//b')