Rev 6563: (jam) Merge bzr-2.5.2-dev into bzr trunk to get the ConnectionReset in file:///srv/pqm.bazaar-vcs.org/archives/thelove/bzr/%2Btrunk/

Patch Queue Manager pqm at pqm.ubuntu.com
Wed Sep 19 08:27:25 UTC 2012


At file:///srv/pqm.bazaar-vcs.org/archives/thelove/bzr/%2Btrunk/

------------------------------------------------------------
revno: 6563 [merge]
revision-id: pqm at pqm.ubuntu.com-20120919082725-dzvmca37zj5xx2hh
parent: pqm at pqm.ubuntu.com-20120919071228-yd09pv4quo9hxtf2
parent: john at arbash-meinel.com-20120919075827-36b2b042kiaps0d3
committer: Patch Queue Manager <pqm at pqm.ubuntu.com>
branch nick: +trunk
timestamp: Wed 2012-09-19 08:27:25 +0000
message:
  (jam) Merge bzr-2.5.2-dev into bzr trunk to get the ConnectionReset
  	fixes.
modified:
  bzrlib/osutils.py              osutils.py-20050309040759-eeaff12fbf77ac86
  bzrlib/remote.py               remote.py-20060720103555-yeeg2x51vn0rbtdp-1
  bzrlib/smart/medium.py         medium.py-20061103051856-rgu2huy59fkz902q-1
  bzrlib/smart/repository.py     repository.py-20061128022038-vr5wy5bubyb8xttk-1
  bzrlib/tests/per_tree/__init__.py __init__.py-20060717075546-420s7b0bj9hzeowi-2
  bzrlib/tests/per_workingtree/__init__.py __init__.py-20060203003124-b2aa5aca21a8bfad
  bzrlib/tests/per_workingtree/test_commit.py test_commit.py-20060421013633-1610ec2331c8190f
  bzrlib/tests/per_workingtree/test_executable.py test_executable.py-20060628162557-tr7h57kl80l3ma8i-1
  bzrlib/tests/per_workingtree/test_parents.py test_set_parents.py-20060807231740-yicmnlci1mj8smu1-1
  bzrlib/tests/per_workingtree/test_remove.py test_remove.py-20070413183901-rvnp85rtc0q0sclp-1
  bzrlib/tests/per_workingtree/test_smart_add.py test_smart_add.py-20070215175752-9s5mxoz8aqpd80fm-1
  bzrlib/tests/per_workingtree/test_views.py test_views.py-20080729134135-v4zjnb85eu9srl80-1
  bzrlib/tests/per_workingtree/test_workingtree.py test_workingtree.py-20060203003124-817757d3e31444fb
  bzrlib/tests/test_osutils.py   test_osutils.py-20051201224856-e48ee24c12182989
  bzrlib/tests/test_selftest.py  test_selftest.py-20051202044319-c110a115d8c0456a
  bzrlib/workingtree_4.py        workingtree_4.py-20070208044105-5fgpc5j3ljlh5q6c-1
  doc/en/release-notes/bzr-2.5.txt bzr2.5.txt-20110708125756-587p0hpw7oke4h05-1
=== modified file 'bzrlib/osutils.py'
--- a/bzrlib/osutils.py	2012-03-12 19:01:05 +0000
+++ b/bzrlib/osutils.py	2012-09-19 07:58:27 +0000
@@ -2086,7 +2086,7 @@
 # data at once.
 MAX_SOCKET_CHUNK = 64 * 1024
 
-_end_of_stream_errors = [errno.ECONNRESET]
+_end_of_stream_errors = [errno.ECONNRESET, errno.EPIPE, errno.EINVAL]
 for _eno in ['WSAECONNRESET', 'WSAECONNABORTED']:
     _eno = getattr(errno, _eno, None)
     if _eno is not None:
@@ -2158,12 +2158,19 @@
     while sent_total < byte_count:
         try:
             sent = sock.send(buffer(bytes, sent_total, MAX_SOCKET_CHUNK))
-        except socket.error, e:
+        except (socket.error, IOError), e:
+            if e.args[0] in _end_of_stream_errors:
+                raise errors.ConnectionReset(
+                    "Error trying to write to socket", e)
             if e.args[0] != errno.EINTR:
                 raise
         else:
