Rev 3978: Faster log (Ian Clatworthy) in file:///home/pqm/archives/thelove/bzr/%2Btrunk/

Canonical.com Patch Queue Manager pqm at pqm.ubuntu.com
Mon Feb 2 09:14:21 GMT 2009


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

------------------------------------------------------------
revno: 3978
revision-id: pqm at pqm.ubuntu.com-20090202091414-4q20mjzsvp03vyfc
parent: pqm at pqm.ubuntu.com-20090202053119-adgabjjho5g49v76
parent: ian.clatworthy at canonical.com-20090202083117-wui3o7auvyt20wta
committer: Canonical.com Patch Queue Manager <pqm at pqm.ubuntu.com>
branch nick: +trunk
timestamp: Mon 2009-02-02 09:14:14 +0000
message:
  Faster log (Ian Clatworthy)
modified:
  NEWS                           NEWS-20050323055033-4e00b5db738777ff
  bzrlib/builtins.py             builtins.py-20050830033751-fc01482b9ca23183
  bzrlib/log.py                  log.py-20050505065812-c40ce11702fe5fb1
  bzrlib/tests/blackbox/test_log.py test_log.py-20060112090212-78f6ea560c868e24
  bzrlib/tests/test_log.py       testlog.py-20050728115707-1a514809d7d49309
    ------------------------------------------------------------
    revno: 3976.1.1
    revision-id: ian.clatworthy at canonical.com-20090202083117-wui3o7auvyt20wta
    parent: pqm at pqm.ubuntu.com-20090131231933-8o4phfvmuuizyyn6
    parent: ian.clatworthy at canonical.com-20090202082854-20ktgsdiqcvc2uf9
    committer: Ian Clatworthy <ian.clatworthy at canonical.com>
    branch nick: ianc-integration
    timestamp: Mon 2009-02-02 18:31:17 +1000
    message:
      Faster log (Ian Clatworthy)
    modified:
      NEWS                           NEWS-20050323055033-4e00b5db738777ff
      bzrlib/builtins.py             builtins.py-20050830033751-fc01482b9ca23183
      bzrlib/log.py                  log.py-20050505065812-c40ce11702fe5fb1
      bzrlib/tests/blackbox/test_log.py test_log.py-20060112090212-78f6ea560c868e24
      bzrlib/tests/test_log.py       testlog.py-20050728115707-1a514809d7d49309
    ------------------------------------------------------------
    revno: 3936.3.43
    revision-id: ian.clatworthy at canonical.com-20090202082854-20ktgsdiqcvc2uf9
    parent: ian.clatworthy at canonical.com-20090202055626-ptlb3jr3sb00v9hh
    committer: Ian Clatworthy <ian.clatworthy at canonical.com>
    branch nick: bzr.log-refactor
    timestamp: Mon 2009-02-02 18:28:54 +1000
    message:
      back out delta filtering for ranges - too slow on MySQL branch still
    modified:
      bzrlib/log.py                  log.py-20050505065812-c40ce11702fe5fb1
    ------------------------------------------------------------
    revno: 3936.3.42
    revision-id: ian.clatworthy at canonical.com-20090202055626-ptlb3jr3sb00v9hh
    parent: ian.clatworthy at canonical.com-20090202054708-sjisrybw25x3ch61
    parent: pqm at pqm.ubuntu.com-20090131231933-8o4phfvmuuizyyn6
    committer: Ian Clatworthy <ian.clatworthy at canonical.com>
    branch nick: bzr.log-refactor
    timestamp: Mon 2009-02-02 15:56:26 +1000
    message:
      merge bzr.dev r3976
    modified:
      bzrlib/log.py                  log.py-20050505065812-c40ce11702fe5fb1
    ------------------------------------------------------------
    revno: 3936.3.41
    revision-id: ian.clatworthy at canonical.com-20090202054708-sjisrybw25x3ch61
    parent: ian.clatworthy at canonical.com-20090202054313-5iokm54sinu9i2vd
    parent: ian.clatworthy at canonical.com-20090129091435-s719ii56so4q826r
    committer: Ian Clatworthy <ian.clatworthy at canonical.com>
    branch nick: bzr.log-refactor
    timestamp: Mon 2009-02-02 15:47:08 +1000
    message:
      merge latest iter-merge-sorted-revisions
    modified:
      bzrlib/branch.py               branch.py-20050309040759-e4baf4e0d046576e
      bzrlib/tests/branch_implementations/test_iter_merge_sorted_revisions.py test_merge_sorted_re-20090121004847-to3gvjwigstu93eh-1
    ------------------------------------------------------------
    revno: 3936.3.40
    revision-id: ian.clatworthy at canonical.com-20090202054313-5iokm54sinu9i2vd
    parent: ian.clatworthy at canonical.com-20090131041743-3v7wmbojb55bx0pq
    committer: Ian Clatworthy <ian.clatworthy at canonical.com>
    branch nick: bzr.log-refactor
    timestamp: Mon 2009-02-02 15:43:13 +1000
    message:
      review feedback from jam
    modified:
      bzrlib/builtins.py             builtins.py-20050830033751-fc01482b9ca23183
      bzrlib/log.py                  log.py-20050505065812-c40ce11702fe5fb1
    ------------------------------------------------------------
    revno: 3936.3.39
    revision-id: ian.clatworthy at canonical.com-20090131041743-3v7wmbojb55bx0pq
    parent: ian.clatworthy at canonical.com-20090128112929-db0zx88s2ddsf21k
    parent: pqm at pqm.ubuntu.com-20090130185542-dbj7mapm1fvtwm3y
    committer: Ian Clatworthy <ian.clatworthy at canonical.com>
    branch nick: bzr.log-refactor
    timestamp: Sat 2009-01-31 14:17:43 +1000
    message:
      merge bzr.dev r3975
    modified:
      NEWS                           NEWS-20050323055033-4e00b5db738777ff
      bzrlib/annotate.py             annotate.py-20050922133147-7c60541d2614f022
      bzrlib/builtins.py             builtins.py-20050830033751-fc01482b9ca23183
      bzrlib/dirstate.py             dirstate.py-20060728012006-d6mvoihjb3je9peu-1
      bzrlib/fetch.py                fetch.py-20050818234941-26fea6105696365d
      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/knit.py                 knit.py-20051212171256-f056ac8f0fbe1bd9
      bzrlib/log.py                  log.py-20050505065812-c40ce11702fe5fb1
      bzrlib/merge.py                merge.py-20050513021216-953b65a438527106
      bzrlib/missing.py              missing.py-20050812153334-097f7097e2a8bcd1
      bzrlib/revisionspec.py         revisionspec.py-20050907152633-17567659fd5c0ddb
      bzrlib/tests/blackbox/test_annotate.py testannotate.py-20051013044000-457f44801bfa9d39
      bzrlib/tests/blackbox/test_breakin.py test_breakin.py-20070424043903-qyy6zm4pj3h4sbp3-1
      bzrlib/tests/blackbox/test_log.py test_log.py-20060112090212-78f6ea560c868e24
      bzrlib/tests/blackbox/test_missing.py test_missing.py-20051211212735-a2cf4c1840bb84c4
      bzrlib/tests/blackbox/test_serve.py test_serve.py-20060913064329-8t2pvmsikl4s3xhl-1
      bzrlib/tests/blackbox/test_shelve.py test_ls_shelf.py-20081202053526-thlo8yt0pi1cgor1-1
      bzrlib/tests/test_foreign.py   test_foreign.py-20081125004048-ywb901edgp9lluxo-1
      bzrlib/tests/test_graph.py     test_graph_walker.py-20070525030405-enq4r60hhi9xrujc-1
      bzrlib/tests/test_log.py       testlog.py-20050728115707-1a514809d7d49309
      bzrlib/tests/test_merge.py     testmerge.py-20050905070950-c1b5aa49ff911024
      bzrlib/tests/test_missing.py   test_missing.py-20051212000028-694fa4f658a81f48
      bzrlib/tests/test_versionedfile.py test_versionedfile.py-20060222045249-db45c9ed14a1c2e5
      bzrlib/tests/tree_implementations/test_get_symlink_target.py test_get_symlink_tar-20070225165554-ickod3w3t7u0zzqh-1
      bzrlib/tests/tree_implementations/test_path_content_summary.py test_path_content_su-20070904100855-3vrwedz6akn34kl5-1
      bzrlib/util/bencode.py         bencode.py-20070220044742-sltr28q21w2wzlxi-1
      bzrlib/util/tests/test_bencode.py test_bencode.py-20070713042202-qjw8rppxaz7ky6i6-1
      bzrlib/versionedfile.py        versionedfile.py-20060222045106-5039c71ee3b65490
      bzrlib/workingtree.py          workingtree.py-20050511021032-29b6ec0a681e02e3
    ------------------------------------------------------------
    revno: 3936.3.38
    revision-id: ian.clatworthy at canonical.com-20090128112929-db0zx88s2ddsf21k
    parent: ian.clatworthy at canonical.com-20090128112721-sr8ahk3zg7f63g85
    committer: Ian Clatworthy <ian.clatworthy at canonical.com>
    branch nick: bzr.log-refactor
    timestamp: Wed 2009-01-28 21:29:29 +1000
    message:
      tweak NEWS
    modified:
      NEWS                           NEWS-20050323055033-4e00b5db738777ff
    ------------------------------------------------------------
    revno: 3936.3.37
    revision-id: ian.clatworthy at canonical.com-20090128112721-sr8ahk3zg7f63g85
    parent: ian.clatworthy at canonical.com-20090127125601-z436vlc25r9l2q18
    committer: Ian Clatworthy <ian.clatworthy at canonical.com>
    branch nick: bzr.log-refactor
    timestamp: Wed 2009-01-28 21:27:21 +1000
    message:
      selectively delay graph generation, not always
    modified:
      bzrlib/log.py                  log.py-20050505065812-c40ce11702fe5fb1
    ------------------------------------------------------------
    revno: 3936.3.36
    revision-id: ian.clatworthy at canonical.com-20090127125601-z436vlc25r9l2q18
    parent: ian.clatworthy at canonical.com-20090127121736-6lnepki0par6606b
    committer: Ian Clatworthy <ian.clatworthy at canonical.com>
    branch nick: bzr.log-refactor
    timestamp: Tue 2009-01-27 22:56:01 +1000
    message:
      minor comment polish & refactoring
    modified:
      bzrlib/log.py                  log.py-20050505065812-c40ce11702fe5fb1
    ------------------------------------------------------------
    revno: 3936.3.35
    revision-id: ian.clatworthy at canonical.com-20090127121736-6lnepki0par6606b
    parent: ian.clatworthy at canonical.com-20090127120003-ykjl7nlhdd1oy8l3
    committer: Ian Clatworthy <ian.clatworthy at canonical.com>
    branch nick: bzr.log-refactor
    timestamp: Tue 2009-01-27 22:17:36 +1000
    message:
      simplify single revision logic
    modified:
      bzrlib/log.py                  log.py-20050505065812-c40ce11702fe5fb1
    ------------------------------------------------------------
    revno: 3936.3.34
    revision-id: ian.clatworthy at canonical.com-20090127120003-ykjl7nlhdd1oy8l3
    parent: ian.clatworthy at canonical.com-20090127110847-nzd0csfhpuf5rl3m
    committer: Ian Clatworthy <ian.clatworthy at canonical.com>
    branch nick: bzr.log-refactor
    timestamp: Tue 2009-01-27 22:00:03 +1000
    message:
      return _mainline_revs() API as used in missing.py
    modified:
      bzrlib/log.py                  log.py-20050505065812-c40ce11702fe5fb1
    ------------------------------------------------------------
    revno: 3936.3.33
    revision-id: ian.clatworthy at canonical.com-20090127110847-nzd0csfhpuf5rl3m
    parent: ian.clatworthy at canonical.com-20090127064917-poxu010onn6u147b
    committer: Ian Clatworthy <ian.clatworthy at canonical.com>
    branch nick: bzr.log-refactor
    timestamp: Tue 2009-01-27 21:08:47 +1000
    message:
      only generate deltas for file matching as long as necessary
    modified:
      bzrlib/log.py                  log.py-20050505065812-c40ce11702fe5fb1
    ------------------------------------------------------------
    revno: 3936.3.32
    revision-id: ian.clatworthy at canonical.com-20090127064917-poxu010onn6u147b
    parent: ian.clatworthy at canonical.com-20090127054211-m4z2x5od2xyljopc
    committer: Ian Clatworthy <ian.clatworthy at canonical.com>
    branch nick: bzr.log-refactor
    timestamp: Tue 2009-01-27 16:49:17 +1000
    message:
      always delay merge graph generation until necessary
    modified:
      bzrlib/log.py                  log.py-20050505065812-c40ce11702fe5fb1
    ------------------------------------------------------------
    revno: 3936.3.31
    revision-id: ian.clatworthy at canonical.com-20090127054211-m4z2x5od2xyljopc
    parent: ian.clatworthy at canonical.com-20090127040514-z72i60ixqx1u0abz
    committer: Ian Clatworthy <ian.clatworthy at canonical.com>
    branch nick: bzr.log-refactor
    timestamp: Tue 2009-01-27 15:42:11 +1000
    message:
      nicer obvious ancestor checking
    modified:
      bzrlib/log.py                  log.py-20050505065812-c40ce11702fe5fb1
    ------------------------------------------------------------
    revno: 3936.3.30
    revision-id: ian.clatworthy at canonical.com-20090127040514-z72i60ixqx1u0abz
    parent: ian.clatworthy at canonical.com-20090127012440-1658qsg5nxc6m70r
    committer: Ian Clatworthy <ian.clatworthy at canonical.com>
    branch nick: bzr.log-refactor
    timestamp: Tue 2009-01-27 14:05:14 +1000
    message:
      use iter_merge_sorted_revisions() with stop_range feature
    modified:
      bzrlib/branch.py               branch.py-20050309040759-e4baf4e0d046576e
      bzrlib/log.py                  log.py-20050505065812-c40ce11702fe5fb1
      bzrlib/tests/test_log.py       testlog.py-20050728115707-1a514809d7d49309
    ------------------------------------------------------------
    revno: 3936.3.29
    revision-id: ian.clatworthy at canonical.com-20090127012440-1658qsg5nxc6m70r
    parent: ian.clatworthy at canonical.com-20090124123817-q11ovizmi67y5gva
    parent: ian.clatworthy at canonical.com-20090127001039-ill4gah3eqx7w7gz
    committer: Ian Clatworthy <ian.clatworthy at canonical.com>
    branch nick: bzr.log-refactor
    timestamp: Tue 2009-01-27 11:24:40 +1000
    message:
      merge stop_rule support in iter_merge_sorted_revisions()
    modified:
      NEWS                           NEWS-20050323055033-4e00b5db738777ff
      bzrlib/branch.py               branch.py-20050309040759-e4baf4e0d046576e
      bzrlib/osutils.py              osutils.py-20050309040759-eeaff12fbf77ac86
      bzrlib/tests/branch_implementations/test_iter_merge_sorted_revisions.py test_merge_sorted_re-20090121004847-to3gvjwigstu93eh-1
      bzrlib/tests/test_osutils.py   test_osutils.py-20051201224856-e48ee24c12182989
      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/http/response.py _response.py-20060613154423-a2ci7hd4iw5c7fnt-1
      doc/developers/api-versioning.txt apiversioning.txt-20070626065626-iiihgmhgkv91uphz-1
      doc/developers/plugin-api.txt  pluginapi.txt-20080229110225-q2j5y4agqhlkjn0s-1
    ------------------------------------------------------------
    revno: 3936.3.28
    revision-id: ian.clatworthy at canonical.com-20090124123817-q11ovizmi67y5gva
    parent: ian.clatworthy at canonical.com-20090124123205-s97pvjvk4ym48nc4
    committer: Ian Clatworthy <ian.clatworthy at canonical.com>
    branch nick: bzr.log-refactor
    timestamp: Sat 2009-01-24 22:38:17 +1000
    message:
      api compatibility: calculate_view_revisions rebases merge depth again
    modified:
      bzrlib/log.py                  log.py-20050505065812-c40ce11702fe5fb1
      bzrlib/tests/test_log.py       testlog.py-20050728115707-1a514809d7d49309
    ------------------------------------------------------------
    revno: 3936.3.27
    revision-id: ian.clatworthy at canonical.com-20090124123205-s97pvjvk4ym48nc4
    parent: ian.clatworthy at canonical.com-20090122060442-1ehshkxz2o1uq65f
    parent: pqm at pqm.ubuntu.com-20090124044940-7j90kl1qq22la0rx
    committer: Ian Clatworthy <ian.clatworthy at canonical.com>
    branch nick: bzr.log-refactor
    timestamp: Sat 2009-01-24 22:32:05 +1000
    message:
      merge bzr.dev r3957
    added:
      bzrlib/tests/branch_implementations/test_iter_merge_sorted_revisions.py test_merge_sorted_re-20090121004847-to3gvjwigstu93eh-1
    modified:
      NEWS                           NEWS-20050323055033-4e00b5db738777ff
      bzrlib/branch.py               branch.py-20050309040759-e4baf4e0d046576e
      bzrlib/knit.py                 knit.py-20051212171256-f056ac8f0fbe1bd9
      bzrlib/log.py                  log.py-20050505065812-c40ce11702fe5fb1
      bzrlib/merge.py                merge.py-20050513021216-953b65a438527106
      bzrlib/progress.py             progress.py-20050610070202-df9faaab791964c0
      bzrlib/remote.py               remote.py-20060720103555-yeeg2x51vn0rbtdp-1
      bzrlib/revisionspec.py         revisionspec.py-20050907152633-17567659fd5c0ddb
      bzrlib/tests/branch_implementations/__init__.py __init__.py-20060123013057-b12a52c3f361daf4
      bzrlib/tests/branch_implementations/test_dotted_revno_to_revision_id.py test_dotted_revno_to-20090121014844-6x7d9jtri5sspg1o-1
      bzrlib/tests/test_knit.py      test_knit.py-20051212171302-95d4c00dd5f11f2b
      bzrlib/tests/test_log.py       testlog.py-20050728115707-1a514809d7d49309
      bzrlib/tests/test_merge.py     testmerge.py-20050905070950-c1b5aa49ff911024
      bzrlib/tests/test_progress.py  test_progress.py-20060308160359-978c397bc79b7fda
      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: 3936.3.26
    revision-id: ian.clatworthy at canonical.com-20090122060442-1ehshkxz2o1uq65f
    parent: ian.clatworthy at canonical.com-20090122055104-4j1ek6agkwgncx49
    committer: Ian Clatworthy <ian.clatworthy at canonical.com>
    branch nick: bzr.log-refactor
    timestamp: Thu 2009-01-22 16:04:42 +1000
    message:
      use new dotted-revno-revision-id conversion methods to simplify & speed up code
    modified:
      bzrlib/log.py                  log.py-20050505065812-c40ce11702fe5fb1
    ------------------------------------------------------------
    revno: 3936.3.25
    revision-id: ian.clatworthy at canonical.com-20090122055104-4j1ek6agkwgncx49
    parent: ian.clatworthy at canonical.com-20090122053626-g1ksg9j7iu3n6ain
    committer: Ian Clatworthy <ian.clatworthy at canonical.com>
    branch nick: bzr.log-refactor
    timestamp: Thu 2009-01-22 15:51:04 +1000
    message:
      fix bug when start/end revision are integers
    modified:
      bzrlib/log.py                  log.py-20050505065812-c40ce11702fe5fb1
    ------------------------------------------------------------
    revno: 3936.3.24
    revision-id: ian.clatworthy at canonical.com-20090122053626-g1ksg9j7iu3n6ain
    parent: ian.clatworthy at canonical.com-20090122053159-rmo3qky7n35phy9s
    parent: ian.clatworthy at canonical.com-20090122053359-0ozol6xxjiyv2p4q
    committer: Ian Clatworthy <ian.clatworthy at canonical.com>
    branch nick: bzr.log-refactor
    timestamp: Thu 2009-01-22 15:36:26 +1000
    message:
      merge bzr.dotted-revno-to-revision-id branch again
    added:
      bzrlib/tests/branch_implementations/test_revision_id_to_dotted_revno.py test_revision_id_to_-20090122052032-g3czslif6sdqfkh3-1
    ------------------------------------------------------------
    revno: 3936.3.23
    revision-id: ian.clatworthy at canonical.com-20090122053159-rmo3qky7n35phy9s
    parent: ian.clatworthy at canonical.com-20090118172010-j11wzy7adzqi79fr
    parent: ian.clatworthy at canonical.com-20090122051710-gqka9rzkxc93p20m
    committer: Ian Clatworthy <ian.clatworthy at canonical.com>
    branch nick: bzr.log-refactor
    timestamp: Thu 2009-01-22 15:31:59 +1000
    message:
      merge bzr.dotted-revno-to-revision-id branch
    added:
      bzrlib/tests/branch_implementations/test_dotted_revno_to_revision_id.py test_dotted_revno_to-20090121014844-6x7d9jtri5sspg1o-1
    modified:
      NEWS                           NEWS-20050323055033-4e00b5db738777ff
      bzrlib/branch.py               branch.py-20050309040759-e4baf4e0d046576e
      bzrlib/bzrdir.py               bzrdir.py-20060131065624-156dfea39c4387cb
      bzrlib/help_topics/__init__.py help_topics.py-20060920210027-rnim90q9e0bwxvy4-1
      bzrlib/help_topics/en/rules.txt rules.txt-20080516063844-ghr5l6pvvrhiycun-1
      bzrlib/log.py                  log.py-20050505065812-c40ce11702fe5fb1
      bzrlib/progress.py             progress.py-20050610070202-df9faaab791964c0
      bzrlib/remote.py               remote.py-20060720103555-yeeg2x51vn0rbtdp-1
      bzrlib/revisionspec.py         revisionspec.py-20050907152633-17567659fd5c0ddb
      bzrlib/rules.py                properties.py-20080506032617-9k06uqalkf09ck0z-1
      bzrlib/tests/blackbox/test_upgrade.py test_upgrade.py-20060120060132-b41e5ed2f886ad28
      bzrlib/tests/branch_implementations/__init__.py __init__.py-20060123013057-b12a52c3f361daf4
      bzrlib/tests/bzrdir_implementations/test_bzrdir.py test_bzrdir.py-20060131065642-0ebeca5e30e30866
      bzrlib/tests/test_bzrdir.py    test_bzrdir.py-20060131065654-deba40eef51cf220
      bzrlib/tests/test_log.py       testlog.py-20050728115707-1a514809d7d49309
      bzrlib/tests/test_rules.py     test_properties.py-20080506033501-3p9kmuob25dho8xl-1
      bzrlib/transport/sftp.py       sftp.py-20051019050329-ab48ce71b7e32dfe
      bzrlib/upgrade.py              history2weaves.py-20050818063535-e7d319791c19a8b2
    ------------------------------------------------------------
    revno: 3936.3.22
    revision-id: ian.clatworthy at canonical.com-20090118172010-j11wzy7adzqi79fr
    parent: ian.clatworthy at canonical.com-20090118164531-wxgk6ac3ejrtychl
    committer: Ian Clatworthy <ian.clatworthy at canonical.com>
    branch nick: bzr.log-refactor
    timestamp: Mon 2009-01-19 03:20:10 +1000
    message:
      make incremental file logging fast again
    modified:
      bzrlib/log.py                  log.py-20050505065812-c40ce11702fe5fb1
    ------------------------------------------------------------
    revno: 3936.3.21
    revision-id: ian.clatworthy at canonical.com-20090118164531-wxgk6ac3ejrtychl
    parent: ian.clatworthy at canonical.com-20090116154148-hvqeiv3r8sp3ncis
    committer: Ian Clatworthy <ian.clatworthy at canonical.com>
    branch nick: bzr.log-refactor
    timestamp: Mon 2009-01-19 02:45:31 +1000
    message:
      make log -rX.. as fast as log -rX..-1
    modified:
      bzrlib/builtins.py             builtins.py-20050830033751-fc01482b9ca23183
    ------------------------------------------------------------
    revno: 3936.3.20
    revision-id: ian.clatworthy at canonical.com-20090116154148-hvqeiv3r8sp3ncis
    parent: ian.clatworthy at canonical.com-20090116144304-tg4l4sl49ahqxpze
    committer: Ian Clatworthy <ian.clatworthy at canonical.com>
    branch nick: bzr.log-refactor
    timestamp: Sat 2009-01-17 01:41:48 +1000
    message:
      must use per-file-graph for full history still
    modified:
      bzrlib/log.py                  log.py-20050505065812-c40ce11702fe5fb1
    ------------------------------------------------------------
    revno: 3936.3.19
    revision-id: ian.clatworthy at canonical.com-20090116144304-tg4l4sl49ahqxpze
    parent: ian.clatworthy at canonical.com-20090116140347-aqboeyop0g19p3u7
    committer: Ian Clatworthy <ian.clatworthy at canonical.com>
    branch nick: bzr.log-refactor
    timestamp: Sat 2009-01-17 00:43:04 +1000
    message:
      NEW item
    modified:
      NEWS                           NEWS-20050323055033-4e00b5db738777ff
    ------------------------------------------------------------
    revno: 3936.3.18
    revision-id: ian.clatworthy at canonical.com-20090116140347-aqboeyop0g19p3u7
    parent: ian.clatworthy at canonical.com-20090116133219-m7j3rcd68v5c4x3h
    committer: Ian Clatworthy <ian.clatworthy at canonical.com>
    branch nick: bzr.log-refactor
    timestamp: Sat 2009-01-17 00:03:47 +1000
    message:
      faster incremental results for FILE logging
    modified:
      bzrlib/log.py                  log.py-20050505065812-c40ce11702fe5fb1
    ------------------------------------------------------------
    revno: 3936.3.17
    revision-id: ian.clatworthy at canonical.com-20090116133219-m7j3rcd68v5c4x3h
    parent: ian.clatworthy at canonical.com-20090116131826-5lw7zzbzfiq7n4vd
    committer: Ian Clatworthy <ian.clatworthy at canonical.com>
    branch nick: bzr.log-refactor
    timestamp: Fri 2009-01-16 23:32:19 +1000
    message:
      delta filtering bug fix
    modified:
      bzrlib/log.py                  log.py-20050505065812-c40ce11702fe5fb1
    ------------------------------------------------------------
    revno: 3936.3.16
    revision-id: ian.clatworthy at canonical.com-20090116131826-5lw7zzbzfiq7n4vd
    parent: ian.clatworthy at canonical.com-20090116114255-qdbi7gtarzlirbcu
    committer: Ian Clatworthy <ian.clatworthy at canonical.com>
    branch nick: bzr.log-refactor
    timestamp: Fri 2009-01-16 23:18:26 +1000
    message:
      use deltas to match files in selected use cases
    modified:
      bzrlib/log.py                  log.py-20050505065812-c40ce11702fe5fb1
    ------------------------------------------------------------
    revno: 3936.3.15
    revision-id: ian.clatworthy at canonical.com-20090116114255-qdbi7gtarzlirbcu
    parent: ian.clatworthy at canonical.com-20090116110851-k7vhta4o4n1qub82
    committer: Ian Clatworthy <ian.clatworthy at canonical.com>
    branch nick: bzr.log-refactor
    timestamp: Fri 2009-01-16 21:42:55 +1000
    message:
      faster long log for a limited range with no merges
    modified:
      bzrlib/log.py                  log.py-20050505065812-c40ce11702fe5fb1
    ------------------------------------------------------------
    revno: 3936.3.14
    revision-id: ian.clatworthy at canonical.com-20090116110851-k7vhta4o4n1qub82
    parent: ian.clatworthy at canonical.com-20090116103954-zuc1mnp2wytgdwwg
    committer: Ian Clatworthy <ian.clatworthy at canonical.com>
    branch nick: bzr.log-refactor
    timestamp: Fri 2009-01-16 21:08:51 +1000
    message:
      bug fix
    modified:
      bzrlib/log.py                  log.py-20050505065812-c40ce11702fe5fb1
    ------------------------------------------------------------
    revno: 3936.3.13
    revision-id: ian.clatworthy at canonical.com-20090116103954-zuc1mnp2wytgdwwg
    parent: ian.clatworthy at canonical.com-20090116082834-07gc3o54z09xos4w
    committer: Ian Clatworthy <ian.clatworthy at canonical.com>
    branch nick: bzr.log-refactor
    timestamp: Fri 2009-01-16 20:39:54 +1000
    message:
      feedback from jameinel
    modified:
      bzrlib/branch.py               branch.py-20050309040759-e4baf4e0d046576e
      bzrlib/log.py                  log.py-20050505065812-c40ce11702fe5fb1
    ------------------------------------------------------------
    revno: 3936.3.12
    revision-id: ian.clatworthy at canonical.com-20090116082834-07gc3o54z09xos4w
    parent: ian.clatworthy at canonical.com-20090116052709-crdqz9q07ens4vc0
    committer: Ian Clatworthy <ian.clatworthy at canonical.com>
    branch nick: bzr.log-refactor
    timestamp: Fri 2009-01-16 18:28:34 +1000
    message:
      more single revision & sequence tuning
    modified:
      bzrlib/log.py                  log.py-20050505065812-c40ce11702fe5fb1
      bzrlib/tests/blackbox/test_log.py test_log.py-20060112090212-78f6ea560c868e24
    ------------------------------------------------------------
    revno: 3936.3.11
    revision-id: ian.clatworthy at canonical.com-20090116052709-crdqz9q07ens4vc0
    parent: ian.clatworthy at canonical.com-20090114071752-q4t19py601nrdrg4
    parent: pqm at pqm.ubuntu.com-20090115233242-4bxyn4zcj2a0ksfk
    committer: Ian Clatworthy <ian.clatworthy at canonical.com>
    branch nick: bzr.log-refactor
    timestamp: Fri 2009-01-16 15:27:09 +1000
    message:
      merge bzr.dev r3943
    added:
      bzrlib/tests/blackbox/test_filesystem_cicp.py test_filesystem_cicp-20081028010456-vclkg401m81keaxc-1
      doc/developers/case-insensitive-file-systems.txt caseinsensitivefiles-20081117224243-p84xpmqnsa1p8k91-1
      doc/news-template.txt          newstemplate.txt-20090113030949-kn6dn0xcj1rd6vmn-1
    modified:
      NEWS                           NEWS-20050323055033-4e00b5db738777ff
      bzr                            bzr.py-20050313053754-5485f144c7006fa6
      bzrlib/__init__.py             __init__.py-20050309040759-33e65acf91bbcd5d
      bzrlib/builtins.py             builtins.py-20050830033751-fc01482b9ca23183
      bzrlib/commands.py             bzr.py-20050309040720-d10f4714595cf8c3
      bzrlib/delta.py                delta.py-20050729221636-54cf14ef94783d0a
      bzrlib/errors.py               errors.py-20050309040759-20512168c4e14fbd
      bzrlib/log.py                  log.py-20050505065812-c40ce11702fe5fb1
      bzrlib/merge.py                merge.py-20050513021216-953b65a438527106
      bzrlib/mutabletree.py          mutabletree.py-20060906023413-4wlkalbdpsxi2r4y-2
      bzrlib/osutils.py              osutils.py-20050309040759-eeaff12fbf77ac86
      bzrlib/progress.py             progress.py-20050610070202-df9faaab791964c0
      bzrlib/status.py               status.py-20050505062338-431bfa63ec9b19e6
      bzrlib/tests/__init__.py       selftest.py-20050531073622-8d0e3c8845c97a64
      bzrlib/tests/blackbox/__init__.py __init__.py-20051128053524-eba30d8255e08dc3
      bzrlib/tests/blackbox/test_init.py test_init.py-20060309032856-a292116204d86eb7
      bzrlib/tests/blackbox/test_log.py test_log.py-20060112090212-78f6ea560c868e24
      bzrlib/tests/blackbox/test_status.py teststatus.py-20050712014354-508855eb9f29f7dc
      bzrlib/tests/blackbox/test_upgrade.py test_upgrade.py-20060120060132-b41e5ed2f886ad28
      bzrlib/tests/test_delta.py     test_delta.py-20070110134455-sqpd1y7mbjndelxf-1
      bzrlib/tests/test_osutils.py   test_osutils.py-20051201224856-e48ee24c12182989
      bzrlib/tests/test_sftp_transport.py testsftp.py-20051027032739-247570325fec7e7e
      bzrlib/tests/test_status.py    test_status.py-20060516190614-fbf6432e4a6e8aa5
      bzrlib/tests/test_transform.py test_transaction.py-20060105172520-b3ffb3946550e6c4
      bzrlib/tests/test_ui.py        test_ui.py-20051130162854-458e667a7414af09
      bzrlib/tests/tree_implementations/test_inv.py test_inv.py-20070312023226-0cdvk5uwhutis9vg-1
      bzrlib/transport/__init__.py   transport.py-20050711165921-4978aa7ce1285ad5
      bzrlib/transport/sftp.py       sftp.py-20051019050329-ab48ce71b7e32dfe
      bzrlib/tree.py                 tree.py-20050309040759-9d5f2496be663e77
      bzrlib/ui/__init__.py          ui.py-20050824083933-8cf663c763ba53a9
      bzrlib/ui/text.py              text.py-20051130153916-2e438cffc8afc478
      doc/developers/index.txt       index.txt-20070508041241-qznziunkg0nffhiw-1
      setup.py                       setup.py-20050314065409-02f8a0a6e3f9bc70
      tools/win32/bzr.iss.cog        bzr.iss.cog-20060622100836-b3yup582rt3y0nvm-5
    ------------------------------------------------------------
    revno: 3936.3.10
    revision-id: ian.clatworthy at canonical.com-20090114071752-q4t19py601nrdrg4
    parent: ian.clatworthy at canonical.com-20090114063539-t4rtvt877xpaqwp3
    committer: Ian Clatworthy <ian.clatworthy at canonical.com>
    branch nick: bzr.log-refactor
    timestamp: Wed 2009-01-14 17:17:52 +1000
    message:
      more single revision clean-up
    modified:
      bzrlib/branch.py               branch.py-20050309040759-e4baf4e0d046576e
      bzrlib/log.py                  log.py-20050505065812-c40ce11702fe5fb1
    ------------------------------------------------------------
    revno: 3936.3.9
    revision-id: ian.clatworthy at canonical.com-20090114063539-t4rtvt877xpaqwp3
    parent: ian.clatworthy at canonical.com-20090114054418-zpoypade4ram52t8
    committer: Ian Clatworthy <ian.clatworthy at canonical.com>
    branch nick: bzr.log-refactor
    timestamp: Wed 2009-01-14 16:35:39 +1000
    message:
      first cut at single revision clean-up
    modified:
      bzrlib/log.py                  log.py-20050505065812-c40ce11702fe5fb1
    ------------------------------------------------------------
    revno: 3936.3.8
    revision-id: ian.clatworthy at canonical.com-20090114054418-zpoypade4ram52t8
    parent: ian.clatworthy at canonical.com-20090114053534-oms12p9qtm3uc12y
    committer: Ian Clatworthy <ian.clatworthy at canonical.com>
    branch nick: bzr.log-refactor
    timestamp: Wed 2009-01-14 15:44:18 +1000
    message:
      back-out --strict
    modified:
      bzrlib/builtins.py             builtins.py-20050830033751-fc01482b9ca23183
      bzrlib/log.py                  log.py-20050505065812-c40ce11702fe5fb1
      bzrlib/tests/blackbox/test_log.py test_log.py-20060112090212-78f6ea560c868e24
      bzrlib/tests/test_log.py       testlog.py-20050728115707-1a514809d7d49309
    ------------------------------------------------------------
    revno: 3936.3.7
    revision-id: ian.clatworthy at canonical.com-20090114053534-oms12p9qtm3uc12y
    parent: ian.clatworthy at canonical.com-20090113184638-8n9nk7ir9cta514h
    committer: Ian Clatworthy <ian.clatworthy at canonical.com>
    branch nick: bzr.log-refactor
    timestamp: Wed 2009-01-14 15:35:34 +1000
    message:
      move fileid filtering up a layer
    modified:
      bzrlib/log.py                  log.py-20050505065812-c40ce11702fe5fb1
      bzrlib/tests/test_log.py       testlog.py-20050728115707-1a514809d7d49309
    ------------------------------------------------------------
    revno: 3936.3.6
    revision-id: ian.clatworthy at canonical.com-20090113184638-8n9nk7ir9cta514h
    parent: ian.clatworthy at canonical.com-20090113150315-qs02m5yy497ct3bt
    committer: Ian Clatworthy <ian.clatworthy at canonical.com>
    branch nick: bzr.log-refactor
    timestamp: Wed 2009-01-14 04:46:38 +1000
    message:
      add & use _NonMainlineRevisionLimit exception
    modified:
      bzrlib/log.py                  log.py-20050505065812-c40ce11702fe5fb1
    ------------------------------------------------------------
    revno: 3936.3.5
    revision-id: ian.clatworthy at canonical.com-20090113150315-qs02m5yy497ct3bt
    parent: ian.clatworthy at canonical.com-20090113093726-o10gqs4rqrh73ym6
    committer: Ian Clatworthy <ian.clatworthy at canonical.com>
    branch nick: bzr.log-refactor
    timestamp: Wed 2009-01-14 01:03:15 +1000
    message:
      get single_merge_revision tests passing again
    modified:
      bzrlib/log.py                  log.py-20050505065812-c40ce11702fe5fb1
    ------------------------------------------------------------
    revno: 3936.3.4
    revision-id: ian.clatworthy at canonical.com-20090113093726-o10gqs4rqrh73ym6
    parent: ian.clatworthy at canonical.com-20090113092406-mp38d8jv2vdyg1vm
    committer: Ian Clatworthy <ian.clatworthy at canonical.com>
    branch nick: bzr.log-refactor
    timestamp: Tue 2009-01-13 19:37:26 +1000
    message:
      fix empty_branch log
    modified:
      bzrlib/log.py                  log.py-20050505065812-c40ce11702fe5fb1
    ------------------------------------------------------------
    revno: 3936.3.3
    revision-id: ian.clatworthy at canonical.com-20090113092406-mp38d8jv2vdyg1vm
    parent: ian.clatworthy at canonical.com-20090113055725-l5k8cjxdbwlp0b0y
    committer: Ian Clatworthy <ian.clatworthy at canonical.com>
    branch nick: bzr.log-refactor
    timestamp: Tue 2009-01-13 19:24:06 +1000
    message:
      add --strict and more refactoring
    modified:
      bzrlib/builtins.py             builtins.py-20050830033751-fc01482b9ca23183
      bzrlib/log.py                  log.py-20050505065812-c40ce11702fe5fb1
      bzrlib/tests/blackbox/test_log.py test_log.py-20060112090212-78f6ea560c868e24
      bzrlib/tests/test_log.py       testlog.py-20050728115707-1a514809d7d49309
    ------------------------------------------------------------
    revno: 3936.3.2
    revision-id: ian.clatworthy at canonical.com-20090113055725-l5k8cjxdbwlp0b0y
    parent: ian.clatworthy at canonical.com-20090113033933-4jqnpz7igopdonzo
    committer: Ian Clatworthy <ian.clatworthy at canonical.com>
    branch nick: bzr.log-refactor
    timestamp: Tue 2009-01-13 15:57:25 +1000
    message:
      minor cleanups
    modified:
      bzrlib/log.py                  log.py-20050505065812-c40ce11702fe5fb1
    ------------------------------------------------------------
    revno: 3936.3.1
    revision-id: ian.clatworthy at canonical.com-20090113033933-4jqnpz7igopdonzo
    parent: pqm at pqm.ubuntu.com-20090112185737-d6kwagahecadwfce
    committer: Ian Clatworthy <ian.clatworthy at canonical.com>
    branch nick: bzr.log-refactor
    timestamp: Tue 2009-01-13 13:39:33 +1000
    message:
      refactor _show_log
    modified:
      bzrlib/log.py                  log.py-20050505065812-c40ce11702fe5fb1
