/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/repository.py

  • Committer: Robert Collins
  • Date: 2007-10-03 06:15:06 UTC
  • mfrom: (2879 +trunk)
  • mto: (2592.3.161 repository)
  • mto: This revision was merged to the branch mainline in revision 2880.
  • Revision ID: robertc@robertcollins.net-20071003061506-2hbze42e1sokni8j
Merge bzr.dev.

Show diffs side-by-side

added added

removed removed

Lines of Context:
199
199
        # _new_revision_id
200
200
        ie.revision = self._new_revision_id
201
201
 
202
 
    def record_entry_contents(self, ie, parent_invs, path, tree):
 
202
    def _get_delta(self, ie, basis_inv, path):
 
203
        """Get a delta against the basis inventory for ie."""
 
204
        if ie.file_id not in basis_inv:
 
205
            # add
 
206
            return (None, path, ie.file_id, ie)
 
207
        elif ie != basis_inv[ie.file_id]:
 
208
            # common but altered
 
209
            # TODO: avoid tis id2path call.
 
210
            return (basis_inv.id2path(ie.file_id), path, ie.file_id, ie)
 
211
        else:
 
212
            # common, unaltered
 
213
            return None
 
214
 
 
215
    def record_entry_contents(self, ie, parent_invs, path, tree,
 
216
        content_summary):
203
217
        """Record the content of ie from tree into the commit if needed.
204
218
 
205
219
        Side effect: sets ie.revision when unchanged
209
223
            commit.
210
224
        :param path: The path the entry is at in the tree.
211
225
        :param tree: The tree which contains this entry and should be used to 
212
 
        obtain content.
 
226
            obtain content.
 
227
        :param content_summary: Summary data from the tree about the paths
 
228
            content - stat, length, exec, sha/link target. This is only
 
229
            accessed when the entry has a revision of None - that is when it is
 
230
            a candidate to commit.
213
231
        :return: A tuple (change_delta, version_recorded). change_delta is 
214
232
            an inventory_delta change for this entry against the basis tree of
215
233
            the commit, or None if no change occured against the basis tree.
221
239
            if ie.parent_id is not None:
222
240
                raise errors.RootMissing()
223
241
            self._check_root(ie, parent_invs, tree)
 
242
        if ie.revision is None:
 
243
            kind = content_summary[0]
 
244
        else:
 
245
            # ie is carried over from a prior commit
 
246
            kind = ie.kind
 
247
        # XXX: repository specific check for nested tree support goes here - if
 
248
        # the repo doesn't want nested trees we skip it ?
 
249
        if (kind == 'tree-reference' and
 
250
            not self.repository._format.supports_tree_reference):
 
251
            # mismatch between commit builder logic and repository:
 
252
            # this needs the entry creation pushed down into the builder.
 
253
            raise NotImplementedError('Missing repository subtree support.')
 
254
        # transitional assert only, will remove before release.
 
255
        assert ie.kind == kind
224
256
        self.new_inventory.add(ie)
225
257
 
226
258
        # TODO: slow, take it out of the inner loop.
230
262
            basis_inv = Inventory(root_id=None)
231
263
 
232
264
        # ie.revision is always None if the InventoryEntry is considered
233
 
        # for committing. ie.snapshot will record the correct revision 
234
 
        # which may be the sole parent if it is untouched.
 
265
        # for committing. We may record the previous parents revision if the
 
266
        # content is actually unchanged against a sole head.
235
267
        if ie.revision is not None:
236
268
            if self._versioned_root or path != '':
237
269
                # not considered for commit
257
289
            return delta, ie.revision == self._new_revision_id and (path != '' or
258
290
                self._versioned_root)
259
291
 
 
292
        # XXX: Friction: parent_candidates should return a list not a dict
 
293
        #      so that we don't have to walk the inventories again.
260
294
        parent_candiate_entries = ie.parent_candidates(parent_invs)
261
 
        heads = self.repository.get_graph().heads(parent_candiate_entries.keys())
262
 
        # XXX: Note that this is unordered - and this is tolerable because 
263
 
        # the previous code was also unordered.
264
 
        previous_entries = dict((head, parent_candiate_entries[head]) for head
265
 
            in heads)
266
 
        # we are creating a new revision for ie in the history store and
267
 
        # inventory.
268
 
        ie.snapshot(self._new_revision_id, path, previous_entries, tree, self)
269
 
        if ie.file_id not in basis_inv:
270
 
            # add
271
 
            delta = (None, path, ie.file_id, ie)
272
 
        elif ie != basis_inv[ie.file_id]:
273
 
            # common but altered
274
 
            delta = (basis_inv.id2path(ie.file_id), path, ie.file_id,
275
 
                ie)
276
 
        else:
277
 
            # common, unaltered
278
 
            delta = None
279
 
        return delta, ie.revision == self._new_revision_id and (path != '' or
280
 
            self._versioned_root)
281
 
 
282
 
    def modified_directory(self, file_id, file_parents):
283
 
        """Record the presence of a symbolic link.
