diff mercurial/sparse.py @ 33324:33d0859c37bd

sparse: move working directory refreshing into core This is a pretty straightforward move of the code. I converted the "force" argument to a keyword argument. Like other recent changes, this code is tightly coupled with working directory update code in merge.py. I suspect the code will become more tightly coupled over time, possibly even moved to merge.py. For now, let's get the code in core.
author Gregory Szorc <gregory.szorc@gmail.com>
date Thu, 06 Jul 2017 14:53:08 -0700
parents 252500520d60
children 38df146d0697
line wrap: on
line diff
--- a/mercurial/sparse.py	Thu Jul 06 16:29:31 2017 -0700
+++ b/mercurial/sparse.py	Thu Jul 06 14:53:08 2017 -0700
@@ -382,3 +382,102 @@
                 prunedactions[file] = ('r', [], '')
 
     return prunedactions
+
+def refreshwdir(repo, origstatus, origsparsematch, force=False):
+    """Refreshes working directory by taking sparse config into account.
+
+    The old status and sparse matcher is compared against the current sparse
+    matcher.
+
+    Will abort if a file with pending changes is being excluded or included
+    unless ``force`` is True.
+    """
+    modified, added, removed, deleted, unknown, ignored, clean = origstatus
+
+    # Verify there are no pending changes
+    pending = set()
+    pending.update(modified)
+    pending.update(added)
+    pending.update(removed)
+    sparsematch = matcher(repo)
+    abort = False
+
+    for f in pending:
+        if not sparsematch(f):
+            repo.ui.warn(_("pending changes to '%s'\n") % f)
+            abort = not force
+
+    if abort:
+        raise error.Abort(_('could not update sparseness due to pending '
+                            'changes'))
+
+    # Calculate actions
+    dirstate = repo.dirstate
+    ctx = repo['.']
+    added = []
+    lookup = []
+    dropped = []
+    mf = ctx.manifest()
+    files = set(mf)
+
+    actions = {}
+
+    for file in files:
+        old = origsparsematch(file)
+        new = sparsematch(file)
+        # Add files that are newly included, or that don't exist in
+        # the dirstate yet.
+        if (new and not old) or (old and new and not file in dirstate):
+            fl = mf.flags(file)
+            if repo.wvfs.exists(file):
+                actions[file] = ('e', (fl,), '')
+                lookup.append(file)
+            else:
+                actions[file] = ('g', (fl, False), '')
+                added.append(file)
+        # Drop files that are newly excluded, or that still exist in
+        # the dirstate.
+        elif (old and not new) or (not old and not new and file in dirstate):
+            dropped.append(file)
+            if file not in pending:
+                actions[file] = ('r', [], '')
+
+    # Verify there are no pending changes in newly included files
+    abort = False
+    for file in lookup:
+        repo.ui.warn(_("pending changes to '%s'\n") % file)
+        abort = not force
+    if abort:
+        raise error.Abort(_('cannot change sparseness due to pending '
+                            'changes (delete the files or use '
+                            '--force to bring them back dirty)'))
+
+    # Check for files that were only in the dirstate.
+    for file, state in dirstate.iteritems():
+        if not file in files:
+            old = origsparsematch(file)
+            new = sparsematch(file)
+            if old and not new:
+                dropped.append(file)
+
+    # Apply changes to disk
+    typeactions = dict((m, []) for m in 'a f g am cd dc r dm dg m e k'.split())
+    for f, (m, args, msg) in actions.iteritems():
+        if m not in typeactions:
+            typeactions[m] = []
+        typeactions[m].append((f, args, msg))
+
+    mergemod.applyupdates(repo, typeactions, repo[None], repo['.'], False)
+
+    # Fix dirstate
+    for file in added:
+        dirstate.normal(file)
+
+    for file in dropped:
+        dirstate.drop(file)
+
+    for file in lookup:
+        # File exists on disk, and we're bringing it back in an unknown state.
+        dirstate.normallookup(file)
+
+    return added, dropped, lookup