Rev 3135: Accelerate build_tree using similar workingtrees (abentley) in file:///home/pqm/archives/thelove/bzr/%2Btrunk/

Canonical.com Patch Queue Manager pqm at pqm.ubuntu.com
Thu Dec 20 16:16:45 GMT 2007


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

------------------------------------------------------------
revno: 3135
revision-id:pqm at pqm.ubuntu.com-20071220161634-2kcjb650o21ydko4
parent: pqm at pqm.ubuntu.com-20071220142004-tw2cffgn9fxq5ra0
parent: abentley at panoramicfeedback.com-20071220152148-rn32up72gm3gankf
committer: Canonical.com Patch Queue Manager <pqm at pqm.ubuntu.com>
branch nick: +trunk
timestamp: Thu 2007-12-20 16:16:34 +0000
message:
  Accelerate build_tree using similar workingtrees (abentley)
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/tests/blackbox/test_checkout.py test_checkout.py-20060211231752-a5cde67cf70af854
  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_transform.py test_transaction.py-20060105172520-b3ffb3946550e6c4
  bzrlib/tests/test_workingtree.py testworkingtree.py-20051004024258-b88d0fe8f101d468
  bzrlib/transform.py            transform.py-20060105172343-dd99e54394d91687
  bzrlib/workingtree.py          workingtree.py-20050511021032-29b6ec0a681e02e3
  bzrlib/workingtree_4.py        workingtree_4.py-20070208044105-5fgpc5j3ljlh5q6c-1
    ------------------------------------------------------------
    revno: 3123.5.18
    revision-id:abentley at panoramicfeedback.com-20071220152148-rn32up72gm3gankf
    parent: abentley at panoramicfeedback.com-20071220142859-9tea7c02aw13w54k
    parent: pqm at pqm.ubuntu.com-20071220142004-tw2cffgn9fxq5ra0
    committer: Aaron Bentley <abentley at panoramicfeedback.com>
    branch nick: hardlinks
    timestamp: Thu 2007-12-20 10:21:48 -0500
    message:
      Merge bzr.dev
    modified:
      NEWS                           NEWS-20050323055033-4e00b5db738777ff
      bzrlib/_patiencediff_c.c       _patiencediff_c.c-20070721205602-q3imkipwlgagp3cy-1
      bzrlib/builtins.py             builtins.py-20050830033751-fc01482b9ca23183
      bzrlib/bundle/serializer/v4.py v10.py-20070611062757-5ggj7k18s9dej0fr-1
      bzrlib/bzrdir.py               bzrdir.py-20060131065624-156dfea39c4387cb
      bzrlib/diff.py                 diff.py-20050309040759-26944fbbf2ebbf36
      bzrlib/dirstate.py             dirstate.py-20060728012006-d6mvoihjb3je9peu-1
      bzrlib/errors.py               errors.py-20050309040759-20512168c4e14fbd
      bzrlib/graph.py                graph_walker.py-20070525030359-y852guab65d4wtn0-1
      bzrlib/index.py                index.py-20070712131115-lolkarso50vjr64s-1
      bzrlib/inventory.py            inventory.py-20050309040759-6648b84ca2005b37
      bzrlib/merge.py                merge.py-20050513021216-953b65a438527106
      bzrlib/osutils.py              osutils.py-20050309040759-eeaff12fbf77ac86
      bzrlib/remote.py               remote.py-20060720103555-yeeg2x51vn0rbtdp-1
      bzrlib/repofmt/knitrepo.py     knitrepo.py-20070206081537-pyy4a00xdas0j4pf-1
      bzrlib/repofmt/pack_repo.py    pack_repo.py-20070813041115-gjv5ma7ktfqwsjgn-1
      bzrlib/repository.py           rev_storage.py-20051111201905-119e9401e46257e3
      bzrlib/revision.py             revision.py-20050309040759-e77802c08f3999d5
      bzrlib/smart/medium.py         medium.py-20061103051856-rgu2huy59fkz902q-1
      bzrlib/symbol_versioning.py    symbol_versioning.py-20060105104851-9ecf8af605d15a80
      bzrlib/tests/TestUtil.py       TestUtil.py-20050824080200-5f70140a2d938694
      bzrlib/tests/__init__.py       selftest.py-20050531073622-8d0e3c8845c97a64
      bzrlib/tests/blackbox/test_merge.py test_merge.py-20060323225809-9bc0459c19917f41
      bzrlib/tests/blackbox/test_non_ascii.py test_non_ascii.py-20060105214030-68010be784a5d854
      bzrlib/tests/blackbox/test_split.py test_split.py-20061008023421-qy0vdpzysh5rriu8-1
      bzrlib/tests/repository_implementations/__init__.py __init__.py-20060131092037-9564957a7d4a841b
      bzrlib/tests/repository_implementations/test_repository.py test_repository.py-20060131092128-ad07f494f5c9d26c
      bzrlib/tests/test_ancestry.py  test_ancestry.py-20050913023709-69768e94848312c6
      bzrlib/tests/test_diff.py      testdiff.py-20050727164403-d1a3496ebb12e339
      bzrlib/tests/test_extract.py   test_extract.py-20061002214140-qdnnm67q1ov6x6pd-1
      bzrlib/tests/test_graph.py     test_graph_walker.py-20070525030405-enq4r60hhi9xrujc-1
      bzrlib/tests/test_merge.py     testmerge.py-20050905070950-c1b5aa49ff911024
      bzrlib/tests/test_msgeditor.py test_msgeditor.py-20051202041359-920315ec6011ee51
      bzrlib/tests/test_revision.py  testrevision.py-20050804210559-46f5e1eb67b01289
      bzrlib/tests/test_selftest.py  test_selftest.py-20051202044319-c110a115d8c0456a
      bzrlib/tests/tree_implementations/test_inv.py test_inv.py-20070312023226-0cdvk5uwhutis9vg-1
      bzrlib/tree.py                 tree.py-20050309040759-9d5f2496be663e77
      bzrlib/version_info_formats/__init__.py generate_version_info.py-20051228204928-8358edabcddcd97e
      bzrlib/versionedfile.py        versionedfile.py-20060222045106-5039c71ee3b65490
      bzrlib/workingtree.py          workingtree.py-20050511021032-29b6ec0a681e02e3
      bzrlib/workingtree_4.py        workingtree_4.py-20070208044105-5fgpc5j3ljlh5q6c-1
    ------------------------------------------------------------
    revno: 3123.5.17
    revision-id:abentley at panoramicfeedback.com-20071220142859-9tea7c02aw13w54k
    parent: abentley at panoramicfeedback.com-20071220141748-ln0j367o0n7840ea
    committer: Aaron Bentley <abentley at panoramicfeedback.com>
    branch nick: hardlinks
    timestamp: Thu 2007-12-20 09:28:59 -0500
    message:
      Update docs
    modified:
      bzrlib/branch.py               branch.py-20050309040759-e4baf4e0d046576e
      bzrlib/bzrdir.py               bzrdir.py-20060131065624-156dfea39c4387cb
      bzrlib/transform.py            transform.py-20060105172343-dd99e54394d91687
      bzrlib/workingtree.py          workingtree.py-20050511021032-29b6ec0a681e02e3
      bzrlib/workingtree_4.py        workingtree_4.py-20070208044105-5fgpc5j3ljlh5q6c-1
    ------------------------------------------------------------
    revno: 3123.5.16
    revision-id:abentley at panoramicfeedback.com-20071220141748-ln0j367o0n7840ea
    parent: abentley at panoramicfeedback.com-20071220140701-1seemr3ds8hky3z1
    committer: Aaron Bentley <abentley at panoramicfeedback.com>
    branch nick: hardlinks
    timestamp: Thu 2007-12-20 09:17:48 -0500
    message:
      Test handling of conversion to non-file
    modified:
      bzrlib/tests/test_transform.py test_transaction.py-20060105172520-b3ffb3946550e6c4
    ------------------------------------------------------------
    revno: 3123.5.15
    revision-id:abentley at panoramicfeedback.com-20071220140701-1seemr3ds8hky3z1
    parent: abentley at panoramicfeedback.com-20071219180244-xx1k4bfir4mvfd0p
    committer: Aaron Bentley <abentley at panoramicfeedback.com>
    branch nick: hardlinks
    timestamp: Thu 2007-12-20 09:07:01 -0500
    message:
      Fix open_tree_or_branch tests
    modified:
      bzrlib/tests/test_bzrdir.py    test_bzrdir.py-20060131065654-deba40eef51cf220
    ------------------------------------------------------------
    revno: 3123.5.14
    revision-id:abentley at panoramicfeedback.com-20071219180244-xx1k4bfir4mvfd0p
    parent: abentley at panoramicfeedback.com-20071219180146-qy931ojw5icsml9r
    committer: Aaron Bentley <abentley at panoramicfeedback.com>
    branch nick: hardlinks
    timestamp: Wed 2007-12-19 13:02:44 -0500
    message:
      Avoid Repository.revision_tree in common-case branching
    modified:
      bzrlib/workingtree_4.py        workingtree_4.py-20070208044105-5fgpc5j3ljlh5q6c-1
    ------------------------------------------------------------
    revno: 3123.5.13
    revision-id:abentley at panoramicfeedback.com-20071219180146-qy931ojw5icsml9r
    parent: abentley at panoramicfeedback.com-20071219170854-wkjt195ere6aorsm
    committer: Aaron Bentley <abentley at panoramicfeedback.com>
    branch nick: hardlinks
    timestamp: Wed 2007-12-19 13:01:46 -0500
    message:
      Accelerate further by using iter_changes
    modified:
      bzrlib/transform.py            transform.py-20060105172343-dd99e54394d91687
    ------------------------------------------------------------
    revno: 3123.5.12
    revision-id:abentley at panoramicfeedback.com-20071219170854-wkjt195ere6aorsm
    parent: abentley at panoramicfeedback.com-20071219150022-1unx3w7nopntj2sj
    committer: Aaron Bentley <abentley at panoramicfeedback.com>
    branch nick: hardlinks
    timestamp: Wed 2007-12-19 12:08:54 -0500
    message:
      Try to optimize iter_changes_accelerated
    modified:
      bzrlib/tests/test_transform.py test_transaction.py-20060105172520-b3ffb3946550e6c4
      bzrlib/transform.py            transform.py-20060105172343-dd99e54394d91687
    ------------------------------------------------------------
    revno: 3123.5.11
    revision-id:abentley at panoramicfeedback.com-20071219150022-1unx3w7nopntj2sj
    parent: abentley at panoramicfeedback.com-20071219143233-ziv092s5phf2y41z
    committer: Aaron Bentley <abentley at panoramicfeedback.com>
    branch nick: hardlinks
    timestamp: Wed 2007-12-19 10:00:22 -0500
    message:
      Accelerate branching from a lightweight checkout
    modified:
      bzrlib/builtins.py             builtins.py-20050830033751-fc01482b9ca23183
      bzrlib/bzrdir.py               bzrdir.py-20060131065624-156dfea39c4387cb
      bzrlib/tests/test_bzrdir.py    test_bzrdir.py-20060131065654-deba40eef51cf220
    ------------------------------------------------------------
    revno: 3123.5.10
    revision-id:abentley at panoramicfeedback.com-20071219143233-ziv092s5phf2y41z
    parent: abentley at panoramicfeedback.com-20071219143133-lov2tcj74hq3cmqs
    committer: Aaron Bentley <abentley at panoramicfeedback.com>
    branch nick: hardlinks
    timestamp: Wed 2007-12-19 09:32:33 -0500
    message:
      Restore old handling of set_root_id
    modified:
      bzrlib/bzrdir.py               bzrdir.py-20060131065624-156dfea39c4387cb
    ------------------------------------------------------------
    revno: 3123.5.9
    revision-id:abentley at panoramicfeedback.com-20071219143133-lov2tcj74hq3cmqs
    parent: aaron.bentley at utoronto.ca-20071219132040-bzbczkkcjko742i1
    committer: Aaron Bentley <abentley at panoramicfeedback.com>
    branch nick: hardlinks
    timestamp: Wed 2007-12-19 09:31:33 -0500
    message:
      Fix generator finally block usage
    modified:
      bzrlib/transform.py            transform.py-20060105172343-dd99e54394d91687
    ------------------------------------------------------------
    revno: 3123.5.8
    revision-id:aaron.bentley at utoronto.ca-20071219132040-bzbczkkcjko742i1
    parent: aaron.bentley at utoronto.ca-20071219060037-s2ouj41ysuu2kmmt
    committer: Aaron Bentley <aaron.bentley at utoronto.ca>
    branch nick: hardlinks
    timestamp: Wed 2007-12-19 08:20:40 -0500
    message:
      Work around double-opening lock issue
    modified:
      bzrlib/builtins.py             builtins.py-20050830033751-fc01482b9ca23183
      bzrlib/bzrdir.py               bzrdir.py-20060131065624-156dfea39c4387cb
      bzrlib/tests/bzrdir_implementations/test_bzrdir.py test_bzrdir.py-20060131065642-0ebeca5e30e30866
    ------------------------------------------------------------
    revno: 3123.5.7
    revision-id:aaron.bentley at utoronto.ca-20071219060037-s2ouj41ysuu2kmmt
    parent: aaron.bentley at utoronto.ca-20071219040456-0bh3fruord0m08gz
    committer: Aaron Bentley <aaron.bentley at utoronto.ca>
    branch nick: hardlinks
    timestamp: Wed 2007-12-19 01:00:37 -0500
    message:
      Avoid redundant conflict check
    modified:
      bzrlib/transform.py            transform.py-20060105172343-dd99e54394d91687
    ------------------------------------------------------------
    revno: 3123.5.6
    revision-id:aaron.bentley at utoronto.ca-20071219040456-0bh3fruord0m08gz
    parent: aaron.bentley at utoronto.ca-20071219035350-n0df6nuii1hp803b
    committer: Aaron Bentley <aaron.bentley at utoronto.ca>
    branch nick: hardlinks
    timestamp: Tue 2007-12-18 23:04:56 -0500
    message:
      Update NEWS
    modified:
      NEWS                           NEWS-20050323055033-4e00b5db738777ff
    ------------------------------------------------------------
    revno: 3123.5.5
    revision-id:aaron.bentley at utoronto.ca-20071219035350-n0df6nuii1hp803b
    parent: aaron.bentley at utoronto.ca-20071219030216-ntnsxt3kwpcmxxqu
    committer: Aaron Bentley <aaron.bentley at utoronto.ca>
    branch nick: hardlinks
    timestamp: Tue 2007-12-18 22:53:50 -0500
    message:
      Split out _iter_files_bytes_accelerated
    modified:
      bzrlib/transform.py            transform.py-20060105172343-dd99e54394d91687
    ------------------------------------------------------------
    revno: 3123.5.4
    revision-id:aaron.bentley at utoronto.ca-20071219030216-ntnsxt3kwpcmxxqu
    parent: abentley at panoramicfeedback.com-20071218231206-zkw1bosst2ah0aeg
    committer: Aaron Bentley <aaron.bentley at utoronto.ca>
    branch nick: hardlinks
    timestamp: Tue 2007-12-18 22:02:16 -0500
    message:
      Use an accelerator tree when branching, handle no-such-id correctly
    modified:
      bzrlib/bzrdir.py               bzrdir.py-20060131065624-156dfea39c4387cb
      bzrlib/tests/test_transform.py test_transaction.py-20060105172520-b3ffb3946550e6c4
      bzrlib/transform.py            transform.py-20060105172343-dd99e54394d91687
    ------------------------------------------------------------
    revno: 3123.5.3
    revision-id:abentley at panoramicfeedback.com-20071218231206-zkw1bosst2ah0aeg
    parent: abentley at panoramicfeedback.com-20071218221735-ruvnju8fhunjg4kh
    committer: Aaron Bentley <abentley at panoramicfeedback.com>
    branch nick: hardlinks
    timestamp: Tue 2007-12-18 18:12:06 -0500
    message:
      Get tests passing with accelerator_tree
    modified:
      bzrlib/builtins.py             builtins.py-20050830033751-fc01482b9ca23183
      bzrlib/tests/blackbox/test_checkout.py test_checkout.py-20060211231752-a5cde67cf70af854
      bzrlib/tests/test_workingtree.py testworkingtree.py-20051004024258-b88d0fe8f101d468
      bzrlib/workingtree.py          workingtree.py-20050511021032-29b6ec0a681e02e3
    ------------------------------------------------------------
    revno: 3123.5.2
    revision-id:abentley at panoramicfeedback.com-20071218221735-ruvnju8fhunjg4kh
    parent: abentley at panoramicfeedback.com-20071218220146-xgb0g70vvu51z77o
    committer: Aaron Bentley <abentley at panoramicfeedback.com>
    branch nick: hardlinks
    timestamp: Tue 2007-12-18 17:17:35 -0500
    message:
      Allow checkout --files_from
    modified:
      bzrlib/branch.py               branch.py-20050309040759-e4baf4e0d046576e
      bzrlib/builtins.py             builtins.py-20050830033751-fc01482b9ca23183
      bzrlib/bzrdir.py               bzrdir.py-20060131065624-156dfea39c4387cb
      bzrlib/workingtree_4.py        workingtree_4.py-20070208044105-5fgpc5j3ljlh5q6c-1
    ------------------------------------------------------------
    revno: 3123.5.1
    revision-id:abentley at panoramicfeedback.com-20071218220146-xgb0g70vvu51z77o
    parent: pqm at pqm.ubuntu.com-20071217234754-hzi1en08nilnvh6s
    committer: Aaron Bentley <abentley at panoramicfeedback.com>
    branch nick: hardlinks
    timestamp: Tue 2007-12-18 17:01:46 -0500
    message:
      Make build-tree able to use an additional 'accelerator' tree
    modified:
      bzrlib/tests/test_transform.py test_transaction.py-20060105172520-b3ffb3946550e6c4
      bzrlib/transform.py            transform.py-20060105172343-dd99e54394d91687
