Rev 4342: Invert control of check so that trees and branches are checked by calling back into them. in http://people.ubuntu.com/~robertc/baz2.0/check

Robert Collins robertc at robertcollins.net
Mon May 11 03:37:48 BST 2009


At http://people.ubuntu.com/~robertc/baz2.0/check

------------------------------------------------------------
revno: 4342
revision-id: robertc at robertcollins.net-20090511023745-7620jhu2tb9s0bnz
parent: robertc at robertcollins.net-20090511015906-6zi6a9b8tuuhipc8
committer: Robert Collins <robertc at robertcollins.net>
branch nick: check
timestamp: Mon 2009-05-11 12:37:45 +1000
message:
  Invert control of check so that trees and branches are checked by calling back into them.
=== modified file 'bzrlib/check.py'
--- a/bzrlib/check.py	2009-05-11 01:59:06 +0000
+++ b/bzrlib/check.py	2009-05-11 02:37:45 +0000
@@ -277,7 +277,7 @@
 
     Results are reported through logging.
 
-    Deprecated in 1.6.  Please use check_branch instead.
+    Deprecated in 1.6.  Please use check_dwim instead.
 
     :raise BzrCheckError: if there's a consistency error.
     """
@@ -325,58 +325,133 @@
     branch_result.report_results(verbose)
 
 
+def scan_branch(branch, needed_refs, to_unlock):
+    """Scan a branch for refs.
+
+    :param branch:  The branch to schedule for checking.
+    :param needed_refs: Refs we are accumulating.
+    :param to_unlock: The unlock list accumulating.
+    """
+    branch.lock_read()
+    to_unlock.append(branch)
+    branch_refs = branch._get_check_refs()
+    for ref in branch_refs:
+        reflist = needed_refs.setdefault(ref, [])
+        reflist.append(branch)
+
+
+def scan_tree(base_tree, tree, needed_refs, to_unlock):
+    """Scan a tree for refs.
+
+    :param base_tree: The original tree check opened, used to detect duplicate
+        tree checks.
+    :param tree:  The tree to schedule for checking.
+    :param needed_refs: Refs we are accumulating.
+    :param to_unlock: The unlock list accumulating.
+    """
+    if base_tree is not None and tree.basedir == base_tree.basedir:
+        return
+    tree.lock_read()
+    to_unlock.append(tree)
+    tree_refs = tree._get_check_refs()
+    for ref in tree_refs:
+        reflist = needed_refs.setdefault(ref, [])
+        reflist.append(tree)
+
+
 def check_dwim(path, verbose, do_branch=False, do_repo=False, do_tree=False):
     try:
-        tree, branch, repo, relpath = \
+        base_tree, branch, repo, relpath = \
                         BzrDir.open_containing_tree_branch_or_repository(path)
     except errors.NotBranchError:
-        tree = branch = repo = None
+        base_tree = branch = repo = None
 
     to_unlock = []
+    needed_refs= {}
     try:
-        if do_tree:
-            if tree is not None:
-                note("Checking working tree at '%s'."
-                     % (tree.bzrdir.root_transport.base,))
-                tree.lock_read()
-                to_unlock.append(tree)
-                needed_refs = tree._get_check_refs()
-                refs = {}
-                for ref in needed_refs:
-                    kind, value = ref
-                    if kind == 'trees':
-                        refs[ref] = tree.branch.repository.revision_tree(value)
-                    else:
-                        raise AssertionError(
-                            'unknown ref kind for ref %s' % ref)
-                tree._check(refs)
-            else:
-                log_error("No working tree found at specified location.")
-
+        if base_tree is not None:
+            # If the tree is a lightweight checkout we won't see it in
+            # repo.find_branches - add now.
+            if do_tree:
+                scan_tree(None, base_tree, needed_refs, to_unlock)
+            branch = base_tree.branch
         if branch is not None:
             # We have a branch
             if repo is None:
                 # The branch is in a shared repository
                 repo = branch.repository
-
         if repo is not None:
             repo.lock_read()
             to_unlock.append(repo)
             branches = repo.find_branches(using=True)
+            saw_tree = False
+            if do_branch or do_tree:
+                for branch in branches:
+                    if do_tree:
+                        try:
+                            tree = branch.bzrdir.open_workingtree()
+                            saw_tree = True
+                        except (errors.NotLocalUrl, errors.NoWorkingTree):
+                            pass
+                        else:
+                            scan_tree(base_tree, tree, needed_refs, to_unlock)
+                    if do_branch:
+                        scan_branch(branch, needed_refs, to_unlock)
+            if do_branch and not branches:
+                log_error("No branch found at specified location.")
+            if do_tree and base_tree is None and not saw_tree:
+                log_error("No working tree found at specified location.")
             if do_repo:
                 note("Checking repository at '%s'."
                      % (repo.bzrdir.root_transport.base,))
                 result = repo.check()
                 result.report_results(verbose)
-            if do_branch:
-                if branches == []:
-                    log_error("No branch found at specified location.")
-                else:
-                    for branch in branches:
-                        note("Checking branch at '%s'."
-                             % (branch.bzrdir.root_transport.base,))
-                        check_branch(branch, verbose)
+            if needed_refs:
+                # calculate all refs, and callback the objects requesting them.
+                refs = {}
+                wanting_items = set()
+                # Current crude version calculates everything and calls
+                # everything at once. Doing a queue and popping as things are
+                # satisfied would be cheaper on memory [but few people have
+                # huge numbers of working trees today. TODO: fix before
+                # landing].
+                distances = set()
+                existences = set()
+                for ref, wantlist in needed_refs.iteritems():
+                    wanting_items.update(wantlist)
+                    kind, value = ref
+                    if kind == 'trees':
+                        refs[ref] = repo.revision_tree(value)
+                    elif kind == 'lefthand-distance':
+                        distances.add(value)
+                    elif kind == 'revision-existence':
+                        existences.add(value)
+                    else:
+                        raise AssertionError(
+                            'unknown ref kind for ref %s' % ref)
+                node_distances = repo.get_graph().find_lefthand_distances(distances)
+                for key, distance in node_distances.iteritems():
+                    refs[('lefthand-distance', key)] = distance
+                    if key in existences and distance > 0:
+                        refs[('revision-existence', key)] = True
+                        existences.remove(key)
+                parent_map = repo.get_graph().get_parent_map(existences)
+                for key in parent_map:
+                    refs[('revision-existence', key)] = True
+                    existences.remove(key)
+                for key in existences:
+                    refs[('revision-existence', key)] = False
+                for item in wanting_items:
+                    if isinstance(item, WorkingTree):
+                        note("Checking working tree at '%s'." % (item.basedir,))
+                        item._check(refs)
+                    if isinstance(item, Branch):
+                        note("Checking branch at '%s'." % (branch.base,))
+                        branch_result = item.check(refs)
+                        branch_result.report_results(verbose)
         else:
+            if do_tree:
+                log_error("No working tree found at specified location.")
             if do_branch:
                 log_error("No branch found at specified location.")
             if do_repo:

=== modified file 'bzrlib/tests/blackbox/test_check.py'
--- a/bzrlib/tests/blackbox/test_check.py	2009-03-23 14:59:43 +0000
+++ b/bzrlib/tests/blackbox/test_check.py	2009-05-11 02:37:45 +0000
@@ -34,23 +34,23 @@
         tree = self.make_branch_and_tree('.')
         tree.commit('hallelujah')
         out, err = self.run_bzr('check')
-        self.assertContainsRe(err, r"^Checking working tree at '.*'\.\n"
-                                   r"Checking repository at '.*'\.\n"
+        self.assertContainsRe(err, r"Checking working tree at '.*'\.\n")
+        self.assertContainsRe(err, r"Checking repository at '.*'\.\n"
                                    r"checked repository.*\n"
                                    r"     1 revisions\n"
                                    r"     0 file-ids\n"
                                    r"     0 unique file texts\n"
                                    r"     0 repeated file texts\n"
-                                   r"     0 unreferenced text versions\n"
-                                   r"Checking branch at '.*'\.\n"
-                                   r"checked branch.*\n$")
+                                   r"     0 unreferenced text versions\n")
+        self.assertContainsRe(err, r"Checking branch at '.*'\.\n"
+                                   r"checked branch.*")
 
     def test_check_branch(self):
         tree = self.make_branch_and_tree('.')
         tree.commit('foo')
         out, err = self.run_bzr('check --branch')
         self.assertContainsRe(err, r"^Checking branch at '.*'\.\n"
-                                   r"checked branch.*\n$")
+                                   r"checked branch.*")
 
     def test_check_repository(self):
         tree = self.make_branch_and_tree('.')
@@ -76,7 +76,7 @@
         out, err = self.run_bzr('check --tree --branch')
         self.assertContainsRe(err, r"^Checking working tree at '.*'\.\n"
                                    r"Checking branch at '.*'\.\n"
-                                   r"checked branch.*\n$")
+                                   r"checked branch.*")
 
     def test_check_missing_tree(self):
         branch = self.make_branch('.')
@@ -89,7 +89,7 @@
         self.assertContainsRe(err,
             r"^No working tree found at specified location\.\n"
             r"Checking branch at '.*'\.\n"
-            r"checked branch.*\n$")
+            r"checked branch.*")
 
     def test_check_missing_branch_in_shared_repo(self):
         self.make_repository('shared', shared=True)




More information about the bazaar-commits mailing list