15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
## XXX: Everything up to here can simply be orphaned if we abort
19
## the commit; it will leave junk files behind but that doesn't
18
## XXX: Can we do any better about making interrupted commits change
21
## XXX: If we merged two versions of a file then we still need to
22
## create a new version representing that merge, even if it didn't
23
## change from the parent.
22
25
## TODO: Read back the just-generated changeset, and make sure it
23
26
## applies and recreates the right state.
30
37
from binascii import hexlify
38
from cStringIO import StringIO
32
40
from bzrlib.osutils import (local_time_offset, username,
33
41
rand_bytes, compact_date, user_email,
185
195
self.delta.show(sys.stdout)
187
197
self._remove_deleted()
190
200
self.branch._write_inventory(self.work_inv)
191
201
self._record_inventory()
193
203
self._make_revision()
194
note('committted r%d', (self.branch.revno() + 1))
195
self.branch.append_revision(rev_id)
204
note('committted r%d {%s}', (self.branch.revno() + 1),
206
self.branch.append_revision(self.rev_id)
196
207
self.branch.set_pending_merges([])
198
209
self.branch.unlock()
201
212
def _record_inventory(self):
202
inv_tmp = tempfile.TemporaryFile()
203
214
serializer_v5.write_inventory(self.new_inv, inv_tmp)
205
self.inv_sha1 = sha_file(inv_tmp)
215
self.inv_sha1 = sha_string(inv_tmp.getvalue())
207
217
self.branch.inventory_store.add(inv_tmp, self.rev_id)
239
249
del self.new_inv[id]
242
def _store_texts(self):
253
def _store_files(self):
243
254
"""Store new texts of modified/added files."""
244
255
for path, id, kind in self.delta.modified:
245
256
if kind != 'file':
247
self._store_file_text(path, id)
258
self._store_file_text(id)
249
260
for path, id, kind in self.delta.added:
250
261
if kind != 'file':
252
self._store_file_text(path, id)
263
self._store_file_text(id)
254
265
for old_path, new_path, id, kind, text_modified in self.delta.renamed:
255
266
if kind != 'file':
257
268
if not text_modified:
259
self._store_file_text(path, id)
262
def _store_file_text(self, path, id):
270
self._store_file_text(id)
273
def _store_file_text(self, file_id):
263
274
"""Store updated text for one modified or added file."""
264
# TODO: Add or update the inventory entry for this file;
265
# put in the new text version
266
275
note('store new text for {%s} in revision {%s}', id, self.rev_id)
267
new_lines = self.work_tree.get_file(id).readlines()
268
weave_fn = self.branch.controlfilename(['weaves', id+'.weave'])
276
new_lines = self.work_tree.get_file(file_id).readlines()
277
self._add_text_to_weave(file_id, new_lines)
278
# update or add an entry
279
if file_id in self.new_inv:
280
ie = self.new_inv[file_id]
281
assert ie.file_id == file_id
283
ie = self.work_inv[file_id].copy()
285
assert ie.kind == 'file'
286
# make a new inventory entry for this file, using whatever
287
# it had in the working copy, plus details on the new text
288
ie.text_sha1 = _sha_strings(new_lines)
289
ie.text_size = sum(map(len, new_lines))
290
ie.text_version = self.rev_id
291
ie.entry_version = self.rev_id
294
def _add_text_to_weave(self, file_id, new_lines):
295
weave_fn = self.branch.controlfilename(['weaves', file_id+'.weave'])
269
296
if os.path.exists(weave_fn):
270
297
w = read_weave(file(weave_fn, 'rb'))
300
# XXX: Should set the appropriate parents by looking for this file_id
301
# in all revision parents
273
302
w.add(self.rev_id, [], new_lines)
274
303
af = AtomicFile(weave_fn)
283
"""Build inventory preparatory to commit.
285
This adds any changed files into the text store, and sets their
286
test-id, sha and size in the returned inventory appropriately.
289
self.any_changes = False
290
self.new_inv = Inventory(self.work_inv.root.file_id)
291
self.missing_ids = []
293
for path, entry in self.work_inv.iter_entries():
294
## TODO: Check that the file kind has not changed from the previous
295
## revision of this file (if any).
297
p = self.branch.abspath(path)
298
file_id = entry.file_id
299
mutter('commit prep file %s, id %r ' % (p, file_id))
301
if (self.specific_files
302
and not is_inside_any(self.specific_files, path)):
303
mutter(' skipping file excluded from commit')
304
if self.basis_inv.has_id(file_id):
305
# carry over with previous state
306
self.new_inv.add(self.basis_inv[file_id].copy())
308
# omit this from committed inventory
312
if not self.work_tree.has_id(file_id):
313
mutter(" file is missing, removing from inventory")
314
self.missing_ids.append(file_id)
317
# this is present in the new inventory; may be new, modified or
319
old_ie = self.basis_inv.has_id(file_id) and self.basis_inv[file_id]
322
self.new_inv.add(entry)
325
old_kind = old_ie.kind
326
if old_kind != entry.kind:
327
raise BzrError("entry %r changed kind from %r to %r"
328
% (file_id, old_kind, entry.kind))
330
if entry.kind == 'directory':
332
raise BzrError("%s is entered as directory but not a directory"
334
elif entry.kind == 'file':
336
raise BzrError("%s is entered as file but is not a file" % quotefn(p))
338
new_sha1 = self.work_tree.get_file_sha1(file_id)
341
and old_ie.text_sha1 == new_sha1):
342
## assert content == basis.get_file(file_id).read()
343
entry.text_id = old_ie.text_id
344
entry.text_sha1 = new_sha1
345
entry.text_size = old_ie.text_size
346
mutter(' unchanged from previous text_id {%s}' %
349
content = file(p, 'rb').read()
351
# calculate the sha again, just in case the file contents
352
# changed since we updated the cache
353
entry.text_sha1 = sha_string(content)
354
entry.text_size = len(content)
356
entry.text_id = gen_file_id(entry.name)
357
self.branch.text_store.add(content, entry.text_id)
358
mutter(' stored with text_id {%s}' % entry.text_id)
360
marked = path + kind_marker(entry.kind)
362
self.reporter.added(marked)
363
self.any_changes = True
364
elif old_ie == entry:
366
elif (old_ie.name == entry.name
367
and old_ie.parent_id == entry.parent_id):
368
self.reporter.modified(marked)
369
self.any_changes = True
371
old_path = old_inv.id2path(file_id) + kind_marker(entry.kind)
372
self.reporter.renamed(old_path, marked)
373
self.any_changes = True
377
311
def _gen_revision_id(branch, when):
378
312
"""Return new revision-id."""
379
313
s = '%s-%s-' % (user_email(branch), compact_date(when))