Update --rebuild-if-* flags to rebuild when build dependencies are changed.
authorDavid James <davidjames@chromium.org>
Mon, 22 Aug 2011 23:29:13 +0000 (16:29 -0700)
committerZac Medico <zmedico@gentoo.org>
Fri, 26 Aug 2011 18:05:01 +0000 (11:05 -0700)
Right now, the --rebuild-if-* flags only rebuild packages that are used at
both run-time and build-time. This doesn't help for packages that are used
only at build-time (for example, static libaries).

Rebuilding packages whenever a build-time dependency is changed is easier to
understand and explain, and it handles all cases correctly.

BUG=chromium-os:15517
TEST=Run emerge test suite.

Change-Id: Iae8dab24e8acb6625bc1a0ce41862e90b232eb84

man/emerge.1
pym/_emerge/depgraph.py
pym/_emerge/help.py
pym/portage/tests/resolver/test_rebuild.py

index 4a19bdb269c45588f59e9c3074f6da097d375273..f7ad3ed5a8173bab29621ad5f8b0ab7f9e1bd60b 100644 (file)
@@ -556,18 +556,16 @@ to be set in the \fBmake.conf\fR(5)
 \fBEMERGE_DEFAULT_OPTS\fR variable.
 .TP
 .BR "\-\-rebuild\-if\-new\-rev [ y | n ]"
-Rebuild packages when dependencies that are used at both build\-time and
-run\-time are built, if the dependency is not already installed with the
-same version and revision.
+Rebuild packages when build\-time dependencies are built from source, if the
+dependency is not already installed with the same version and revision.
 .TP
 .BR "\-\-rebuild\-if\-new\-ver [ y | n ]"
-Rebuild packages when dependencies that are used at both build\-time and
-run\-time are built, if the dependency is not already installed with the
-same version. Revision numbers are ignored.
+Rebuild packages when build\-time dependencies are built from source, if the
+dependency is not already installed with the same version. Revision numbers
+are ignored.
 .TP
 .BR "\-\-rebuild\-if\-unbuilt [ y | n ]"
-Rebuild packages when dependencies that are used at both build\-time and
-run\-time are built.
+Rebuild packages when build\-time dependencies are built from source.
 .TP
 .BR "\-\-rebuilt\-binaries [ y | n ]"
 Replace installed packages with binary packages that have
index 8b6125d84dd17f1e4e5911df3357aaae31ecc61f..42cc659df0a398f27ccfa9fe4483db0c861c7ac9 100644 (file)
@@ -174,7 +174,7 @@ class _rebuild_config(object):
                rebuild_exclude = self._frozen_config.rebuild_exclude
                rebuild_ignore = self._frozen_config.rebuild_ignore
                if (self.rebuild and isinstance(parent, Package) and
-                       parent.built and (priority.buildtime or priority.runtime) and
+                       parent.built and priority.buildtime and
                        isinstance(dep_pkg, Package) and
                        not rebuild_exclude.findAtomForPackage(parent) and
                        not rebuild_ignore.findAtomForPackage(dep_pkg)):
@@ -209,66 +209,63 @@ class _rebuild_config(object):
 
                return True
 
-       def _trigger_rebuild(self, parent, build_deps, runtime_deps):
+       def _trigger_rebuild(self, parent, build_deps):
                root_slot = (parent.root, parent.slot_atom)
                if root_slot in self.rebuild_list:
                        return False
                trees = self._frozen_config.trees
-               children = set(build_deps).intersection(runtime_deps)
                reinstall = False
