~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/bundle/bundle_data.py

  • Committer: John Arbash Meinel
  • Date: 2010-08-02 17:16:12 UTC
  • mto: This revision was merged to the branch mainline in revision 5369.
  • Revision ID: john@arbash-meinel.com-20100802171612-rdh5ods70w2bl3j7
We also have to re-implement it for _simple_set_pyx.pyx

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
 
194
192
        raise KeyError(revision_id)
195
193
 
196
194
    def revision_tree(self, repository, revision_id, base=None):
197
 
        revision_id = osutils.safe_revision_id(revision_id)
198
195
        revision = self.get_revision(revision_id)
199
196
        base = self.get_base(revision)
200
 
        assert base != revision_id
 
197
        if base == revision_id:
 
198
            raise AssertionError()
201
199
        if not self._validated_revisions_against_repo:
202
200
            self._validate_references_from_repository(repository)
203
201
        revision_info = self.get_revision_info(revision_id)
204
202
        inventory_revision_id = revision_id
205
 
        bundle_tree = BundleTree(repository.revision_tree(base), 
 
203
        bundle_tree = BundleTree(repository.revision_tree(base),
206
204
                                  inventory_revision_id)
207
205
        self._update_tree(bundle_tree, revision_id)
208
206
 
241
239
        for rev_info in self.revisions:
242
240
            checked[rev_info.revision_id] = True
243
241
            add_sha(rev_to_sha, rev_info.revision_id, rev_info.sha1)
244
 
                
 
242
 
245
243
        for (rev, rev_info) in zip(self.real_revisions, self.revisions):
246
244
            add_sha(inv_to_sha, rev_info.revision_id, rev_info.inventory_sha1)
247
245
 
249
247
        missing = {}
250
248
        for revision_id, sha1 in rev_to_sha.iteritems():
251
249
            if repository.has_revision(revision_id):
252
 
                testament = StrictTestament.from_revision(repository, 
 
250
                testament = StrictTestament.from_revision(repository,
253
251
                                                          revision_id)
254
252
                local_sha1 = self._testament_sha1_from_revision(repository,
255
253
                                                                revision_id)
256
254
                if sha1 != local_sha1:
257
 
                    raise BzrError('sha1 mismatch. For revision id {%s}' 
 
255
                    raise BzrError('sha1 mismatch. For revision id {%s}'
258
256
                            'local: %s, bundle: %s' % (revision_id, local_sha1, sha1))
259
257
                else:
260
258
                    count += 1
261
259
            elif revision_id not in checked:
262
260
                missing[revision_id] = sha1
263
261
 
264
 
        for inv_id, sha1 in inv_to_sha.iteritems():
265
 
            if repository.has_revision(inv_id):
266
 
                # Note: branch.get_inventory_sha1() just returns the value that
267
 
                # is stored in the revision text, and that value may be out
268
 
                # of date. This is bogus, because that means we aren't
269
 
                # validating the actual text, just that we wrote and read the
270
 
                # string. But for now, what the hell.
271
 
                local_sha1 = repository.get_inventory_sha1(inv_id)
272
 
                if sha1 != local_sha1:
273
 
                    raise BzrError('sha1 mismatch. For inventory id {%s}' 
274
 
                                   'local: %s, bundle: %s' % 
275
 
                                   (inv_id, local_sha1, sha1))
276
 
                else:
277
 
                    count += 1
278
 
 
279
262
        if len(missing) > 0:
280
263
            # I don't know if this is an error yet
281
264
            warning('Not all revision hashes could be validated.'
287
270
        """At this point we should have generated the BundleTree,
288
271
        so build up an inventory, and make sure the hashes match.
289
272
        """
290
 
 
291
 
        assert inv is not None
292
 
 
293
273
        # Now we should have a complete inventory entry.
294
274
        s = serializer_v5.write_inventory_to_string(inv)
295
275
        sha1 = sha_string(s)
296
276
        # Target revision is the last entry in the real_revisions list
297
277
        rev = self.get_revision(revision_id)
298
 
        assert rev.revision_id == revision_id
 
278
        if rev.revision_id != revision_id:
 
279
            raise AssertionError()
299
280
        if sha1 != rev.inventory_sha1:
300
 
            open(',,bogus-inv', 'wb').write(s)
 
281
            f = open(',,bogus-inv', 'wb')
 
282
            try:
 
283
                f.write(s)
 
284
            finally:
 
285
                f.close()
301
286
            warning('Inventory sha hash mismatch for revision %s. %s'
302
287
                    ' != %s' % (revision_id, sha1, rev.inventory_sha1))
303
288
 
306
291
 
307
292
        # This is a mapping from each revision id to it's sha hash
308
293
        rev_to_sha1 = {}
309
 
        
 
294
 
310
295
        rev = self.get_revision(revision_id)
311
296
        rev_info = self.get_revision_info(revision_id)
312
 
        assert rev.revision_id == rev_info.revision_id
313
 
        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()
314
301
        sha1 = self._testament_sha1(rev, inventory)
315
302
        if sha1 != rev_info.sha1:
316
303
            raise TestamentMismatch(rev.revision_id, rev_info.sha1, sha1)
344
331
                try:
345
332
                    name, value = info_item.split(':', 1)
346
333
                except ValueError:
347
 
                    raise 'Value %r has no colon' % info_item
 
334
                    raise ValueError('Value %r has no colon' % info_item)
348
335
                if name == 'last-changed':
349
336
                    last_changed = value
350
337
                elif name == 'executable':
351
 
                    assert value in ('yes', 'no'), value
352
338
                    val = (value == 'yes')
353
339
                    bundle_tree.note_executable(new_path, val)
354
340
                elif name == 'target':
358
344
            return last_changed, encoding
359
345
 
360
346
        def do_patch(path, lines, encoding):
361
 
            if encoding is not None:
362
 
                assert encoding == 'base64'
 
347
            if encoding == 'base64':
363
348
                patch = base64.decodestring(''.join(lines))
364
 
            else:
 
349
            elif encoding is None:
365
350
                patch =  ''.join(lines)
 
351
            else:
 
352
                raise ValueError(encoding)
366
353
            bundle_tree.note_patch(path, patch)
367
354
 
368
355
        def renamed(kind, extra, lines):
428
415
            revision = get_rev_id(last_modified, path, kind)
429
416
            if lines:
430
417
                do_patch(path, lines, encoding)
431
 
            
 
418
 
432
419
        valid_actions = {
433
420
            'renamed':renamed,
434
421
            'removed':removed,
496
483
 
497
484
    def note_rename(self, old_path, new_path):
498
485
        """A file/directory has been renamed from old_path => new_path"""
499
 
        assert new_path not in self._renamed
500
 
        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)
501
490
        self._renamed[new_path] = old_path
502
491
        self._renamed_r[old_path] = new_path
503
492
 
533
522
 
534
523
    def old_path(self, new_path):
535
524
        """Get the old_path (path in the base_tree) for the file at new_path"""
536
 
        assert new_path[:1] not in ('\\', '/')
 
525
        if new_path[:1] in ('\\', '/'):
 
526
            raise ValueError(new_path)
537
527
        old_path = self._renamed.get(new_path)
538
528
        if old_path is not None:
539
529
            return old_path
553
543
        #renamed_r
554
544
        if old_path in self._renamed_r:
555
545
            return None
556
 
        return old_path 
 
546
        return old_path
557
547
 
558
548
    def new_path(self, old_path):
559
549
        """Get the new_path (path in the target_tree) for the file at old_path
560
550
        in the base tree.
561
551
        """
562
 
        assert old_path[:1] not in ('\\', '/')
 
552
        if old_path[:1] in ('\\', '/'):
 
553
            raise ValueError(old_path)
563
554
        new_path = self._renamed_r.get(old_path)
564
555
        if new_path is not None:
565
556
            return new_path
578
569
        #renamed_r
579
570
        if new_path in self._renamed:
580
571
            return None
581
 
        return new_path 
 
572
        return new_path
582
573
 
583
574
    def path2id(self, path):
584
575
        """Return the id of the file present at path in the target tree."""
618
609
                return None
619
610
        new_path = self.id2path(file_id)
620
611
        return self.base_tree.path2id(new_path)
621
 
        
 
612
 
622
613
    def get_file(self, file_id):
623
614
        """Return a file-like object containing the new contents of the
624
615
        file given by file_id.
635
626
            patch_original = None
636
627
        file_patch = self.patches.get(self.id2path(file_id))
637
628
        if file_patch is None:
638
 
            if (patch_original is None and 
 
629
            if (patch_original is None and
639
630
                self.get_kind(file_id) == 'directory'):
640
631
                return StringIO()
641
 
            assert patch_original is not None, "None: %s" % file_id
 
632
            if patch_original is None:
 
633
                raise AssertionError("None: %s" % file_id)
642
634
            return patch_original
643
635
 
644
 
        assert not file_patch.startswith('\\'), \
645
 
            '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))
646
639
        return patched_file(file_patch, patch_original)
647
640
 
648
641
    def get_symlink_target(self, file_id):
695
688
        This need to be called before ever accessing self.inventory
696
689
        """
697
690
        from os.path import dirname, basename
698
 
 
699
 
        assert self.base_tree is not None
700
691
        base_inv = self.base_tree.inventory
701
692
        inv = Inventory(None, self.revision_id)
702
693