Rev 5386: (parthm) EACCES error during clean-tree is now shown as a warning and bzr in file:///home/pqm/archives/thelove/bzr/%2Btrunk/

Canonical.com Patch Queue Manager pqm at pqm.ubuntu.com
Sat Aug 21 16:53:06 BST 2010


At file:///home/pqm/archives/thelove/bzr/%2Btrunk/

------------------------------------------------------------
revno: 5386 [merge]
revision-id: pqm at pqm.ubuntu.com-20100821155305-v8pgzvno9tyvhd8r
parent: pqm at pqm.ubuntu.com-20100820111010-xwracendg19hytgt
parent: parth.malwankar at gmail.com-20100821035037-tlk4qfw899rj5n8p
committer: Canonical.com Patch Queue Manager <pqm at pqm.ubuntu.com>
branch nick: +trunk
timestamp: Sat 2010-08-21 16:53:05 +0100
message:
  (parthm) EACCES error during clean-tree is now shown as a warning and bzr
   does not error out. (Parth Malwankar)
modified:
  NEWS                           NEWS-20050323055033-4e00b5db738777ff
  bzrlib/clean_tree.py           clean_tree.py-20050827022328-5ba46e22d074695c
  bzrlib/tests/test_clean_tree.py test_clean_tree.py-20060603174249-ozlk5sl2166opxbk-1
=== modified file 'NEWS'
--- a/NEWS	2010-08-20 09:39:20 +0000
+++ b/NEWS	2010-08-21 03:50:37 +0000
@@ -57,6 +57,10 @@
   regular expression.
   (Parth Malwankar #300062)
 
+* ``clean-tree`` issues a warning if it is unable to delete a file
+  due to ``errno.EACCES`` instead of exiting with an error on Windows.
+  (Parth Malwankar, #430785)
+
 * CommitBuilder now uses the committer instead of _config.username to generate
   the revision-id.  (Aaron Bentley, #614404)
 

=== modified file 'bzrlib/clean_tree.py'
--- a/bzrlib/clean_tree.py	2010-05-20 02:57:52 +0000
+++ b/bzrlib/clean_tree.py	2010-08-21 03:42:26 +0000
@@ -15,10 +15,15 @@
 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
 
+import errno
 import os
 import shutil
 
-from bzrlib import bzrdir, errors
+from bzrlib import (
+    bzrdir,
+    errors,
+    ui,
+    )
 from bzrlib.osutils import isdir
 from bzrlib.trace import note
 from bzrlib.workingtree import WorkingTree
@@ -93,16 +98,33 @@
 
 def delete_items(deletables, dry_run=False):
     """Delete files in the deletables iterable"""
+    def onerror(function, path, excinfo):
+        """Show warning for errors seen by rmtree.
+        """
+        # Handle only permission error while removing files.
+        # Other errors are re-raised.
+        if function is not os.remove or excinfo[1].errno != errno.EACCES:
+            raise
+        ui.ui_factory.show_warning('unable to remove %s' % path)
     has_deleted = False
     for path, subp in deletables:
         if not has_deleted:
             note("deleting paths:")
             has_deleted = True
-        note('  ' + subp)
         if not dry_run:
             if isdir(path):
-                shutil.rmtree(path)
+                shutil.rmtree(path, onerror=onerror)
             else:
-                os.unlink(path)
+                try:
+                    os.unlink(path)
+                    note('  ' + subp)
+                except OSError, e:
+                    # We handle only permission error here
+                    if e.errno != errno.EACCES:
+                        raise e
+                    ui.ui_factory.show_warning(
+                        'unable to remove "%s": %s.' % (path, e.strerror))
+        else:
+            note('  ' + subp)
     if not has_deleted:
         note("No files deleted.")

=== modified file 'bzrlib/tests/test_clean_tree.py'
--- a/bzrlib/tests/test_clean_tree.py	2009-03-23 14:59:43 +0000
+++ b/bzrlib/tests/test_clean_tree.py	2010-08-21 03:42:26 +0000
@@ -15,9 +15,14 @@
 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
 
+import errno
 import os
+import shutil
 from StringIO import StringIO
+import sys
+import types
 
+from bzrlib import tests, ui
 from bzrlib.bzrdir import (
     BzrDir,
     )
@@ -76,3 +81,60 @@
             self.assertEqual([], dels)
         finally:
             tree.unlock()
+
+    def test_delete_items_warnings(self):
+        """Ensure delete_items issues warnings on EACCES. (bug #430785)
+        """
+        def _dummy_unlink(path):
+            """unlink() files other than files named '0foo'.
+            """
+            if path.endswith('0foo'):
+                # Simulate 'permission denied' error.
+                # This should show up as a warning for the
+                # user.
+                e = OSError()
+                e.errno = errno.EACCES
+                raise e
+
+        def _dummy_rmtree(path, ignore_errors=False, onerror=None):
+            """Call user supplied error handler onerror.
+            """
+            self.assertTrue(isinstance(onerror, types.FunctionType))
+            # Indicate failure in removing 'path' if path is subdir0
+            # We later check to ensure that this is indicated
+            # to the user as a warning. We raise OSError to construct
+            # proper excinfo that needs to be passed to onerror
+            try:
+                raise OSError
+            except OSError, e:
+                e.errno = errno.EACCES
+                excinfo = sys.exc_info()
+                function = os.remove
+                if 'subdir0' not in path:
+                    # onerror should show warning only for os.remove
+                    # error. For any other failures the error should
+                    # be shown to the user.
+                    function = os.listdir
+                onerror(function=function,
+                    path=path, excinfo=excinfo)
+
+        self.overrideAttr(os, 'unlink', _dummy_unlink)
+        self.overrideAttr(shutil, 'rmtree', _dummy_rmtree)
+        stdout = tests.StringIOWrapper()
+        stderr = tests.StringIOWrapper()
+        ui.ui_factory = tests.TestUIFactory(stdout=stdout, stderr=stderr)
+
+        BzrDir.create_standalone_workingtree('.')
+        self.build_tree(['0foo', '1bar', '2baz', 'subdir0/'])
+        clean_tree('.', unknown=True, no_prompt=True)
+        self.assertContainsRe(stderr.getvalue(),
+            'bzr: warning: unable to remove.*0foo')
+        self.assertContainsRe(stderr.getvalue(),
+            'bzr: warning: unable to remove.*subdir0')
+
+        # Ensure that error other than EACCES during os.remove are
+        # not turned into warnings.
+        self.build_tree(['subdir1/'])
+        self.assertRaises(OSError, clean_tree, '.',
+            unknown=True, no_prompt=True)
+




More information about the bazaar-commits mailing list