-               for slot_atom in children:
-                       kids = set([build_deps[slot_atom], runtime_deps[slot_atom]])
-                       for dep_pkg in kids:
-                               dep_root_slot = (dep_pkg.root, slot_atom)
-                               if self._needs_rebuild(dep_pkg):
+               for slot_atom, dep_pkg in build_deps.items():
+                       dep_root_slot = (dep_pkg.root, slot_atom)
+                       if self._needs_rebuild(dep_pkg):
+                               self.rebuild_list.add(root_slot)
+                               return True
+                       elif ("--usepkg" in self._frozen_config.myopts and
+                               (dep_root_slot in self.reinstall_list or
+                               dep_root_slot in self.rebuild_list or
+                               not dep_pkg.installed)):
+
+                               # A direct rebuild dependency is being installed. We
+                               # should update the parent as well to the latest binary,
+                               # if that binary is valid.
+                               #
+                               # To validate the binary, we check whether all of the
+                               # rebuild dependencies are present on the same binhost.
+                               #
+                               # 1) If parent is present on the binhost, but one of its
+                               #    rebuild dependencies is not, then the parent should
+                               #    be rebuilt from source.
+                               # 2) Otherwise, the parent binary is assumed to be valid,
+                               #    because all of its rebuild dependencies are
+                               #    consistent.
+                               bintree = trees[parent.root]["bintree"]
+                               uri = bintree.get_pkgindex_uri(parent.cpv)
+                               dep_uri = bintree.get_pkgindex_uri(dep_pkg.cpv)
+                               bindb = bintree.dbapi
+                               if self.rebuild_if_new_ver and uri and uri != dep_uri:
+                                       cpv_norev = catpkgsplit(dep_pkg.cpv)[:-1]
+                                       for cpv in bindb.match(dep_pkg.slot_atom):
+                                               if cpv_norev == catpkgsplit(cpv)[:-1]:
+                                                       dep_uri = bintree.get_pkgindex_uri(cpv)
+                                                       if uri == dep_uri:
+                                                               break
+                               if uri and uri != dep_uri:
+                                       # 1) Remote binary package is invalid because it was
+                                       #    built without dep_pkg. Force rebuild.
                                        self.rebuild_list.add(root_slot)
                                        return True
-                               elif ("--usepkg" in self._frozen_config.myopts and
-                                       (dep_root_slot in self.reinstall_list or
-                                       dep_root_slot in self.rebuild_list or
-                                       not dep_pkg.installed)):
-
-                                       # A direct rebuild dependency is being installed. We
-                                       # should update the parent as well to the latest binary,
-                                       # if that binary is valid.
-                                       #
-                                       # To validate the binary, we check whether all of the
-                                       # rebuild dependencies are present on the same binhost.
-                                       #
-                                       # 1) If parent is present on the binhost, but one of its
-                                       #    rebuild dependencies is not, then the parent should
-                                       #    be rebuilt from source.
-                                       # 2) Otherwise, the parent binary is assumed to be valid,
-                                       #    because all of its rebuild dependencies are
-                                       #    consistent.
-                                       bintree = trees[parent.root]["bintree"]
-                                       uri = bintree.get_pkgindex_uri(parent.cpv)
-                                       dep_uri = bintree.get_pkgindex_uri(dep_pkg.cpv)
-                                       bindb = bintree.dbapi
-                                       if self.rebuild_if_new_ver and uri and uri != dep_uri:
-                                               cpv_norev = catpkgsplit(dep_pkg.cpv)[:-1]
-                                               for cpv in bindb.match(dep_pkg.slot_atom):
-                                                       if cpv_norev == catpkgsplit(cpv)[:-1]:
-                                                               dep_uri = bintree.get_pkgindex_uri(cpv)
-                                                               if uri == dep_uri:
-                                                                       break
-                                       if uri and uri != dep_uri:
-                                               # 1) Remote binary package is invalid because it was
-                                               #    built without dep_pkg. Force rebuild.
-                                               self.rebuild_list.add(root_slot)
-                                               return True
-                                       elif (parent.installed and
-                                               root_slot not in self.reinstall_list):
-                                               inst_build_time = parent.metadata.get("BUILD_TIME")
-                                               try:
-                                                       bin_build_time, = bindb.aux_get(parent.cpv,
-                                                               ["BUILD_TIME"])
-                                               except KeyError:
-                                                       continue
-                                               if bin_build_time != inst_build_time:
-                                                       # 2) Remote binary package is valid, and local package
-                                                       #    is not up to date. Force reinstall.
-                                                       reinstall = True
+                               elif (parent.installed and
+                                       root_slot not in self.reinstall_list):
+                                       inst_build_time = parent.metadata.get("BUILD_TIME")
+                                       try:
+                                               bin_build_time, = bindb.aux_get(parent.cpv,
+                                                       ["BUILD_TIME"])
+                                       except KeyError:
+                                               continue
+                                       if bin_build_time != inst_build_time:
+                                               # 2) Remote binary package is valid, and local package
+                                               #    is not up to date. Force reinstall.
+                                               reinstall = True
                if reinstall:
                        self.reinstall_list.add(root_slot)
                return reinstall
@@ -282,31 +279,15 @@ class _rebuild_config(object):
                need_restart = False
                graph = self._graph
                build_deps = {}
-               runtime_deps = {}
-               leaf_nodes = deque(graph.leaf_nodes())
-
-               def ignore_non_runtime(priority):
-                       return not priority.runtime
 
-               def ignore_non_buildtime(priority):
-                       return not priority.buildtime
+               leaf_nodes = deque(graph.leaf_nodes())
 
                # Trigger rebuilds bottom-up (starting with the leaves) so that parents
                # will always know which children are being rebuilt.
                while graph:
                        if not leaf_nodes:
