| 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):
 | 
| 
 |