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

  • Committer: Jelmer Vernooij
  • Date: 2020-03-22 01:35:14 UTC
  • mfrom: (7490.7.6 work)
  • mto: This revision was merged to the branch mainline in revision 7499.
  • Revision ID: jelmer@jelmer.uk-20200322013514-7vw1ntwho04rcuj3
merge lp:brz/3.1.

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
 
 
 
17
from io import BytesIO
19
18
 
20
19
from . import (
21
20
    osutils,
23
22
    trace,
24
23
    )
25
24
from .i18n import gettext
26
 
from .sixish import (
27
 
    BytesIO,
28
 
    viewitems,
29
 
    )
30
25
from .ui import ui_factory
31
26
 
 
27
 
32
28
class RenameMap(object):
33
29
    """Determine a mapping of renames."""
34
30
 
47
43
        """
48
44
        modulus = 1024 * 1024 * 10
49
45
        for n in range(len(lines)):
50
 
            yield hash(tuple(lines[n:n+2])) % modulus
 
46
            yield hash(tuple(lines[n:n + 2])) % modulus
51
47
 
52
48
    def add_edge_hashes(self, lines, tag):
53
49
        """Update edge_hashes to include the given lines.
64
60
        :param tree: The tree containing the files.
65
61
        :param file_ids: A list of file_ids to perform the updates for.
66
62
        """
67
 
        desired_files = [(f, f) for f in file_ids]
68
 
        task = ui_factory.nested_progress_bar()
69
 
        try:
 
63
        desired_files = [(tree.id2path(f), f) for f in file_ids]
 
64
        with ui_factory.nested_progress_bar() as task:
70
65
            for num, (file_id, contents) in enumerate(
71
 
                tree.iter_files_bytes(desired_files)):
 
66
                    tree.iter_files_bytes(desired_files)):
72
67
                task.update(gettext('Calculating hashes'), num, len(file_ids))
73
68
                s = BytesIO()
74
69
                s.writelines(contents)
75
70
                s.seek(0)
76
71
                self.add_edge_hashes(s.readlines(), file_id)
77
 
        finally:
78
 
            task.finished()
79
72
 
80
73
    def hitcounts(self, lines):
81
74
        """Count the number of hash hits for each tag, for the given lines.
104
97
        :return: A list of tuples of count, path, file_id.
105
98
        """
106
99
        all_hits = []
107
 
        task = ui_factory.nested_progress_bar()
108
 
        try:
 
100
        with ui_factory.nested_progress_bar() as task:
109
101
            for num, path in enumerate(paths):
110
102
                task.update(gettext('Determining hash hits'), num, len(paths))
111
103
                hits = self.hitcounts(self.tree.get_file_lines(path))
112
 
                all_hits.extend((v, path, k) for k, v in viewitems(hits))
113
 
        finally:
114
 
            task.finished()
 
104
                all_hits.extend((v, path, k) for k, v in hits.items())
115
105
        return all_hits
116
106
 
117
107
    def file_match(self, paths):
150
140
                    break
151
141
                required_parents.setdefault(path, []).append(child)
152
142
        require_ids = {}
153
 
        for parent, children in viewitems(required_parents):
 
143
        for parent, children in required_parents.items():
154
144
            child_file_ids = set()
155
145
            for child in children:
156
146
                file_id = matches.get(child)
167
157
        parent directories.
168
158
        """
169
159
        all_hits = []
170
 
        for file_id, file_id_children in viewitems(missing_parents):
171
 
            for path, path_children in viewitems(required_parents):
 
160
        for file_id, file_id_children in missing_parents.items():
 
161
            for path, path_children in required_parents.items():
172
162
                hits = len(path_children.intersection(file_id_children))
173
163
                if hits > 0:
174
164
                    all_hits.append((hits, path, file_id))
178
168
        missing_files = set()
179
169
        missing_parents = {}
180
170
        candidate_files = set()
181
 
        task = ui_factory.nested_progress_bar()
182
 
        iterator = self.tree.iter_changes(basis, want_unversioned=True,
183
 
                                          pb=task)
184
 
        try:
185
 
            for (file_id, paths, changed_content, versioned, parent, name,
186
 
                 kind, executable) in iterator:
187
 
                if kind[1] is None and versioned[1]:
188
 
                    if not self.tree.has_filename(self.tree.id2path(parent[0])):
189
 
                        missing_parents.setdefault(parent[0], set()).add(file_id)
190
 
                    if kind[0] == 'file':
191
 
                        missing_files.add(file_id)
 
171
        with ui_factory.nested_progress_bar() as task:
 
172
            iterator = self.tree.iter_changes(basis, want_unversioned=True,
 
173
                                              pb=task)
 
174
            for change in iterator:
 
175
                if change.kind[1] is None and change.versioned[1]:
 
