diff mercurial/pathutil.py @ 43571:c21aca51b392

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
author Pierre-Yves David <pierre-yves.david@octobus.net>
date Wed, 06 Nov 2019 14:13:19 +0100
parents 687b865b95ad
children 0b7733719d21
line wrap: on
line diff
--- 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.