284
 
 
285
 
        :param file_id: The file_id of the link to record.
286
 
        :param file_parents: The per-file parent revision ids.
287
 
        """
288
 
        self._add_text_to_weave(file_id, [], file_parents.keys())
289
 
 
290
 
    def modified_reference(self, file_id, file_parents):
291
 
        """Record the modification of a reference.
292
 
 
293
 
        :param file_id: The file_id of the link to record.
294
 
        :param file_parents: The per-file parent revision ids.
295
 
        """
296
 
        self._add_text_to_weave(file_id, [], file_parents.keys())
297
 
    
298
 
    def modified_file_text(self, file_id, file_parents,
299
 
                           get_content_byte_lines, text_sha1=None,
300
 
                           text_size=None):
301
 
        """Record the text of file file_id
302
 
 
303
 
        :param file_id: The file_id of the file to record the text of.
304
 
        :param file_parents: The per-file parent revision ids.
305
 
        :param get_content_byte_lines: A callable which will return the byte
306
 
            lines for the file.
307
 
        :param text_sha1: Optional SHA1 of the file contents.
308
 
        :param text_size: Optional size of the file contents.
309
 
        """
310
 
        # mutter('storing text of file {%s} in revision {%s} into %r',
311
 
        #        file_id, self._new_revision_id, self.repository.weave_store)
312
 
        # special case to avoid diffing on renames or 
313
 
        # reparenting
314
 
        if (len(file_parents) == 1
315
 
            and text_sha1 == file_parents.values()[0].text_sha1
316
 
            and text_size == file_parents.values()[0].text_size):
317
 
            previous_ie = file_parents.values()[0]
318
 
            versionedfile = self.repository.weave_store.get_weave(file_id,
319
 
                self.repository.get_transaction())
320
 
            versionedfile.clone_text(self._new_revision_id,
321
 
                previous_ie.revision, file_parents.keys())
322
 
            return text_sha1, text_size
323
 
        else:
324
 
            new_lines = get_content_byte_lines()
325
 
            return self._add_text_to_weave(file_id, new_lines,
326
 
                file_parents.keys())
327
 
 
328
 
    def modified_link(self, file_id, file_parents, link_target):
329
 
        """Record the presence of a symbolic link.
330
 
 
331
 
        :param file_id: The file_id of the link to record.
332
 
        :param file_parents: The per-file parent revision ids.
333
 
        :param link_target: Target location of this link.