+            if sent == 0:
+                raise errors.ConnectionReset('Sending to %s returned 0 bytes'
+                                             % (sock,))
             sent_total += sent
-            report_activity(sent, 'write')
+            if report_activity is not None:
+                report_activity(sent, 'write')
 
 
 def connect_socket(address):

=== modified file 'bzrlib/remote.py'
--- a/bzrlib/remote.py	2012-07-31 13:01:03 +0000
+++ b/bzrlib/remote.py	2012-09-19 07:58:27 +0000
@@ -3117,7 +3117,8 @@
         return a_bzrdir.open_branch(name=name, 
             ignore_fallbacks=ignore_fallbacks)
 
-    def _vfs_initialize(self, a_bzrdir, name, append_revisions_only):
+    def _vfs_initialize(self, a_bzrdir, name, append_revisions_only,
+                        repository=None):
         # Initialisation when using a local bzrdir object, or a non-vfs init
         # method is not available on the server.
         # self._custom_format is always set - the start of initialize ensures
@@ -3125,11 +3126,13 @@
         if isinstance(a_bzrdir, RemoteBzrDir):
             a_bzrdir._ensure_real()
             result = self._custom_format.initialize(a_bzrdir._real_bzrdir,
-                name=name, append_revisions_only=append_revisions_only)
+                name=name, append_revisions_only=append_revisions_only,
+                repository=repository)
         else:
             # We assume the bzrdir is parameterised; it may not be.
             result = self._custom_format.initialize(a_bzrdir, name=name,
-                append_revisions_only=append_revisions_only)
+                append_revisions_only=append_revisions_only,
+                repository=repository)
         if (isinstance(a_bzrdir, RemoteBzrDir) and
             not isinstance(result, RemoteBranch)):
             result = RemoteBranch(a_bzrdir, a_bzrdir.find_repository(), result,
@@ -3152,11 +3155,13 @@
         # Being asked to create on a non RemoteBzrDir:
         if not isinstance(a_bzrdir, RemoteBzrDir):
             return self._vfs_initialize(a_bzrdir, name=name,
-                append_revisions_only=append_revisions_only)
+                append_revisions_only=append_revisions_only,
+                repository=repository)
         medium = a_bzrdir._client._medium
         if medium._is_remote_before((1, 13)):
             return self._vfs_initialize(a_bzrdir, name=name,
-                append_revisions_only=append_revisions_only)
+                append_revisions_only=append_revisions_only,
+                repository=repository)
         # Creating on a remote bzr dir.
         # 2) try direct creation via RPC
         path = a_bzrdir._path_for_remote_call(a_bzrdir._client)
@@ -3170,7 +3175,8 @@
             # Fallback - use vfs methods
             medium._remember_remote_is_before((1, 13))
             return self._vfs_initialize(a_bzrdir, name=name,
-                    append_revisions_only=append_revisions_only)
+                    append_revisions_only=append_revisions_only,
+                    repository=repository)
         if response[0] != 'ok':
             raise errors.UnexpectedSmartServerResponse(response)
         # Turn the response into a RemoteRepository object.
@@ -3845,6 +3851,9 @@
             target, overwrite=overwrite, stop_revision=stop_revision, lossy=lossy,
             _override_hook_source_branch=self)
 
+    def peek_lock_mode(self):
+        return self._lock_mode
+
     def is_locked(self):
         return self._lock_count >= 1
 

=== modified file 'bzrlib/smart/medium.py'
--- a/bzrlib/smart/medium.py	2011-12-24 09:59:02 +0000
+++ b/bzrlib/smart/medium.py	2012-09-10 11:50:34 +0000
@@ -910,7 +910,7 @@
         except IOError, e:
             if e.errno in (errno.EINVAL, errno.EPIPE):
                 raise errors.ConnectionReset(
-                    "Error trying to write to subprocess:\n%s" % (e,))
+                    "Error trying to write to subprocess", e)
             raise
         self._report_activity(len(bytes), 'write')
 
@@ -1043,7 +1043,7 @@
 
 class SmartClientSocketMedium(SmartClientStreamMedium):
     """A client medium using a socket.
-    
+
     This class isn't usable directly.  Use one of its subclasses instead.
     """
 

