From 2f253bcc364bd75c9b103133a17ea9887a3de15d Mon Sep 17 00:00:00 2001 From: David James Date: Mon, 22 Aug 2011 16:29:13 -0700 Subject: Update --rebuild-if-* flags to rebuild when build dependencies are changed. 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 | 14 ++- pym/_emerge/depgraph.py | 150 ++++++++++++----------------- pym/_emerge/help.py | 18 ++-- pym/portage/tests/resolver/test_rebuild.py | 65 +++++++------ 4 files changed, 110 insertions(+), 137 deletions(-) diff --git a/man/emerge.1 b/man/emerge.1 index 4a19bdb26..f7ad3ed5a 100644 --- a/man/emerge.1 +++ b/man/emerge.1 @@ -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 diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py index 8b6125d84..42cc659df 100644 --- a/pym/_emerge/depgraph.py +++ b/pym/_emerge/depgraph.py @@ -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 diff --git a/pym/_emerge/help.py b/pym/_emerge/help.py index c978ce255..57b376d55 100644 --- a/pym/_emerge/help.py +++ b/pym/_emerge/help.py @@ -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() diff --git a/pym/portage/tests/resolver/test_rebuild.py b/pym/portage/tests/resolver/test_rebuild.py index b9c4d6d65..6f1a7834b 100644 --- a/pym/portage/tests/resolver/test_rebuild.py +++ b/pym/portage/tests/resolver/test_rebuild.py @@ -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), ) -- cgit v1.2.3-1-g7c22