--- a/mercurial/merge.py Thu Sep 06 23:37:24 2018 -0400
+++ b/mercurial/merge.py Thu Sep 06 18:30:12 2018 -0700
@@ -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