/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/bzr/vf_repository.py

  • Committer: Breezy landing bot
  • Author(s): Jelmer Vernooij
  • Date: 2017-06-20 22:54:06 UTC
  • mfrom: (6700.2.5 remove-record-entry-contents)
  • Revision ID: breezy.the.bot@gmail.com-20170620225406-0my0i6wr2ow0o7g7
Remove remaining implementations of CommitBuilder.record_{entry_contents,delete}.

Merged from https://code.launchpad.net/~jelmer/brz/remove-record-entry-contents/+merge/325968

Show diffs side-by-side

added added

removed removed

Lines of Context:
112
112
    """Commit builder implementation for versioned files based repositories.
113
113
    """
114
114
 
115
 
    # this commit builder supports the record_entry_contents interface
116
 
    supports_record_entry_contents = True
117
 
 
118
115
    # the default CommitBuilder does not manage trees whose root is versioned.
119
116
    _versioned_root = False
120
117
 
129
126
        except IndexError:
130
127
            basis_id = _mod_revision.NULL_REVISION
131
128
        self.basis_delta_revision = basis_id
132
 
        self.new_inventory = Inventory(None)
 
129
        self._new_inventory = None
133
130
        self._basis_delta = []
134
131
        self.__heads = graph.HeadsCache(repository.get_graph()).heads
135
132
        # memo'd check for no-op commits.
220
217
        require deserializing the inventory, while we already have a copy in
221
218
        memory.
222
219
        """
223
 
        if self.new_inventory is None:
224
 
            self.new_inventory = self.repository.get_inventory(
 
220
        if self._new_inventory is None:
 
221
            self._new_inventory = self.repository.get_inventory(
225
222
                self._new_revision_id)
226
223
        return inventorytree.InventoryRevisionTree(self.repository,
227
 
            self.new_inventory, self._new_revision_id)
 
224
            self._new_inventory, self._new_revision_id)
228
225
 
229
226
    def finish_inventory(self):
230
227
        """Tell the builder that the inventory is finished.
232
229
        :return: The inventory id in the repository, which can be used with
233
230
            repository.get_inventory.
234
231
        """
235
 
        if self.new_inventory is None:
236
 
            # an inventory delta was accumulated without creating a new
237
 
            # inventory.
238
 
            basis_id = self.basis_delta_revision
239
 
            # We ignore the 'inventory' returned by add_inventory_by_delta
240
 
            # because self.new_inventory is used to hint to the rest of the
241
 
            # system what code path was taken
242
 
            self.inv_sha1, _ = self.repository.add_inventory_by_delta(
243
 
                basis_id, self._basis_delta, self._new_revision_id,
244
 
                self.parents)
245
 
        else:
246
 
            if self.new_inventory.root is None:
247
 
                raise AssertionError('Root entry should be supplied to'
248
 
                    ' record_entry_contents, as of bzr 0.10.')
249
 
                self.new_inventory.add(InventoryDirectory(ROOT_ID, '', None))
250
 
            self.new_inventory.revision_id = self._new_revision_id
251
 
            self.inv_sha1 = self.repository.add_inventory(
252
 
                self._new_revision_id,
253
 
                self.new_inventory,
254
 
                self.parents
255
 
                )
 
232
        # an inventory delta was accumulated without creating a new
 
233
        # inventory.
 
234
        basis_id = self.basis_delta_revision
 
235
        self.inv_sha1, self._new_inventory = self.repository.add_inventory_by_delta(
 
236
            basis_id, self._basis_delta, self._new_revision_id,
 
237
            self.parents)
256
238
        return self._new_revision_id
257
239
 
258
 
    def _check_root(self, ie, parent_invs, tree):
259
 
        """Helper for record_entry_contents.
260
 
 
261
 
        :param ie: An entry being added.
262
 
        :param parent_invs: The inventories of the parent revisions of the
263
 
            commit.
264
 
        :param tree: The tree that is being committed.
265
 
        """
266
 
        # In this revision format, root entries have no knit or weave When
267
 
        # serializing out to disk and back in root.revision is always
268
 
        # _new_revision_id
269
 
        ie.revision = self._new_revision_id
270
 
 
271
240
    def _require_root_change(self, tree):
272
241
        """Enforce an appropriate root object change.