=== modified file 'NEWS'
--- a/NEWS	2007-12-20 04:20:19 +0000
+++ b/NEWS	2007-12-20 15:21:48 +0000
@@ -21,6 +21,10 @@
 
   IMPROVEMENTS:
 
+   * ``branch`` and ``checkout`` can now use files from a working tree to
+     to speed up the process.  For checkout, this requires the new
+     --files-from flag.  (Aaron Bentley)
+
    * ``bzr diff`` now sorts files in alphabetical order.  (Aaron Bentley)
 
    * ``bzr diff`` now works on branches without working trees. Tree-less

=== modified file 'bzrlib/branch.py'
--- a/bzrlib/branch.py	2007-12-10 19:20:41 +0000
+++ b/bzrlib/branch.py	2007-12-20 14:28:59 +0000
@@ -757,13 +757,17 @@
         return format
 
     def create_checkout(self, to_location, revision_id=None,
-                        lightweight=False):
+                        lightweight=False, accelerator_tree=None):
         """Create a checkout of a branch.
         
         :param to_location: The url to produce the checkout at
         :param revision_id: The revision to check out
         :param lightweight: If True, produce a lightweight checkout, otherwise,
         produce a bound branch (heavyweight checkout)
+        :param accelerator_tree: A tree which can be used for retrieving file
+            contents more quickly than the revision tree, i.e. a workingtree.
+            The revision tree will be used for cases where accelerator_tree's
+            content is different.
         :return: The tree of the created checkout
         """
         t = transport.get_transport(to_location)
