~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/bundle/bundle_data.py

  • Committer: Robert Collins
  • Date: 2007-08-06 23:49:18 UTC
  • mto: (2592.3.81 repository)
  • mto: This revision was merged to the branch mainline in revision 2933.
  • Revision ID: robertc@robertcollins.net-20070806234918-xc9w5f86tgjphf9u
Prevent the duplicate additions of names to FileNames collections.

Show diffs side-by-side

added added

removed removed

Lines of Context:
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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
 
                    if not property.endswith(':'):
82
 
                        raise ValueError(property)
 
81
                    assert property.endswith(':')
83
82
                    key = str(property[:-1])
84
83
                    value = ''
85
84
                else:
159
158
    def get_base(self, revision):
160
159
        revision_info = self.get_revision_info(revision.revision_id)
161
160
        if revision_info.base_id is not None:
162
 
            return revision_info.base_id
 
161
            if revision_info.base_id == NULL_REVISION:
 
162
                return None
 
163
            else:
 
164
                return revision_info.base_id
163
165
        if len(revision.parent_ids) == 0:
164
166
            # There is no base listed, and
165
167
            # the lowest revision doesn't have a parent
166
168
            # so this is probably against the empty tree
167
 
            # and thus base truly is NULL_REVISION
168
 
            return NULL_REVISION
 
169
            # and thus base truly is None
 
170
            return None
169
171
        else:
170
172
            return revision.parent_ids[-1]
171
173
 
192
194
        raise KeyError(revision_id)
193
195
 
194
196
    def revision_tree(self, repository, revision_id, base=None):
 
197
        revision_id = osutils.safe_revision_id(revision_id)
195
198
        revision = self.get_revision(revision_id)
196
199
        base = self.get_base(revision)
197
 
        if base == revision_id:
198
 
            raise AssertionError()
 
200
        assert base != revision_id
199
201
        if not self._validated_revisions_against_repo:
200
202
            self._validate_references_from_repository(repository)
201
203
        revision_info = self.get_revision_info(revision_id)
202
204
        inventory_revision_id = revision_id
