Rev 5193: (andrew) Add bzrlib.merge.PerFileMerger to make it easier to write in file:///home/pqm/archives/thelove/bzr/%2Btrunk/

Canonical.com Patch Queue Manager pqm at pqm.ubuntu.com
Thu Apr 29 08:30:14 BST 2010


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

------------------------------------------------------------
revno: 5193 [merge]
revision-id: pqm at pqm.ubuntu.com-20100429073011-5f4kzm2wpojq9we1
parent: pqm at pqm.ubuntu.com-20100428220257-fwkbybtzi147j8re
parent: andrew.bennetts at canonical.com-20100429055235-24e81jfdse3h3ugt
committer: Canonical.com Patch Queue Manager <pqm at pqm.ubuntu.com>
branch nick: +trunk
timestamp: Thu 2010-04-29 08:30:11 +0100
message:
  (andrew) Add bzrlib.merge.PerFileMerger to make it easier to write
  	simple merge_file_content hooks.
modified:
  NEWS                           NEWS-20050323055033-4e00b5db738777ff
  bzrlib/merge.py                merge.py-20050513021216-953b65a438527106
  doc/en/user-guide/hooks.txt    hooks.txt-20070829200551-7nr6e5a1io6x78uf-1
=== modified file 'NEWS'
--- a/NEWS	2010-04-28 22:02:57 +0000
+++ b/NEWS	2010-04-29 05:52:35 +0000
@@ -76,6 +76,10 @@
 API Changes
 ***********
 
+* Added ``bzrlib.merge.PerFileMerger``, a more convenient way to write
+  some kinds of ``merge_file_content`` hook functions.
+  (Andrew Bennetts)
+  
 * `BzrDir`, `Branch`, `Repository` and `WorkingTree` now all support `user_url`,
   `user_transport`, `control_url` and `control_transport` members pointing
   respectively to the directory containing the ``.bzr`` control directory, 

=== modified file 'bzrlib/merge.py'
--- a/bzrlib/merge.py	2010-04-26 23:36:26 +0000
+++ b/bzrlib/merge.py	2010-04-29 05:52:35 +0000
@@ -93,7 +93,60 @@
         return ('not applicable', None)
 
 
-class ConfigurableFileMerger(AbstractPerFileMerger):
+class PerFileMerger(AbstractPerFileMerger):
+    """Merge individual files when self.file_matches returns True.
+
+    This class is intended to be subclassed.  The file_matches and
+    merge_matching methods should be overridden with concrete implementations.
+    """
+
+    def file_matches(self, params):
+        """Return True if merge_matching should be called on this file.
+
+        Only called with merges of plain files with no clear winner.
+
+        Subclasses must override this.
+        """
+        raise NotImplementedError(self.file_matches)
+
+    def get_filename(self, params, tree):
+        """Lookup the filename (i.e. basename, not path), given a Tree (e.g.
+        self.merger.this_tree) and a MergeHookParams.
+        """
+        return osutils.basename(tree.id2path(params.file_id))
+
+    def get_filepath(self, params, tree):
+        """Calculate the path to the file in a tree.
+
+        :param params: A MergeHookParams describing the file to merge
+        :param tree: a Tree, e.g. self.merger.this_tree.
+        """
+        return tree.id2path(params.file_id)
+
+    def merge_contents(self, params):
+        """Merge the contents of a single file."""
+        # Check whether this custom merge logic should be used.
+        if (
+            # OTHER is a straight winner, rely on default merge.
+            params.winner == 'other' or
+            # THIS and OTHER aren't both files.
+            not params.is_file_merge() or
+            # The filename doesn't match *.xml
+            not self.file_matches(params)):
+            return 'not_applicable', None
+        return self.merge_matching(params)
+
+    def merge_matching(self, params):
+        """Merge the contents of a single file that has matched the criteria
+        in PerFileMerger.merge_contents (is a conflict, is a file,
+        self.file_matches is True).
+
+        Subclasses must override this.
+        """
+        raise NotImplementedError(self.merge_matching)
+
+
+class ConfigurableFileMerger(PerFileMerger):
     """Merge individual files when configured via a .conf file.
 
     This is a base class for concrete custom file merging logic. Concrete
@@ -122,7 +175,7 @@
         if self.name_prefix is None:
             raise ValueError("name_prefix must be set.")
 
-    def filename_matches_config(self, params):
+    def file_matches(self, params):
         """Check whether the file should call the merge hook.
 
         <name_prefix>_merge_files configuration variable is a list of files
@@ -142,24 +195,12 @@
                 affected_files = self.default_files
             self.affected_files = affected_files
         if affected_files:
-            filename = self.merger.this_tree.id2path(params.file_id)
-            if filename in affected_files:
+            filepath = self.get_filepath(params, self.merger.this_tree)
+            if filepath in affected_files:
                 return True
         return False
 
-    def merge_contents(self, params):
-        """Merge the contents of a single file."""
-        # First, check whether this custom merge logic should be used.  We
-        # expect most files should not be merged by this handler.
-        if (
-            # OTHER is a straight winner, rely on default merge.
-            params.winner == 'other' or
-            # THIS and OTHER aren't both files.
-            not params.is_file_merge() or
-            # The filename isn't listed in the 'NAME_merge_files' config
-            # option.
-            not self.filename_matches_config(params)):
-            return 'not_applicable', None
+    def merge_matching(self, params):
         return self.merge_text(params)
 
     def merge_text(self, params):

=== modified file 'doc/en/user-guide/hooks.txt'
--- a/doc/en/user-guide/hooks.txt	2010-04-21 07:52:31 +0000
+++ b/doc/en/user-guide/hooks.txt	2010-04-22 07:35:06 +0000
@@ -77,32 +77,19 @@
   Always conflicts if both branches have changed the file.
   """
   
-  from bzrlib.merge import AbstractPerFileMerger, Merger
+  from bzrlib.merge import PerFileMerger, Merger
   
   def merge_xml_files_hook(merger):
       """Hook to merge *.xml files"""
       return MergeXMLFiles(merger)
   
-  class MergeXMLFiles(AbstractPerFileMerger):
-  
-      def filename_matches(self, params):
-          inventory = self.merger.this_tree.inventory
-          filename = inventory[params.file_id].name
-          if filename.endswith('.xml'):
-              return filename
-  
-      def merge_contents(self, params):
-          """Merge the contents of a single file."""
-          # First, check whether this custom merge logic should be used. We
-          # expect most files should not be merged by this handler.
-          if (
-              # OTHER is a straight winner, rely on default merge.
-              params.winner == 'other' or
-              # THIS and OTHER aren't both files.
-              not params.is_file_merge() or
-              # The filename doesn't match *.xml
-              not self.filename_matches(params)):
-              return 'not_applicable', None
+  class AlwaysConflictXMLMerger(PerFileMerger):
+  
+      def file_matches(self, params):
+          filename = self.get_filename(params, self.merger.this_tree)
+          return filename.endswith('.xml')
+  
+      def merge_matching(self, params):
           return 'conflicted', params.this_lines
   
   Merger.hooks.install_named_hook(




More information about the bazaar-commits mailing list