[patch] update of alexander's rmtree patch

Martin Pool mbp at sourcefrog.net
Thu May 4 10:52:29 BST 2006


This is an update of Alexander's patch posted last month to take account
of shifts in bzr.dev.   Alexander, is there anything else you strongly
want merged for 0.8?

-- 
Martin
-------------- next part --------------
=== modified file 'a/bzrlib/branch.py'
--- a/bzrlib/branch.py	
+++ b/bzrlib/branch.py	
@@ -45,6 +45,7 @@
                             rename, splitpath, sha_file,
                             file_kind, abspath, normpath, pathjoin,
                             safe_unicode,
+                            rmtree,
                             )
 from bzrlib.textui import show_status
 from bzrlib.trace import mutter, note
@@ -886,7 +887,7 @@
         # XXX: cache_root seems to be unused, 2006-01-13 mbp
         if hasattr(self, 'cache_root') and self.cache_root is not None:
             try:
-                shutil.rmtree(self.cache_root)
+                rmtree(self.cache_root)
             except:
                 pass
             self.cache_root = None

=== modified file 'a/bzrlib/builtins.py'
--- a/bzrlib/builtins.py	
+++ b/bzrlib/builtins.py	
@@ -19,7 +19,6 @@
 
 import errno
 import os
-from shutil import rmtree
 import sys
 
 import bzrlib
@@ -565,6 +564,7 @@
     aliases = ['get', 'clone']
 
     def run(self, from_location, to_location=None, revision=None, basis=None):
+        from bzrlib.osutils import rmtree
         if revision is None:
             revision = [None]
         elif len(revision) > 1:

=== modified file 'a/bzrlib/merge.py'
--- a/bzrlib/merge.py	
+++ b/bzrlib/merge.py	
@@ -1,4 +1,4 @@
-# Copyright (C) 2005 Canonical Ltd
+# Copyright (C) 2005, 2006 Canonical Ltd
 
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -17,7 +17,6 @@
 
 import os
 import errno
-from shutil import rmtree
 from tempfile import mkdtemp
 
 import bzrlib
@@ -39,7 +38,7 @@
                            )
 from bzrlib.merge3 import Merge3
 import bzrlib.osutils
-from bzrlib.osutils import rename, pathjoin
+from bzrlib.osutils import rename, pathjoin, rmtree
 from progress import DummyProgress, ProgressPhase
 from bzrlib.revision import common_ancestor, is_ancestor, NULL_REVISION
 from bzrlib.symbol_versioning import *

=== modified file 'a/bzrlib/osutils.py'
--- a/bzrlib/osutils.py	
+++ b/bzrlib/osutils.py	
@@ -24,6 +24,7 @@
 import os
 import re
 import sha
+import shutil
 import string
 import sys
 import time
@@ -171,7 +172,8 @@
             else:
                 rename_func(tmp_name, new)
 
-# Default is to just use the python builtins
+# Default is to just use the python builtins, but these can be rebound on
+# particular platforms.
 abspath = os.path.abspath
 realpath = os.path.realpath
 pathjoin = os.path.join
@@ -181,6 +183,7 @@
 rename = os.rename
 dirname = os.path.dirname
 basename = os.path.basename
+rmtree = shutil.rmtree
 
 MIN_ABS_PATHLENGTH = 1
 
@@ -221,6 +224,24 @@
         fancy_rename(old, new, rename_func=os.rename, unlink_func=os.unlink)
 
     MIN_ABS_PATHLENGTH = 3
+
+    def _win32_delete_readonly(function, path, excinfo):
+        """Error handler for shutil.rmtree function [for win32]
+        Helps to remove files and dirs marked as read-only.
+        """
+        type_, value = excinfo[:2]
+        if function in (os.remove, os.rmdir) \
+            and type_ == OSError \
+            and value.errno == errno.EACCES:
+            bzrlib.osutils.make_writable(path)
+            function(path)
+        else:
+            raise
+
+    def rmtree(path, ignore_errors=False, onerror=_win32_delete_readonly):
+        """Replacer for shutil.rmtree: could remove readonly dirs/files"""
+        return shutil.rmtree(path, ignore_errors, onerror)
+
 
 def normalizepath(f):
     if hasattr(os.path, 'realpath'):

=== modified file 'a/bzrlib/tests/__init__.py'
--- a/bzrlib/tests/__init__.py	
+++ b/bzrlib/tests/__init__.py	
@@ -33,7 +33,6 @@
 import logging
 import os
 import re
-import shutil
 import stat
 import sys
 import tempfile
@@ -908,7 +907,7 @@
         if test_root is not None:
             print 'Deleting test root %s...' % test_root
             try:
-                shutil.rmtree(test_root)
+                osutils.rmtree(test_root)
             finally:
                 print
     else:

=== modified file 'a/bzrlib/tests/blackbox/test_too_much.py'
--- a/bzrlib/tests/blackbox/test_too_much.py	
+++ b/bzrlib/tests/blackbox/test_too_much.py	
@@ -37,14 +37,13 @@
 from cStringIO import StringIO
 import os
 import re
-import shutil
 import sys
 
 import bzrlib
 from bzrlib.branch import Branch
 import bzrlib.bzrdir as bzrdir
 from bzrlib.errors import BzrCommandError
