Rev 5017: ``bzr add`` won't blindly add conflict related files. in file:///home/vila/src/bzr/bugs/322767-dont-add-conflict-related-files/

Vincent Ladeuil v.ladeuil+lp at free.fr
Mon Feb 8 16:36:13 GMT 2010


At file:///home/vila/src/bzr/bugs/322767-dont-add-conflict-related-files/

------------------------------------------------------------
revno: 5017
revision-id: v.ladeuil+lp at free.fr-20100208163613-9sgl3ugvdxapwgw8
parent: v.ladeuil+lp at free.fr-20100208104948-jylpbzqlqyg6we1e
committer: Vincent Ladeuil <v.ladeuil+lp at free.fr>
branch nick: 322767-dont-add-conflict-related-files
timestamp: Mon 2010-02-08 17:36:13 +0100
message:
  ``bzr add`` won't blindly add conflict related files.
  
  * bzrlib/tests/per_workingtree/test_smart_add.py:
  (TestSmartAddConflictRelatedFiles): Make sure we don't add blindly
  but that we can add on demand.
  
  * bzrlib/mutabletree.py:
  (MutableTree.smart_add): Check that we don't, implicitly, add a
  file generated to help resolve a conflict.
  
  * bzrlib/conflicts.py:
  (Conflict.associated_filenames): New helper.
  (Conflict.cleanup): Use the helper to reduce duplication.
  (PathConflict, ContentsConflict, TextConflict, HandledConflict):
  Define associated_filenames instead of cleanup.
-------------- next part --------------
=== modified file 'NEWS'
--- a/NEWS	2010-02-07 10:51:26 +0000
+++ b/NEWS	2010-02-08 16:36:13 +0000
@@ -36,6 +36,9 @@
 * Avoid infinite recursion when probing for apport.
   (Vincent Ladeuil, #516934)
 
+* ``bzr add`` will not add conflict related files unless explicitly required.
+  (Vincent Ladeuil, #322767)
+
 Testing
 *******
 

=== modified file 'bzrlib/conflicts.py'
--- a/bzrlib/conflicts.py	2010-02-05 10:27:33 +0000
+++ b/bzrlib/conflicts.py	2010-02-08 16:36:13 +0000
@@ -412,8 +412,17 @@
             raise NotImplementedError(self.__class__.__name__ + '.' + action)
         meth(tree)
 
+    def associated_filenames(self):
+        """The names of the files generated to help resolve the conflict."""
+        raise NotImplementedError(self.associated_filenames)
+
     def cleanup(self, tree):
-        raise NotImplementedError(self.cleanup)
+        for fname in self.associated_filenames():
+            try:
+                osutils.delete_any(tree.abspath(fname))
+            except OSError, e:
+                if e.errno != errno.ENOENT:
+                    raise
 
     def action_done(self, tree):
         """Mark the conflict as solved once it has been handled."""
@@ -446,9 +455,9 @@
             s.add('conflict_path', self.conflict_path)
         return s
 
-    def cleanup(self, tree):
+    def associated_filenames(self):
         # No additional files have been generated here
-        pass
+        return []
 
     def action_take_this(self, tree):
         tree.rename_one(self.conflict_path, self.path)
@@ -467,13 +476,8 @@
 
     format = 'Contents conflict in %(path)s'
 
-    def cleanup(self, tree):
-        for suffix in ('.BASE', '.OTHER'):
-            try:
-                osutils.delete_any(tree.abspath(self.path + suffix))
-            except OSError, e:
-                if e.errno != errno.ENOENT:
-                    raise
+    def associated_filenames(self):
+        return [self.path + suffix for suffix in ('.BASE', '.OTHER')]
 
     # FIXME: I smell something weird here and it seems we should be able to be
     # more coherent with some other conflict ? bzr *did* a choice there but
@@ -501,13 +505,8 @@
 
     format = 'Text conflict in %(path)s'
 
-    def cleanup(self, tree):
-        for suffix in CONFLICT_SUFFIXES:
-            try:
-                osutils.delete_any(tree.abspath(self.path+suffix))
-            except OSError, e:
-                if e.errno != errno.ENOENT:
-                    raise
+    def associated_filenames(self):
+        return [self.path + suffix for suffix in CONFLICT_SUFFIXES]
 
 
 class HandledConflict(Conflict):
@@ -529,9 +528,9 @@
         s.add('action', self.action)
         return s
 
-    def cleanup(self, tree):
-        """Nothing to cleanup."""
-        pass
+    def associated_filenames(self):
+        # Nothing has been generated here
+        return []
 
 
 class HandledPathConflict(HandledConflict):

=== modified file 'bzrlib/mutabletree.py'
--- a/bzrlib/mutabletree.py	2009-10-06 14:40:37 +0000
+++ b/bzrlib/mutabletree.py	2010-02-08 16:36:13 +0000
@@ -380,6 +380,8 @@
 
         if not file_list:
             # no paths supplied: add the entire tree.
+            # FIXME: this assumes we are running in a working tree subdir :-/
+            # -- vila 20100208
             file_list = [u'.']
         # mutter("smart add of %r")
         inv = self.inventory
@@ -387,6 +389,14 @@
         ignored = {}
         dirs_to_add = []
         user_dirs = set()
+        conflicts_related = []
+        # Not all mutable trees can have conflicts
+        if getattr(self, 'conflicts', None) is not None:
+            # Collect all related files without checking whether they exist or
+            # are versioned. It's cheaper to do that once for all conflicts
+            # than trying to find the relevant conflict for each added file.
+            for c in self.conflicts():
+                conflicts_related.extend(c.associated_filenames())
 
         # validate user file paths and convert all paths to tree
         # relative : it's cheaper to make a tree relative path an abspath
@@ -453,6 +463,13 @@
             if illegalpath_re.search(directory.raw_path):
                 trace.warning("skipping %r (contains \\n or \\r)" % abspath)
                 continue
+            if directory.raw_path in conflicts_related:
+                # If the file looks like one generated for a conflict, don't
+                # add it.
+                trace.warning(
+                    'skipping %s (generated to help resolve conflicts)',
+                    abspath)
+                continue
 
             if parent_ie is not None:
                 versioned = directory.base_path in parent_ie.children

=== modified file 'bzrlib/tests/per_workingtree/test_smart_add.py'
--- a/bzrlib/tests/per_workingtree/test_smart_add.py	2010-02-08 10:49:48 +0000
+++ b/bzrlib/tests/per_workingtree/test_smart_add.py	2010-02-08 16:36:13 +0000
@@ -227,6 +227,36 @@
                                 in wt.inventory.iter_entries()])
 
 
