Rev 4660: (mbp) merge 1.18 and 2.0 back to trunk; bump version to 2.1 in file:///home/pqm/archives/thelove/bzr/%2Btrunk/

Canonical.com Patch Queue Manager pqm at pqm.ubuntu.com
Fri Aug 28 07:40:35 BST 2009


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

------------------------------------------------------------
revno: 4660 [merge]
revision-id: pqm at pqm.ubuntu.com-20090828064033-q7eyzxnnyc3jcpag
parent: pqm at pqm.ubuntu.com-20090827132024-h13eo7blndo2dfpl
parent: mbp at sourcefrog.net-20090828051110-wk4cr5yrqf2v467t
committer: Canonical.com Patch Queue Manager <pqm at pqm.ubuntu.com>
branch nick: +trunk
timestamp: Fri 2009-08-28 07:40:33 +0100
message:
  (mbp) merge 1.18 and 2.0 back to trunk; bump version to 2.1
modified:
  NEWS                           NEWS-20050323055033-4e00b5db738777ff
  bzr                            bzr.py-20050313053754-5485f144c7006fa6
  bzrlib/__init__.py             __init__.py-20050309040759-33e65acf91bbcd5d
  bzrlib/_known_graph_pyx.pyx    _known_graph_pyx.pyx-20090610194911-yjk73td9hpjilas0-1
  bzrlib/commit.py               commit.py-20050511101309-79ec1a0168e0e825
  bzrlib/repofmt/groupcompress_repo.py repofmt.py-20080715094215-wp1qfvoo7093c8qr-1
  bzrlib/repository.py           rev_storage.py-20051111201905-119e9401e46257e3
  bzrlib/tests/per_tree/test_path_content_summary.py test_path_content_su-20070904100855-3vrwedz6akn34kl5-1
  bzrlib/tests/per_workingtree/test_content_filters.py test_content_filters-20080424071441-8navsrmrfdxpn90a-1
  bzrlib/tests/test__known_graph.py test__known_graph.py-20090610185421-vw8vfda2cgnckgb1-2
  bzrlib/tests/test_shelf.py     test_prepare_shelf.p-20081005181341-n74qe6gu1e65ad4v-2
  bzrlib/tree.py                 tree.py-20050309040759-9d5f2496be663e77
  bzrlib/tsort.py                tsort.py-20051025073946-7808f6aaf7d07208
  bzrlib/workingtree.py          workingtree.py-20050511021032-29b6ec0a681e02e3
  bzrlib/workingtree_4.py        workingtree_4.py-20070208044105-5fgpc5j3ljlh5q6c-1
=== modified file 'NEWS'
--- a/NEWS	2009-08-27 13:20:24 +0000
+++ b/NEWS	2009-08-28 05:00:33 +0000
@@ -12,6 +12,72 @@
 Compatibility Breaks
 ********************
 
