~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/bundle/bundle_data.py

  • Committer: Andrew Bennetts
  • Date: 2010-10-08 08:15:14 UTC
  • mto: This revision was merged to the branch mainline in revision 5498.
  • Revision ID: andrew.bennetts@canonical.com-20101008081514-dviqzrdfwyzsqbz2
Split NEWS into per-release doc/en/release-notes/bzr-*.txt

Show diffs side-by-side

added added

removed removed

Lines of Context:
16
16
 
17
17
"""Read in a bundle stream, and process it into a BundleReader object."""
18
18
 
19
 
from __future__ import absolute_import
20
 
 
21
19
import base64
22
20
from cStringIO import StringIO
23
21
import os
27
25
    osutils,
28
26
    timestamp,
29
27
    )
 
28
import bzrlib.errors
30
29
from bzrlib.bundle import apply_bundle
31
 
from bzrlib.errors import (
32
 
    TestamentMismatch,
33
 
    BzrError,
34
 
    )
35
 
from bzrlib.inventory import (
36
 
    Inventory,
37
 
    InventoryDirectory,
38
 
    InventoryFile,
39
 
    InventoryLink,
40
 
    )
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,
 
34
                              InventoryLink)
 
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
47
43
 
48
44
 
210
206
 
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)
214
210
 
215
211
        return bundle_tree
216
212
 
290
286
            warning('Inventory sha hash mismatch for revision %s. %s'
291
287
                    ' != %s' % (revision_id, sha1, rev.inventory_sha1))
292
288
 
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."""
295
291
 
296
292
        # This is a mapping from each revision id to its sha hash
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:
466
462
 
467
463
 
468
464
class BundleTree(Tree):
469
 
 
470
465
    def __init__(self, base_tree, revision_id):
471
466
        self.base_tree = base_tree
472
467
        self._renamed = {} # Mapping from old_path => new_path
576
571
            return None
577
572
        return new_path
578
573
 
579
 
    def get_root_id(self):
580
 
        return self.path2id('')
581
 
 
582
574
    def path2id(self, path):
583
575
        """Return the id of the file present at path in the target tree."""
584
576
        file_id = self._new_id.get(path)
589
581
            return None
590
582
        if old_path in self.deleted:
591
583
            return None
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)
 
586
        else:
 
587
            return self.base_tree.inventory.path2id(old_path)
593
588
 
594
589
    def id2path(self, file_id):
595
590
        """Return the new path in the target tree of the file with id file_id"""
625
620
        """
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)
630
625
        else:
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)
645
640
 
646
 
    def get_symlink_target(self, file_id, path=None):
647
 
        if path is None:
648
 
            path = self.id2path(file_id)
 
641
    def get_symlink_target(self, file_id):
 
642
        new_path = self.id2path(file_id)
649
643
        try:
650
 
            return self._targets[path]
 
644
            return self._targets[new_path]
651
645
        except KeyError:
652
646
            return self.base_tree.get_symlink_target(file_id)
653
647
 
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)
658
 
 
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]
663
 
        else:
664
 
            return self.base_tree.get_file_revision(file_id)
 
651
        return self.base_tree.inventory[file_id].kind
665
652
 
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]
670
657
        else:
671
 
            return self.base_tree.is_executable(file_id)
 
658
            return self.base_tree.inventory[file_id].executable
672
659
 
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
678
665
 
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
701
689
        """
702
690
        from os.path import dirname, basename
 
691
        base_inv = self.base_tree.inventory
703
692
        inv = Inventory(None, self.revision_id)
704
693
 
705
694
        def add_entry(file_id):
712
701
                parent_path = dirname(path)
713
702
                parent_id = self.path2id(parent_path)
714
703
 
715
 
            kind = self.kind(file_id)
 
704
            kind = self.get_kind(file_id)
716
705
            revision_id = self.get_last_changed(file_id)
717
706
 
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
728
717
 
729
718
            if kind == 'file':
746
735
    # at that instant
747
736
    inventory = property(_get_inventory)
748
737
 
749
 
    root_inventory = property(_get_inventory)
750
 
 
751
 
    def all_file_ids(self):
752
 
        return set(
753
 
            [entry.file_id for path, entry in self.inventory.iter_entries()])
754
 
 
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
757
 
        inv = self.inventory
758
 
        if from_dir is None:
759
 
            from_dir_id = None
760
 
        else:
761
 
            from_dir_id = inv.path2id(from_dir)
762
 
            if from_dir_id is None:
763
 
                # Directory not versioned
764
 
                return
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.
768
 
            entries.next()
769
 
        for path, entry in entries:
770
 
            yield path, 'V', entry.kind, entry.file_id, entry
 
738
    def __iter__(self):
 
739
        for path, entry in self.inventory.iter_entries():
 
740
            yield entry.file_id
771
741
 
772
742
    def sorted_path_id(self):
773
743
        paths = []
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)
778
748
            if path is None:
779
749
                continue