@@ -783,7 +787,8 @@
             checkout_branch.pull(self, stop_revision=revision_id)
             from_branch=None
         tree = checkout.create_workingtree(revision_id,
-                                           from_branch=from_branch)
+                                           from_branch=from_branch,
+                                           accelerator_tree=accelerator_tree)
         basis_tree = tree.basis_tree()
         basis_tree.lock_read()
         try:

=== modified file 'bzrlib/builtins.py'
--- a/bzrlib/builtins.py	2007-12-20 00:56:46 +0000
+++ b/bzrlib/builtins.py	2007-12-20 15:21:48 +0000
@@ -874,7 +874,8 @@
             raise errors.BzrCommandError(
                 'bzr branch --revision takes exactly 1 revision value')
 
-        br_from = Branch.open(from_location)
+        accelerator_tree, br_from = bzrdir.BzrDir.open_tree_or_branch(
+            from_location)
         br_from.lock_read()
         try:
             if len(revision) == 1 and revision[0] is not None:
@@ -902,7 +903,8 @@
             try:
                 # preserve whatever source format we have.
                 dir = br_from.bzrdir.sprout(to_transport.base, revision_id,
-                                            possible_transports=[to_transport])
+                                            possible_transports=[to_transport],
+                                            accelerator_tree=accelerator_tree)
                 branch = dir.open_branch()
             except errors.NoSuchRevision:
                 to_transport.delete_tree('.')
