38
38
from bzrlib.osutils import (pumpfile, quotefn, splitpath, joinpath,
39
appendpath, sha_strings)
39
pathjoin, sha_strings)
40
40
from bzrlib.trace import mutter
41
41
from bzrlib.errors import (NotVersionedError, InvalidEntryName,
42
42
BzrError, BzrCheckError)
79
79
InventoryDirectory('123', 'src', parent_id='TREE_ROOT')
80
80
>>> i.add(InventoryFile('2323', 'hello.c', parent_id='123'))
81
81
InventoryFile('2323', 'hello.c', parent_id='123')
82
>>> for j in i.iter_entries():
82
>>> shouldbe = {0: 'src', 1: pathjoin('src','hello.c')}
83
>>> for ix, j in enumerate(i.iter_entries()):
84
... print (j[0] == shouldbe[ix], j[1])
85
('src', InventoryDirectory('123', 'src', parent_id='TREE_ROOT'))
86
('src/hello.c', InventoryFile('2323', 'hello.c', parent_id='123'))
86
(True, InventoryDirectory('123', 'src', parent_id='TREE_ROOT'))
87
(True, InventoryFile('2323', 'hello.c', parent_id='123'))
87
88
>>> i.add(InventoryFile('2323', 'bye.c', '123'))
88
89
Traceback (most recent call last):
102
103
InventoryFile('2326', 'wibble.c', parent_id='2325')
103
104
>>> for path, entry in i.iter_entries():
104
... print path.replace('\\\\', '/') # for win32 os.sep
105
106
... assert i.path2id(path)
120
121
def _add_text_to_weave(self, new_lines, parents, weave_store, transaction):
121
weave_store.add_text(self.file_id, self.revision, new_lines, parents,
122
versionedfile = weave_store.get_weave(self.file_id, transaction)
123
versionedfile.add_lines(self.revision, parents, new_lines)
124
125
def detect_changes(self, old_entry):
125
126
"""Return a (text_modified, meta_modified) from this to old_entry.
160
161
any other. If the file is new, the set will be empty.
162
163
def get_ancestors(weave, entry):
163
return set(map(weave.idx_to_name,
164
weave.inclusions([weave.lookup(entry.revision)])))
164
return set(weave.get_ancestry(entry.revision))
166
166
head_ancestors = {}
167
167
for inv in previous_inventories:
202
202
def get_tar_item(self, root, dp, now, tree):
203
203
"""Get a tarfile item and a file stream for its content."""
204
item = tarfile.TarInfo(os.path.join(root, dp))
204
item = tarfile.TarInfo(pathjoin(root, dp))
205
205
# TODO: would be cool to actually set it to the timestamp of the
206
206
# revision it was last changed
267
267
This is a template method - implement _put_on_disk in subclasses.
269
fullpath = appendpath(dest, dp)
269
fullpath = pathjoin(dest, dp)
270
270
self._put_on_disk(fullpath, tree)
271
mutter(" export {%s} kind %s to %s" % (self.file_id, self.kind, fullpath))
271
mutter(" export {%s} kind %s to %s", self.file_id,
273
274
def _put_on_disk(self, fullpath, tree):
274
275
"""Put this entry onto disk at fullpath, from tree tree."""
357
358
mutter('storing file {%s} in revision {%s}',
358
359
self.file_id, self.revision)
359
self._add_text_to_weave([], file_parents, weave_store, transaction)
360
self._add_text_to_weave([], file_parents.keys(), weave_store, transaction)
361
362
def __eq__(self, other):
362
363
if not isinstance(other, InventoryEntry):
405
406
# first requested, or preload them if they're already known
406
407
pass # nothing to do by default
409
def _forget_tree_state(self):
409
413
class RootEntry(InventoryEntry):
481
485
checker.repeated_text_cnt += 1
488
if self.file_id not in checker.checked_weaves:
489
mutter('check weave {%s}', self.file_id)
490
w = tree.get_weave(self.file_id)
491
# Not passing a progress bar, because it creates a new
492
# progress, which overwrites the current progress,
493
# and doesn't look nice
495
checker.checked_weaves[self.file_id] = True
497
w = tree.get_weave(self.file_id)
483
499
mutter('check version {%s} of {%s}', rev_id, self.file_id)
484
file_lines = tree.get_file_lines(self.file_id)
485
500
checker.checked_text_cnt += 1
486
if self.text_size != sum(map(len, file_lines)):
487
raise BzrCheckError('text {%s} wrong size' % self.text_id)
488
if self.text_sha1 != sha_strings(file_lines):
489
raise BzrCheckError('text {%s} wrong sha1' % self.text_id)
501
# We can't check the length, because Weave doesn't store that
502
# information, and the whole point of looking at the weave's
503
# sha1sum is that we don't have to extract the text.
504
if self.text_sha1 != w.get_sha1(self.revision):
505
raise BzrCheckError('text {%s} version {%s} wrong sha1'
506
% (self.file_id, self.revision))
490
507
checker.checked_texts[t] = self.text_sha1
555
572
self.text_sha1 = work_tree.get_file_sha1(self.file_id)
556
573
self.executable = work_tree.is_executable(self.file_id)
575
def _forget_tree_state(self):
576
self.text_sha1 = None
577
self.executable = None
558
579
def _snapshot_text(self, file_parents, work_tree, weave_store, transaction):
559
580
"""See InventoryEntry._snapshot_text."""
560
581
mutter('storing file {%s} in revision {%s}',
565
586
and self.text_sha1 == file_parents.values()[0].text_sha1
566
587
and self.text_size == file_parents.values()[0].text_size):
567
588
previous_ie = file_parents.values()[0]
568
weave_store.add_identical_text(
569
self.file_id, previous_ie.revision,
570
self.revision, file_parents, transaction)
589
versionedfile = weave_store.get_weave(self.file_id, transaction)
590
versionedfile.clone_text(self.revision, previous_ie.revision, file_parents.keys())
572
592
new_lines = work_tree.get_file(self.file_id).readlines()
573
self._add_text_to_weave(new_lines, file_parents, weave_store,
593
self._add_text_to_weave(new_lines, file_parents.keys(), weave_store,
575
595
self.text_sha1 = sha_strings(new_lines)
576
596
self.text_size = sum(map(len, new_lines))
647
667
def _put_in_tar(self, item, tree):
648
668
"""See InventoryEntry._put_in_tar."""
649
iterm.type = tarfile.SYMTYPE
669
item.type = tarfile.SYMTYPE
664
684
"""See InventoryEntry._read_tree_state."""
665
685
self.symlink_target = work_tree.get_symlink_target(self.file_id)
687
def _forget_tree_state(self):
688
self.symlink_target = None
667
690
def _unchanged(self, previous_ie):
668
691
"""See InventoryEntry._unchanged."""
669
692
compatible = super(InventoryLink, self)._unchanged(previous_ie)
720
743
The inventory is created with a default root directory, with
723
# We are letting Branch.initialize() create a unique inventory
746
# We are letting Branch.create() create a unique inventory
724
747
# root id. Rather than generating a random one here.
725
748
#if root_id is None:
726
749
# root_id = bzrlib.branch.gen_file_id('TREE_ROOT')
763
786
if ie.kind == 'directory':
764
787
for cn, cie in self.iter_entries(from_dir=ie.file_id):
765
yield os.path.join(name, cn), cie
788
yield pathjoin(name, cn), cie
768
791
def entries(self):
775
798
kids = dir_ie.children.items()
777
800
for name, ie in kids:
778
child_path = os.path.join(dir_path, name)
801
child_path = pathjoin(dir_path, name)
779
802
accum.append((child_path, ie))
780
803
if ie.kind == 'directory':
781
804
descend(ie, child_path)
783
descend(self.root, '')
806
descend(self.root, u'')
797
820
for name, child_ie in kids:
798
child_path = os.path.join(parent_path, name)
821
child_path = pathjoin(parent_path, name)
799
822
descend(child_ie, child_path)
800
descend(self.root, '')
823
descend(self.root, u'')
863
886
if parent.children.has_key(entry.name):
864
887
raise BzrError("%s is already versioned" %
865
appendpath(self.id2path(parent.file_id), entry.name))
888
pathjoin(self.id2path(parent.file_id), entry.name))
867
890
self._byid[entry.file_id] = entry
868
891
parent.children[entry.name] = entry
875
898
The immediate parent must already be versioned.
877
900
Returns the new entry object."""
878
from bzrlib.branch import gen_file_id
901
from bzrlib.workingtree import gen_file_id
880
903
parts = bzrlib.osutils.splitpath(relpath)
882
raise BzrError("cannot re-add root of inventory")
884
905
if file_id == None:
885
906
file_id = gen_file_id(relpath)
887
parent_path = parts[:-1]
888
parent_id = self.path2id(parent_path)
889
if parent_id == None:
890
raise NotVersionedError(path=parent_path)
909
self.root = RootEntry(file_id)
910
self._byid = {self.root.file_id: self.root}
913
parent_path = parts[:-1]
914
parent_id = self.path2id(parent_path)
915
if parent_id == None:
916
raise NotVersionedError(path=parent_path)
891
917
if kind == 'directory':
892
918
ie = InventoryDirectory(file_id, parts[-1], parent_id)
893
919
elif kind == 'file':
914
940
ie = self[file_id]
916
assert self[ie.parent_id].children[ie.name] == ie
942
assert ie.parent_id is None or \
943
self[ie.parent_id].children[ie.name] == ie
918
# TODO: Test deleting all children; maybe hoist to a separate
920
if ie.kind == 'directory':
921
for cie in ie.children.values():
922
del self[cie.file_id]
925
945
del self._byid[file_id]
926
del self[ie.parent_id].children[ie.name]
946
if ie.parent_id is not None:
947
del self[ie.parent_id].children[ie.name]
929
950
def __eq__(self, other):
985
1006
>>> i = Inventory()
986
1007
>>> e = i.add(InventoryDirectory('src-id', 'src', ROOT_ID))
987
1008
>>> e = i.add(InventoryFile('foo-id', 'foo.c', parent_id='src-id'))
988
>>> print i.id2path('foo-id').replace(os.sep, '/')
1009
>>> print i.id2path('foo-id')
991
1012
# get all names, skipping root
992
1013
p = [self._byid[fid].name for fid in self.get_idpath(file_id)[1:]]
993
return os.sep.join(p)