334
 
        """
335
 
        self._add_text_to_weave(file_id, [], file_parents.keys())
336
 
 
337
 
    def _add_text_to_weave(self, file_id, new_lines, parents):
 
295
        head_set = self.repository.get_graph().heads(parent_candiate_entries.keys())
 
296
        heads = []
 
297
        for inv in parent_invs:
 
298
            if ie.file_id in inv:
 
299
                old_rev = inv[ie.file_id].revision
 
300
                if old_rev in head_set:
 
301
                    heads.append(inv[ie.file_id].revision)
 
302
                    head_set.remove(inv[ie.file_id].revision)
 
303
 
 
304
        store = False
 
305
        # now we check to see if we need to write a new record to the
 
306
        # file-graph.
 
307
        # We write a new entry unless there is one head to the ancestors, and
 
308
        # the kind-derived content is unchanged.
 
309
 
 
310
        # Cheapest check first: no ancestors, or more the one head in the
 
311
        # ancestors, we write a new node.
 
312
        if len(heads) != 1:
 
313
            store = True
 
314
        if not store:
 
315
            # There is a single head, look it up for comparison
 
316
            parent_entry = parent_candiate_entries[heads[0]]
 
317
            # if the non-content specific data has changed, we'll be writing a
 
318
            # node:
 
319
            if (parent_entry.parent_id != ie.parent_id or
 
320
                parent_entry.name != ie.name):
 
321
                store = True
 
322
        # now we need to do content specific checks:
 
323
        if not store:
 
324
            # if the kind changed the content obviously has
 
325
            if kind != parent_entry.kind:
 
326
                store = True
 
327
        if kind == 'file':
 
328
            if not store:
 
329
                if (# if the file length changed we have to store:
 
330
                    parent_entry.text_size != content_summary[1] or
 
331
                    # if the exec bit has changed we have to store:
 
332
                    parent_entry.executable != content_summary[2]):
 
333
                    store = True
 
334
                elif parent_entry.text_sha1 == content_summary[3]:
 
335
                    # all meta and content is unchanged (using a hash cache
 
336
                    # hit to check the sha)
 
337
                    ie.revision = parent_entry.revision
 
338
                    ie.text_size = parent_entry.text_size
 
339
                    ie.text_sha1 = parent_entry.text_sha1
 
340
                    ie.executable = parent_entry.executable
 
341
                    return self._get_delta(ie, basis_inv, path), False
 
342
                else:
 
343
                    # Either there is only a hash change(no hash cache entry,
 
344
                    # or same size content change), or there is no change on
 
345
                    # this file at all.
 
346
                    # Provide the parent's hash to the store layer, so that the
 
347
                    # content is unchanged we will not store a new node.
 
348
                    nostore_sha = parent_entry.text_sha1
 
349
            if store:
 
350
                # We want to record a new node regardless of the presence or
 
351
                # absence of a content change in the file.
 
352
                nostore_sha = None
 
353
            ie.executable = content_summary[2]
 
354
            lines = tree.get_file(ie.file_id, path).readlines()
 
355
            try:
 
356
                ie.text_sha1, ie.text_size = self._add_text_to_weave(
 
357
                    ie.file_id, lines, heads, nostore_sha)
 
358
            except errors.ExistingContent:
 
359
                # Turns out that the file content was unchanged, and we were
 
360
                # only going to store a new node if it was changed. Carry over
 
361
                # the entry.
 
362
                ie.revision = parent_entry.revision
 
363
                ie.text_size = parent_entry.text_size
 
364
                ie.text_sha1 = parent_entry.text_sha1
 
365
                ie.executable = parent_entry.executable
 
366
                return self._get_delta(ie, basis_inv, path), False
 
367
        elif kind == 'directory':
 
368
            if not store:
 
369
                # all data is meta here, nothing specific to directory, so
 
370
                # carry over:
 
371
                ie.revision = parent_entry.revision
 
372
                return self._get_delta(ie, basis_inv, path), False
 
373
            lines = []
 
374
            self._add_text_to_weave(ie.file_id, lines, heads, None)
 
375
        elif kind == 'symlink':
 
376
            current_link_target = content_summary[3]
 
377
            if not store:
 
378
                # symlink target is not generic metadata, check if it has
 
379
                # changed.
 
380
                if current_link_target != parent_entry.symlink_target:
 
381
                    store = True
 
382
            if not store:
 
383
                # unchanged, carry over.
 
384
                ie.revision = parent_entry.revision
 
385
                ie.symlink_target = parent_entry.symlink_target
 
386
                return self._get_delta(ie, basis_inv, path), False
 
387
            ie.symlink_target = current_link_target
 
388
            lines = []
 
389
            self._add_text_to_weave(ie.file_id, lines, heads, None)
 
390
        elif kind == 'tree-reference':
 
391
            if not store:
 
392
                if content_summary[3] != parent_entry.reference_revision:
 
393
                    store = True
 
394
            if not store:
 
395
                # unchanged, carry over.
 
396
                ie.reference_revision = parent_entry.reference_revision
 
397
                ie.revision = parent_entry.revision
 
398
                return self._get_delta(ie, basis_inv, path), False
 
399
            ie.reference_revision = content_summary[3]
 
400
            lines = []
 
401
            self._add_text_to_weave(ie.file_id, lines, heads, None)
 
402
        else:
 
403
            raise NotImplementedError('unknown kind')
 
404
        ie.revision = self._new_revision_id
 
405
        return self._get_delta(ie, basis_inv, path), True
 
406
 
 
407
    def _add_text_to_weave(self, file_id, new_lines, parents, nostore_sha):
338
408
        versionedfile = self.repository.weave_store.get_weave_or_empty(
339
409
            file_id, self.repository.get_transaction())
340
410
        # Don't change this to add_lines - add_lines_with_ghosts is cheaper
345
415
        # implementation could give us bad output from readlines() so this is
346
416
        # not a guarantee of safety. What would be better is always checking
347
417
        # the content during test suite execution. RBC 20070912
348
 
        result = versionedfile.add_lines_with_ghosts(
349
 
            self._new_revision_id, parents, new_lines,
350
 
            random_id=self.random_revid, check_content=False)[0:2]
351
 
        versionedfile.clear_cache()
352
 
        return result
 
418
        try:
 
419
            return versionedfile.add_lines_with_ghosts(
 
420
                self._new_revision_id, parents, new_lines,
 
421
                nostore_sha=nostore_sha, random_id=self.random_revid,
 
422
                check_content=False)[0:2]
 
423
        finally:
 
424
            versionedfile.clear_cache()
353
425
 
354
426
 
355
427
class RootCommitBuilder(CommitBuilder):