summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRenaud Paquay <rpaquay@google.com>2016-11-03 10:37:53 -0700
committerDavid Pursehouse <dpursehouse@collab.net>2017-05-29 19:32:31 +0900
commita65adf74f990eeac0d90011476376c7239cb7af5 (patch)
tree9278d9ce7c8d68a85dd049ed1ea5b64d84135fc0
parentd5cec5e752821ca2710101b626b3a3ca07fdb7f8 (diff)
downloadgit-repo-a65adf74f990eeac0d90011476376c7239cb7af5.tar.gz
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
-rw-r--r--platform_utils.py15
-rw-r--r--project.py12
-rw-r--r--subcmds/gitc_delete.py4
-rw-r--r--subcmds/init.py4
-rw-r--r--subcmds/sync.py4
5 files changed, 27 insertions, 12 deletions
diff --git a/platform_utils.py b/platform_utils.py
index f4dfa0b1..4417c5a3 100644
--- a/platform_utils.py
+++ b/platform_utils.py
@@ -16,6 +16,8 @@
16import os 16import os
17import platform 17import platform
18import select 18import select
19import shutil
20import stat
19 21
20from Queue import Queue 22from Queue import Queue
21from threading import Thread 23from threading import Thread
@@ -210,3 +212,16 @@ def _winpath_is_valid(path):
210 return tail[0] == os.sep # "x:foo" is invalid 212 return tail[0] == os.sep # "x:foo" is invalid
211 else: 213 else:
212 return not drive # "x:" is invalid 214 return not drive # "x:" is invalid
215
216
217def rmtree(path):
218 if isWindows():
219 shutil.rmtree(path, onerror=handle_rmtree_error)
220 else:
221 shutil.rmtree(path)
222
223
224def handle_rmtree_error(function, path, excinfo):
225 # Allow deleting read-only files
226 os.chmod(path, stat.S_IWRITE)
227 function(path)
diff --git a/project.py b/project.py
index de5c7915..ba18337b 100644
--- a/project.py
+++ b/project.py
@@ -2299,10 +2299,10 @@ class Project(object):
2299 print("Retrying clone after deleting %s" % 2299 print("Retrying clone after deleting %s" %
2300 self.gitdir, file=sys.stderr) 2300 self.gitdir, file=sys.stderr)
2301 try: 2301 try:
2302 shutil.rmtree(os.path.realpath(self.gitdir)) 2302 platform_utils.rmtree(os.path.realpath(self.gitdir))
2303 if self.worktree and os.path.exists(os.path.realpath 2303 if self.worktree and os.path.exists(os.path.realpath
2304 (self.worktree)): 2304 (self.worktree)):
2305 shutil.rmtree(os.path.realpath(self.worktree)) 2305 platform_utils.rmtree(os.path.realpath(self.worktree))
2306 return self._InitGitDir(mirror_git=mirror_git, force_sync=False) 2306 return self._InitGitDir(mirror_git=mirror_git, force_sync=False)
2307 except: 2307 except:
2308 raise e 2308 raise e
@@ -2344,9 +2344,9 @@ class Project(object):
2344 self.config.SetString('core.bare', None) 2344 self.config.SetString('core.bare', None)
2345 except Exception: 2345 except Exception:
2346 if init_obj_dir and os.path.exists(self.objdir): 2346 if init_obj_dir and os.path.exists(self.objdir):
2347 shutil.rmtree(self.objdir) 2347 platform_utils.rmtree(self.objdir)
2348 if init_git_dir and os.path.exists(self.gitdir): 2348 if init_git_dir and os.path.exists(self.gitdir):
2349 shutil.rmtree(self.gitdir) 2349 platform_utils.rmtree(self.gitdir)
2350 raise 2350 raise
2351 2351
2352 def _UpdateHooks(self): 2352 def _UpdateHooks(self):
@@ -2516,7 +2516,7 @@ class Project(object):
2516 except GitError as e: 2516 except GitError as e:
2517 if force_sync: 2517 if force_sync:
2518 try: 2518 try:
2519 shutil.rmtree(dotgit) 2519 platform_utils.rmtree(dotgit)
2520 return self._InitWorkTree(force_sync=False, submodules=submodules) 2520 return self._InitWorkTree(force_sync=False, submodules=submodules)
2521 except: 2521 except:
2522 raise e 2522 raise e
@@ -2536,7 +2536,7 @@ class Project(object):
2536 self._CopyAndLinkFiles() 2536 self._CopyAndLinkFiles()
2537 except Exception: 2537 except Exception:
2538 if init_dotgit: 2538 if init_dotgit:
2539 shutil.rmtree(dotgit) 2539 platform_utils.rmtree(dotgit)
2540 raise 2540 raise
2541 2541
2542 def _gitdir_path(self, path): 2542 def _gitdir_path(self, path):
diff --git a/subcmds/gitc_delete.py b/subcmds/gitc_delete.py
index 19caac5a..54f62f46 100644
--- a/subcmds/gitc_delete.py
+++ b/subcmds/gitc_delete.py
@@ -14,10 +14,10 @@
14# limitations under the License. 14# limitations under the License.
15 15
16from __future__ import print_function 16from __future__ import print_function
17import shutil
18import sys 17import sys
19 18
20from command import Command, GitcClientCommand 19from command import Command, GitcClientCommand
20import platform_utils
21 21
22from pyversion import is_python3 22from pyversion import is_python3
23if not is_python3(): 23if not is_python3():
@@ -50,4 +50,4 @@ and all locally downloaded sources.
50 if not response == 'yes': 50 if not response == 'yes':
51 print('Response was not "yes"\n Exiting...') 51 print('Response was not "yes"\n Exiting...')
52 sys.exit(1) 52 sys.exit(1)
53 shutil.rmtree(self.gitc_manifest.gitc_client_dir) 53 platform_utils.rmtree(self.gitc_manifest.gitc_client_dir)
diff --git a/subcmds/init.py b/subcmds/init.py
index 65dfd1fd..e6470916 100644
--- a/subcmds/init.py
+++ b/subcmds/init.py
@@ -17,7 +17,6 @@ from __future__ import print_function
17import os 17import os
18import platform 18import platform
19import re 19import re
20import shutil
21import sys 20import sys
22 21
23from pyversion import is_python3 22from pyversion import is_python3
@@ -35,6 +34,7 @@ from error import ManifestParseError
35from project import SyncBuffer 34from project import SyncBuffer
36from git_config import GitConfig 35from git_config import GitConfig
37from git_command import git_require, MIN_GIT_VERSION 36from git_command import git_require, MIN_GIT_VERSION
37import platform_utils
38 38
39class Init(InteractiveCommand, MirrorSafeCommand): 39class Init(InteractiveCommand, MirrorSafeCommand):
40 common = True 40 common = True
@@ -252,7 +252,7 @@ to update the working directory files.
252 # Better delete the manifest git dir if we created it; otherwise next 252 # Better delete the manifest git dir if we created it; otherwise next
253 # time (when user fixes problems) we won't go through the "is_new" logic. 253 # time (when user fixes problems) we won't go through the "is_new" logic.
254 if is_new: 254 if is_new:
255 shutil.rmtree(m.gitdir) 255 platform_utils.rmtree(m.gitdir)
256 sys.exit(1) 256 sys.exit(1)
257 257
258 if opt.manifest_branch: 258 if opt.manifest_branch:
diff --git a/subcmds/sync.py b/subcmds/sync.py
index ef023274..797fc403 100644
--- a/subcmds/sync.py
+++ b/subcmds/sync.py
@@ -19,7 +19,6 @@ import netrc
19from optparse import SUPPRESS_HELP 19from optparse import SUPPRESS_HELP
20import os 20import os
21import re 21import re
22import shutil
23import socket 22import socket
24import subprocess 23import subprocess
25import sys 24import sys
@@ -73,6 +72,7 @@ from project import Project
73from project import RemoteSpec 72from project import RemoteSpec
74from command import Command, MirrorSafeCommand 73from command import Command, MirrorSafeCommand
75from error import RepoChangedException, GitError, ManifestParseError 74from error import RepoChangedException, GitError, ManifestParseError
75import platform_utils
76from project import SyncBuffer 76from project import SyncBuffer
77from progress import Progress 77from progress import Progress
78from wrapper import Wrapper 78from wrapper import Wrapper
@@ -473,7 +473,7 @@ later is required to fix a server side protocol bug.
473 # working git repository around. There shouldn't be any git projects here, 473 # working git repository around. There shouldn't be any git projects here,
474 # so rmtree works. 474 # so rmtree works.
475 try: 475 try:
476 shutil.rmtree(os.path.join(path, '.git')) 476 platform_utils.rmtree(os.path.join(path, '.git'))
477 except OSError: 477 except OSError:
478 print('Failed to remove %s' % os.path.join(path, '.git'), file=sys.stderr) 478 print('Failed to remove %s' % os.path.join(path, '.git'), file=sys.stderr)
479 print('error: Failed to delete obsolete path %s' % path, file=sys.stderr) 479 print('error: Failed to delete obsolete path %s' % path, file=sys.stderr)