Explorar el Código

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
Renaud Paquay hace 9 años
padre
commit
a65adf74f9
Se han modificado 5 ficheros con 27 adiciones y 12 borrados
  1. 15 0
      platform_utils.py
  2. 6 6
      project.py
  3. 2 2
      subcmds/gitc_delete.py
  4. 2 2
      subcmds/init.py
  5. 2 2
      subcmds/sync.py

+ 15 - 0
platform_utils.py

@@ -16,6 +16,8 @@
 import os
 import os
 import platform
 import platform
 import select
 import select
+import shutil
+import stat
 
 
 from Queue import Queue
 from Queue import Queue
 from threading import Thread
 from threading import Thread
@@ -210,3 +212,16 @@ def _winpath_is_valid(path):
       return tail[0] == os.sep  # "x:foo" is invalid
       return tail[0] == os.sep  # "x:foo" is invalid
   else:
   else:
     return not drive  # "x:" is invalid
     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)

+ 6 - 6
project.py

@@ -2299,10 +2299,10 @@ class Project(object):
             print("Retrying clone after deleting %s" %
             print("Retrying clone after deleting %s" %
                   self.gitdir, file=sys.stderr)
                   self.gitdir, file=sys.stderr)
             try:
             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
               if self.worktree and os.path.exists(os.path.realpath
                                                   (self.worktree)):
                                                   (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)
               return self._InitGitDir(mirror_git=mirror_git, force_sync=False)
             except:
             except:
               raise e
               raise e
@@ -2344,9 +2344,9 @@ class Project(object):
           self.config.SetString('core.bare', None)
           self.config.SetString('core.bare', None)
     except Exception:
     except Exception:
       if init_obj_dir and os.path.exists(self.objdir):
       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):
       if init_git_dir and os.path.exists(self.gitdir):
-        shutil.rmtree(self.gitdir)
+        platform_utils.rmtree(self.gitdir)
       raise
       raise
 
 
   def _UpdateHooks(self):
   def _UpdateHooks(self):
@@ -2516,7 +2516,7 @@ class Project(object):
       except GitError as e:
       except GitError as e:
         if force_sync:
         if force_sync:
           try:
           try:
-            shutil.rmtree(dotgit)
+            platform_utils.rmtree(dotgit)
             return self._InitWorkTree(force_sync=False, submodules=submodules)
             return self._InitWorkTree(force_sync=False, submodules=submodules)
           except:
           except:
             raise e
             raise e
@@ -2536,7 +2536,7 @@ class Project(object):
         self._CopyAndLinkFiles()
         self._CopyAndLinkFiles()
     except Exception:
     except Exception:
       if init_dotgit:
       if init_dotgit:
-        shutil.rmtree(dotgit)
+        platform_utils.rmtree(dotgit)
       raise
       raise
 
 
   def _gitdir_path(self, path):
   def _gitdir_path(self, path):

+ 2 - 2
subcmds/gitc_delete.py

@@ -14,10 +14,10 @@
 # limitations under the License.
 # limitations under the License.
 
 
 from __future__ import print_function
 from __future__ import print_function
-import shutil
 import sys
 import sys
 
 
 from command import Command, GitcClientCommand
 from command import Command, GitcClientCommand
+import platform_utils
 
 
 from pyversion import is_python3
 from pyversion import is_python3
 if not is_python3():
 if not is_python3():
@@ -50,4 +50,4 @@ and all locally downloaded sources.
       if not response == 'yes':
       if not response == 'yes':
         print('Response was not "yes"\n Exiting...')
         print('Response was not "yes"\n Exiting...')
         sys.exit(1)
         sys.exit(1)
-    shutil.rmtree(self.gitc_manifest.gitc_client_dir)
+    platform_utils.rmtree(self.gitc_manifest.gitc_client_dir)

+ 2 - 2
subcmds/init.py

@@ -17,7 +17,6 @@ from __future__ import print_function
 import os
 import os
 import platform
 import platform
 import re
 import re
-import shutil
 import sys
 import sys
 
 
 from pyversion import is_python3
 from pyversion import is_python3
@@ -35,6 +34,7 @@ from error import ManifestParseError
 from project import SyncBuffer
 from project import SyncBuffer
 from git_config import GitConfig
 from git_config import GitConfig
 from git_command import git_require, MIN_GIT_VERSION
 from git_command import git_require, MIN_GIT_VERSION
+import platform_utils
 
 
 class Init(InteractiveCommand, MirrorSafeCommand):
 class Init(InteractiveCommand, MirrorSafeCommand):
   common = True
   common = True
@@ -252,7 +252,7 @@ to update the working directory files.
       # Better delete the manifest git dir if we created it; otherwise next
       # 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.
       # time (when user fixes problems) we won't go through the "is_new" logic.
       if is_new:
       if is_new:
-        shutil.rmtree(m.gitdir)
+        platform_utils.rmtree(m.gitdir)
       sys.exit(1)
       sys.exit(1)
 
 
     if opt.manifest_branch:
     if opt.manifest_branch:

+ 2 - 2
subcmds/sync.py

@@ -19,7 +19,6 @@ import netrc
 from optparse import SUPPRESS_HELP
 from optparse import SUPPRESS_HELP
 import os
 import os
 import re
 import re
-import shutil
 import socket
 import socket
 import subprocess
 import subprocess
 import sys
 import sys
@@ -73,6 +72,7 @@ from project import Project
 from project import RemoteSpec
 from project import RemoteSpec
 from command import Command, MirrorSafeCommand
 from command import Command, MirrorSafeCommand
 from error import RepoChangedException, GitError, ManifestParseError
 from error import RepoChangedException, GitError, ManifestParseError
+import platform_utils
 from project import SyncBuffer
 from project import SyncBuffer
 from progress import Progress
 from progress import Progress
 from wrapper import Wrapper
 from wrapper import Wrapper
@@ -473,7 +473,7 @@ later is required to fix a server side protocol bug.
     # working git repository around. There shouldn't be any git projects here,
     # working git repository around. There shouldn't be any git projects here,
     # so rmtree works.
     # so rmtree works.
     try:
     try:
-      shutil.rmtree(os.path.join(path, '.git'))
+      platform_utils.rmtree(os.path.join(path, '.git'))
     except OSError:
     except OSError:
       print('Failed to remove %s' % os.path.join(path, '.git'), file=sys.stderr)
       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)
       print('error: Failed to delete obsolete path %s' % path, file=sys.stderr)