mercurial/sparse.py
changeset 33371 c6415195fa78
parent 33370 482320104672
child 33374 4dc04cdf2520
--- a/mercurial/sparse.py	Sat Jul 08 14:01:32 2017 -0700
+++ b/mercurial/sparse.py	Sat Jul 08 14:15:07 2017 -0700
@@ -18,6 +18,7 @@
     match as matchmod,
     merge as mergemod,
     pycompat,
+    util,
 )
 
 # Whether sparse features are enabled. This variable is intended to be
@@ -521,6 +522,67 @@
         writeconfig(repo, set(), set(), profiles)
         refreshwdir(repo, oldstatus, oldmatch, force=force)
 
+def importfromfiles(repo, opts, paths, force=False):
+    """Import sparse config rules from files.
+
+    The updated sparse config is written out and the working directory
+    is refreshed, as needed.
+    """
+    with repo.wlock():
+        # read current configuration
+        raw = repo.vfs.tryread('sparse')
+        oincludes, oexcludes, oprofiles = parseconfig(repo.ui, raw)
+        includes, excludes, profiles = map(
+                set, (oincludes, oexcludes, oprofiles))
+
+        aincludes, aexcludes, aprofiles = activeconfig(repo)
+
+        # Import rules on top; only take in rules that are not yet
+        # part of the active rules.
+        changed = False
+        for p in paths:
+            with util.posixfile(util.expandpath(p)) as fh:
+                raw = fh.read()
+
+            iincludes, iexcludes, iprofiles = parseconfig(repo.ui, raw)
+            oldsize = len(includes) + len(excludes) + len(profiles)
+            includes.update(iincludes - aincludes)
+            excludes.update(iexcludes - aexcludes)
+            profiles.update(set(iprofiles) - aprofiles)
+            if len(includes) + len(excludes) + len(profiles) > oldsize:
+                changed = True
+
+        profilecount = includecount = excludecount = 0
+        fcounts = (0, 0, 0)
+
+        if changed:
+            profilecount = len(profiles - aprofiles)
+            includecount = len(includes - aincludes)
+            excludecount = len(excludes - aexcludes)
+
+            oldstatus = repo.status()
+            oldsparsematch = matcher(repo)
+
+            # TODO remove this try..except once the matcher integrates better
+            # with dirstate. We currently have to write the updated config
+            # because that will invalidate the matcher cache and force a
+            # re-read. We ideally want to update the cached matcher on the
+            # repo instance then flush the new config to disk once wdir is
+            # updated. But this requires massive rework to matcher() and its
+            # consumers.
+            writeconfig(repo, includes, excludes, profiles)
+
+            try:
+                fcounts = map(
+                    len,
+                    refreshwdir(repo, oldstatus, oldsparsematch, force=force))
+            except Exception:
+                writeconfig(repo, oincludes, oexcludes, oprofiles)
+                raise
+
+        printchanges(repo.ui, opts, profilecount, includecount, excludecount,
+                     *fcounts)
+
 def printchanges(ui, opts, profilecount=0, includecount=0, excludecount=0,
                  added=0, dropped=0, conflicting=0):
     """Print output summarizing sparse config changes."""