=== modified file 'bzrlib/smart/repository.py'
--- a/bzrlib/smart/repository.py	2011-12-19 13:23:58 +0000
+++ b/bzrlib/smart/repository.py	2012-09-06 11:19:35 +0000
@@ -736,15 +736,18 @@
         self.seed_state()
         pb = ui.ui_factory.nested_progress_bar()
         rc = self._record_counter
-        # Make and consume sub generators, one per substream type:
-        while self.first_bytes is not None:
-            substream = NetworkRecordStream(self.iter_substream_bytes())
-            # after substream is fully consumed, self.current_type is set to
-            # the next type, and self.first_bytes is set to the matching bytes.
-            yield self.current_type, wrap_and_count(pb, rc, substream)
-        if rc:
-            pb.update('Done', rc.max, rc.max)
-        pb.finished()
+        try:
+            # Make and consume sub generators, one per substream type:
+            while self.first_bytes is not None:
+                substream = NetworkRecordStream(self.iter_substream_bytes())
+                # after substream is fully consumed, self.current_type is set
+                # to the next type, and self.first_bytes is set to the matching
+                # bytes.
+                yield self.current_type, wrap_and_count(pb, rc, substream)
+        finally:
+            if rc:
+                pb.update('Done', rc.max, rc.max)
+            pb.finished()
 
     def seed_state(self):
         """Prepare the _ByteStreamDecoder to decode from the pack stream."""

=== modified file 'bzrlib/tests/per_tree/__init__.py'
--- a/bzrlib/tests/per_tree/__init__.py	2012-03-05 17:29:08 +0000
+++ b/bzrlib/tests/per_tree/__init__.py	2012-09-19 07:58:27 +0000
@@ -29,6 +29,7 @@
     errors,
     tests,
     transform,
+    transport,
     )
 from bzrlib.tests.per_controldir.test_controldir import TestCaseWithControlDir
 from bzrlib.tests.per_workingtree import (
@@ -99,11 +100,24 @@
 class TestCaseWithTree(TestCaseWithControlDir):
 
     def make_branch_and_tree(self, relpath):
-        made_control = self.make_bzrdir(relpath, format=
-            self.workingtree_format._matchingbzrdir)
+        bzrdir_format = self.workingtree_format.get_controldir_for_branch()
+        made_control = self.make_bzrdir(relpath, format=bzrdir_format)
         made_control.create_repository()
-        made_control.create_branch()
-        return self.workingtree_format.initialize(made_control)
+        b = made_control.create_branch()
+        if getattr(self, 'repo_is_remote', False):
+            # If the repo is remote, then we just create a local lightweight
+            # checkout
+            # XXX: This duplicates a lot of Branch.create_checkout, but we know
+            #      we want a) lightweight, and b) a specific WT format. We also
+            #      know that nothing should already exist, etc.
+            t = transport.get_transport(relpath)
+            t.ensure_base()
+            wt_dir = bzrdir_format.initialize_on_transport(t)
+            branch_ref = wt_dir.set_branch_reference(b)
+            wt = wt_dir.create_workingtree(None, from_branch=branch_ref)
+        else:
+            wt = self.workingtree_format.initialize(made_control)
+        return wt
 
     def workingtree_to_test_tree(self, tree):
         return self._workingtree_to_test_tree(self, tree)

=== modified file 'bzrlib/tests/per_workingtree/__init__.py'
--- a/bzrlib/tests/per_workingtree/__init__.py	2011-09-23 12:32:30 +0000
+++ b/bzrlib/tests/per_workingtree/__init__.py	2012-09-07 08:52:36 +0000
@@ -25,18 +25,37 @@
 from bzrlib import (
     branchbuilder,
     tests,
+    transport,
     workingtree,
     )
-from bzrlib.tests import per_controldir
-
-
-def make_scenarios(transport_server, transport_readonly_server, formats):
+from bzrlib.transport import memory
+from bzrlib.tests import (
+    per_controldir,
+    test_server,
+    )
+
+
+def make_scenarios(transport_server, transport_readonly_server, formats,
+                   remote_server=None, remote_readonly_server=None,
+                   remote_backing_server=None):
     result = []
     for workingtree_format in formats:
         result.append((workingtree_format.__class__.__name__,
                        make_scenario(transport_server,
                                      transport_readonly_server,
                                      workingtree_format)))
+    default_wt_format = workingtree.format_registry.get_default()
+    if remote_server is None:
+        remote_server = test_server.SmartTCPServer_for_testing
+    if remote_readonly_server is None:
+        remote_readonly_server = test_server.ReadonlySmartTCPServer_for_testing
+    if remote_backing_server is None:
+        remote_backing_server = memory.MemoryServer
+    scenario = make_scenario(remote_server, remote_readonly_server,
+                             default_wt_format)
+    scenario['repo_is_remote'] = True;
+    scenario['vfs_transport_factory'] = remote_backing_server
+    result.append((default_wt_format.__class__.__name__ + ',remote', scenario))
     return result
 
 
@@ -71,8 +90,22 @@
     def make_branch_and_tree(self, relpath, format=None):
         made_control = self.make_bzrdir(relpath, format=format)
         made_control.create_repository()
-        made_control.create_branch()
-        return self.workingtree_format.initialize(made_control)
+        b = made_control.create_branch()
+        if getattr(self, 'repo_is_remote', False):
+            # If the repo is remote, then we just create a local lightweight
+            # checkout
+            # XXX: This duplicates a lot of Branch.create_checkout, but we know
+            #      we want a) lightweight, and b) a specific WT format. We also
+            #      know that nothing should already exist, etc.
+            t = transport.get_transport(relpath)
+            t.ensure_base()
+            bzrdir_format = self.workingtree_format.get_controldir_for_branch()
+            wt_dir = bzrdir_format.initialize_on_transport(t)
+            branch_ref = wt_dir.set_branch_reference(b)
+            wt = wt_dir.create_workingtree(None, from_branch=branch_ref)
+        else:
+            wt = self.workingtree_format.initialize(made_control)
+        return wt
 
     def make_branch_builder(self, relpath, format=None):
         if format is None:

=== modified file 'bzrlib/tests/per_workingtree/test_commit.py'
--- a/bzrlib/tests/per_workingtree/test_commit.py	2012-02-23 23:26:35 +0000
+++ b/bzrlib/tests/per_workingtree/test_commit.py	2012-09-19 07:58:27 +0000
@@ -26,6 +26,7 @@
     osutils,
     revision as _mod_revision,
     tests,
+    transport as _mod_transport,
     ui,
     )
 from bzrlib.tests.per_workingtree import TestCaseWithWorkingTree
