1
# Copyright (C) 2005-2010 Canonical Ltd
1
# Copyright (C) 2006 Canonical Ltd
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
30
29
from bzrlib.bundle import apply_bundle
31
from bzrlib.errors import (
35
from bzrlib.inventory import (
41
from bzrlib.osutils import sha_string, pathjoin
30
from bzrlib.errors import (TestamentMismatch, BzrError,
31
MalformedHeader, MalformedPatches, NotABundle)
32
from bzrlib.inventory import (Inventory, InventoryEntry,
33
InventoryDirectory, InventoryFile,
35
from bzrlib.osutils import sha_file, sha_string, pathjoin
42
36
from bzrlib.revision import Revision, NULL_REVISION
43
37
from bzrlib.testament import StrictTestament
44
38
from bzrlib.trace import mutter, warning
39
import bzrlib.transport
45
40
from bzrlib.tree import Tree
41
import bzrlib.urlutils
46
42
from bzrlib.xml5 import serializer_v5
211
207
inv = bundle_tree.inventory
212
208
self._validate_inventory(inv, revision_id)
213
self._validate_revision(bundle_tree, revision_id)
209
self._validate_revision(inv, revision_id)
215
211
return bundle_tree
282
278
if rev.revision_id != revision_id:
283
279
raise AssertionError()
284
280
if sha1 != rev.inventory_sha1:
285
f = open(',,bogus-inv', 'wb')
281
open(',,bogus-inv', 'wb').write(s)
290
282
warning('Inventory sha hash mismatch for revision %s. %s'
291
283
' != %s' % (revision_id, sha1, rev.inventory_sha1))
293
def _validate_revision(self, tree, revision_id):
285
def _validate_revision(self, inventory, revision_id):
294
286
"""Make sure all revision entries match their checksum."""
296
# This is a mapping from each revision id to its sha hash
288
# This is a mapping from each revision id to it's sha hash
299
291
rev = self.get_revision(revision_id)
302
294
raise AssertionError()
303
295
if not (rev.revision_id == revision_id):
304
296
raise AssertionError()
305
sha1 = self._testament_sha1(rev, tree)
297
sha1 = self._testament_sha1(rev, inventory)
306
298
if sha1 != rev_info.sha1:
307
299
raise TestamentMismatch(rev.revision_id, rev_info.sha1, sha1)
308
300
if rev.revision_id in rev_to_sha1:
336
328
name, value = info_item.split(':', 1)
337
329
except ValueError:
338
raise ValueError('Value %r has no colon' % info_item)
330
raise 'Value %r has no colon' % info_item
339
331
if name == 'last-changed':
340
332
last_changed = value
341
333
elif name == 'executable':
590
578
if old_path in self.deleted:
592
return self.base_tree.path2id(old_path)
580
if getattr(self.base_tree, 'path2id', None) is not None:
581
return self.base_tree.path2id(old_path)
583
return self.base_tree.inventory.path2id(old_path)
594
585
def id2path(self, file_id):
595
586
"""Return the new path in the target tree of the file with id file_id"""
626
617
base_id = self.old_contents_id(file_id)
627
618
if (base_id is not None and
628
base_id != self.base_tree.get_root_id()):
619
base_id != self.base_tree.inventory.root.file_id):
629
620
patch_original = self.base_tree.get_file(base_id)
631
622
patch_original = None
632
623
file_patch = self.patches.get(self.id2path(file_id))
633
624
if file_patch is None:
634
625
if (patch_original is None and
635
self.kind(file_id) == 'directory'):
626
self.get_kind(file_id) == 'directory'):
636
627
return StringIO()
637
628
if patch_original is None:
638
629
raise AssertionError("None: %s" % file_id)
643
634
'Malformed patch for %s, %r' % (file_id, file_patch))
644
635
return patched_file(file_patch, patch_original)
646
def get_symlink_target(self, file_id, path=None):
648
path = self.id2path(file_id)
637
def get_symlink_target(self, file_id):
638
new_path = self.id2path(file_id)
650
return self._targets[path]
640
return self._targets[new_path]
652
642
return self.base_tree.get_symlink_target(file_id)
654
def kind(self, file_id):
644
def get_kind(self, file_id):
655
645
if file_id in self._kinds:
656
646
return self._kinds[file_id]
657
return self.base_tree.kind(file_id)
659
def get_file_revision(self, file_id):
660
path = self.id2path(file_id)
661
if path in self._last_changed:
662
return self._last_changed[path]
664
return self.base_tree.get_file_revision(file_id)
647
return self.base_tree.inventory[file_id].kind
666
649
def is_executable(self, file_id):
667
650
path = self.id2path(file_id)
668
651
if path in self._executable:
669
652
return self._executable[path]
671
return self.base_tree.is_executable(file_id)
654
return self.base_tree.inventory[file_id].executable
673
656
def get_last_changed(self, file_id):
674
657
path = self.id2path(file_id)
675
658
if path in self._last_changed:
676
659
return self._last_changed[path]
677
return self.base_tree.get_file_revision(file_id)
660
return self.base_tree.inventory[file_id].revision
679
662
def get_size_and_sha1(self, file_id):
680
663
"""Return the size and sha1 hash of the given file id.
714
697
parent_path = dirname(path)
715
698
parent_id = self.path2id(parent_path)
717
kind = self.kind(file_id)
700
kind = self.get_kind(file_id)
718
701
revision_id = self.get_last_changed(file_id)
720
703
name = basename(path)
725
708
ie.executable = self.is_executable(file_id)
726
709
elif kind == 'symlink':
727
710
ie = InventoryLink(file_id, name, parent_id)
728
ie.symlink_target = self.get_symlink_target(file_id, path)
711
ie.symlink_target = self.get_symlink_target(file_id)
729
712
ie.revision = revision_id
714
if kind in ('directory', 'symlink'):
715
ie.text_size, ie.text_sha1 = None, None
732
717
ie.text_size, ie.text_sha1 = self.get_size_and_sha1(file_id)
733
if ie.text_size is None:
735
'Got a text_size of None for file_id %r' % file_id)
718
if (ie.text_size is None) and (kind == 'file'):
719
raise BzrError('Got a text_size of None for file_id %r' % file_id)
738
722
sorted_entries = self.sorted_path_id()
752
736
for path, entry in self.inventory.iter_entries():
753
737
yield entry.file_id
755
def list_files(self, include_root=False, from_dir=None, recursive=True):
756
# The only files returned by this are those from the version
761
from_dir_id = inv.path2id(from_dir)
762
if from_dir_id is None:
763
# Directory not versioned
765
entries = inv.iter_entries(from_dir=from_dir_id, recursive=recursive)
766
if inv.root is not None and not include_root and from_dir is None:
767
# skip the root for compatability with the current apis.
769
for path, entry in entries:
770
yield path, 'V', entry.kind, entry.file_id, entry
772
739
def sorted_path_id(self):
774
741
for result in self._new_id.iteritems():
775
742
paths.append(result)
776
for id in self.base_tree.all_file_ids():
743
for id in self.base_tree:
777
744
path = self.id2path(id)