-                               # We're interested in intersection of buildtime and runtime,
-                               # so ignore edges that do not contain both.
-                               leaf_nodes.extend(graph.leaf_nodes(
-                                       ignore_priority=ignore_non_runtime))
-                               if not leaf_nodes:
-                                       leaf_nodes.extend(graph.leaf_nodes(
-                                               ignore_priority=ignore_non_buildtime))
-                                       if not leaf_nodes:
-                                               # We'll have to drop an edge that is both
-                                               # buildtime and runtime. This should be
-                                               # quite rare.
-                                               leaf_nodes.append(graph.order[-1])
+                               # We'll have to drop an edge. This should be quite rare.
+                               leaf_nodes.append(graph.order[-1])
 
                        node = leaf_nodes.popleft()
                        if node not in graph:
@@ -315,32 +296,23 @@ class _rebuild_config(object):
                        slot_atom = node.slot_atom
 
                        # Remove our leaf node from the graph, keeping track of deps.
-                       parents = graph.nodes[node][1].items()
+                       parents = graph.parent_nodes(node)
                        graph.remove(node)
                        node_build_deps = build_deps.get(node, {})
-                       node_runtime_deps = runtime_deps.get(node, {})
-                       for parent, priorities in parents:
+                       for parent in parents:
                                if parent == node:
                                        # Ignore a direct cycle.
                                        continue
                                parent_bdeps = build_deps.setdefault(parent, {})
-                               parent_rdeps = runtime_deps.setdefault(parent, {})
-                               for priority in priorities:
-                                       if priority.buildtime:
-                                               parent_bdeps[slot_atom] = node
-                                       if priority.runtime:
-                                               parent_rdeps[slot_atom] = node
-                               if slot_atom in parent_bdeps and slot_atom in parent_rdeps:
-                                       parent_rdeps.update(node_runtime_deps)
+                               parent_bdeps[slot_atom] = node
                                if not graph.child_nodes(parent):
                                        leaf_nodes.append(parent)
 
                        # Trigger rebuilds for our leaf node. Because all of our children
-                       # have been processed, build_deps and runtime_deps will be
-                       # completely filled in, and self.rebuild_list / self.reinstall_list
-                       # will tell us whether any of our children need to be rebuilt or
-                       # reinstalled.
-                       if self._trigger_rebuild(node, node_build_deps, node_runtime_deps):
+                       # have been processed, the build_deps will be completely filled in,
+                       # and self.rebuild_list / self.reinstall_list will tell us whether
+                       # any of our children need to be rebuilt or reinstalled.
+                       if self._trigger_rebuild(node, node_build_deps):
                                need_restart = True
 
                return need_restart
index c978ce255e7ce082cb49c4dd9969c36af7415b89..57b376d55bbac4c0c971b19d8a5b7eb6d523ed05 100644 (file)
@@ -641,26 +641,24 @@ def help(myopts, havecolor=1):
                print()
                print("       " + green("--rebuild-if-new-rev") + " [ %s | %s ]" % \
                        (turquoise("y"), turquoise("n")))
-               desc = "Rebuild packages when dependencies that are " + \
-                       "used at both build-time and run-time are built, " + \
-                       "if the dependency is not already installed with the " + \
-                       "same version and revision."
+               desc = "Rebuild packages when build-time dependencies are built " + \
+                       "from source, if the dependency is not already installed with " + \
+                       "the same version and revision."
                for line in wrap(desc, desc_width):
                        print(desc_indent + line)
                print()
                print("       " + green("--rebuild-if-new-ver") + " [ %s | %s ]" % \
                        (turquoise("y"), turquoise("n")))
-               desc = "Rebuild packages when dependencies that are " + \
-                       "used at both build-time and run-time are built, " + \
-                       "if the dependency is not already installed with the " + \
-                       "same version. Revision numbers are ignored."
+               desc = "Rebuild packages when build-time dependencies are built " + \
+                       "from source, if the dependency is not already installed with " + \
+                       "the same version. Revision numbers are ignored."
                for line in wrap(desc, desc_width):
                        print(desc_indent + line)
                print()
                print("       " + green("--rebuild-if-unbuilt") + " [ %s | %s ]" % \
                        (turquoise("y"), turquoise("n")))
-               desc = "Rebuild packages when dependencies that are " + \
-                       "used at both build-time and run-time are built."
+               desc = "Rebuild packages when build-time dependencies are built " + \
+                       "from source"
                for line in wrap(desc, desc_width):
                        print(desc_indent + line)
                print()
