Rev 3807: Fix tracebacks caused by 'Permission denied' errors from a smart in file:///home/pqm/archives/thelove/bzr/%2Btrunk/

Canonical.com Patch Queue Manager pqm at pqm.ubuntu.com
Wed Oct 29 21:51:40 GMT 2008


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

------------------------------------------------------------
revno: 3807
revision-id: pqm at pqm.ubuntu.com-20081029215135-qbnx14rn0gagdvik
parent: pqm at pqm.ubuntu.com-20081029070146-p1cqjt23zctbpg51
parent: andrew.bennetts at canonical.com-20081029011946-m408t8eco1klvoio
committer: Canonical.com Patch Queue Manager <pqm at pqm.ubuntu.com>
branch nick: +trunk
timestamp: Wed 2008-10-29 21:51:35 +0000
message:
  Fix tracebacks caused by 'Permission denied' errors from a smart
  	server (bug 278673),
  	and refactor client-side smart error handling. (Andrew Bennetts)
modified:
  NEWS                           NEWS-20050323055033-4e00b5db738777ff
  bzrlib/errors.py               errors.py-20050309040759-20512168c4e14fbd
  bzrlib/remote.py               remote.py-20060720103555-yeeg2x51vn0rbtdp-1
  bzrlib/smart/request.py        request.py-20061108095550-gunadhxmzkdjfeek-1
  bzrlib/smart/vfs.py            vfs.py-20061108095550-gunadhxmzkdjfeek-2
  bzrlib/tests/test_remote.py    test_remote.py-20060720103555-yeeg2x51vn0rbtdp-2
  bzrlib/tests/test_smart_transport.py test_ssh_transport.py-20060608202016-c25gvf1ob7ypbus6-2
  bzrlib/transport/remote.py     ssh.py-20060608202016-c25gvf1ob7ypbus6-1
    ------------------------------------------------------------
    revno: 3786.2.6
    revision-id: andrew.bennetts at canonical.com-20081029011946-m408t8eco1klvoio
    parent: andrew.bennetts at canonical.com-20081021214652-uruf96yloni2nq7q
    parent: andrew.bennetts at canonical.com-20081029011826-jm8g7g2enemhekcc
    committer: Andrew Bennetts <andrew.bennetts at canonical.com>
    branch nick: Refactor error catching in Remote* classes.
    timestamp: Wed 2008-10-29 12:19:46 +1100
    message:
      Merge loom thread (includes latest bzr.dev and new tests in bt.test_remote).
    added:
      bzrlib/tests/fake_command.py   fake_command.py-20081021195002-r9v65tgxx63c25v9-1
      doc/developers/btree_index_prefetch.txt btree_index_request_-20081004155340-2u6apsy53f43f0xn-1
      tools/packaging/lp-upload-release lpuploadrelease-20081020075647-56zdf9z6yav1bx81-1
    modified:
      Makefile                       Makefile-20050805140406-d96e3498bb61c5bb
      NEWS                           NEWS-20050323055033-4e00b5db738777ff
      bzrlib/_walkdirs_win32.pyx     _walkdirs_win32.pyx-20080716220454-kweh3tgxez5dvw2l-2
      bzrlib/branch.py               branch.py-20050309040759-e4baf4e0d046576e
      bzrlib/btree_index.py          index.py-20080624222253-p0x5f92uyh5hw734-7
      bzrlib/builtins.py             builtins.py-20050830033751-fc01482b9ca23183
      bzrlib/chunk_writer.py         chunk_writer.py-20080630234519-6ggn4id17nipovny-1
      bzrlib/commands.py             bzr.py-20050309040720-d10f4714595cf8c3
      bzrlib/errors.py               errors.py-20050309040759-20512168c4e14fbd
      bzrlib/help_topics/en/hooks.txt hooks.txt-20070830033044-xxu2rced13f72dka-1
      bzrlib/index.py                index.py-20070712131115-lolkarso50vjr64s-1
      bzrlib/knit.py                 knit.py-20051212171256-f056ac8f0fbe1bd9
      bzrlib/lru_cache.py            lru_cache.py-20070119165515-tlw203kuwh0id5gv-1
      bzrlib/plugin.py               plugin.py-20050622060424-829b654519533d69
      bzrlib/plugins/launchpad/account.py account.py-20071011033320-50y6vfftywf4yllw-1
      bzrlib/plugins/launchpad/test_account.py test_account.py-20071011033320-50y6vfftywf4yllw-2
      bzrlib/python-compat.h         pythoncompat.h-20080924041409-9kvi0fgtuuqp743j-1
      bzrlib/remote.py               remote.py-20060720103555-yeeg2x51vn0rbtdp-1
      bzrlib/repofmt/pack_repo.py    pack_repo.py-20070813041115-gjv5ma7ktfqwsjgn-1
      bzrlib/repository.py           rev_storage.py-20051111201905-119e9401e46257e3
      bzrlib/revisiontree.py         revisiontree.py-20060724012533-bg8xyryhxd0o0i0h-1
      bzrlib/tests/__init__.py       selftest.py-20050531073622-8d0e3c8845c97a64
      bzrlib/tests/blackbox/test_command_encoding.py test_command_encoding.py-20060106032110-45431fd2ce9ff21f
      bzrlib/tests/blackbox/test_missing.py test_missing.py-20051211212735-a2cf4c1840bb84c4
      bzrlib/tests/branch_implementations/test_stacking.py test_stacking.py-20080214020755-msjlkb7urobwly0f-1
      bzrlib/tests/test_btree_index.py test_index.py-20080624222253-p0x5f92uyh5hw734-13
      bzrlib/tests/test_chunk_writer.py test_chunk_writer.py-20080630234519-6ggn4id17nipovny-2
      bzrlib/tests/test_commands.py  test_command.py-20051019190109-3b17be0f52eaa7a8
      bzrlib/tests/test_index.py     test_index.py-20070712131115-lolkarso50vjr64s-2
      bzrlib/tests/test_knit.py      test_knit.py-20051212171302-95d4c00dd5f11f2b
      bzrlib/tests/test_lru_cache.py test_lru_cache.py-20070119165535-hph6rk4h9rzy4180-1
      bzrlib/tests/test_pack_repository.py test_pack_repository-20080801043947-eaw0e6h2gu75kwmy-1
      bzrlib/tests/test_plugins.py   plugins.py-20050622075746-32002b55e5e943e9
      bzrlib/tests/test_remote.py    test_remote.py-20060720103555-yeeg2x51vn0rbtdp-2
      bzrlib/tests/test_repository.py test_repository.py-20060131075918-65c555b881612f4d
      bzrlib/tests/test_store.py     teststore.py-20050826022702-f6caadb647395769
      bzrlib/tests/tree_implementations/test_tree.py test_tree.py-20061215160206-usu7lwcj8aq2n3br-1
      bzrlib/transform.py            transform.py-20060105172343-dd99e54394d91687
      bzrlib/transport/__init__.py   transport.py-20050711165921-4978aa7ce1285ad5
      bzrlib/tree.py                 tree.py-20050309040759-9d5f2496be663e77
      bzrlib/win32utils.py           win32console.py-20051021033308-123c6c929d04973d
      bzrlib/workingtree.py          workingtree.py-20050511021032-29b6ec0a681e02e3
      bzrlib/workingtree_4.py        workingtree_4.py-20070208044105-5fgpc5j3ljlh5q6c-1
      doc/developers/ppa.txt         ppa.txt-20080722055539-606u7t2z32t3ae4w-1
      doc/developers/releasing.txt   releasing.txt-20080502015919-fnrcav8fwy8ccibu-1
      doc/en/user-guide/branching_a_project.txt branching_a_project.-20071122141511-0knao2lklsdsvb1q-2
      doc/en/user-guide/core_concepts.txt core_concepts.txt-20071114035000-q36a9h57ps06uvnl-2
      doc/en/user-guide/using_checkouts.txt using_checkouts.txt-20071123055134-k5x4ekduci2lbn36-4
        ------------------------------------------------------------
        revno: 3786.3.3
        revision-id: andrew.bennetts at canonical.com-20081029011826-jm8g7g2enemhekcc
        parent: andrew.bennetts at canonical.com-20081029010456-7j0c3bji305f9uy7
        parent: andrew.bennetts at canonical.com-20081029011707-yz42ky3kn63eh5th
        committer: Andrew Bennetts <andrew.bennetts at canonical.com>
        branch nick: Unify error decoding
        timestamp: Wed 2008-10-29 12:18:26 +1100
        message:
          Merge new tests from 'Always encode PermissionDenied and ReadError'.
        modified:
          bzrlib/errors.py               errors.py-20050309040759-20512168c4e14fbd
          bzrlib/tests/test_remote.py    test_remote.py-20060720103555-yeeg2x51vn0rbtdp-2
            ------------------------------------------------------------
            revno: 3786.4.3
            revision-id: andrew.bennetts at canonical.com-20081029011707-yz42ky3kn63eh5th
            parent: andrew.bennetts at canonical.com-20081029011622-sbppwxeujj23y6bo
            committer: Andrew Bennetts <andrew.bennetts at canonical.com>
            branch nick: Always encode PermissionDenied and ReadError
            timestamp: Wed 2008-10-29 12:17:07 +1100
            message:
              Add __repr__ to BzrError to make some test failure output clearer.
            modified:
              bzrlib/errors.py               errors.py-20050309040759-20512168c4e14fbd
            ------------------------------------------------------------
            revno: 3786.4.2
            revision-id: andrew.bennetts at canonical.com-20081029011622-sbppwxeujj23y6bo
            parent: andrew.bennetts at canonical.com-20081029004917-3xnmjrj0z9skkjsr
            committer: Andrew Bennetts <andrew.bennetts at canonical.com>
            branch nick: Always encode PermissionDenied and ReadError
            timestamp: Wed 2008-10-29 12:16:22 +1100
            message:
              Add tests and fix code to make sure ReadError and PermissionDenied are robustly handled by _translate_error.
            modified:
              bzrlib/remote.py               remote.py-20060720103555-yeeg2x51vn0rbtdp-1
              bzrlib/tests/test_remote.py    test_remote.py-20060720103555-yeeg2x51vn0rbtdp-2
        ------------------------------------------------------------
        revno: 3786.3.2
        revision-id: andrew.bennetts at canonical.com-20081029010456-7j0c3bji305f9uy7
        parent: andrew.bennetts at canonical.com-20081021214543-cxhpfnoqwoav35y1
        parent: andrew.bennetts at canonical.com-20081029004917-3xnmjrj0z9skkjsr
        committer: Andrew Bennetts <andrew.bennetts at canonical.com>
        branch nick: Unify error decoding
        timestamp: Wed 2008-10-29 12:04:56 +1100
        message:
          Merge thread.
        added:
          bzrlib/tests/fake_command.py   fake_command.py-20081021195002-r9v65tgxx63c25v9-1
          doc/developers/btree_index_prefetch.txt btree_index_request_-20081004155340-2u6apsy53f43f0xn-1
          tools/packaging/lp-upload-release lpuploadrelease-20081020075647-56zdf9z6yav1bx81-1
        modified:
          Makefile                       Makefile-20050805140406-d96e3498bb61c5bb
          NEWS                           NEWS-20050323055033-4e00b5db738777ff
          bzrlib/_walkdirs_win32.pyx     _walkdirs_win32.pyx-20080716220454-kweh3tgxez5dvw2l-2
          bzrlib/branch.py               branch.py-20050309040759-e4baf4e0d046576e
          bzrlib/btree_index.py          index.py-20080624222253-p0x5f92uyh5hw734-7
          bzrlib/builtins.py             builtins.py-20050830033751-fc01482b9ca23183
          bzrlib/chunk_writer.py         chunk_writer.py-20080630234519-6ggn4id17nipovny-1
          bzrlib/commands.py             bzr.py-20050309040720-d10f4714595cf8c3
          bzrlib/errors.py               errors.py-20050309040759-20512168c4e14fbd
          bzrlib/help_topics/en/hooks.txt hooks.txt-20070830033044-xxu2rced13f72dka-1
          bzrlib/index.py                index.py-20070712131115-lolkarso50vjr64s-1
          bzrlib/knit.py                 knit.py-20051212171256-f056ac8f0fbe1bd9
          bzrlib/lru_cache.py            lru_cache.py-20070119165515-tlw203kuwh0id5gv-1
          bzrlib/plugin.py               plugin.py-20050622060424-829b654519533d69
          bzrlib/plugins/launchpad/account.py account.py-20071011033320-50y6vfftywf4yllw-1
          bzrlib/plugins/launchpad/test_account.py test_account.py-20071011033320-50y6vfftywf4yllw-2
          bzrlib/python-compat.h         pythoncompat.h-20080924041409-9kvi0fgtuuqp743j-1
          bzrlib/remote.py               remote.py-20060720103555-yeeg2x51vn0rbtdp-1
          bzrlib/repofmt/pack_repo.py    pack_repo.py-20070813041115-gjv5ma7ktfqwsjgn-1
          bzrlib/repository.py           rev_storage.py-20051111201905-119e9401e46257e3
          bzrlib/revisiontree.py         revisiontree.py-20060724012533-bg8xyryhxd0o0i0h-1
          bzrlib/tests/__init__.py       selftest.py-20050531073622-8d0e3c8845c97a64
          bzrlib/tests/blackbox/test_command_encoding.py test_command_encoding.py-20060106032110-45431fd2ce9ff21f
          bzrlib/tests/blackbox/test_missing.py test_missing.py-20051211212735-a2cf4c1840bb84c4
          bzrlib/tests/branch_implementations/test_stacking.py test_stacking.py-20080214020755-msjlkb7urobwly0f-1
          bzrlib/tests/test_btree_index.py test_index.py-20080624222253-p0x5f92uyh5hw734-13
          bzrlib/tests/test_chunk_writer.py test_chunk_writer.py-20080630234519-6ggn4id17nipovny-2
          bzrlib/tests/test_commands.py  test_command.py-20051019190109-3b17be0f52eaa7a8
          bzrlib/tests/test_index.py     test_index.py-20070712131115-lolkarso50vjr64s-2
          bzrlib/tests/test_knit.py      test_knit.py-20051212171302-95d4c00dd5f11f2b
          bzrlib/tests/test_lru_cache.py test_lru_cache.py-20070119165535-hph6rk4h9rzy4180-1
          bzrlib/tests/test_pack_repository.py test_pack_repository-20080801043947-eaw0e6h2gu75kwmy-1
          bzrlib/tests/test_plugins.py   plugins.py-20050622075746-32002b55e5e943e9
          bzrlib/tests/test_repository.py test_repository.py-20060131075918-65c555b881612f4d
          bzrlib/tests/test_store.py     teststore.py-20050826022702-f6caadb647395769
          bzrlib/tests/tree_implementations/test_tree.py test_tree.py-20061215160206-usu7lwcj8aq2n3br-1
          bzrlib/transform.py            transform.py-20060105172343-dd99e54394d91687
          bzrlib/transport/__init__.py   transport.py-20050711165921-4978aa7ce1285ad5
          bzrlib/tree.py                 tree.py-20050309040759-9d5f2496be663e77
          bzrlib/win32utils.py           win32console.py-20051021033308-123c6c929d04973d
          bzrlib/workingtree.py          workingtree.py-20050511021032-29b6ec0a681e02e3
          bzrlib/workingtree_4.py        workingtree_4.py-20070208044105-5fgpc5j3ljlh5q6c-1
          doc/developers/ppa.txt         ppa.txt-20080722055539-606u7t2z32t3ae4w-1
          doc/developers/releasing.txt   releasing.txt-20080502015919-fnrcav8fwy8ccibu-1
          doc/en/user-guide/branching_a_project.txt branching_a_project.-20071122141511-0knao2lklsdsvb1q-2
          doc/en/user-guide/core_concepts.txt core_concepts.txt-20071114035000-q36a9h57ps06uvnl-2
          doc/en/user-guide/using_checkouts.txt using_checkouts.txt-20071123055134-k5x4ekduci2lbn36-4
        ------------------------------------------------------------
        revno: 3786.4.1
        revision-id: andrew.bennetts at canonical.com-20081029004917-3xnmjrj0z9skkjsr
        parent: andrew.bennetts at canonical.com-20081020120522-z5ogdmu0citd690d
        parent: pqm at pqm.ubuntu.com-20081028202057-u3csau9zvf0hapya
        committer: Andrew Bennetts <andrew.bennetts at canonical.com>
        branch nick: Always encode PermissionDenied and ReadError
        timestamp: Wed 2008-10-29 11:49:17 +1100
        message:
          Merge from bzr.dev.
        added:
          bzrlib/tests/fake_command.py   fake_command.py-20081021195002-r9v65tgxx63c25v9-1
          doc/developers/btree_index_prefetch.txt btree_index_request_-20081004155340-2u6apsy53f43f0xn-1
          tools/packaging/lp-upload-release lpuploadrelease-20081020075647-56zdf9z6yav1bx81-1
        modified:
          Makefile                       Makefile-20050805140406-d96e3498bb61c5bb
          NEWS                           NEWS-20050323055033-4e00b5db738777ff
          bzrlib/_walkdirs_win32.pyx     _walkdirs_win32.pyx-20080716220454-kweh3tgxez5dvw2l-2
          bzrlib/branch.py               branch.py-20050309040759-e4baf4e0d046576e
          bzrlib/btree_index.py          index.py-20080624222253-p0x5f92uyh5hw734-7
          bzrlib/builtins.py             builtins.py-20050830033751-fc01482b9ca23183
          bzrlib/chunk_writer.py         chunk_writer.py-20080630234519-6ggn4id17nipovny-1
          bzrlib/commands.py             bzr.py-20050309040720-d10f4714595cf8c3
          bzrlib/errors.py               errors.py-20050309040759-20512168c4e14fbd
          bzrlib/help_topics/en/hooks.txt hooks.txt-20070830033044-xxu2rced13f72dka-1
          bzrlib/index.py                index.py-20070712131115-lolkarso50vjr64s-1
          bzrlib/knit.py                 knit.py-20051212171256-f056ac8f0fbe1bd9
          bzrlib/lru_cache.py            lru_cache.py-20070119165515-tlw203kuwh0id5gv-1
          bzrlib/plugin.py               plugin.py-20050622060424-829b654519533d69
          bzrlib/plugins/launchpad/account.py account.py-20071011033320-50y6vfftywf4yllw-1
          bzrlib/plugins/launchpad/test_account.py test_account.py-20071011033320-50y6vfftywf4yllw-2
          bzrlib/python-compat.h         pythoncompat.h-20080924041409-9kvi0fgtuuqp743j-1
          bzrlib/remote.py               remote.py-20060720103555-yeeg2x51vn0rbtdp-1
          bzrlib/repofmt/pack_repo.py    pack_repo.py-20070813041115-gjv5ma7ktfqwsjgn-1
          bzrlib/repository.py           rev_storage.py-20051111201905-119e9401e46257e3
          bzrlib/revisiontree.py         revisiontree.py-20060724012533-bg8xyryhxd0o0i0h-1
          bzrlib/tests/__init__.py       selftest.py-20050531073622-8d0e3c8845c97a64
          bzrlib/tests/blackbox/test_command_encoding.py test_command_encoding.py-20060106032110-45431fd2ce9ff21f
          bzrlib/tests/blackbox/test_missing.py test_missing.py-20051211212735-a2cf4c1840bb84c4
          bzrlib/tests/branch_implementations/test_stacking.py test_stacking.py-20080214020755-msjlkb7urobwly0f-1
          bzrlib/tests/test_btree_index.py test_index.py-20080624222253-p0x5f92uyh5hw734-13
          bzrlib/tests/test_chunk_writer.py test_chunk_writer.py-20080630234519-6ggn4id17nipovny-2
          bzrlib/tests/test_commands.py  test_command.py-20051019190109-3b17be0f52eaa7a8
          bzrlib/tests/test_index.py     test_index.py-20070712131115-lolkarso50vjr64s-2
          bzrlib/tests/test_knit.py      test_knit.py-20051212171302-95d4c00dd5f11f2b
          bzrlib/tests/test_lru_cache.py test_lru_cache.py-20070119165535-hph6rk4h9rzy4180-1
          bzrlib/tests/test_pack_repository.py test_pack_repository-20080801043947-eaw0e6h2gu75kwmy-1
          bzrlib/tests/test_plugins.py   plugins.py-20050622075746-32002b55e5e943e9
          bzrlib/tests/test_repository.py test_repository.py-20060131075918-65c555b881612f4d
          bzrlib/tests/test_store.py     teststore.py-20050826022702-f6caadb647395769
          bzrlib/tests/tree_implementations/test_tree.py test_tree.py-20061215160206-usu7lwcj8aq2n3br-1
          bzrlib/transform.py            transform.py-20060105172343-dd99e54394d91687
          bzrlib/transport/__init__.py   transport.py-20050711165921-4978aa7ce1285ad5
          bzrlib/tree.py                 tree.py-20050309040759-9d5f2496be663e77
          bzrlib/win32utils.py           win32console.py-20051021033308-123c6c929d04973d
          bzrlib/workingtree.py          workingtree.py-20050511021032-29b6ec0a681e02e3
          bzrlib/workingtree_4.py        workingtree_4.py-20070208044105-5fgpc5j3ljlh5q6c-1
          doc/developers/ppa.txt         ppa.txt-20080722055539-606u7t2z32t3ae4w-1
          doc/developers/releasing.txt   releasing.txt-20080502015919-fnrcav8fwy8ccibu-1
          doc/en/user-guide/branching_a_project.txt branching_a_project.-20071122141511-0knao2lklsdsvb1q-2
          doc/en/user-guide/core_concepts.txt core_concepts.txt-20071114035000-q36a9h57ps06uvnl-2
          doc/en/user-guide/using_checkouts.txt using_checkouts.txt-20071123055134-k5x4ekduci2lbn36-4
    ------------------------------------------------------------
    revno: 3786.2.5
    revision-id: andrew.bennetts at canonical.com-20081021214652-uruf96yloni2nq7q
    parent: andrew.bennetts at canonical.com-20081021055910-u6yii5k2add0sw2s
    parent: andrew.bennetts at canonical.com-20081021214543-cxhpfnoqwoav35y1
    committer: Andrew Bennetts <andrew.bennetts at canonical.com>
    branch nick: Refactor error catching in Remote* classes.
    timestamp: Wed 2008-10-22 08:46:52 +1100
    message:
      Merge from loom thread.
        ------------------------------------------------------------
        revno: 3786.3.1
        revision-id: andrew.bennetts at canonical.com-20081021214543-cxhpfnoqwoav35y1
        parent: andrew.bennetts at canonical.com-20081020120656-jqttn3kqvu1u5pfa
        committer: Andrew Bennetts <andrew.bennetts at canonical.com>
        branch nick: Unify error decoding
        timestamp: Wed 2008-10-22 08:45:43 +1100
        message:
          Fix unbound local in _translate_error.
        modified:
          bzrlib/remote.py               remote.py-20060720103555-yeeg2x51vn0rbtdp-1
    ------------------------------------------------------------
    revno: 3786.2.4
    revision-id: andrew.bennetts at canonical.com-20081021055910-u6yii5k2add0sw2s
    parent: andrew.bennetts at canonical.com-20081020125231-gv4dn91he3j4e7zk
    committer: Andrew Bennetts <andrew.bennetts at canonical.com>
    branch nick: Refactor error catching in Remote* classes.
    timestamp: Tue 2008-10-21 16:59:10 +1100
    message:
      Add NEWS entry, because this branch fixes #278673.
    modified:
      NEWS                           NEWS-20050323055033-4e00b5db738777ff
    ------------------------------------------------------------
    revno: 3786.2.3
    revision-id: andrew.bennetts at canonical.com-20081020125231-gv4dn91he3j4e7zk
    parent: andrew.bennetts at canonical.com-20081020120656-jqttn3kqvu1u5pfa
    committer: Andrew Bennetts <andrew.bennetts at canonical.com>
    branch nick: Refactor error catching in Remote* classes.
    timestamp: Mon 2008-10-20 23:52:31 +1100
    message:
      Remove duplicated 'call & translate errors' code in bzrlib.remote.
      
      Also fixes many places in bzrlib.remote that were missing error translation!
    modified:
      bzrlib/remote.py               remote.py-20060720103555-yeeg2x51vn0rbtdp-1
    ------------------------------------------------------------
    revno: 3786.2.2
    revision-id: andrew.bennetts at canonical.com-20081020120656-jqttn3kqvu1u5pfa
    parent: andrew.bennetts at canonical.com-20081020120522-z5ogdmu0citd690d
    parent: andrew.bennetts at canonical.com-20081017060607-zk5au6wuq2vpdhkw
    committer: Andrew Bennetts <andrew.bennetts at canonical.com>
    branch nick: Unify error decoding
    timestamp: Mon 2008-10-20 23:06:56 +1100
    message:
      Unify error translation done in bzrlib.remote and bzrlib.transport.remote.
    modified:
      bzrlib/remote.py               remote.py-20060720103555-yeeg2x51vn0rbtdp-1
      bzrlib/tests/test_smart_transport.py test_ssh_transport.py-20060608202016-c25gvf1ob7ypbus6-2
      bzrlib/transport/remote.py     ssh.py-20060608202016-c25gvf1ob7ypbus6-1
        ------------------------------------------------------------
        revno: 3779.3.3
        revision-id: andrew.bennetts at canonical.com-20081017060607-zk5au6wuq2vpdhkw
        parent: andrew.bennetts at canonical.com-20081017060110-hx8shx11fhyiionq
        committer: Andrew Bennetts <andrew.bennetts at canonical.com>
        branch nick: hpss-error-translation
        timestamp: Fri 2008-10-17 17:06:07 +1100
        message:
          Add a docstring.
        modified:
          bzrlib/remote.py               remote.py-20060720103555-yeeg2x51vn0rbtdp-1
        ------------------------------------------------------------
        revno: 3779.3.2
        revision-id: andrew.bennetts at canonical.com-20081017060110-hx8shx11fhyiionq
        parent: andrew.bennetts at canonical.com-20081016055443-nsppqkpy3ospbhu3
        committer: Andrew Bennetts <andrew.bennetts at canonical.com>
        branch nick: hpss-error-translation
        timestamp: Fri 2008-10-17 17:01:10 +1100
        message:
          Unify error translation done in bzrlib.remote and bzrlib.transport.remote.
        modified:
          bzrlib/remote.py               remote.py-20060720103555-yeeg2x51vn0rbtdp-1
          bzrlib/tests/test_smart_transport.py test_ssh_transport.py-20060608202016-c25gvf1ob7ypbus6-2
          bzrlib/transport/remote.py     ssh.py-20060608202016-c25gvf1ob7ypbus6-1
    ------------------------------------------------------------
    revno: 3786.2.1
    revision-id: andrew.bennetts at canonical.com-20081020120522-z5ogdmu0citd690d
    parent: pqm at pqm.ubuntu.com-20081020020359-7f8c4hviijt1m5vq
    parent: andrew.bennetts at canonical.com-20081016055443-nsppqkpy3ospbhu3
    committer: Andrew Bennetts <andrew.bennetts at canonical.com>
    branch nick: Always encode PermissionDenied and ReadError
    timestamp: Mon 2008-10-20 23:05:22 +1100
    message:
      Move encoding/decoding logic of PermissionDenied and ReadError so that it happens for all RPCs.
    modified:
      bzrlib/remote.py               remote.py-20060720103555-yeeg2x51vn0rbtdp-1
      bzrlib/smart/request.py        request.py-20061108095550-gunadhxmzkdjfeek-1
      bzrlib/smart/vfs.py            vfs.py-20061108095550-gunadhxmzkdjfeek-2
    ------------------------------------------------------------
    revno: 3779.3.1
    revision-id: andrew.bennetts at canonical.com-20081016055443-nsppqkpy3ospbhu3
    parent: pqm at pqm.ubuntu.com-20081016043554-38i4ho6svnlyba65
    committer: Andrew Bennetts <andrew.bennetts at canonical.com>
    branch nick: hpss-error-translation
    timestamp: Thu 2008-10-16 16:54:43 +1100
    message:
      Move encoding/decoding logic of PermissionDenied and ReadError so that it happens for all RPCs.
    modified:
      bzrlib/remote.py               remote.py-20060720103555-yeeg2x51vn0rbtdp-1
      bzrlib/smart/request.py        request.py-20061108095550-gunadhxmzkdjfeek-1
      bzrlib/smart/vfs.py            vfs.py-20061108095550-gunadhxmzkdjfeek-2
