Rev 3940: (mbp) transport-based progress bars in file:///home/pqm/archives/thelove/bzr/%2Btrunk/

Canonical.com Patch Queue Manager pqm at pqm.ubuntu.com
Thu Jan 15 07:34:23 GMT 2009


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

------------------------------------------------------------
revno: 3940
revision-id: pqm at pqm.ubuntu.com-20090115073416-vnzvkab4dfesetj0
parent: pqm at pqm.ubuntu.com-20090115062848-vl9tlzwnawaqht01
parent: mbp at sourcefrog.net-20090115064409-ual02s892v27bq5o
committer: Canonical.com Patch Queue Manager <pqm at pqm.ubuntu.com>
branch nick: +trunk
timestamp: Thu 2009-01-15 07:34:16 +0000
message:
  (mbp) transport-based progress bars
modified:
  NEWS                           NEWS-20050323055033-4e00b5db738777ff
  bzrlib/commands.py             bzr.py-20050309040720-d10f4714595cf8c3
  bzrlib/errors.py               errors.py-20050309040759-20512168c4e14fbd
  bzrlib/progress.py             progress.py-20050610070202-df9faaab791964c0
  bzrlib/tests/blackbox/test_upgrade.py test_upgrade.py-20060120060132-b41e5ed2f886ad28
  bzrlib/tests/test_sftp_transport.py testsftp.py-20051027032739-247570325fec7e7e
  bzrlib/tests/test_ui.py        test_ui.py-20051130162854-458e667a7414af09
  bzrlib/transport/__init__.py   transport.py-20050711165921-4978aa7ce1285ad5
  bzrlib/transport/sftp.py       sftp.py-20051019050329-ab48ce71b7e32dfe
  bzrlib/ui/__init__.py          ui.py-20050824083933-8cf663c763ba53a9
  bzrlib/ui/text.py              text.py-20051130153916-2e438cffc8afc478
    ------------------------------------------------------------
    revno: 3882.7.17
    revision-id: mbp at sourcefrog.net-20090115064409-ual02s892v27bq5o
    parent: mbp at sourcefrog.net-20090115051249-dwwq2byltadxi6s8
    committer: Martin Pool <mbp at sourcefrog.net>
    branch nick: progress
    timestamp: Thu 2009-01-15 17:44:09 +1100
    message:
      test_ui should not expect warnings from ProgressBar.finished
    modified:
      bzrlib/tests/test_ui.py        test_ui.py-20051130162854-458e667a7414af09
    ------------------------------------------------------------
    revno: 3882.7.16
    revision-id: mbp at sourcefrog.net-20090115051249-dwwq2byltadxi6s8
    parent: mbp at sourcefrog.net-20090115032155-vaxa3k8pdeh15r4z
    committer: Martin Pool <mbp at sourcefrog.net>
    branch nick: progress
    timestamp: Thu 2009-01-15 16:12:49 +1100
    message:
      Update SFTP tests to accommodate progress reporting
    modified:
      bzrlib/tests/test_sftp_transport.py testsftp.py-20051027032739-247570325fec7e7e
      bzrlib/transport/sftp.py       sftp.py-20051019050329-ab48ce71b7e32dfe
    ------------------------------------------------------------
    revno: 3882.7.15
    revision-id: mbp at sourcefrog.net-20090115032155-vaxa3k8pdeh15r4z
    parent: mbp at sourcefrog.net-20090113051626-0d5q6luqdoyx4xaf
    committer: Martin Pool <mbp at sourcefrog.net>
    branch nick: progress
    timestamp: Thu 2009-01-15 14:21:55 +1100
    message:
      Remove Robey's copyright as he assigned to Canonical
    modified:
      bzrlib/transport/sftp.py       sftp.py-20051019050329-ab48ce71b7e32dfe
    ------------------------------------------------------------
    revno: 3882.7.14
    revision-id: mbp at sourcefrog.net-20090113051626-0d5q6luqdoyx4xaf
    parent: mbp at sourcefrog.net-20090113050727-r0uw27cvei8tyvh8
    parent: pqm at pqm.ubuntu.com-20090112185737-d6kwagahecadwfce
    committer: Martin Pool <mbp at sourcefrog.net>
    branch nick: progress
    timestamp: Tue 2009-01-13 16:16:26 +1100
    message:
      Fix recommend_upgrade ui and merge trunk
    added:
      bzrlib/plugins/netrc_credential_store/ netrc_credential_sto-20081006090354-oaoid1olhgk8vevm-1
      bzrlib/plugins/netrc_credential_store/__init__.py __init__.py-20081006090402-hd75m8kcrrm0vlz1-1
      bzrlib/plugins/netrc_credential_store/tests/ tests-20081006090406-6mddz8j10pux993e-1
      bzrlib/plugins/netrc_credential_store/tests/__init__.py __init__.py-20081006090411-vytweyz6sun61d4q-1
      bzrlib/plugins/netrc_credential_store/tests/test_netrc.py test_netrc.py-20081006090414-vm3or4tz6c9wk2oi-1
      bzrlib/tests/https_server.py   https_server.py-20071121173708-aj8zczi0ziwbwz21-1
      bzrlib/tests/ssl_certs/        ssl_certs-20071124141654-dc9za9nho2gmzbri-1
      bzrlib/tests/ssl_certs/__init__.py __init__.py-20071124141703-j5hr254lm287lyut-8
      bzrlib/tests/ssl_certs/ca.crt  ca.crt-20071124141703-j5hr254lm287lyut-7
      bzrlib/tests/ssl_certs/ca.key  ca.key-20071124141703-j5hr254lm287lyut-6
      bzrlib/tests/ssl_certs/create_ssls.py create_ssls.py-20071124141703-j5hr254lm287lyut-5
      bzrlib/tests/ssl_certs/server.crt server.crt-20071124141703-j5hr254lm287lyut-4
      bzrlib/tests/ssl_certs/server.csr server.csr-20071124141703-j5hr254lm287lyut-3
      bzrlib/tests/ssl_certs/server_with_pass.key server_with_pass.key-20071124141703-j5hr254lm287lyut-2
      bzrlib/tests/ssl_certs/server_without_pass.key server_without_pass.-20071124141703-j5hr254lm287lyut-1
    modified:
      NEWS                           NEWS-20050323055033-4e00b5db738777ff
      bzrlib/branch.py               branch.py-20050309040759-e4baf4e0d046576e
      bzrlib/builtins.py             builtins.py-20050830033751-fc01482b9ca23183
      bzrlib/bzrdir.py               bzrdir.py-20060131065624-156dfea39c4387cb
      bzrlib/config.py               config.py-20051011043216-070c74f4e9e338e8
      bzrlib/diff.py                 diff.py-20050309040759-26944fbbf2ebbf36
      bzrlib/dirstate.py             dirstate.py-20060728012006-d6mvoihjb3je9peu-1
      bzrlib/errors.py               errors.py-20050309040759-20512168c4e14fbd
      bzrlib/help_topics/en/configuration.txt configuration.txt-20060314161707-868350809502af01
      bzrlib/knit.py                 knit.py-20051212171256-f056ac8f0fbe1bd9
      bzrlib/log.py                  log.py-20050505065812-c40ce11702fe5fb1
      bzrlib/mail_client.py          mail_client.py-20070809192806-vuxt3t19srtpjpdn-1
      bzrlib/osutils.py              osutils.py-20050309040759-eeaff12fbf77ac86
      bzrlib/patiencediff.py         patiencediff.py-20070721205536-jz8gaykeb7xtampk-1
      bzrlib/push.py                 push.py-20080606021927-5fe39050e8xne9un-1
      bzrlib/smart/medium.py         medium.py-20061103051856-rgu2huy59fkz902q-1
      bzrlib/tests/__init__.py       selftest.py-20050531073622-8d0e3c8845c97a64
      bzrlib/tests/blackbox/test_push.py test_push.py-20060329002750-929af230d5d22663
      bzrlib/tests/branch_implementations/test_branch.py testbranch.py-20050711070244-121d632bc37d7253
      bzrlib/tests/branch_implementations/test_stacking.py test_stacking.py-20080214020755-msjlkb7urobwly0f-1
      bzrlib/tests/commands/test_push.py test_push.py-20070525122003-gc1ob0ea0nueoqgj-1
      bzrlib/tests/http_server.py    httpserver.py-20061012142527-m1yxdj1xazsf8d7s-1
      bzrlib/tests/test_bzrdir.py    test_bzrdir.py-20060131065654-deba40eef51cf220
      bzrlib/tests/test_config.py    testconfig.py-20051011041908-742d0c15d8d8c8eb
      bzrlib/tests/test_diff.py      testdiff.py-20050727164403-d1a3496ebb12e339
      bzrlib/tests/test_errors.py    test_errors.py-20060210110251-41aba2deddf936a8
      bzrlib/tests/test_http.py      testhttp.py-20051018020158-b2eef6e867c514d9
      bzrlib/tests/test_log.py       testlog.py-20050728115707-1a514809d7d49309
      bzrlib/tests/test_mail_client.py test_mail_client.py-20070809192806-vuxt3t19srtpjpdn-2
      bzrlib/tests/test_osutils.py   test_osutils.py-20051201224856-e48ee24c12182989
      bzrlib/tests/test_plugins.py   plugins.py-20050622075746-32002b55e5e943e9
      bzrlib/tests/workingtree_implementations/test_move.py test_move.py-20070225171927-mohn2vqj5fx7edc6-1
      bzrlib/trace.py                trace.py-20050309040759-c8ed824bdcd4748a
      bzrlib/transport/ftp/__init__.py ftp.py-20051116161804-58dc9506548c2a53
      bzrlib/transport/http/_pycurl.py pycurlhttp.py-20060110060940-4e2a705911af77a6
      bzrlib/transport/http/_urllib.py _urlgrabber.py-20060113083826-0bbf7d992fbf090c
      bzrlib/transport/http/_urllib2_wrappers.py _urllib2_wrappers.py-20060913231729-ha9ugi48ktx481ao-1
      bzrlib/transport/http/ca_bundle.py ca_bundle.py-20070226091335-84kb1xg1r2jjf858-1
      doc/developers/authentication-ring.txt authring.txt-20070718200437-q5tdik0ne6lor86d-1
      tools/win32/build_release.py   build_release.py-20081105204355-2ghh5cv01v1x4rzz-1
    ------------------------------------------------------------
    revno: 3882.7.13
    revision-id: mbp at sourcefrog.net-20090113050727-r0uw27cvei8tyvh8
    parent: mbp at sourcefrog.net-20081224073737-1pm721uhv3077qd0
    committer: Martin Pool <mbp at sourcefrog.net>
    branch nick: progress
    timestamp: Tue 2009-01-13 16:07:27 +1100
    message:
      Don't mask out recommend_upgrade in CLIUIFactory
    modified:
      bzrlib/tests/blackbox/test_upgrade.py test_upgrade.py-20060120060132-b41e5ed2f886ad28
      bzrlib/ui/__init__.py          ui.py-20050824083933-8cf663c763ba53a9
    ------------------------------------------------------------
    revno: 3882.7.12
    revision-id: mbp at sourcefrog.net-20081224073737-1pm721uhv3077qd0
    parent: mbp at sourcefrog.net-20081224070720-ptodndbmje6uy5ej
    parent: pqm at pqm.ubuntu.com-20081224050842-15xix09apawzgs05
    committer: Martin Pool <mbp at sourcefrog.net>
    branch nick: progress
    timestamp: Wed 2008-12-24 18:37:37 +1100
    message:
      merge news
    added:
      bzrlib/_chunks_to_lines_py.py  _chunks_to_lines_py.-20081211024848-6uc3mtuje8j14l60-1
      bzrlib/_chunks_to_lines_pyx.pyx _chunks_to_lines_pyx-20081211021736-op7n8vrxgrd8snfi-1
      bzrlib/fifo_cache.py           fifo_cache.py-20081209212307-31ffjwvteyvmydnf-1
      bzrlib/tests/blackbox/test_shelve.py test_ls_shelf.py-20081202053526-thlo8yt0pi1cgor1-1
      bzrlib/tests/per_repository/test_add_inventory_by_delta.py test_add_inventory_d-20081013002626-rut81igtlqb4590z-1
      bzrlib/tests/test__chunks_to_lines.py test__chunks_to_line-20081211024848-6uc3mtuje8j14l60-2
      bzrlib/tests/test_fifo_cache.py test_fifo_cache.py-20081209212307-31ffjwvteyvmydnf-2
    modified:
      .bzrignore                     bzrignore-20050311232317-81f7b71efa2db11a
      Makefile                       Makefile-20050805140406-d96e3498bb61c5bb
      NEWS                           NEWS-20050323055033-4e00b5db738777ff
      bzrlib/__init__.py             __init__.py-20050309040759-33e65acf91bbcd5d
      bzrlib/_dirstate_helpers_c.h   _dirstate_helpers_c.-20070802205935-hqo9yzuzjix271dd-1
      bzrlib/atomicfile.py           atomicfile.py-20050509044450-dbd24e6c564f7c66
      bzrlib/branch.py               branch.py-20050309040759-e4baf4e0d046576e
      bzrlib/builtins.py             builtins.py-20050830033751-fc01482b9ca23183
      bzrlib/bzrdir.py               bzrdir.py-20060131065624-156dfea39c4387cb
      bzrlib/commit.py               commit.py-20050511101309-79ec1a0168e0e825
      bzrlib/delta.py                delta.py-20050729221636-54cf14ef94783d0a
      bzrlib/errors.py               errors.py-20050309040759-20512168c4e14fbd
      bzrlib/foreign.py              foreign.py-20081112170002-olsxmandkk8qyfuq-1
      bzrlib/graph.py                graph_walker.py-20070525030359-y852guab65d4wtn0-1
      bzrlib/help_topics/__init__.py help_topics.py-20060920210027-rnim90q9e0bwxvy4-1
      bzrlib/inventory.py            inventory.py-20050309040759-6648b84ca2005b37
      bzrlib/knit.py                 knit.py-20051212171256-f056ac8f0fbe1bd9
      bzrlib/log.py                  log.py-20050505065812-c40ce11702fe5fb1
      bzrlib/lru_cache.py            lru_cache.py-20070119165515-tlw203kuwh0id5gv-1
      bzrlib/merge.py                merge.py-20050513021216-953b65a438527106
      bzrlib/msgeditor.py            msgeditor.py-20050901111708-ef6d8de98f5d8f2f
      bzrlib/osutils.py              osutils.py-20050309040759-eeaff12fbf77ac86
      bzrlib/push.py                 push.py-20080606021927-5fe39050e8xne9un-1
      bzrlib/registry.py             lazy_factory.py-20060809213415-2gfvqadtvdn0phtg-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/shelf.py                prepare_shelf.py-20081005181341-n74qe6gu1e65ad4v-1
      bzrlib/shelf_ui.py             shelver.py-20081005210102-33worgzwrtdw0yrm-1
      bzrlib/tests/__init__.py       selftest.py-20050531073622-8d0e3c8845c97a64
      bzrlib/tests/blackbox/__init__.py __init__.py-20051128053524-eba30d8255e08dc3
      bzrlib/tests/blackbox/test_log.py test_log.py-20060112090212-78f6ea560c868e24
      bzrlib/tests/blackbox/test_ls.py test_ls.py-20060712232047-0jraqpecwngee12y-1
      bzrlib/tests/blackbox/test_pull.py test_pull.py-20051201144907-64959364f629947f
      bzrlib/tests/blackbox/test_push.py test_push.py-20060329002750-929af230d5d22663
      bzrlib/tests/blackbox/test_revision_info.py test_revision_info.py-20050917162600-21dab3877aa348d7
      bzrlib/tests/blackbox/test_tags.py test_tags.py-20070116132048-5h4qak2cm22jlb9e-1
      bzrlib/tests/branch_implementations/__init__.py __init__.py-20060123013057-b12a52c3f361daf4
      bzrlib/tests/branch_implementations/test_push.py test_push.py-20070130153159-fhfap8uoifevg30j-1
      bzrlib/tests/interrepository_implementations/__init__.py __init__.py-20060220054744-baf49a1f88f17b1a
      bzrlib/tests/per_repository/__init__.py __init__.py-20060131092037-9564957a7d4a841b
      bzrlib/tests/per_repository/test_add_fallback_repository.py test_add_fallback_re-20080215040003-8w9n4ck9uqdxj18m-1
      bzrlib/tests/per_repository/test_commit_builder.py test_commit_builder.py-20060606110838-76e3ra5slucqus81-1
      bzrlib/tests/per_repository/test_repository.py test_repository.py-20060131092128-ad07f494f5c9d26c
      bzrlib/tests/test_bzrdir.py    test_bzrdir.py-20060131065654-deba40eef51cf220
      bzrlib/tests/test_graph.py     test_graph_walker.py-20070525030405-enq4r60hhi9xrujc-1
      bzrlib/tests/test_http.py      testhttp.py-20051018020158-b2eef6e867c514d9
      bzrlib/tests/test_info.py      test_info.py-20070320150933-m0xxm1g7xi9v6noe-1
      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_msgeditor.py test_msgeditor.py-20051202041359-920315ec6011ee51
      bzrlib/tests/test_osutils.py   test_osutils.py-20051201224856-e48ee24c12182989
      bzrlib/tests/test_remote.py    test_remote.py-20060720103555-yeeg2x51vn0rbtdp-2
      bzrlib/tests/test_repository.py test_repository.py-20060131075918-65c555b881612f4d
      bzrlib/tests/test_revisionspec.py testrevisionnamespaces.py-20050711050225-8b4af89e6b1efe84
      bzrlib/tests/test_selftest.py  test_selftest.py-20051202044319-c110a115d8c0456a
      bzrlib/tests/test_shelf.py     test_prepare_shelf.p-20081005181341-n74qe6gu1e65ad4v-2
      bzrlib/tests/test_smart_transport.py test_ssh_transport.py-20060608202016-c25gvf1ob7ypbus6-2
      bzrlib/tests/test_source.py    test_source.py-20051207061333-a58dea6abecc030d
      bzrlib/tests/test_versionedfile.py test_versionedfile.py-20060222045249-db45c9ed14a1c2e5
      bzrlib/tests/tree_implementations/__init__.py __init__.py-20060717075546-420s7b0bj9hzeowi-2
      bzrlib/tests/workingtree_implementations/test_add.py test_add.py-20070226165239-4vo178spkrnhavc7-1
      bzrlib/tests/workingtree_implementations/test_basis_inventory.py test_basis_inventory.py-20051218151655-3650468941091309
      bzrlib/tests/workingtree_implementations/test_move.py test_move.py-20070225171927-mohn2vqj5fx7edc6-1
      bzrlib/tests/workingtree_implementations/test_rename_one.py test_rename_one.py-20070226161242-2d8ibdedl700jgio-1
      bzrlib/transform.py            transform.py-20060105172343-dd99e54394d91687
      bzrlib/transport/__init__.py   transport.py-20050711165921-4978aa7ce1285ad5
      bzrlib/transport/decorator.py  decorator.py-20060402223305-e913a0f25319ab42
      bzrlib/transport/http/__init__.py http_transport.py-20050711212304-506c5fd1059ace96
      bzrlib/transport/http/_pycurl.py pycurlhttp.py-20060110060940-4e2a705911af77a6
      bzrlib/transport/http/_urllib.py _urlgrabber.py-20060113083826-0bbf7d992fbf090c
      bzrlib/transport/remote.py     ssh.py-20060608202016-c25gvf1ob7ypbus6-1
      bzrlib/tree.py                 tree.py-20050309040759-9d5f2496be663e77
      bzrlib/versionedfile.py        versionedfile.py-20060222045106-5039c71ee3b65490
      bzrlib/weave.py                knit.py-20050627021749-759c29984154256b
      bzrlib/workingtree.py          workingtree.py-20050511021032-29b6ec0a681e02e3
      bzrlib/workingtree_4.py        workingtree_4.py-20070208044105-5fgpc5j3ljlh5q6c-1
      bzrlib/xml4.py                 xml4.py-20050916091259-db5ab55e7e6ca324
      bzrlib/xml5.py                 xml5.py-20080328030717-t9guwinq8hom0ar3-1
      bzrlib/xml7.py                 xml7.py-20061029182747-d5tiiny21bvrd2jj-1
      bzrlib/xml8.py                 xml5.py-20050907032657-aac8f960815b66b1
      bzrlib/xml_serializer.py       xml.py-20050309040759-57d51586fdec365d
      doc/developers/HACKING.txt     HACKING-20050805200004-2a5dc975d870f78c
      doc/en/user-guide/organizing_branches.txt organizing_branches.-20071123154453-dk2mjhrg1vpjm5w2-3
      doc/en/user-guide/publishing_a_branch.txt publishing_a_branch.-20071123055134-k5x4ekduci2lbn36-2
      doc/en/user-guide/reusing_a_checkout.txt reusing_a_checkout.t-20071123055134-k5x4ekduci2lbn36-3
      doc/en/user-guide/svn_plugin.txt svn_plugin.txt-20080509065016-cjc90f46407vi9a0-2
      doc/en/user-guide/using_checkouts.txt using_checkouts.txt-20071123055134-k5x4ekduci2lbn36-4
      setup.py                       setup.py-20050314065409-02f8a0a6e3f9bc70
      tools/win32/build_release.py   build_release.py-20081105204355-2ghh5cv01v1x4rzz-1
    ------------------------------------------------------------
    revno: 3882.7.11
    revision-id: mbp at sourcefrog.net-20081224070720-ptodndbmje6uy5ej
    parent: mbp at sourcefrog.net-20081224070433-6trk2e9btcx45o6s
    parent: mbp at sourcefrog.net-20081217082831-gfro2xbtou9w1bnd
    committer: Martin Pool <mbp at sourcefrog.net>
    branch nick: progress
    timestamp: Wed 2008-12-24 18:07:20 +1100
    message:
      Merge other progress work
    modified:
      NEWS                           NEWS-20050323055033-4e00b5db738777ff
      bzrlib/commands.py             bzr.py-20050309040720-d10f4714595cf8c3
      bzrlib/errors.py               errors.py-20050309040759-20512168c4e14fbd
      bzrlib/progress.py             progress.py-20050610070202-df9faaab791964c0
      bzrlib/tests/test_ui.py        test_ui.py-20051130162854-458e667a7414af09
      bzrlib/ui/__init__.py          ui.py-20050824083933-8cf663c763ba53a9
      bzrlib/ui/text.py              text.py-20051130153916-2e438cffc8afc478
        ------------------------------------------------------------
        revno: 3882.8.14
        revision-id: mbp at sourcefrog.net-20081217082831-gfro2xbtou9w1bnd
        parent: mbp at sourcefrog.net-20081217082742-8ezdb3qvhx7rcpuq
        committer: Martin Pool <mbp at sourcefrog.net>
        branch nick: progress
        timestamp: Wed 2008-12-17 19:28:31 +1100
        message:
          note progress apis have changed
        modified:
          NEWS                           NEWS-20050323055033-4e00b5db738777ff
        ------------------------------------------------------------
        revno: 3882.8.13
        revision-id: mbp at sourcefrog.net-20081217082742-8ezdb3qvhx7rcpuq
        parent: mbp at sourcefrog.net-20081217081814-qxpip6fd8f3ofkgh
        committer: Martin Pool <mbp at sourcefrog.net>
        branch nick: progress
        timestamp: Wed 2008-12-17 19:27:42 +1100
        message:
          update news
        modified:
          NEWS                           NEWS-20050323055033-4e00b5db738777ff
        ------------------------------------------------------------
        revno: 3882.8.12
        revision-id: mbp at sourcefrog.net-20081217081814-qxpip6fd8f3ofkgh
        parent: mbp at sourcefrog.net-20081216075629-zhgjzxgoh32453tu
        committer: Martin Pool <mbp at sourcefrog.net>
        branch nick: progress
        timestamp: Wed 2008-12-17 19:18:14 +1100
        message:
          Give a warning, not an error, if a progress bar is not finished in order
        modified:
          bzrlib/progress.py             progress.py-20050610070202-df9faaab791964c0
          bzrlib/tests/test_ui.py        test_ui.py-20051130162854-458e667a7414af09
          bzrlib/ui/__init__.py          ui.py-20050824083933-8cf663c763ba53a9
        ------------------------------------------------------------
        revno: 3882.8.11
        revision-id: mbp at sourcefrog.net-20081216075629-zhgjzxgoh32453tu
        parent: mbp at sourcefrog.net-20081216071030-dbxgukznexs9zqn8
        committer: Martin Pool <mbp at sourcefrog.net>
        branch nick: progress
        timestamp: Tue 2008-12-16 18:56:29 +1100
        message:
          Choose the UIFactory class depending on the terminal capabilities
        modified:
          bzrlib/commands.py             bzr.py-20050309040720-d10f4714595cf8c3
          bzrlib/tests/test_ui.py        test_ui.py-20051130162854-458e667a7414af09
          bzrlib/ui/__init__.py          ui.py-20050824083933-8cf663c763ba53a9
          bzrlib/ui/text.py              text.py-20051130153916-2e438cffc8afc478
        ------------------------------------------------------------
        revno: 3882.8.10
        revision-id: mbp at sourcefrog.net-20081216071030-dbxgukznexs9zqn8
        parent: mbp at sourcefrog.net-20081216070053-443injzwkblc0rij
        committer: Martin Pool <mbp at sourcefrog.net>
        branch nick: progress
        timestamp: Tue 2008-12-16 18:10:30 +1100
        message:
          Fix up test_ui for new progress bars
        modified:
          bzrlib/tests/test_ui.py        test_ui.py-20051130162854-458e667a7414af09
        ------------------------------------------------------------
        revno: 3882.8.9
        revision-id: mbp at sourcefrog.net-20081216070053-443injzwkblc0rij
        parent: mbp at sourcefrog.net-20081216065958-b4ce9x9w34xwan5a
        committer: Martin Pool <mbp at sourcefrog.net>
        branch nick: progress
        timestamp: Tue 2008-12-16 18:00:53 +1100
        message:
          Move TextProgressView to ui.text
        modified:
          bzrlib/progress.py             progress.py-20050610070202-df9faaab791964c0
          bzrlib/ui/text.py              text.py-20051130153916-2e438cffc8afc478
        ------------------------------------------------------------
        revno: 3882.8.8
        revision-id: mbp at sourcefrog.net-20081216065958-b4ce9x9w34xwan5a
        parent: mbp at sourcefrog.net-20081216061801-7ty3ke724hruq0nw
        committer: Martin Pool <mbp at sourcefrog.net>
        branch nick: progress
        timestamp: Tue 2008-12-16 17:59:58 +1100
        message:
          Progress and UI test cleanups
        modified:
          bzrlib/progress.py             progress.py-20050610070202-df9faaab791964c0
          bzrlib/tests/test_ui.py        test_ui.py-20051130162854-458e667a7414af09
          bzrlib/ui/text.py              text.py-20051130153916-2e438cffc8afc478
        ------------------------------------------------------------
        revno: 3882.8.7
        revision-id: mbp at sourcefrog.net-20081216061801-7ty3ke724hruq0nw
        parent: mbp at sourcefrog.net-20081216061654-6hvc6dlf8srcpoxz
        committer: Martin Pool <mbp at sourcefrog.net>
        branch nick: progress
        timestamp: Tue 2008-12-16 17:18:01 +1100
        message:
          Remove MissingProgressBarFinish exception
        modified:
          bzrlib/errors.py               errors.py-20050309040759-20512168c4e14fbd
          bzrlib/progress.py             progress.py-20050610070202-df9faaab791964c0
          bzrlib/tests/test_ui.py        test_ui.py-20051130162854-458e667a7414af09
        ------------------------------------------------------------
        revno: 3882.8.6
        revision-id: mbp at sourcefrog.net-20081216061654-6hvc6dlf8srcpoxz
        parent: mbp at sourcefrog.net-20081216061014-8hsdpmhake0s9ak6
        committer: Martin Pool <mbp at sourcefrog.net>
        branch nick: progress
        timestamp: Tue 2008-12-16 17:16:54 +1100
        message:
          TextUIFactory ignores and deprecates the bar_type parameter
        modified:
          bzrlib/ui/text.py              text.py-20051130153916-2e438cffc8afc478
        ------------------------------------------------------------
        revno: 3882.8.5
        revision-id: mbp at sourcefrog.net-20081216061014-8hsdpmhake0s9ak6
        parent: mbp at sourcefrog.net-20081216055124-uxx9245lbuef07le
        committer: Martin Pool <mbp at sourcefrog.net>
        branch nick: progress
        timestamp: Tue 2008-12-16 17:10:14 +1100
        message:
          Progress tasks can indicate what kind of display is useful
        modified:
          bzrlib/progress.py             progress.py-20050610070202-df9faaab791964c0
          bzrlib/tests/test_ui.py        test_ui.py-20051130162854-458e667a7414af09
        ------------------------------------------------------------
        revno: 3882.8.4
        revision-id: mbp at sourcefrog.net-20081216055124-uxx9245lbuef07le
        parent: mbp at sourcefrog.net-20081216042643-lelt3haqjmedugq6
        committer: Martin Pool <mbp at sourcefrog.net>
        branch nick: progress
        timestamp: Tue 2008-12-16 16:51:24 +1100
        message:
          All UI factories should support note()
        modified:
          bzrlib/progress.py             progress.py-20050610070202-df9faaab791964c0
          bzrlib/tests/test_ui.py        test_ui.py-20051130162854-458e667a7414af09
          bzrlib/ui/__init__.py          ui.py-20050824083933-8cf663c763ba53a9
          bzrlib/ui/text.py              text.py-20051130153916-2e438cffc8afc478
        ------------------------------------------------------------
        revno: 3882.8.3
        revision-id: mbp at sourcefrog.net-20081216042643-lelt3haqjmedugq6
        parent: mbp at sourcefrog.net-20081216033052-crrxy0eo3njhtidl
        committer: Martin Pool <mbp at sourcefrog.net>
        branch nick: progress
        timestamp: Tue 2008-12-16 15:26:43 +1100
        message:
          Move display of transport throughput into TextProgressView
        modified:
          bzrlib/progress.py             progress.py-20050610070202-df9faaab791964c0
          bzrlib/ui/__init__.py          ui.py-20050824083933-8cf663c763ba53a9
          bzrlib/ui/text.py              text.py-20051130153916-2e438cffc8afc478
        ------------------------------------------------------------
        revno: 3882.8.2
        revision-id: mbp at sourcefrog.net-20081216033052-crrxy0eo3njhtidl
        parent: mbp at sourcefrog.net-20081216032241-6xuetbwb8xlifayh
        committer: Martin Pool <mbp at sourcefrog.net>
        branch nick: progress
        timestamp: Tue 2008-12-16 14:30:52 +1100
        message:
          ProgressTask holds a reference to the ui that displays it
        modified:
          bzrlib/progress.py             progress.py-20050610070202-df9faaab791964c0
          bzrlib/ui/__init__.py          ui.py-20050824083933-8cf663c763ba53a9
        ------------------------------------------------------------
        revno: 3882.8.1
        revision-id: mbp at sourcefrog.net-20081216032241-6xuetbwb8xlifayh
        parent: mbp at sourcefrog.net-20081215085130-rqxig49n8g9jh8qt
        committer: Martin Pool <mbp at sourcefrog.net>
        branch nick: progress
        timestamp: Tue 2008-12-16 14:22:41 +1100
        message:
          Remove experimental transport display from TTYProgressBar
        modified:
          bzrlib/progress.py             progress.py-20050610070202-df9faaab791964c0
    ------------------------------------------------------------
    revno: 3882.7.10
    revision-id: mbp at sourcefrog.net-20081224070433-6trk2e9btcx45o6s
    parent: mbp at sourcefrog.net-20081224070318-pq87j6nbk3aocy6y
    committer: Martin Pool <mbp at sourcefrog.net>
    branch nick: progress
    timestamp: Wed 2008-12-24 18:04:33 +1100
    message:
      CLIUIFactory implements (as stubs) progress methods
    modified:
      bzrlib/ui/__init__.py          ui.py-20050824083933-8cf663c763ba53a9
    ------------------------------------------------------------
    revno: 3882.7.9
    revision-id: mbp at sourcefrog.net-20081224070318-pq87j6nbk3aocy6y
    parent: mbp at sourcefrog.net-20081215085130-rqxig49n8g9jh8qt
    committer: Martin Pool <mbp at sourcefrog.net>
    branch nick: progress
    timestamp: Wed 2008-12-24 18:03:18 +1100
    message:
      Move the point at which sftp issues transport activity (thanks vila)
    modified:
      bzrlib/transport/sftp.py       sftp.py-20051019050329-ab48ce71b7e32dfe
    ------------------------------------------------------------
    revno: 3882.7.8
    revision-id: mbp at sourcefrog.net-20081215085130-rqxig49n8g9jh8qt
    parent: mbp at sourcefrog.net-20081215082857-asjzld70e2s1i0ta
    committer: Martin Pool <mbp at sourcefrog.net>
    branch nick: progress
    timestamp: Mon 2008-12-15 19:51:30 +1100
    message:
      Progress layout tweaks
    modified:
      bzrlib/progress.py             progress.py-20050610070202-df9faaab791964c0
      bzrlib/ui/text.py              text.py-20051130153916-2e438cffc8afc478
    ------------------------------------------------------------
    revno: 3882.7.7
    revision-id: mbp at sourcefrog.net-20081215082857-asjzld70e2s1i0ta
    parent: mbp at sourcefrog.net-20081215063120-s06lzbt1fye3lbim
    committer: Martin Pool <mbp at sourcefrog.net>
    branch nick: progress
    timestamp: Mon 2008-12-15 19:28:57 +1100
    message:
      Change progress bars to a more MVC style
    modified:
      bzrlib/progress.py             progress.py-20050610070202-df9faaab791964c0
      bzrlib/ui/__init__.py          ui.py-20050824083933-8cf663c763ba53a9
      bzrlib/ui/text.py              text.py-20051130153916-2e438cffc8afc478
    ------------------------------------------------------------
    revno: 3882.7.6
    revision-id: mbp at sourcefrog.net-20081215063120-s06lzbt1fye3lbim
    parent: mbp at sourcefrog.net-20081215010123-diylgwx90yz0gfs3
    committer: Martin Pool <mbp at sourcefrog.net>
    branch nick: progress
    timestamp: Mon 2008-12-15 17:31:20 +1100
    message:
      Preliminary support for drawing network io into the progress bar
    modified:
      bzrlib/progress.py             progress.py-20050610070202-df9faaab791964c0
      bzrlib/ui/text.py              text.py-20051130153916-2e438cffc8afc478
    ------------------------------------------------------------
    revno: 3882.7.5
    revision-id: mbp at sourcefrog.net-20081215010123-diylgwx90yz0gfs3
    parent: mbp at sourcefrog.net-20081214200649-8ilmikjrp0r6utp1
    committer: Martin Pool <mbp at sourcefrog.net>
    branch nick: progress
    timestamp: Mon 2008-12-15 12:01:23 +1100
    message:
      Further mockup of transport-based activity indicator.
      
      The activity is now drawn by the UI layer, and it shows total traffic plus 
      approximate current rate.
      
      This currently disables the regular progress bars.
    modified:
      bzrlib/transport/__init__.py   transport.py-20050711165921-4978aa7ce1285ad5
      bzrlib/ui/__init__.py          ui.py-20050824083933-8cf663c763ba53a9
      bzrlib/ui/text.py              text.py-20051130153916-2e438cffc8afc478
    ------------------------------------------------------------
    revno: 3882.7.4
    revision-id: mbp at sourcefrog.net-20081214200649-8ilmikjrp0r6utp1
    parent: mbp at sourcefrog.net-20081214200631-2elwxl7o6sbcpo0x
    committer: Martin Pool <mbp at sourcefrog.net>
    branch nick: progress
    timestamp: Mon 2008-12-15 07:06:49 +1100
    message:
      SFTPTransport also sends activity from get()
    modified:
      bzrlib/transport/sftp.py       sftp.py-20051019050329-ab48ce71b7e32dfe
    ------------------------------------------------------------
    revno: 3882.7.3
    revision-id: mbp at sourcefrog.net-20081214200631-2elwxl7o6sbcpo0x
    parent: mbp at sourcefrog.net-20081214183716-rdtk0w8yvxubdd3k
    committer: Martin Pool <mbp at sourcefrog.net>
    branch nick: progress
    timestamp: Mon 2008-12-15 07:06:31 +1100
    message:
      transport.get should specifically close the file handle
    modified:
      bzrlib/transport/__init__.py   transport.py-20050711165921-4978aa7ce1285ad5
    ------------------------------------------------------------
    revno: 3882.7.2
    revision-id: mbp at sourcefrog.net-20081214183716-rdtk0w8yvxubdd3k
    parent: mbp at sourcefrog.net-20081214183654-v91j52svczc56q9c
    committer: Martin Pool <mbp at sourcefrog.net>
    branch nick: progress
    timestamp: Mon 2008-12-15 05:37:16 +1100
    message:
      Start reporting activity from sftp read access
    modified:
      bzrlib/transport/sftp.py       sftp.py-20051019050329-ab48ce71b7e32dfe
    ------------------------------------------------------------
    revno: 3882.7.1
    revision-id: mbp at sourcefrog.net-20081214183654-v91j52svczc56q9c
    parent: pqm at pqm.ubuntu.com-20081205181554-ofrdnafloc43bxkh
    committer: Martin Pool <mbp at sourcefrog.net>
    branch nick: progress
    timestamp: Mon 2008-12-15 05:36:54 +1100
    message:
      Add stub _report_activity method as a transport callback
    modified:
      bzrlib/transport/__init__.py   transport.py-20050711165921-4978aa7ce1285ad5