index b9c4d6d65c91691d14556eaaa65f3a5fa2037aff..6f1a7834b44f9ee885ceb077a05f2f18732f4ce6 100644 (file)
@@ -9,57 +9,58 @@ class RebuildTestCase(TestCase):
 
        def testRebuild(self):
                """
-               Rebuild packages when dependencies that are used at both build-time and
-               run-time are upgraded.
+               Rebuild packages when build-time dependencies are upgraded.
                """
 
                ebuilds = {
                        "sys-libs/x-1": { },
                        "sys-libs/x-1-r1": { },
                        "sys-libs/x-2": { },
-                       "sys-apps/a-1": { "DEPEND"  : "sys-libs/x", "RDEPEND" : "sys-libs/x"},
-                       "sys-apps/a-2": { "DEPEND"  : "sys-libs/x", "RDEPEND" : "sys-libs/x"},
-                       "sys-apps/b-1": { "DEPEND"  : "sys-libs/x", "RDEPEND" : "sys-libs/x"},
-                       "sys-apps/b-2": { "DEPEND"  : "sys-libs/x", "RDEPEND" : "sys-libs/x"},
+                       "sys-apps/a-1": { "DEPEND"  : "sys-libs/x", "RDEPEND" : ""},
+                       "sys-apps/a-2": { "DEPEND"  : "sys-libs/x", "RDEPEND" : ""},
+                       "sys-apps/b-1": { "DEPEND"  : "sys-libs/x", "RDEPEND" : ""},
+                       "sys-apps/b-2": { "DEPEND"  : "sys-libs/x", "RDEPEND" : ""},
                        "sys-apps/c-1": { "DEPEND"  : "sys-libs/x", "RDEPEND" : ""},
                        "sys-apps/c-2": { "DEPEND"  : "sys-libs/x", "RDEPEND" : ""},
                        "sys-apps/d-1": { "RDEPEND" : "sys-libs/x"},
                        "sys-apps/d-2": { "RDEPEND" : "sys-libs/x"},
-                       "sys-apps/e-2": { "DEPEND"  : "sys-libs/x", "RDEPEND" : "sys-libs/x"},
-                       "sys-apps/f-2": { "DEPEND"  : "sys-apps/a", "RDEPEND" : "sys-apps/a"},
+                       "sys-apps/e-2": { "DEPEND"  : "sys-libs/x", "RDEPEND" : ""},
+                       "sys-apps/f-2": { "DEPEND"  : "sys-apps/a", "RDEPEND" : ""},
                        "sys-apps/g-2": { "DEPEND"  : "sys-apps/b sys-libs/x",
-                               "RDEPEND" : "sys-apps/b"},
+                               "RDEPEND" : ""},
                        }
 
                installed = {
                        "sys-libs/x-1": { },
-                       "sys-apps/a-1": { "DEPEND"  : "sys-libs/x", "RDEPEND" : "sys-libs/x"},
-                       "sys-apps/b-1": { "DEPEND"  : "sys-libs/x", "RDEPEND" : "sys-libs/x"},
+                       "sys-apps/a-1": { "DEPEND"  : "sys-libs/x", "RDEPEND" : ""},
+                       "sys-apps/b-1": { "DEPEND"  : "sys-libs/x", "RDEPEND" : ""},
                        "sys-apps/c-1": { "DEPEND"  : "sys-libs/x", "RDEPEND" : ""},
                        "sys-apps/d-1": { "RDEPEND" : "sys-libs/x"},
-                       "sys-apps/e-1": { "DEPEND"  : "sys-libs/x", "RDEPEND" : "sys-libs/x"},
-                       "sys-apps/f-1": { "DEPEND"  : "sys-apps/a", "RDEPEND" : "sys-apps/a"},
-                       "sys-apps/g-1": { "DEPEND"  : "sys-apps/b sys-libs/x",
-                               "RDEPEND" : "sys-apps/b"},
+                       "sys-apps/e-1": { "DEPEND"  : "sys-libs/x", "RDEPEND" : ""},
+                       "sys-apps/f-1": { "DEPEND"  : "sys-apps/a", "RDEPEND" : ""},
+                       "sys-apps/g-1": { "DEPEND"  : "sys-apps/b",
+                               "RDEPEND" : ""},
                        }
 
                world = ["sys-apps/a", "sys-apps/b", "sys-apps/c", "sys-apps/d",
                        "sys-apps/e", "sys-apps/f", "sys-apps/g"]
 