-from bzrlib.osutils import has_symlinks, pathjoin
+from bzrlib.osutils import has_symlinks, pathjoin, rmtree
 from bzrlib.tests.HTTPTestUtil import TestCaseWithWebserver
 from bzrlib.tests.test_sftp_transport import TestCaseWithSFTPServer
 from bzrlib.tests.blackbox import ExternalBase
@@ -491,7 +490,7 @@
         self.runbzr('pull')
         self.runbzr('pull ../c')
         self.runbzr('branch ../c ../d')
-        shutil.rmtree('../c')
+        rmtree('../c')
         self.runbzr('pull')
         os.chdir('../b')
         self.runbzr('pull')

=== modified file 'a/bzrlib/tests/test_merge_core.py'
--- a/bzrlib/tests/test_merge_core.py	
+++ b/bzrlib/tests/test_merge_core.py	
@@ -1,5 +1,4 @@
 import os
-import shutil
 import stat
 import sys
 
@@ -12,7 +11,9 @@
 from bzrlib.inventory import RootEntry
 import bzrlib.inventory as inventory
 from bzrlib.merge import Merge3Merger, Diff3Merger, WeaveMerger
-from bzrlib.osutils import file_kind, rename, sha_file, pathjoin, mkdtemp
+from bzrlib.osutils import (file_kind, mkdtemp, pathjoin, rename, rmtree,
+                            sha_file, 
+                            )
 from bzrlib.transform import TreeTransform
 from bzrlib.tests import TestCaseWithTransport, TestCase, TestSkipped
 from bzrlib.workingtree import WorkingTree
@@ -176,7 +177,7 @@
                                                      self.this.inventory_dict)
 
     def cleanup(self):
-        shutil.rmtree(self.dir)
+        rmtree(self.dir)
 
 
 class MergeTest(TestCase):

=== modified file 'a/bzrlib/tests/test_osutils.py'
--- a/bzrlib/tests/test_osutils.py	
+++ b/bzrlib/tests/test_osutils.py	
@@ -72,6 +72,21 @@
         self.assertContainsRe(result, r'^[a-z0-9]{100}$')
 
 
+    def test_rmtree(self):
+        # Check to remove tree with read-only files/dirs
+        os.mkdir('dir')
+        osutils.make_readonly('dir')
+        f = file('dir/file', 'w')
+        f.write('spam')
+        f.close()
+        osutils.make_readonly('dir/file')
+
+        osutils.rmtree('dir')
+
+        self.failIfExists('dir/file')
+        self.failIfExists('dir')
+
+
 class TestSafeUnicode(TestCase):
 
     def test_from_ascii_string(self):

=== modified file 'a/bzrlib/tests/test_setup.py'
--- a/bzrlib/tests/test_setup.py	
+++ b/bzrlib/tests/test_setup.py	
@@ -1,3 +1,19 @@
+# Copyright (C) 2005, 2006 by Canonical Ltd
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
 """ test for setup.py build process """
 
 import os
@@ -7,7 +23,7 @@
 from tempfile import TemporaryFile
 
 from bzrlib.tests import TestCase
-
+import bzrlib.osutils as osutils
 
 # TODO: ideally run this in a separate directory, so as not to clobber the
 # real build directory
@@ -30,4 +46,4 @@
             self.assertEqual(0, p.returncode, '`python setup.py build` fails')
         finally:
             if os.path.exists('build'):
-                shutil.rmtree(u'build')
+                osutils.rmtree(u'build')

=== modified file 'a/bzrlib/tests/test_whitebox.py'
--- a/bzrlib/tests/test_whitebox.py	
+++ b/bzrlib/tests/test_whitebox.py	
@@ -16,7 +16,8 @@
         job: given a path (either relative to cwd or absolute), work out
         if it is inside a branch and return the path relative to the base.
         """
-        import tempfile, shutil
+        import tempfile
+        from bzrlib.osutils import rmtree
         
         savedir = os.getcwdu()
         dtmp = tempfile.mkdtemp()
@@ -64,4 +65,4 @@
 
         finally:
             os.chdir(savedir)
-            shutil.rmtree(dtmp)
+            rmtree(dtmp)

=== modified file 'a/bzrlib/transport/local.py'
--- a/bzrlib/transport/local.py	
+++ b/bzrlib/transport/local.py	
@@ -28,7 +28,7 @@
 from bzrlib.trace import mutter
 from bzrlib.transport import Transport, Server
 from bzrlib.osutils import (abspath, realpath, normpath, pathjoin, rename, 
-                            check_legal_path)
+                            check_legal_path, rmtree)
 
 
 class LocalTransport(Transport):
@@ -152,7 +152,6 @@
 
     def copy(self, rel_from, rel_to):
         """Copy the item at rel_from to the location at rel_to"""
-        import shutil
         path_from = self.abspath(rel_from)
         path_to = self.abspath(rel_to)
         try:
@@ -202,8 +201,6 @@
             # Both from & to are on the local filesystem
             # Unfortunately, I can't think of anything faster than just
             # copying them across, one by one :(
-            import shutil
-
             total = self._get_total(relpaths)
             count = 0
             for path in relpaths:
@@ -297,7 +294,7 @@
         super(ScratchTransport, self).__init__(base)
 
     def __del__(self):
-        shutil.rmtree(self.base, ignore_errors=True)
+        rmtree(self.base, ignore_errors=True)
         mutter("%r destroyed" % self)
 
 



More information about the bazaar mailing list