=== modified file 'NEWS'
--- a/NEWS	2009-01-15 05:18:22 +0000
+++ b/NEWS	2009-01-15 07:34:16 +0000
@@ -4,6 +4,13 @@
 
 .. contents::
 
+IN DEVELOPMENT
+--------------
+
+  IMPROVEMENTS:
+
+    * Progress bars now show the rate of activity for some sftp 
+      operations, and they are drawn different.  (Martin Pool, #172741)
 
 NOT RELEASED YET
 ----------------
@@ -271,6 +278,10 @@
       advantage of pycurl is that it checks ssl certificates.)
       (John Arbash Meinel)
 
+    * The progress and UI classes have changed; the main APIs remain the
+      same but code that provides a new UI or progress bar class may
+      need to be updated.  (Martin Pool)
+
     * ``VersionedFiles.get_record_stream()`` can now return objects with a
       storage_kind of ``chunked``. This is a collection (list/tuple) of
       strings. You can use ``osutils.chunks_to_lines()`` to turn them into

=== modified file 'bzrlib/commands.py'
--- a/bzrlib/commands.py	2008-10-21 20:43:05 +0000
+++ b/bzrlib/commands.py	2008-12-16 07:56:29 +0000
@@ -868,8 +868,8 @@
 
 def main(argv):
     import bzrlib.ui
