119 """Recursively removes a directory, even if it's marked read-only.
121 This was copied from:
122 https://chromium.googlesource.com/chromium/tools/build/+/f3e7ff03613cd59a463b2ccc49773c3813e77404/scripts/common/chromium_utils.py#491
124 Remove the directory located at *path, if it exists.
126 shutil.rmtree() doesn't work on Windows if any of the files or directories
127 are read-only, which svn repositories and some .svn files are. We need to
128 be able to force the files to be writable (i.e., deletable) as we traverse
131 Even with all this, Windows still sometimes fails to delete a file, citing
132 a permission error (maybe something to do with antivirus scans or disk
133 indexing). The best suggestion any of the user forums had was to wait a
134 bit and try again, so we do that too. It's hand-waving, but sometimes it
137 file_path = os.path.join(*path)
138 if not os.path.exists(file_path):
141 if sys.platform ==
'win32':
143 file_path = os.path.normcase(file_path)
145 print(
'RemoveDirectory running %s' % (
' '.join(
146 [
'cmd.exe',
'/c',
'rd',
'/q',
'/s', file_path])))
147 if not subprocess.call([
'cmd.exe',
'/c',
'rd',
'/q',
'/s', file_path]):
153 def RemoveWithRetry_non_win(rmfunc, path):
154 if os.path.islink(path):
155 return os.remove(path)
159 remove_with_retry = RemoveWithRetry_non_win
161 def RmTreeOnError(function, path, excinfo):
162 r"""This works around a problem whereby python 2.x on Windows has no ability
163 to check for symbolic links. os.path.islink always returns False. But
164 shutil.rmtree will fail if invoked on a symbolic link whose target was
165 deleted before the link. E.g., reproduce like this:
168 > mklink /D test\current test\1
169 > python -c "import chromium_utils; chromium_utils.RemoveDirectory('test')"
170 To avoid this issue, we pass this error-handling function to rmtree. If
171 we see the exact sort of failure, we ignore it. All other failures we re-
175 exception_type = excinfo[0]
176 exception_value = excinfo[1]
183 if (function
is os.listdir)
and issubclass(exception_type, OSError):
184 if exception_value.errno == errno.ENOENT:
187 print(
'WARNING: Failed to list %s during rmtree. Ignoring.\n' % path)
193 for root, dirs, files
in os.walk(file_path, topdown=
False):
196 os.chmod(root, 0o770)
198 remove_with_retry(os.remove, os.path.join(root, name))
200 remove_with_retry(
lambda p: shutil.rmtree(p, onerror=RmTreeOnError),
201 os.path.join(root, name))
203 remove_with_retry(os.rmdir, file_path)