=== modified file 'NEWS'
--- a/NEWS	2008-10-29 06:19:35 +0000
+++ b/NEWS	2008-10-29 21:51:35 +0000
@@ -67,6 +67,9 @@
       could only happen if ``bzr reconcile`` decided that the parent
       ordering was incorrect in the file graph.  (John Arbash Meinel)
 
+    * "Permission denied" errors that occur when pushing a new branch to a
+      smart server no longer cause tracebacks.  (Andrew Bennetts, #278673)
+
     * Some compatibility fixes for building the extensions with MSVC and
       for python2.4. (John Arbash Meinel, #277484)
 

=== modified file 'bzrlib/errors.py'
--- a/bzrlib/errors.py	2008-10-21 03:47:13 +0000
+++ b/bzrlib/errors.py	2008-10-29 01:17:07 +0000
@@ -134,6 +134,9 @@
             s = str(s)
         return s
 
+    def __repr__(self):
+        return '%s(%s)' % (self.__class__.__name__, str(self))
+
     def _get_format_string(self):
         """Return format string for this exception or None"""
         fmt = getattr(self, '_fmt', None)

=== modified file 'bzrlib/remote.py'
--- a/bzrlib/remote.py	2008-10-27 06:14:45 +0000
+++ b/bzrlib/remote.py	2008-10-29 01:19:46 +0000
@@ -43,9 +43,32 @@
 from bzrlib.trace import mutter, note, warning
 
 
+class _RpcHelper(object):
+    """Mixin class that helps with issuing RPCs."""
+
+    def _call(self, method, *args, **err_context):
+        try:
+            return self._client.call(method, *args)
+        except errors.ErrorFromSmartServer, err:
+            self._translate_error(err, **err_context)
+        
+    def _call_expecting_body(self, method, *args, **err_context):
+        try:
+            return self._client.call_expecting_body(method, *args)
+        except errors.ErrorFromSmartServer, err:
+            self._translate_error(err, **err_context)
+        
+    def _call_with_body_bytes_expecting_body(self, method, args, body_bytes,
+                                             **err_context):
+        try:
+            return self._client.call_with_body_bytes_expecting_body(
+                method, args, body_bytes)
+        except errors.ErrorFromSmartServer, err:
+            self._translate_error(err, **err_context)
+        
 # Note: RemoteBzrDirFormat is in bzrdir.py
 
-class RemoteBzrDir(BzrDir):
+class RemoteBzrDir(BzrDir, _RpcHelper):
     """Control directory on a remote server, accessed via bzr:// or similar."""
 
     def __init__(self, transport, _client=None):
@@ -67,7 +90,7 @@
             return
 
         path = self._path_for_remote_call(self._client)
-        response = self._client.call('BzrDir.open', path)
+        response = self._call('BzrDir.open', path)
         if response not in [('yes',), ('no',)]:
             raise errors.UnexpectedSmartServerResponse(response)
         if response == ('no',):
@@ -82,13 +105,13 @@
             self._real_bzrdir = BzrDir.open_from_transport(
                 self.root_transport, _server_formats=False)
 
+    def _translate_error(self, err, **context):
+        _translate_error(err, bzrdir=self, **context)
+
     def cloning_metadir(self, stacked=False):
         self._ensure_real()
         return self._real_bzrdir.cloning_metadir(stacked)
 
-    def _translate_error(self, err, **context):
-        _translate_error(err, bzrdir=self, **context)
-        
     def create_repository(self, shared=False):
         self._ensure_real()
         self._real_bzrdir.create_repository(shared=shared)
@@ -123,10 +146,7 @@
     def get_branch_reference(self):
         """See BzrDir.get_branch_reference()."""
         path = self._path_for_remote_call(self._client)
-        try:
-            response = self._client.call('BzrDir.open_branch', path)
-        except errors.ErrorFromSmartServer, err:
-            self._translate_error(err)
+        response = self._call('BzrDir.open_branch', path)
         if response[0] == 'ok':
             if response[1] == '':
                 # branch at this location.
@@ -157,13 +177,10 @@
         path = self._path_for_remote_call(self._client)
         verb = 'BzrDir.find_repositoryV2'
         try:
-            try:
-                response = self._client.call(verb, path)
-            except errors.UnknownSmartMethod:
-                verb = 'BzrDir.find_repository'
-                response = self._client.call(verb, path)
-        except errors.ErrorFromSmartServer, err:
-            self._translate_error(err)
+            response = self._call(verb, path)
+        except errors.UnknownSmartMethod:
+            verb = 'BzrDir.find_repository'
+            response = self._call(verb, path)
         if response[0] != 'ok':
             raise errors.UnexpectedSmartServerResponse(response)
         if verb == 'BzrDir.find_repository':
@@ -270,7 +287,7 @@
                 'Does not support nested trees', target_format)
 
 
-class RemoteRepository(object):
+class RemoteRepository(_RpcHelper):
     """Repository accessed over rpc.
 
     For the moment most operations are performed using local transport-backed
@@ -396,11 +413,8 @@
             return {}
 
         path = self.bzrdir._path_for_remote_call(self._client)
-        try:
-            response = self._client.call_expecting_body(
-                'Repository.get_revision_graph', path, revision_id)
-        except errors.ErrorFromSmartServer, err:
-            self._translate_error(err)
+        response = self._call_expecting_body(
+            'Repository.get_revision_graph', path, revision_id)
         response_tuple, response_handler = response
         if response_tuple[0] != 'ok':
             raise errors.UnexpectedSmartServerResponse(response_tuple)
@@ -422,8 +436,7 @@
             # The null revision is always present.
             return True
         path = self.bzrdir._path_for_remote_call(self._client)
-        response = self._client.call(
-            'Repository.has_revision', path, revision_id)
+        response = self._call('Repository.has_revision', path, revision_id)
         if response[0] not in ('yes', 'no'):
             raise errors.UnexpectedSmartServerResponse(response)
         if response[0] == 'yes':
@@ -469,7 +482,7 @@
             fmt_committers = 'no'
         else:
             fmt_committers = 'yes'
-        response_tuple, response_handler = self._client.call_expecting_body(
+        response_tuple, response_handler = self._call_expecting_body(
             'Repository.gather_stats', path, fmt_revid, fmt_committers)
         if response_tuple[0] != 'ok':
             raise errors.UnexpectedSmartServerResponse(response_tuple)
@@ -514,7 +527,7 @@
     def is_shared(self):
         """See Repository.is_shared()."""
         path = self.bzrdir._path_for_remote_call(self._client)
-        response = self._client.call('Repository.is_shared', path)
+        response = self._call('Repository.is_shared', path)
         if response[0] not in ('yes', 'no'):
             raise SmartProtocolError('unexpected response code %s' % (response,))
         return response[0] == 'yes'
@@ -539,11 +552,9 @@
         path = self.bzrdir._path_for_remote_call(self._client)
         if token is None:
             token = ''
-        try:
-            response = self._client.call('Repository.lock_write', path, token)
-        except errors.ErrorFromSmartServer, err:
-            self._translate_error(err, token=token)
-
+        err_context = {'token': token}
+        response = self._call('Repository.lock_write', path, token,
+                              **err_context)
         if response[0] == 'ok':
             ok, token = response
             return token
@@ -626,10 +637,9 @@
         if not token:
             # with no token the remote repository is not persistently locked.
             return
-        try:
-            response = self._client.call('Repository.unlock', path, token)
-        except errors.ErrorFromSmartServer, err:
-            self._translate_error(err, token=token)
+        err_context = {'token': token}
+        response = self._call('Repository.unlock', path, token,
+                              **err_context)
         if response == ('ok',):
             return
         else:
@@ -676,7 +686,7 @@
         import tempfile
         path = self.bzrdir._path_for_remote_call(self._client)
         try:
-            response, protocol = self._client.call_expecting_body(
+            response, protocol = self._call_expecting_body(
                 'Repository.tarball', path, compression)
         except errors.UnknownSmartMethod:
             protocol.cancel_read_body()
@@ -962,7 +972,7 @@
         verb = 'Repository.get_parent_map'
         args = (path,) + tuple(keys)
         try:
-            response = self._client.call_with_body_bytes_expecting_body(
+            response = self._call_with_body_bytes_expecting_body(
                 verb, args, self._serialise_search_recipe(recipe))
         except errors.UnknownSmartMethod:
             # Server does not support this method, so get the whole graph.
@@ -1252,7 +1262,7 @@
         return True
 
 
-class RemoteBranch(branch.Branch):
+class RemoteBranch(branch.Branch, _RpcHelper):
     """Branch stored on a server accessed by HPSS RPC.
 
     At the moment most operations are mapped down to simple file operations.
@@ -1409,11 +1419,10 @@
             stacking.
         """
         try:
+            # there may not be a repository yet, so we can't use
+            # self._translate_error, so we can't use self._call either.
             response = self._client.call('Branch.get_stacked_on_url',
                 self._remote_path())
-            if response[0] != 'ok':
-                raise errors.UnexpectedSmartServerResponse(response)
-            return response[1]
         except errors.ErrorFromSmartServer, err:
             # there may not be a repository yet, so we can't call through
             # its _translate_error
@@ -1421,6 +1430,9 @@
         except errors.UnknownSmartMethod, err:
             self._ensure_real()
             return self._real_branch.get_stacked_on_url()
+        if response[0] != 'ok':
+            raise errors.UnexpectedSmartServerResponse(response)
+        return response[1]
 
     def lock_read(self):
         self.repository.lock_read()
@@ -1439,12 +1451,10 @@
             branch_token = token
             repo_token = self.repository.lock_write()
             self.repository.unlock()
-        try:
-            response = self._client.call(
-                'Branch.lock_write', self._remote_path(),
-                branch_token, repo_token or '')
-        except errors.ErrorFromSmartServer, err:
-            self._translate_error(err, token=token)
+        err_context = {'token': token}
+        response = self._call(
+            'Branch.lock_write', self._remote_path(), branch_token,
+            repo_token or '', **err_context)
         if response[0] != 'ok':
             raise errors.UnexpectedSmartServerResponse(response)
         ok, branch_token, repo_token = response
@@ -1484,11 +1494,10 @@
         return self._lock_token or None
 
     def _unlock(self, branch_token, repo_token):
-        try:
-            response = self._client.call('Branch.unlock', self._remote_path(), branch_token,
-                                         repo_token or '')
-        except errors.ErrorFromSmartServer, err:
-            self._translate_error(err, token=str((branch_token, repo_token)))
+        err_context = {'token': str((branch_token, repo_token))}
+        response = self._call(
+            'Branch.unlock', self._remote_path(), branch_token,
+            repo_token or '', **err_context)
         if response == ('ok',):
             return
         raise errors.UnexpectedSmartServerResponse(response)
@@ -1539,7 +1548,7 @@
         self._leave_lock = False
 
     def _last_revision_info(self):
-        response = self._client.call('Branch.last_revision_info', self._remote_path())
+        response = self._call('Branch.last_revision_info', self._remote_path())
         if response[0] != 'ok':
             raise SmartProtocolError('unexpected response code %s' % (response,))
         revno = int(response[1])
@@ -1548,7 +1557,7 @@
 
     def _gen_revision_history(self):
         """See Branch._gen_revision_history()."""
-        response_tuple, response_handler = self._client.call_expecting_body(
+        response_tuple, response_handler = self._call_expecting_body(
             'Branch.revision_history', self._remote_path())
         if response_tuple[0] != 'ok':
             raise errors.UnexpectedSmartServerResponse(response_tuple)
@@ -1562,12 +1571,11 @@
 
     def _set_last_revision_descendant(self, revision_id, other_branch,
             allow_diverged=False, allow_overwrite_descendant=False):
-        try:
-            response = self._client.call('Branch.set_last_revision_ex',
-                self._remote_path(), self._lock_token, self._repo_lock_token, revision_id,
-                int(allow_diverged), int(allow_overwrite_descendant))
-        except errors.ErrorFromSmartServer, err:
-            self._translate_error(err, other_branch=other_branch)
+        err_context = {'other_branch': other_branch}
+        response = self._call('Branch.set_last_revision_ex',
+            self._remote_path(), self._lock_token, self._repo_lock_token,
+            revision_id, int(allow_diverged), int(allow_overwrite_descendant),
+            **err_context)
         self._clear_cached_state()
         if len(response) != 3 and response[0] != 'ok':
             raise errors.UnexpectedSmartServerResponse(response)
@@ -1579,11 +1587,9 @@
 
     def _set_last_revision(self, revision_id):
         self._clear_cached_state()
-        try:
-            response = self._client.call('Branch.set_last_revision',
-                self._remote_path(), self._lock_token, self._repo_lock_token, revision_id)
-        except errors.ErrorFromSmartServer, err:
-            self._translate_error(err)
+        response = self._call('Branch.set_last_revision',
+            self._remote_path(), self._lock_token, self._repo_lock_token,
+            revision_id)
         if response != ('ok',):
             raise errors.UnexpectedSmartServerResponse(response)
 
@@ -1657,16 +1663,15 @@
     def set_last_revision_info(self, revno, revision_id):
         revision_id = ensure_null(revision_id)
         try:
-            response = self._client.call('Branch.set_last_revision_info',
-                self._remote_path(), self._lock_token, self._repo_lock_token, str(revno), revision_id)
+            response = self._call('Branch.set_last_revision_info',
+                self._remote_path(), self._lock_token, self._repo_lock_token,
+                str(revno), revision_id)
         except errors.UnknownSmartMethod:
             self._ensure_real()
             self._clear_cached_state_of_remote_branch_only()
             self._real_branch.set_last_revision_info(revno, revision_id)
             self._last_revision_info_cache = revno, revision_id
             return
-        except errors.ErrorFromSmartServer, err:
-            self._translate_error(err)
         if response == ('ok',):
             self._clear_cached_state()
             self._last_revision_info_cache = revno, revision_id
@@ -1760,6 +1765,7 @@
       - bzrdir
       - token
       - other_branch
+      - path
 
     If the error from the server doesn't match a known pattern, then
     UnknownErrorFromSmartServer is raised.
@@ -1767,9 +1773,23 @@
     def find(name):
         try:
             return context[name]
-        except KeyError, keyErr:
-            mutter('Missing key %r in context %r', keyErr.args[0], context)
+        except KeyError, key_err:
+            mutter('Missing key %r in context %r', key_err.args[0], context)
             raise err
+    def get_path():
+        """Get the path from the context if present, otherwise use first error
+        arg.
+        """
+        try:
+            return context['path']
+        except KeyError, key_err:
+            try:
+                return err.error_args[0]
+            except IndexError, idx_err:
+                mutter(
+                    'Missing key %r in context %r', key_err.args[0], context)
+                raise err
+
     if err.error_verb == 'NoSuchRevision':
         raise NoSuchRevision(find('branch'), err.error_args[0])
     elif err.error_verb == 'nosuchrevision':
@@ -1796,4 +1816,41 @@
         raise errors.UnstackableRepositoryFormat(*err.error_args)
     elif err.error_verb == 'NotStacked':
         raise errors.NotStacked(branch=find('branch'))
+    elif err.error_verb == 'PermissionDenied':
+        path = get_path()
+        if len(err.error_args) >= 2:
+            extra = err.error_args[1]
+        else:
+            extra = None
+        raise errors.PermissionDenied(path, extra=extra)
+    elif err.error_verb == 'ReadError':
+        path = get_path()
+        raise errors.ReadError(path)
+    elif err.error_verb == 'NoSuchFile':
+        path = get_path()
+        raise errors.NoSuchFile(path)
+    elif err.error_verb == 'FileExists':
+        raise errors.FileExists(err.error_args[0])
+    elif err.error_verb == 'DirectoryNotEmpty':
+        raise errors.DirectoryNotEmpty(err.error_args[0])
+    elif err.error_verb == 'ShortReadvError':
+        args = err.error_args
+        raise errors.ShortReadvError(
+            args[0], int(args[1]), int(args[2]), int(args[3]))
+    elif err.error_verb in ('UnicodeEncodeError', 'UnicodeDecodeError'):
+        encoding = str(err.error_args[0]) # encoding must always be a string
+        val = err.error_args[1]
+        start = int(err.error_args[2])
+        end = int(err.error_args[3])
+        reason = str(err.error_args[4]) # reason must always be a string
+        if val.startswith('u:'):
+            val = val[2:].decode('utf-8')
+        elif val.startswith('s:'):
+            val = val[2:].decode('base64')
+        if err.error_verb == 'UnicodeDecodeError':
+            raise UnicodeDecodeError(encoding, val, start, end, reason)
+        elif err.error_verb == 'UnicodeEncodeError':
+            raise UnicodeEncodeError(encoding, val, start, end, reason)
+    elif err.error_verb == 'ReadOnlyError':
+        raise errors.TransportNotPossible('readonly transport')
     raise errors.UnknownErrorFromSmartServer(err)

=== modified file 'bzrlib/smart/request.py'
--- a/bzrlib/smart/request.py	2008-10-01 05:40:45 +0000
+++ b/bzrlib/smart/request.py	2008-10-16 05:54:43 +0000
@@ -303,8 +303,9 @@
             # with a plain string
             str_or_unicode = e.object
             if isinstance(str_or_unicode, unicode):
-                # XXX: UTF-8 might have \x01 (our seperator byte) in it.  We
-                # should escape it somehow.
+                # XXX: UTF-8 might have \x01 (our protocol v1 and v2 seperator
+                # byte) in it, so this encoding could cause broken responses.
+                # Newer clients use protocol v3, so will be fine.
                 val = 'u:' + str_or_unicode.encode('utf-8')
             else:
                 val = 's:' + str_or_unicode.encode('base64')
@@ -316,6 +317,12 @@
                 return FailedSmartServerResponse(('ReadOnlyError', ))
             else:
                 raise
+        except errors.ReadError, e:
+            # cannot read the file
+            return FailedSmartServerResponse(('ReadError', e.path))
+        except errors.PermissionDenied, e:
+            return FailedSmartServerResponse(
+                ('PermissionDenied', e.path, e.extra))
 
     def headers_received(self, headers):
         # Just a no-op at the moment.

=== modified file 'bzrlib/smart/vfs.py'
--- a/bzrlib/smart/vfs.py	2008-01-04 03:12:11 +0000
+++ b/bzrlib/smart/vfs.py	2008-10-16 05:54:43 +0000
@@ -72,13 +72,7 @@
 
     def do(self, relpath):
         relpath = self.translate_client_path(relpath)
-        try:
-            backing_bytes = self._backing_transport.get_bytes(relpath)
-        except errors.ReadError:
-            # cannot read the file
-            return request.FailedSmartServerResponse(('ReadError', ))
-        except errors.PermissionDenied:
-            return request.FailedSmartServerResponse(('PermissionDenied',))
+        backing_bytes = self._backing_transport.get_bytes(relpath)
         return request.SuccessfulSmartServerResponse(('ok',), backing_bytes)
 
 

=== modified file 'bzrlib/tests/test_remote.py'
--- a/bzrlib/tests/test_remote.py	2008-10-15 18:45:28 +0000
+++ b/bzrlib/tests/test_remote.py	2008-10-29 01:16:22 +0000
@@ -1551,6 +1551,50 @@
         expected_error = errors.DivergedBranches(branch, other_branch)
         self.assertEqual(expected_error, translated_error)
 
+    def test_ReadError_no_args(self):
+        path = 'a path'
+        translated_error = self.translateTuple(('ReadError',), path=path)
+        expected_error = errors.ReadError(path)
+        self.assertEqual(expected_error, translated_error)
+
+    def test_ReadError(self):
+        path = 'a path'
+        translated_error = self.translateTuple(('ReadError', path))
+        expected_error = errors.ReadError(path)
+        self.assertEqual(expected_error, translated_error)
+
+    def test_PermissionDenied_no_args(self):
+        path = 'a path'
+        translated_error = self.translateTuple(('PermissionDenied',), path=path)
+        expected_error = errors.PermissionDenied(path)
+        self.assertEqual(expected_error, translated_error)
+
+    def test_PermissionDenied_one_arg(self):
+        path = 'a path'
+        translated_error = self.translateTuple(('PermissionDenied', path))
+        expected_error = errors.PermissionDenied(path)
+        self.assertEqual(expected_error, translated_error)
+
+    def test_PermissionDenied_one_arg_and_context(self):
+        """Given a choice between a path from the local context and a path on
+        the wire, _translate_error prefers the path from the local context.
+        """
+        local_path = 'local path'
+        remote_path = 'remote path'
+        translated_error = self.translateTuple(
+            ('PermissionDenied', remote_path), path=local_path)
+        expected_error = errors.PermissionDenied(local_path)
+        self.assertEqual(expected_error, translated_error)
+
+    def test_PermissionDenied_two_args(self):
+        path = 'a path'
+        extra = 'a string with extra info'
+        translated_error = self.translateTuple(
+            ('PermissionDenied', path, extra))
+        expected_error = errors.PermissionDenied(path, extra)
+        self.assertEqual(expected_error, translated_error)
+
+
 
 class TestErrorTranslationRobustness(TestErrorTranslationBase):
     """Unit tests for bzrlib.remote._translate_error's robustness.
@@ -1589,6 +1633,20 @@
             self._get_log(keep_log_file=True),
             "Missing key 'branch' in context")
         
