D4477: merge: move purge logic from extension

indygreg (Gregory Szorc) phabricator at mercurial-scm.org
Fri Sep 7 08:12:59 EDT 2018


This revision was automatically updated to reflect the committed changes.
Closed by commit rHG7fea205fd5dc: merge: move purge logic from extension (authored by indygreg, committed by ).

CHANGED PRIOR TO COMMIT
  https://phab.mercurial-scm.org/D4477?vs=10825&id=10827#toc

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D4477?vs=10825&id=10827

REVISION DETAIL
  https://phab.mercurial-scm.org/D4477

AFFECTED FILES
  hgext/purge.py
  mercurial/merge.py

CHANGE DETAILS

diff --git a/mercurial/merge.py b/mercurial/merge.py
--- a/mercurial/merge.py
+++ b/mercurial/merge.py
@@ -9,6 +9,7 @@
 
 import errno
 import hashlib
+import os
 import shutil
 import struct
 
@@ -2240,3 +2241,71 @@
         # fix up dirstate for copies and renames
         copies.duplicatecopies(repo, repo[None], ctx.rev(), pctx.rev())
     return stats
+
+def purge(repo, matcher, ignored=False, removeemptydirs=True,
+          removefiles=True, abortonerror=False, noop=False):
+    """Purge the working directory of untracked files.
+
+    ``matcher`` is a matcher configured to scan the working directory -
+    potentially a subset.
+
+    ``ignored`` controls whether ignored files should also be purged.
+
+    ``removeemptydirs`` controls whether empty directories should be removed.
+
+    ``removefiles`` controls whether files are removed.
+
+    ``abortonerror`` causes an exception to be raised if an error occurs
+    deleting a file or directory.
+
+    ``noop`` controls whether to actually remove files. If not defined, actions
+    will be taken.
+
+    Returns an iterable of relative paths in the working directory that were
+    or would be removed.
+    """
+
+    def remove(removefn, path):
+        try:
+            removefn(repo.wvfs.join(path))
+        except OSError:
+            m = _('%s cannot be removed') % path
+            if abortonerror:
+                raise error.Abort(m)
+            else:
+                repo.ui.warn(_('warning: %s\n') % m)
+
+    # There's no API to copy a matcher. So mutate the passed matcher and
+    # restore it when we're done.
+    oldexplicitdir = matcher.explicitdir
+    oldtraversedir = matcher.traversedir
+
+    res = []
+
+    try:
+        if removeemptydirs:
+            directories = []
+            matcher.explicitdir = matcher.traversedir = directories.append
+
+        status = repo.status(match=matcher, ignored=ignored, unknown=True)
+
+        if removefiles:
+            for f in sorted(status.unknown + status.ignored):
+                if not noop:
+                    repo.ui.note(_('removing file %s\n') % f)
+                    remove(util.unlink, f)
+                res.append(f)
+
+        if removeemptydirs:
+            for f in sorted(directories, reverse=True):
+                if matcher(f) and not os.listdir(repo.wvfs.join(f)):
+                    if not noop:
+                        repo.ui.note(_('removing directory %s\n') % f)
+                        remove(os.rmdir, f)
+                    res.append(f)
+
+        return res
+
+    finally:
+        matcher.explicitdir = oldexplicitdir
+        matcher.traversedir = oldtraversedir
diff --git a/hgext/purge.py b/hgext/purge.py
--- a/hgext/purge.py
+++ b/hgext/purge.py
@@ -25,16 +25,13 @@
 '''command to delete untracked files from the working directory'''
 from __future__ import absolute_import
 
-import os
-
 from mercurial.i18n import _
 from mercurial import (
     cmdutil,
-    error,
+    merge as mergemod,
     pycompat,
     registrar,
     scmutil,
-    util,
 )
 
 cmdtable = {}
@@ -86,44 +83,28 @@
     option.
     '''
     opts = pycompat.byteskwargs(opts)
+
     act = not opts.get('print')
     eol = '\n'
     if opts.get('print0'):
         eol = '\0'
         act = False # --print0 implies --print
+
     removefiles = opts.get('files')
     removedirs = opts.get('dirs')
+
     if not removefiles and not removedirs:
         removefiles = True
         removedirs = True
 
-    def remove(remove_func, name):
-        if act:
-            try:
-                remove_func(repo.wjoin(name))
-            except OSError:
-                m = _('%s cannot be removed') % name
-                if opts.get('abort_on_err'):
-                    raise error.Abort(m)
-                ui.warn(_('warning: %s\n') % m)
-        else:
-            ui.write('%s%s' % (name, eol))
+    match = scmutil.match(repo[None], dirs, opts)
 
-    match = scmutil.match(repo[None], dirs, opts)
-    if removedirs:
-        directories = []
-        match.explicitdir = match.traversedir = directories.append
-    status = repo.status(match=match, ignored=opts.get('all'), unknown=True)
+    paths = mergemod.purge(
+        repo, match, ignored=opts.get('all', False),
+        removeemptydirs=removedirs, removefiles=removefiles,
+        abortonerror=opts.get('abort_on_err'),
+        noop=not act)
 
-    if removefiles:
-        for f in sorted(status.unknown + status.ignored):
-            if act:
-                ui.note(_('removing file %s\n') % f)
-            remove(util.unlink, f)
-
-    if removedirs:
-        for f in sorted(directories, reverse=True):
-            if match(f) and not os.listdir(repo.wjoin(f)):
-                if act:
-                    ui.note(_('removing directory %s\n') % f)
-                remove(os.rmdir, f)
+    for path in paths:
+        if not act:
+            ui.write('%s%s' % (path, eol))



To: indygreg, #hg-reviewers
Cc: yuja, mercurial-devel


More information about the Mercurial-devel mailing list