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

  • Committer: Jelmer Vernooij
  • Date: 2017-05-21 12:41:27 UTC
  • mto: This revision was merged to the branch mainline in revision 6623.
  • Revision ID: jelmer@jelmer.uk-20170521124127-iv8etg0vwymyai6y
s/bzr/brz/ in apport config.

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