@@ -316,7 +317,7 @@
         wt.lock_write()
         self.build_tree(['a', 'b/', 'b/c', 'd'])
         wt.add(['a', 'b', 'b/c', 'd'], ['a-id', 'b-id', 'c-id', 'd-id'])
-        this_dir = self.get_transport()
+        this_dir = wt.bzrdir.root_transport
         this_dir.delete_tree('b')
         this_dir.delete('d')
         # now we have a tree with a through d in the inventory, but only
@@ -352,7 +353,7 @@
         wt.add(['a', 'b', 'b/c'], ['a-id', 'b-id', 'c-id'])
         wt.commit('first')
         wt.remove('b/c')
-        this_dir = self.get_transport()
+        this_dir = wt.bzrdir.root_transport
         this_dir.delete_tree('b')
         wt.lock_write()
         wt.commit('commit deleted rename')

=== modified file 'bzrlib/tests/per_workingtree/test_executable.py'
--- a/bzrlib/tests/per_workingtree/test_executable.py	2012-01-24 03:04:58 +0000
+++ b/bzrlib/tests/per_workingtree/test_executable.py	2012-09-19 07:58:27 +0000
@@ -71,8 +71,7 @@
         self.wt.commit('adding a,b', rev_id='r1')
         # Now make sure that 'bzr branch' also preserves the
         # executable bit
-        # TODO: Maybe this should be a blackbox test
-        dir2 = self.wt.branch.bzrdir.clone('b2', revision_id='r1')
+        dir2 = self.wt.branch.bzrdir.sprout('b2', revision_id='r1')
         wt2 = dir2.open_workingtree()
         self.assertEqual(['r1'], wt2.get_parent_ids())
         self.assertEqual('r1', wt2.branch.last_revision())

