146
146
output_to, reverse=False):
147
147
"""Perform a diff between two entries of the same kind."""
149
def find_previous_heads(self, previous_inventories, entry_weave):
150
"""Return the revisions and entries that directly preceed this.
152
Returned as a map from revision to inventory entry.
154
This is a map containing the file revisions in all parents
155
for which the file exists, and its revision is not a parent of
156
any other. If the file is new, the set will be empty.
158
def get_ancestors(weave, entry):
159
return set(map(weave.idx_to_name,
160
weave.inclusions([weave.lookup(entry.revision)])))
163
for inv in previous_inventories:
164
if self.file_id in inv:
165
ie = inv[self.file_id]
166
assert ie.file_id == self.file_id
167
if ie.revision in heads:
168
assert heads[ie.revision] == ie
170
# may want to add it.
171
# may already be covered:
172
already_present = 0 != len(
173
[head for head in heads
174
if ie.revision in head_ancestors[head]])
176
# an ancestor of a known head.
179
ancestors = get_ancestors(entry_weave, ie)
180
# may knock something else out:
181
check_heads = list(heads.keys())
182
for head in check_heads:
183
if head in ancestors:
184
# this head is not really a head
186
head_ancestors[ie.revision] = ancestors
187
heads[ie.revision] = ie
149
190
def get_tar_item(self, root, dp, now, tree):
150
191
"""Get a tarfile item and a file stream for its content."""
151
192
item = tarfile.TarInfo(os.path.join(root, dp))
159
200
"""Return true if the object this entry represents has textual data.
161
202
Note that textual data includes binary content.
204
Also note that all entries get weave files created for them.
205
This attribute is primarily used when upgrading from old trees that
206
did not have the weave index for all inventory entries.
267
def snapshot(self, revision, path, previous_entries, work_tree,
312
def snapshot(self, revision, path, previous_entries,
313
work_tree, weave_store):
269
314
"""Make a snapshot of this entry which may or may not have changed.
271
316
This means that all its fields are populated, that it has its
276
321
if len(previous_entries) == 1:
277
322
# cannot be unchanged unless there is only one parent file rev.
278
323
parent_ie = previous_entries.values()[0]
279
if self._unchanged(path, parent_ie, work_tree):
324
if self._unchanged(parent_ie):
280
325
mutter("found unchanged entry")
281
326
self.revision = parent_ie.revision
282
327
return "unchanged"
289
334
mutter('new revision for {%s}', self.file_id)
290
335
self.revision = revision
291
336
change = self._get_snapshot_change(previous_entries)
337
self._snapshot_text(previous_entries, work_tree, weave_store)
294
340
def _snapshot_text(self, file_parents, work_tree, weave_store):
341
"""Record the 'text' of this entry, whatever form that takes.
343
This default implementation simply adds an empty text.
295
345
mutter('storing file {%s} in revision {%s}',
296
346
self.file_id, self.revision)
297
# special case to avoid diffing on renames or
299
if (len(file_parents) == 1
300
and self.text_sha1 == file_parents.values()[0].text_sha1
301
and self.text_size == file_parents.values()[0].text_size):
302
previous_ie = file_parents.values()[0]
303
weave_store.add_identical_text(
304
self.file_id, previous_ie.revision,
305
self.revision, file_parents)
307
new_lines = work_tree.get_file(self.file_id).readlines()
308
self._add_text_to_weave(new_lines, file_parents, weave_store)
309
self.text_sha1 = sha_strings(new_lines)
310
self.text_size = sum(map(len, new_lines))
347
self._add_text_to_weave([], file_parents, weave_store)
312
349
def __eq__(self, other):
313
350
if not isinstance(other, InventoryEntry):
331
368
def __hash__(self):
332
369
raise ValueError('not hashable')
334
def _unchanged(self, path, previous_ie, work_tree):
371
def _unchanged(self, previous_ie):
335
372
"""Has this entry changed relative to previous_ie.
337
374
This method should be overriden in child classes.
502
539
self.text_sha1 = work_tree.get_file_sha1(self.file_id)
503
540
self.executable = work_tree.is_executable(self.file_id)
505
def snapshot_revision(self, revision, previous_entries, work_tree,
507
"""See InventoryEntry.snapshot_revision."""
508
change = super(InventoryFile, self).snapshot_revision(revision,
509
previous_entries, work_tree, weave_store)
510
self._snapshot_text(previous_entries, work_tree, weave_store)
513
def _unchanged(self, path, previous_ie, work_tree):
542
def _snapshot_text(self, file_parents, work_tree, weave_store):
543
"""See InventoryEntry._snapshot_text."""
544
mutter('storing file {%s} in revision {%s}',
545
self.file_id, self.revision)
546
# special case to avoid diffing on renames or
548
if (len(file_parents) == 1
549
and self.text_sha1 == file_parents.values()[0].text_sha1
550
and self.text_size == file_parents.values()[0].text_size):
551
previous_ie = file_parents.values()[0]
552
weave_store.add_identical_text(
553
self.file_id, previous_ie.revision,
554
self.revision, file_parents)
556
new_lines = work_tree.get_file(self.file_id).readlines()
557
self._add_text_to_weave(new_lines, file_parents, weave_store)
558
self.text_sha1 = sha_strings(new_lines)
559
self.text_size = sum(map(len, new_lines))
562
def _unchanged(self, previous_ie):
514
563
"""See InventoryEntry._unchanged."""
515
compatible = super(InventoryFile, self)._unchanged(path, previous_ie,
564
compatible = super(InventoryFile, self)._unchanged(previous_ie)
517
565
if self.text_sha1 != previous_ie.text_sha1:
518
566
compatible = False
597
645
"""See InventoryEntry._read_tree_state."""
598
646
self.symlink_target = work_tree.get_symlink_target(self.file_id)
600
def _unchanged(self, path, previous_ie, work_tree):
648
def _unchanged(self, previous_ie):
601
649
"""See InventoryEntry._unchanged."""
602
compatible = super(InventoryLink, self)._unchanged(path, previous_ie,
650
compatible = super(InventoryLink, self)._unchanged(previous_ie)
604
651
if self.symlink_target != previous_ie.symlink_target:
605
652
compatible = False
606
653
return compatible