-    from bzrlib.ui.text import TextUIFactory
-    bzrlib.ui.ui_factory = TextUIFactory()
+    bzrlib.ui.ui_factory = bzrlib.ui.make_ui_for_terminal(
+        sys.stdin, sys.stdout, sys.stderr)
 
     # Is this a final release version? If so, we should suppress warnings
     if bzrlib.version_info[3] == 'final':

=== modified file 'bzrlib/errors.py'
--- a/bzrlib/errors.py	2009-01-08 16:57:10 +0000
+++ b/bzrlib/errors.py	2009-01-13 05:16:26 +0000
@@ -2171,11 +2171,6 @@
     _fmt = "Cannot perform local-only commits on unbound branches."
 
 
-class MissingProgressBarFinish(BzrError):
-
-    _fmt = "A nested progress bar was not 'finished' correctly."
-
-
 class InvalidProgressBarType(BzrError):
 
     _fmt = ("Environment variable BZR_PROGRESS_BAR='%(bar_type)s"

=== modified file 'bzrlib/progress.py'
--- a/bzrlib/progress.py	2008-04-24 07:22:53 +0000
+++ b/bzrlib/progress.py	2008-12-17 08:18:14 +0000
@@ -1,5 +1,4 @@
-# Copyright (C) 2005 Aaron Bentley <aaron.bentley at utoronto.ca>
-# Copyright (C) 2005, 2006 Canonical Ltd
+# Copyright (C) 2005, 2006, 2008 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
@@ -28,20 +27,19 @@
 bzrlib it really is best to use bzrlib.ui.ui_factory.
 """
 
-# TODO: Optionally show elapsed time instead/as well as ETA; nicer
-# when the rate is unpredictable
 
 import sys
 import time
 import os
-
-from bzrlib.lazy_import import lazy_import
-lazy_import(globals(), """
+import warnings
+
+
 from bzrlib import (
     errors,
+    osutils,
+    trace,
+    ui,
     )
-""")
-
 from bzrlib.trace import mutter
 
 
@@ -62,7 +60,69 @@
     return True
 
 
-_progress_bar_types = {}
+class ProgressTask(object):
+    """Model component of a progress indicator.
+
+    Most code that needs to indicate progress should update one of these, 
+    and it will in turn update the display, if one is present.
+
+    Code updating the task may also set fields as hints about how to display
+    it: show_pct, show_spinner, show_eta, show_count, show_bar.  UIs
+    will not necessarily respect all these fields.
+    """
+
+    def __init__(self, parent_task=None, ui_factory=None):
+        self._parent_task = parent_task
+        self._last_update = 0
+        self.total_cnt = None
+        self.current_cnt = None
+        self.msg = ''
+        self.ui_factory = ui_factory
+        self.show_pct = False
+        self.show_spinner = True
+        self.show_eta = False,
+        self.show_count = True
+        self.show_bar = True
+
+    def update(self, msg, current_cnt=None, total_cnt=None):
+        self.msg = msg
+        self.current_cnt = current_cnt
+        if total_cnt:
+            self.total_cnt = total_cnt
+        self.ui_factory.show_progress(self)
+
+    def tick(self):
+        self.update(self.msg)
+
+    def finished(self):
+        self.ui_factory.progress_finished(self)
+
+    def make_sub_task(self):
+        return ProgressTask(self, self.ui_factory)
+
+    def _overall_completion_fraction(self, child_fraction=0.0):
+        """Return fractional completion of this task and its parents
+        
+        Returns None if no completion can be computed."""
+        if self.total_cnt:
+            own_fraction = (float(self.current_cnt) + child_fraction) / self.total_cnt
+        else:
+            own_fraction = None
+        if self._parent_task is None:
+            return own_fraction
+        else:
+            if own_fraction is None:
+                own_fraction = 0.0
+            return self._parent_task._overall_completion_fraction(own_fraction)
+
+    def note(self, fmt_string, *args):
+        """Record a note without disrupting the progress bar."""
+        # XXX: shouldn't be here; put it in mutter or the ui instead
+        self.ui_factory.note(fmt_string % args)
+
+    def clear(self):
+        # XXX: shouldn't be here; put it in mutter or the ui instead
+        self.ui_factory.clear_term()
 
 
 def ProgressBar(to_file=None, **kwargs):
@@ -87,7 +147,7 @@
                                                 _progress_bar_types.keys())
         return _progress_bar_types[requested_bar_type](to_file=to_file, **kwargs)
 
- 
+
 class ProgressBarStack(object):
     """A stack of progress bars."""
 
@@ -147,8 +207,9 @@
     def return_pb(self, bar):
         """Return bar after its been used."""
         if bar is not self._stack[-1]:
-            raise errors.MissingProgressBarFinish()
-        self._stack.pop()
+            warnings.warn("%r is not currently active" % (bar,))
+        else:
+            self._stack.pop()
 
  
 class _BaseProgressBar(object):
@@ -206,6 +267,7 @@
 
     This can be used as the default argument for methods that
     take an optional progress indicator."""
+
     def tick(self):
         pass
 
@@ -225,10 +287,6 @@
         return DummyProgress(**kwargs)
 
 
-_progress_bar_types['dummy'] = DummyProgress
-_progress_bar_types['none'] = DummyProgress
-
-
 class DotsProgressBar(_BaseProgressBar):
 
     def __init__(self, **kwargs):
@@ -257,7 +315,6 @@
         self.tick()
 
 
-_progress_bar_types['dots'] = DotsProgressBar
 
     
 class TTYProgressBar(_BaseProgressBar):
@@ -329,8 +386,9 @@
         self.tick()
 
     def update(self, msg, current_cnt=None, total_cnt=None,
-               child_fraction=0):
-        """Update and redraw progress bar."""
+            child_fraction=0):
+        """Update and redraw progress bar.
+        """
         if msg is None:
             msg = self.last_msg
 
