/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-04-05 19:11:34 UTC
  • mto: (7490.7.16 work)
  • mto: This revision was merged to the branch mainline in revision 7501.
  • Revision ID: jelmer@jelmer.uk-20200405191134-0aebh8ikiwygxma5
Populate the .gitignore file.

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