64
60
:param tree: The tree containing the files.
65
61
:param file_ids: A list of file_ids to perform the updates for.
67
desired_files = [(f, f) for f in file_ids]
68
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:
70
65
for num, (file_id, contents) in enumerate(
71
tree.iter_files_bytes(desired_files)):
66
tree.iter_files_bytes(desired_files)):
72
67
task.update(gettext('Calculating hashes'), num, len(file_ids))
74
69
s.writelines(contents)
76
71
self.add_edge_hashes(s.readlines(), file_id)
80
73
def hitcounts(self, lines):
81
74
"""Count the number of hash hits for each tag, for the given lines.
104
97
:return: A list of tuples of count, path, file_id.
107
task = ui_factory.nested_progress_bar()
100
with ui_factory.nested_progress_bar() as task:
109
101
for num, path in enumerate(paths):
110
102
task.update(gettext('Determining hash hits'), num, len(paths))
111
103
hits = self.hitcounts(self.tree.get_file_lines(path))
112
all_hits.extend((v, path, k) for k, v in viewitems(hits))
104
all_hits.extend((v, path, k) for k, v in hits.items())
117
107
def file_match(self, paths):
178
168
missing_files = set()
179
169
missing_parents = {}
180
170
candidate_files = set()
181
task = ui_factory.nested_progress_bar()
182
iterator = self.tree.iter_changes(basis, want_unversioned=True,
185
for (file_id, paths, changed_content, versioned, parent, name,
186
kind, executable) in iterator:
187
if kind[1] is None and versioned[1]:
188
if not self.tree.has_filename(self.tree.id2path(parent[0])):
189
missing_parents.setdefault(parent[0], set()).add(file_id)
190
if kind[0] == 'file':
191
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)
193
#other kinds are not handled
183
# other kinds are not handled
195
if versioned == (False, False):
196
if self.tree.is_ignored(paths[1]):
185
if change.versioned == (False, False):
186
if self.tree.is_ignored(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]):
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]):
202
192
for child in children:
203
193
if child[2] == 'file':
204
194
candidate_files.add(child[0])
207
195
return missing_files, missing_parents, candidate_files
210
def guess_renames(klass, tree, dry_run=False):
198
def guess_renames(klass, from_tree, to_tree, dry_run=False):
211
199
"""Guess which files to rename, and perform the rename.
213
201
We assume that unversioned files and missing files indicate that
214
202
versioned files have been renamed outside of Bazaar.
216
: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.
218
207
required_parents = {}
219
task = ui_factory.nested_progress_bar()
208
with ui_factory.nested_progress_bar() as task:
221
209
pp = progress.ProgressPhase('Guessing renames', 4, task)
222
basis = tree.basis_tree()
210
with from_tree.lock_read():
227
213
missing_files, missing_parents, candidate_files = (
228
rn._find_missing_files(basis))
214
rn._find_missing_files(from_tree))
230
rn.add_file_edge_hashes(basis, missing_files)
216
rn.add_file_edge_hashes(from_tree, missing_files)
234
218
matches = rn.file_match(candidate_files)
235
219
parents_matches = matches
243
227
delta = rn._make_inventory_delta(matches)
244
228
for old, new, file_id, entry in delta:
245
trace.note( gettext("{0} => {1}").format(old, new) )
229
trace.note(gettext("{0} => {1}").format(old, new))
247
tree.add(required_parents)
248
tree.apply_inventory_delta(delta)
231
to_tree.add(required_parents)
232
to_tree.apply_inventory_delta(delta)
252
234
def _make_inventory_delta(self, matches):
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):
236
file_id_matches = dict((f, p) for p, f in matches.items())
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):
256
245
new_path = file_id_matches[entry.file_id]
257
246
parent_path, new_name = osutils.split(new_path)
258
247
parent_id = matches.get(parent_path)
259
248
if parent_id is None:
260
249
parent_id = self.tree.path2id(parent_path)
261
250
if parent_id is None:
262
added, ignored = self.tree.smart_add([parent_path], recurse=False)
251
added, ignored = self.tree.smart_add(
252
[parent_path], recurse=False)
263
253
if len(ignored) > 0 and ignored[0] == parent_path: