Workaround shutil.rmtree limitation on Windows
By default, shutil.rmtree raises an exception when deleting readonly
files on Windows.
Replace all shutil.rmtree with platform_utils.rmtree, which adds an
error handler to make files read-write when they can't be deleted.
Change-Id: I9cfea9a7b3703fb16a82cf69331540c2c179ed53
diff --git a/platform_utils.py b/platform_utils.py
index f4dfa0b..4417c5a 100644
--- a/platform_utils.py
+++ b/platform_utils.py
@@ -16,6 +16,8 @@
import os
import platform
import select
+import shutil
+import stat
from Queue import Queue
from threading import Thread
@@ -210,3 +212,16 @@
return tail[0] == os.sep # "x:foo" is invalid
else:
return not drive # "x:" is invalid
+
+
+def rmtree(path):
+ if isWindows():
+ shutil.rmtree(path, onerror=handle_rmtree_error)
+ else:
+ shutil.rmtree(path)
+
+
+def handle_rmtree_error(function, path, excinfo):
+ # Allow deleting read-only files
+ os.chmod(path, stat.S_IWRITE)
+ function(path)
diff --git a/project.py b/project.py
index de5c791..ba18337 100644
--- a/project.py
+++ b/project.py
@@ -2299,10 +2299,10 @@
print("Retrying clone after deleting %s" %
self.gitdir, file=sys.stderr)
try:
- shutil.rmtree(os.path.realpath(self.gitdir))
+ platform_utils.rmtree(os.path.realpath(self.gitdir))
if self.worktree and os.path.exists(os.path.realpath
(self.worktree)):
- shutil.rmtree(os.path.realpath(self.worktree))
+ platform_utils.rmtree(os.path.realpath(self.worktree))
return self._InitGitDir(mirror_git=mirror_git, force_sync=False)
except:
raise e
@@ -2344,9 +2344,9 @@
self.config.SetString('core.bare', None)
except Exception:
if init_obj_dir and os.path.exists(self.objdir):
- shutil.rmtree(self.objdir)
+ platform_utils.rmtree(self.objdir)
if init_git_dir and os.path.exists(self.gitdir):
- shutil.rmtree(self.gitdir)
+ platform_utils.rmtree(self.gitdir)
raise
def _UpdateHooks(self):
@@ -2516,7 +2516,7 @@
except GitError as e:
if force_sync:
try:
- shutil.rmtree(dotgit)
+ platform_utils.rmtree(dotgit)
return self._InitWorkTree(force_sync=False, submodules=submodules)
except:
raise e
@@ -2536,7 +2536,7 @@
self._CopyAndLinkFiles()
except Exception:
if init_dotgit:
- shutil.rmtree(dotgit)
+ platform_utils.rmtree(dotgit)
raise
def _gitdir_path(self, path):
diff --git a/subcmds/gitc_delete.py b/subcmds/gitc_delete.py
index 19caac5..54f62f4 100644
--- a/subcmds/gitc_delete.py
+++ b/subcmds/gitc_delete.py
@@ -14,10 +14,10 @@
# limitations under the License.
from __future__ import print_function
-import shutil
import sys
from command import Command, GitcClientCommand
+import platform_utils
from pyversion import is_python3
if not is_python3():
@@ -50,4 +50,4 @@
if not response == 'yes':
print('Response was not "yes"\n Exiting...')
sys.exit(1)
- shutil.rmtree(self.gitc_manifest.gitc_client_dir)
+ platform_utils.rmtree(self.gitc_manifest.gitc_client_dir)
diff --git a/subcmds/init.py b/subcmds/init.py
index 65dfd1f..e647091 100644
--- a/subcmds/init.py
+++ b/subcmds/init.py
@@ -17,7 +17,6 @@
import os
import platform
import re
-import shutil
import sys
from pyversion import is_python3
@@ -35,6 +34,7 @@
from project import SyncBuffer
from git_config import GitConfig
from git_command import git_require, MIN_GIT_VERSION
+import platform_utils
class Init(InteractiveCommand, MirrorSafeCommand):
common = True
@@ -252,7 +252,7 @@
# Better delete the manifest git dir if we created it; otherwise next
# time (when user fixes problems) we won't go through the "is_new" logic.
if is_new:
- shutil.rmtree(m.gitdir)
+ platform_utils.rmtree(m.gitdir)
sys.exit(1)
if opt.manifest_branch:
diff --git a/subcmds/sync.py b/subcmds/sync.py
index ef02327..797fc40 100644
--- a/subcmds/sync.py
+++ b/subcmds/sync.py
@@ -19,7 +19,6 @@
from optparse import SUPPRESS_HELP
import os
import re
-import shutil
import socket
import subprocess
import sys
@@ -73,6 +72,7 @@
from project import RemoteSpec
from command import Command, MirrorSafeCommand
from error import RepoChangedException, GitError, ManifestParseError
+import platform_utils
from project import SyncBuffer
from progress import Progress
from wrapper import Wrapper
@@ -473,7 +473,7 @@
# working git repository around. There shouldn't be any git projects here,
# so rmtree works.
try:
- shutil.rmtree(os.path.join(path, '.git'))
+ platform_utils.rmtree(os.path.join(path, '.git'))
except OSError:
print('Failed to remove %s' % os.path.join(path, '.git'), file=sys.stderr)
print('error: Failed to delete obsolete path %s' % path, file=sys.stderr)