~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/bundle/bundle_data.py

  • Committer: John Arbash Meinel
  • Date: 2009-06-04 16:50:33 UTC
  • mto: This revision was merged to the branch mainline in revision 4410.
  • Revision ID: john@arbash-meinel.com-20090604165033-bfdo0lyf4yt4vjcz
We don't need a base Coder class, because Decoder._update_tail is different than Encoder._update_tail.
(one adds, one subtracts from self.size).
So we now have 2 versions of the macro, and the test suite stops crashing... :)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2010 Canonical Ltd
 
1
# Copyright (C) 2006 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
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
 
282
278
        if rev.revision_id != revision_id:
283
279
            raise AssertionError()
284
280
        if sha1 != rev.inventory_sha1:
285
 
            f = open(',,bogus-inv', 'wb')
286
 
            try:
287
 
                f.write(s)
288
 
            finally:
289
 
                f.close()
 
281
            open(',,bogus-inv', 'wb').write(s)
290
282
            warning('Inventory sha hash mismatch for revision %s. %s'
291
283
                    ' != %s' % (revision_id, sha1, rev.inventory_sha1))
292
284
 
293
 
    def _validate_revision(self, tree, revision_id):
 
285
    def _validate_revision(self, inventory, revision_id):
294
286
        """Make sure all revision entries match their checksum."""
295
287
 
296
 
        # This is a mapping from each revision id to its sha hash
 
288
        # This is a mapping from each revision id to it's sha hash
297
289
        rev_to_sha1 = {}
298
290
 
299
291
        rev = self.get_revision(revision_id)
302
294
            raise AssertionError()
303
295
        if not (rev.revision_id == revision_id):
304
296
            raise AssertionError()
305
 
        sha1 = self._testament_sha1(rev, tree)
 
297
        sha1 = self._testament_sha1(rev, inventory)
306
298
        if sha1 != rev_info.sha1:
307
299
            raise TestamentMismatch(rev.revision_id, rev_info.sha1, sha1)
308
300
        if rev.revision_id in rev_to_sha1:
335
327
                try:
336
328
                    name, value = info_item.split(':', 1)
337
329
                except ValueError:
338
 
                    raise ValueError('Value %r has no colon' % info_item)
 
330
                    raise 'Value %r has no colon' % info_item
339
331
                if name == 'last-changed':
340
332
                    last_changed = value
341
333
                elif name == 'executable':
466
458
 
467
459
 
468
460
class BundleTree(Tree):
469
 
 
470
461
    def __init__(self, base_tree, revision_id):
471
462
        self.base_tree = base_tree
472
463
        self._renamed = {} # Mapping from old_path => new_path
576
567
            return None
577
568
        return new_path
578
569
 
579
 
    def get_root_id(self):
580
 
        return self.path2id('')
581
 
 
582
570
    def path2id(self, path):
583
571
        """Return the id of the file present at path in the target tree."""
584
572
        file_id = self._new_id.get(path)
589
577
            return None
590
578
        if old_path in self.deleted:
591
579
            return None
592
 
        return self.base_tree.path2id(old_path)
 
580
        if getattr(self.base_tree, 'path2id', None) is not None:
 
581
            return self.base_tree.path2id(old_path)
 
582
        else:
 
583
            return self.base_tree.inventory.path2id(old_path)
593
584
 
594
585
    def id2path(self, file_id):
595
586
        """Return the new path in the target tree of the file with id file_id"""