273
242
 
311
280
    def get_basis_delta(self):
312
281
        """Return the complete inventory delta versus the basis inventory.
313
282
 
314
 
        This has been built up with the calls to record_delete and
315
 
        record_entry_contents.
316
 
 
317
283
        :return: An inventory delta, suitable for use with apply_delta, or
318
284
            Repository.add_inventory_by_delta, etc.
319
285
        """
320
286
        return self._basis_delta
321
287
 
322
 
    def record_delete(self, path, file_id):
323
 
        """Record that a delete occured against a basis tree.
324
 
 
325
 
        This is an optional API - when used it adds items to the basis_delta
326
 
        being accumulated by the commit builder.
327
 
 
328
 
        :param path: The path of the thing deleted.
329
 
        :param file_id: The file id that was deleted.
330
 
        """
331
 
        delta = (path, None, file_id, None)
332
 
        self._basis_delta.append(delta)
333
 
        self._any_changes = True
334
 
        return delta
335
 
 
336
 
    def record_entry_contents(self, ie, parent_invs, path, tree,
337
 
        content_summary):
338
 
        """Record the content of ie from tree into the commit if needed.
339
 
 
340
 
        Side effect: sets ie.revision when unchanged
341
 
 
342
 
        :param ie: An inventory entry present in the commit.
343
 
        :param parent_invs: The inventories of the parent revisions of the
344
 
            commit.
345
 
        :param path: The path the entry is at in the tree.
346
 
        :param tree: The tree which contains this entry and should be used to
347
 
            obtain content.
348
 
        :param content_summary: Summary data from the tree about the paths
349
 
            content - stat, length, exec, sha/link target. This is only
350
 
            accessed when the entry has a revision of None - that is when it is
351
 
            a candidate to commit.
352
 
        :return: A tuple (change_delta, version_recorded, fs_hash).
353
 
            change_delta is an inventory_delta change for this entry against
354
 
            the basis tree of the commit, or None if no change occured against
355
 
            the basis tree.
356
 
            version_recorded is True if a new version of the entry has been
357
 
            recorded. For instance, committing a merge where a file was only
358
 
            changed on the other side will return (delta, False).
359
 
            fs_hash is either None, or the hash details for the path (currently
360
 
            a tuple of the contents sha1 and the statvalue returned by
361
 
            tree.get_file_with_stat()).
362
 
        """
363
 
        if self.new_inventory.root is None:
364
 
            if ie.parent_id is not None:
365
 
                raise errors.RootMissing()
366
 
            self._check_root(ie, parent_invs, tree)
367
 
        if ie.revision is None:
368
 
            kind = content_summary[0]
369
 
        else:
370
 
            # ie is carried over from a prior commit
371
 
            kind = ie.kind
372
 
        # XXX: repository specific check for nested tree support goes here - if
373
 
        # the repo doesn't want nested trees we skip it ?
374
 
        if (kind == 'tree-reference' and
375
 
            not self.repository._format.supports_tree_reference):
376
 
            # mismatch between commit builder logic and repository:
377
 
            # this needs the entry creation pushed down into the builder.
378
 
            raise NotImplementedError('Missing repository subtree support.')
379
 
        self.new_inventory.add(ie)
380
 
 
381
 
        # TODO: slow, take it out of the inner loop.
382
 
        try:
383
 
            basis_inv = parent_invs[0]
384
 
        except IndexError:
385
 
            basis_inv = Inventory(root_id=None)
386
 
 
387
 
        # ie.revision is always None if the InventoryEntry is considered
388
 
        # for committing. We may record the previous parents revision if the
389
 
        # content is actually unchanged against a sole head.
390
 
        if ie.revision is not None:
391
 
            if not self._versioned_root and path == '':
392
 
                # repositories that do not version the root set the root's
393
 
                # revision to the new commit even when no change occurs (more
394
 
                # specifically, they do not record a revision on the root; and
395
 
                # the rev id is assigned to the root during deserialisation -
396
 
                # this masks when a change may have occurred against the basis.
397
 
                # To match this we always issue a delta, because the revision
398
 
                # of the root will always be changing.
399
 
                if basis_inv.has_id(ie.file_id):
