117
118
__slots__ = ['text_sha1', 'text_size', 'file_id', 'name', 'kind',
118
'text_id', 'parent_id', 'children',
119
'text_version', 'name_version', ]
119
'text_id', 'parent_id', 'children', 'executable',
120
'revision', 'symlink_target']
122
def _add_text_to_weave(self, new_lines, parents, weave_store):
123
weave_store.add_text(self.file_id, self.revision, new_lines, parents)
122
125
def __init__(self, file_id, name, kind, parent_id, text_id=None):
123
126
"""Create an InventoryEntry
148
151
self.text_id = text_id
149
152
self.parent_id = parent_id
153
self.symlink_target = None
150
154
if kind == 'directory':
151
155
self.children = {}
152
156
elif kind == 'file':
158
elif kind == 'symlink':
155
161
raise BzrError("unhandled entry kind %r" % kind)
163
def read_symlink_target(self, path):
164
if self.kind == 'symlink':
166
self.symlink_target = os.readlink(path)
168
raise BzrError("os.readlink error, %s" % e)
159
170
def sorted_children(self):
160
171
l = self.children.items()
175
def check(self, checker, rev_id, inv, tree):
176
if self.parent_id != None:
177
if not inv.has_id(self.parent_id):
178
raise BzrCheckError('missing parent {%s} in inventory for revision {%s}'
179
% (self.parent_id, rev_id))
180
if self.kind == 'file':
181
revision = self.revision
182
t = (self.file_id, revision)
183
if t in checker.checked_texts:
184
prev_sha = checker.checked_texts[t]
185
if prev_sha != self.text_sha1:
186
raise BzrCheckError('mismatched sha1 on {%s} in {%s}' %
187
(self.file_id, rev_id))
189
checker.repeated_text_cnt += 1
191
mutter('check version {%s} of {%s}', rev_id, self.file_id)
192
file_lines = tree.get_file_lines(self.file_id)
193
checker.checked_text_cnt += 1
194
if self.text_size != sum(map(len, file_lines)):
195
raise BzrCheckError('text {%s} wrong size' % self.text_id)
196
if self.text_sha1 != sha_strings(file_lines):
197
raise BzrCheckError('text {%s} wrong sha1' % self.text_id)
198
checker.checked_texts[t] = self.text_sha1
199
elif self.kind == 'directory':
200
if self.text_sha1 != None or self.text_size != None or self.text_id != None:
201
raise BzrCheckError('directory {%s} has text in revision {%s}'
202
% (self.file_id, rev_id))
203
elif self.kind == 'root_directory':
205
elif self.kind == 'symlink':
206
if self.text_sha1 != None or self.text_size != None or self.text_id != None:
207
raise BzrCheckError('symlink {%s} has text in revision {%s}'
208
% (self.file_id, rev_id))
209
if self.symlink_target == None:
210
raise BzrCheckError('symlink {%s} has no target in revision {%s}'
211
% (self.file_id, rev_id))
213
raise BzrCheckError('unknown entry kind %r in revision {%s}' %
166
218
other = InventoryEntry(self.file_id, self.name, self.kind,
220
other.executable = self.executable
168
221
other.text_id = self.text_id
169
222
other.text_sha1 = self.text_sha1
170
223
other.text_size = self.text_size
171
other.text_version = self.text_version
172
other.name_version = self.name_version
224
other.symlink_target = self.symlink_target
225
other.revision = self.revision
173
226
# note that children are *not* copied; they're pulled across when
174
227
# others are added
230
def _get_snapshot_change(self, previous_entries):
231
if len(previous_entries) > 1:
233
elif len(previous_entries) == 0:
236
return 'modified/renamed/reparented'
178
238
def __repr__(self):
179
239
return ("%s(%r, %r, kind=%r, parent_id=%r)"
246
def snapshot(self, revision, path, previous_entries, work_tree,
248
"""Make a snapshot of this entry.
250
This means that all its fields are populated, that it has its
251
text stored in the text store or weave.
253
mutter('new parents of %s are %r', path, previous_entries)
254
self._read_tree_state(path, work_tree)
255
if len(previous_entries) == 1:
256
# cannot be unchanged unless there is only one parent file rev.
257
parent_ie = previous_entries.values()[0]
258
if self._unchanged(path, parent_ie, work_tree):
259
mutter("found unchanged entry")
260
self.revision = parent_ie.revision
262
mutter('new revision for {%s}', self.file_id)
263
self.revision = revision
264
change = self._get_snapshot_change(previous_entries)
265
if self.kind != 'file':
267
self._snapshot_text(previous_entries, work_tree, weave_store)
270
def _snapshot_text(self, file_parents, work_tree, weave_store):
271
mutter('storing file {%s} in revision {%s}',
272
self.file_id, self.revision)
273
# special case to avoid diffing on renames or
275
if (len(file_parents) == 1
276
and self.text_sha1 == file_parents.values()[0].text_sha1
277
and self.text_size == file_parents.values()[0].text_size):
278
previous_ie = file_parents.values()[0]
279
weave_store.add_identical_text(
280
self.file_id, previous_ie.revision,
281
self.revision, file_parents)
283
new_lines = work_tree.get_file(self.file_id).readlines()
284
self._add_text_to_weave(new_lines, file_parents, weave_store)
285
self.text_sha1 = sha_strings(new_lines)
286
self.text_size = sum(map(len, new_lines))
187
288
def __eq__(self, other):
188
289
if not isinstance(other, InventoryEntry):
189
290
return NotImplemented
191
return (self.file_id == other.file_id) \
192
and (self.name == other.name) \
193
and (self.text_sha1 == other.text_sha1) \
194
and (self.text_size == other.text_size) \
195
and (self.text_id == other.text_id) \
196
and (self.parent_id == other.parent_id) \
197
and (self.kind == other.kind) \
198
and (self.text_version == other.text_version) \
199
and (self.name_version == other.name_version)
292
return ((self.file_id == other.file_id)
293
and (self.name == other.name)
294
and (other.symlink_target == self.symlink_target)
295
and (self.text_sha1 == other.text_sha1)
296
and (self.text_size == other.text_size)
297
and (self.text_id == other.text_id)
298
and (self.parent_id == other.parent_id)
299
and (self.kind == other.kind)
300
and (self.revision == other.revision)
301
and (self.executable == other.executable)
202
304
def __ne__(self, other):
203
305
return not (self == other)
205
307
def __hash__(self):
206
308
raise ValueError('not hashable')
310
def _unchanged(self, path, previous_ie, work_tree):
312
# different inv parent
313
if previous_ie.parent_id != self.parent_id:
316
elif previous_ie.name != self.name:
318
if self.kind == 'symlink':
319
if self.symlink_target != previous_ie.symlink_target:
321
if self.kind == 'file':
322
if self.text_sha1 != previous_ie.text_sha1:
325
# FIXME: 20050930 probe for the text size when getting sha1
326
# in _read_tree_state
327
self.text_size = previous_ie.text_size
330
def _read_tree_state(self, path, work_tree):
331
if self.kind == 'symlink':
332
self.read_symlink_target(work_tree.abspath(path))
333
if self.kind == 'file':
334
self.text_sha1 = work_tree.get_file_sha1(self.file_id)
335
self.executable = work_tree.is_executable(self.file_id)
210
338
class RootEntry(InventoryEntry):