159
163
This is a map containing the file revisions in all parents
160
164
for which the file exists, and its revision is not a parent of
161
165
any other. If the file is new, the set will be empty.
167
:param versioned_file_store: A store where ancestry data on this
168
file id can be queried.
169
:param transaction: The transaction that queries to the versioned
170
file store should be completed under.
171
:param entry_vf: The entry versioned file, if its already available.
163
173
def get_ancestors(weave, entry):
164
174
return set(weave.get_ancestry(entry.revision))
175
# revision:ie mapping for each ie found in previous_inventories.
177
# revision:ie mapping with one revision for each head.
179
# revision: ancestor list for each head
166
180
head_ancestors = {}
181
# identify candidate head revision ids.
167
182
for inv in previous_inventories:
168
183
if self.file_id in inv:
169
184
ie = inv[self.file_id]
170
185
assert ie.file_id == self.file_id
171
if ie.revision in heads:
172
# fixup logic, there was a bug in revision updates.
173
# with x bit support.
186
if ie.revision in candidates:
187
# same revision value in two different inventories:
188
# correct possible inconsistencies:
189
# * there was a bug in revision updates with 'x' bit
175
if heads[ie.revision].executable != ie.executable:
176
heads[ie.revision].executable = False
192
if candidates[ie.revision].executable != ie.executable:
193
candidates[ie.revision].executable = False
177
194
ie.executable = False
178
195
except AttributeError:
180
assert heads[ie.revision] == ie
197
# must now be the same.
198
assert candidates[ie.revision] == ie
182
# may want to add it.
183
# may already be covered:
184
already_present = 0 != len(
185
[head for head in heads
186
if ie.revision in head_ancestors[head]])
188
# an ancestor of a known head.
191
ancestors = get_ancestors(entry_weave, ie)
192
# may knock something else out:
193
check_heads = list(heads.keys())
194
for head in check_heads:
195
if head in ancestors:
196
# this head is not really a head
198
head_ancestors[ie.revision] = ancestors
199
heads[ie.revision] = ie
200
# add this revision as a candidate.
201
candidates[ie.revision] = ie
203
# common case optimisation
204
if len(candidates) == 1:
205
# if there is only one candidate revision found
206
# then we can opening the versioned file to access ancestry:
207
# there cannot be any ancestors to eliminate when there is
208
# only one revision available.
209
heads[ie.revision] = ie
212
# eliminate ancestors amongst the available candidates:
213
# heads are those that are not an ancestor of any other candidate
214
# - this provides convergence at a per-file level.
215
for ie in candidates.values():
216
# may be an ancestor of a known head:
217
already_present = 0 != len(
218
[head for head in heads
219
if ie.revision in head_ancestors[head]])
221
# an ancestor of an analyzed candidate.
223
# not an ancestor of a known head:
224
# load the versioned file for this file id if needed
226
entry_vf = versioned_file_store.get_weave_or_empty(
227
self.file_id, transaction)
228
ancestors = get_ancestors(entry_vf, ie)
229
# may knock something else out:
230
check_heads = list(heads.keys())
231
for head in check_heads:
232
if head in ancestors:
233
# this previously discovered 'head' is not
234
# really a head - its an ancestor of the newly
237
head_ancestors[ie.revision] = ancestors
238
heads[ie.revision] = ie
202
241
def get_tar_item(self, root, dp, now, tree):