15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
# TODO: Maybe also keep the full path of the entry, and the children?
19
# But those depend on its position within a particular inventory, and
20
# it would be nice not to need to hold the backpointer here.
22
# TODO: Perhaps split InventoryEntry into subclasses for files,
23
# directories, etc etc.
18
26
# This should really be an id randomly assigned when the tree is
19
27
# created, but it's not for now.
20
28
ROOT_ID = "TREE_ROOT"
29
37
from bzrlib.errors import BzrError, BzrCheckError
31
from bzrlib.osutils import quotefn, splitpath, joinpath, appendpath
39
from bzrlib.osutils import quotefn, splitpath, joinpath, appendpath, sha_strings
32
40
from bzrlib.trace import mutter
33
41
from bzrlib.errors import NotVersionedError
39
47
An InventoryEntry has the following fields, which are also
40
48
present in the XML inventory-entry element:
43
* *name*: (only the basename within the directory, must not
45
* *kind*: "directory" or "file"
46
* *directory_id*: (if absent/null means the branch root directory)
47
* *text_sha1*: only for files
48
* *text_size*: in bytes, only for files
49
* *text_id*: identifier for the text version, only for files
51
InventoryEntries can also exist inside a WorkingTree
52
inventory, in which case they are not yet bound to a
53
particular revision of the file. In that case the text_sha1,
54
text_size and text_id are absent.
53
(within the parent directory)
59
file_id of the parent directory, or ROOT_ID
62
the revision_id in which the name or parent of this file was
66
sha-1 of the text of the file
69
size in bytes of the text of the file
72
the revision_id in which the text of this file was introduced
74
(reading a version 4 tree created a text_id field.)
57
76
>>> i = Inventory()
93
112
src/wibble/wibble.c
94
113
>>> i.id2path('2326').replace('\\\\', '/')
95
114
'src/wibble/wibble.c'
97
TODO: Maybe also keep the full path of the entry, and the children?
98
But those depend on its position within a particular inventory, and
99
it would be nice not to need to hold the backpointer here.
102
# TODO: split InventoryEntry into subclasses for files,
103
# directories, etc etc.
105
117
__slots__ = ['text_sha1', 'text_size', 'file_id', 'name', 'kind',
106
118
'text_id', 'parent_id', 'children',
107
'text_version', 'entry_version', 'symlink_target']
119
'text_version', 'name_version', 'symlink_target']
121
def compatible_for_commit(self, previous_ie):
123
# different inv parent
124
if previous_ie.parent_id != self.parent_id:
127
elif previous_ie.name != self.name:
129
# changed link target
130
elif (hasattr(self,'symlink_target')
131
and self.symlink_target != previous_ie.symlink_target):
109
135
def __init__(self, file_id, name, kind, parent_id, text_id=None):
110
136
"""Create an InventoryEntry
185
def check(self, checker, rev_id, inv, tree):
186
if self.parent_id != None:
187
if not inv.has_id(self.parent_id):
188
raise BzrCheckError('missing parent {%s} in inventory for revision {%s}'
189
% (self.parent_id, rev_id))
190
if self.kind == 'file':
191
text_version = self.text_version
192
t = (self.file_id, text_version)
193
if t in checker.checked_texts:
194
prev_sha = checker.checked_texts[t]
195
if prev_sha != self.text_sha1:
196
raise BzrCheckError('mismatched sha1 on {%s} in {%s}' %
197
(self.file_id, rev_id))
199
checker.repeated_text_cnt += 1
201
mutter('check version {%s} of {%s}', rev_id, self.file_id)
202
file_lines = tree.get_file_lines(self.file_id)
203
checker.checked_text_cnt += 1
204
if self.text_size != sum(map(len, file_lines)):
205
raise BzrCheckError('text {%s} wrong size' % self.text_id)
206
if self.text_sha1 != sha_strings(file_lines):
207
raise BzrCheckError('text {%s} wrong sha1' % self.text_id)
208
checker.checked_texts[t] = self.text_sha1
209
elif self.kind == 'directory':
210
if self.text_sha1 != None or self.text_size != None or self.text_id != None:
211
raise BzrCheckError('directory {%s} has text in revision {%s}'
212
% (self.file_id, rev_id))
213
elif self.kind == 'root_directory':
215
elif self.kind == 'symlink':
216
if self.text_sha1 != None or self.text_size != None or self.text_id != None:
217
raise BzrCheckError('symlink {%s} has text in revision {%s}'
218
% (self.file_id, rev_id))
219
if self.symlink_target == None:
220
raise BzrCheckError('symlink {%s} has no target in revision {%s}'
221
% (self.file_id, rev_id))
223
raise BzrCheckError('unknown entry kind %r in revision {%s}' %
161
228
other = InventoryEntry(self.file_id, self.name, self.kind,
162
self.parent_id, text_id=self.text_id)
230
other.text_id = self.text_id
163
231
other.text_sha1 = self.text_sha1
164
232
other.text_size = self.text_size
165
233
other.symlink_target = self.symlink_target
234
other.text_version = self.text_version
235
other.name_version = self.name_version
166
236
# note that children are *not* copied; they're pulled across when
167
237
# others are added