/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: 2019-05-29 03:22:34 UTC
  • mfrom: (7303 work)
  • mto: This revision was merged to the branch mainline in revision 7306.
  • Revision ID: jelmer@jelmer.uk-20190529032234-mt3fuws8gq03tapi
Merge trunk.

Show diffs side-by-side

added added

removed removed

Lines of Context:
44
44
from ..sixish import (
45
45
    viewitems,
46
46
    )
47
 
from ..testament import StrictTestament
 
47
from ..bzr.testament import StrictTestament
48
48
from ..trace import mutter, warning
49
49
from ..tree import Tree
50
50
from ..bzr.xml5 import serializer_v5
74
74
 
75
75
    def as_revision(self):
76
76
        rev = Revision(revision_id=self.revision_id,
77
 
            committer=self.committer,
78
 
            timestamp=float(self.timestamp),
79
 
            timezone=int(self.timezone),
80
 
            inventory_sha1=self.inventory_sha1,
81
 
            message='\n'.join(self.message))
 
77
                       committer=self.committer,
 
78
                       timestamp=float(self.timestamp),
 
79
                       timezone=int(self.timezone),
 
80
                       inventory_sha1=self.inventory_sha1,
 
81
                       message='\n'.join(self.message))
82
82
 
83
83
        if self.parent_ids:
84
84
            rev.parent_ids.extend(self.parent_ids)
93
93
                    value = ''
94
94
                else:
95
95
                    key = str(property[:key_end])
96
 
                    value = property[key_end+2:]
 
96
                    value = property[key_end + 2:]
97
97
                rev.properties[key] = value
98
98
 
99
99
        return rev
116
116
    """This contains the meta information. Stuff that allows you to
117
117
    recreate the revision or inventory XML.
118
118
    """
 
119
 
119
120
    def __init__(self, bundle_format=None):
120
121
        self.bundle_format = None
121
122
        self.committer = None
155
156
            if rev.timestamp is None:
156
157
                if rev.date is not None:
157
158
                    rev.timestamp, rev.timezone = \
158
 
                            unpack_highres_date(rev.date)
 
159
                        unpack_highres_date(rev.date)
159
160
                else:
160
161
                    rev.timestamp = self.timestamp
161
162
                    rev.timezone = self.timezone
210
211
        revision_info = self.get_revision_info(revision_id)
211
212
        inventory_revision_id = revision_id
212
213
        bundle_tree = BundleTree(repository.revision_tree(base),
213
 
                                  inventory_revision_id)
 
214
                                 inventory_revision_id)
214
215
        self._update_tree(bundle_tree, revision_id)
215
216
 
216
217
        inv = bundle_tree.inventory