@@ -947,11 +949,17 @@
                                  "common operations like diff and status without "
                                  "such access, and also support local commits."
                             ),
+                     Option('files-from',
+                            help="Get file contents from this tree.", type=str)
                      ]
     aliases = ['co']
 
     def run(self, branch_location=None, to_location=None, revision=None,
-            lightweight=False):
+            lightweight=False, files_from=None):
+        if files_from is not None:
+            accelerator_tree = WorkingTree.open(files_from)
+        else:
+            accelerator_tree = None
         if revision is None:
             revision = [None]
         elif len(revision) > 1:
@@ -978,7 +986,8 @@
             except errors.NoWorkingTree:
                 source.bzrdir.create_workingtree(revision_id)
                 return
-        source.create_checkout(to_location, revision_id, lightweight)
+        source.create_checkout(to_location, revision_id, lightweight,
+                               accelerator_tree)
 
 
 class cmd_renames(Command):

=== modified file 'bzrlib/bzrdir.py'
--- a/bzrlib/bzrdir.py	2007-12-18 22:40:58 +0000
+++ b/bzrlib/bzrdir.py	2007-12-20 15:21:48 +0000
@@ -381,11 +381,16 @@
                                                format=format).bzrdir
         return bzrdir.create_workingtree()
 
-    def create_workingtree(self, revision_id=None, from_branch=None):
+    def create_workingtree(self, revision_id=None, from_branch=None,
+        accelerator_tree=None):
         """Create a working tree at this BzrDir.
         
         :param revision_id: create it as of this revision id.
         :param from_branch: override bzrdir branch (for lightweight checkouts)
+        :param accelerator_tree: A tree which can be used for retrieving file
+            contents more quickly than the revision tree, i.e. a workingtree.
+            The revision tree will be used for cases where accelerator_tree's
+            content is different.
         """
         raise NotImplementedError(self.create_workingtree)
 
