~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/bundle/bundle_data.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2010-11-06 16:01:48 UTC
  • mfrom: (5527.1.1 trunk)
  • Revision ID: pqm@pqm.ubuntu.com-20101106160148-8maemz21jbrhpzky
(vila) Move NEWS entry into the correct section (Vincent Ladeuil)

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
12
12
#
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
 
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
17
"""Read in a bundle stream, and process it into a BundleReader object."""
18
18
 
27
27
    )
28
28
import bzrlib.errors
29
29
from bzrlib.bundle import apply_bundle
30
 
from bzrlib.errors import (TestamentMismatch, BzrError, 
 
30
from bzrlib.errors import (TestamentMismatch, BzrError,
31
31
                           MalformedHeader, MalformedPatches, NotABundle)
32
32
from bzrlib.inventory import (Inventory, InventoryEntry,
33
33
                              InventoryDirectory, InventoryFile,
78
78
            for property in self.properties:
79
79
                key_end = property.find(': ')
80
80
                if key_end == -1:
81
 
                    assert property.endswith(':')
 
81
                    if not property.endswith(':'):
 
82
                        raise ValueError(property)
82
83
                    key = str(property[:-1])
83
84
                    value = ''
84
85
                else:
158
159
    def get_base(self, revision):
159
160
        revision_info = self.get_revision_info(revision.revision_id)
160
161
        if revision_info.base_id is not None:
161
 
            if revision_info.base_id == NULL_REVISION:
162
 
                return None
163
 
            else:
164
 
                return revision_info.base_id
 
162
            return revision_info.base_id
165
163
        if len(revision.parent_ids) == 0:
166
164
            # There is no base listed, and
167
165
            # the lowest revision doesn't have a parent
168
166
            # so this is probably against the empty tree
169
 
            # and thus base truly is None
170
 
            return None
 
167
            # and thus base truly is NULL_REVISION
 
168
            return NULL_REVISION
171
169
        else:
172
170
            return revision.parent_ids[-1]
173
171
 
196
194
    def revision_tree(self, repository, revision_id, base=None):
197
195
        revision = self.get_revision(revision_id)
198
196
        base = self.get_base(revision)
199
 
        assert base != revision_id
 
197
        if base == revision_id:
 
198
            raise AssertionError()
200
199
        if not self._validated_revisions_against_repo:
201
200
            self._validate_references_from_repository(repository)
202
201
        revision_info = self.get_revision_info(revision_id)
203
202
        inventory_revision_id = revision_id
204
 
        bundle_tree = BundleTree(repository.revision_tree(base), 
 
203
        bundle_tree = BundleTree(repository.revision_tree(base),
205
204
                                  inventory_revision_id)
206
205
        self._update_tree(bundle_tree, revision_id)
207
206
 
240
239
        for rev_info in self.revisions:
241
240
            checked[rev_info.revision_id] = True
242
241
            add_sha(rev_to_sha, rev_info.revision_id, rev_info.sha1)
243
 
                
 
242
 
244
243
        for (rev, rev_info) in zip(self.real_revisions, self.revisions):
245
244
            add_sha(inv_to_sha, rev_info.revision_id, rev_info.inventory_sha1)
246
245
 
248
247
        missing = {}
249
248
        for revision_id, sha1 in rev_to_sha.iteritems():
250
249
            if repository.has_revision(revision_id):
251
 
                testament = StrictTestament.from_revision(repository, 
 
250
                testament = StrictTestament.from_revision(repository,
252
251
                                                          revision_id)
253
252
                local_sha1 = self._testament_sha1_from_revision(repository,
254
253
                                                                revision_id)
255
254
                if sha1 != local_sha1:
256
 
                    raise BzrError('sha1 mismatch. For revision id {%s}' 
 
255
                    raise BzrError('sha1 mismatch. For revision id {%s}'
257
256
                            'local: %s, bundle: %s' % (revision_id, local_sha1, sha1))
258
257
                else:
259
258
                    count += 1
260
259
            elif revision_id not in checked:
261
260
                missing[revision_id] = sha1
262
261
 
263
 
        for inv_id, sha1 in inv_to_sha.iteritems():
264
 
            if repository.has_revision(inv_id):
265
 
                # Note: branch.get_inventory_sha1() just returns the value that
266
 
                # is stored in the revision text, and that value may be out
267
 
                # of date. This is bogus, because that means we aren't
268
 
                # validating the actual text, just that we wrote and read the
269
 
                # string. But for now, what the hell.
270
 
                local_sha1 = repository.get_inventory_sha1(inv_id)
271
 
                if sha1 != local_sha1:
272
 
                    raise BzrError('sha1 mismatch. For inventory id {%s}' 
273
 
                                   'local: %s, bundle: %s' % 
274
 
                                   (inv_id, local_sha1, sha1))
275
 
                else:
276
 
                    count += 1
277
 
 
278
262
        if len(missing) > 0:
279
263
            # I don't know if this is an error yet
280
264
            warning('Not all revision hashes could be validated.'
286
270
        """At this point we should have generated the BundleTree,
287
271
        so build up an inventory, and make sure the hashes match.
288
272
        """
289
 
 
290
 
        assert inv is not None
291
 
 
292
273
        # Now we should have a complete inventory entry.
293
274
        s = serializer_v5.write_inventory_to_string(inv)
294
275
        sha1 = sha_string(s)
295
276
        # Target revision is the last entry in the real_revisions list
296
277
        rev = self.get_revision(revision_id)
297
 
        assert rev.revision_id == revision_id
 
278
        if rev.revision_id != revision_id:
 
279
            raise AssertionError()
298
280
        if sha1 != rev.inventory_sha1:
299
 
            open(',,bogus-inv', 'wb').write(s)
 
281
            f = open(',,bogus-inv', 'wb')
 
282
            try:
 
283
                f.write(s)
 
284
            finally:
 
285
                f.close()
300
286
            warning('Inventory sha hash mismatch for revision %s. %s'
301
287
                    ' != %s' % (revision_id, sha1, rev.inventory_sha1))
302
288
 
303
289
    def _validate_revision(self, inventory, revision_id):
304
290
        """Make sure all revision entries match their checksum."""
305
291
 
306
 
        # This is a mapping from each revision id to it's sha hash
 
292
        # This is a mapping from each revision id to its sha hash
307
293
        rev_to_sha1 = {}
308
 
        
 
294
 
309
295
        rev = self.get_revision(revision_id)
310
296
        rev_info = self.get_revision_info(revision_id)
311
 
        assert rev.revision_id == rev_info.revision_id
312
 
        assert rev.revision_id == revision_id
 
297
        if not (rev.revision_id == rev_info.revision_id):
 
298
            raise AssertionError()
 
299
        if not (rev.revision_id == revision_id):
 
300
            raise AssertionError()
313
301
        sha1 = self._testament_sha1(rev, inventory)
314
302
        if sha1 != rev_info.sha1:
315
303
            raise TestamentMismatch(rev.revision_id, rev_info.sha1, sha1)
343
331
                try:
344
332
                    name, value = info_item.split(':', 1)
345
333
                except ValueError:
346
 
                    raise 'Value %r has no colon' % info_item
 
334
                    raise ValueError('Value %r has no colon' % info_item)
347
335
                if name == 'last-changed':
348
336
                    last_changed = value
349
337
                elif name == 'executable':
350
 
                    assert value in ('yes', 'no'), value
351
338
                    val = (value == 'yes')
352
339
                    bundle_tree.note_executable(new_path, val)
353
340
                elif name == 'target':
357
344
            return last_changed, encoding
358
345
 
359
346
        def do_patch(path, lines, encoding):
360
 
            if encoding is not None:
361
 
                assert encoding == 'base64'
 
347
            if encoding == 'base64':
362
348
                patch = base64.decodestring(''.join(lines))
363
 
            else:
 
349
            elif encoding is None:
364
350
                patch =  ''.join(lines)
 
351
            else:
 
352
                raise ValueError(encoding)
365
353
            bundle_tree.note_patch(path, patch)
366
354
 
367
355
        def renamed(kind, extra, lines):
427
415
            revision = get_rev_id(last_modified, path, kind)
428
416
            if lines:
429
417
                do_patch(path, lines, encoding)
430
 
            
 
418
 
431
419
        valid_actions = {
432
420
            'renamed':renamed,
433
421
            'removed':removed,
495
483
 
496
484
    def note_rename(self, old_path, new_path):
497
485
        """A file/directory has been renamed from old_path => new_path"""
498
 
        assert new_path not in self._renamed
499
 
        assert old_path not in self._renamed_r
 
486
        if new_path in self._renamed:
 
487
            raise AssertionError(new_path)
 
488
        if old_path in self._renamed_r:
 
489
            raise AssertionError(old_path)
500
490
        self._renamed[new_path] = old_path
501
491
        self._renamed_r[old_path] = new_path
502
492
 
532
522
 
533
523
    def old_path(self, new_path):
534
524
        """Get the old_path (path in the base_tree) for the file at new_path"""
535
 
        assert new_path[:1] not in ('\\', '/')
 
525
        if new_path[:1] in ('\\', '/'):
 
526
            raise ValueError(new_path)
536
527
        old_path = self._renamed.get(new_path)
537
528
        if old_path is not None:
538
529
            return old_path
552
543
        #renamed_r
553
544
        if old_path in self._renamed_r:
554
545
            return None
555
 
        return old_path 
 
546
        return old_path
556
547
 
557
548
    def new_path(self, old_path):
558
549
        """Get the new_path (path in the target_tree) for the file at old_path
559
550
        in the base tree.
560
551
        """
561
 
        assert old_path[:1] not in ('\\', '/')
 
552
        if old_path[:1] in ('\\', '/'):
 
553
            raise ValueError(old_path)
562
554
        new_path = self._renamed_r.get(old_path)
563
555
        if new_path is not None:
564
556
            return new_path
577
569
        #renamed_r
578
570
        if new_path in self._renamed:
579
571
            return None
580
 
        return new_path 
 
572
        return new_path
581
573
 
582
574
    def path2id(self, path):
583
575
        """Return the id of the file present at path in the target tree."""
617
609
                return None
618
610
        new_path = self.id2path(file_id)
619
611
        return self.base_tree.path2id(new_path)
620
 
        
 
612
 
621
613
    def get_file(self, file_id):
622
614
        """Return a file-like object containing the new contents of the
623
615
        file given by file_id.
634
626
            patch_original = None
635
627
        file_patch = self.patches.get(self.id2path(file_id))
636
628
        if file_patch is None:
637
 
            if (patch_original is None and 
 
629
            if (patch_original is None and
638
630
                self.get_kind(file_id) == 'directory'):
639
631
                return StringIO()
640
 
            assert patch_original is not None, "None: %s" % file_id
 
632
            if patch_original is None:
 
633
                raise AssertionError("None: %s" % file_id)
641
634
            return patch_original
642
635
 
643
 
        assert not file_patch.startswith('\\'), \
644
 
            'Malformed patch for %s, %r' % (file_id, file_patch)
 
636
        if file_patch.startswith('\\'):
 
637
            raise ValueError(
 
638
                'Malformed patch for %s, %r' % (file_id, file_patch))
645
639
        return patched_file(file_patch, patch_original)
646
640
 
647
641
    def get_symlink_target(self, file_id):
694
688
        This need to be called before ever accessing self.inventory
695
689
        """
696
690
        from os.path import dirname, basename
697
 
 
698
 
        assert self.base_tree is not None
699
691
        base_inv = self.base_tree.inventory
700
692
        inv = Inventory(None, self.revision_id)
701
693
 
723
715
                ie.symlink_target = self.get_symlink_target(file_id)
724
716
            ie.revision = revision_id
725
717
 
726
 
            if kind in ('directory', 'symlink'):
727
 
                ie.text_size, ie.text_sha1 = None, None
728
 
            else:
 
718
            if kind == 'file':
729
719
                ie.text_size, ie.text_sha1 = self.get_size_and_sha1(file_id)
730
 
            if (ie.text_size is None) and (kind == 'file'):
731
 
                raise BzrError('Got a text_size of None for file_id %r' % file_id)
 
720
                if ie.text_size is None:
 
721
                    raise BzrError(
 
722
                        'Got a text_size of None for file_id %r' % file_id)
732
723
            inv.add(ie)
733
724
 
734
725
        sorted_entries = self.sorted_path_id()