=== modified file 'bzrlib/tests/per_workingtree/test_parents.py'
--- a/bzrlib/tests/per_workingtree/test_parents.py	2012-01-24 03:04:58 +0000
+++ b/bzrlib/tests/per_workingtree/test_parents.py	2012-09-19 07:58:27 +0000
@@ -21,9 +21,7 @@
 
 from bzrlib import (
     errors,
-    osutils,
     revision as _mod_revision,
-    tests,
     )
 from bzrlib.inventory import (
     Inventory,
@@ -475,7 +473,11 @@
         # large hammer, this is a particularly sensitive area of code, so the
         # extra assurance is well worth it.
         tree._validate()
-        osutils.rmtree('tree')
+        # If tree.branch is remote
+        if tree.user_url != tree.branch.user_url:
+            # We have a lightweight checkout, delete both locations
+            tree.branch.bzrdir.root_transport.delete_tree('.')
+        tree.bzrdir.root_transport.delete_tree('.')
 
     def test_no_parents_just_root(self):
         """Test doing an empty commit - no parent, set a root only."""

=== modified file 'bzrlib/tests/per_workingtree/test_remove.py'
--- a/bzrlib/tests/per_workingtree/test_remove.py	2011-05-13 12:51:05 +0000
+++ b/bzrlib/tests/per_workingtree/test_remove.py	2012-09-06 09:29:30 +0000
@@ -173,7 +173,7 @@
         """Removing a absent directory succeeds without corruption (#150438)."""
         paths = ['a/', 'a/b']
         tree = self.get_committed_tree(paths)
-        self.get_transport('.').delete_tree('a')
+        tree.bzrdir.root_transport.delete_tree('a')
         tree.remove(['a'])
         self.assertRemovedAndDeleted('b')
         tree._validate()

=== modified file 'bzrlib/tests/per_workingtree/test_smart_add.py'
--- a/bzrlib/tests/per_workingtree/test_smart_add.py	2011-09-06 09:51:45 +0000
+++ b/bzrlib/tests/per_workingtree/test_smart_add.py	2012-09-06 09:29:30 +0000
@@ -135,6 +135,9 @@
 
         self.build_tree(build_paths)
         wt = self.make_branch_and_tree('.')
+        if wt.user_url != wt.branch.user_url:
+            # Lightweight checkout, make sure we have a repo location.
+            wt.branch.bzrdir.root_transport.mkdir('original')
         child_tree = self.make_branch_and_tree('original/child')
         wt.smart_add((".",))
         for path in paths:

=== modified file 'bzrlib/tests/per_workingtree/test_views.py'
--- a/bzrlib/tests/per_workingtree/test_views.py	2012-08-04 14:27:47 +0000
+++ b/bzrlib/tests/per_workingtree/test_views.py	2012-09-19 07:58:27 +0000
@@ -22,7 +22,7 @@
 
 
 from bzrlib import views, errors
-from bzrlib.tests import TestSkipped
+from bzrlib.tests import TestNotApplicable, TestSkipped
 from bzrlib.workingtree import WorkingTree
 
 from bzrlib.tests.per_workingtree import TestCaseWithWorkingTree
@@ -39,7 +39,7 @@
             raise TestSkipped("format %s doesn't declare whether it "
                 "supports views, assuming not" % fmt)
         if not f():
-            raise TestSkipped("format %s doesn't support views" % fmt)
+            raise TestNotApplicable("format %s doesn't support views" % fmt)
         super(TestTreeViews, self).setUp()
 
     def test_views_initially_empty(self):

=== modified file 'bzrlib/tests/per_workingtree/test_workingtree.py'
--- a/bzrlib/tests/per_workingtree/test_workingtree.py	2012-03-14 13:34:43 +0000
+++ b/bzrlib/tests/per_workingtree/test_workingtree.py	2012-09-19 07:58:27 +0000
@@ -58,10 +58,20 @@
 
 class TestWorkingTree(TestCaseWithWorkingTree):
 
+    def requireBranchReference(self):
+        test_branch = self.make_branch('test-branch')
+        try:
+            # if there is a working tree now, this is not supported.
+            test_branch.bzrdir.open_workingtree()
+            raise TestNotApplicable("only on trees that can be separate"
+                " from their branch.")
+        except (errors.NoWorkingTree, errors.NotLocalUrl):
+            pass
+
     def test_branch_builder(self):
         # Just a smoke test that we get a branch at the specified relpath
         builder = self.make_branch_builder('foobar')
-        br = branch.Branch.open('foobar')
+        br = branch.Branch.open(self.get_url('foobar'))
 
     def test_list_files(self):
         tree = self.make_branch_and_tree('.')
@@ -129,8 +139,10 @@
         self.assertIsInstance(conf, config.Stack)
 
     def test_open_containing(self):
-        branch = self.make_branch_and_tree('.').branch
-        local_base = urlutils.local_path_from_url(branch.base)
+        local_wt = self.make_branch_and_tree('.')
+        local_url = local_wt.bzrdir.root_transport.base
+        local_base = urlutils.local_path_from_url(local_url)
+        del local_wt
 
         # Empty opens '.'
         wt, relpath = WorkingTree.open_containing()
@@ -168,6 +180,7 @@
 
     def test_lock_locks_branch(self):
         tree = self.make_branch_and_tree('.')
+        self.assertEqual(None, tree.branch.peek_lock_mode())
         tree.lock_read()
         self.assertEqual('r', tree.branch.peek_lock_mode())
         tree.unlock()
@@ -366,14 +379,8 @@
         # that formats where initialising a branch does not initialise a
         # tree - and thus have separable entities - support skewing the
         # two things.
-        branch = self.make_branch('tree')
-        try:
-            # if there is a working tree now, this is not supported.
-            branch.bzrdir.open_workingtree()
-            return
-        except errors.NoWorkingTree:
-            pass
-        wt = branch.bzrdir.create_workingtree()
+        self.requireBranchReference()
+        wt = self.make_branch_and_tree('tree')
         wt.commit('A', allow_pointless=True, rev_id='A')
         wt.set_last_revision(None)
         self.assertEqual([], wt.get_parent_ids())
@@ -482,19 +489,13 @@
         # that formats where initialising a branch does not initialise a
         # tree - and thus have separable entities - support skewing the
         # two things.
-        main_branch = self.make_branch('tree')
-        try:
-            # if there is a working tree now, this is not supported.
-            main_branch.bzrdir.open_workingtree()
-            return
-        except errors.NoWorkingTree:
-            pass
-        wt = main_branch.bzrdir.create_workingtree()
+        self.requireBranchReference()
+        wt = self.make_branch_and_tree('tree')
         # create an out of date working tree by making a checkout in this
         # current format
         self.build_tree(['checkout/', 'tree/file'])
         checkout = bzrdir.BzrDirMetaFormat1().initialize('checkout')
-        checkout.set_branch_reference(main_branch)
+        checkout.set_branch_reference(wt.branch)
         old_tree = self.workingtree_format.initialize(checkout)
         # now commit to 'tree'
         wt.add('file')
@@ -549,19 +550,13 @@
         # that formats where initialising a branch does not initialise a
         # tree - and thus have separable entities - support skewing the
         # two things.
-        main_branch = self.make_branch('tree')
-        try:
-            # if there is a working tree now, this is not supported.
-            main_branch.bzrdir.open_workingtree()
-            return
-        except errors.NoWorkingTree:
-            pass
-        wt = main_branch.bzrdir.create_workingtree()
+        self.requireBranchReference()
+        wt = self.make_branch_and_tree('tree')
         # create an out of date working tree by making a checkout in this
         # current format
         self.build_tree(['checkout/', 'tree/file'])
         checkout = bzrdir.BzrDirMetaFormat1().initialize('checkout')
-        checkout.set_branch_reference(main_branch)
+        checkout.set_branch_reference(wt.branch)
         old_tree = self.workingtree_format.initialize(checkout)
         # now commit to 'tree'
         wt.add('file')

=== modified file 'bzrlib/tests/test_osutils.py'
--- a/bzrlib/tests/test_osutils.py	2012-08-04 14:27:47 +0000
+++ b/bzrlib/tests/test_osutils.py	2012-09-19 07:58:27 +0000
@@ -828,6 +828,45 @@
         self.assertEqual(None, osutils.safe_file_id(None))
 
 
+class TestSendAll(tests.TestCase):
+
+    def test_send_with_disconnected_socket(self):
+        class DisconnectedSocket(object):
+            def __init__(self, err):
+                self.err = err
+            def send(self, content):
+                raise self.err
+            def close(self):
+                pass
+        # All of these should be treated as ConnectionReset
+        errs = []
+        for err_cls in (IOError, socket.error):
+            for errnum in osutils._end_of_stream_errors:
+                errs.append(err_cls(errnum))
+        for err in errs:
+            sock = DisconnectedSocket(err)
+            self.assertRaises(errors.ConnectionReset,
+                osutils.send_all, sock, 'some more content')
+
+    def test_send_with_no_progress(self):
+        # See https://bugs.launchpad.net/bzr/+bug/1047309
+        # It seems that paramiko can get into a state where it doesn't error,
+        # but it returns 0 bytes sent for requests over and over again.
+        class NoSendingSocket(object):
+            def __init__(self):
+                self.call_count = 0
+            def send(self, bytes):
+                self.call_count += 1
+                if self.call_count > 100:
+                    # Prevent the test suite from hanging
+                    raise RuntimeError('too many calls')
+                return 0
+        sock = NoSendingSocket()
+        self.assertRaises(errors.ConnectionReset,
+                          osutils.send_all, sock, 'content')
+        self.assertEqual(1, sock.call_count)
+
+
 class TestPosixFuncs(tests.TestCase):
     """Test that the posix version of normpath returns an appropriate path
        when used with 2 leading slashes."""

=== modified file 'bzrlib/tests/test_selftest.py'
--- a/bzrlib/tests/test_selftest.py	2012-08-04 14:27:47 +0000
+++ b/bzrlib/tests/test_selftest.py	2012-09-19 07:58:27 +0000
@@ -335,8 +335,11 @@
         server1 = "a"
         server2 = "b"
         formats = [workingtree_4.WorkingTreeFormat4(),
-                   workingtree_3.WorkingTreeFormat3(),]
-        scenarios = make_scenarios(server1, server2, formats)
+                   workingtree_3.WorkingTreeFormat3(),
+                   workingtree_4.WorkingTreeFormat6()]
+        scenarios = make_scenarios(server1, server2, formats,
+            remote_server='c', remote_readonly_server='d',
+            remote_backing_server='e')
         self.assertEqual([
             ('WorkingTreeFormat4',
              {'bzrdir_format': formats[0]._matchingbzrdir,
@@ -347,19 +350,33 @@
              {'bzrdir_format': formats[1]._matchingbzrdir,
               'transport_readonly_server': 'b',
               'transport_server': 'a',
-              'workingtree_format': formats[1]})],
-            scenarios)
+              'workingtree_format': formats[1]}),
+            ('WorkingTreeFormat6',
+             {'bzrdir_format': formats[2]._matchingbzrdir,
+              'transport_readonly_server': 'b',
+              'transport_server': 'a',
+              'workingtree_format': formats[2]}),
+            ('WorkingTreeFormat6,remote',
+             {'bzrdir_format': formats[2]._matchingbzrdir,
+              'repo_is_remote': True,
+              'transport_readonly_server': 'd',
+              'transport_server': 'c',
+              'vfs_transport_factory': 'e',
+              'workingtree_format': formats[2]}),
+            ], scenarios)
 
 
 class TestTreeScenarios(tests.TestCase):
 
     def test_scenarios(self):
         # the tree implementation scenario generator is meant to setup one