400
 
                    delta = (basis_inv.id2path(ie.file_id), path,
401
 
                        ie.file_id, ie)
402
 
                else:
403
 
                    # add
404
 
                    delta = (None, path, ie.file_id, ie)
405
 
                self._basis_delta.append(delta)
406
 
                return delta, False, None
407
 
            else:
408
 
                # we don't need to commit this, because the caller already
409
 
                # determined that an existing revision of this file is
410
 
                # appropriate. If it's not being considered for committing then
411
 
                # it and all its parents to the root must be unaltered so
412
 
                # no-change against the basis.
413
 
                if ie.revision == self._new_revision_id:
414
 
                    raise AssertionError("Impossible situation, a skipped "
415
 
                        "inventory entry (%r) claims to be modified in this "
416
 
                        "commit (%r).", (ie, self._new_revision_id))
417
 
                return None, False, None
418
 
        # XXX: Friction: parent_candidates should return a list not a dict
419
 
        #      so that we don't have to walk the inventories again.
420
 
        parent_candidate_entries = ie.parent_candidates(parent_invs)
421
 
        head_set = self._heads(ie.file_id, parent_candidate_entries)
422
 
        heads = []
423
 
        for inv in parent_invs:
424
 
            if inv.has_id(ie.file_id):
425
 
                old_rev = inv[ie.file_id].revision
426
 
                if old_rev in head_set:
427
 
                    heads.append(inv[ie.file_id].revision)
428
 
                    head_set.remove(inv[ie.file_id].revision)
429
 
 
430
 
        store = False
431
 
        # now we check to see if we need to write a new record to the
432
 
        # file-graph.
433
 
        # We write a new entry unless there is one head to the ancestors, and
434
 
        # the kind-derived content is unchanged.
435
 
 
436
 
        # Cheapest check first: no ancestors, or more the one head in the
437
 
        # ancestors, we write a new node.
438
 
        if len(heads) != 1:
439
 
            store = True
440
 
        if not store:
441
 
            # There is a single head, look it up for comparison
442
 
            parent_entry = parent_candidate_entries[heads[0]]
443
 
            # if the non-content specific data has changed, we'll be writing a
444
 
            # node:
445
 
            if (parent_entry.parent_id != ie.parent_id or
446
 
                parent_entry.name != ie.name):
447
 
                store = True
448
 
        # now we need to do content specific checks:
449
 
        if not store:
450
 
            # if the kind changed the content obviously has
451
 
            if kind != parent_entry.kind:
452
 
                store = True
453
 
        # Stat cache fingerprint feedback for the caller - None as we usually
454
 
        # don't generate one.
455
 
        fingerprint = None
456
 
        if kind == 'file':
457
 
            if content_summary[2] is None:
458
 
                raise ValueError("Files must not have executable = None")
459
 
            if not store:
460
 
                # We can't trust a check of the file length because of content
461
 
                # filtering...
462
 
                if (# if the exec bit has changed we have to store:
463
 
                    parent_entry.executable != content_summary[2]):
464
 
                    store = True
465
 
                elif parent_entry.text_sha1 == content_summary[3]:
466
 
                    # all meta and content is unchanged (using a hash cache
467
 
                    # hit to check the sha)
468
 
                    ie.revision = parent_entry.revision
469
 
                    ie.text_size = parent_entry.text_size
470
 
                    ie.text_sha1 = parent_entry.text_sha1
471
 
                    ie.executable = parent_entry.executable
472
 
                    return self._get_delta(ie, basis_inv, path), False, None
473
 
                else:
474
 
                    # Either there is only a hash change(no hash cache entry,
475
 
                    # or same size content change), or there is no change on
476
 
                    # this file at all.
477
 
                    # Provide the parent's hash to the store layer, so that the
478
 
                    # content is unchanged we will not store a new node.
479
 
                    nostore_sha = parent_entry.text_sha1
480
 
            if store:
481
 
                # We want to record a new node regardless of the presence or
482
 
                # absence of a content change in the file.
483
 
                nostore_sha = None
484
 
            ie.executable = content_summary[2]
485
 
            file_obj, stat_value = tree.get_file_with_stat(ie.file_id, path)
486
 
            try:
487
 
                text = file_obj.read()