226
227
        """
227
228
        rev_to_sha = {}
228
229
        inv_to_sha = {}
 
230
 
229
231
        def add_sha(d, revision_id, sha1):
230
232
            if revision_id is None:
231
233
                if sha1 is not None:
232
234
                    raise BzrError('A Null revision should always'
233
 
                        'have a null sha1 hash')
 
235
                                   'have a null sha1 hash')
234
236
                return
235
237
            if revision_id in d:
236
238
                # This really should have been validated as part
237
239
                # of _validate_revisions but lets do it again
238
240
                if sha1 != d[revision_id]:
239
241
                    raise BzrError('** Revision %r referenced with 2 different'
240
 
                            ' sha hashes %s != %s' % (revision_id,
241
 
                                sha1, d[revision_id]))
 
242
                                   ' sha hashes %s != %s' % (revision_id,
 
243
                                                             sha1, d[revision_id]))
242
244
            else:
243
245
                d[revision_id] = sha1
244
246
 
262
264
                                                                revision_id)
263
265
                if sha1 != local_sha1:
264
266
                    raise BzrError('sha1 mismatch. For revision id {%s}'
265
 
                            'local: %s, bundle: %s' % (revision_id, local_sha1, sha1))
 
267
                                   'local: %s, bundle: %s' % (revision_id, local_sha1, sha1))
266
268
                else:
267
269
                    count += 1
268
270
            elif revision_id not in checked:
309
311
            raise TestamentMismatch(rev.revision_id, rev_info.sha1, sha1)
310
312
        if rev.revision_id in rev_to_sha1:
311
313
            raise BzrError('Revision {%s} given twice in the list'
312
 
                    % (rev.revision_id))
 
314
                           % (rev.revision_id))
313
315
        rev_to_sha1[rev.revision_id] = sha1
314
316
 
315
317
    def _update_tree(self, bundle_tree, revision_id):
352
354
            if encoding == 'base64':
353
355
                patch = base64.b64decode(b''.join(lines))
354
356
            elif encoding is None:
355
 
                patch =  b''.join(lines)
 
357
                patch = b''.join(lines)
356
358
            else:
357
359
                raise ValueError(encoding)
358
360
            bundle_tree.note_patch(path, patch)
361
363
            info = extra.split(' // ')
362
364
            if len(info) < 2:
363
365
                raise BzrError('renamed action lines need both a from and to'
364
 
                        ': %r' % extra)
 
366
                               ': %r' % extra)
365
367
            old_path = info[0]
366
368
            if info[1].startswith('=> '):
367
369
                new_path = info[1][3:]
380
382
                # TODO: in the future we might allow file ids to be
381
383
                # given for removed entries
382
384
                raise BzrError('removed action lines should only have the path'
383
 
                        ': %r' % extra)
 
385
                               ': %r' % extra)
384
386
            path = info[0]
385
387
            bundle_tree.note_deletion(path)
386
388
 
388
390
            info = extra.split(' // ')
389
391
            if len(info) <= 1:
390
392
                raise BzrError('add action lines require the path and file id'
391
 
                        ': %r' % extra)
 
393
                               ': %r' % extra)
392
394
            elif len(info) > 5:
393
395
                raise BzrError('add action lines have fewer than 5 entries.'
394
 
                        ': %r' % extra)
 
396
                               ': %r' % extra)
395
397
            path = info[0]
396
398
            if not info[1].startswith('file-id:'):
397
399
                raise BzrError('The file-id should follow the path for an add'
398
 
                        ': %r' % extra)
 
400
                               ': %r' % extra)
399
401
            # This will be Unicode because of how the stream is read. Turn it
400
402
            # back into a utf8 file_id
401
403
            file_id = cache_utf8.encode(info[1][8:])
413
415
            info = extra.split(' // ')
414
416
            if len(info) < 1:
415
417
                raise BzrError('modified action lines have at least'
416
 
                        'the path in them: %r' % extra)
 
418
                               'the path in them: %r' % extra)
417
419
            path = info[0]
418
420
 
419
421
            last_modified, encoding = extra_info(info[1:], path)
422
424
                do_patch(path, lines, encoding)
423
425
 
424
426
        valid_actions = {
425
 
            'renamed':renamed,
426
 
            'removed':removed,
427
 
            'added':added,
428
 
            'modified':modified
 
427
            'renamed': renamed,
 
428
            'removed': removed,
 
429
            'added': added,
 
430
            'modified': modified
429
431
        }
430
432
        for action_line, lines in \
431
 
            self.get_revision_info(revision_id).tree_actions:
 
433
                self.get_revision_info(revision_id).tree_actions:
432
434
            first = action_line.find(' ')
433
435
            if first == -1:
434
436
                raise BzrError('Bogus action line'
435
 
                        ' (no opening space): %r' % action_line)
436
 
            second = action_line.find(' ', first+1)
 
437
                               ' (no opening space): %r' % action_line)
 
438
            second = action_line.find(' ', first + 1)
437
439
            if second == -1:
438
440
                raise BzrError('Bogus action line'
439
 
                        ' (missing second space): %r' % action_line)
 
441
                               ' (missing second space): %r' % action_line)
440
442
            action = action_line[:first]
441
 
            kind = action_line[first+1:second]
 
443
            kind = action_line[first + 1:second]
442
444
            if kind not in ('file', 'directory', 'symlink'):
443
445
                raise BzrError('Bogus action line'
444
 
                        ' (invalid object kind %r): %r' % (kind, action_line))
445
 
            extra = action_line[second+1:]
 
446
                               ' (invalid object kind %r): %r' % (kind, action_line))
 
447
            extra = action_line[second + 1:]
446
448
 
447
449
            if action not in valid_actions:
448
450
                raise BzrError('Bogus action line'
449
 
                        ' (unrecognized action): %r' % action_line)
 
451
                               ' (unrecognized action): %r' % action_line)
450
452
            valid_actions[action](kind, extra, lines)
451
453
 
452
454
    def install_revisions(self, target_repo, stream_input=True):
470
472
 
471
473
    def __init__(self, base_tree, revision_id):
472
474
        self.base_tree = base_tree
473
 
        self._renamed = {} # Mapping from old_path => new_path
474
 
        self._renamed_r = {} # new_path => old_path
475
 
        self._new_id = {} # new_path => new_id
476
 
        self._new_id_r = {} # new_id => new_path
477
 
        self._kinds = {} # new_path => kind
478
 
        self._last_changed = {} # new_id => revision_id
479
 
        self._executable = {} # new_id => executable value
 
475
        self._renamed = {}  # Mapping from old_path => new_path
 
476
        self._renamed_r = {}  # new_path => old_path
 
477
        self._new_id = {}  # new_path => new_id
 
478
        self._new_id_r = {}  # new_id => new_path
 
479
        self._kinds = {}  # new_path => kind
 
480
        self._last_changed = {}  # new_id => revision_id
 
481
        self._executable = {}  # new_id => executable value
480
482
        self.patches = {}
481
 
        self._targets = {} # new path => new symlink target
 
483
        self._targets = {}  # new path => new symlink target
482
484
        self.deleted = []
483
485
        self.contents_by_id = True
484
486
        self.revision_id = revision_id
506
508
        if (file_id in self._last_changed
507
509
                and self._last_changed[file_id] != revision_id):
508
510
            raise BzrError('Mismatched last-changed revision for file_id {%s}'
509
 
                    ': %s != %s' % (file_id,
510
 
                                    self._last_changed[file_id],
511
 
                                    revision_id))
 
511
                           ': %s != %s' % (file_id,
 
512
                                           self._last_changed[file_id],
 
513
                                           revision_id))
512
514
        self._last_changed[file_id] = revision_id
513
515
 
514
516
    def note_patch(self, new_path, patch):
545
547
                old_path = pathjoin(old_dir, basename)
546
548
        else:
547
549
            old_path = new_path
548
 
        #If the new path wasn't in renamed, the old one shouldn't be in
549
 
        #renamed_r
 
550
        # If the new path wasn't in renamed, the old one shouldn't be in
 
551
        # renamed_r
550
552
        if old_path in self._renamed_r:
551
553
            return None
552
554
        return old_path
571
573
                new_path = pathjoin(new_dir, basename)
572
574
        else:
573
575
            new_path = old_path
574
 
        #If the old path wasn't in renamed, the new one shouldn't be in
575
 
        #renamed_r
 
576
        # If the old path wasn't in renamed, the new one shouldn't be in
 
577
        # renamed_r
576
578
        if new_path in self._renamed:
577
579
            return None
578
580
        return new_path
616
618
        new_path = self.id2path(file_id)
617
619
        return self.base_tree.path2id(new_path)
618
620
 
619
 
    def get_file(self, path, file_id=None):
 
621
    def get_file(self, path):
620
622
        """Return a file-like object containing the new contents of the
