60
60
:param tree: The tree containing the files.
61
61
:param file_ids: A list of file_ids to perform the updates for.
63
desired_files = [(f, f) for f in file_ids]
64
task = ui_factory.nested_progress_bar()
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))
66
tree.iter_files_bytes(desired_files)):
67
task.update(gettext('Calculating hashes'), num, len(file_ids))
70
69
s.writelines(contents)
72
71
self.add_edge_hashes(s.readlines(), file_id)
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.
103
task = ui_factory.nested_progress_bar()
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,
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())
114
107
def file_match(self, paths):
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,
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,
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)
189
#other kinds are not handled
183
# other kinds are not handled
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]):
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])
203
195
return missing_files, missing_parents, candidate_files
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.
209
201
We assume that unversioned files and missing files indicate that
210
202
versioned files have been renamed outside of Bazaar.
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.
214
207
required_parents = {}
215
task = ui_factory.nested_progress_bar()
208
with ui_factory.nested_progress_bar() as task:
217
209
pp = progress.ProgressPhase('Guessing renames', 4, task)
218
basis = tree.basis_tree()
210
with from_tree.lock_read():
223
213
missing_files, missing_parents, candidate_files = (
224
rn._find_missing_files(basis))
214
rn._find_missing_files(from_tree))
226
rn.add_file_edge_hashes(basis, missing_files)
216
rn.add_file_edge_hashes(from_tree, missing_files)
230
218
matches = rn.file_match(candidate_files)
231
219
parents_matches = matches
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))
243
tree.add(required_parents)
244
tree.apply_inventory_delta(delta)
231
to_tree.add(required_parents)
232
to_tree.apply_inventory_delta(delta)
248
234
def _make_inventory_delta(self, matches):
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()):
238
for f in matches.values():
240
file_id_query.append(self.tree.id2path(f))
241
except errors.NoSuchId:
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:
256
parent_id = self.tree.path2id(parent_path)
257
257
if entry.name == new_name and entry.parent_id == parent_id:
259
259
new_entry = entry.copy()