-        # instance for each working tree format, and one additional instance
+        # instance for each working tree format, one additional instance
         # that will use the default wt format, but create a revision tree for
-        # the tests.  this means that the wt ones should have the
-        # workingtree_to_test_tree attribute set to 'return_parameter' and the
-        # revision one set to revision_tree_from_workingtree.
+        # the tests, and one more that uses the default wt format as a
+        # lightweight checkout of a remote repository.  This means that the wt
+        # ones should have the workingtree_to_test_tree attribute set to
+        # 'return_parameter' and the revision one set to
+        # revision_tree_from_workingtree.
 
         from bzrlib.tests.per_tree import (
             _dirstate_tree_from_workingtree,
@@ -371,13 +388,17 @@
             )
         server1 = "a"
         server2 = "b"
+        smart_server = test_server.SmartTCPServer_for_testing
+        smart_readonly_server = test_server.ReadonlySmartTCPServer_for_testing
+        mem_server = memory.MemoryServer
         formats = [workingtree_4.WorkingTreeFormat4(),
                    workingtree_3.WorkingTreeFormat3(),]
         scenarios = make_scenarios(server1, server2, formats)
-        self.assertEqual(7, len(scenarios))
+        self.assertEqual(8, len(scenarios))
         default_wt_format = workingtree.format_registry.get_default()
         wt4_format = workingtree_4.WorkingTreeFormat4()
         wt5_format = workingtree_4.WorkingTreeFormat5()
