/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 brzlib/bundle/bundle_data.py

  • Committer: Jelmer Vernooij
  • Date: 2017-05-21 12:41:27 UTC
  • mto: This revision was merged to the branch mainline in revision 6623.
  • Revision ID: jelmer@jelmer.uk-20170521124127-iv8etg0vwymyai6y
s/bzr/brz/ in apport config.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006 Canonical Ltd
 
1
# Copyright (C) 2005-2010 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
 
19
21
import base64
20
22
from cStringIO import StringIO
21
23
import os
22
24
import pprint
23
25
 
24
 
from bzrlib import (
 
26
from brzlib import (
25
27
    osutils,
26
28
    timestamp,
27
29
    )
28
 
import bzrlib.errors
29
 
from bzrlib.bundle import apply_bundle
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
36
 
from bzrlib.revision import Revision, NULL_REVISION
37
 
from bzrlib.testament import StrictTestament
38
 
from bzrlib.trace import mutter, warning
39
 
import bzrlib.transport
40
 
from bzrlib.tree import Tree
41
 
import bzrlib.urlutils
42
 
from bzrlib.xml5 import serializer_v5
 
30
from brzlib.bundle import apply_bundle
 
31
from brzlib.errors import (
 
32
    TestamentMismatch,
 
33
    BzrError,
 
34
    )
 
35
from brzlib.inventory import (
 
36
    Inventory,
 
37
    InventoryDirectory,
 
38
    InventoryFile,
 
39
    InventoryLink,
 
40
    )
 
41
from brzlib.osutils import sha_string, pathjoin
 
42
from brzlib.revision import Revision, NULL_REVISION
 
43
from brzlib.testament import StrictTestament
 
44
from brzlib.trace import mutter, warning
 
45
from brzlib.tree import Tree
 
46
from brzlib.xml5 import serializer_v5
43
47
 
44
48
 
45
49
class RevisionInfo(object):
136
140
        split up, based on the assumptions that can be made
137
141
        when information is missing.
138
142
        """
139
 
        from bzrlib.timestamp import unpack_highres_date
 
143
        from brzlib.timestamp import unpack_highres_date
140
144
        # Put in all of the guessable information.
141
145
        if not self.timestamp and self.date:
142
146
            self.timestamp, self.timezone = unpack_highres_date(self.date)
206
210
 
207
211
        inv = bundle_tree.inventory
208
212
        self._validate_inventory(inv, revision_id)
209
 
        self._validate_revision(inv, revision_id)
 
213
        self._validate_revision(bundle_tree, revision_id)
210
214
 
211
215
        return bundle_tree
212
216
 
278
282
        if rev.revision_id != revision_id:
279
283
            raise AssertionError()
280
284
        if sha1 != rev.inventory_sha1:
281
 
            open(',,bogus-inv', 'wb').write(s)
 
285
            f = open(',,bogus-inv', 'wb')
 
286
            try:
 
287
                f.write(s)
 
288
            finally:
 
289
                f.close()
282
290
            warning('Inventory sha hash mismatch for revision %s. %s'
283
291
                    ' != %s' % (revision_id, sha1, rev.inventory_sha1))
284
292
 
285
 
    def _validate_revision(self, inventory, revision_id):
 
293
    def _validate_revision(self, tree, revision_id):
286
294
        """Make sure all revision entries match their checksum."""
287
295
 
288
 
        # This is a mapping from each revision id to it's sha hash
 
296
        # This is a mapping from each revision id to its sha hash
289
297
        rev_to_sha1 = {}
290
298
 
291
299
        rev = self.get_revision(revision_id)
294
302
            raise AssertionError()
295
303
        if not (rev.revision_id == revision_id):
296
304
            raise AssertionError()
297
 
        sha1 = self._testament_sha1(rev, inventory)
 
305
        sha1 = self._testament_sha1(rev, tree)
298
306
        if sha1 != rev_info.sha1:
299
307
            raise TestamentMismatch(rev.revision_id, rev_info.sha1, sha1)
300
308
        if rev.revision_id in rev_to_sha1:
327
335
                try:
328
336
                    name, value = info_item.split(':', 1)
329
337
                except ValueError:
330
 
                    raise 'Value %r has no colon' % info_item
 
338
                    raise ValueError('Value %r has no colon' % info_item)
331
339
                if name == 'last-changed':
332
340
                    last_changed = value
333
341
                elif name == 'executable':
458
466
 
459
467
 
460
468
class BundleTree(Tree):
 
469
 
461
470
    def __init__(self, base_tree, revision_id):
462
471
        self.base_tree = base_tree
463
472
        self._renamed = {} # Mapping from old_path => new_path
567
576
            return None
568
577
        return new_path
569
578
 
 
579
    def get_root_id(self):
 
580
        return self.path2id('')
 
581
 
570
582
    def path2id(self, path):
571
583
        """Return the id of the file present at path in the target tree."""
572
584
        file_id = self._new_id.get(path)
577
589
            return None
578
590
        if old_path in self.deleted:
579
591
            return None
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)
 
592
        return self.base_tree.path2id(old_path)
584
593
 
585
594
    def id2path(self, file_id):
586
595
        """Return the new path in the target tree of the file with id file_id"""
616
625
        """
617
626
        base_id = self.old_contents_id(file_id)
618
627
        if (base_id is not None and
619
 
            base_id != self.base_tree.inventory.root.file_id):
 
628
            base_id != self.base_tree.get_root_id()):