+    def test_path_missing(self):
+        """Some translations (PermissionDenied, ReadError) can determine the
+        'path' variable from either the wire or the local context.  If neither
+        has it, then an error is raised.
+        """
+        error_tuple = ('ReadError',)
+        server_error = errors.ErrorFromSmartServer(error_tuple)
+        translated_error = self.translateErrorFromSmartServer(server_error)
+        self.assertEqual(server_error, translated_error)
+        # In addition to re-raising ErrorFromSmartServer, some debug info has
+        # been muttered to the log file for developer to look at.
+        self.assertContainsRe(
+            self._get_log(keep_log_file=True), "Missing key 'path' in context")
+
 
 class TestStacking(tests.TestCaseWithTransport):
     """Tests for operations on stacked remote repositories.

=== modified file 'bzrlib/tests/test_smart_transport.py'
--- a/bzrlib/tests/test_smart_transport.py	2008-08-29 19:32:00 +0000
+++ b/bzrlib/tests/test_smart_transport.py	2008-10-17 06:01:10 +0000
@@ -992,12 +992,9 @@
         smart_server.start_background_thread('-' + self.id())
         try:
             transport = remote.RemoteTCPTransport(smart_server.get_url())
-            try:
-                transport.get('something')
-            except errors.TransportError, e:
-                self.assertContainsRe(str(e), 'some random exception')
-            else:
-                self.fail("get did not raise expected error")
+            err = self.assertRaises(errors.UnknownErrorFromSmartServer,
+                transport.get, 'something')
+            self.assertContainsRe(str(err), 'some random exception')
             transport.disconnect()
         finally:
             smart_server.stop_background_thread()
@@ -1091,12 +1088,9 @@
         # asked for by the client. This gives meaningful and unsurprising errors
         # for users.
         self._captureVar('BZR_NO_SMART_VFS', None)
-        try:
-            self.transport.get('not%20a%20file')
-        except errors.NoSuchFile, e:
-            self.assertEqual('not%20a%20file', e.path)
-        else:
-            self.fail("get did not raise expected error")
+        err = self.assertRaises(
+            errors.NoSuchFile, self.transport.get, 'not%20a%20file')
+        self.assertEqual('not%20a%20file', err.path)
 
     def test_simple_clone_conn(self):
         """Test that cloning reuses the same connection."""
@@ -1400,8 +1394,9 @@
         client_medium = medium.SmartSimplePipesClientMedium(None, None, 'base')
         transport = remote.RemoteTransport(
             'bzr://localhost/', medium=client_medium)
+        err = errors.ErrorFromSmartServer(("ReadOnlyError", ))
         self.assertRaises(errors.TransportNotPossible,
-            transport._translate_error, ("ReadOnlyError", ))
+            transport._translate_error, err)
 
 
 class TestSmartProtocol(tests.TestCase):

=== modified file 'bzrlib/transport/remote.py'
--- a/bzrlib/transport/remote.py	2008-10-15 18:45:28 +0000
+++ b/bzrlib/transport/remote.py	2008-10-17 06:01:10 +0000
@@ -28,6 +28,7 @@
     config,
     debug,
     errors,
+    remote,
     trace,
     transport,
     urlutils,
@@ -143,8 +144,7 @@
         elif resp == ('no', ):
             return False
         else:
-            self._translate_error(resp)
-        raise errors.UnexpectedSmartServerResponse(resp)
+            raise errors.UnexpectedSmartServerResponse(resp)
 
     def get_smart_client(self):
         return self._get_connection()
@@ -161,25 +161,22 @@
         return self._combine_paths(self._path, relpath)
 
     def _call(self, method, *args):
-        try:
-            resp = self._call2(method, *args)
-        except errors.ErrorFromSmartServer, err:
-            self._translate_error(err.error_tuple)
-        self._translate_error(resp)
+        resp = self._call2(method, *args)
+        self._ensure_ok(resp)
 
     def _call2(self, method, *args):
         """Call a method on the remote server."""
         try:
             return self._client.call(method, *args)
         except errors.ErrorFromSmartServer, err:
-            self._translate_error(err.error_tuple)
+            self._translate_error(err)
 
     def _call_with_body_bytes(self, method, args, body):
         """Call a method on the remote server with body bytes."""
         try:
             return self._client.call_with_body_bytes(method, args, body)
         except errors.ErrorFromSmartServer, err:
-            self._translate_error(err.error_tuple)
+            self._translate_error(err)
 
     def has(self, relpath):
         """Indicate whether a remote file of the given name exists or not.
