Rev 4777: (jam) Merge lp:bzr/2.0 4696 into lp:bzr in file:///home/pqm/archives/thelove/bzr/%2Btrunk/

Canonical.com Patch Queue Manager pqm at pqm.ubuntu.com
Thu Oct 29 22:00:45 GMT 2009


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

------------------------------------------------------------
revno: 4777 [merge]
revision-id: pqm at pqm.ubuntu.com-20091029220043-u2qbo0ci5867xniz
parent: pqm at pqm.ubuntu.com-20091029080429-lyew1dt9mf17vuje
parent: john at arbash-meinel.com-20091029211316-d70fv1sxe2ev9rhy
committer: Canonical.com Patch Queue Manager <pqm at pqm.ubuntu.com>
branch nick: +trunk
timestamp: Thu 2009-10-29 22:00:43 +0000
message:
  (jam) Merge lp:bzr/2.0 4696 into lp:bzr
modified:
  NEWS                           NEWS-20050323055033-4e00b5db738777ff
  bzrlib/builtins.py             builtins.py-20050830033751-fc01482b9ca23183
  bzrlib/log.py                  log.py-20050505065812-c40ce11702fe5fb1
  bzrlib/merge_directive.py      merge_directive.py-20070228184838-ja62280spt1g7f4x-1
  bzrlib/tests/__init__.py       selftest.py-20050531073622-8d0e3c8845c97a64
  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-10-29 05:57:55 +0000
+++ b/NEWS	2009-10-29 21:13:16 +0000
@@ -125,18 +125,30 @@
 * Avoid "NoneType has no attribute st_mode" error when files disappear
   from a directory while it's being read.  (Martin Pool, #446033)
 