@@ -356,6 +414,9 @@
         ##     self.child_fraction == child_fraction):
         ##     return
 
+        if msg is None:
+            msg = ''
+
         old_msg = self.last_msg
         # save these for the tick() function
         self.last_msg = msg
@@ -401,7 +462,7 @@
             # make both fields the same size
             t = '%i' % (self.last_total)
             c = '%*i' % (len(t), self.last_cnt)
-            count_str = ' ' + c + '/' + t 
+            count_str = ' ' + c + '/' + t
 
         if self.show_bar:
             # progress bar, if present, soaks up all remaining space
@@ -425,7 +486,8 @@
         else:
             bar_str = ''
 
-        m = spin_str + bar_str + self.last_msg + count_str + pct_str + eta_str
+        m = spin_str + bar_str + self.last_msg + count_str \
+            + pct_str + eta_str
         self.to_file.write('\r%-*.*s' % (self.width - 1, self.width - 1, m))
         self._have_output = True
         #self.to_file.flush()
@@ -437,7 +499,6 @@
         #self.to_file.flush()        
 
 
-_progress_bar_types['tty'] = TTYProgressBar
 
 
 class ChildProgress(_BaseProgressBar):
@@ -557,3 +618,10 @@
         else:
             self.cur_phase += 1
         self.pb.update(self.message, self.cur_phase, self.total)
