~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/bundle/bundle_data.py

  • Committer: Alexander Belchenko
  • Date: 2006-07-31 16:12:57 UTC
  • mto: (1711.2.111 jam-integration)
  • mto: This revision was merged to the branch mainline in revision 1906.
  • Revision ID: bialix@ukr.net-20060731161257-91a231523255332c
new official bzr.ico

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006 Canonical Ltd
 
1
# Copyright (C) 2006 by 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
21
21
import os
22
22
import pprint
23
23
 
24
 
from bzrlib import (
25
 
    osutils,
26
 
    timestamp,
27
 
    )
28
24
import bzrlib.errors
29
 
from bzrlib.bundle import apply_bundle
30
25
from bzrlib.errors import (TestamentMismatch, BzrError, 
31
26
                           MalformedHeader, MalformedPatches, NotABundle)
32
27
from bzrlib.inventory import (Inventory, InventoryEntry,
77
72
        if self.properties:
78
73
            for property in self.properties:
79
74
                key_end = property.find(': ')
80
 
                if key_end == -1:
81
 
                    assert property.endswith(':')
82
 
                    key = str(property[:-1])
83
 
                    value = ''
84
 
                else:
85
 
                    key = str(property[:key_end])
86
 
                    value = property[key_end+2:]
 
75
                assert key_end is not None
 
76
                key = property[:key_end].encode('utf-8')
 
77
                value = property[key_end+2:].encode('utf-8')
87
78
                rev.properties[key] = value
88
79
 
89
80
        return rev
90
81
 
91
 
    @staticmethod
92
 
    def from_revision(revision):
93
 
        revision_info = RevisionInfo(revision.revision_id)
94
 
        date = timestamp.format_highres_date(revision.timestamp,
95
 
                                             revision.timezone)
96
 
        revision_info.date = date
97
 
        revision_info.timezone = revision.timezone
98
 
        revision_info.timestamp = revision.timestamp
99
 
        revision_info.message = revision.message.split('\n')
100
 
        revision_info.properties = [': '.join(p) for p in
101
 
                                    revision.properties.iteritems()]
102
 
        return revision_info
103
 
 
104
82
 
105
83
class BundleInfo(object):
106
84
    """This contains the meta information. Stuff that allows you to
107
85
    recreate the revision or inventory XML.
108
86
    """
109
 
    def __init__(self, bundle_format=None):
110
 
        self.bundle_format = None
 
87
    def __init__(self):
111
88
        self.committer = None
112
89
        self.date = None
113
90
        self.message = None
124
101
        self.timestamp = None
125
102
        self.timezone = None
126
103
 
127
 
        # Have we checked the repository yet?
128
 
        self._validated_revisions_against_repo = False
129
 
 
130
104
    def __str__(self):
131
105
        return pprint.pformat(self.__dict__)
132
106
 
135
109
        split up, based on the assumptions that can be made
136
110
        when information is missing.
137
111
        """
138
 
        from bzrlib.timestamp import unpack_highres_date
 
112
        from bzrlib.bundle.serializer import unpack_highres_date
139
113
        # Put in all of the guessable information.
140
114
        if not self.timestamp and self.date:
141
115
            self.timestamp, self.timezone = unpack_highres_date(self.date)
194
168
        raise KeyError(revision_id)
195
169
 
196
170
    def revision_tree(self, repository, revision_id, base=None):
197
 
        revision_id = osutils.safe_revision_id(revision_id)
198
171
        revision = self.get_revision(revision_id)
199
172
        base = self.get_base(revision)
200
173
        assert base != revision_id
201
 
        if not self._validated_revisions_against_repo:
202
 
            self._validate_references_from_repository(repository)
 
174
        self._validate_references_from_repository(repository)
203
175
        revision_info = self.get_revision_info(revision_id)
204
176
        inventory_revision_id = revision_id
205
177
        bundle_tree = BundleTree(repository.revision_tree(base), 
251
223
            if repository.has_revision(revision_id):
252
224
                testament = StrictTestament.from_revision(repository, 
253
225
                                                          revision_id)
254
 
                local_sha1 = self._testament_sha1_from_revision(repository,
255
 
                                                                revision_id)
 
226
                local_sha1 = testament.as_sha1()
256
227
                if sha1 != local_sha1:
257
228
                    raise BzrError('sha1 mismatch. For revision id {%s}' 
258
229
                            'local: %s, bundle: %s' % (revision_id, local_sha1, sha1))
281
252
            warning('Not all revision hashes could be validated.'
282
253
                    ' Unable validate %d hashes' % len(missing))
283
254
        mutter('Verified %d sha hashes for the bundle.' % count)
284
 
        self._validated_revisions_against_repo = True
285
255
 
286
256
    def _validate_inventory(self, inv, revision_id):
287
257
        """At this point we should have generated the BundleTree,
311
281
        rev_info = self.get_revision_info(revision_id)
312
282
        assert rev.revision_id == rev_info.revision_id
313
283
        assert rev.revision_id == revision_id
314
 
        sha1 = self._testament_sha1(rev, inventory)
 
284
        sha1 = StrictTestament(rev, inventory).as_sha1()
315
285
        if sha1 != rev_info.sha1:
316
286
            raise TestamentMismatch(rev.revision_id, rev_info.sha1, sha1)
317
 
        if rev.revision_id in rev_to_sha1:
 
287
        if rev_to_sha1.has_key(rev.revision_id):
318
288
            raise BzrError('Revision {%s} given twice in the list'
319
289
                    % (rev.revision_id))
320
290
        rev_to_sha1[rev.revision_id] = sha1
328
298
 
329
299
        def get_rev_id(last_changed, path, kind):
330
300
            if last_changed is not None:
331
 
                # last_changed will be a Unicode string because of how it was
332
 
                # read. Convert it back to utf8.
333
 
                changed_revision_id = osutils.safe_revision_id(last_changed,
334
 
                                                               warn=False)
 
301
                changed_revision_id = last_changed.decode('utf-8')
335
302
            else:
336
303
                changed_revision_id = revision_id
337
304
            bundle_tree.note_last_changed(path, changed_revision_id)
404
371
            if not info[1].startswith('file-id:'):
405
372
                raise BzrError('The file-id should follow the path for an add'
406
373
                        ': %r' % extra)
407
 
            # This will be Unicode because of how the stream is read. Turn it
408
 
            # back into a utf8 file_id
409
 
            file_id = osutils.safe_file_id(info[1][8:], warn=False)
 
374
            file_id = info[1][8:]
410
375
 
411
376
            bundle_tree.note_id(file_id, path, kind)
412
377
            # this will be overridden in extra_info if executable is specified.
457
422
                        ' (unrecognized action): %r' % action_line)
