/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/rename_map.py

  • Committer: Robert Collins
  • Date: 2010-05-06 11:08:10 UTC
  • mto: This revision was merged to the branch mainline in revision 5223.
  • Revision ID: robertc@robertcollins.net-20100506110810-h3j07fh5gmw54s25
Cleaner matcher matching revised unlocking protocol.

Show diffs side-by-side

added added

removed removed

Lines of Context:
14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
 
from __future__ import absolute_import
18
 
 
19
 
 
20
 
from . import (
 
17
 
 
18
from cStringIO import StringIO
 
19
 
 
20
from bzrlib import (
21
21
    osutils,
22
22
    progress,
23
23
    trace,
24
 
    )
25
 
from .i18n import gettext
26
 
from .sixish import (
27
 
    BytesIO,
28
 
    viewitems,
29
 
    viewvalues,
30
 
    )
31
 
from .ui import ui_factory
 
24
)
 
25
from bzrlib.ui import ui_factory
 
26
 
32
27
 
33
28
class RenameMap(object):
34
29
    """Determine a mapping of renames."""
65
60
        :param tree: The tree containing the files.
66
61
        :param file_ids: A list of file_ids to perform the updates for.
67
62
        """
68
 
        desired_files = [(tree.id2path(f), f) for f in file_ids]
69
 
        with ui_factory.nested_progress_bar() as task:
 
63
        desired_files = [(f, f) for f in file_ids]
 
64
        task = ui_factory.nested_progress_bar()
 
65
        try:
70
66
            for num, (file_id, contents) in enumerate(
71
67
                tree.iter_files_bytes(desired_files)):
72
 
                task.update(gettext('Calculating hashes'), num, len(file_ids))
73
 
                s = BytesIO()
 
68
                task.update('Calculating hashes', num, len(file_ids))
 
69
                s = StringIO()
74
70
                s.writelines(contents)
75
71
                s.seek(0)
76
72
                self.add_edge_hashes(s.readlines(), file_id)
 
73
        finally:
 
74
            task.finished()
77
75
 
78
76
    def hitcounts(self, lines):
79
77
        """Count the number of hash hits for each tag, for the given lines.
102
100
        :return: A list of tuples of count, path, file_id.
103
101
        """
104
102
        all_hits = []
105
 
        with ui_factory.nested_progress_bar() as task:
 
103
        task = ui_factory.nested_progress_bar()
 
104
        try:
106
105
            for num, path in enumerate(paths):
107
 
                task.update(gettext('Determining hash hits'), num, len(paths))
108
 
                hits = self.hitcounts(self.tree.get_file_lines(path))
109
 
                all_hits.extend((v, path, k) for k, v in viewitems(hits))
 
106
                task.update('Determining hash hits', num, len(paths))
 
107
                hits = self.hitcounts(self.tree.get_file_lines(None,
 
108
                                                               path=path))
 
109
                all_hits.extend((v, path, k) for k, v in hits.items())
 
110
        finally:
 
111
            task.finished()
110
112
        return all_hits
111
113
 
112
114
    def file_match(self, paths):
141
143
            while True:
142
144
                child = path
143
145
                path = osutils.dirname(path)
144
 
                if self.tree.is_versioned(path):
 
146
                if self.tree.path2id(path) is not None:
145
147
                    break
146
148
                required_parents.setdefault(path, []).append(child)
147
149
        require_ids = {}
148
 
        for parent, children in viewitems(required_parents):
 
150
        for parent, children in required_parents.iteritems():
149
151
            child_file_ids = set()
150
152
            for child in children:
151
153
                file_id = matches.get(child)
162
164
        parent directories.
163
165
        """
164
166
        all_hits = []
165
 
        for file_id, file_id_children in viewitems(missing_parents):
166
 
            for path, path_children in viewitems(required_parents):
 
167
        for file_id, file_id_children in missing_parents.iteritems():
 
168
            for path, path_children in required_parents.iteritems():
167
169
                hits = len(path_children.intersection(file_id_children))
168
170
                if hits > 0:
169
171
                    all_hits.append((hits, path, file_id))
173
175
        missing_files = set()
174
176
        missing_parents = {}
175
177
        candidate_files = set()
176
 
        with ui_factory.nested_progress_bar() as task:
177
 
            iterator = self.tree.iter_changes(basis, want_unversioned=True,
178
 
                                              pb=task)
 
178
        task = ui_factory.nested_progress_bar()
 