+
+
+_progress_bar_types = {}
+_progress_bar_types['dummy'] = DummyProgress
+_progress_bar_types['none'] = DummyProgress
+_progress_bar_types['tty'] = TTYProgressBar
+_progress_bar_types['dots'] = DotsProgressBar

=== modified file 'bzrlib/tests/blackbox/test_upgrade.py'
--- a/bzrlib/tests/blackbox/test_upgrade.py	2008-03-14 21:31:15 +0000
+++ b/bzrlib/tests/blackbox/test_upgrade.py	2009-01-13 05:07:27 +0000
@@ -1,6 +1,4 @@
-# Copyright (C) 2006, 2007 Canonical Ltd
-# Authors: Robert Collins <robert.collins at canonical.com>
-#          and others
+# Copyright (C) 2006, 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

=== modified file 'bzrlib/tests/test_sftp_transport.py'
--- a/bzrlib/tests/test_sftp_transport.py	2008-12-09 14:04:01 +0000
+++ b/bzrlib/tests/test_sftp_transport.py	2009-01-15 05:12:49 +0000
@@ -474,12 +474,17 @@
             yield self._data[start:start+length]
 
 
+def _null_report_activity(*a, **k):
+    pass
+
+
 class Test_SFTPReadvHelper(tests.TestCase):
 
     def checkGetRequests(self, expected_requests, offsets):
         if not paramiko_loaded:
             raise TestSkipped('you must have paramiko to run this test')