+New Features
+************
+
+Bug Fixes
+*********
+
+Improvements
+************
+
+Documentation
+*************
+
+API Changes
+***********
+
+* ``bzrlib.tests`` now uses ``stopTestRun`` for its ``TestResult``
+  subclasses - the same as python's unittest module. (Robert Collins)
+
+Internals
+*********
+
+* The ``bzrlib.lsprof`` module has a new class ``BzrProfiler`` which makes
+  profiling in some situations like callbacks and generators easier.
+  (Robert Collins)
+
+Testing
+*******
+
+* Passing ``--lsprof-tests -v`` to bzr selftest will cause lsprof output to
+  be output for every test. Note that this is very verbose! (Robert Collins)
+
+* Test parameterisation now does a shallow copy, not a deep copy of the test
+  to be parameterised. This is not expected to break external use of test
+  parameterisation, and is substantially faster. (Robert Collins)
+
+
+bzr 2.0rc2
+##########
+
+Bug Fixes
+*********
+
+* Fix a potential segmentation fault when doing 'log' of a branch that had
+  ghosts in its mainline. (evaluating None as a tuple is bad.)
+  (John Arbash Meinel, #419241)
+
+
+bzr 2.0rc1
+##########
+
+
+:Codename: no worries
+:2.0rc1: 2009-08-26
+
+This release of Bazaar makes 2a 'brisbane-core' format the
+default.  Most of the work in this release now focuses on bug
+fixes and stabilization, covering both 2a and previous formats.
+
+The Bazaar team decided that 2.0 will be a long-term supported
+release, with bugfix-only releases based on it continuing for at
+least six months or until the following stable release (we said
+that previously, but that's worth repeating).
+
+Compatibility Breaks
+********************
+
 * The default format for bzr is now ``2a``. This format brings many
   significant performance and size improvements. bzr can pull from
   any existing repository into a ``2a`` one, but can only transfer
@@ -32,6 +98,15 @@
 Bug Fixes
 *********
 
+* Further tweaks to handling of ``bzr add`` messages about ignored files.
+  (Jason Spashett, #76616)
+
+* Fetches were being requested in 'groupcompress' order, but weren't
+  recombining the groups. Thus they would 'fragment' to get the correct
+  order, but not 'recombine' to actually benefit from it. Until we get
+  recombining to work, switching to 'unordered' fetches avoids the
+  fragmentation. (John Arbash Meinel, #402645)
+
 * Fix a pycurl related test failure on karmic by recognizing an error
   raised by newer versions of pycurl.
   (Vincent Ladeuil, #306264)
@@ -46,6 +121,11 @@
   or when doing fetches from a stacked source to a stacked target.
   (Andrew Bennetts, #399140)
 
+* ``bzr branch`` of 2a repositories over HTTP is much faster.  bzr now
+  batches together small fetches from 2a repositories, rather than
+  fetching only a few hundred bytes at a time.
+  (Andrew Bennetts, #402657)
+
 Improvements
 ************
 
@@ -90,25 +170,38 @@
   classes changed to manage lock lifetime of the trees they open in a way
   consistent with reader-exclusive locks. (Robert Collins, #305006)
 
-* ``bzrlib.tests`` now uses ``stopTestRun`` for its ``TestResult``
-  subclasses - the same as python's unittest module. (Robert Collins)
-
-Internals
-*********
-
-* The ``bzrlib.lsprof`` module has a new class ``BzrProfiler`` which makes
-  profiling in some situations like callbacks and generators easier.
-  (Robert Collins)
-
 Testing
 *******
 
-* Passing ``--lsprof-tests -v`` to bzr selftest will cause lsprof output to
-  be output for every test. Note that this is very verbose! (Robert Collins)
-
-* Test parameterisation now does a shallow copy, not a deep copy of the test
-  to be parameterised. This is not expected to break external use of test
-  parameterisation, and is substantially faster. (Robert Collins)
+bzr 1.18.1 NOT RELEASED YET
+###########################
+
+Bug Fixes
+*********
+
+* Fixed a problem where using content filtering and especially end-of-line
+  conversion will commit too many copies a file.
+  (Martin Pool, #415508)
+
+Improvements
+************
+
+* ``bzr push`` locally on windows will no longer give a locking error with
+  dirstate based formats. (Robert Collins)
+
+* ``bzr shelve`` and ``bzr unshelve`` now work on windows.
+  (Robert Collins, #305006)
+
+API Changes
+***********
+
+* ``bzrlib.shelf_ui`` has had the ``from_args`` convenience methods of its
+  classes changed to manage lock lifetime of the trees they open in a way
+  consistent with reader-exclusive locks. (Robert Collins, #305006)
+
+* ``Tree.path_content_summary`` may return a size of None, when called on
+  a tree with content filtering where the size of the canonical form
+  cannot be cheaply determined.  (Martin Pool)
 
 bzr 1.18
 ########
@@ -225,6 +318,7 @@
 ###########
 
 :Codename: little traveller
+:1.18:    2009-08-20
 :1.18rc1: 2009-08-10
 
 This release of Bazaar marches on towards the 2.0 release in which the 2a
@@ -238,6 +332,7 @@
 with bugfix-only releases based on it continuing for at least six months
 or until the following stable release.
 
+There are no changes from 1.18rc1 to 1.18.
 
 New Features
 ************
@@ -444,6 +539,17 @@
   ``countTestsCases``. (Robert Collins)
 
 
+bzr 1.17.1 (unreleased)
+#######################
+
+Bug Fixes
+*********
+
+* The optional ``_knit_load_data_pyx`` C extension was never being
+  imported.  This caused significant slowdowns when reading data from
+  knit format repositories.  (Andrew Bennetts, #405653)
+  
+
 bzr 1.17 "So late it's brunch" 2009-07-20
 #########################################
 :Codename: so-late-its-brunch

=== modified file 'bzr'
--- a/bzr	2009-08-11 03:02:56 +0000
+++ b/bzr	2009-08-28 05:11:10 +0000
@@ -23,7 +23,7 @@
 import warnings
 
 # update this on each release
-_script_version = (2, 0, 0)
+_script_version = (2, 1, 0)
 
 if __doc__ is None:
     print "bzr does not support python -OO."

=== modified file 'bzrlib/__init__.py'
--- a/bzrlib/__init__.py	2009-08-11 03:02:56 +0000
+++ b/bzrlib/__init__.py	2009-08-28 04:13:16 +0000
@@ -50,7 +50,7 @@
 # Python version 2.0 is (2, 0, 0, 'final', 0)."  Additionally we use a
 # releaselevel of 'dev' for unreleased under-development code.
 
-version_info = (2, 0, 0, 'dev', 0)
+version_info = (2, 1, 0, 'dev', 0)
 
 # API compatibility version: bzrlib is currently API compatible with 1.15.
 api_minimum_version = (1, 17, 0)

=== modified file 'bzrlib/_known_graph_pyx.pyx'
--- a/bzrlib/_known_graph_pyx.pyx	2009-08-18 21:41:08 +0000
+++ b/bzrlib/_known_graph_pyx.pyx	2009-08-26 16:03:59 +0000
@@ -443,7 +443,8 @@
         self.completed = 0
 
     def __repr__(self):
-        return '%s(depth:%s rev:%s,%s,%s first:%s seen:%s)' % (self.__class__.__name__,
+        return '%s(%s depth:%s rev:%s,%s,%s first:%s seen:%s)' % (
+            self.__class__.__name__, self.key,
             self.merge_depth,
             self._revno_first, self._revno_second, self._revno_last,
             self.is_first_child, self.seen_by_child)
@@ -497,7 +498,6 @@
         if (tip_key is not None and tip_key != NULL_REVISION
             and tip_key != (NULL_REVISION,)):
             node = self.graph._nodes[tip_key]
-            self._get_ms_node(node)
             self._push_node(node, 0)
 
     cdef _MergeSortNode _get_ms_node(self, _KnownGraphNode node):
@@ -518,10 +518,17 @@
 
         ms_node = self._get_ms_node(node)
         ms_node.merge_depth = merge_depth
+        if node.parents is None:
+            raise RuntimeError('ghost nodes should not be pushed'
+                               ' onto the stack: %s' % (node,))
         if PyTuple_GET_SIZE(node.parents) > 0:
             parent_node = _get_parent(node.parents, 0)
             ms_node.left_parent = parent_node
-            ms_node.left_pending_parent = parent_node
+            if parent_node.parents is None: # left-hand ghost
+                ms_node.left_pending_parent = None
+                ms_node.left_parent = None
+            else:
+                ms_node.left_pending_parent = parent_node
         if PyTuple_GET_SIZE(node.parents) > 1:
             ms_node.pending_parents = []
             for pos from 1 <= pos < PyTuple_GET_SIZE(node.parents):

=== modified file 'bzrlib/commit.py'
--- a/bzrlib/commit.py	2009-08-25 22:28:19 +0000
+++ b/bzrlib/commit.py	2009-08-28 05:00:33 +0000
@@ -805,10 +805,11 @@
                 # _update_builder_with_changes.
                 continue
             content_summary = self.work_tree.path_content_summary(path)
+            kind = content_summary[0]
             # Note that when a filter of specific files is given, we must only
             # skip/record deleted files matching that filter.
             if not specific_files or is_inside_any(specific_files, path):
-                if content_summary[0] == 'missing':
+                if kind == 'missing':
                     if not deleted_paths:
                         # path won't have been split yet.
                         path_segments = splitpath(path)
@@ -821,23 +822,20 @@
                     continue
             # TODO: have the builder do the nested commit just-in-time IF and
             # only if needed.
-            if content_summary[0] == 'tree-reference':
+            if kind == 'tree-reference':
                 # enforce repository nested tree policy.
                 if (not self.work_tree.supports_tree_reference() or
                     # repository does not support it either.
                     not self.branch.repository._format.supports_tree_reference):
-                    content_summary = ('directory',) + content_summary[1:]
-            kind = content_summary[0]
-            # TODO: specific_files filtering before nested tree processing
-            if kind == 'tree-reference':
-                if self.recursive == 'down':
+                    kind = 'directory'
+                    content_summary = (kind, None, None, None)
+                elif self.recursive == 'down':
                     nested_revision_id = self._commit_nested_tree(
                         file_id, path)
-                    content_summary = content_summary[:3] + (
-                        nested_revision_id,)
+                    content_summary = (kind, None, None, nested_revision_id)
                 else:
-                    content_summary = content_summary[:3] + (
-                        self.work_tree.get_reference_revision(file_id),)
+                    nested_revision_id = self.work_tree.get_reference_revision(file_id)
+                    content_summary = (kind, None, None, nested_revision_id)
 
             # Record an entry for this item
             # Note: I don't particularly want to have the existing_ie

=== modified file 'bzrlib/repofmt/groupcompress_repo.py'
--- a/bzrlib/repofmt/groupcompress_repo.py	2009-08-18 05:18:52 +0000
+++ b/bzrlib/repofmt/groupcompress_repo.py	2009-08-24 19:34:13 +0000
@@ -932,7 +932,7 @@
         super(GroupCHKStreamSource, self).__init__(from_repository, to_format)
         self._revision_keys = None
         self._text_keys = None
-        self._text_fetch_order = 'groupcompress'
+        # self._text_fetch_order = 'unordered'
         self._chk_id_roots = None
         self._chk_p_id_roots = None
 
@@ -949,7 +949,7 @@
             p_id_roots_set = set()
             source_vf = self.from_repository.inventories
             stream = source_vf.get_record_stream(inventory_keys,
-                                                 'groupcompress', True)
+                                                 'unordered', True)
             for record in stream:
                 if record.storage_kind == 'absent':
                     if allow_absent:

=== modified file 'bzrlib/repository.py'
--- a/bzrlib/repository.py	2009-08-25 22:28:19 +0000
+++ b/bzrlib/repository.py	2009-08-28 05:00:33 +0000
@@ -465,9 +465,9 @@
             if content_summary[2] is None:
                 raise ValueError("Files must not have executable = None")
             if not store:
-                if (# if the file length changed we have to store:
-                    parent_entry.text_size != content_summary[1] or
-                    # if the exec bit has changed we have to store:
+                # We can't trust a check of the file length because of content
+                # filtering...
+                if (# if the exec bit has changed we have to store:
                     parent_entry.executable != content_summary[2]):
                     store = True
                 elif parent_entry.text_sha1 == content_summary[3]:
@@ -540,6 +540,9 @@
                 ie.revision = parent_entry.revision
                 return self._get_delta(ie, basis_inv, path), False, None
             ie.reference_revision = content_summary[3]
+            if ie.reference_revision is None:
+                raise AssertionError("invalid content_summary for nested tree: %r"
+                    % (content_summary,))
             self._add_text_to_weave(ie.file_id, '', heads, None)
         else:
             raise NotImplementedError('unknown kind')

=== modified file 'bzrlib/tests/per_tree/test_path_content_summary.py'
--- a/bzrlib/tests/per_tree/test_path_content_summary.py	2009-07-10 07:14:02 +0000
+++ b/bzrlib/tests/per_tree/test_path_content_summary.py	2009-08-26 05:34:10 +0000
@@ -1,4 +1,4 @@
-# Copyright (C) 2007 Canonical Ltd
+# Copyright (C) 2007, 2009 Canonical Ltd
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -34,6 +34,18 @@
         self.addCleanup(result.unlock)
         return result
 
+    def check_content_summary_size(self, tree, summary, expected_size):
+        # if the tree supports content filters, then it's allowed to leave out
+        # the size because it might be difficult to compute.  otherwise, it
+        # must be present and correct
+        returned_size = summary[1]
+        if returned_size == expected_size or (
+            tree.supports_content_filtering()
+            and returned_size is None):
+            pass
+        else:
+            self.fail("invalid size in summary: %r" % (returned_size,))
+
     def test_symlink_content_summary(self):
         self.requireFeature(tests.SymlinkFeature)
         tree = self.make_branch_and_tree('tree')
@@ -76,8 +88,7 @@
         summary = self._convert_tree(tree).path_content_summary('path')
         self.assertEqual(4, len(summary))
         self.assertEqual('file', summary[0])
-        # size must be known
-        self.assertEqual(22, summary[1])
+        self.check_content_summary_size(tree, summary, 22)
         # executable
         self.assertEqual(True, summary[2])
         # may have hash,
@@ -91,8 +102,7 @@
         summary = self._convert_tree(tree).path_content_summary('path')
         self.assertEqual(4, len(summary))
         self.assertEqual('file', summary[0])
-        # size must be known
-        self.assertEqual(22, summary[1])
+        self.check_content_summary_size(tree, summary, 22)
         # not executable
         if osutils.supports_executable:
             self.assertEqual(False, summary[2])

=== modified file 'bzrlib/tests/per_workingtree/test_content_filters.py'
--- a/bzrlib/tests/per_workingtree/test_content_filters.py	2009-07-10 07:14:02 +0000
+++ b/bzrlib/tests/per_workingtree/test_content_filters.py	2009-08-25 04:43:21 +0000
@@ -43,6 +43,25 @@
     return _converter_helper(chunks, 'lower')
 
 
+_trailer_string = '\nend string\n'
+
+
+def _append_text(chunks, context=None):
+    """A content filter that appends a string to the end of the file.
+
+    This tests filters that change the length."""
+    return chunks + [_trailer_string]
+
+
+def _remove_appended_text(chunks, context=None):
+    """Remove the appended text."""
+
+    text = ''.join(chunks)
+    if text.endswith(_trailer_string):
+        text = text[:-len(_trailer_string)]
+    return [text]
+
+
 class TestWorkingTreeWithContentFilters(TestCaseWithWorkingTree):
 
     def create_cf_tree(self, txt_reader, txt_writer, dir='.'):
@@ -159,3 +178,34 @@
         self.assertFileEqual("fOO tXT", 'target/file1.txt')
         changes = target.changes_from(source.basis_tree())
         self.assertFalse(changes.has_changed())
+
+    def test_path_content_summary(self):
+        """path_content_summary should always talk about the canonical form."""
+        # see https://bugs.edge.launchpad.net/bzr/+bug/415508
+        #
+        # set up a tree where the canonical form has a string added to the
+        # end
+        source, txt_fileid, bin_fileid = self.create_cf_tree(
+            txt_reader=_append_text,
+            txt_writer=_remove_appended_text,
+            dir='source')
+        if not source.supports_content_filtering():
+            return
+        source.lock_read()
+        self.addCleanup(source.unlock)
+
+        expected_canonical_form = 'Foo Txt\nend string\n'
+        self.assertEquals(source.get_file(txt_fileid, filtered=True).read(),
+            expected_canonical_form)
+        self.assertEquals(source.get_file(txt_fileid, filtered=False).read(),
+            'Foo Txt')
+
+        # results are: kind, size, executable, sha1_or_link_target
+        result = source.path_content_summary('file1.txt')
+
+        self.assertEquals(result,
+            ('file', None, False, None))
+
+        # 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.

=== modified file 'bzrlib/tests/test__known_graph.py'
--- a/bzrlib/tests/test__known_graph.py	2009-08-18 21:41:08 +0000
+++ b/bzrlib/tests/test__known_graph.py	2009-08-26 16:03:59 +0000
@@ -731,6 +731,20 @@
              ('A', 0, (1,), True),
             ])
 
+    def test_lefthand_ghost(self):
+        # ghost
+        #  |
+        #  A
+        #  |
+        #  B
+        self.assertSortAndIterate(
+            {'A': ['ghost'],
+             'B': ['A'],
+            }, 'B',
+            [('B', 0, (2,), False),
+             ('A', 0, (1,), True),
+            ])
+
     def test_graph_cycle(self):
         # merge_sort should fail with a simple error when a graph cycle is
         # encountered.

=== modified file 'bzrlib/tests/test_shelf.py'
--- a/bzrlib/tests/test_shelf.py	2009-08-25 21:09:17 +0000
+++ b/bzrlib/tests/test_shelf.py	2009-08-28 05:00:33 +0000
@@ -473,6 +473,15 @@
         self.addCleanup(creator.finalize)
         self.assertEqual([], list(creator.iter_shelvable()))
 
+    def test_shelve_skips_added_root(self):
+        """Skip adds of the root when iterating through shelvable changes."""
+        tree = self.make_branch_and_tree('tree')
+        tree.lock_tree_write()
+        self.addCleanup(tree.unlock)
+        creator = shelf.ShelfCreator(tree, tree.basis_tree())
+        self.addCleanup(creator.finalize)
+        self.assertEqual([], list(creator.iter_shelvable()))
+
 
 class TestUnshelver(tests.TestCaseWithTransport):
 

=== modified file 'bzrlib/tree.py'
--- a/bzrlib/tree.py	2009-08-03 03:36:47 +0000
+++ b/bzrlib/tree.py	2009-08-28 05:00:33 +0000
@@ -222,10 +222,14 @@
     def path_content_summary(self, path):
         """Get a summary of the information about path.
 
+        All the attributes returned are for the canonical form, not the
+        convenient form (if content filters are in use.)
+
         :param path: A relative path within the tree.
         :return: A tuple containing kind, size, exec, sha1-or-link.
             Kind is always present (see tree.kind()).
-            size is present if kind is file, None otherwise.
+            size is present if kind is file and the size of the 
+                canonical form can be cheaply determined, None otherwise.
             exec is None unless kind is file and the platform supports the 'x'
                 bit.
             sha1-or-link is the link target if kind is symlink, or the sha1 if

=== modified file 'bzrlib/tsort.py'
--- a/bzrlib/tsort.py	2009-08-19 16:23:39 +0000
+++ b/bzrlib/tsort.py	2009-08-26 16:03:59 +0000
@@ -459,9 +459,15 @@
             left_subtree_pushed_stack_append(False)
             pending_parents_stack_append(list(parents))
             # as we push it, check if it is the first child
+            parent_info = None
             if parents:
                 # node has parents, assign from the left most parent.
-                parent_info = revnos[parents[0]]
+                try:
+                    parent_info = revnos[parents[0]]
+                except KeyError:
+                    # Left-hand parent is a ghost, consider it not to exist
+                    pass
+            if parent_info is not None:
                 first_child = parent_info[1]
                 parent_info[1] = False
             else:
@@ -495,9 +501,15 @@
             pending_parents_stack_pop()
 
             parents = original_graph[node_name]
+            parent_revno = None
             if parents:
                 # node has parents, assign from the left most parent.
-                parent_revno = revnos[parents[0]][0]
+                try:
+                    parent_revno = revnos[parents[0]][0]
+                except KeyError:
+                    # left-hand parent is a ghost, treat it as not existing
+                    pass
+            if parent_revno is not None:
                 if not first_child:
                     # not the first child, make a new branch
                     base_revno = parent_revno[0]
@@ -628,10 +640,15 @@
         self._left_subtree_pushed_stack.append(False)
         self._pending_parents_stack.append(list(parents))
         # as we push it, figure out if this is the first child
-        parents = self._original_graph[node_name]
+        parent_info = None
         if parents:
             # node has parents, assign from the left most parent.
-            parent_info = self._revnos[parents[0]]
+            try:
+                parent_info = self._revnos[parents[0]]
+            except KeyError:
+                # Left-hand parent is a ghost, consider it not to exist
+                pass
+        if parent_info is not None:
             first_child = parent_info[1]
             parent_info[1] = False
         else:
@@ -655,9 +672,15 @@
         self._pending_parents_stack.pop()
 
         parents = self._original_graph[node_name]
+        parent_revno = None
         if parents:
             # node has parents, assign from the left most parent.
-            parent_revno = self._revnos[parents[0]][0]
+            try:
+                parent_revno = self._revnos[parents[0]][0]
+            except KeyError:
+                # left-hand parent is a ghost, treat it as not existing
+                pass
+        if parent_revno is not None:
             if not first_child:
                 # not the first child, make a new branch
                 base_revno = parent_revno[0]

=== modified file 'bzrlib/workingtree.py'
--- a/bzrlib/workingtree.py	2009-08-14 02:43:55 +0000
+++ b/bzrlib/workingtree.py	2009-08-26 05:38:16 +0000
@@ -613,6 +613,8 @@
 
     def get_file_size(self, file_id):
         """See Tree.get_file_size"""
+        # XXX: this returns the on-disk size; it should probably return the
+        # canonical size
         try:
             return os.path.getsize(self.id2abspath(file_id))
         except OSError, e:
@@ -749,11 +751,7 @@
             raise
         kind = _mapper(stat_result.st_mode)
         if kind == 'file':
-            size = stat_result.st_size
-            # try for a stat cache lookup
-            executable = self._is_executable_from_path_and_stat(path, stat_result)
-            return (kind, size, executable, self._sha_from_stat(
-                path, stat_result))
+            return self._file_content_summary(path, stat_result)
         elif kind == 'directory':
             # perhaps it looks like a plain directory, but it's really a
             # reference.
@@ -766,6 +764,13 @@
         else:
             return (kind, None, None, None)
 
+    def _file_content_summary(self, path, stat_result):
+        size = stat_result.st_size
+        executable = self._is_executable_from_path_and_stat(path, stat_result)
+        # try for a stat cache lookup
+        return ('file', size, executable, self._sha_from_stat(
+            path, stat_result))
+
     def _check_parents_for_ghosts(self, revision_ids, allow_leftmost_as_ghost):
         """Common ghost checking functionality from set_parent_*.
 

=== modified file 'bzrlib/workingtree_4.py'
--- a/bzrlib/workingtree_4.py	2009-08-04 11:25:23 +0000
+++ b/bzrlib/workingtree_4.py	2009-08-25 04:43:21 +0000
@@ -1300,6 +1300,32 @@
         return statvalue, sha1
 
 
+class ContentFilteringDirStateWorkingTree(DirStateWorkingTree):
+    """Dirstate working tree that supports content filtering.
+
+    The dirstate holds the hash and size of the canonical form of the file, 
+    and most methods must return that.
+    """
+
+    def _file_content_summary(self, path, stat_result):
+        # This is to support the somewhat obsolete path_content_summary method
+        # with content filtering: see
+        # <https://bugs.edge.launchpad.net/bzr/+bug/415508>.
+        #
+        # If the dirstate cache is up to date and knows the hash and size,
+        # return that.
+        # Otherwise if there are no content filters, return the on-disk size
+        # and leave the hash blank.
+        # Otherwise, read and filter the on-disk file and use its size and
+        # hash.
+        #
+        # The dirstate doesn't store the size of the canonical form so we
+        # can't trust it for content-filtered trees.  We just return None.
+        dirstate_sha1 = self._dirstate.sha1_from_stat(path, stat_result)
+        executable = self._is_executable_from_path_and_stat(path, stat_result)
+        return ('file', None, executable, dirstate_sha1)
+
+
 class WorkingTree4(DirStateWorkingTree):
     """This is the Format 4 working tree.
 
@@ -1313,7 +1339,7 @@
     """
 
 
-class WorkingTree5(DirStateWorkingTree):
+class WorkingTree5(ContentFilteringDirStateWorkingTree):
     """This is the Format 5 working tree.
 
     This differs from WorkingTree4 by:
@@ -1323,7 +1349,7 @@
     """
 
 
-class WorkingTree6(DirStateWorkingTree):
+class WorkingTree6(ContentFilteringDirStateWorkingTree):
     """This is the Format 6 working tree.
 
     This differs from WorkingTree5 by:
@@ -1550,7 +1576,11 @@
 
 
 class DirStateRevisionTree(Tree):
-    """A revision tree pulling the inventory from a dirstate."""
+    """A revision tree pulling the inventory from a dirstate.
+    
+    Note that this is one of the historical (ie revision) trees cached in the
+    dirstate for easy access, not the workingtree.
+    """
 
     def __init__(self, dirstate, revision_id, repository):
         self._dirstate = dirstate




More information about the bazaar-commits mailing list