=== modified file 'NEWS'
--- a/NEWS	2009-01-29 16:46:44 +0000
+++ b/NEWS	2009-01-31 04:17:43 +0000
@@ -46,6 +46,10 @@
     * ``bzr init`` will now print a little less verbose output.
       (Marius Kruger)
 
+    * ``bzr log`` is now much faster in many use cases, particularly
+      at incrementally displaying results and filtering by a
+      revision range. (Ian Clatworthy)
+
     * ``bzr log --short`` and ``bzr log --line`` now show tags, if any,
       for each revision. The tags are shown comma-separated inside
       ``{}``. For short format, the tags appear at the end of line

=== modified file 'bzrlib/builtins.py'
--- a/bzrlib/builtins.py	2009-01-29 07:57:43 +0000
+++ b/bzrlib/builtins.py	2009-02-02 05:43:13 +0000
@@ -49,7 +49,7 @@
     )
 from bzrlib.branch import Branch
 from bzrlib.conflicts import ConflictList
-from bzrlib.revisionspec import RevisionSpec
+from bzrlib.revisionspec import RevisionSpec, RevisionInfo
 from bzrlib.smtp_connection import SMTPConnection
 from bzrlib.workingtree import WorkingTree
 """)
@@ -1972,16 +1972,23 @@
     elif len(revisionspec_list) == 1:
         rev1 = rev2 = revisionspec_list[0].in_history(branch)
     elif len(revisionspec_list) == 2:
-        if revisionspec_list[1].get_branch() != revisionspec_list[0
-                ].get_branch():
+        start_spec = revisionspec_list[0]
+        end_spec = revisionspec_list[1]
+        if end_spec.get_branch() != start_spec.get_branch():
             # b is taken from revision[0].get_branch(), and
             # show_log will use its revision_history. Having
             # different branches will lead to weird behaviors.
             raise errors.BzrCommandError(
                 "bzr %s doesn't accept two revisions in different"
                 " branches." % command_name)
-        rev1 = revisionspec_list[0].in_history(branch)
-        rev2 = revisionspec_list[1].in_history(branch)
+        rev1 = start_spec.in_history(branch)
+        # Avoid loading all of history when we know a missing
+        # end of range means the last revision ...
+        if end_spec.spec is None:
+            last_revno, last_revision_id = branch.last_revision_info()
+            rev2 = RevisionInfo(branch, last_revno, last_revision_id)
+        else:
+            rev2 = end_spec.in_history(branch)
     else:
         raise errors.BzrCommandError(
             'bzr %s --revision takes one or two values.' % command_name)

=== modified file 'bzrlib/log.py'
--- a/bzrlib/log.py	2009-01-29 12:24:29 +0000
+++ b/bzrlib/log.py	2009-02-02 08:28:54 +0000
@@ -52,6 +52,7 @@
 import codecs
 from cStringIO import StringIO
 from itertools import (
+    chain,
     izip,
     )
 import re
@@ -199,34 +200,31 @@
     """Worker function for show_log - see show_log."""
     if not isinstance(lf, LogFormatter):
         warn("not a LogFormatter instance: %r" % lf)
-
     if specific_fileid:
         trace.mutter('get log for file_id %r', specific_fileid)
+
+    # Consult the LogFormatter about what it needs and can handle
     levels_to_display = lf.get_levels()
     generate_merge_revisions = levels_to_display != 1
     allow_single_merge_revision = True
     if not getattr(lf, 'supports_merge_revisions', False):
         allow_single_merge_revision = getattr(lf,
             'supports_single_merge_revision', False)
-    view_revisions = calculate_view_revisions(branch, start_revision,
-                                              end_revision, direction,
-                                              specific_fileid,
-                                              generate_merge_revisions,
-                                              allow_single_merge_revision)
-    rev_tag_dict = {}
     generate_tags = getattr(lf, 'supports_tags', False)
-    if generate_tags:
-        if branch.supports_tags():
-            rev_tag_dict = branch.tags.get_reverse_tag_dict()
-
+    if generate_tags and branch.supports_tags():
+        rev_tag_dict = branch.tags.get_reverse_tag_dict()
+    else:
+        rev_tag_dict = {}
     generate_delta = verbose and getattr(lf, 'supports_delta', False)
     generate_diff = show_diff and getattr(lf, 'supports_diff', False)
 
-    # now we just print all the revisions
+    # Find and print the interesting revisions
     repo = branch.repository
     log_count = 0
-    revision_iterator = make_log_rev_iterator(branch, view_revisions,
-        generate_delta, search)
+    revision_iterator = _create_log_revision_iterator(branch,
+        start_revision, end_revision, direction, specific_fileid, search,
+        generate_merge_revisions, allow_single_merge_revision,
+        generate_delta, limited_output=limit > 0)
     for revs in revision_iterator:
         for (rev_id, revno, merge_depth), rev, delta in revs:
             # Note: 0 levels means show everything; merge_depth counts from 0
@@ -262,48 +260,275 @@
     return s.getvalue()
 
 
-def calculate_view_revisions(branch, start_revision, end_revision, direction,
-                             specific_fileid, generate_merge_revisions,
-                             allow_single_merge_revision):
-    if (    not generate_merge_revisions
-        and start_revision is end_revision is None
-        and direction == 'reverse'
-        and specific_fileid is None):
-        return _linear_view_revisions(branch)
-
-    mainline_revs, rev_nos, start_rev_id, end_rev_id = _get_mainline_revs(
-        branch, start_revision, end_revision)
-    if not mainline_revs:
+class _StartNotLinearAncestor(Exception):
+    """Raised when a start revision is not found walking left-hand history."""
+
+
+def _create_log_revision_iterator(branch, start_revision, end_revision,
+    direction, specific_fileid, search, generate_merge_revisions,
+    allow_single_merge_revision, generate_delta, limited_output=False):
+    """Create a revision iterator for log.
+
+    :param branch: The branch being logged.
+    :param start_revision: If not None, only show revisions >= start_revision
+    :param end_revision: If not None, only show revisions <= end_revision
+    :param direction: 'reverse' (default) is latest to earliest; 'forward' is
+        earliest to latest.
+    :param specific_fileid: If not None, list only the commits affecting the
+        specified file.
+    :param search: If not None, only show revisions with matching commit
+        messages.
+    :param generate_merge_revisions: If False, show only mainline revisions.
+    :param allow_single_merge_revision: If True, logging of a single
+        revision off the mainline is to be allowed
+    :param generate_delta: Whether to generate a delta for each revision.
+    :param limited_output: if True, the user only wants a limited result
+
+    :return: An iterator over lists of ((rev_id, revno, merge_depth), rev,
+        delta).
+    """
+    start_rev_id, end_rev_id = _get_revision_limits(branch, start_revision,
+        end_revision)
+
+    # Decide how file-ids are matched: delta-filtering vs per-file graph.
+    # Delta filtering allows revisions to be displayed incrementally
+    # though the total time is much slower for huge repositories: log -v
+    # is the *lower* performance bound. At least until the split
+    # inventory format arrives, per-file-graph needs to remain the
+    # default except in verbose mode. Delta filtering should give more
+    # accurate results (e.g. inclusion of FILE deletions) so arguably
+    # it should always be used in the future.
+    use_deltas_for_matching = specific_fileid and generate_delta
+    delayed_graph_generation = not specific_fileid and (
+            start_rev_id or end_rev_id or limited_output)
+    generate_merges = generate_merge_revisions or (specific_fileid and
+        not use_deltas_for_matching)
+    view_revisions = _calc_view_revisions(branch, start_rev_id, end_rev_id,
+        direction, generate_merges, allow_single_merge_revision,
+        delayed_graph_generation=delayed_graph_generation)
+    search_deltas_for_fileids = None
+    if use_deltas_for_matching:
+        search_deltas_for_fileids = set([specific_fileid])
+    elif specific_fileid:
+        if not isinstance(view_revisions, list):
+            view_revisions = list(view_revisions)
+        view_revisions = _filter_revisions_touching_file_id(branch,
+            specific_fileid, view_revisions,
+            include_merges=generate_merge_revisions)
+    return make_log_rev_iterator(branch, view_revisions, generate_delta,
+        search, file_ids=search_deltas_for_fileids, direction=direction)
+
+
+def _calc_view_revisions(branch, start_rev_id, end_rev_id, direction,
+    generate_merge_revisions, allow_single_merge_revision,
+    delayed_graph_generation=False):
+    """Calculate the revisions to view.
+
+    :return: An iterator of (revision_id, dotted_revno, merge_depth) tuples OR
+             a list of the same tuples.
+    """
+    br_revno, br_rev_id = branch.last_revision_info()
+    if br_revno == 0:
         return []
 
-    generate_single_revision = False
-    if ((not generate_merge_revisions)
-        and ((start_rev_id and (start_rev_id not in rev_nos))
-            or (end_rev_id and (end_rev_id not in rev_nos)))):
-        generate_single_revision = ((start_rev_id == end_rev_id)
-            and allow_single_merge_revision)
-        if not generate_single_revision:
-            raise errors.BzrCommandError('Selected log formatter only supports'
-                ' mainline revisions.')
-        generate_merge_revisions = generate_single_revision
-    include_merges = generate_merge_revisions or specific_fileid
-    view_revs_iter = get_view_revisions(mainline_revs, rev_nos, branch,
-                          direction, include_merges=include_merges)
-
+    # If a single revision is requested, check we can handle it
+    generate_single_revision = (end_rev_id and start_rev_id == end_rev_id and
+        (not generate_merge_revisions or not _has_merges(branch, end_rev_id)))
+    if generate_single_revision:
+        if end_rev_id == br_rev_id:
+            # It's the tip
+            return [(br_rev_id, br_revno, 0)]
+        else:
+            revno = branch.revision_id_to_dotted_revno(end_rev_id)
+            if len(revno) > 1 and not allow_single_merge_revision:
+                # It's a merge revision and the log formatter is
+                # completely brain dead. This "feature" of allowing
+                # log formatters incapable of displaying dotted revnos
+                # ought to be deprecated IMNSHO. IGC 20091022
+                raise errors.BzrCommandError('Selected log formatter only'
+                    ' supports mainline revisions.')
+            revno_str = '.'.join(str(n) for n in revno)
+            return [(end_rev_id, revno_str, 0)]
+
+    # If we only want to see linear revisions, we can iterate ...
+    if not generate_merge_revisions:
+        result = _linear_view_revisions(branch, start_rev_id, end_rev_id)
+        # If a start limit was given and it's not obviously an
+        # ancestor of the end limit, check it before outputting anything
+        if direction == 'forward' or (start_rev_id
+            and not _is_obvious_ancestor(branch, start_rev_id, end_rev_id)):
+            try:
+                result = list(result)
+            except _StartNotLinearAncestor:
+                raise errors.BzrCommandError('Start revision not found in'
+                    ' left-hand history of end revision.')
+        if direction == 'forward':
+            result = reversed(list(result))
+        return result
+
+    # On large trees, generating the merge graph can take 30-60 seconds
+    # so we delay doing it until a merge is detected, incrementally
+    # returning initial (non-merge) revisions while we can.
+    initial_revisions = []
+    if delayed_graph_generation:
+        try:
+            for rev_id, revno, depth in \
+                _linear_view_revisions(branch, start_rev_id, end_rev_id):
+                if _has_merges(branch, rev_id):
+                    end_rev_id = rev_id
+                    break
+                else:
+                    initial_revisions.append((rev_id, revno, depth))
+            else:
+                # No merged revisions found
+                if direction == 'reverse':
+                    return initial_revisions
+                elif direction == 'forward':
+                    return reversed(initial_revisions)
+                else:
+                    raise ValueError('invalid direction %r' % direction)
+        except _StartNotLinearAncestor:
+            # A merge was never detected so the lower revision limit can't
+            # be nested down somewhere
+            raise errors.BzrCommandError('Start revision not found in'
+                ' history of end revision.')
+
+    # A log including nested merges is required. If the direction is reverse,
+    # we rebase the initial merge depths so that the development line is
+    # shown naturally, i.e. just like it is for linear logging. We can easily
+    # make forward the exact opposite display, but showing the merge revisions
+    # indented at the end seems slightly nicer in that case.
+    view_revisions = chain(iter(initial_revisions),
+        _graph_view_revisions(branch, start_rev_id, end_rev_id,
+        rebase_initial_depths=direction == 'reverse'))
     if direction == 'reverse':
-        start_rev_id, end_rev_id = end_rev_id, start_rev_id
-    view_revisions = _filter_revision_range(list(view_revs_iter),
-                                            start_rev_id,
-                                            end_rev_id)
-    if view_revisions and generate_single_revision:
-        view_revisions = view_revisions[0:1]
+        return view_revisions
+    elif direction == 'forward':
+        # Forward means oldest first, adjusting for depth.
+        view_revisions = reverse_by_depth(list(view_revisions))
+        return _rebase_merge_depth(view_revisions)
+    else:
+        raise ValueError('invalid direction %r' % direction)
+
+
+def _has_merges(branch, rev_id):
+    """Does a revision have multiple parents or not?"""
+    parents = branch.repository.get_parent_map([rev_id]).get(rev_id, [])
+    return len(parents) > 1
+
+
+def _is_obvious_ancestor(branch, start_rev_id, end_rev_id):
+    """Is start_rev_id an obvious ancestor of end_rev_id?"""
+    if start_rev_id and end_rev_id:
+        start_dotted = branch.revision_id_to_dotted_revno(start_rev_id)
+        end_dotted = branch.revision_id_to_dotted_revno(end_rev_id)
+        if len(start_dotted) == 1 and len(end_dotted) == 1:
+            # both on mainline
+            return start_dotted[0] <= end_dotted[0]
+        elif (len(start_dotted) == 3 and len(end_dotted) == 3 and
+            start_dotted[0:1] == end_dotted[0:1]):
+            # both on same development line
+            return start_dotted[2] <= end_dotted[2]
+        else:
+            # not obvious
+            return False
+    return True
+
+
+def _linear_view_revisions(branch, start_rev_id, end_rev_id):
+    """Calculate a sequence of revisions to view, newest to oldest.
+
+    :param start_rev_id: the lower revision-id
+    :param end_rev_id: the upper revision-id
+    :return: An iterator of (revision_id, dotted_revno, merge_depth) tuples.
+    :raises _StartNotLinearAncestor: if a start_rev_id is specified but
+      is not found walking the left-hand history
+    """
+    br_revno, br_rev_id = branch.last_revision_info()
+    repo = branch.repository
+    if start_rev_id is None and end_rev_id is None:
+        cur_revno = br_revno
+        for revision_id in repo.iter_reverse_revision_history(br_rev_id):
+            yield revision_id, str(cur_revno), 0
+            cur_revno -= 1
+    else:
+        if end_rev_id is None:
+            end_rev_id = br_rev_id
+        found_start = start_rev_id is None
+        for revision_id in repo.iter_reverse_revision_history(end_rev_id):
+            revno = branch.revision_id_to_dotted_revno(revision_id)
+            revno_str = '.'.join(str(n) for n in revno)
+            if not found_start and revision_id == start_rev_id:
+                yield revision_id, revno_str, 0
+                found_start = True
+                break
+            else:
+                yield revision_id, revno_str, 0
+        else:
+            if not found_start:
+                raise _StartNotLinearAncestor()
+
+
+def _graph_view_revisions(branch, start_rev_id, end_rev_id,
+    rebase_initial_depths=True):
+    """Calculate revisions to view including merges, newest to oldest.
+
+    :param branch: the branch
+    :param start_rev_id: the lower revision-id
+    :param end_rev_id: the upper revision-id
+    :param rebase_initial_depth: should depths be rebased until a mainline
+      revision is found?
+    :return: An iterator of (revision_id, dotted_revno, merge_depth) tuples.
+    """
+    view_revisions = branch.iter_merge_sorted_revisions(
+        start_revision_id=end_rev_id, stop_revision_id=start_rev_id,
+        stop_rule="with-merges")
+    if not rebase_initial_depths:
+        for (rev_id, merge_depth, revno, end_of_merge
+             ) in view_revisions:
+            yield rev_id, '.'.join(map(str, revno)), merge_depth
+    else:
+        # We're following a development line starting at a merged revision.
+        # We need to adjust depths down by the initial depth until we find
+        # a depth less than it. Then we use that depth as the adjustment.
+        # If and when we reach the mainline, depth adjustment ends.
+        depth_adjustment = None
+        for (rev_id, merge_depth, revno, end_of_merge
+             ) in view_revisions:
+            if depth_adjustment is None:
+                depth_adjustment = merge_depth
+            if depth_adjustment:
+                if merge_depth < depth_adjustment:
+                    depth_adjustment = merge_depth
+                merge_depth -= depth_adjustment
+            yield rev_id, '.'.join(map(str, revno)), merge_depth
+
+
+def calculate_view_revisions(branch, start_revision, end_revision, direction,
+        specific_fileid, generate_merge_revisions, allow_single_merge_revision):
+    """Calculate the revisions to view.
+
+    :return: An iterator of (revision_id, dotted_revno, merge_depth) tuples OR
+             a list of the same tuples.
+    """
+    # This method is no longer called by the main code path.
+    # It is retained for API compatibility and may be deprecated
+    # soon. IGC 20090116
+    start_rev_id, end_rev_id = _get_revision_limits(branch, start_revision,
+        end_revision)
+    view_revisions = list(_calc_view_revisions(branch, start_rev_id, end_rev_id,
+        direction, generate_merge_revisions or specific_fileid,
+        allow_single_merge_revision))
     if specific_fileid:
         view_revisions = _filter_revisions_touching_file_id(branch,
             specific_fileid, view_revisions,
             include_merges=generate_merge_revisions)
-
-    # rebase merge_depth - unless there are no revisions or 
-    # either the first or last revision have merge_depth = 0.
+    return _rebase_merge_depth(view_revisions)
+
+
+def _rebase_merge_depth(view_revisions):
+    """Adjust depths upwards so the top level is 0."""
+    # If either the first or last revision have a merge_depth of 0, we're done
     if view_revisions and view_revisions[0][2] and view_revisions[-1][2]:
         min_depth = min([d for r,n,d in view_revisions])
         if min_depth != 0:
@@ -311,21 +536,17 @@
     return view_revisions
 
 
-def _linear_view_revisions(branch):
-    start_revno, start_revision_id = branch.last_revision_info()
-    repo = branch.repository
-    revision_ids = repo.iter_reverse_revision_history(start_revision_id)
-    for num, revision_id in enumerate(revision_ids):
-        yield revision_id, str(start_revno - num), 0
-
-
-def make_log_rev_iterator(branch, view_revisions, generate_delta, search):
+def make_log_rev_iterator(branch, view_revisions, generate_delta, search,
+        file_ids=None, direction='reverse'):
     """Create a revision iterator for log.
 
     :param branch: The branch being logged.
     :param view_revisions: The revisions being viewed.
     :param generate_delta: Whether to generate a delta for each revision.
     :param search: A user text search string.
