Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(645)

Unified Diff: third_party/WebKit/Tools/Scripts/webkitpy/common/system/filesystem.py

Issue 2896423004: webkitpy: Remove contents of directory. (Closed)
Patch Set: Fixing tests. Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: third_party/WebKit/Tools/Scripts/webkitpy/common/system/filesystem.py
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/common/system/filesystem.py b/third_party/WebKit/Tools/Scripts/webkitpy/common/system/filesystem.py
index c06c190f8e66399a55140e0fbcdfeceba612bab1..f55d249ff7b1df0ac0dddb2ba630b4c7cdf687c8 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/common/system/filesystem.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/common/system/filesystem.py
@@ -28,19 +28,23 @@
"""Wrapper object for the file system / source tree."""
-import stat
import codecs
import errno
import exceptions
import glob
import hashlib
+import logging
import os
import shutil
+import stat
import sys
import tempfile
import time
+_log = logging.getLogger(__name__)
+
+
class FileSystem(object):
"""FileSystem interface for webkitpy.
@@ -136,8 +140,8 @@ class FileSystem(object):
def listdir(self, path):
return os.listdir(path)
- def walk(self, top):
- return os.walk(top)
+ def walk(self, top, topdown=True, onerror=None, followlinks=False):
+ return os.walk(top, topdown=topdown, onerror=onerror, followlinks=followlinks)
def mkdtemp(self, **kwargs):
"""Create and return a uniquely named directory.
@@ -246,7 +250,7 @@ class FileSystem(object):
class _WindowsError(exceptions.OSError):
"""Fake exception for Linux and Mac."""
- def remove(self, path, osremove=os.remove):
+ def remove(self, path, osremove=os.remove, retry=True):
"""On Windows, if a process was recently killed and it held on to a
file, the OS will hold on to the file for a short while. This makes
attempts to delete the file fail. To work around that, this method
@@ -266,12 +270,22 @@ class FileSystem(object):
except exceptions.WindowsError:
time.sleep(sleep_interval)
retry_timeout_sec -= sleep_interval
- if retry_timeout_sec < 0:
+ if retry_timeout_sec < 0 and not retry:
raise
- def rmtree(self, path):
+ def rmtree(self, path, ignore_errors=True, onerror=None):
"""Delete the directory rooted at path, whether empty or not."""
- shutil.rmtree(path, ignore_errors=True)
+ shutil.rmtree(path, ignore_errors=ignore_errors, onerror=onerror)
+
+ def remove_contents(self, dirname):
+ """Attempt to remove the contents of a directory tree.
+ Args:
+ dirname (string): Directory to remove the contents of.
+
+ Returns:
+ bool: True if the directory is now empty.
+ """
+ return _remove_contents(self, dirname)
def copytree(self, source, destination):
shutil.copytree(source, destination)
@@ -286,3 +300,66 @@ class FileSystem(object):
def make_executable(self, file_path):
os.chmod(file_path, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR | stat.S_IRGRP | stat.S_IXGRP)
+
+
+# _remove_contents is implemented in terms of other FileSystem functions. To
+# allow it to be reused on the MockFileSystem object, we define it here and
+# then call it in both FileSystem and MockFileSystem classes.
+def _remove_contents(fs, dirname, sleep=time.sleep):
+ # We try multiple times, because on Windows a process which is
+ # currently closing could still have a file open in the directory.
+ _log.info('Removing contents of %s', dirname)
+ errors = []
+
+ def onerror(func, path, exc_info):
+ errors.append(path)
+ _log.exception('Failed at %s %s: %r', func, path, exc_info)
+
+ attempts = 0
+ while attempts < 5:
+ del errors[:]
+
+ for name in fs.listdir(dirname):
+ fullname = fs.join(dirname, name)
+
+ isdir = True
+ try:
+ isdir = fs.isdir(fullname)
+ except os.error:
+ onerror(fs.isdir, fullname, sys.exc_info())
+ continue
+
+ if isdir:
+ try:
+ _log.debug('Removing directory %s', fullname)
+ fs.rmtree(fullname, ignore_errors=False, onerror=onerror)
+ except os.error:
+ onerror(fs.rmtree, fullname, sys.exc_info())
+ continue
+ else:
+ try:
+ _log.debug('Removing file %s', fullname)
+ fs.remove(fullname, retry=False)
+ except os.error:
+ onerror(fs.remove, fullname, sys.exc_info())
+ continue
+
+ if not errors:
+ break
+
+ _log.warning('Contents removal failed, retrying in 1 second.')
+ attempts += 1
+ sleep(1)
+
+ # Check the path is gone.
+ if not fs.listdir(dirname):
+ return True
+
+ _log.warning('Unable to remove %s', dirname)
+ for dirpath, dirnames, filenames in fs.walk(dirname, onerror=onerror, topdown=False):
+ for fname in filenames:
+ _log.warning('File %s still in output dir.', fs.join(dirpath, fname))
+ for dname in dirnames:
+ _log.warning('Dir %s still in output dir.', fs.join(dirpath, dname))
+
+ return False

Powered by Google App Engine
This is Rietveld 408576698