@@ -666,6 +671,34 @@
                 raise errors.NotBranchError(path=url)
             a_transport = new_t
 
+    def _get_tree_branch(self):
+        """Return the branch and tree, if any, for this bzrdir.
+
+        Return None for tree if not present.
+        Raise NotBranchError if no branch is present.
+        :return: (tree, branch)
+        """
+        try:
+            tree = self.open_workingtree()
+        except (errors.NoWorkingTree, errors.NotLocalUrl):
+            tree = None
+            branch = self.open_branch()
+        else:
+            branch = tree.branch
+        return tree, branch
+
+    @classmethod
+    def open_tree_or_branch(klass, location):
+        """Return the branch and working tree at a location.
+
+        If there is no tree at the location, tree will be None.
+        If there is no branch at the location, an exception will be
+        raised
+        :return: (tree, branch)
+        """
+        bzrdir = klass.open(location)
+        return bzrdir._get_tree_branch()
+
     @classmethod
     def open_containing_tree_or_branch(klass, location):
         """Return the branch and working tree contained by a location.
@@ -677,13 +710,7 @@
         relpath is the portion of the path that is contained by the branch.
         """
         bzrdir, relpath = klass.open_containing(location)
-        try:
-            tree = bzrdir.open_workingtree()
-        except (errors.NoWorkingTree, errors.NotLocalUrl):
-            tree = None
-            branch = bzrdir.open_branch()
-        else:
-            branch = tree.branch
+        tree, branch = bzrdir._get_tree_branch()
         return tree, branch, relpath
 
     def open_repository(self, _unsupported=False):
@@ -788,7 +815,8 @@
         return self.cloning_metadir()
 
     def sprout(self, url, revision_id=None, force_new_repo=False,
-               recurse='down', possible_transports=None):
+               recurse='down', possible_transports=None,
+               accelerator_tree=None):
         """Create a copy of this bzrdir prepared for use as a new line of
         development.
 
@@ -801,6 +829,10 @@
 
         if revision_id is not None, then the clone operation may tune
             itself to download less data.
+        :param accelerator_tree: A tree which can be used for retrieving file
+            contents more quickly than the revision tree, i.e. a workingtree.
+            The revision tree will be used for cases where accelerator_tree's
+            content is different.
         """
         target_transport = get_transport(url, possible_transports)
         target_transport.ensure_base()
@@ -845,7 +877,7 @@
             result.create_branch()
         if isinstance(target_transport, LocalTransport) and (
             result_repo is None or result_repo.make_working_trees()):
-            wt = result.create_workingtree()
+            wt = result.create_workingtree(accelerator_tree=accelerator_tree)
             wt.lock_write()
             try:
                 if wt.path2id('') is None:
@@ -939,7 +971,8 @@
         """See BzrDir.destroy_repository."""
         raise errors.UnsupportedOperation(self.destroy_repository, self)
 
-    def create_workingtree(self, revision_id=None, from_branch=None):
+    def create_workingtree(self, revision_id=None, from_branch=None,
+                           accelerator_tree=None):
         """See BzrDir.create_workingtree."""
         # this looks buggy but is not -really-
         # because this format creates the workingtree when the bzrdir is
@@ -1013,7 +1046,7 @@
         return format.open(self, _found=True)
 
     def sprout(self, url, revision_id=None, force_new_repo=False,
-               possible_transports=None):
+               possible_transports=None, accelerator_tree=None):
         """See BzrDir.sprout()."""
         from bzrlib.workingtree import WorkingTreeFormat2
         self._make_tail(url)
