/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: Gustav Hartvigsson
  • Date: 2021-01-09 21:36:27 UTC
  • Revision ID: gustav.hartvigsson@gmail.com-20210109213627-h1xwcutzy9m7a99b
Added 'Case Preserving Working Tree Use Cases' from Canonical Wiki

* Addod a page from the Canonical Bazaar wiki
  with information on the scmeatics of case
  perserving filesystems an a case insensitive
  filesystem works.
  
  * Needs re-work, but this will do as it is the
    same inforamoton as what was on the linked
    page in the currint documentation.

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