Chromium Code Reviews| 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..e6fc1b556d859d4940a7525d674c03880190bb16 100644 |
| --- a/third_party/WebKit/Tools/Scripts/webkitpy/common/system/filesystem.py |
| +++ b/third_party/WebKit/Tools/Scripts/webkitpy/common/system/filesystem.py |
| @@ -28,14 +28,15 @@ |
| """Wrapper object for the file system / source tree.""" |
| -import stat |
| import codecs |
| import errno |
| import exceptions |
| import glob |
| import hashlib |
| +import logging |
|
qyearsley
2017/05/25 23:32:12
Nit: The general convention in webkitpy is to use
mithro
2017/05/26 04:04:23
Done.
|
| import os |
| import shutil |
| +import stat |
| import sys |
| import tempfile |
| import time |
| @@ -136,8 +137,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. |
| @@ -269,9 +270,72 @@ class FileSystem(object): |
| if retry_timeout_sec < 0: |
| 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 when the directory is now empty. |
|
mcgreevy_g
2017/05/26 06:38:01
s/when/if/
mithro
2017/05/29 03:55:58
Done.
|
| + """ |
| + # We try multiple times as on Windows a process which is currently closing |
|
mcgreevy_g
2017/05/26 06:38:01
I'd put a comma after "times" and use "because" in
mithro
2017/05/29 03:55:58
Done.
|
| + # could still have a file open in the directory. |
| + logging.info('Removing contents of %s', dirname) |
| + errors = [] |
| + |
| + def onerror(func, path, exc_info): |
| + errors.append(path) |
| + logging.exception('Failed at %s %s: %r', func, path, exc_info) |
| + |
| + attempts = 0 |
| + while attempts < 5: |
| + del errors[:] |
| + |
| + for name in self.listdir(dirname): |
| + fullname = self.join(dirname, name) |
| + |
| + isdir = True |
|
mcgreevy_g
2017/05/26 06:38:01
I think it's odd to intialize this to True when yo
mithro
2017/05/29 03:55:57
Acknowledged.
|
| + try: |
| + isdir = self.isdir(fullname) |
| + except os.error: |
| + onerror(self.isdir, fullname, sys.exc_info()) |
| + continue |
| + |
| + if isdir: |
| + try: |
| + self.rmtree(fullname, ignore_errors=False, onerror=onerror) |
| + except os.error: |
| + onerror(self.rmtree, fullname, sys.exc_info()) |
| + continue |
| + else: |
| + try: |
| + self.remove(fullname) |
|
mcgreevy_g
2017/05/26 06:38:01
The implementation of remove has a series of retri
mithro
2017/05/29 03:55:57
I added a flag to prevent retry behaviour in the r
mcgreevy_g
2017/05/29 04:17:56
Why three?
mithro
2017/05/29 06:00:30
Arbitrary number.
mcgreevy_g
2017/05/29 07:00:54
I still think setting a deadline would be nicer, b
|
| + except os.error: |
| + onerror(self.remove, fullname, sys.exc_info()) |
| + continue |
| + |
| + if not errors: |
| + break |
| + |
| + attempts += 1 |
| + time.sleep(1) |
| + |
| + # Check the path is gone. |
| + if not self.listdir(dirname): |
| + return True |
| + |
| + logging.warning('Unable to remove %s', dirname) |
| + for dirpath, dirnames, filenames in self.walk(dirname, onerror=onerror, topdown=False): |
| + for fname in filenames: |
| + logging.warning('File %s still in output dir.', self.join(dirpath, fname)) |
| + for dname in dirnames: |
| + logging.warning('Dir %s still in output dir.', self.join(dirpath, dname)) |
| + |
| + return False |
| def copytree(self, source, destination): |
| shutil.copytree(source, destination) |