458
423
            valid_actions[action](kind, extra, lines)
459
424
 
460
 
    def install_revisions(self, target_repo):
461
 
        """Install revisions and return the target revision"""
462
 
        apply_bundle.install_bundle(target_repo, self)
463
 
        return self.target
464
 
 
465
 
    def get_merge_request(self, target_repo):
466
 
        """Provide data for performing a merge
467
 
 
468
 
        Returns suggested base, suggested target, and patch verification status
469
 
        """
470
 
        return None, self.target, 'inapplicable'
471
 
 
472
425
 
473
426
class BundleTree(Tree):
474
427
    def __init__(self, base_tree, revision_id):
492
445
 
493
446
    def note_rename(self, old_path, new_path):
494
447
        """A file/directory has been renamed from old_path => new_path"""
495
 
        assert new_path not in self._renamed
496
 
        assert old_path not in self._renamed_r
 
448
        assert not self._renamed.has_key(new_path)
 
449
        assert not self._renamed_r.has_key(old_path)
497
450
        self._renamed[new_path] = old_path
498
451
        self._renamed_r[old_path] = new_path
499
452
 
504
457
        self._kinds[new_id] = kind
505
458
 
506
459
    def note_last_changed(self, file_id, revision_id):
507
 
        if (file_id in self._last_changed
 
460
        if (self._last_changed.has_key(file_id)
508
461
                and self._last_changed[file_id] != revision_id):
509
462
            raise BzrError('Mismatched last-changed revision for file_id {%s}'
510
463
                    ': %s != %s' % (file_id,
547
500
            old_path = new_path
548
501
        #If the new path wasn't in renamed, the old one shouldn't be in
549
502
        #renamed_r
550
 
        if old_path in self._renamed_r:
 
503
        if self._renamed_r.has_key(old_path):
551
504
            return None
552
505
        return old_path 
553
506
 
559
512
        new_path = self._renamed_r.get(old_path)
560
513
        if new_path is not None:
561
514
            return new_path
562
 
        if new_path in self._renamed:
 
515
        if self._renamed.has_key(new_path):
563
516
            return None
564
517
        dirname,basename = os.path.split(old_path)
565
518
        if dirname != '':
572
525
            new_path = old_path
573
526
        #If the old path wasn't in renamed, the new one shouldn't be in
574
527
        #renamed_r
575
 
        if new_path in self._renamed:
 
528
        if self._renamed.has_key(new_path):
576
529
            return None
577
530
        return new_path 
578
531
 
586
539
            return None
587
540
        if old_path in self.deleted:
588
541
            return None
589
 
        if getattr(self.base_tree, 'path2id', None) is not None:
 
542
        if hasattr(self.base_tree, 'path2id'):
590
543
            return self.base_tree.path2id(old_path)
591
544
        else:
592
545
            return self.base_tree.inventory.path2id(old_path)
624
577
                then be cached.
625
578
        """
626
579
        base_id = self.old_contents_id(file_id)
627
 
        if (base_id is not None and
628
 
            base_id != self.base_tree.inventory.root.file_id):
 
580
        if base_id is not None:
629
581
            patch_original = self.base_tree.get_file(base_id)
630
582
        else:
631
583
            patch_original = None
694
646
 
695
647
        assert self.base_tree is not None
696
648
        base_inv = self.base_tree.inventory
697
 
        inv = Inventory(None, self.revision_id)
 
649
        root_id = base_inv.root.file_id
 
650
        try:
 
651
            # New inventories have a unique root_id
 
652
            inv = Inventory(root_id, self.revision_id)
 
653
        except TypeError:
 
654
            inv = Inventory(revision_id=self.revision_id)
698
655
 
699
656
        def add_entry(file_id):
700
657
            path = self.id2path(file_id)
701
658
            if path is None:
702
659
                return
703
 
            if path == '':
704
 
                parent_id = None
 
660
            parent_path = dirname(path)
 
661
            if parent_path == u'':
 
662
                parent_id = root_id
705
663
            else:
706
 
                parent_path = dirname(path)
707
664
                parent_id = self.path2id(parent_path)
708
665
 
709
666
            kind = self.get_kind(file_id)
730
687
 
731
688
        sorted_entries = self.sorted_path_id()
732
689
        for path, file_id in sorted_entries:
 
690
            if file_id == inv.root.file_id:
 
691
                continue
733
692
            add_entry(file_id)
734
693
 
735
694
        return inv