~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/repository.py

  • Committer: Robert Collins
  • Date: 2007-09-05 05:51:34 UTC
  • mto: (2592.3.126 repository)
  • mto: This revision was merged to the branch mainline in revision 2879.
  • Revision ID: robertc@robertcollins.net-20070905055134-pwbueao0qq6krf9u
nuke _read_tree_state and snapshot from inventory, moving responsibility into the commit builder.

Show diffs side-by-side

added added

removed removed

Lines of Context:
2219
2219
        """
2220
2220
        if self.new_inventory.root is None:
2221
2221
            self._check_root(ie, parent_invs, tree)
 
2222
        content_summary = tree.path_content_summary(path)
 
2223
        kind = content_summary[0]
 
2224
        # XXX: repository specific check for nested tree support goes here - if
 
2225
        # the repo doesn't want nested trees we skip it ?
 
2226
        if (kind == 'tree-reference' and
 
2227
            not self.repository._format.supports_tree_reference):
 
2228
            # mismatch between commit builder logic and repository:
 
2229
            # this needs the entry creation pushed down into the builder.
 
2230
            raise NotImplementedError
 
2231
        # transitional assert only, will remove before release.
 
2232
        assert ie.kind == kind
2222
2233
        self.new_inventory.add(ie)
2223
2234
 
2224
2235
        # ie.revision is always None if the InventoryEntry is considered
2227
2238
        if ie.revision is not None:
2228
2239
            return
2229
2240
 
 
2241
        # XXX: Friction: parent_candidates should return a list not a dict
 
2242
        #      so that we don't have to walk the inventories again.
2230
2243
        parent_candiate_entries = ie.parent_candidates(parent_invs)
2231
 
        heads = self.repository.get_graph().heads(parent_candiate_entries.keys())
2232
 
        # XXX: Note that this is unordered - and this is tolerable because 
2233
 
        # the previous code was also unordered.
2234
 
        previous_entries = dict((head, parent_candiate_entries[head]) for head
2235
 
            in heads)
2236
 
        # we are creating a new revision for ie in the history store and
2237
 
        # inventory.
2238
 
        ie.snapshot(self._new_revision_id, path, previous_entries, tree, self)
2239
 
 
2240
 
    def modified_directory(self, file_id, file_parents):
2241
 
        """Record the presence of a symbolic link.
2242
 
 
2243
 
        :param file_id: The file_id of the link to record.
2244
 
        :param file_parents: The per-file parent revision ids.
2245
 
        """
2246
 
        self._add_text_to_weave(file_id, [], file_parents.keys())
2247
 
 
2248
 
    def modified_reference(self, file_id, file_parents):
2249
 
        """Record the modification of a reference.
2250
 
 
2251
 
        :param file_id: The file_id of the link to record.
2252
 
        :param file_parents: The per-file parent revision ids.
2253
 
        """
2254
 
        self._add_text_to_weave(file_id, [], file_parents.keys())
2255
 
    
2256
 
    def modified_file_text(self, file_id, file_parents,
2257
 
                           get_content_byte_lines, text_sha1=None,
2258
 
                           text_size=None):
2259
 
        """Record the text of file file_id
2260
 
 
2261
 
        :param file_id: The file_id of the file to record the text of.
2262
 
        :param file_parents: The per-file parent revision ids.
2263
 
        :param get_content_byte_lines: A callable which will return the byte
2264
 
            lines for the file.
2265
 
        :param text_sha1: Optional SHA1 of the file contents.
2266
 
        :param text_size: Optional size of the file contents.
