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