621
623
        file given by file_id.
622
624
 
624
626
                in the text-store, so that the file contents would
625
627
                then be cached.
626
628
        """
627
 
        if file_id is None:
628
 
            file_id = self.path2id(path)
 
629
        file_id = self.path2id(path)
629
630
        base_id = self.old_contents_id(file_id)
630
631
        if (base_id is not None and
631
 
            base_id != self.base_tree.get_root_id()):
632
 
            old_path = self.old_path(path)
633
 
            patch_original = self.base_tree.get_file(
634
 
                    old_path, base_id)
 
632
                base_id != self.base_tree.get_root_id()):
 
633
            old_path = self.base_tree.id2path(base_id)
 
634
            patch_original = self.base_tree.get_file(old_path)
635
635
        else:
636
636
            patch_original = None
637
637
        file_patch = self.patches.get(path)
638
638
        if file_patch is None:
639
639
            if (patch_original is None and
640
 
                self.kind(path, file_id) == 'directory'):
 
640
                    self.kind(path) == 'directory'):
641
641
                return BytesIO()
642
642
            if patch_original is None:
643
643
                raise AssertionError("None: %s" % file_id)
648
648
                'Malformed patch for %s, %r' % (file_id, file_patch))
649
649
        return patched_file(file_patch, patch_original)
650
650
 
651
 
    def get_symlink_target(self, path, file_id=None):
 
651
    def get_symlink_target(self, path):
652
652
        try:
653
653
            return self._targets[path]
654
654
        except KeyError:
655
655
            old_path = self.old_path(path)
656
 
            return self.base_tree.get_symlink_target(old_path, file_id)
 
656
            return self.base_tree.get_symlink_target(old_path)
657
657
 
658
 
    def kind(self, path, file_id=None):
 
658
    def kind(self, path):
659
659
        try:
660
660
            return self._kinds[path]
661
661
        except KeyError:
662
662
            old_path = self.old_path(path)
663
 
            return self.base_tree.kind(old_path, file_id)
 
663
            return self.base_tree.kind(old_path)
664
664
 
665
 
    def get_file_revision(self, path, file_id=None):
 
665
    def get_file_revision(self, path):
666
666
        if path in self._last_changed:
667
667
            return self._last_changed[path]
668
668
        else:
669
669
            old_path = self.old_path(path)
670
 
            return self.base_tree.get_file_revision(old_path, file_id)
 
670
            return self.base_tree.get_file_revision(old_path)
671
671
 
672
 
    def is_executable(self, path, file_id=None):
 
672
    def is_executable(self, path):
673
673
        if path in self._executable:
674
674
            return self._executable[path]
675
675
        else:
676
676
            old_path = self.old_path(path)
677
 
            return self.base_tree.is_executable(old_path, file_id)
 
677
            return self.base_tree.is_executable(old_path)
678
678
 
679
 
    def get_last_changed(self, path, file_id=None):
 
679
    def get_last_changed(self, path):
680
680
        if path in self._last_changed:
681
681
            return self._last_changed[path]
682
682
        old_path = self.old_path(path)
683
 
        return self.base_tree.get_file_revision(old_path, file_id)
 
683
        return self.base_tree.get_file_revision(old_path)
684
684
 
685
 
    def get_size_and_sha1(self, new_path, file_id=None):
 
685
    def get_size_and_sha1(self, new_path):
686
686
        """Return the size and sha1 hash of the given file id.