+    :param file_ids: If non empty, only revisions matching one or more of
+      the file-ids are to be kept.
+    :param direction: the direction in which view_revisions is sorted
     :return: An iterator over lists of ((rev_id, revno, merge_depth), rev,
         delta).
     """
@@ -342,8 +563,14 @@
                 yield (view, None, None)
         log_rev_iterator = iter([_convert()])
     for adapter in log_adapters:
-        log_rev_iterator = adapter(branch, generate_delta, search,
-            log_rev_iterator)
+        # It would be nicer if log adapters were first class objects
+        # with custom parameters. This will do for now. IGC 20090127
+        if adapter == _make_delta_filter:
+            log_rev_iterator = adapter(branch, generate_delta,
+                search, log_rev_iterator, file_ids, direction)
+        else:
+            log_rev_iterator = adapter(branch, generate_delta,
+                search, log_rev_iterator)
     return log_rev_iterator
 
 
@@ -374,7 +601,8 @@
         yield new_revs
 
 
-def _make_delta_filter(branch, generate_delta, search, log_rev_iterator):
+def _make_delta_filter(branch, generate_delta, search, log_rev_iterator,
+    fileids=None, direction='reverse'):
     """Add revision deltas to a log iterator if needed.
 
     :param branch: The branch being logged.
