| Index: gclient_utils.py
|
| diff --git a/gclient_utils.py b/gclient_utils.py
|
| index 7182848527a15af96b5b4fbfe2770cf6f0d7438e..8e2d1c315e19807b8ade9c65ee3013b87dee6029 100644
|
| --- a/gclient_utils.py
|
| +++ b/gclient_utils.py
|
| @@ -182,10 +182,10 @@ def FileWrite(filename, content, mode='w'):
|
| f.close()
|
|
|
|
|
| -def RemoveDirectory(*path):
|
| - """Recursively removes a directory, even if it's marked read-only.
|
| +def rmtree(path):
|
| + """shutil.rmtree() on steroids.
|
|
|
| - Remove the directory located at *path, if it exists.
|
| + Recursively removes a directory, even if it's marked read-only.
|
|
|
| shutil.rmtree() doesn't work on Windows if any of the files or directories
|
| are read-only, which svn repositories and some .svn files are. We need to
|
| @@ -208,63 +208,55 @@ def RemoveDirectory(*path):
|
| In the ordinary case, this is not a problem: for our purposes, the user
|
| will never lack write permission on *path's parent.
|
| """
|
| - logging.debug(path)
|
| - file_path = os.path.join(*path)
|
| - if not os.path.exists(file_path):
|
| + if not os.path.exists(path):
|
| return
|
|
|
| - if os.path.islink(file_path) or not os.path.isdir(file_path):
|
| - raise Error('RemoveDirectory asked to remove non-directory %s' % file_path)
|
| + if os.path.islink(path) or not os.path.isdir(path):
|
| + raise Error('Called rmtree(%s) in non-directory' % path)
|
|
|
| - has_win32api = False
|
| if sys.platform == 'win32':
|
| - has_win32api = True
|
| # Some people don't have the APIs installed. In that case we'll do without.
|
| try:
|
| win32api = __import__('win32api')
|
| win32con = __import__('win32con')
|
| except ImportError:
|
| - has_win32api = False
|
| + pass
|
| else:
|
| # On POSIX systems, we need the x-bit set on the directory to access it,
|
| # the r-bit to see its contents, and the w-bit to remove files from it.
|
| # The actual modes of the files within the directory is irrelevant.
|
| - os.chmod(file_path, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR)
|
| - for fn in os.listdir(file_path):
|
| - fullpath = os.path.join(file_path, fn)
|
| + os.chmod(path, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR)
|
|
|
| + def remove(func, subpath):
|
| + if sys.platform == 'win32':
|
| + os.chmod(subpath, stat.S_IWRITE)
|
| + if win32api and win32con:
|
| + win32api.SetFileAttributes(subpath, win32con.FILE_ATTRIBUTE_NORMAL)
|
| + try:
|
| + func(subpath)
|
| + except OSError, e:
|
| + if e.errno != errno.EACCES or sys.platform != 'win32':
|
| + raise
|
| + # Failed to delete, try again after a 100ms sleep.
|
| + time.sleep(0.1)
|
| + func(subpath)
|
| +
|
| + for fn in os.listdir(path):
|
| # If fullpath is a symbolic link that points to a directory, isdir will
|
| # be True, but we don't want to descend into that as a directory, we just
|
| # want to remove the link. Check islink and treat links as ordinary files
|
| # would be treated regardless of what they reference.
|
| + fullpath = os.path.join(path, fn)
|
| if os.path.islink(fullpath) or not os.path.isdir(fullpath):
|
| - if sys.platform == 'win32':
|
| - os.chmod(fullpath, stat.S_IWRITE)
|
| - if has_win32api:
|
| - win32api.SetFileAttributes(fullpath, win32con.FILE_ATTRIBUTE_NORMAL)
|
| - try:
|
| - os.remove(fullpath)
|
| - except OSError, e:
|
| - if e.errno != errno.EACCES or sys.platform != 'win32':
|
| - raise
|
| - print 'Failed to delete %s: trying again' % fullpath
|
| - time.sleep(0.1)
|
| - os.remove(fullpath)
|
| + remove(os.remove, fullpath)
|
| else:
|
| - RemoveDirectory(fullpath)
|
| + # Recurse.
|
| + rmtree(fullpath)
|
|
|
| - if sys.platform == 'win32':
|
| - os.chmod(file_path, stat.S_IWRITE)
|
| - if has_win32api:
|
| - win32api.SetFileAttributes(file_path, win32con.FILE_ATTRIBUTE_NORMAL)
|
| - try:
|
| - os.rmdir(file_path)
|
| - except OSError, e:
|
| - if e.errno != errno.EACCES or sys.platform != 'win32':
|
| - raise
|
| - print 'Failed to remove %s: trying again' % file_path
|
| - time.sleep(0.1)
|
| - os.rmdir(file_path)
|
| + remove(os.rmdir, path)
|
| +
|
| +# TODO(maruel): Rename the references.
|
| +RemoveDirectory = rmtree
|
|
|
|
|
| def CheckCallAndFilterAndHeader(args, always=False, **kwargs):
|
|
|