625
616
        """
626
617
        base_id = self.old_contents_id(file_id)
627
618
        if (base_id is not None and
628
 
            base_id != self.base_tree.get_root_id()):
 
619
            base_id != self.base_tree.inventory.root.file_id):
629
620
            patch_original = self.base_tree.get_file(base_id)
630
621
        else:
631
622
            patch_original = None
632
623
        file_patch = self.patches.get(self.id2path(file_id))
633
624
        if file_patch is None:
634
625
            if (patch_original is None and
635
 
                self.kind(file_id) == 'directory'):
 
626
                self.get_kind(file_id) == 'directory'):
636
627
                return StringIO()
637
628
            if patch_original is None:
638
629
                raise AssertionError("None: %s" % file_id)
643
634
                'Malformed patch for %s, %r' % (file_id, file_patch))
644
635
        return patched_file(file_patch, patch_original)
645
636
 
646
 
    def get_symlink_target(self, file_id, path=None):
647
 
        if path is None:
648
 
            path = self.id2path(file_id)
 
637
    def get_symlink_target(self, file_id):
 
638
        new_path = self.id2path(file_id)
649
639
        try:
650
 
            return self._targets[path]
 
640
            return self._targets[new_path]
651
641
        except KeyError:
652
642
            return self.base_tree.get_symlink_target(file_id)
653
643
 
654
 
    def kind(self, file_id):
 
644
    def get_kind(self, file_id):
655
645
        if file_id in self._kinds:
656
646
            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)
 
647
        return self.base_tree.inventory[file_id].kind
665
648
 
666
649
    def is_executable(self, file_id):
667
650
        path = self.id2path(file_id)
668
651
        if path in self._executable:
669
652
            return self._executable[path]
670
653
        else:
671
 
            return self.base_tree.is_executable(file_id)
 
654
            return self.base_tree.inventory[file_id].executable
672
655
 
673
656
    def get_last_changed(self, file_id):
674
657
        path = self.id2path(file_id)
675
658
        if path in self._last_changed:
676
659
            return self._last_changed[path]
677
 
        return self.base_tree.get_file_revision(file_id)
 
660
        return self.base_tree.inventory[file_id].revision
678
661
 
679
662
    def get_size_and_sha1(self, file_id):
680
663
        """Return the size and sha1 hash of the given file id.
687
670
        if new_path not in self.patches:
688
671
            # If the entry does not have a patch, then the
689
672
            # 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
 
673
            ie = self.base_tree.inventory[file_id]
 
674
            if ie.text_size is None:
 
675
                return ie.text_size, ie.text_sha1
 
676
            return int(ie.text_size), ie.text_sha1
693
677
        fileobj = self.get_file(file_id)
694
678
        content = fileobj.read()
695
679
        return len(content), sha_string(content)
700
684
        This need to be called before ever accessing self.inventory
701
685
        """
702
686
        from os.path import dirname, basename
 
687
        base_inv = self.base_tree.inventory
703
688
        inv = Inventory(None, self.revision_id)
704
689
 
705
690
        def add_entry(file_id):
712
697
                parent_path = dirname(path)
713
698
                parent_id = self.path2id(parent_path)
714
699
 
715
 
            kind = self.kind(file_id)
 
700
            kind = self.get_kind(file_id)
716
701
            revision_id = self.get_last_changed(file_id)
717
702
 
718
703
            name = basename(path)
723
708
                ie.executable = self.is_executable(file_id)
724
709
            elif kind == 'symlink':
725
710
                ie = InventoryLink(file_id, name, parent_id)
726
 
                ie.symlink_target = self.get_symlink_target(file_id, path)
 
711
                ie.symlink_target = self.get_symlink_target(file_id)
727
712
            ie.revision = revision_id
728
713
 
729
 
            if kind == 'file':
 
714
            if kind in ('directory', 'symlink'):
 
715
                ie.text_size, ie.text_sha1 = None, None
 
716
            else:
730
717
                ie.text_size, ie.text_sha1 = self.get_size_and_sha1(file_id)
731
 
                if ie.text_size is None:
732
 
                    raise BzrError(
733
 
                        'Got a text_size of None for file_id %r' % file_id)
 
718
            if (ie.text_size is None) and (kind == 'file'):
 
719
                raise BzrError('Got a text_size of None for file_id %r' % file_id)
734
720
            inv.add(ie)
735
721
 
736
722
        sorted_entries = self.sorted_path_id()
746
732
    # at that instant
747
733
    inventory = property(_get_inventory)
748
734
 
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
 
735
    def __iter__(self):
 
736
        for path, entry in self.inventory.iter_entries():
 
737
            yield entry.file_id
771
738
 
772
739
    def sorted_path_id(self):
773
740
        paths = []
774
741
        for result in self._new_id.iteritems():
775
742
            paths.append(result)
776
 
        for id in self.base_tree.all_file_ids():
 
743
        for id in self.base_tree:
777
744
            path = self.id2path(id)
778
745
            if path is None:
779
746
                continue