@@ -1027,7 +1060,8 @@
         except errors.NotBranchError:
             pass
         # we always want a working tree
-        WorkingTreeFormat2().initialize(result)
+        WorkingTreeFormat2().initialize(result,
+                                        accelerator_tree=accelerator_tree)
         return result
 
 
@@ -1121,10 +1155,12 @@
         """See BzrDir.destroy_repository."""
         self.transport.delete_tree('repository')
 
-    def create_workingtree(self, revision_id=None, from_branch=None):
+    def create_workingtree(self, revision_id=None, from_branch=None,
+                           accelerator_tree=None):
         """See BzrDir.create_workingtree."""
         return self._format.workingtree_format.initialize(
-            self, revision_id, from_branch=from_branch)
+            self, revision_id, from_branch=from_branch,
+            accelerator_tree=accelerator_tree)
 
     def destroy_workingtree(self):
         """See BzrDir.destroy_workingtree."""

=== modified file 'bzrlib/tests/blackbox/test_checkout.py'
--- a/bzrlib/tests/blackbox/test_checkout.py	2007-08-20 13:07:12 +0000
+++ b/bzrlib/tests/blackbox/test_checkout.py	2007-12-18 23:12:06 +0000
@@ -137,3 +137,8 @@
         branch.bzrdir.destroy_workingtree()
         self.run_bzr('checkout -r 0')
         self.assertEqual('null:', tree.last_revision())
+
+    def test_checkout_files_from(self):
+        branch = _mod_branch.Branch.open('branch')
+        self.run_bzr(['checkout', 'branch', 'branch2', '--files-from',
+                      'branch'])