176
                    if not self.tree.has_filename(
 
177
                            self.tree.id2path(change.parent_id[0])):
 
178
                        missing_parents.setdefault(
 
179
                            change.parent_id[0], set()).add(change.file_id)
 
180
                    if change.kind[0] == 'file':
 
181
                        missing_files.add(change.file_id)
192
182
                    else:
193
 
                        #other kinds are not handled
 
183
                        # other kinds are not handled
194
184
                        pass
195
 
                if versioned == (False, False):
196
 
                    if self.tree.is_ignored(paths[1]):
 
185
                if change.versioned == (False, False):
 
186
                    if self.tree.is_ignored(change.path[1]):
197
187
                        continue
198
 
                    if kind[1] == 'file':
199
 
                        candidate_files.add(paths[1])
200
 
                    if kind[1] == 'directory':
201
 
                        for _dir, children in self.tree.walkdirs(paths[1]):
 
188
                    if change.kind[1] == 'file':
 
189
                        candidate_files.add(change.path[1])
 
190
                    if change.kind[1] == 'directory':
 
191
                        for _dir, children in self.tree.walkdirs(change.path[1]):
202
192
                            for child in children:
203
193
                                if child[2] == 'file':
204
194
                                    candidate_files.add(child[0])
205
 
        finally:
206
 
            task.finished()
207
195
        return missing_files, missing_parents, candidate_files
208
196
 
209
197
    @classmethod
210
 
    def guess_renames(klass, tree, dry_run=False):
 
198
    def guess_renames(klass, from_tree, to_tree, dry_run=False):
211
199
        """Guess which files to rename, and perform the rename.
212
200
 
213
201
        We assume that unversioned files and missing files indicate that
214
202
        versioned files have been renamed outside of Bazaar.
215
203
 
216
 
        :param tree: A write-locked working tree.
 
204
        :param from_tree: A tree to compare from
 
205
        :param to_tree: A write-locked working tree.
217
206
        """
218
207
        required_parents = {}
219
 
        task = ui_factory.nested_progress_bar()
220
 
        try:
 
208
        with ui_factory.nested_progress_bar() as task:
221
209
            pp = progress.ProgressPhase('Guessing renames', 4, task)
222
 
            basis = tree.basis_tree()
223
 
            basis.lock_read()
224
 
            try:
225
 
                rn = klass(tree)
 
210
            with from_tree.lock_read():
 
211
                rn = klass(to_tree)
226
212
                pp.next_phase()
227
213
                missing_files, missing_parents, candidate_files = (
228
 
                    rn._find_missing_files(basis))
 
214
                    rn._find_missing_files(from_tree))
229
215
                pp.next_phase()
230
 
                rn.add_file_edge_hashes(basis, missing_files)
231
 
            finally:
232
 
                basis.unlock()
 
216
                rn.add_file_edge_hashes(from_tree, missing_files)
233
217
            pp.next_phase()
234
218
            matches = rn.file_match(candidate_files)
235
219
            parents_matches = matches
242
226
            pp.next_phase()
243
227
            delta = rn._make_inventory_delta(matches)
244
228
            for old, new, file_id, entry in delta:
245
 
                trace.note( gettext("{0} => {1}").format(old, new) )
 
229
                trace.note(gettext("{0} => {1}").format(old, new))
246
230
            if not dry_run:
247
 
                tree.add(required_parents)
248
 
                tree.apply_inventory_delta(delta)
249
 
        finally:
250
 
            task.finished()
 
231
                to_tree.add(required_parents)
 
232
                to_tree.apply_inventory_delta(delta)
251
233
 
252
234
    def _make_inventory_delta(self, matches):
253
235
        delta = []
254
 
        file_id_matches = dict((f, p) for p, f in viewitems(matches))
255
 
        for old_path, entry in self.tree.iter_entries_by_dir(file_id_matches):
 
236
        file_id_matches = dict((f, p) for p, f in matches.items())
 
237
        file_id_query = []
 
238
        for f in matches.values():
 
239
            try:
 
240
                file_id_query.append(self.tree.id2path(f))
 
241
            except errors.NoSuchId:
 
242
                pass
 
243
        for old_path, entry in self.tree.iter_entries_by_dir(
 
244
                specific_files=file_id_query):
256
245
            new_path = file_id_matches[entry.file_id]
257
246
            parent_path, new_name = osutils.split(new_path)
258
247
            parent_id = matches.get(parent_path)
259
248
            if parent_id is None:
260
249
                parent_id = self.tree.path2id(parent_path)
261
250
                if parent_id is None:
262
 
                    added, ignored = self.tree.smart_add([parent_path], recurse=False)
 
251
                    added, ignored = self.tree.smart_add(
 
252
                        [parent_path], recurse=False)
263
253
                    if len(ignored) > 0 and ignored[0] == parent_path:
264
254
                        continue
265
255
                    else: