Rev 4857: (andrew) Merge lp:bzr/2.0 into lp:bzr. in file:///home/pqm/archives/thelove/bzr/%2Btrunk/

Canonical.com Patch Queue Manager pqm at pqm.ubuntu.com
Thu Dec 3 05:08:08 GMT 2009


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

------------------------------------------------------------
revno: 4857 [merge]
revision-id: pqm at pqm.ubuntu.com-20091203050805-s70sybyrsrbbs10c
parent: pqm at pqm.ubuntu.com-20091203015454-c4ya8tkb3o084ae3
parent: andrew.bennetts at canonical.com-20091203022454-m2gyhbcdqi1t7ujz
committer: Canonical.com Patch Queue Manager <pqm at pqm.ubuntu.com>
branch nick: +trunk
timestamp: Thu 2009-12-03 05:08:05 +0000
message:
  (andrew) Merge lp:bzr/2.0 into lp:bzr.
modified:
  NEWS                           NEWS-20050323055033-4e00b5db738777ff
  bzrlib/branch.py               branch.py-20050309040759-e4baf4e0d046576e
  bzrlib/merge.py                merge.py-20050513021216-953b65a438527106
  bzrlib/push.py                 push.py-20080606021927-5fe39050e8xne9un-1
  bzrlib/tests/blackbox/test_push.py test_push.py-20060329002750-929af230d5d22663
  bzrlib/tests/per_workingtree/test_content_filters.py test_content_filters-20080424071441-8navsrmrfdxpn90a-1
  bzrlib/transform.py            transform.py-20060105172343-dd99e54394d91687
=== modified file 'NEWS'
--- a/NEWS	2009-12-02 18:10:32 +0000
+++ b/NEWS	2009-12-03 02:24:54 +0000
@@ -104,7 +104,13 @@
 
 Bug Fixes
 *********
-* Fix for shell completion and short options.  (Benoît PIERRE)
+
+* ``bzr push --use-existing-dir`` no longer crashes if the directory
+  exists but contains an invalid ``.bzr`` directory.
+  (Andrew Bennetts, #423563)
+
+* Content filters are now applied correctly after pull, merge and switch.
+  (Ian Clatworthy, #385879)
 
 * Improve "Binary files differ" hunk handling.  (Aaron Bentley, #436325)
 
@@ -344,6 +350,21 @@
   start reading 'inventories', etc.) This can have a significant impact on
   peak memory for initial copies (~200MB). (John Arbash Meinel)
 
+Improvements
+************
+
+Documentation
+*************
+
+API Changes
+***********
+
+Internals
+*********
+
+Testing
+*******
+
 
 bzr 2.0.2
 #########

=== modified file 'bzrlib/branch.py'
--- a/bzrlib/branch.py	2009-12-02 17:50:30 +0000
+++ b/bzrlib/branch.py	2009-12-03 02:24:54 +0000
@@ -1285,16 +1285,9 @@
         # clone call. Or something. 20090224 RBC/spiv.
         if revision_id is None:
             revision_id = self.last_revision()
-        try:
-            dir_to = self.bzrdir.clone_on_transport(to_transport,
-                revision_id=revision_id, stacked_on=stacked_on,
-                create_prefix=create_prefix, use_existing_dir=use_existing_dir)
-        except errors.FileExists:
-            if not use_existing_dir:
-                raise
-        except errors.NoSuchFile:
-            if not create_prefix:
-                raise
+        dir_to = self.bzrdir.clone_on_transport(to_transport,
+            revision_id=revision_id, stacked_on=stacked_on,
+            create_prefix=create_prefix, use_existing_dir=use_existing_dir)
         return dir_to.open_branch()
 
     def create_checkout(self, to_location, revision_id=None,

=== modified file 'bzrlib/merge.py'
--- a/bzrlib/merge.py	2009-10-06 14:40:37 +0000
+++ b/bzrlib/merge.py	2009-12-03 02:24:54 +0000
@@ -1150,8 +1150,22 @@
                 self.tt.delete_contents(trans_id)
             if file_id in self.other_tree:
                 # OTHER changed the file
+                wt = self.this_tree
+                if wt.supports_content_filtering():
+                    # We get the path from the working tree if it exists.
+                    # That fails though when OTHER is adding a file, so
+                    # we fall back to the other tree to find the path if
+                    # it doesn't exist locally.
+                    try:
+                        filter_tree_path = wt.id2path(file_id)
+                    except errors.NoSuchId:
+                        filter_tree_path = self.other_tree.id2path(file_id)
+                else:
+                    # Skip the id2path lookup for older formats
+                    filter_tree_path = None
                 transform.create_from_tree(self.tt, trans_id,
-                                           self.other_tree, file_id)
+                                 self.other_tree, file_id,
+                                 filter_tree_path=filter_tree_path)
                 if not file_in_this:
                     self.tt.version_file(file_id, trans_id)
                 return "modified"
@@ -1244,12 +1258,26 @@
                 ('THIS', self.this_tree, this_lines)]
         if not no_base:
             data.append(('BASE', self.base_tree, base_lines))
+
+        # We need to use the actual path in the working tree of the file here,
+        # ignoring the conflict suffixes
+        wt = self.this_tree
+        if wt.supports_content_filtering():
+            try:
+                filter_tree_path = wt.id2path(file_id)
+            except errors.NoSuchId:
+                # file has been deleted
+                filter_tree_path = None
+        else:
+            # Skip the id2path lookup for older formats
+            filter_tree_path = None
+
         versioned = False
         file_group = []
         for suffix, tree, lines in data:
             if file_id in tree:
                 trans_id = self._conflict_file(name, parent_id, tree, file_id,
-                                               suffix, lines)
+                                               suffix, lines, filter_tree_path)
                 file_group.append(trans_id)
                 if set_version and not versioned:
                     self.tt.version_file(file_id, trans_id)
@@ -1257,11 +1285,12 @@
         return file_group
 
     def _conflict_file(self, name, parent_id, tree, file_id, suffix,
-                       lines=None):
+                       lines=None, filter_tree_path=None):
         """Emit a single conflict file."""
         name = name + '.' + suffix
         trans_id = self.tt.create_path(name, parent_id)
-        transform.create_from_tree(self.tt, trans_id, tree, file_id, lines)
+        transform.create_from_tree(self.tt, trans_id, tree, file_id, lines,
+            filter_tree_path)
         return trans_id
 
     def merge_executable(self, file_id, file_status):

=== modified file 'bzrlib/push.py'
--- a/bzrlib/push.py	2009-07-18 21:09:00 +0000
+++ b/bzrlib/push.py	2009-11-25 06:10:00 +0000
@@ -90,12 +90,19 @@
             br_to = br_from.create_clone_on_transport(to_transport,
                 revision_id=revision_id, stacked_on=stacked_on,
                 create_prefix=create_prefix, use_existing_dir=use_existing_dir)
-        except errors.FileExists:
+        except errors.FileExists, err:
+            if err.path.endswith('/.bzr'):
+                raise errors.BzrCommandError(
+                    "Target directory %s already contains a .bzr directory, "
+                    "but it is not valid." % (location,))
             if not use_existing_dir:
                 raise errors.BzrCommandError("Target directory %s"
-                     " already exists, but does not have a valid .bzr"
+                     " already exists, but does not have a .bzr"
                      " directory. Supply --use-existing-dir to push"
                      " there anyway." % location)
+            # This shouldn't occur, but if it does the FileExists error will be
+            # more informative than an UnboundLocalError for br_to.
+            raise
         except errors.NoSuchFile:
             if not create_prefix:
                 raise errors.BzrCommandError("Parent directory of %s"

=== modified file 'bzrlib/tests/blackbox/test_push.py'
--- a/bzrlib/tests/blackbox/test_push.py	2009-10-02 11:35:02 +0000
+++ b/bzrlib/tests/blackbox/test_push.py	2009-12-03 02:24:54 +0000
@@ -335,6 +335,17 @@
         # The push should have created target/a
         self.failUnlessExists('target/a')
 
+    def test_push_use_existing_into_empty_bzrdir(self):
+        """'bzr push --use-existing-dir' into a dir with an empty .bzr dir
+        fails.
+        """
+        tree = self.create_simple_tree()
+        self.build_tree(['target/', 'target/.bzr/'])
+        self.run_bzr_error(
+            ['Target directory ../target already contains a .bzr directory, '
+             'but it is not valid.'],
+            'push ../target --use-existing-dir', working_dir='tree')
+
     def test_push_onto_repo(self):
         """We should be able to 'bzr push' into an existing bzrdir."""
         tree = self.create_simple_tree()

=== modified file 'bzrlib/tests/per_workingtree/test_content_filters.py'
--- a/bzrlib/tests/per_workingtree/test_content_filters.py	2009-10-28 01:16:10 +0000
+++ b/bzrlib/tests/per_workingtree/test_content_filters.py	2009-10-28 23:34:13 +0000
@@ -18,7 +18,9 @@
 
 import os
 
+from bzrlib.bzrdir import BzrDir
 from bzrlib.filters import ContentFilter
+from bzrlib.switch import switch
 from bzrlib.workingtree import WorkingTree
 from bzrlib.tests.per_workingtree import TestCaseWithWorkingTree
 
@@ -83,6 +85,38 @@
         bin_fileid = tree.path2id('file2.bin')
         return tree, txt_fileid, bin_fileid
 
+    def create_cf_tree_with_two_revisions(self, txt_reader, txt_writer,
+        dir='.'):
+        tree = self.make_branch_and_tree(dir)
+        def _content_filter_stack(path=None, file_id=None):
+            if path.endswith('.txt'):
+                return [ContentFilter(txt_reader, txt_writer)]
+            else:
+                return []
+        tree._content_filter_stack = _content_filter_stack
+        self.build_tree_contents([
+            (dir + '/file1.txt', 'Foo Txt'),
+            (dir + '/file2.bin', 'Foo Bin'),
+            (dir + '/file3.txt', 'Bar Txt'),
+            ])
+        tree.add(['file1.txt', 'file2.bin', 'file3.txt'])
+        tree.commit('commit raw content')
+        fileid_1 = tree.path2id('file1.txt')
+        fileid_2 = tree.path2id('file2.bin')
+        fileid_3 = tree.path2id('file3.txt')
+        # Commit another revision with various changes. We make sure
+        # the change includes a modification, an addition and a deletion.
+        # Renames are more complex and need a separate set of tests later.
+        self.build_tree_contents([
+            (dir + '/file1.txt', 'Foo ROCKS!'),
+            (dir + '/file4.txt', 'Hello World'),
+            ])
+        tree.add(['file4.txt'])
+        tree.remove(['file3.txt'], keep_files=False)
+        tree.commit("change, add and rename stuff")
+        fileid_4 = tree.path2id('file4.txt')
+        return tree, fileid_1, fileid_2, fileid_3, fileid_4
+
     def patch_in_content_filter(self):
         # Patch in a custom, symmetric content filter stack. It's pretty gross
         # that we need to monkey-patch a class method to do this, bit it's
@@ -222,6 +256,89 @@
         # that will be expensive to compute, so it's acceptable to just return
         # None.
 
+    def test_content_filtering_applied_on_pull(self):
+        # Create a source branch with two revisions
+        source, fileid_1, fileid_2, fileid_3, fileid_4 = \
+            self.create_cf_tree_with_two_revisions(txt_reader=None,
+            txt_writer=None, dir='source')
+        if not source.supports_content_filtering():
+            return
+        self.assertFileEqual("Foo ROCKS!", 'source/file1.txt')
+        self.assert_basis_content("Foo ROCKS!", source, fileid_1)
+
+        # Now patch in content filtering and branch from revision 1
+        self.patch_in_content_filter()
+        self.run_bzr('branch -r1 source target')
+        target = WorkingTree.open('target')
+        self.assert_basis_content("Foo Txt", target, fileid_1)
+        self.assertFileEqual("fOO tXT", 'target/file1.txt')
+        self.assert_basis_content("Foo Bin", target, fileid_2)
+        self.assertFileEqual("Foo Bin", 'target/file2.bin')
+        self.assert_basis_content("Bar Txt", target, fileid_3)
+        self.assertFileEqual("bAR tXT", 'target/file3.txt')
+
+        # Pull the latter change and check the target tree is updated
+        self.run_bzr('pull -d target')
+        self.assert_basis_content("Foo ROCKS!", target, fileid_1)
+        self.assertFileEqual("fOO rocks!", 'target/file1.txt')
+        self.assert_basis_content("Foo Bin", target, fileid_2)
+        self.assert_basis_content("Hello World", target, fileid_4)
+        self.assertFileEqual("hELLO wORLD", 'target/file4.txt')
+
+    def test_content_filtering_applied_on_merge(self):
+        # Create a source branch with two revisions
+        source, fileid_1, fileid_2, fileid_3, fileid_4 = \
+            self.create_cf_tree_with_two_revisions(txt_reader=None,
+            txt_writer=None, dir='source')
+        if not source.supports_content_filtering():
+            return
+        self.assert_basis_content("Foo ROCKS!", source, fileid_1)
+        self.assertFileEqual("Foo ROCKS!", 'source/file1.txt')
+        self.assert_basis_content("Foo Bin", source, fileid_2)
+        self.assert_basis_content("Hello World", source, fileid_4)
+        self.assertFileEqual("Hello World", 'source/file4.txt')
+
+        # Now patch in content filtering and branch from revision 1
+        self.patch_in_content_filter()
+        self.run_bzr('branch -r1 source target')
+        target = WorkingTree.open('target')
+        self.assert_basis_content("Foo Txt", target, fileid_1)
+        self.assertFileEqual("fOO tXT", 'target/file1.txt')
+        self.assertFileEqual("Foo Bin", 'target/file2.bin')
+        self.assertFileEqual("bAR tXT", 'target/file3.txt')
+
+        # Merge the latter change and check the target tree is updated
+        self.run_bzr('merge -d target source')
+        self.assertFileEqual("fOO rocks!", 'target/file1.txt')
+        self.assertFileEqual("hELLO wORLD", 'target/file4.txt')
+
+        # Commit the merge and check the right content is stored
+        target.commit("merge file1.txt changes from source")
+        self.assert_basis_content("Foo ROCKS!", target, fileid_1)
+        self.assert_basis_content("Hello World", target, fileid_4)
+
+    def test_content_filtering_applied_on_switch(self):
+        # Create a source branch with two revisions
+        source, fileid_1, fileid_2, fileid_3, fileid_4 = \
+            self.create_cf_tree_with_two_revisions(txt_reader=None,
+            txt_writer=None, dir='branch-a')
+        if not source.supports_content_filtering():
+            return
+
+        # Now patch in content filtering and branch from revision 1
+        self.patch_in_content_filter()
+        self.run_bzr('branch -r1 branch-a branch-b')
+
+        # Now create a lightweight checkout referring to branch-b
+        self.run_bzr('checkout --lightweight branch-b checkout')
+        self.assertFileEqual("fOO tXT", 'checkout/file1.txt')
+
+        # Switch it to branch-b and check the tree is updated
+        checkout_control_dir = BzrDir.open_containing('checkout')[0]
+        switch(checkout_control_dir, source.branch)
+        self.assertFileEqual("fOO rocks!", 'checkout/file1.txt')
+        self.assertFileEqual("hELLO wORLD", 'checkout/file4.txt')
+
     def test_content_filtering_applied_on_revert_delete(self):
         # Create a source branch with content filtering
         source, txt_fileid, bin_fileid = self.create_cf_tree(

=== modified file 'bzrlib/transform.py'
--- a/bzrlib/transform.py	2009-11-10 19:45:43 +0000
+++ b/bzrlib/transform.py	2009-12-03 02:24:54 +0000
@@ -2430,8 +2430,14 @@
         tt.create_directory(trans_id)
 
 
-def create_from_tree(tt, trans_id, tree, file_id, bytes=None):
-    """Create new file contents according to tree contents."""
+def create_from_tree(tt, trans_id, tree, file_id, bytes=None,
+    filter_tree_path=None):
+    """Create new file contents according to tree contents.
+    
+    :param filter_tree_path: the tree path to use to lookup
+      content filters to apply to the bytes output in the working tree.
+      This only applies if the working tree supports content filtering.
+    """
     kind = tree.kind(file_id)
     if kind == 'directory':
         tt.create_directory(trans_id)
@@ -2442,6 +2448,11 @@
                 bytes = tree_file.readlines()
             finally:
                 tree_file.close()
+        wt = tt._tree
+        if wt.supports_content_filtering() and filter_tree_path is not None:
+            filters = wt._content_filter_stack(filter_tree_path)
+            bytes = filtered_output_bytes(bytes, filters,
+                ContentFilterContext(filter_tree_path, tree))
         tt.create_file(bytes, trans_id)
     elif kind == "symlink":
         tt.create_symlink(tree.get_symlink_target(file_id), trans_id)




More information about the bazaar-commits mailing list