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