/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/commit.py

  • Committer: Martin Pool
  • Date: 2005-09-07 09:19:10 UTC
  • Revision ID: mbp@sourcefrog.net-20050907091910-a9bac45116ba594c
- [BROKEN] more progress of commit into weaves

 - store all modified texts into weaves

 - delete dead commit code

 - update committed inventories to point to weaves

Show diffs side-by-side

added added

removed removed

Lines of Context:
15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
16
 
17
17
 
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
20
 
## matter.
 
18
## XXX: Can we do any better about making interrupted commits change
 
19
## nothing?
 
20
 
 
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.
21
24
 
22
25
## TODO: Read back the just-generated changeset, and make sure it
23
26
## applies and recreates the right state.
24
27
 
25
28
 
 
29
 
 
30
 
26
31
import os
27
32
import sys
28
33
import time
29
34
import tempfile
 
35
import sha
 
36
 
30
37
from binascii import hexlify
 
38
from cStringIO import StringIO
31
39
 
32
40
from bzrlib.osutils import (local_time_offset, username,
33
41
                            rand_bytes, compact_date, user_email,
133
141
        self.branch.lock_write()
134
142
        self.rev_id = rev_id
135
143
        self.specific_files = specific_files
 
144
        self.allow_pointless = allow_pointless
136
145
 
137
146
        if timestamp is None:
138
147
            self.timestamp = time.time()
172
181
            if self.rev_id is None:
173
182
                self.rev_id = _gen_revision_id(self.branch, time.time())
174
183
 
 
184
            # todo: update hashcache
175
185
            self.delta = compare_trees(self.basis_tree, self.work_tree,
176
186
                                       specific_files=self.specific_files)
177
187
 
185
195
            self.delta.show(sys.stdout)
186
196
 
187
197
            self._remove_deleted()
188
 
            self._store_texts()
 
198
            self._store_files()
189
199
 
190
200
            self.branch._write_inventory(self.work_inv)
191
201
            self._record_inventory()
192
202
 
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),
 
205
                 self.rev_id)
 
206
            self.branch.append_revision(self.rev_id)
196
207
            self.branch.set_pending_merges([])
197
208
        finally:
198
209
            self.branch.unlock()
199
210
 
200
211
 
201
212
    def _record_inventory(self):
202
 
        inv_tmp = tempfile.TemporaryFile()
 
213
        inv_tmp = StringIO()
203
214
        serializer_v5.write_inventory(self.new_inv, inv_tmp)
204
 
        inv_tmp.seek(0)
205
 
        self.inv_sha1 = sha_file(inv_tmp)
 
215
        self.inv_sha1 = sha_string(inv_tmp.getvalue())
206
216
        inv_tmp.seek(0)
207
217
        self.branch.inventory_store.add(inv_tmp, self.rev_id)
208
218
 
239
249
                del self.new_inv[id]
240
250
 
241
251
 
242
 
    def _store_texts(self):
 
252
 
 
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':
246
257
                continue
247
 
            self._store_file_text(path, id)
 
258
            self._store_file_text(id)
248
259
 
249
260
        for path, id, kind in self.delta.added:
250
261
            if kind != 'file':
251
262
                continue
252
 
            self._store_file_text(path, id)
 
263
            self._store_file_text(id)
253
264
 
254
265
        for old_path, new_path, id, kind, text_modified in self.delta.renamed:
255
266
            if kind != 'file':
256
267
                continue
257
268
            if not text_modified:
258
269
                continue
259
 
            self._store_file_text(path, id)
260
 
 
261
 
 
262
 
    def _store_file_text(self, path, id):
 
270
            self._store_file_text(id)
 
271
 
 
272
 
 
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
 
282
        else:
 
283
            ie = self.work_inv[file_id].copy()
 
284
            self.new_inv.add(ie)
 
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
 
292
 
 
293
 
 
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'))
271
298
        else:
272
299
            w = Weave()
 
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)
275
304
        try:
279
308
            af.close()
280
309
 
281
310
 
282
 
    def _gather(self):
283
 
        """Build inventory preparatory to commit.
284
 
 
285
 
        This adds any changed files into the text store, and sets their
286
 
        test-id, sha and size in the returned inventory appropriately.
287
 
 
288
 
        """
289
 
        self.any_changes = False
290
 
        self.new_inv = Inventory(self.work_inv.root.file_id)
291
 
        self.missing_ids = []
292
 
 
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).
296
 
 
297
 
            p = self.branch.abspath(path)
298
 
            file_id = entry.file_id
299
 
            mutter('commit prep file %s, id %r ' % (p, file_id))
300
 
 
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())
307
 
                else:
308
 
                    # omit this from committed inventory
309
 
                    pass
310
 
                continue
311
 
 
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)
315
 
                continue
316
 
 
317
 
            # this is present in the new inventory; may be new, modified or
318
 
            # unchanged.
319
 
            old_ie = self.basis_inv.has_id(file_id) and self.basis_inv[file_id]
320
 
 
321
 
            entry = entry.copy()
322
 
            self.new_inv.add(entry)
323
 
 
324
 
            if old_ie:
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))
329
 
 
330
 
            if entry.kind == 'directory':
331
 
                if not isdir(p):
332
 
                    raise BzrError("%s is entered as directory but not a directory"
333
 
                                   % quotefn(p))
334
 
            elif entry.kind == 'file':
335
 
                if not isfile(p):
336
 
                    raise BzrError("%s is entered as file but is not a file" % quotefn(p))
337
 
 
338
 
                new_sha1 = self.work_tree.get_file_sha1(file_id)
339
 
 
340
 
                if (old_ie
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}' %
347
 
                           entry.text_id)
348
 
                else:
349
 
                    content = file(p, 'rb').read()
350
 
 
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)
355
 
 
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)
359
 
 
360
 
            marked = path + kind_marker(entry.kind)
361
 
            if not old_ie:
362
 
                self.reporter.added(marked)
363
 
                self.any_changes = True
364
 
            elif old_ie == entry:
365
 
                pass                    # unchanged
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
370
 
            else:
371
 
                old_path = old_inv.id2path(file_id) + kind_marker(entry.kind)
372
 
                self.reporter.renamed(old_path, marked)
373
 
                self.any_changes = True
374
 
 
375
 
 
376
 
 
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))
381
315
    return s
382
316
 
383
317
 
 
318
def _sha_strings(strings):
 
319
    """Return the sha-1 of concatenation of strings"""
 
320
    s = sha.new()
 
321
    map(s.update, strings)
 
322
    return s.hexdigest()