+
                test_cases = (
                                ResolverPlaygroundTestCase(
-                                       ["sys-libs/x"],
+                                       ["sys-libs/x", "sys-apps/b"],
                                        options = {"--rebuild-if-unbuilt" : True,
-                                               "--rebuild-exclude" : ["sys-apps/b"]},
-                                       mergelist = ['sys-libs/x-2', 'sys-apps/a-2', 'sys-apps/e-2'],
+                                               "--rebuild-exclude" : ["sys-apps/c"]},
+                                       mergelist = ['sys-libs/x-2', 'sys-apps/a-2', 'sys-apps/b-2',
+                                               'sys-apps/e-2', 'sys-apps/g-2'],
                                        ignore_mergelist_order = True,
                                        success = True),
 
                                ResolverPlaygroundTestCase(
-                                       ["sys-libs/x"],
+                                       ["sys-libs/x", "sys-apps/b"],
                                        options = {"--rebuild-if-unbuilt" : True},
                                        mergelist = ['sys-libs/x-2', 'sys-apps/a-2', 'sys-apps/b-2',
-                                               'sys-apps/e-2', 'sys-apps/g-2'],
+                                               'sys-apps/c-2', 'sys-apps/e-2', 'sys-apps/g-2'],
                                        ignore_mergelist_order = True,
                                        success = True),
 
@@ -72,27 +73,29 @@ class RebuildTestCase(TestCase):
                                        success = True),
 
                                ResolverPlaygroundTestCase(
-                                       ["sys-libs/x"],
+                                       ["sys-libs/x", "sys-apps/b"],
                                        options = {"--rebuild-if-unbuilt" : True,
                                                "--rebuild-ignore" : ["sys-apps/b"]},
                                        mergelist = ['sys-libs/x-2', 'sys-apps/a-2', 'sys-apps/b-2',
-                                               'sys-apps/e-2'],
+                                               'sys-apps/c-2', 'sys-apps/e-2'],
                                        ignore_mergelist_order = True,
                                        success = True),
 
                                ResolverPlaygroundTestCase(
-                                       ["=sys-libs/x-1-r1"],
+                                       ["=sys-libs/x-1-r1", "sys-apps/b"],
                                        options = {"--rebuild-if-unbuilt" : True},
                                        mergelist = ['sys-libs/x-1-r1', 'sys-apps/a-2',
-                                               'sys-apps/b-2', 'sys-apps/e-2', 'sys-apps/g-2'],
+                                               'sys-apps/b-2', 'sys-apps/c-2', 'sys-apps/e-2',
+                                               'sys-apps/g-2'],
                                        ignore_mergelist_order = True,
                                        success = True),
 
                                ResolverPlaygroundTestCase(
-                                       ["=sys-libs/x-1-r1"],
+                                       ["=sys-libs/x-1-r1", "sys-apps/b"],
                                        options = {"--rebuild-if-new-rev" : True},
                                        mergelist = ['sys-libs/x-1-r1', 'sys-apps/a-2',
-                                               'sys-apps/b-2', 'sys-apps/e-2', 'sys-apps/g-2'],
+                                               'sys-apps/b-2', 'sys-apps/c-2', 'sys-apps/e-2',
+                                               'sys-apps/g-2'],
                                        ignore_mergelist_order = True,
                                        success = True),
 
@@ -104,10 +107,11 @@ class RebuildTestCase(TestCase):
                                        success = True),
 
                                ResolverPlaygroundTestCase(
-                                       ["sys-libs/x"],
+                                       ["sys-libs/x", "sys-apps/b"],
                                        options = {"--rebuild-if-new-ver" : True},
                                        mergelist = ['sys-libs/x-2', 'sys-apps/a-2',
-                                               'sys-apps/b-2', 'sys-apps/e-2', 'sys-apps/g-2'],
+                                               'sys-apps/b-2', 'sys-apps/c-2', 'sys-apps/e-2',
+                                               'sys-apps/g-2'],
                                        ignore_mergelist_order = True,
                                        success = True),
 
@@ -119,10 +123,11 @@ class RebuildTestCase(TestCase):
                                        success = True),
 
                                ResolverPlaygroundTestCase(
-                                       ["=sys-libs/x-1"],
+                                       ["=sys-libs/x-1", "=sys-apps/b-1"],
                                        options = {"--rebuild-if-unbuilt" : True},
                                        mergelist = ['sys-libs/x-1', 'sys-apps/a-2',
-                                               'sys-apps/b-2', 'sys-apps/e-2', 'sys-apps/g-2'],
+                                               'sys-apps/b-1', 'sys-apps/c-2', 'sys-apps/e-2',
+                                               'sys-apps/g-2'],
                                        ignore_mergelist_order = True,
                                        success = True),
                        )