203
 
        bundle_tree = BundleTree(repository.revision_tree(base),
 
205
        bundle_tree = BundleTree(repository.revision_tree(base), 
204
206
                                  inventory_revision_id)
205
207
        self._update_tree(bundle_tree, revision_id)
206
208
 
239
241
        for rev_info in self.revisions:
240
242
            checked[rev_info.revision_id] = True
241
243
            add_sha(rev_to_sha, rev_info.revision_id, rev_info.sha1)
242
 
 
 
244
                
243
245
        for (rev, rev_info) in zip(self.real_revisions, self.revisions):
244
246
            add_sha(inv_to_sha, rev_info.revision_id, rev_info.inventory_sha1)
245
247
 
247
249
        missing = {}
248
250
        for revision_id, sha1 in rev_to_sha.iteritems():
249
251
            if repository.has_revision(revision_id):
250
 
                testament = StrictTestament.from_revision(repository,
 
252
                testament = StrictTestament.from_revision(repository, 
251
253
                                                          revision_id)
252
254
                local_sha1 = self._testament_sha1_from_revision(repository,
253
255
                                                                revision_id)
254
256
                if sha1 != local_sha1:
255
 
                    raise BzrError('sha1 mismatch. For revision id {%s}'
 
257
                    raise BzrError('sha1 mismatch. For revision id {%s}' 
256
258
                            'local: %s, bundle: %s' % (revision_id, local_sha1, sha1))
257
259
                else:
258
260
                    count += 1
259
261
            elif revision_id not in checked:
260
262
                missing[revision_id] = sha1
261
263
 
 
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
 
262
279
        if len(missing) > 0:
263
280
            # I don't know if this is an error yet
264
281
            warning('Not all revision hashes could be validated.'
270
287
        """At this point we should have generated the BundleTree,
271
288
        so build up an inventory, and make sure the hashes match.
272
289
        """
 
290
 
 
291
        assert inv is not None
 
292
 
273
293
        # Now we should have a complete inventory entry.
274
294
        s = serializer_v5.write_inventory_to_string(inv)
275
295
        sha1 = sha_string(s)
276
296
        # Target revision is the last entry in the real_revisions list
277
297
        rev = self.get_revision(revision_id)
278
 
        if rev.revision_id != revision_id:
279
 
            raise AssertionError()
 
298
        assert rev.revision_id == revision_id
280
299
        if sha1 != rev.inventory_sha1:
281
300
            open(',,bogus-inv', 'wb').write(s)
282
301
            warning('Inventory sha hash mismatch for revision %s. %s'
287
306
 
288
307
        # This is a mapping from each revision id to it's sha hash
289
308
        rev_to_sha1 = {}
290
 
 
 
309
        
291
310
        rev = self.get_revision(revision_id)
292
311
        rev_info = self.get_revision_info(revision_id)
293
 
        if not (rev.revision_id == rev_info.revision_id):
294
 
            raise AssertionError()
295
 
        if not (rev.revision_id == revision_id):
296
 
            raise AssertionError()
 
312
        assert rev.revision_id == rev_info.revision_id
 
313
        assert rev.revision_id == revision_id
297
314
        sha1 = self._testament_sha1(rev, inventory)
298
315
        if sha1 != rev_info.sha1:
299
316
            raise TestamentMismatch(rev.revision_id, rev_info.sha1, sha1)
331
348
                if name == 'last-changed':
332
349
                    last_changed = value
333
350
                elif name == 'executable':
 
351
                    assert value in ('yes', 'no'), value
334
352
                    val = (value == 'yes')
335
353
                    bundle_tree.note_executable(new_path, val)
336
354
                elif name == 'target':
340
358
            return last_changed, encoding
341
359
 
342
360
        def do_patch(path, lines, encoding):
343
 
            if encoding == 'base64':
 
361
            if encoding is not None:
 
362
                assert encoding == 'base64'
344
363
                patch = base64.decodestring(''.join(lines))
345
 
            elif encoding is None:
 
364
            else:
346
365
                patch =  ''.join(lines)
347
 
            else:
348
 
                raise ValueError(encoding)
349
366
            bundle_tree.note_patch(path, patch)
350
367
 
351
368
        def renamed(kind, extra, lines):
411
428
            revision = get_rev_id(last_modified, path, kind)
412
429
            if lines:
413
430
                do_patch(path, lines, encoding)
414
 
 
 
431
            
415
432
        valid_actions = {
416
433
            'renamed':renamed,
417
434
            'removed':removed,
440
457
                        ' (unrecognized action): %r' % action_line)
441
458
            valid_actions[action](kind, extra, lines)
442
459
 
443
 
    def install_revisions(self, target_repo, stream_input=True):
444
 
        """Install revisions and return the target revision
445
 
 
446
 
        :param target_repo: The repository to install into
447
 
        :param stream_input: Ignored by this implementation.
448
 
        """
 
460
    def install_revisions(self, target_repo):
 
461
        """Install revisions and return the target revision"""
449
462
        apply_bundle.install_bundle(target_repo, self)
450
463
        return self.target
451
464
 
479
492
 
480
493
    def note_rename(self, old_path, new_path):
481
494
        """A file/directory has been renamed from old_path => new_path"""
482
 
        if new_path in self._renamed:
483
 
            raise AssertionError(new_path)
484
 
        if old_path in self._renamed_r:
485
 
            raise AssertionError(old_path)
 
495
        assert new_path not in self._renamed
 
496
        assert old_path not in self._renamed_r
486
497
        self._renamed[new_path] = old_path
487
498
        self._renamed_r[old_path] = new_path
488
499
 
518
529
 
519
530
    def old_path(self, new_path):
520
531
        """Get the old_path (path in the base_tree) for the file at new_path"""
521
 
        if new_path[:1] in ('\\', '/'):
522
 
            raise ValueError(new_path)
 
532
        assert new_path[:1] not in ('\\', '/')
523
533
        old_path = self._renamed.get(new_path)
524
534
        if old_path is not None:
525
535
            return old_path
539
549
        #renamed_r
540
550
        if old_path in self._renamed_r:
541
551
            return None
542
 
        return old_path
 
552
        return old_path 
543
553
 
544
554
    def new_path(self, old_path):
545
555
        """Get the new_path (path in the target_tree) for the file at old_path
546
556
        in the base tree.
547
557
        """
548
 
        if old_path[:1] in ('\\', '/'):
549
 
            raise ValueError(old_path)
 
558
        assert old_path[:1] not in ('\\', '/')
550
559
        new_path = self._renamed_r.get(old_path)
551
560
        if new_path is not None:
552
561
            return new_path
565
574
        #renamed_r
566
575
        if new_path in self._renamed:
567
576
            return None
568
 
        return new_path
 
577
        return new_path 
569
578
 
570
579
    def path2id(self, path):
571
580
        """Return the id of the file present at path in the target tree."""
605
614
                return None
606
615
        new_path = self.id2path(file_id)
607
616
        return self.base_tree.path2id(new_path)
608
 
 
 
617
        
609
618
    def get_file(self, file_id):
610
619
        """Return a file-like object containing the new contents of the
611
620
        file given by file_id.
622
631
            patch_original = None
623
632
        file_patch = self.patches.get(self.id2path(file_id))
624
633
        if file_patch is None:
625
 
            if (patch_original is None and
 
634
            if (patch_original is None and 
626
635
                self.get_kind(file_id) == 'directory'):
627
636
                return StringIO()
628
 
            if patch_original is None:
629
 
                raise AssertionError("None: %s" % file_id)
 
637
            assert patch_original is not None, "None: %s" % file_id
630
638
            return patch_original
631
639
 
632
 
        if file_patch.startswith('\\'):
633
 
            raise ValueError(
634
 
                'Malformed patch for %s, %r' % (file_id, file_patch))
 
640
        assert not file_patch.startswith('\\'), \
 
641
            'Malformed patch for %s, %r' % (file_id, file_patch)
635
642
        return patched_file(file_patch, patch_original)
636
643
 
637
644
    def get_symlink_target(self, file_id):
684
691
        This need to be called before ever accessing self.inventory
685
692
        """
686
693
        from os.path import dirname, basename
 
694
 
 
695
        assert self.base_tree is not None
687
696
        base_inv = self.base_tree.inventory
688
697
        inv = Inventory(None, self.revision_id)
689
698