=== modified file 'bzrlib/tests/bzrdir_implementations/test_bzrdir.py'
--- a/bzrlib/tests/bzrdir_implementations/test_bzrdir.py	2007-11-27 19:40:32 +0000
+++ b/bzrlib/tests/bzrdir_implementations/test_bzrdir.py	2007-12-19 13:20:40 +0000
@@ -187,7 +187,7 @@
                               % a_bzrdir.transport)
 
     def sproutOrSkip(self, from_bzrdir, to_url, revision_id=None,
-                     force_new_repo=False):
+                     force_new_repo=False, accelerator_tree=None):
         """Sprout from_bzrdir into to_url, or raise TestSkipped.
         
         A simple wrapper for from_bzrdir.sprout that translates NotLocalUrl into
@@ -198,7 +198,8 @@
             raise TestSkipped('Cannot sprout to remote bzrdirs.')
         target = from_bzrdir.sprout(to_url, revision_id=revision_id,
                                     force_new_repo=force_new_repo,
-                                    possible_transports=[to_transport])
+                                    possible_transports=[to_transport],
+                                    accelerator_tree=accelerator_tree)
         return target
 
     def test_create_null_workingtree(self):
@@ -1080,6 +1081,17 @@
         target = self.sproutOrSkip(dir, self.get_url('target'), revision_id='1')
         self.assertEqual(['1'], target.open_workingtree().get_parent_ids())
 
+    def test_sprout_takes_accelerator(self):
+        tree = self.make_branch_and_tree('source')
+        self.build_tree(['source/foo'])
+        tree.add('foo')
+        tree.commit('revision 1', rev_id='1')
+        tree.commit('revision 2', rev_id='2', allow_pointless=True)
+        dir = tree.bzrdir
+        target = self.sproutOrSkip(dir, self.get_url('target'),
+                                   accelerator_tree=tree)
+        self.assertEqual(['2'], target.open_workingtree().get_parent_ids())
+
     def test_format_initialize_find_open(self):
         # loopback test to check the current format initializes to itself.
         if not self.bzrdir_format.is_supported():

=== modified file 'bzrlib/tests/test_bzrdir.py'
--- a/bzrlib/tests/test_bzrdir.py	2007-11-29 07:12:42 +0000
+++ b/bzrlib/tests/test_bzrdir.py	2007-12-20 14:07:01 +0000
@@ -509,6 +509,29 @@
                          local_branch_path(branch))
         self.assertEqual('', relpath)
 
+    def test_open_tree_or_branch(self):
+        def local_branch_path(branch):
+             return os.path.realpath(
+                urlutils.local_path_from_url(branch.base))
+
+        self.make_branch_and_tree('topdir')
+        tree, branch = bzrdir.BzrDir.open_tree_or_branch('topdir')
+        self.assertEqual(os.path.realpath('topdir'),
+                         os.path.realpath(tree.basedir))
+        self.assertEqual(os.path.realpath('topdir'),
+                         local_branch_path(branch))
+        self.assertIs(tree.bzrdir, branch.bzrdir)
+        # opening from non-local should not return the tree
+        tree, branch = bzrdir.BzrDir.open_tree_or_branch(
+            self.get_readonly_url('topdir'))
+        self.assertEqual(None, tree)
+        # without a tree:
+        self.make_branch('topdir/foo')
+        tree, branch = bzrdir.BzrDir.open_tree_or_branch('topdir/foo')
+        self.assertIs(tree, None)
+        self.assertEqual(os.path.realpath('topdir/foo'),
+                         local_branch_path(branch))
+
     def test_open_from_transport(self):
         # transport pointing at bzrdir should give a bzrdir with root transport
         # set to the given transport

=== modified file 'bzrlib/tests/test_transform.py'
--- a/bzrlib/tests/test_transform.py	2007-12-11 19:21:27 +0000
+++ b/bzrlib/tests/test_transform.py	2007-12-20 14:17:48 +0000
@@ -1499,6 +1499,58 @@
         # children of non-root directories should not be renamed
         self.assertEqual(2, transform_result.rename_count)
 
+    def test_build_tree_accelerator_tree(self):
+        source = self.make_branch_and_tree('source')
+        self.build_tree_contents([('source/file1', 'A')])
+        self.build_tree_contents([('source/file2', 'B')])
+        source.add(['file1', 'file2'], ['file1-id', 'file2-id'])
+        source.commit('commit files')
+        self.build_tree_contents([('source/file2', 'C')])
+        calls = []
+        real_source_get_file = source.get_file
+        def get_file(file_id, path=None):
+            calls.append(file_id)
+            return real_source_get_file(file_id, path)
+        source.get_file = get_file
+        source.lock_read()
+        self.addCleanup(source.unlock)
+        target = self.make_branch_and_tree('target')
+        build_tree(source.basis_tree(), target, source)
+        self.assertEqual(['file1-id'], calls)
+
+    def test_build_tree_accelerator_tree_missing_file(self):
+        source = self.make_branch_and_tree('source')
+        self.build_tree_contents([('source/file1', 'A')])
+        self.build_tree_contents([('source/file2', 'B')])
+        source.add(['file1', 'file2'])
+        source.commit('commit files')
+        os.unlink('source/file1')
+        source.remove(['file2'])
+        target = self.make_branch_and_tree('target')
+        build_tree(source.basis_tree(), target, source)
+
+    def test_build_tree_accelerator_wrong_kind(self):
+        source = self.make_branch_and_tree('source')
+        self.build_tree_contents([('source/file1', '')])
+        self.build_tree_contents([('source/file2', '')])
+        source.add(['file1', 'file2'], ['file1-id', 'file2-id'])
+        source.commit('commit files')
+        os.unlink('source/file2')
+        self.build_tree_contents([('source/file2/', 'C')])
+        os.unlink('source/file1')
+        os.symlink('file2', 'source/file1')
+        calls = []
+        real_source_get_file = source.get_file
+        def get_file(file_id, path=None):
+            calls.append(file_id)
+            return real_source_get_file(file_id, path)
+        source.get_file = get_file
+        source.lock_read()
+        self.addCleanup(source.unlock)
+        target = self.make_branch_and_tree('target')
+        build_tree(source.basis_tree(), target, source)
+        self.assertEqual([], calls)
+
 
 class MockTransform(object):
 

=== modified file 'bzrlib/tests/test_workingtree.py'
--- a/bzrlib/tests/test_workingtree.py	2007-11-23 20:19:57 +0000
+++ b/bzrlib/tests/test_workingtree.py	2007-12-18 23:12:06 +0000
@@ -94,7 +94,8 @@
         """See WorkingTreeFormat.get_format_string()."""
         return "Sample tree format."
 
-    def initialize(self, a_bzrdir, revision_id=None, from_branch=None):
+    def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
+                   accelerator_tree=None):
         """Sample branches cannot be created."""
         t = a_bzrdir.get_workingtree_transport(self)
         t.put_bytes('format', self.get_format_string())

=== modified file 'bzrlib/transform.py'
--- a/bzrlib/transform.py	2007-12-11 19:21:27 +0000
+++ b/bzrlib/transform.py	2007-12-20 14:28:59 +0000
@@ -1322,7 +1322,7 @@
     return file_ids
 
 
-def build_tree(tree, wt):
+def build_tree(tree, wt, accelerator_tree=None):
     """Create working tree for a branch, using a TreeTransform.
     
     This function should be used on empty trees, having a tree root at most.
@@ -1335,19 +1335,31 @@
     - Otherwise, if the content on disk matches the content we are building,
       it is silently replaced.
     - Otherwise, conflict resolution will move the old file to 'oldname.moved'.