-        helper = _mod_sftp._SFTPReadvHelper(offsets, 'artificial_test')
+        helper = _mod_sftp._SFTPReadvHelper(offsets, 'artificial_test',
+            _null_report_activity)
         self.assertEqual(expected_requests, helper._get_requests())
 
     def test__get_requests(self):
@@ -499,7 +504,8 @@
     def checkRequestAndYield(self, expected, data, offsets):
         if not paramiko_loaded:
             raise TestSkipped('you must have paramiko to run this test')
-        helper = _mod_sftp._SFTPReadvHelper(offsets, 'artificial_test')
+        helper = _mod_sftp._SFTPReadvHelper(offsets, 'artificial_test',
+            _null_report_activity)
         data_f = ReadvFile(data)
         result = list(helper.request_and_yield_offsets(data_f))
         self.assertEqual(expected, result)

=== modified file 'bzrlib/tests/test_ui.py'
--- a/bzrlib/tests/test_ui.py	2007-04-13 16:16:54 +0000
+++ b/bzrlib/tests/test_ui.py	2009-01-15 06:44:09 +0000
@@ -1,4 +1,4 @@
-# Copyright (C) 2005 Canonical Ltd
+# Copyright (C) 2005, 2008 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
@@ -101,11 +101,11 @@
     def test_progress_note(self):
         stderr = StringIO()
         stdout = StringIO()
-        ui_factory = TextUIFactory(bar_type=TTYProgressBar)
+        ui_factory = TextUIFactory(stdin=StringIO(''),
+            stderr=stderr,
+            stdout=stdout)
         pb = ui_factory.nested_progress_bar()
         try:
-            pb.to_messages_file = stdout
-            ui_factory._progress_bar_stack.bottom().to_file = stderr
             result = pb.note('t')
             self.assertEqual(None, result)
             self.assertEqual("t\n", stdout.getvalue())
@@ -122,13 +122,12 @@
         # The PQM redirects the output to a file, so it
         # defaults to creating a Dots progress bar. we
         # need to force it to believe we are a TTY
-        ui_factory = TextUIFactory(bar_type=TTYProgressBar)
+        ui_factory = TextUIFactory(
+            stdin=StringIO(''),
+            stdout=stdout, stderr=stderr)
         pb = ui_factory.nested_progress_bar()
         try:
-            pb.to_messages_file = stdout
-            ui_factory._progress_bar_stack.bottom().to_file = stderr
             # Create a progress update that isn't throttled
-            pb.start_time -= 10
             pb.update('x', 1, 1)
             result = pb.note('t')
             self.assertEqual(None, result)
@@ -142,10 +141,12 @@
 
     def test_progress_nested(self):
         # test factory based nested and popping.
-        ui = TextUIFactory()
+        ui = TextUIFactory(None, None, None)
         pb1 = ui.nested_progress_bar()
         pb2 = ui.nested_progress_bar()
-        self.assertRaises(errors.MissingProgressBarFinish, pb1.finished)
+        # We no longer warn about finishing unnested progress bars.
+        warnings, _ = self.callCatchWarnings(pb1.finished)
+        self.assertEqual(len(warnings), 0)
         pb2.finished()
         pb1.finished()
 
@@ -160,28 +161,19 @@
         self.assertFalse(getattr(stack, 'note', False))
         pb1 = stack.get_nested()
         pb2 = stack.get_nested()
-        self.assertRaises(errors.MissingProgressBarFinish, pb1.finished)
+        warnings, _ = self.callCatchWarnings(pb1.finished)
+        self.assertEqual(len(warnings), 1)
         pb2.finished()
         pb1.finished()
         # the text ui factory never actually removes the stack once its setup.
         # we need to be able to nest again correctly from here.
         pb1 = stack.get_nested()
         pb2 = stack.get_nested()
-        self.assertRaises(errors.MissingProgressBarFinish, pb1.finished)
+        warnings, _ = self.callCatchWarnings(pb1.finished)
+        self.assertEqual(len(warnings), 1)
         pb2.finished()
         pb1.finished()
 