2267
 
        """
2268
 
        # mutter('storing text of file {%s} in revision {%s} into %r',
2269
 
        #        file_id, self._new_revision_id, self.repository.weave_store)
2270
 
        # special case to avoid diffing on renames or 
2271
 
        # reparenting
2272
 
        if (len(file_parents) == 1
2273
 
            and text_sha1 == file_parents.values()[0].text_sha1
2274
 
            and text_size == file_parents.values()[0].text_size):
2275
 
            previous_ie = file_parents.values()[0]
2276
 
            versionedfile = self.repository.weave_store.get_weave(file_id,
2277
 
                self.repository.get_transaction())
2278
 
            versionedfile.clone_text(self._new_revision_id,
2279
 
                previous_ie.revision, file_parents.keys())
2280
 
            return text_sha1, text_size
 
2244
        head_set = self.repository.get_graph().heads(parent_candiate_entries.keys())
 
2245
        heads = []
 
2246
        for inv in parent_invs:
 
2247
            if ie.file_id in inv:
 
2248
                old_rev = inv[ie.file_id].revision
 
2249
                if old_rev in head_set:
 
2250
                    heads.append(inv[ie.file_id].revision)
 
2251
                    head_set.remove(inv[ie.file_id].revision)
 
2252
 
 
2253
        store = False
 
2254
        # now we check to see if we need to write a new record to the
 
2255
        # file-graph.
 
2256
        # We write a new entry unless there is one head to the ancestors, and
 
2257
        # the kind-derived content is unchanged.
 
2258
 
 
2259
        # Cheapest check first: no ancestors, or more the one head in the
 
2260
        # ancestors, we write a new node.
 
2261
        if len(heads) != 1:
 
2262
            store = True
 
2263
        if not store:
 
2264
            # There is a single head, look it up for comparison
 
2265
            parent_entry = parent_candiate_entries[heads[0]]
 
2266
            # if the non-content specific data has changed, we'll be writing a
 
2267
            # node:
 
2268
            if (parent_entry.parent_id != ie.parent_id or
 
2269
                parent_entry.name != ie.name):
 
2270
                store = True
 
2271
        # now we need to do content specific checks:
 
2272
        if not store:
 
2273
            # if the kind changed the content obviously has
 
2274
            if kind != parent_entry.kind:
 
2275
                store = True
 
2276
        if kind == 'file':
 
2277
            if not store:
 
2278
                if (# if the file length changed we have to store:
 
2279
                    parent_entry.text_size != content_summary[1] or
 
2280
                    # if the exec bit has changed we have to store:
 
2281
                    parent_entry.executable != content_summary[2]):
 
2282
                    store = True
 
2283
                elif parent_entry.text_sha1 == content_summary[3]:
 
2284
                    # all meta and content is unchanged (using a hash cache
 
2285
                    # hit to check the sha)
 
2286
                    ie.revision = parent_entry.revision
 
2287
                    ie.text_size = parent_entry.text_size
 
2288
                    ie.text_sha1 = parent_entry.text_sha1
 
2289
                    ie.executable = parent_entry.executable
 
2290
                    return
 
2291
                else:
 
2292
                    # Either there is only a hash change(no hash cache entry,
 
2293
                    # or same size content change), or there is no change on
 
2294
                    # this file at all.
 
2295
                    # There is a race condition when inserting content into the
 
2296
                    # knit though that can result in different content being
 
2297
                    # inserted so even though we may have had a hash cache hit
 
2298
                    # here we still tell the store the hash we would *not*
 
2299
                    # store a new text on, which means that it can avoid for us
 
2300
                    # without a race condition and without double-shaing the
 
2301
                    # lines.
 
2302
                    nostore_sha = parent_entry.text_sha1
 
2303
            if store:
 
2304
                nostore_sha = None
 
2305
            try:
 
2306
                ie.executable = content_summary[2]
 
2307
                lines = tree.get_file(ie.file_id, path).readlines()
 
2308
                ie.text_sha1, ie.text_size = self._add_text_to_weave(
 
2309
                    ie.file_id, lines, heads, nostore_sha)
 
2310
                ie.revision = self._new_revision_id
 
2311
            except errors.ExistingContent:
 
2312
                # we are not going to store a new file graph node as it turns
 
2313
                # out to be unchanged.
 
2314
                ie.revision = parent_entry.revision
 
2315
                ie.text_size = parent_entry.text_size
 
2316
                ie.text_sha1 = parent_entry.text_sha1
 
2317
                ie.executable = parent_entry.executable
 
2318
                return
 
2319
        elif kind == 'directory':
 
2320
            if not store:
 
2321
                # all data is meta here, so carry over:
 
2322
                ie.revision = parent_entry.revision
 
2323
                return
 
2324
            lines = []
 
2325
            self._add_text_to_weave(ie.file_id, lines, heads, None)
 
2326
        elif kind == 'symlink':
 
2327
            current_link_target = content_summary[3]
 
2328
            if not store:
 
2329
                # symmlink target is not generic metadata, check if it has
 
2330
                # changed.
 
2331
                if current_link_target != parent_entry.symlink_target:
 
2332
                    store = True
 
2333
            if not store:
 
2334
                ie.revision = parent_entry.revision
 
2335
                ie.symlink_target = parent_entry.symlink_target
 
2336
                return
 
2337
            ie.symlink_target = current_link_target
 
2338
            lines = []
 
2339
            self._add_text_to_weave(ie.file_id, lines, heads, None)
 
2340
        elif kind == 'tree-reference':
 
2341
            if not store:
 
2342
                # all data is meta here, so carry over:
 
2343
                ie.revision = parent_entry.revision
 
2344
                return
 
2345
            lines = []
 
2346
            self._add_text_to_weave(ie.file_id, lines, heads, None)
2281
2347
        else:
2282
 
            new_lines = get_content_byte_lines()
2283
 
            return self._add_text_to_weave(file_id, new_lines,
2284
 
                file_parents.keys())
2285
 
 
2286
 
    def modified_link(self, file_id, file_parents, link_target):
2287
 
        """Record the presence of a symbolic link.
2288
 
 
2289
 
        :param file_id: The file_id of the link to record.
2290
 
        :param file_parents: The per-file parent revision ids.
2291
 
        :param link_target: Target location of this link.
2292
 
        """
2293
 
        self._add_text_to_weave(file_id, [], file_parents.keys())
2294
 
 
2295
 
    def _add_text_to_weave(self, file_id, new_lines, parents):
 
2348
            raise NotImplementedError('unknown kind')
 
2349
        ie.revision = self._new_revision_id
 
2350
 
 
2351
    def _add_text_to_weave(self, file_id, new_lines, parents, nostore_sha):
2296
2352
        versionedfile = self.repository.weave_store.get_weave_or_empty(
2297
2353
            file_id, self.repository.get_transaction())
2298
 
        result = versionedfile.add_lines(
2299
 
            self._new_revision_id, parents, new_lines)[0:2]
2300
 
        versionedfile.clear_cache()
2301
 
        return result
 
2354
        try:
 
2355
            return versionedfile.add_lines(
 
2356
                self._new_revision_id, parents, new_lines,
 
2357
                nostore_sha=nostore_sha)[0:2]
 
2358
        finally:
 
2359
            versionedfile.clear_cache()
2302
2360
 
2303
2361
 
2304
2362
class _CommitBuilder(CommitBuilder):