+
+    :param tree: The tree to convert wt into a copy of
+    :param wt: The working tree that files will be placed into
+    :param accelerator_tree: A tree which can be used for retrieving file
+        contents more quickly than tree itself, i.e. a workingtree.  tree
+        will be used for cases where accelerator_tree's content is different.
     """
     wt.lock_tree_write()
     try:
         tree.lock_read()
         try:
-            return _build_tree(tree, wt)
+            if accelerator_tree is not None:
+                accelerator_tree.lock_read()
+            try:
+                return _build_tree(tree, wt, accelerator_tree)
+            finally:
+                if accelerator_tree is not None:
+                    accelerator_tree.unlock()
         finally:
             tree.unlock()
     finally:
         wt.unlock()
 
 
-def _build_tree(tree, wt):
+def _build_tree(tree, wt, accelerator_tree):
     """See build_tree."""
     if len(wt.inventory) > 1:  # more than just a root
         raise errors.WorkingTreeAlreadyPopulated(base=wt.basedir)
@@ -1424,7 +1436,8 @@
                     old_parent = tt.trans_id_tree_path(tree_path)
                     _reparent_children(tt, old_parent, new_trans_id)
             for num, (trans_id, bytes) in enumerate(
-                tree.iter_files_bytes(deferred_contents)):
+                _iter_files_bytes_accelerated(tree, accelerator_tree,
+                                              deferred_contents)):
                 tt.create_file(bytes, trans_id)
                 pb.update('Adding file contents',
                           (num + len(tree.inventory) - len(deferred_contents)),
@@ -1442,13 +1455,37 @@
             wt.add_conflicts(conflicts)
         except errors.UnsupportedOperation:
             pass
-        result = tt.apply()
+        result = tt.apply(no_conflicts=True)
     finally:
         tt.finalize()
         top_pb.finished()
     return result
 
 
+def _iter_files_bytes_accelerated(tree, accelerator_tree, desired_files):
+    if accelerator_tree is None:
+        new_desired_files = desired_files
+    else:
+        iter = accelerator_tree._iter_changes(tree, include_unchanged=True)
+        unchanged = dict((f, p[0]) for (f, p, c, v, d, n, k, e)
+                         in iter if not c)
+        new_desired_files = []
+        for file_id, identifier in desired_files:
+            accelerator_path = unchanged.get(file_id)
+            if accelerator_path is None:
+                new_desired_files.append((file_id, identifier))
+                continue
+            contents = accelerator_tree.get_file(file_id, accelerator_path)
+            try:
+                want_new = False
+                contents_bytes = (contents.read(),)
+            finally:
+                contents.close()
+            yield identifier, contents_bytes
+    for result in tree.iter_files_bytes(new_desired_files):
+        yield result
+
+
 def _reparent_children(tt, old_parent, new_parent):
     for child in tt.iter_tree_children(old_parent):
         tt.adjust_path(tt.final_name(child), new_parent, child)

=== modified file 'bzrlib/workingtree.py'
--- a/bzrlib/workingtree.py	2007-12-20 12:34:06 +0000
+++ b/bzrlib/workingtree.py	2007-12-20 15:21:48 +0000
@@ -2746,7 +2746,8 @@
         control_files.put_bytes('pending-merges', '')
         
 
-    def initialize(self, a_bzrdir, revision_id=None, from_branch=None):
+    def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
+                   accelerator_tree=None):
         """See WorkingTreeFormat.initialize()."""
         if not isinstance(a_bzrdir.transport, LocalTransport):
             raise errors.NotLocalUrl(a_bzrdir.transport.base)
@@ -2838,11 +2839,16 @@
         return LockableFiles(transport, self._lock_file_name, 
                              self._lock_class)
 
-    def initialize(self, a_bzrdir, revision_id=None, from_branch=None):
+    def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
+                   accelerator_tree=None):
         """See WorkingTreeFormat.initialize().
         
-        revision_id allows creating a working tree at a different
-        revision than the branch is at.
+        :param revision_id: if supplied, create a working tree at a different
+            revision than the branch is at.
+        :param accelerator_tree: A tree which can be used for retrieving file
+            contents more quickly than the revision tree, i.e. a workingtree.
+            The revision tree will be used for cases where accelerator_tree's
+            content is different.
         """
         if not isinstance(a_bzrdir.transport, LocalTransport):
             raise errors.NotLocalUrl(a_bzrdir.transport.base)

=== modified file 'bzrlib/workingtree_4.py'
--- a/bzrlib/workingtree_4.py	2007-12-20 12:34:06 +0000
+++ b/bzrlib/workingtree_4.py	2007-12-20 15:21:48 +0000
@@ -1257,11 +1257,16 @@
         """See WorkingTreeFormat.get_format_description()."""
         return "Working tree format 4"
 
-    def initialize(self, a_bzrdir, revision_id=None, from_branch=None):
+    def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
+                   accelerator_tree=None):
         """See WorkingTreeFormat.initialize().
 
         :param revision_id: allows creating a working tree at a different
         revision than the branch is at.
+        :param accelerator_tree: A tree which can be used for retrieving file
+            contents more quickly than the revision tree, i.e. a workingtree.
+            The revision tree will be used for cases where accelerator_tree's
+            content is different.
 
         These trees get an initial random root id, if their repository supports
         rich root data, TREE_ROOT otherwise.
@@ -1298,17 +1303,31 @@
                 else:
                     wt._set_root_id(ROOT_ID)
                 wt.flush()
-            wt.set_last_revision(revision_id)
+            basis = None
+            # frequently, we will get here due to branching.  The accelerator
+            # tree will be the tree from the branch, so the desired basis
+            # tree will often be a parent of the accelerator tree.
+            if accelerator_tree is not None:
+                try:
+                    basis = accelerator_tree.revision_tree(revision_id)
+                except errors.NoSuchRevision:
+                    pass
+            if basis is None:
+                basis = branch.repository.revision_tree(revision_id)
+            if revision_id == NULL_REVISION:
+                parents_list = []
+            else:
+                parents_list = [(revision_id, basis)]
+            basis.lock_read()
+            wt.set_parent_trees(parents_list, allow_leftmost_as_ghost=True)
             wt.flush()
-            basis = wt.basis_tree()
-            basis.lock_read()
             # if the basis has a root id we have to use that; otherwise we use
             # a new random one
             basis_root_id = basis.get_root_id()
             if basis_root_id is not None:
                 wt._set_root_id(basis_root_id)
                 wt.flush()
-            transform.build_tree(basis, wt)
+            transform.build_tree(basis, wt, accelerator_tree)
             basis.unlock()
         finally:
             control_files.unlock()




More information about the bazaar-commits mailing list