@@ -382,21 +610,86 @@
     :param search: A user text search string.
     :param log_rev_iterator: An input iterator containing all revisions that
         could be displayed, in lists.
+    :param fileids: If non empty, only revisions matching one or more of
+      the file-ids are to be kept.
+    :param direction: the direction in which view_revisions is sorted
     :return: An iterator over lists of ((rev_id, revno, merge_depth), rev,
         delta).
     """
-    if not generate_delta:
+    if not generate_delta and not fileids:
         return log_rev_iterator
-    return _generate_deltas(branch.repository, log_rev_iterator)
-
-
-def _generate_deltas(repository, log_rev_iterator):
-    """Create deltas for each batch of revisions in log_rev_iterator."""
+    return _generate_deltas(branch.repository, log_rev_iterator,
+        generate_delta, fileids, direction)
+
+
+def _generate_deltas(repository, log_rev_iterator, always_delta, fileids,
+    direction):
+    """Create deltas for each batch of revisions in log_rev_iterator.
+    
+    If we're only generating deltas for the sake of filtering against
+    file-ids, we stop generating deltas once all file-ids reach the
+    appropriate life-cycle point. If we're receiving data newest to
+    oldest, then that life-cycle point is 'add', otherwise it's 'remove'.
+    """
+    check_fileids = fileids is not None and len(fileids) > 0
+    if check_fileids:
+        fileid_set = set(fileids)
+        if direction == 'reverse':
+            stop_on = 'add'
+        else:
+            stop_on = 'remove'
+    else:
+        fileid_set = None
     for revs in log_rev_iterator:
+        # If we were matching against fileids and we've run out,
+        # there's nothing left to do
+        if check_fileids and not fileid_set:
+            return
         revisions = [rev[1] for rev in revs]
         deltas = repository.get_deltas_for_revisions(revisions)
-        revs = [(rev[0], rev[1], delta) for rev, delta in izip(revs, deltas)]
-        yield revs
+        new_revs = []
+        for rev, delta in izip(revs, deltas):
+            if check_fileids:
+                if not _delta_matches_fileids(delta, fileid_set, stop_on):
+                    continue
+                elif not always_delta:
+                    # Delta was created just for matching - ditch it
+                    # Note: It would probably be a better UI to return
+                    # a delta filtered by the file-ids, rather than
+                    # None at all. That functional enhancement can
+                    # come later ...
+                    delta = None
+            new_revs.append((rev[0], rev[1], delta))
+        yield new_revs
+
+
+def _delta_matches_fileids(delta, fileids, stop_on='add'):
+    """Check is a delta matches one of more file-ids.
+    
+    :param fileids: a set of fileids to match against.
+    :param stop_on: either 'add' or 'remove' - take file-ids out of the
+      fileids set once their add or remove entry is detected respectively
+    """
+    if not fileids:
+        return False
+    result = False
+    for item in delta.added:
+        if item[1] in fileids:
+            if stop_on == 'add':
+                fileids.remove(item[1])
+            result = True
+    for item in delta.removed:
+        if item[1] in fileids:
+            if stop_on == 'delete':
+                fileids.remove(item[1])
+            result = True
+    if result:
+        return True
+    for l in (delta.modified, delta.renamed, delta.kind_changed):
+        for item in l:
+            if item[1] in fileids:
+                return True
+    return False
 
 
 def _make_revision_objects(branch, generate_delta, search, log_rev_iterator):
@@ -443,6 +736,56 @@
             num = min(int(num * 1.5), 200)
 
 
+def _get_revision_limits(branch, start_revision, end_revision):
+    """Get and check revision limits.
+
+    :param  branch: The branch containing the revisions. 
+
+    :param  start_revision: The first revision to be logged.
+            For backwards compatibility this may be a mainline integer revno,
+            but for merge revision support a RevisionInfo is expected.
+
+    :param  end_revision: The last revision to be logged.
+            For backwards compatibility this may be a mainline integer revno,
+            but for merge revision support a RevisionInfo is expected.
+
+    :return: (start_rev_id, end_rev_id) tuple.
+    """
+    branch_revno, branch_rev_id = branch.last_revision_info()
+    start_rev_id = None
+    if start_revision is None:
+        start_revno = 1
+    else:
+        if isinstance(start_revision, revisionspec.RevisionInfo):
+            start_rev_id = start_revision.rev_id
+            start_revno = start_revision.revno or 1
+        else:
+            branch.check_real_revno(start_revision)
+            start_revno = start_revision
+            start_rev_id = branch.get_rev_id(start_revno)
+
+    end_rev_id = None
+    if end_revision is None:
+        end_revno = branch_revno
+    else:
+        if isinstance(end_revision, revisionspec.RevisionInfo):
+            end_rev_id = end_revision.rev_id
+            end_revno = end_revision.revno or branch_revno
+        else:
+            branch.check_real_revno(end_revision)
+            end_revno = end_revision
+            end_rev_id = branch.get_rev_id(end_revno)
+
+    if branch_revno != 0:
+        if (start_rev_id == _mod_revision.NULL_REVISION
+            or end_rev_id == _mod_revision.NULL_REVISION):
+            raise errors.BzrCommandError('Logging revision 0 is invalid.')
+        if start_revno > end_revno:
+            raise errors.BzrCommandError("Start revision must be older than "
+                                         "the end revision.")
+    return (start_rev_id, end_rev_id)
+
+
 def _get_mainline_revs(branch, start_revision, end_revision):
     """Get the mainline revisions from the branch.
     