@@ -192,7 +189,7 @@
         elif resp == ('no', ):
             return False
         else:
-            self._translate_error(resp)
+            raise errors.UnexpectedSmartServerResponse(resp)
 
     def get(self, relpath):
         """Return file-like object reading the contents of a remote file.
@@ -206,7 +203,7 @@
         try:
             resp, response_handler = self._client.call_expecting_body('get', remote)
         except errors.ErrorFromSmartServer, err:
-            self._translate_error(err.error_tuple, relpath)
+            self._translate_error(err, relpath)
         if resp != ('ok', ):
             response_handler.cancel_read_body()
             raise errors.UnexpectedSmartServerResponse(resp)
@@ -221,7 +218,6 @@
     def mkdir(self, relpath, mode=None):
         resp = self._call2('mkdir', self._remote_path(relpath),
             self._serialise_optional_mode(mode))
-        self._translate_error(resp)
 
     def open_write_stream(self, relpath, mode=None):
         """See Transport.open_write_stream."""
@@ -243,7 +239,7 @@
         resp = self._call_with_body_bytes('put',
             (self._remote_path(relpath), self._serialise_optional_mode(mode)),
             upload_contents)
-        self._translate_error(resp)
+        self._ensure_ok(resp)
         return len(upload_contents)
 
     def put_bytes_non_atomic(self, relpath, bytes, mode=None,
@@ -260,7 +256,7 @@
             (self._remote_path(relpath), self._serialise_optional_mode(mode),
              create_parent_str, self._serialise_optional_mode(dir_mode)),
             bytes)
-        self._translate_error(resp)
+        self._ensure_ok(resp)
 
     def put_file(self, relpath, upload_file, mode=None):
         # its not ideal to seek back, but currently put_non_atomic_file depends
@@ -290,11 +286,11 @@
             bytes)
         if resp[0] == 'appended':
             return int(resp[1])
-        self._translate_error(resp)
+        raise errors.UnexpectedSmartServerResponse(resp)
 
     def delete(self, relpath):
         resp = self._call2('delete', self._remote_path(relpath))
-        self._translate_error(resp)
+        self._ensure_ok(resp)
 
     def external_url(self):
         """See bzrlib.transport.Transport.external_url."""
@@ -322,7 +318,7 @@
                 [(c.start, c.length) for c in coalesced])
             resp, response_handler = result
         except errors.ErrorFromSmartServer, err:
-            self._translate_error(err.error_tuple)
+            self._translate_error(err)
 
         if resp[0] != 'readv':
             # This should raise an exception
@@ -381,59 +377,12 @@
     def rmdir(self, relpath):
         resp = self._call('rmdir', self._remote_path(relpath))
 
-    def _translate_error(self, resp, orig_path=None):
-        """Raise an exception from a response"""
-        if resp is None:
-            what = None
-        else:
-            what = resp[0]
-        if what == 'ok':
-            return
-        elif what == 'NoSuchFile':
-            if orig_path is not None:
-                error_path = orig_path
-            else:
-                error_path = resp[1]
-            raise errors.NoSuchFile(error_path)
-        elif what == 'error':
-            raise errors.SmartProtocolError(unicode(resp[1]))
-        elif what == 'FileExists':
-            raise errors.FileExists(resp[1])
-        elif what == 'DirectoryNotEmpty':
-            raise errors.DirectoryNotEmpty(resp[1])
-        elif what == 'ShortReadvError':
-            raise errors.ShortReadvError(resp[1], int(resp[2]),
-                                         int(resp[3]), int(resp[4]))
-        elif what in ('UnicodeEncodeError', 'UnicodeDecodeError'):
-            encoding = str(resp[1]) # encoding must always be a string
-            val = resp[2]
-            start = int(resp[3])
-            end = int(resp[4])
-            reason = str(resp[5]) # reason must always be a string
-            if val.startswith('u:'):
-                val = val[2:].decode('utf-8')
-            elif val.startswith('s:'):
-                val = val[2:].decode('base64')
-            if what == 'UnicodeDecodeError':
-                raise UnicodeDecodeError(encoding, val, start, end, reason)
-            elif what == 'UnicodeEncodeError':
-                raise UnicodeEncodeError(encoding, val, start, end, reason)
-        elif what == "ReadOnlyError":
-            raise errors.TransportNotPossible('readonly transport')
-        elif what == "ReadError":
-            if orig_path is not None:
-                error_path = orig_path
-            else:
-                error_path = resp[1]
-            raise errors.ReadError(error_path)
-        elif what == "PermissionDenied":
-            if orig_path is not None:
-                error_path = orig_path
-            else:
-                error_path = resp[1]
-            raise errors.PermissionDenied(error_path)
-        else:
-            raise errors.SmartProtocolError('unexpected smart server error: %r' % (resp,))
+    def _ensure_ok(self, resp):
+        if resp[0] != 'ok':
+            raise errors.UnexpectedSmartServerResponse(resp)
+        
+    def _translate_error(self, err, orig_path=None):
+        remote._translate_error(err, path=orig_path)
 
     def disconnect(self):
         self.get_smart_medium().disconnect()
@@ -442,8 +391,7 @@
         resp = self._call2('stat', self._remote_path(relpath))
         if resp[0] == 'stat':
             return _SmartStat(int(resp[1]), int(resp[2], 8))
-        else:
-            self._translate_error(resp)
+        raise errors.UnexpectedSmartServerResponse(resp)
 
     ## def lock_read(self, relpath):
     ##     """Lock the given file for shared (read) access.
@@ -465,15 +413,13 @@
         resp = self._call2('list_dir', self._remote_path(relpath))
         if resp[0] == 'names':
             return [name.encode('ascii') for name in resp[1:]]
-        else:
-            self._translate_error(resp)
+        raise errors.UnexpectedSmartServerResponse(resp)
 
     def iter_files_recursive(self):
         resp = self._call2('iter_files_recursive', self._remote_path(''))
         if resp[0] == 'names':
             return resp[1:]
-        else:
-            self._translate_error(resp)
+        raise errors.UnexpectedSmartServerResponse(resp)
 
 
 class RemoteTCPTransport(RemoteTransport):




More information about the bazaar-commits mailing list