mercurial/pathutil.py
changeset 43523 c21aca51b392
parent 43077 687b865b95ad
child 43633 0b7733719d21
--- 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.