+* Content filters are now applied correctly after revert.
+  (Ian Clatworthy)
+
 * Diff parsing handles "Binary files differ" hunks.  (Aaron Bentley, #436325)
 
 * Fetching from stacked pre-2a repository via a smart server no longer
   fails intermittently with "second push failed to complete".
   (Andrew Bennetts, #437626)
 
+* Fix typos left after test_selftest refactoring.
+  (Vincent Ladeuil, Matt Nordhoff, #461149)
+
+* Fixed ``ObjectNotLocked`` errors during ``bzr log -r NNN somefile``.
+  (Andrew Bennetts, #445171)
+  
 * PreviewTree file names are not limited by the encoding of the temp
   directory's filesystem. (Aaron Bentley, #436794)
 
 Improvements
 ************
 
+* ``bzr log`` now read-locks branches exactly once, so makes better use of
+  data caches.  (Andrew Bennetts)
+
 Documentation
 *************
 

=== modified file 'bzrlib/builtins.py'
--- a/bzrlib/builtins.py	2009-10-29 05:54:49 +0000
+++ b/bzrlib/builtins.py	2009-10-29 21:13:16 +0000
@@ -2276,50 +2276,51 @@
 
         file_ids = []
         filter_by_dir = False
-        if file_list:
-            # find the file ids to log and check for directory filtering
-            b, file_info_list, rev1, rev2 = _get_info_for_log_files(revision,
-                file_list)
-            for relpath, file_id, kind in file_info_list:
-                if file_id is None:
-                    raise errors.BzrCommandError(
-                        "Path unknown at end or start of revision range: %s" %
-                        relpath)
-                # If the relpath is the top of the tree, we log everything
-                if relpath == '':
-                    file_ids = []
-                    break
+        b = None
+        try:
+            if file_list:
+                # find the file ids to log and check for directory filtering
+                b, file_info_list, rev1, rev2 = _get_info_for_log_files(
+                    revision, file_list)
+                for relpath, file_id, kind in file_info_list:
+                    if file_id is None:
+                        raise errors.BzrCommandError(
+                            "Path unknown at end or start of revision range: %s" %
+                            relpath)
+                    # If the relpath is the top of the tree, we log everything
+                    if relpath == '':
+                        file_ids = []
+                        break
+                    else:
+                        file_ids.append(file_id)
+                    filter_by_dir = filter_by_dir or (
+                        kind in ['directory', 'tree-reference'])
+            else:
+                # log everything
+                # FIXME ? log the current subdir only RBC 20060203
+                if revision is not None \
+                        and len(revision) > 0 and revision[0].get_branch():
+                    location = revision[0].get_branch()
                 else:
-                    file_ids.append(file_id)
-                filter_by_dir = filter_by_dir or (
-                    kind in ['directory', 'tree-reference'])
-        else:
-            # log everything
-            # FIXME ? log the current subdir only RBC 20060203
-            if revision is not None \
-                    and len(revision) > 0 and revision[0].get_branch():
-                location = revision[0].get_branch()
-            else:
-                location = '.'
-            dir, relpath = bzrdir.BzrDir.open_containing(location)
-            b = dir.open_branch()
-            rev1, rev2 = _get_revision_range(revision, b, self.name())
-
-        # Decide on the type of delta & diff filtering to use
-        # TODO: add an --all-files option to make this configurable & consistent
-        if not verbose:
-            delta_type = None
-        else:
-            delta_type = 'full'
-        if not show_diff:
-            diff_type = None
-        elif file_ids:
-            diff_type = 'partial'
-        else:
-            diff_type = 'full'
-
-        b.lock_read()
-        try:
+                    location = '.'
+                dir, relpath = bzrdir.BzrDir.open_containing(location)
+                b = dir.open_branch()
+                b.lock_read()
+                rev1, rev2 = _get_revision_range(revision, b, self.name())
+
+            # Decide on the type of delta & diff filtering to use
+            # TODO: add an --all-files option to make this configurable & consistent
+            if not verbose:
+                delta_type = None
+            else:
+                delta_type = 'full'
+            if not show_diff:
+                diff_type = None
+            elif file_ids:
+                diff_type = 'partial'
+            else:
+                diff_type = 'full'
+
             # Build the log formatter
             if log_format is None:
                 log_format = log.log_formatter_registry.get_default(b)
@@ -2355,7 +2356,8 @@
                 diff_type=diff_type, _match_using_deltas=match_using_deltas)
             Logger(b, rqst).show(lf)
         finally:
-            b.unlock()
+            if b is not None:
+                b.unlock()
 
 
 def _get_revision_range(revisionspec_list, branch, command_name):
@@ -2425,10 +2427,15 @@
     @display_command
     def run(self, filename):
         tree, relpath = WorkingTree.open_containing(filename)
+        file_id = tree.path2id(relpath)
         b = tree.branch
-        file_id = tree.path2id(relpath)
-        for revno, revision_id, what in log.find_touching_revisions(b, file_id):
-            self.outf.write("%6d %s\n" % (revno, what))
+        b.lock_read()
+        try:
+            touching_revs = log.find_touching_revisions(b, file_id)
+            for revno, revision_id, what in touching_revs:
+                self.outf.write("%6d %s\n" % (revno, what))
+        finally:
+            b.unlock()
 
 
 class cmd_ls(Command):

=== modified file 'bzrlib/log.py'
--- a/bzrlib/log.py	2009-06-10 03:56:49 +0000
+++ b/bzrlib/log.py	2009-10-29 03:32:42 +0000
@@ -1846,9 +1846,11 @@
     :return: (branch, info_list, start_rev_info, end_rev_info) where
       info_list is a list of (relative_path, file_id, kind) tuples where
       kind is one of values 'directory', 'file', 'symlink', 'tree-reference'.
+      branch will be read-locked.
     """
     from builtins import _get_revision_range, safe_relpath_files
     tree, b, path = bzrdir.BzrDir.open_containing_tree_or_branch(file_list[0])
+    b.lock_read()
     # XXX: It's damn messy converting a list of paths to relative paths when
     # those paths might be deleted ones, they might be on a case-insensitive
     # filesystem and/or they might be in silly locations (like another branch).

=== modified file 'bzrlib/merge_directive.py'
--- a/bzrlib/merge_directive.py	2009-05-11 19:11:14 +0000
+++ b/bzrlib/merge_directive.py	2009-10-29 05:49:32 +0000
@@ -582,11 +582,13 @@
                     revision_id):
                     raise errors.PublicBranchOutOfDate(public_branch,
                                                        revision_id)
+            testament_sha1 = t.as_sha1()
         finally:
             for entry in reversed(locked):
                 entry.unlock()
-        return klass(revision_id, t.as_sha1(), time, timezone, target_branch,
-            patch, public_branch, message, bundle, base_revision_id)
+        return klass(revision_id, testament_sha1, time, timezone,
+            target_branch, patch, public_branch, message, bundle,
+            base_revision_id)
 
     def _verify_patch(self, repository):
         calculated_patch = self._generate_diff(repository, self.revision_id,

=== modified file 'bzrlib/tests/__init__.py'
--- a/bzrlib/tests/__init__.py	2009-10-28 00:12:03 +0000
+++ b/bzrlib/tests/__init__.py	2009-10-29 21:13:16 +0000
@@ -53,6 +53,7 @@
 from bzrlib import (
     branchbuilder,
     bzrdir,
+    chk_map,
     config,
     debug,
     errors,
@@ -1790,6 +1791,9 @@
 
     def _run_bzr_core(self, args, retcode, encoding, stdin,
             working_dir):
+        # Clear chk_map page cache, because the contents are likely to mask
+        # locking errors.
+        chk_map.clear_cache()
         if encoding is None:
             encoding = osutils.get_user_encoding()
         stdout = StringIOWrapper()

=== modified file 'bzrlib/tests/per_workingtree/test_content_filters.py'
--- a/bzrlib/tests/per_workingtree/test_content_filters.py	2009-08-25 04:43:21 +0000
+++ b/bzrlib/tests/per_workingtree/test_content_filters.py	2009-10-28 01:16:10 +0000
@@ -16,6 +16,8 @@
 
 """Tests for content filtering conformance"""
 
+import os
+
 from bzrlib.filters import ContentFilter
 from bzrlib.workingtree import WorkingTree
 from bzrlib.tests.per_workingtree import TestCaseWithWorkingTree
@@ -81,6 +83,33 @@
         bin_fileid = tree.path2id('file2.bin')
         return tree, txt_fileid, bin_fileid
 
+    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
+        # the easiest way currently given we don't have easy access to the
+        # WorkingTree after it is created but before the filter stack is used
+        # to populate content.
+        self.real_content_filter_stack = WorkingTree._content_filter_stack
+        def restore_real_content_filter_stack():
+            WorkingTree._content_filter_stack = self.real_content_filter_stack
+        self.addCleanup(restore_real_content_filter_stack)
+        def _content_filter_stack(tree, path=None, file_id=None):
+            if path.endswith('.txt'):
+                return [ContentFilter(_swapcase, _swapcase)]
+            else:
+                return []
+        WorkingTree._content_filter_stack = _content_filter_stack
+
+    def assert_basis_content(self, expected_content, branch, file_id):
+        # Note: We need to use try/finally here instead of addCleanup()
+        # as the latter leaves the read lock in place too long
+        basis = branch.basis_tree()
+        basis.lock_read()
+        try:
+            self.assertEqual(expected_content, basis.get_file_text(file_id))
+        finally:
+            basis.unlock()
+
     def test_symmetric_content_filtering(self):
         # test handling when read then write gives back the initial content
         tree, txt_fileid, bin_fileid = self.create_cf_tree(
@@ -132,10 +161,7 @@
         if not source.supports_content_filtering():
             return
         self.assertFileEqual("Foo Txt", 'source/file1.txt')
-        basis = source.basis_tree()
-        basis.lock_read()
-        self.addCleanup(basis.unlock)
-        self.assertEqual("FOO TXT", basis.get_file_text(txt_fileid))
+        self.assert_basis_content("FOO TXT", source, txt_fileid)
 
         # Now branch it
         self.run_bzr('branch source target')
@@ -153,24 +179,10 @@
         if not source.supports_content_filtering():
             return
         self.assertFileEqual("Foo Txt", 'source/file1.txt')
-        basis = source.basis_tree()
-        basis.lock_read()
-        self.addCleanup(basis.unlock)
-        self.assertEqual("Foo Txt", basis.get_file_text(txt_fileid))
-
-        # Patch in a custom, symmetric content filter stack
-        self.real_content_filter_stack = WorkingTree._content_filter_stack
-        def restore_real_content_filter_stack():
-            WorkingTree._content_filter_stack = self.real_content_filter_stack
-        self.addCleanup(restore_real_content_filter_stack)
-        def _content_filter_stack(tree, path=None, file_id=None):
-            if path.endswith('.txt'):
-                return [ContentFilter(_swapcase, _swapcase)]
-            else:
-                return []
-        WorkingTree._content_filter_stack = _content_filter_stack
-
-        # Now branch it
+        self.assert_basis_content("Foo Txt", source, txt_fileid)
+
+        # Now patch in content filtering and branch the source
+        self.patch_in_content_filter()
         self.run_bzr('branch source target')
         target = WorkingTree.open('target')
         # Even though the content in source and target are different
@@ -209,3 +221,44 @@
         # we could give back the length of the canonical form, but in general
         # that will be expensive to compute, so it's acceptable to just return
         # None.
+
+    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(
+            txt_reader=_uppercase, txt_writer=_lowercase, dir='source')
+        if not source.supports_content_filtering():
+            return
+        self.assertFileEqual("Foo Txt", 'source/file1.txt')
+        self.assert_basis_content("FOO TXT", source, txt_fileid)
+
+        # Now delete the file, revert it and check the content
+        os.unlink('source/file1.txt')
+        self.assertFalse(os.path.exists('source/file1.txt'))
+        source.revert(['file1.txt'])
+        self.assertTrue(os.path.exists('source/file1.txt'))
+        # Note: we don't get back exactly what was in the tree
+        # previously because lower(upper(text)) is a lossy transformation
+        self.assertFileEqual("foo txt", 'source/file1.txt')
+
+    def test_content_filtering_applied_on_revert_rename(self):
+        # Create a source branch with content filtering
+        source, txt_fileid, bin_fileid = self.create_cf_tree(
+            txt_reader=_uppercase, txt_writer=_lowercase, dir='source')
+        if not source.supports_content_filtering():
+            return
+        self.assertFileEqual("Foo Txt", 'source/file1.txt')
+        self.assert_basis_content("FOO TXT", source, txt_fileid)
+
+        # Now modify & rename a file, revert it and check the content
+        self.build_tree_contents([
+            ('source/file1.txt', 'Foo Txt with new content')])
+        source.rename_one('file1.txt', 'file1.bin')
+        self.assertTrue(os.path.exists('source/file1.bin'))
+        self.assertFalse(os.path.exists('source/file1.txt'))
+        self.assertFileEqual("Foo Txt with new content", 'source/file1.bin')
+        source.revert(['file1.bin'])
+        self.assertFalse(os.path.exists('source/file1.bin'))
+        self.assertTrue(os.path.exists('source/file1.txt'))
+        # Note: we don't get back exactly what was in the tree
+        # previously because lower(upper(text)) is a lossy transformation
+        self.assertFileEqual("foo txt", 'source/file1.txt')

=== modified file 'bzrlib/transform.py'
--- a/bzrlib/transform.py	2009-10-26 06:44:40 +0000
+++ b/bzrlib/transform.py	2009-10-29 21:13:16 +0000
@@ -2639,9 +2639,22 @@
                 tt.adjust_path(name[1], parent_trans, trans_id)
             if executable[0] != executable[1] and kind[1] == "file":
                 tt.set_executability(executable[1], trans_id)
-        for (trans_id, mode_id), bytes in target_tree.iter_files_bytes(
-            deferred_files):
-            tt.create_file(bytes, trans_id, mode_id)
+        if working_tree.supports_content_filtering():
+            for index, ((trans_id, mode_id), bytes) in enumerate(
+                target_tree.iter_files_bytes(deferred_files)):
+                file_id = deferred_files[index][0]
+                # We're reverting a tree to the target tree so using the
+                # target tree to find the file path seems the best choice
+                # here IMO - Ian C 27/Oct/2009
+                filter_tree_path = target_tree.id2path(file_id)
+                filters = working_tree._content_filter_stack(filter_tree_path)
+                bytes = filtered_output_bytes(bytes, filters,
+                    ContentFilterContext(filter_tree_path, working_tree))
+                tt.create_file(bytes, trans_id, mode_id)
+        else:
+            for (trans_id, mode_id), bytes in target_tree.iter_files_bytes(
+                deferred_files):
+                tt.create_file(bytes, trans_id, mode_id)
     finally:
         if basis_tree is not None:
             basis_tree.unlock()




More information about the bazaar-commits mailing list