@@ -539,6 +882,8 @@
 
     :return: The filtered view_revisions.
     """
+    # This method is no longer called by the main code path.
+    # It may be removed soon. IGC 20090127
     if start_rev_id or end_rev_id:
         revision_ids = [r for r, n, d in view_revisions]
         if start_rev_id:
@@ -655,6 +1000,9 @@
     :return: an iterator of (revision_id, revno, merge_depth)
     (if there is no revno for a revision, None is supplied)
     """
+    # This method is no longer called by the main code path.
+    # It is retained for API compatibility and may be deprecated
+    # soon. IGC 20090127
     if not include_merges:
         revision_ids = mainline_revs[1:]
         if direction == 'reverse':
@@ -731,7 +1079,7 @@
     def __init__(self, rev=None, revno=None, merge_depth=0, delta=None,
                  tags=None, diff=None):
         self.rev = rev
-        self.revno = revno
+        self.revno = str(revno)
         self.merge_depth = merge_depth
         self.delta = delta
         self.tags = tags
@@ -752,10 +1100,10 @@
     - supports_delta must be True if this log formatter supports delta.
         Otherwise the delta attribute may not be populated.  The 'delta_format'
         attribute describes whether the 'short_status' format (1) or the long
-        one (2) sould be used.
+        one (2) should be used.
  
     - supports_merge_revisions must be True if this log formatter supports 