+class TestSmartAddConflictRelatedFiles(per_workingtree.TestCaseWithWorkingTree):
+
+    def make_tree_with_text_conflict(self):
+        tb = self.make_branch_and_tree('base')
+        self.build_tree_contents([('base/file', 'content in base')])
+        tb.add('file')
+        tb.commit('Adding file')
+
+        t1 = tb.bzrdir.sprout('t1').open_workingtree()
+
+        self.build_tree_contents([('base/file', 'content changed in base')])
+        tb.commit('Changing file in base')
+
+        self.build_tree_contents([('t1/file', 'content in t1')])
+        t1.commit('Changing file in t1')
+        t1.merge_from_branch(tb.branch)
+        return t1
+
+    def test_cant_add_generated_files_implicitly(self):
+        t = self.make_tree_with_text_conflict()
+        added, ignored = t.smart_add([t.basedir])
+        self.assertEqual(([], {}), (added, ignored))
+
+    def test_can_add_generated_files_explicitly(self):
+        fnames = ['file.%s' % s  for s in ('BASE', 'THIS', 'OTHER')]
+        t = self.make_tree_with_text_conflict()
+        added, ignored = t.smart_add([t.basedir + '/%s' % f for f in fnames])
+        self.assertEqual((fnames, {}), (added, ignored))
+
+
 class TestSmartAddTreeUnicode(per_workingtree.TestCaseWithWorkingTree):
 
     _test_needs_features = [tests.UnicodeFilenameFeature]



More information about the bazaar-commits mailing list