Rev 2825: (robertc) Allow declaritive changing of the CommitBuilder class for repositories. (Robert Collins) in file:///home/pqm/archives/thelove/bzr/%2Btrunk/

Canonical.com Patch Queue Manager pqm at pqm.ubuntu.com
Mon Sep 17 01:50:42 BST 2007


At file:///home/pqm/archives/thelove/bzr/%2Btrunk/

------------------------------------------------------------
revno: 2825
revision-id: pqm at pqm.ubuntu.com-20070917005035-cshdkpzbj63id1uw
parent: pqm at pqm.ubuntu.com-20070916202904-8ad60iodgmscjglj
parent: robertc at robertcollins.net-20070916234815-85qrvjbtikmge5wa
committer: Canonical.com Patch Queue Manager <pqm at pqm.ubuntu.com>
branch nick: +trunk
timestamp: Mon 2007-09-17 01:50:35 +0100
message:
  (robertc) Allow declaritive changing of the CommitBuilder class for repositories. (Robert Collins)
modified:
  bzrlib/repofmt/knitrepo.py     knitrepo.py-20070206081537-pyy4a00xdas0j4pf-1
  bzrlib/repository.py           rev_storage.py-20051111201905-119e9401e46257e3
    ------------------------------------------------------------
    revno: 2818.3.3
    merged: robertc at robertcollins.net-20070916234815-85qrvjbtikmge5wa
    parent: robertc at robertcollins.net-20070916234606-f4jtysecefi2bnh2
    parent: pqm at pqm.ubuntu.com-20070916202904-8ad60iodgmscjglj
    committer: Robert Collins <robertc at robertcollins.net>
    branch nick: integration
    timestamp: Mon 2007-09-17 09:48:15 +1000
    message:
      Merge bzr.dev.
    ------------------------------------------------------------
    revno: 2818.3.2
    merged: robertc at robertcollins.net-20070916234606-f4jtysecefi2bnh2
    parent: robertc at robertcollins.net-20070914003133-qo0tvlg5fwvbwp5i
    committer: Robert Collins <robertc at robertcollins.net>
    branch nick: commit-builder
    timestamp: Mon 2007-09-17 09:46:06 +1000
    message:
      Review feedback.
    ------------------------------------------------------------
    revno: 2818.3.1
    merged: robertc at robertcollins.net-20070914003133-qo0tvlg5fwvbwp5i
    parent: pqm at pqm.ubuntu.com-20070913193317-hi3rhwxhbrviw7hz
    committer: Robert Collins <robertc at robertcollins.net>
    branch nick: commit-builder
    timestamp: Fri 2007-09-14 10:31:33 +1000
    message:
      Change CommitBuilder factory delegation to allow simple declaration.
=== modified file 'bzrlib/repofmt/knitrepo.py'
--- a/bzrlib/repofmt/knitrepo.py	2007-09-13 22:41:38 +0000
+++ b/bzrlib/repofmt/knitrepo.py	2007-09-16 23:48:15 +0000
@@ -227,6 +227,8 @@
 
 class KnitRepository3(KnitRepository):
 