-    def test_text_factory_setting_progress_bar(self):
-        # we should be able to choose the progress bar type used.
-        factory = TextUIFactory(bar_type=DotsProgressBar)
-        bar = factory.nested_progress_bar()
-        bar.finished()
-        self.assertIsInstance(bar, DotsProgressBar)
-
-    def test_cli_stdin_is_default_stdin(self):
-        factory = CLIUIFactory()
-        self.assertEqual(sys.stdin, factory.stdin)
-
     def assert_get_bool_acceptance_of_user_input(self, factory):
         factory.stdin = StringIO("y\nyes with garbage\n"
                                  "yes\nn\nnot an answer\n"
@@ -212,28 +204,27 @@
         self.assertEqual('', factory.stdin.readline())
 
     def test_text_ui_getbool(self):
-        factory = TextUIFactory()
+        factory = TextUIFactory(None, None, None)
         self.assert_get_bool_acceptance_of_user_input(factory)
 
     def test_text_factory_prompts_and_clears(self):
         # a get_boolean call should clear the pb before prompting
-        factory = TextUIFactory(bar_type=DotsProgressBar)
-        factory.stdout = _TTYStringIO()
-        factory.stdin = StringIO("yada\ny\n")
-        pb = self.apply_redirected(factory.stdin, factory.stdout,
-                                   factory.stdout, factory.nested_progress_bar)
-        pb.start_time = None
-        self.apply_redirected(factory.stdin, factory.stdout,
-                              factory.stdout, pb.update, "foo", 0, 1)
+        out = _TTYStringIO()
+        factory = TextUIFactory(stdin=StringIO("yada\ny\n"), stdout=out, stderr=out)
+        pb = factory.nested_progress_bar()
+        pb.show_bar = False
+        pb.show_spinner = False
+        pb.show_count = False
+        pb.update("foo", 0, 1)
         self.assertEqual(True,
                          self.apply_redirected(None, factory.stdout,
                                                factory.stdout,
                                                factory.get_boolean,
                                                "what do you want"))
-        output = factory.stdout.getvalue()
-        self.assertEqual("foo: .\n"
-                         "what do you want? [y/n]: what do you want? [y/n]: ",
-                         factory.stdout.getvalue())
-        # stdin should be empty
+        output = out.getvalue()
+        self.assertContainsRe(factory.stdout.getvalue(),
+            "foo *\r\r  *\r*")
+        self.assertContainsRe(factory.stdout.getvalue(),
+            r"what do you want\? \[y/n\]: what do you want\? \[y/n\]: ")
+        # stdin should have been totally consumed
         self.assertEqual('', factory.stdin.readline())
-

=== modified file 'bzrlib/transport/__init__.py'
--- a/bzrlib/transport/__init__.py	2008-12-12 13:09:26 +0000
+++ b/bzrlib/transport/__init__.py	2008-12-24 07:37:37 +0000
@@ -41,6 +41,7 @@
     errors,
     osutils,
     symbol_versioning,
+    ui,
     urlutils,
     )
 """)
@@ -382,6 +383,18 @@
         except TypeError: # We can't tell how many, because relpaths is a generator
             return None
 
+    def _report_activity(self, bytes, direction):
+        """Notify that this transport has activity.
+
+        Implementations should call this from all methods that actually do IO.
+        Be careful that it's not called twice, if one method is implemented on
+        top of another.
+
+        :param bytes: Number of bytes read or written.
+        :param direction: 'read' or 'write' or None.
+        """
+        ui.ui_factory.report_transport_activity(self, bytes, direction)
+
     def _update_pb(self, pb, msg, count, total):
         """Update the progress bar based on the current count
         and total available, total may be None if it was
@@ -568,7 +581,11 @@
 
         :param relpath: The relative path to the file
         """
-        return self.get(relpath).read()
+        f = self.get(relpath)
+        try:
+            return f.read()
+        finally:
+            f.close()
 
     @deprecated_method(one_four)
     def get_smart_client(self):

=== modified file 'bzrlib/transport/sftp.py'
--- a/bzrlib/transport/sftp.py	2008-11-07 05:39:09 +0000
+++ b/bzrlib/transport/sftp.py	2009-01-15 05:12:49 +0000
@@ -1,5 +1,4 @@
-# Copyright (C) 2005 Robey Pointer <robey at lag.net>
-# Copyright (C) 2005, 2006, 2007 Canonical Ltd
+# Copyright (C) 2005, 2006, 2007, 2008, 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
@@ -140,15 +139,18 @@
     # See _get_requests for an explanation.
     _max_request_size = 32768
 
-    def __init__(self, original_offsets, relpath):
+    def __init__(self, original_offsets, relpath, _report_activity):
         """Create a new readv helper.
 
         :param original_offsets: The original requests given by the caller of
             readv()
         :param relpath: The name of the file (if known)
+        :param _report_activity: A Transport._report_activity bound method,
+            to be called as data arrives.
         """
         self.original_offsets = list(original_offsets)
         self.relpath = relpath
+        self._report_activity = _report_activity
 
     def _get_requests(self):
         """Break up the offsets into individual requests over sftp.
@@ -219,6 +221,7 @@
             if len(data) != length:
                 raise errors.ShortReadvError(self.relpath,
                     start, length, len(data))
+            self._report_activity(length, 'read')
             if last_end is None:
                 # This is the first request, just buffer it
                 buffered_data = [data]
@@ -405,8 +408,7 @@
             return False
 
     def get(self, relpath):
-        """
-        Get the file at the given relative path.
+        """Get the file at the given relative path.
 
         :param relpath: The relative path to the file
         """
@@ -420,6 +422,16 @@
             self._translate_io_exception(e, path, ': error retrieving',
                 failure_exc=errors.ReadError)
 
+    def get_bytes(self, relpath):
+        # reimplement this here so that we can report how many bytes came back
+        f = self.get(relpath)
+        try:
+            bytes = f.read()
+            self._report_activity(len(bytes), 'read')
+            return bytes
+        finally:
+            f.close()
+
     def _readv(self, relpath, offsets):
         """See Transport.readv()"""
         # We overload the default readv() because we want to use a file
@@ -454,7 +466,7 @@
         does not support ranges > 64K, so it caps the request size, and
         just reads until it gets all the stuff it wants
         """
-        helper = _SFTPReadvHelper(offsets, relpath)
+        helper = _SFTPReadvHelper(offsets, relpath, self._report_activity)
         return helper.request_and_yield_offsets(fp)
 
     def put_file(self, relpath, f, mode=None):

=== modified file 'bzrlib/ui/__init__.py'
--- a/bzrlib/ui/__init__.py	2008-03-11 22:15:16 +0000
+++ b/bzrlib/ui/__init__.py	2009-01-13 05:07:27 +0000
@@ -26,7 +26,9 @@
 displays no output.
 """
 
+import os
 import sys
+import warnings
 
 from bzrlib.lazy_import import lazy_import
 lazy_import(globals(), """
@@ -49,8 +51,7 @@
     """
 
     def __init__(self):
-        super(UIFactory, self).__init__()
-        self._progress_bar_stack = None
+        self._task_stack = []
 
     def get_password(self, prompt='', **kwargs):
         """Prompt the user for a password.
@@ -73,7 +74,18 @@
         When the bar has been finished with, it should be released by calling
         bar.finished().
         """
-        raise NotImplementedError(self.nested_progress_bar)
+        if self._task_stack:
+            t = progress.ProgressTask(self._task_stack[-1], self)
+        else:
+            t = progress.ProgressTask(None, self)
+        self._task_stack.append(t)
+        return t
+
+    def progress_finished(self, task):
+        if task != self._task_stack[-1]:
+            warnings.warn("%r is not currently active" % (task,))
+        else:
+            del self._task_stack[-1]
 
     def clear_term(self):
         """Prepare the terminal for output.
@@ -104,13 +116,26 @@
             current_format_name,
             basedir)
 
+    def report_transport_activity(self, transport, byte_count, direction):
+        """Called by transports as they do IO.
+        
+        This may update a progress bar, spinner, or similar display.
+        By default it does nothing.
+        """
+        pass
+
+
 
 class CLIUIFactory(UIFactory):
-    """Common behaviour for command line UI factories."""
+    """Common behaviour for command line UI factories.
+    
+    This is suitable for dumb terminals that can't repaint existing text."""
 
-    def __init__(self):
-        super(CLIUIFactory, self).__init__()
-        self.stdin = sys.stdin
+    def __init__(self, stdin=None, stdout=None, stderr=None):
+        UIFactory.__init__(self)
+        self.stdin = stdin or sys.stdin
+        self.stdout = stdout or sys.stdout
+        self.stderr = stderr or sys.stderr
 
     def get_boolean(self, prompt):
         self.clear_term()
@@ -148,6 +173,15 @@
     def prompt(self, prompt):
         """Emit prompt on the CLI."""
 
+    def clear_term(self):
+        pass
+
+    def show_progress(self, task):
+        pass
+
+    def progress_finished(self, task):
+        pass
+
 
 class SilentUIFactory(CLIUIFactory):
     """A UI Factory which never prints anything.
@@ -155,19 +189,14 @@
     This is the default UI, if another one is never registered.
     """
 
+    def __init__(self):
+        CLIUIFactory.__init__(self)
+
     def get_password(self, prompt='', **kwargs):
         return None
 
-    def nested_progress_bar(self):
-        if self._progress_bar_stack is None:
-            self._progress_bar_stack = progress.ProgressBarStack(
-                klass=progress.DummyProgress)
-        return self._progress_bar_stack.get_nested()
-
-    def clear_term(self):
-        pass
-
-    def recommend_upgrade(self, *args):
+
+    def note(self, msg):
         pass
 
 