687
687
        If the file was not locally modified, this is extracted
688
688
        from the base_tree. Rather than re-reading the file.
693
693
            # If the entry does not have a patch, then the
694
694
            # contents must be the same as in the base_tree
695
695
            base_path = self.old_path(new_path)
696
 
            text_size = self.base_tree.get_file_size(base_path, file_id)
697
 
            text_sha1 = self.base_tree.get_file_sha1(base_path, file_id)
 
696
            text_size = self.base_tree.get_file_size(base_path)
 
697
            text_sha1 = self.base_tree.get_file_sha1(base_path)
698
698
            return text_size, text_sha1
699
 
        fileobj = self.get_file(new_path, file_id)
 
699
        fileobj = self.get_file(new_path)
700
700
        content = fileobj.read()
701
701
        return len(content), sha_string(content)
702
702
 
715
715
                parent_path = dirname(path)
716
716
                parent_id = self.path2id(parent_path)
717
717
 
718
 
            kind = self.kind(path, file_id)
719
 
            revision_id = self.get_last_changed(path, file_id)
 
718
            kind = self.kind(path)
 
719
            revision_id = self.get_last_changed(path)
720
720
 
721
721
            name = basename(path)
722
722
            if kind == 'directory':
723
723
                ie = InventoryDirectory(file_id, name, parent_id)
724
724
            elif kind == 'file':
725
725
                ie = InventoryFile(file_id, name, parent_id)
726
 
                ie.executable = self.is_executable(path, file_id)
 
726
                ie.executable = self.is_executable(path)
727
727
            elif kind == 'symlink':
728
728
                ie = InventoryLink(file_id, name, parent_id)
729
 
                ie.symlink_target = self.get_symlink_target(path, file_id)
 
729
                ie.symlink_target = self.get_symlink_target(path)
730
730
            ie.revision = revision_id
731
731
 
732
732
            if kind == 'file':
733
 
                ie.text_size, ie.text_sha1 = self.get_size_and_sha1(
734
 
                        path, file_id)
 
733
                ie.text_size, ie.text_sha1 = self.get_size_and_sha1(path)
735
734
                if ie.text_size is None:
736
735
                    raise BzrError(
737
736
                        'Got a text_size of None for file_id %r' % file_id)
770
769
                return
771
770
        entries = inv.iter_entries(from_dir=from_dir_id, recursive=recursive)
772
771
        if inv.root is not None and not include_root and from_dir is None:
773
 
            # skip the root for compatability with the current apis.
 
772
            # skip the root for compatibility with the current apis.
774
773
            next(entries)
775
774
        for path, entry in entries:
776
 
            yield path, 'V', entry.kind, entry.file_id, entry
 
775
            yield path, 'V', entry.kind, entry
777
776
 
778
777
    def sorted_path_id(self):
779
778
        paths = []
797
796
    # string.splitlines(True) also splits on '\r', but the iter_patched code
798
797
    # only expects to iterate over '\n' style lines
799
798
    return IterableFile(iter_patched(original,
800
 
                BytesIO(file_patch).readlines()))
 
799
                                     BytesIO(file_patch).readlines()))