30
29
from bzrlib.bundle import apply_bundle
31
from bzrlib.errors import (
35
from bzrlib.inventory import (
41
from bzrlib.osutils import sha_string, pathjoin
30
from bzrlib.errors import (TestamentMismatch, BzrError,
31
MalformedHeader, MalformedPatches, NotABundle)
32
from bzrlib.inventory import (Inventory, InventoryEntry,
33
InventoryDirectory, InventoryFile,
35
from bzrlib.osutils import sha_file, sha_string, pathjoin
42
36
from bzrlib.revision import Revision, NULL_REVISION
43
37
from bzrlib.testament import StrictTestament
44
38
from bzrlib.trace import mutter, warning
39
import bzrlib.transport
45
40
from bzrlib.tree import Tree
41
import bzrlib.urlutils
46
42
from bzrlib.xml5 import serializer_v5
211
207
inv = bundle_tree.inventory
212
208
self._validate_inventory(inv, revision_id)
213
self._validate_revision(bundle_tree, revision_id)
209
self._validate_revision(inv, revision_id)
215
211
return bundle_tree
290
286
warning('Inventory sha hash mismatch for revision %s. %s'
291
287
' != %s' % (revision_id, sha1, rev.inventory_sha1))
293
def _validate_revision(self, tree, revision_id):
289
def _validate_revision(self, inventory, revision_id):
294
290
"""Make sure all revision entries match their checksum."""
296
# This is a mapping from each revision id to its sha hash
292
# This is a mapping from each revision id to it's sha hash
299
295
rev = self.get_revision(revision_id)
302
298
raise AssertionError()
303
299
if not (rev.revision_id == revision_id):
304
300
raise AssertionError()
305
sha1 = self._testament_sha1(rev, tree)
301
sha1 = self._testament_sha1(rev, inventory)
306
302
if sha1 != rev_info.sha1:
307
303
raise TestamentMismatch(rev.revision_id, rev_info.sha1, sha1)
308
304
if rev.revision_id in rev_to_sha1:
590
582
if old_path in self.deleted:
592
return self.base_tree.path2id(old_path)
584
if getattr(self.base_tree, 'path2id', None) is not None:
585
return self.base_tree.path2id(old_path)
587
return self.base_tree.inventory.path2id(old_path)
594
589
def id2path(self, file_id):
595
590
"""Return the new path in the target tree of the file with id file_id"""
626
621
base_id = self.old_contents_id(file_id)
627
622
if (base_id is not None and
628
base_id != self.base_tree.get_root_id()):
623
base_id != self.base_tree.inventory.root.file_id):
629
624
patch_original = self.base_tree.get_file(base_id)
631
626
patch_original = None
632
627
file_patch = self.patches.get(self.id2path(file_id))
633
628
if file_patch is None:
634
629
if (patch_original is None and
635
self.kind(file_id) == 'directory'):
630
self.get_kind(file_id) == 'directory'):
636
631
return StringIO()
637
632
if patch_original is None:
638
633
raise AssertionError("None: %s" % file_id)
643
638
'Malformed patch for %s, %r' % (file_id, file_patch))
644
639
return patched_file(file_patch, patch_original)
646
def get_symlink_target(self, file_id, path=None):
648
path = self.id2path(file_id)
641
def get_symlink_target(self, file_id):
642
new_path = self.id2path(file_id)
650
return self._targets[path]
644
return self._targets[new_path]
652
646
return self.base_tree.get_symlink_target(file_id)
654
def kind(self, file_id):
648
def get_kind(self, file_id):
655
649
if file_id in self._kinds:
656
650
return self._kinds[file_id]
657
return self.base_tree.kind(file_id)
659
def get_file_revision(self, file_id):
660
path = self.id2path(file_id)
661
if path in self._last_changed:
662
return self._last_changed[path]
664
return self.base_tree.get_file_revision(file_id)
651
return self.base_tree.inventory[file_id].kind
666
653
def is_executable(self, file_id):
667
654
path = self.id2path(file_id)
668
655
if path in self._executable:
669
656
return self._executable[path]
671
return self.base_tree.is_executable(file_id)
658
return self.base_tree.inventory[file_id].executable
673
660
def get_last_changed(self, file_id):
674
661
path = self.id2path(file_id)
675
662
if path in self._last_changed:
676
663
return self._last_changed[path]
677
return self.base_tree.get_file_revision(file_id)
664
return self.base_tree.inventory[file_id].revision
679
666
def get_size_and_sha1(self, file_id):
680
667
"""Return the size and sha1 hash of the given file id.
687
674
if new_path not in self.patches:
688
675
# If the entry does not have a patch, then the
689
676
# contents must be the same as in the base_tree
690
text_size = self.base_tree.get_file_size(file_id)
691
text_sha1 = self.base_tree.get_file_sha1(file_id)
692
return text_size, text_sha1
677
ie = self.base_tree.inventory[file_id]
678
if ie.text_size is None:
679
return ie.text_size, ie.text_sha1
680
return int(ie.text_size), ie.text_sha1
693
681
fileobj = self.get_file(file_id)
694
682
content = fileobj.read()
695
683
return len(content), sha_string(content)
700
688
This need to be called before ever accessing self.inventory
702
690
from os.path import dirname, basename
691
base_inv = self.base_tree.inventory
703
692
inv = Inventory(None, self.revision_id)
705
694
def add_entry(file_id):
712
701
parent_path = dirname(path)
713
702
parent_id = self.path2id(parent_path)
715
kind = self.kind(file_id)
704
kind = self.get_kind(file_id)
716
705
revision_id = self.get_last_changed(file_id)
718
707
name = basename(path)
723
712
ie.executable = self.is_executable(file_id)
724
713
elif kind == 'symlink':
725
714
ie = InventoryLink(file_id, name, parent_id)
726
ie.symlink_target = self.get_symlink_target(file_id, path)
715
ie.symlink_target = self.get_symlink_target(file_id)
727
716
ie.revision = revision_id
729
718
if kind == 'file':
746
735
# at that instant
747
736
inventory = property(_get_inventory)
749
root_inventory = property(_get_inventory)
751
def all_file_ids(self):
753
[entry.file_id for path, entry in self.inventory.iter_entries()])
755
def list_files(self, include_root=False, from_dir=None, recursive=True):
756
# The only files returned by this are those from the version
761
from_dir_id = inv.path2id(from_dir)
762
if from_dir_id is None:
763
# Directory not versioned
765
entries = inv.iter_entries(from_dir=from_dir_id, recursive=recursive)
766
if inv.root is not None and not include_root and from_dir is None:
767
# skip the root for compatability with the current apis.
769
for path, entry in entries:
770
yield path, 'V', entry.kind, entry.file_id, entry
739
for path, entry in self.inventory.iter_entries():
772
742
def sorted_path_id(self):
774
744
for result in self._new_id.iteritems():
775
745
paths.append(result)
776
for id in self.base_tree.all_file_ids():
746
for id in self.base_tree:
777
747
path = self.id2path(id)