1
# Copyright (C) 2006 Canonical Ltd
1
# Copyright (C) 2005-2010 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
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
17
17
"""Read in a bundle stream, and process it into a BundleReader object."""
29
28
from bzrlib.bundle import apply_bundle
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
29
from bzrlib.errors import (
33
from bzrlib.inventory import (
39
from bzrlib.osutils import sha_string, pathjoin
36
40
from bzrlib.revision import Revision, NULL_REVISION
37
41
from bzrlib.testament import StrictTestament
38
42
from bzrlib.trace import mutter, warning
39
import bzrlib.transport
40
43
from bzrlib.tree import Tree
41
import bzrlib.urlutils
42
44
from bzrlib.xml5 import serializer_v5
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)
207
209
inv = bundle_tree.inventory
208
210
self._validate_inventory(inv, revision_id)
209
self._validate_revision(inv, revision_id)
211
self._validate_revision(bundle_tree, revision_id)
211
213
return bundle_tree
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)
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)
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,
252
254
local_sha1 = self._testament_sha1_from_revision(repository,
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))
278
280
if rev.revision_id != revision_id:
279
281
raise AssertionError()
280
282
if sha1 != rev.inventory_sha1:
281
open(',,bogus-inv', 'wb').write(s)
283
f = open(',,bogus-inv', 'wb')
282
288
warning('Inventory sha hash mismatch for revision %s. %s'
283
289
' != %s' % (revision_id, sha1, rev.inventory_sha1))
285
def _validate_revision(self, inventory, revision_id):
291
def _validate_revision(self, tree, revision_id):
286
292
"""Make sure all revision entries match their checksum."""
288
# This is a mapping from each revision id to it's sha hash
294
# This is a mapping from each revision id to its sha hash
291
297
rev = self.get_revision(revision_id)
292
298
rev_info = self.get_revision_info(revision_id)
293
299
if not (rev.revision_id == rev_info.revision_id):
294
300
raise AssertionError()
295
301
if not (rev.revision_id == revision_id):
296
302
raise AssertionError()
297
sha1 = self._testament_sha1(rev, inventory)
303
sha1 = self._testament_sha1(rev, tree)
298
304
if sha1 != rev_info.sha1:
299
305
raise TestamentMismatch(rev.revision_id, rev_info.sha1, sha1)
300
306
if rev.revision_id in rev_to_sha1:
328
334
name, value = info_item.split(':', 1)
329
335
except ValueError:
330
raise 'Value %r has no colon' % info_item
336
raise ValueError('Value %r has no colon' % info_item)
331
337
if name == 'last-changed':
332
338
last_changed = value
333
339
elif name == 'executable':
606
613
new_path = self.id2path(file_id)
607
614
return self.base_tree.path2id(new_path)
609
616
def get_file(self, file_id):
610
617
"""Return a file-like object containing the new contents of the
611
618
file given by file_id.
622
629
patch_original = None
623
630
file_patch = self.patches.get(self.id2path(file_id))
624
631
if file_patch is None:
625
if (patch_original is None and
632
if (patch_original is None and
626
633
self.get_kind(file_id) == 'directory'):
627
634
return StringIO()
628
635
if patch_original is None:
634
641
'Malformed patch for %s, %r' % (file_id, file_patch))
635
642
return patched_file(file_patch, patch_original)
637
def get_symlink_target(self, file_id):
638
new_path = self.id2path(file_id)
644
def get_symlink_target(self, file_id, path=None):
646
path = self.id2path(file_id)
640
return self._targets[new_path]
648
return self._targets[path]
642
650
return self.base_tree.get_symlink_target(file_id)
657
665
path = self.id2path(file_id)
658
666
if path in self._last_changed:
659
667
return self._last_changed[path]
660
return self.base_tree.inventory[file_id].revision
668
return self.base_tree.get_file_revision(file_id)
662
670
def get_size_and_sha1(self, file_id):
663
671
"""Return the size and sha1 hash of the given file id.
708
716
ie.executable = self.is_executable(file_id)
709
717
elif kind == 'symlink':
710
718
ie = InventoryLink(file_id, name, parent_id)
711
ie.symlink_target = self.get_symlink_target(file_id)
719
ie.symlink_target = self.get_symlink_target(file_id, path)
712
720
ie.revision = revision_id
714
if kind in ('directory', 'symlink'):
715
ie.text_size, ie.text_sha1 = None, None
717
723
ie.text_size, ie.text_sha1 = self.get_size_and_sha1(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)
724
if ie.text_size is None:
726
'Got a text_size of None for file_id %r' % file_id)
722
729
sorted_entries = self.sorted_path_id()
736
743
for path, entry in self.inventory.iter_entries():
737
744
yield entry.file_id
746
def list_files(self, include_root=False, from_dir=None, recursive=True):
747
# The only files returned by this are those from the version
752
from_dir_id = inv.path2id(from_dir)
753
if from_dir_id is None:
754
# Directory not versioned
756
entries = inv.iter_entries(from_dir=from_dir_id, recursive=recursive)
757
if inv.root is not None and not include_root and from_dir is None:
758
# skip the root for compatability with the current apis.
760
for path, entry in entries:
761
yield path, 'V', entry.kind, entry.file_id, entry
739
763
def sorted_path_id(self):
741
765
for result in self._new_id.iteritems():
742
766
paths.append(result)
743
for id in self.base_tree:
767
for id in self.base_tree.all_file_ids():
744
768
path = self.id2path(id)