+        wt6_format = workingtree_4.WorkingTreeFormat6()
         expected_scenarios = [
             ('WorkingTreeFormat4',
              {'bzrdir_format': formats[0]._matchingbzrdir,
@@ -393,6 +414,15 @@
               'workingtree_format': formats[1],
               '_workingtree_to_test_tree': return_parameter,
              }),
+            ('WorkingTreeFormat6,remote',
+             {'bzrdir_format': wt6_format._matchingbzrdir,
+              'repo_is_remote': True,
+              'transport_readonly_server': smart_readonly_server,
+              'transport_server': smart_server,
+              'vfs_transport_factory': mem_server,
+              'workingtree_format': wt6_format,
+              '_workingtree_to_test_tree': return_parameter,
+             }),
             ('RevisionTree',
              {'_workingtree_to_test_tree': revision_tree_from_workingtree,
               'bzrdir_format': default_wt_format._matchingbzrdir,

=== modified file 'bzrlib/workingtree_4.py'
--- a/bzrlib/workingtree_4.py	2012-03-12 13:38:09 +0000
+++ b/bzrlib/workingtree_4.py	2012-09-19 07:58:27 +0000
@@ -1,4 +1,4 @@
-# Copyright (C) 2007-2011 Canonical Ltd
+# Copyright (C) 2007-2012 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
@@ -1693,6 +1693,12 @@
     def supports_views(self):
         return True
 
+    def _get_matchingbzrdir(self):
+        """Overrideable method to get a bzrdir for testing."""
+        # We use 'development-subtree' instead of '2a', because we have a
+        # few tests that want to test tree references
+        return bzrdir.format_registry.make_bzrdir('development-subtree')
+
 
 class DirStateRevisionTree(InventoryTree):
     """A revision tree pulling the inventory from a dirstate.
@@ -1901,8 +1907,18 @@
         return inv[inv_file_id].text_size
 
     def get_file_text(self, file_id, path=None):
-        _, content = list(self.iter_files_bytes([(file_id, None)]))[0]
-        return ''.join(content)
+        content = None
+        for _, content_iter in self.iter_files_bytes([(file_id, None)]):
+            if content is not None:
+                raise AssertionError('iter_files_bytes returned'
+                    ' too many entries')
+            # For each entry returned by iter_files_bytes, we must consume the
+            # content_iter before we step the files iterator.
+            content = ''.join(content_iter)
+        if content is None:
+            raise AssertionError('iter_files_bytes did not return'
+                ' the requested data')
+        return content
 
     def get_reference_revision(self, file_id, path=None):
         inv, inv_file_id = self._unpack_file_id(file_id)

=== modified file 'doc/en/release-notes/bzr-2.5.txt'
--- a/doc/en/release-notes/bzr-2.5.txt	2012-08-01 09:27:40 +0000
+++ b/doc/en/release-notes/bzr-2.5.txt	2012-09-19 07:58:27 +0000
@@ -35,8 +35,23 @@
 * ``bzr config`` properly handles aliases and references in the
   ``--directory`` parameter (Vincent Ladeuil, Wouter van Heyst, #947049)
 
+* Lightweight checkouts of remote repositories had a bug with how they
+  extracted texts from the repository. (Just an ordering constraint on how
+  they consumed the stream.) (John Arbash Meinel, #1046284)
+
+* ``osutils.send_all`` now detects if we get a series of zero bytes sent,
+  and fails with a ECONNRESET. It seems if paramiko gets disconnected, it
+  will get into a state where it returns 0 bytes sent, but doesn't raise
+  an error. This change allows us to get a couple hiccups of no content
+  sent, but if it is consistent, we will consider it to be a failure.
+  (John Arbash Meinel, #1047309)
+
 * Revert use of --no-tty when gpg signing commits. (Jelmer Vernooij, #1014570)
 
+* Some small bug fixes wrt lightweight checkouts and remote repositories.
+  A test permutation was added that runs all working tree tests against a
+  lightweight checkout. (John Arbash Meinel, #1046697)
+
 Documentation
 *************
 




More information about the bazaar-commits mailing list