179
        iterator = self.tree.iter_changes(basis, want_unversioned=True,
 
180
                                          pb=task)
 
181
        try:
179
182
            for (file_id, paths, changed_content, versioned, parent, name,
180
183
                 kind, executable) in iterator:
181
184
                if kind[1] is None and versioned[1]:
182
 
                    if not self.tree.has_filename(self.tree.id2path(parent[0])):
183
 
                        missing_parents.setdefault(parent[0], set()).add(file_id)
 
185
                    missing_parents.setdefault(parent[0], set()).add(file_id)
184
186
                    if kind[0] == 'file':
185
187
                        missing_files.add(file_id)
186
188
                    else:
196
198
                            for child in children:
197
199
                                if child[2] == 'file':
198
200
                                    candidate_files.add(child[0])
 
201
        finally:
 
202
            task.finished()
199
203
        return missing_files, missing_parents, candidate_files
200
204
 
201
205
    @classmethod
202
 
    def guess_renames(klass, from_tree, to_tree, dry_run=False):
 
206
    def guess_renames(klass, tree, dry_run=False):
203
207
        """Guess which files to rename, and perform the rename.
204
208
 
205
209
        We assume that unversioned files and missing files indicate that
206
210
        versioned files have been renamed outside of Bazaar.
207
211
 
208
 
        :param from_tree: A tree to compare from
209
 
        :param to_tree: A write-locked working tree.
 
212
        :param tree: A write-locked working tree.
210
213
        """
211
214
        required_parents = {}
212
 
        with ui_factory.nested_progress_bar() as task:
 
215
        task = ui_factory.nested_progress_bar()
 
216
        try:
213
217
            pp = progress.ProgressPhase('Guessing renames', 4, task)
214
 
            with from_tree.lock_read():
215
 
                rn = klass(to_tree)
 
218
            basis = tree.basis_tree()
 
219
            basis.lock_read()
 
220
            try:
 
221
                rn = klass(tree)
216
222
                pp.next_phase()
217
223
                missing_files, missing_parents, candidate_files = (
218
 
                    rn._find_missing_files(from_tree))
 
224
                    rn._find_missing_files(basis))
219
225
                pp.next_phase()
220
 
                rn.add_file_edge_hashes(from_tree, missing_files)
 
226
                rn.add_file_edge_hashes(basis, missing_files)
 
227
            finally:
 
228
                basis.unlock()
221
229
            pp.next_phase()
222
230
            matches = rn.file_match(candidate_files)
223
231
            parents_matches = matches
230
238
            pp.next_phase()
231
239
            delta = rn._make_inventory_delta(matches)
232
240
            for old, new, file_id, entry in delta:
233
 
                trace.note( gettext("{0} => {1}").format(old, new) )
 
241
                trace.note("%s => %s", old, new)
234
242
            if not dry_run:
235
 
                to_tree.add(required_parents)
236
 
                to_tree.apply_inventory_delta(delta)
 
243
                tree.add(required_parents)
 
244
                tree.apply_inventory_delta(delta)
 
245
        finally:
 
246
            task.finished()
237
247
 
238
248
    def _make_inventory_delta(self, matches):
239
249
        delta = []
240
 
        file_id_matches = dict((f, p) for p, f in viewitems(matches))
241
 
        file_id_query = []
242
 
        for f in viewvalues(matches):
243
 
            try:
244
 
                file_id_query.append(self.tree.id2path(f))
245
 
            except errors.NoSuchId:
246
 
                pass
247
 
        for old_path, entry in self.tree.iter_entries_by_dir(
248
 
                specific_files=file_id_query):
 
250
        file_id_matches = dict((f, p) for p, f in matches.items())
 
251
        for old_path, entry in self.tree.iter_entries_by_dir(matches.values()):
249
252
            new_path = file_id_matches[entry.file_id]
250
253
            parent_path, new_name = osutils.split(new_path)
251
254
            parent_id = matches.get(parent_path)
252
255
            if parent_id is None:
253
256
                parent_id = self.tree.path2id(parent_path)
254
 
                if parent_id is None:
255
 
                    added, ignored = self.tree.smart_add([parent_path], recurse=False)
256
 
                    if len(ignored) > 0 and ignored[0] == parent_path:
257
 
                        continue
258
 
                    else:
259
 
                        parent_id = self.tree.path2id(parent_path)
260
257
            if entry.name == new_name and entry.parent_id == parent_id:
261
258
                continue
262
259
            new_entry = entry.copy()