# HG changeset patch # User FUJIWARA Katsunori # Date 2015-04-10 15:47:09 # Node ID ca3a90096c9538493f2780ba06c895762113631f # Parent 897a0715ee71a24af14416277aa7c0b28e75e82a vfs: add rmtree This duplicates "onerror()" function from "svnsubrepo.remove()" for equivalence of replacing in subsequent patch. This "onerror()" function for "shutil.rmtree()" was introduced by 92b0d669637f, which avoids failure of removing svn repository on Windows. diff --git a/mercurial/scmutil.py b/mercurial/scmutil.py --- a/mercurial/scmutil.py +++ b/mercurial/scmutil.py @@ -10,7 +10,7 @@ from mercurial.node import nullrev import util, error, osutil, revset, similar, encoding, phases import pathutil import match as matchmod -import os, errno, re, glob, tempfile +import os, errno, re, glob, tempfile, shutil, stat if os.name == 'nt': import scmwindows as scmplatform @@ -316,6 +316,26 @@ class abstractvfs(object): def readlink(self, path): return os.readlink(self.join(path)) + def rmtree(self, path=None, ignore_errors=False, forcibly=False): + """Remove a directory tree recursively + + If ``forcibly``, this tries to remove READ-ONLY files, too. + """ + if forcibly: + def onerror(function, path, excinfo): + if function is not os.remove: + raise + # read-only files cannot be unlinked under Windows + s = os.stat(path) + if (s.st_mode & stat.S_IWRITE) != 0: + raise + os.chmod(path, stat.S_IMODE(s.st_mode) | stat.S_IWRITE) + os.remove(path) + else: + onerror = None + return shutil.rmtree(self.join(path), + ignore_errors=ignore_errors, onerror=onerror) + def setflags(self, path, l, x): return util.setflags(self.join(path), l, x)