/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: 2017-06-08 23:30:31 UTC
  • mto: This revision was merged to the branch mainline in revision 6690.
  • Revision ID: jelmer@jelmer.uk-20170608233031-3qavls2o7a1pqllj
Update imports.

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