+    _commit_builder_class = RootCommitBuilder
+
     def __init__(self, _format, a_bzrdir, control_files, _revision_store,
                  control_store, text_store):
         KnitRepository.__init__(self, _format, a_bzrdir, control_files,
@@ -253,26 +255,6 @@
         assert inv.root.revision is not None
         return KnitRepository.serialise_inventory(self, inv)
 
-    def get_commit_builder(self, branch, parents, config, timestamp=None,
-                           timezone=None, committer=None, revprops=None,
-                           revision_id=None):
-        """Obtain a CommitBuilder for this repository.
-        
-        :param branch: Branch to commit to.
-        :param parents: Revision ids of the parents of the new revision.
-        :param config: Configuration to use.
-        :param timestamp: Optional timestamp recorded for commit.
-        :param timezone: Optional timezone for timestamp.
-        :param committer: Optional committer to set for commit.
-        :param revprops: Optional dictionary of revision properties.
-        :param revision_id: Optional revision id.
-        """
-        revision_id = osutils.safe_revision_id(revision_id)
-        result = RootCommitBuilder(self, parents, config, timestamp, timezone,
-                                 committer, revprops, revision_id)
-        self.start_write_group()
-        return result
-
 
 class RepositoryFormatKnit(MetaDirRepositoryFormat):
     """Bzr repository knit format (generalized). 

=== modified file 'bzrlib/repository.py'
--- a/bzrlib/repository.py	2007-09-13 22:41:38 +0000
+++ b/bzrlib/repository.py	2007-09-16 23:48:15 +0000
@@ -61,6 +61,270 @@
 _deprecation_warning_done = False
 
 
+class CommitBuilder(object):
+    """Provides an interface to build up a commit.
+
+    This allows describing a tree to be committed without needing to 
+    know the internals of the format of the repository.
+    """
+    
+    # all clients should supply tree roots.
+    record_root_entry = True
+
+    def __init__(self, repository, parents, config, timestamp=None, 
+                 timezone=None, committer=None, revprops=None, 
+                 revision_id=None):
+        """Initiate a CommitBuilder.
+
+        :param repository: Repository to commit to.
+        :param parents: Revision ids of the parents of the new revision.
+        :param config: Configuration to use.
+        :param timestamp: Optional timestamp recorded for commit.
+        :param timezone: Optional timezone for timestamp.
+        :param committer: Optional committer to set for commit.
+        :param revprops: Optional dictionary of revision properties.
+        :param revision_id: Optional revision id.
+        """
+        self._config = config
+
+        if committer is None:
+            self._committer = self._config.username()
+        else:
+            assert isinstance(committer, basestring), type(committer)
+            self._committer = committer
+
+        self.new_inventory = Inventory(None)
+        self._new_revision_id = osutils.safe_revision_id(revision_id)
+        self.parents = parents
+        self.repository = repository
+
+        self._revprops = {}
+        if revprops is not None:
+            self._revprops.update(revprops)
+
+        if timestamp is None:
+            timestamp = time.time()
+        # Restrict resolution to 1ms
+        self._timestamp = round(timestamp, 3)
+
+        if timezone is None:
+            self._timezone = osutils.local_time_offset()
+        else:
+            self._timezone = int(timezone)
+
+        self._generate_revision_if_needed()
+
+    def commit(self, message):
+        """Make the actual commit.
+
+        :return: The revision id of the recorded revision.
+        """
+        rev = _mod_revision.Revision(
+                       timestamp=self._timestamp,
+                       timezone=self._timezone,
+                       committer=self._committer,
+                       message=message,
+                       inventory_sha1=self.inv_sha1,
+                       revision_id=self._new_revision_id,
+                       properties=self._revprops)
+        rev.parent_ids = self.parents
+        self.repository.add_revision(self._new_revision_id, rev,
+            self.new_inventory, self._config)
+        self.repository.commit_write_group()
+        return self._new_revision_id
+
+    def abort(self):
+        """Abort the commit that is being built.
+        """
+        self.repository.abort_write_group()
+
+    def revision_tree(self):
+        """Return the tree that was just committed.
+
+        After calling commit() this can be called to get a RevisionTree
+        representing the newly committed tree. This is preferred to
+        calling Repository.revision_tree() because that may require
+        deserializing the inventory, while we already have a copy in
+        memory.
+        """
+        return RevisionTree(self.repository, self.new_inventory,
+                            self._new_revision_id)
+
+    def finish_inventory(self):
+        """Tell the builder that the inventory is finished."""
+        if self.new_inventory.root is None:
+            symbol_versioning.warn('Root entry should be supplied to'
+                ' record_entry_contents, as of bzr 0.10.',
+                 DeprecationWarning, stacklevel=2)
+            self.new_inventory.add(InventoryDirectory(ROOT_ID, '', None))
+        self.new_inventory.revision_id = self._new_revision_id
+        self.inv_sha1 = self.repository.add_inventory(
+            self._new_revision_id,
+            self.new_inventory,
+            self.parents
+            )
+
+    def _gen_revision_id(self):
+        """Return new revision-id."""
+        return generate_ids.gen_revision_id(self._config.username(),
+                                            self._timestamp)
+
+    def _generate_revision_if_needed(self):
+        """Create a revision id if None was supplied.
+        
+        If the repository can not support user-specified revision ids
+        they should override this function and raise CannotSetRevisionId
+        if _new_revision_id is not None.
+
+        :raises: CannotSetRevisionId
+        """
+        if self._new_revision_id is None:
+            self._new_revision_id = self._gen_revision_id()
+            self.random_revid = True
+        else:
+            self.random_revid = False
+
+    def _check_root(self, ie, parent_invs, tree):
+        """Helper for record_entry_contents.
+
+        :param ie: An entry being added.
+        :param parent_invs: The inventories of the parent revisions of the
+            commit.
+        :param tree: The tree that is being committed.
+        """
+        if ie.parent_id is not None:
+            # if ie is not root, add a root automatically.
+            symbol_versioning.warn('Root entry should be supplied to'
+                ' record_entry_contents, as of bzr 0.10.',
+                 DeprecationWarning, stacklevel=2)
+            self.record_entry_contents(tree.inventory.root.copy(), parent_invs,
+                                       '', tree)
+        else:
+            # In this revision format, root entries have no knit or weave When
+            # serializing out to disk and back in root.revision is always
+            # _new_revision_id
+            ie.revision = self._new_revision_id
+
+    def record_entry_contents(self, ie, parent_invs, path, tree):
+        """Record the content of ie from tree into the commit if needed.
+
+        Side effect: sets ie.revision when unchanged
+
+        :param ie: An inventory entry present in the commit.
+        :param parent_invs: The inventories of the parent revisions of the
+            commit.
+        :param path: The path the entry is at in the tree.
+        :param tree: The tree which contains this entry and should be used to 
+        obtain content.
+        """
+        if self.new_inventory.root is None:
+            self._check_root(ie, parent_invs, tree)
+        self.new_inventory.add(ie)
+
+        # ie.revision is always None if the InventoryEntry is considered
+        # for committing. ie.snapshot will record the correct revision 
+        # which may be the sole parent if it is untouched.
+        if ie.revision is not None:
+            return
+
+        parent_candiate_entries = ie.parent_candidates(parent_invs)
+        heads = self.repository.get_graph().heads(parent_candiate_entries.keys())
+        # XXX: Note that this is unordered - and this is tolerable because 
+        # the previous code was also unordered.
+        previous_entries = dict((head, parent_candiate_entries[head]) for head
+            in heads)
+        # we are creating a new revision for ie in the history store and
+        # inventory.
+        ie.snapshot(self._new_revision_id, path, previous_entries, tree, self)
+
+    def modified_directory(self, file_id, file_parents):
+        """Record the presence of a symbolic link.
+
+        :param file_id: The file_id of the link to record.
+        :param file_parents: The per-file parent revision ids.
+        """
+        self._add_text_to_weave(file_id, [], file_parents.keys())
+
+    def modified_reference(self, file_id, file_parents):
+        """Record the modification of a reference.
+
+        :param file_id: The file_id of the link to record.
+        :param file_parents: The per-file parent revision ids.
+        """
+        self._add_text_to_weave(file_id, [], file_parents.keys())
+    
+    def modified_file_text(self, file_id, file_parents,
+                           get_content_byte_lines, text_sha1=None,
+                           text_size=None):
+        """Record the text of file file_id
+
+        :param file_id: The file_id of the file to record the text of.
+        :param file_parents: The per-file parent revision ids.
+        :param get_content_byte_lines: A callable which will return the byte
+            lines for the file.
+        :param text_sha1: Optional SHA1 of the file contents.
+        :param text_size: Optional size of the file contents.
+        """
+        # mutter('storing text of file {%s} in revision {%s} into %r',
+        #        file_id, self._new_revision_id, self.repository.weave_store)
+        # special case to avoid diffing on renames or 
+        # reparenting
+        if (len(file_parents) == 1
+            and text_sha1 == file_parents.values()[0].text_sha1
+            and text_size == file_parents.values()[0].text_size):
+            previous_ie = file_parents.values()[0]
+            versionedfile = self.repository.weave_store.get_weave(file_id,
+                self.repository.get_transaction())
+            versionedfile.clone_text(self._new_revision_id,
+                previous_ie.revision, file_parents.keys())
+            return text_sha1, text_size
+        else:
+            new_lines = get_content_byte_lines()
+            return self._add_text_to_weave(file_id, new_lines,
+                file_parents.keys())
+
+    def modified_link(self, file_id, file_parents, link_target):
+        """Record the presence of a symbolic link.
+
+        :param file_id: The file_id of the link to record.
+        :param file_parents: The per-file parent revision ids.
+        :param link_target: Target location of this link.
+        """
+        self._add_text_to_weave(file_id, [], file_parents.keys())
+
+    def _add_text_to_weave(self, file_id, new_lines, parents):
+        versionedfile = self.repository.weave_store.get_weave_or_empty(
+            file_id, self.repository.get_transaction())
+        # Don't change this to add_lines - add_lines_with_ghosts is cheaper
+        # than add_lines, and allows committing when a parent is ghosted for
+        # some reason.
+        # Note: as we read the content directly from the tree, we know its not
+        # been turned into unicode or badly split - but a broken tree
+        # implementation could give us bad output from readlines() so this is
+        # not a guarantee of safety. What would be better is always checking
+        # the content during test suite execution. RBC 20070912
+        result = versionedfile.add_lines_with_ghosts(
+            self._new_revision_id, parents, new_lines,
+            random_id=self.random_revid, check_content=False)[0:2]
+        versionedfile.clear_cache()
+        return result
+
+
+class RootCommitBuilder(CommitBuilder):
+    """This commitbuilder actually records the root id"""
+    
+    def _check_root(self, ie, parent_invs, tree):
+        """Helper for record_entry_contents.
+
+        :param ie: An entry being added.
+        :param parent_invs: The inventories of the parent revisions of the
+            commit.
+        :param tree: The tree that is being committed.
+        """
+        # ie must be root for this builder
+        assert ie.parent_id is None
+
+
 ######################################################################
 # Repositories
 
@@ -76,6 +340,12 @@
     remote) disk.
     """
 
+    # What class to use for a CommitBuilder. Often its simpler to change this
+    # in a Repository class subclass rather than to override
+    # get_commit_builder.
+    _commit_builder_class = CommitBuilder
+    # The search regex used by xml based repositories to determine what things
+    # where changed in a single commit.
     _file_ids_altered_regex = lazy_regex.lazy_compile(
         r'file_id="(?P<file_id>[^"]+)"'
         r'.* revision="(?P<revision_id>[^"]+)"'
@@ -461,8 +731,8 @@
         :param revision_id: Optional revision id.
         """
         revision_id = osutils.safe_revision_id(revision_id)
-        result = CommitBuilder(self, parents, config, timestamp, timezone,
-                              committer, revprops, revision_id)
+        result = self._commit_builder_class(self, parents, config,
+            timestamp, timezone, committer, revprops, revision_id)
         self.start_write_group()
         return result
 
@@ -2073,270 +2343,6 @@
         self.pb.update(message, self.count, self.total)
 
 
-class CommitBuilder(object):
-    """Provides an interface to build up a commit.
-
-    This allows describing a tree to be committed without needing to 
-    know the internals of the format of the repository.
-    """
-    
-    # all clients should supply tree roots.
-    record_root_entry = True
-
-    def __init__(self, repository, parents, config, timestamp=None, 
-                 timezone=None, committer=None, revprops=None, 
-                 revision_id=None):
-        """Initiate a CommitBuilder.
-
-        :param repository: Repository to commit to.
-        :param parents: Revision ids of the parents of the new revision.
-        :param config: Configuration to use.
-        :param timestamp: Optional timestamp recorded for commit.
-        :param timezone: Optional timezone for timestamp.
-        :param committer: Optional committer to set for commit.
-        :param revprops: Optional dictionary of revision properties.
-        :param revision_id: Optional revision id.
-        """
-        self._config = config
-
-        if committer is None:
-            self._committer = self._config.username()
-        else:
-            assert isinstance(committer, basestring), type(committer)
-            self._committer = committer
-
-        self.new_inventory = Inventory(None)
-        self._new_revision_id = osutils.safe_revision_id(revision_id)
-        self.parents = parents
-        self.repository = repository
-
-        self._revprops = {}
-        if revprops is not None:
-            self._revprops.update(revprops)
-
-        if timestamp is None:
-            timestamp = time.time()
-        # Restrict resolution to 1ms
-        self._timestamp = round(timestamp, 3)
-
-        if timezone is None:
-            self._timezone = osutils.local_time_offset()
-        else:
-            self._timezone = int(timezone)
-
-        self._generate_revision_if_needed()
-
-    def commit(self, message):
-        """Make the actual commit.
-
-        :return: The revision id of the recorded revision.
-        """
-        rev = _mod_revision.Revision(
-                       timestamp=self._timestamp,
-                       timezone=self._timezone,
-                       committer=self._committer,
-                       message=message,
-                       inventory_sha1=self.inv_sha1,
-                       revision_id=self._new_revision_id,
-                       properties=self._revprops)
-        rev.parent_ids = self.parents
-        self.repository.add_revision(self._new_revision_id, rev,
-            self.new_inventory, self._config)
-        self.repository.commit_write_group()
-        return self._new_revision_id
-
-    def abort(self):
-        """Abort the commit that is being built.
-        """
-        self.repository.abort_write_group()
-
-    def revision_tree(self):
-        """Return the tree that was just committed.
-
-        After calling commit() this can be called to get a RevisionTree
-        representing the newly committed tree. This is preferred to
-        calling Repository.revision_tree() because that may require
-        deserializing the inventory, while we already have a copy in
-        memory.
-        """
-        return RevisionTree(self.repository, self.new_inventory,
-                            self._new_revision_id)
-
-    def finish_inventory(self):
-        """Tell the builder that the inventory is finished."""
-        if self.new_inventory.root is None:
-            symbol_versioning.warn('Root entry should be supplied to'
-                ' record_entry_contents, as of bzr 0.10.',
-                 DeprecationWarning, stacklevel=2)
-            self.new_inventory.add(InventoryDirectory(ROOT_ID, '', None))
-        self.new_inventory.revision_id = self._new_revision_id
-        self.inv_sha1 = self.repository.add_inventory(
-            self._new_revision_id,
-            self.new_inventory,
-            self.parents
-            )
-
-    def _gen_revision_id(self):
-        """Return new revision-id."""
-        return generate_ids.gen_revision_id(self._config.username(),
-                                            self._timestamp)
-
-    def _generate_revision_if_needed(self):
-        """Create a revision id if None was supplied.
-        
-        If the repository can not support user-specified revision ids
-        they should override this function and raise CannotSetRevisionId
-        if _new_revision_id is not None.
-
-        :raises: CannotSetRevisionId
-        """
-        if self._new_revision_id is None:
-            self._new_revision_id = self._gen_revision_id()
-            self.random_revid = True
-        else:
-            self.random_revid = False
-
-    def _check_root(self, ie, parent_invs, tree):
-        """Helper for record_entry_contents.
-
-        :param ie: An entry being added.
-        :param parent_invs: The inventories of the parent revisions of the
-            commit.
-        :param tree: The tree that is being committed.
-        """
-        if ie.parent_id is not None:
-            # if ie is not root, add a root automatically.
-            symbol_versioning.warn('Root entry should be supplied to'
-                ' record_entry_contents, as of bzr 0.10.',
-                 DeprecationWarning, stacklevel=2)
-            self.record_entry_contents(tree.inventory.root.copy(), parent_invs,
-                                       '', tree)
-        else:
-            # In this revision format, root entries have no knit or weave When
-            # serializing out to disk and back in root.revision is always
-            # _new_revision_id
-            ie.revision = self._new_revision_id
-
-    def record_entry_contents(self, ie, parent_invs, path, tree):
-        """Record the content of ie from tree into the commit if needed.
-
-        Side effect: sets ie.revision when unchanged
-
-        :param ie: An inventory entry present in the commit.
-        :param parent_invs: The inventories of the parent revisions of the
-            commit.
-        :param path: The path the entry is at in the tree.
-        :param tree: The tree which contains this entry and should be used to 
-        obtain content.
-        """
-        if self.new_inventory.root is None:
-            self._check_root(ie, parent_invs, tree)
-        self.new_inventory.add(ie)
-
-        # ie.revision is always None if the InventoryEntry is considered
-        # for committing. ie.snapshot will record the correct revision 
-        # which may be the sole parent if it is untouched.
-        if ie.revision is not None:
-            return
-
-        parent_candiate_entries = ie.parent_candidates(parent_invs)
-        heads = self.repository.get_graph().heads(parent_candiate_entries.keys())
-        # XXX: Note that this is unordered - and this is tolerable because 
-        # the previous code was also unordered.
-        previous_entries = dict((head, parent_candiate_entries[head]) for head
-            in heads)
-        # we are creating a new revision for ie in the history store and
-        # inventory.
-        ie.snapshot(self._new_revision_id, path, previous_entries, tree, self)
-
-    def modified_directory(self, file_id, file_parents):
-        """Record the presence of a symbolic link.
-
-        :param file_id: The file_id of the link to record.
-        :param file_parents: The per-file parent revision ids.
-        """
-        self._add_text_to_weave(file_id, [], file_parents.keys())
-
-    def modified_reference(self, file_id, file_parents):
-        """Record the modification of a reference.
-
-        :param file_id: The file_id of the link to record.
-        :param file_parents: The per-file parent revision ids.
-        """
-        self._add_text_to_weave(file_id, [], file_parents.keys())
-    
-    def modified_file_text(self, file_id, file_parents,
-                           get_content_byte_lines, text_sha1=None,
-                           text_size=None):
-        """Record the text of file file_id
-
-        :param file_id: The file_id of the file to record the text of.
-        :param file_parents: The per-file parent revision ids.
-        :param get_content_byte_lines: A callable which will return the byte
-            lines for the file.
-        :param text_sha1: Optional SHA1 of the file contents.
-        :param text_size: Optional size of the file contents.
-        """
-        # mutter('storing text of file {%s} in revision {%s} into %r',
-        #        file_id, self._new_revision_id, self.repository.weave_store)
-        # special case to avoid diffing on renames or 
-        # reparenting
-        if (len(file_parents) == 1
-            and text_sha1 == file_parents.values()[0].text_sha1
-            and text_size == file_parents.values()[0].text_size):
-            previous_ie = file_parents.values()[0]
-            versionedfile = self.repository.weave_store.get_weave(file_id,
-                self.repository.get_transaction())
-            versionedfile.clone_text(self._new_revision_id,
-                previous_ie.revision, file_parents.keys())
-            return text_sha1, text_size
-        else:
-            new_lines = get_content_byte_lines()
-            return self._add_text_to_weave(file_id, new_lines,
-                file_parents.keys())
-
-    def modified_link(self, file_id, file_parents, link_target):
-        """Record the presence of a symbolic link.
-
-        :param file_id: The file_id of the link to record.
-        :param file_parents: The per-file parent revision ids.
-        :param link_target: Target location of this link.
-        """
-        self._add_text_to_weave(file_id, [], file_parents.keys())
-
-    def _add_text_to_weave(self, file_id, new_lines, parents):
-        versionedfile = self.repository.weave_store.get_weave_or_empty(
-            file_id, self.repository.get_transaction())
-        # Don't change this to add_lines - add_lines_with_ghosts is cheaper
-        # than add_lines, and allows committing when a parent is ghosted for
-        # some reason.
-        # Note: as we read the content directly from the tree, we know its not
-        # been turned into unicode or badly split - but a broken tree
-        # implementation could give us bad output from readlines() so this is
-        # not a guarantee of safety. What would be better is always checking
-        # the content during test suite execution. RBC 20070912
-        result = versionedfile.add_lines_with_ghosts(
-            self._new_revision_id, parents, new_lines,
-            random_id=self.random_revid, check_content=False)[0:2]
-        versionedfile.clear_cache()
-        return result
-
-
-class RootCommitBuilder(CommitBuilder):
-    """This commitbuilder actually records the root id"""
-    
-    def _check_root(self, ie, parent_invs, tree):
-        """Helper for record_entry_contents.
-
-        :param ie: An entry being added.
-        :param parent_invs: The inventories of the parent revisions of the
-            commit.
-        :param tree: The tree that is being committed.
-        """
-        # ie must be root for this builder
-        assert ie.parent_id is None
-
-
 _unescape_map = {
     'apos':"'",
     'quot':'"',




More information about the bazaar-commits mailing list