620
629
            patch_original = self.base_tree.get_file(base_id)
621
630
        else:
622
631
            patch_original = None
623
632
        file_patch = self.patches.get(self.id2path(file_id))
624
633
        if file_patch is None:
625
634
            if (patch_original is None and
626
 
                self.get_kind(file_id) == 'directory'):
 
635
                self.kind(file_id) == 'directory'):
627
636
                return StringIO()
628
637
            if patch_original is None:
629
638
                raise AssertionError("None: %s" % file_id)
634
643
                'Malformed patch for %s, %r' % (file_id, file_patch))
635
644
        return patched_file(file_patch, patch_original)
636
645
 
637
 
    def get_symlink_target(self, file_id):
638
 
        new_path = self.id2path(file_id)
 
646
    def get_symlink_target(self, file_id, path=None):
 
647
        if path is None:
 
648
            path = self.id2path(file_id)
639
649
        try:
640
 
            return self._targets[new_path]
 
650
            return self._targets[path]
641
651
        except KeyError:
642
652
            return self.base_tree.get_symlink_target(file_id)
643
653
 
644
 
    def get_kind(self, file_id):
 
654
    def kind(self, file_id):
645
655
        if file_id in self._kinds:
646
656
            return self._kinds[file_id]
647
 
        return self.base_tree.inventory[file_id].kind
 
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)
648
665
 
649
666
    def is_executable(self, file_id):
650
667
        path = self.id2path(file_id)
651
668
        if path in self._executable:
652
669
            return self._executable[path]
653
670
        else:
654
 
            return self.base_tree.inventory[file_id].executable
 
671
            return self.base_tree.is_executable(file_id)
655
672
 
656
673
    def get_last_changed(self, file_id):
657
674
        path = self.id2path(file_id)
658
675
        if path in self._last_changed:
659
676
            return self._last_changed[path]
660
 
        return self.base_tree.inventory[file_id].revision
 
677
        return self.base_tree.get_file_revision(file_id)
661
678
 
662
679
    def get_size_and_sha1(self, file_id):
663
680
        """Return the size and sha1 hash of the given file id.
670
687
        if new_path not in self.patches:
671
688
            # If the entry does not have a patch, then the
672
689
            # contents must be the same as in the base_tree
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
 
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
693
        fileobj = self.get_file(file_id)
678
694
        content = fileobj.read()
679
695
        return len(content), sha_string(content)
684
700
        This need to be called before ever accessing self.inventory
685
701
        """
686
702
        from os.path import dirname, basename
687
 
        base_inv = self.base_tree.inventory
688
703
        inv = Inventory(None, self.revision_id)
689
704
 
690
705
        def add_entry(file_id):
697
712
                parent_path = dirname(path)
698
713
                parent_id = self.path2id(parent_path)
699
714
 
700
 
            kind = self.get_kind(file_id)
 
715
            kind = self.kind(file_id)
701
716
            revision_id = self.get_last_changed(file_id)
702
717
 
703
718
            name = basename(path)
708
723
                ie.executable = self.is_executable(file_id)
709
724
            elif kind == 'symlink':
710
725
                ie = InventoryLink(file_id, name, parent_id)
711
 
                ie.symlink_target = self.get_symlink_target(file_id)
 
726
                ie.symlink_target = self.get_symlink_target(file_id, path)
712
727
            ie.revision = revision_id
713
728
 
714
 
            if kind in ('directory', 'symlink'):
715
 
                ie.text_size, ie.text_sha1 = None, None
716
 
            else:
 
729
            if kind == 'file':
717
730
                ie.text_size, ie.text_sha1 = self.get_size_and_sha1(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)
 
731
                if ie.text_size is None:
 
732
                    raise BzrError(
 
733
                        'Got a text_size of None for file_id %r' % file_id)
720
734
            inv.add(ie)
721
735
 
722
736
        sorted_entries = self.sorted_path_id()
732
746
    # at that instant
733
747
    inventory = property(_get_inventory)
734
748
 
735
 
    def __iter__(self):
736
 
        for path, entry in self.inventory.iter_entries():
737
 
            yield entry.file_id
 
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
771
 
739
772
    def sorted_path_id(self):
740
773
        paths = []
741
774
        for result in self._new_id.iteritems():
742
775
            paths.append(result)
743
 
        for id in self.base_tree:
 
776
        for id in self.base_tree.all_file_ids():
744
777
            path = self.id2path(id)
745
778
            if path is None:
746
779
                continue
751
784
 
752
785
def patched_file(file_patch, original):
753
786
    """Produce a file-like object with the patched version of a text"""
754
 
    from bzrlib.patches import iter_patched
755
 
    from bzrlib.iterablefile import IterableFile
 
787
    from brzlib.patches import iter_patched
 
788
    from brzlib.iterablefile import IterableFile
756
789
    if file_patch == "":
757
790
        return IterableFile(())
758
791
    # string.splitlines(True) also splits on '\r', but the iter_patched code