/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/clean_tree.py

  • Committer: John Arbash Meinel
  • Date: 2011-04-20 14:27:19 UTC
  • mto: This revision was merged to the branch mainline in revision 5837.
  • Revision ID: john@arbash-meinel.com-20110420142719-advs1k5vztqzbrgv
Fix bug #767177. Be more agressive with file.close() calls.

Our test suite gets a number of thread leaks and failures because it happens to get async
SFTPFile.close() calls. (if an SFTPFile closes due to __del__ it is done as an async request,
while if you call SFTPFile.close() it is done as a synchronous request.)
We have a couple other cases, probably. Namely SFTPTransport.get() also does an async
prefetch of the content, so if you don't .read() you'll also leak threads that think they
are doing work that you want.

The biggest change here, though, is using a try/finally in a generator, which is not 
python2.4 compatible.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005 Canonical Ltd
 
1
# Copyright (C) 2009, 2010 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
15
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
17
 
 
18
import errno
18
19
import os
19
20
import shutil
20
21
 
 
22
from bzrlib import (
 
23
    bzrdir,
 
24
    errors,
 
25
    ui,
 
26
    )
21
27
from bzrlib.osutils import isdir
22
28
from bzrlib.trace import note
23
29
from bzrlib.workingtree import WorkingTree
51
57
    try:
52
58
        deletables = list(iter_deletables(tree, unknown=unknown,
53
59
            ignored=ignored, detritus=detritus))
 
60
        deletables = _filter_out_nested_bzrdirs(deletables)
54
61
        if len(deletables) == 0:
55
62
            note('Nothing to delete.')
56
63
            return 0
57
64
        if not no_prompt:
58
65
            for path, subp in deletables:
 
66
                # FIXME using print is very bad idea
 
67
                # clean_tree should accept to_file argument to write the output
59
68
                print subp
60
69
            val = raw_input('Are you sure you wish to delete these [y/N]?')
61
70
            if val.lower() not in ('y', 'yes'):
66
75
        tree.unlock()
67
76
 
68
77
 
 
78
def _filter_out_nested_bzrdirs(deletables):
 
79
    result = []
 
80
    for path, subp in deletables:
 
81
        # bzr won't recurse into unknowns/ignored directories by default
 
82
        # so we don't pay a penalty for checking subdirs of path for nested
 
83
        # bzrdir.
 
84
        # That said we won't detect the branch in the subdir of non-branch
 
85
        # directory and therefore delete it. (worth to FIXME?)
 
86
        if isdir(path):
 
87
            try:
 
88
                bzrdir.BzrDir.open(path)
 
89
            except errors.NotBranchError:
 
90
                result.append((path,subp))
 
91
            else:
 
92
                # TODO may be we need to notify user about skipped directories?
 
93
                pass
 
94
        else:
 
95
            result.append((path,subp))
 
96
    return result
 
97
 
 
98
 
69
99
def delete_items(deletables, dry_run=False):
70
100
    """Delete files in the deletables iterable"""
 
101
    def onerror(function, path, excinfo):
 
102
        """Show warning for errors seen by rmtree.
 
103
        """
 
104
        # Handle only permission error while removing files.
 
105
        # Other errors are re-raised.
 
106
        if function is not os.remove or excinfo[1].errno != errno.EACCES:
 
107
            raise
 
108
        ui.ui_factory.show_warning('unable to remove %s' % path)
71
109
    has_deleted = False
72
110
    for path, subp in deletables:
73
111
        if not has_deleted:
74
112
            note("deleting paths:")
75
113
            has_deleted = True
76
 
        note('  ' + subp)
77
114
        if not dry_run:
78
115
            if isdir(path):
79
 
                shutil.rmtree(path)
 
116
                shutil.rmtree(path, onerror=onerror)
80
117
            else:
81
 
                os.unlink(path)
 
118
                try:
 
119
                    os.unlink(path)
 
120
                    note('  ' + subp)
 
121
                except OSError, e:
 
122
                    # We handle only permission error here
 
123
                    if e.errno != errno.EACCES:
 
124
                        raise e
 
125
                    ui.ui_factory.show_warning(
 
126
                        'unable to remove "%s": %s.' % (path, e.strerror))
 
127
        else:
 
128
            note('  ' + subp)
82
129
    if not has_deleted:
83
130
        note("No files deleted.")