@@ -180,3 +209,23 @@
 ui_factory = SilentUIFactory()
 """IMPORTANT: never import this symbol directly. ONLY ever access it as 
 ui.ui_factory."""
+
+
+def make_ui_for_terminal(stdin, stdout, stderr):
+    """Construct and return a suitable UIFactory for a text mode program.
+
+    If stdout is a smart terminal, this gets a smart UIFactory with 
+    progress indicators, etc.  If it's a dumb terminal, just plain text output.
+    """
+    isatty = getattr(stdin, 'isatty', None)
+    if isatty is None:
+        cls = CLIUIFactory
+    elif not isatty():
+        cls = CLIUIFactory
+    elif os.environ.get('TERM') in (None, 'dumb', ''):
+        # e.g. emacs compile window
+        cls = CLIUIFactory
+    else:
+        from bzrlib.ui.text import TextUIFactory
+        cls = TextUIFactory
+    return cls(stdin=stdin, stdout=stdout, stderr=stderr)

=== modified file 'bzrlib/ui/text.py'
--- a/bzrlib/ui/text.py	2007-08-15 04:33:34 +0000
+++ b/bzrlib/ui/text.py	2008-12-16 07:56:29 +0000
@@ -1,4 +1,4 @@
-# Copyright (C) 2005 Canonical Ltd
+# Copyright (C) 2005, 2008 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
@@ -20,6 +20,7 @@
 """
 
 import sys
+import time
 
 from bzrlib.lazy_import import lazy_import
 lazy_import(globals(), """
@@ -28,7 +29,9 @@
 from bzrlib import (
     progress,
     osutils,
+    symbol_versioning,
     )
+
 """)
 
 from bzrlib.ui import CLIUIFactory
@@ -39,47 +42,189 @@
 
     def __init__(self,
                  bar_type=None,
+                 stdin=None,
                  stdout=None,
                  stderr=None):
         """Create a TextUIFactory.
 
         :param bar_type: The type of progress bar to create. It defaults to 
                          letting the bzrlib.progress.ProgressBar factory auto
-                         select.
+                         select.   Deprecated.
         """
-        super(TextUIFactory, self).__init__()
-        self._bar_type = bar_type
-        if stdout is None:
-            self.stdout = sys.stdout
-        else:
-            self.stdout = stdout
-        if stderr is None:
-            self.stderr = sys.stderr
-        else:
-            self.stderr = stderr
+        super(TextUIFactory, self).__init__(stdin=stdin,
+                stdout=stdout, stderr=stderr)
+        if bar_type:
+            symbol_versioning.warn(symbol_versioning.deprecated_in((1, 11, 0))
+                % "bar_type parameter")
+        # paints progress, network activity, etc
+        self._progress_view = TextProgressView(self.stderr)
 
     def prompt(self, prompt):
         """Emit prompt on the CLI."""
         self.stdout.write(prompt)
         
-    def nested_progress_bar(self):
-        """Return a nested progress bar.
-        
-        The actual bar type returned depends on the progress module which
-        may return a tty or dots bar depending on the terminal.
-        """
-        if self._progress_bar_stack is None:
-            self._progress_bar_stack = progress.ProgressBarStack(
-                klass=self._bar_type)
-        return self._progress_bar_stack.get_nested()
-
     def clear_term(self):
         """Prepare the terminal for output.
 
         This will, clear any progress bars, and leave the cursor at the
         leftmost position."""
-        if self._progress_bar_stack is None:
+        # XXX: If this is preparing to write to stdout, but that's for example
+        # directed into a file rather than to the terminal, and the progress
+        # bar _is_ going to the terminal, we shouldn't need
+        # to clear it.  We might need to separately check for the case of 
+        self._progress_view.clear()
+
+    def note(self, msg):
+        """Write an already-formatted message, clearing the progress bar if necessary."""
+        self.clear_term()
+        self.stdout.write(msg + '\n')
+
+    def report_transport_activity(self, transport, byte_count, direction):
+        """Called by transports as they do IO.
+        
+        This may update a progress bar, spinner, or similar display.
+        By default it does nothing.
+        """
+        self._progress_view.show_transport_activity(byte_count)
+
+    def show_progress(self, task):
+        """A task has been updated and wants to be displayed.
+        """
+        self._progress_view.show_progress(task)
+
+    def progress_finished(self, task):
+        CLIUIFactory.progress_finished(self, task)
+        if not self._task_stack:
+            # finished top-level task
+            self._progress_view.clear()
+
+
+class TextProgressView(object):
+    """Display of progress bar and other information on a tty.
+    
+    This shows one line of text, including possibly a network indicator, spinner, 
+    progress bar, message, etc.
+
+    One instance of this is created and held by the UI, and fed updates when a
+    task wants to be painted.
+
+    Transports feed data to this through the ui_factory object.
+    """
+
+    def __init__(self, term_file):
+        self._term_file = term_file
+        # true when there's output on the screen we may need to clear
+        self._have_output = False
+        # XXX: We could listen for SIGWINCH and update the terminal width...
+        self._width = osutils.terminal_width()
+        self._last_transport_msg = ''
+        self._spin_pos = 0
+        # time we last repainted the screen
+        self._last_repaint = 0
+        # time we last got information about transport activity
+        self._transport_update_time = 0
+        self._task_fraction = None
+        self._last_task = None
+        self._total_byte_count = 0
+        self._bytes_since_update = 0
+
+    def _show_line(self, s):
+        n = self._width - 1
+        self._term_file.write('\r%-*.*s\r' % (n, n, s))
+
+    def clear(self):
+        if self._have_output:
+            self._show_line('')
+        self._have_output = False
+
+    def _render_bar(self):
+        # return a string for the progress bar itself
+        if (self._last_task is not None) and self._last_task.show_bar:
+            spin_str =  r'/-\|'[self._spin_pos % 4]
+            self._spin_pos += 1
+            f = self._task_fraction or 0
+            cols = 20
+            # number of markers highlighted in bar
+            markers = int(round(float(cols) * f)) - 1
+            bar_str = '[' + ('#' * markers + spin_str).ljust(cols) + '] '
+            return bar_str
+        elif (self._last_task is None) or self._last_task.show_spinner:
+            spin_str =  r'/-\|'[self._spin_pos % 4]
+            self._spin_pos += 1
+            return spin_str + ' '
+        else:
+            return ''
+
+    def _format_task(self, task):
+        if not task.show_count:
+            s = ''
+        elif task.total_cnt is not None:
+            s = ' %d/%d' % (task.current_cnt, task.total_cnt)
+        elif task.current_cnt is not None:
+            s = ' %d' % (task.current_cnt)
+        else:
+            s = ''
+        self._task_fraction = task._overall_completion_fraction()
+        # compose all the parent messages
+        t = task
+        m = task.msg
+        while t._parent_task:
+            t = t._parent_task
+            if t.msg:
+                m = t.msg + ':' + m
+        return m + s
+
+    def _repaint(self):
+        bar_string = self._render_bar()
+        if self._last_task:
+            task_msg = self._format_task(self._last_task)
+        else:
+            task_msg = ''
+        trans = self._last_transport_msg
+        if trans and task_msg:
+            trans += ' | '
+        s = (bar_string
+             + trans
+             + task_msg
+             )
+        self._show_line(s)
+        self._have_output = True
+
+    def show_progress(self, task):
+        self._last_task = task
+        now = time.time()
+        if now < self._last_repaint + 0.1:
             return
-        overall_pb = self._progress_bar_stack.bottom()
-        if overall_pb is not None:
-            overall_pb.clear()
+        if now > self._transport_update_time + 5:
+            # no recent activity; expire it
+            self._last_transport_msg = ''
+        self._last_repaint = now
+        self._repaint()
+
+    def show_transport_activity(self, byte_count):
+        """Called by transports as they do IO.
+        
+        This may update a progress bar, spinner, or similar display.
+        By default it does nothing.
+        """
+        # XXX: Probably there should be a transport activity model, and that
+        # too should be seen by the progress view, rather than being poked in
+        # here.
+        self._total_byte_count += byte_count
+        self._bytes_since_update += byte_count
+        now = time.time()
+        if self._transport_update_time is None:
+            self._transport_update_time = now
+        elif now >= (self._transport_update_time + 0.2):
+            # guard against clock stepping backwards, and don't update too
+            # often
+            rate = self._bytes_since_update / (now - self._transport_update_time)
+            msg = ("%6dkB @ %4dkB/s" %
+                (self._total_byte_count>>10, int(rate)>>10,))
+            self._transport_update_time = now
+            self._last_repaint = now
+            self._bytes_since_update = 0
+            self._last_transport_msg = msg
+            self._repaint()
+
+




More information about the bazaar-commits mailing list