-        merge revisions.  If not, and if supports_single_merge_revisions is
+        merge revisions.  If not, and if supports_single_merge_revision is
         also not True, then only mainline revisions will be passed to the 
         formatter.
 

=== modified file 'bzrlib/tests/blackbox/test_log.py'
--- a/bzrlib/tests/blackbox/test_log.py	2009-01-29 07:57:43 +0000
+++ b/bzrlib/tests/blackbox/test_log.py	2009-01-31 04:17:43 +0000
@@ -22,7 +22,7 @@
 
 from bzrlib import osutils
 from bzrlib.tests.blackbox import ExternalBase
-from bzrlib.tests import TestCaseInTempDir, TestCaseWithTransport
+from bzrlib.tests import KnownFailure, TestCaseInTempDir, TestCaseWithTransport
 from bzrlib.tests.test_log import (
     normalize_log,
     )
@@ -482,6 +482,10 @@
 """)
 
     def test_merges_nonsupporting_formatter(self):
+        # This "feature" of log formatters is madness. If a log
+        # formatter cannot display a dotted-revno, it ought to ignore it.
+        # Otherwise, a linear sequence is always expected to be handled now.
+        raise KnownFailure('log formatters must support linear sequences now')
         self._prepare()
         err_msg = 'Selected log formatter only supports mainline revisions.'
         # The single revision case is tested in the core tests

=== modified file 'bzrlib/tests/test_log.py'
--- a/bzrlib/tests/test_log.py	2009-01-29 06:18:25 +0000
+++ b/bzrlib/tests/test_log.py	2009-01-31 04:17:43 +0000
@@ -1314,11 +1314,8 @@
         rev_4b = rev_from_rev_id('4b', wt.branch)
         self.assertEqual([('3c', '3', 0), ('3a', '2.1.1', 1)],
                           view_revs(rev_3a, rev_4b, 'f-id', 'reverse'))
-        # Note that the depth is 0 for 3a because depths are normalized, but
-        # there is still a bug somewhere... most probably in
-        # _filter_revision_range and/or get_view_revisions still around a bad
-        # use of reverse_by_depth
-        self.assertEqual([('3a', '2.1.1', 0)],
+        # Note: 3c still appears before 3a here because of depth-based sorting
+        self.assertEqual([('3c', '3', 0), ('3a', '2.1.1', 1)],
                           view_revs(rev_3a, rev_4b, 'f-id', 'forward'))
 
 




More information about the bazaar-commits mailing list