Patchwork [05,of,11,sparse] sparse: move code for importing rules from files into core

login
register
mail settings
Submitter Gregory Szorc
Date July 8, 2017, 11:29 p.m.
Message ID <bdba7b6ce456921675eb.1499556540@ubuntu-vm-main>
Download mbox | patch
Permalink /patch/22130/
State Accepted
Headers show

Comments

Gregory Szorc - July 8, 2017, 11:29 p.m.
# HG changeset patch
# User Gregory Szorc <gregory.szorc@gmail.com>
# Date 1499548507 25200
#      Sat Jul 08 14:15:07 2017 -0700
# Node ID bdba7b6ce456921675ebf2dd54efd567709ed446
# Parent  663d36aeb183dfce677f52a27cc371272f15b5b7
sparse: move code for importing rules from files into core

This is a pretty straightforward port. Some code cleanup was
performed. But no major changes to the logic were made.

I'm not a huge fan of this function because it does multiple
things. I'd like to get things into core first to facilitate
refactoring later.

Please also note the added inline comment about the oddities
of writeconfig() and the try..except to undo it. This is because
of the hackiness in which the sparse matcher is obtained by
various consumers, notably dirstate. We'll need a massive
refactor to address this. That refactor is effectively blocked
on having the sparse dirstate hacks live in core.

Patch

diff --git a/hgext/sparse.py b/hgext/sparse.py
--- a/hgext/sparse.py
+++ b/hgext/sparse.py
@@ -361,7 +361,7 @@  def debugsparse(ui, repo, *pats, **opts)
                 disableprofile=disableprofile, force=force)
 
     if importrules:
-        _import(ui, repo, pats, opts, force=force)
+        sparse.importfromfiles(repo, opts, pats, force=force)
 
     if clearrules:
         sparse.clearrules(repo, force=force)
@@ -444,51 +444,3 @@  def _config(ui, repo, pats, opts, includ
             raise
     finally:
         wlock.release()
-
-def _import(ui, repo, files, opts, force=False):
-    with repo.wlock():
-        # read current configuration
-        raw = repo.vfs.tryread('sparse')
-        oincludes, oexcludes, oprofiles = sparse.parseconfig(ui, raw)
-        includes, excludes, profiles = map(
-                set, (oincludes, oexcludes, oprofiles))
-
-        aincludes, aexcludes, aprofiles = sparse.activeconfig(repo)
-
-        # import rules on top; only take in rules that are not yet
-        # part of the active rules.
-        changed = False
-        for file in files:
-            with util.posixfile(util.expandpath(file)) as importfile:
-                iincludes, iexcludes, iprofiles = sparse.parseconfig(
-                    ui, importfile.read())
-                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 = sparse.matcher(repo)
-            sparse.writeconfig(repo, includes, excludes, profiles)
-
-            try:
-                fcounts = map(
-                    len,
-                    sparse.refreshwdir(repo, oldstatus, oldsparsematch,
-                                       force=force))
-            except Exception:
-                sparse.writeconfig(repo, oincludes, oexcludes, oprofiles)
-                raise
-
-        sparse.printchanges(ui, opts, profilecount, includecount, excludecount,
-                            *fcounts)
diff --git a/mercurial/sparse.py b/mercurial/sparse.py
--- a/mercurial/sparse.py
+++ b/mercurial/sparse.py
@@ -18,6 +18,7 @@  from . import (
     match as matchmod,
     merge as mergemod,
     pycompat,
+    util,
 )
 
 # Whether sparse features are enabled. This variable is intended to be
@@ -524,6 +525,67 @@  def clearrules(repo, force=False):
         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."""