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

  • Committer: Jelmer Vernooij
  • Date: 2017-05-22 00:56:52 UTC
  • mfrom: (6621.2.26 py3_pokes)
  • Revision ID: jelmer@jelmer.uk-20170522005652-yjahcr9hwmjkno7n
Merge Python3 porting work ('py3 pokes')

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