488
 
            finally:
489
 
                file_obj.close()
490
 
            try:
491
 
                ie.text_sha1, ie.text_size = self._add_text_to_weave(
492
 
                    ie.file_id, text, heads, nostore_sha)
493
 
                # Let the caller know we generated a stat fingerprint.
494
 
                fingerprint = (ie.text_sha1, stat_value)
495
 
            except errors.ExistingContent:
496
 
                # Turns out that the file content was unchanged, and we were
497
 
                # only going to store a new node if it was changed. Carry over
498
 
                # the entry.
499
 
                ie.revision = parent_entry.revision
500
 
                ie.text_size = parent_entry.text_size
501
 
                ie.text_sha1 = parent_entry.text_sha1
502
 
                ie.executable = parent_entry.executable
503
 
                return self._get_delta(ie, basis_inv, path), False, None
504
 
        elif kind == 'directory':
505
 
            if not store:
506
 
                # all data is meta here, nothing specific to directory, so
507
 
                # carry over:
508
 
                ie.revision = parent_entry.revision
509
 
                return self._get_delta(ie, basis_inv, path), False, None
510
 
            self._add_text_to_weave(ie.file_id, '', heads, None)
511
 
        elif kind == 'symlink':
512
 
            current_link_target = content_summary[3]
513
 
            if not store:
514
 
                # symlink target is not generic metadata, check if it has
515
 
                # changed.
516
 
                if current_link_target != parent_entry.symlink_target:
517
 
                    store = True
518
 
            if not store:
519
 
                # unchanged, carry over.
520
 
                ie.revision = parent_entry.revision
521
 
                ie.symlink_target = parent_entry.symlink_target
522
 
                return self._get_delta(ie, basis_inv, path), False, None
523
 
            ie.symlink_target = current_link_target
524
 
            self._add_text_to_weave(ie.file_id, '', heads, None)
525
 
        elif kind == 'tree-reference':
526
 
            if not store:
527
 
                if content_summary[3] != parent_entry.reference_revision:
528
 
                    store = True
529
 
            if not store:
530
 
                # unchanged, carry over.
531
 
                ie.reference_revision = parent_entry.reference_revision
532
 
                ie.revision = parent_entry.revision
533
 
                return self._get_delta(ie, basis_inv, path), False, None
534
 
            ie.reference_revision = content_summary[3]
535
 
            if ie.reference_revision is None:
536
 
                raise AssertionError("invalid content_summary for nested tree: %r"
537
 
                    % (content_summary,))
538
 
            self._add_text_to_weave(ie.file_id, '', heads, None)
539
 
        else:
540
 
            raise NotImplementedError('unknown kind')
541
 
        ie.revision = self._new_revision_id
542
 
        # The initial commit adds a root directory, but this in itself is not
543
 
        # a worthwhile commit.
544
 
        if (self.basis_delta_revision != _mod_revision.NULL_REVISION or
545
 
            path != ""):
546
 
            self._any_changes = True
547
 
        return self._get_delta(ie, basis_inv, path), True, fingerprint
548
 
 
549
288
    def record_iter_changes(self, tree, basis_revision_id, iter_changes,
550
289
        _entry_factory=entry_factory):
551
290
        """Record a new tree via iter_changes.
805
544
            inv_delta.append((change[1][0], new_path, change[0], entry))
806
545
            if new_path == '':
807
546
                seen_root = True
808
 
        self.new_inventory = None
809
547
        # The initial commit adds a root directory, but this in itself is not
810
548
        # a worthwhile commit.
811
549
        if ((len(inv_delta) > 0 and basis_revision_id != _mod_revision.NULL_REVISION) or
832
570
    # the root entry gets versioned properly by this builder.
833
571
    _versioned_root = True
834
572
 
835
 
    def _check_root(self, ie, parent_invs, tree):
836
 
        """Helper for record_entry_contents.
837
 
 
838
 
        :param ie: An entry being added.
839
 
        :param parent_invs: The inventories of the parent revisions of the
840
 
            commit.
841
 
        :param tree: The tree that is being committed.
842
 
        """
843
 
 
844
573
    def _require_root_change(self, tree):
845
574
        """Enforce an appropriate root object change.
846
575