diff --git a/conans/client/graph/graph_binaries.py b/conans/client/graph/graph_binaries.py index b1850ce5373..b03bad52170 100644 --- a/conans/client/graph/graph_binaries.py +++ b/conans/client/graph/graph_binaries.py @@ -96,7 +96,7 @@ def _evaluate_cache_pkg(self, node, package_layout, pref, metadata, remote, remo node.prev = metadata.packages[pref.id].revision assert node.prev, "PREV for %s is None: %s" % (str(pref), metadata.dumps()) - def _evaluate_remote_pkg(self, node, pref, remote, remotes, build_mode): + def _evaluate_remote_pkg(self, node, pref, remote, remotes): remote_info = None if remote: try: @@ -126,11 +126,8 @@ def _evaluate_remote_pkg(self, node, pref, remote, remotes, build_mode): recipe_hash = remote_info.recipe_hash else: recipe_hash = None - if build_mode.allowed(node.conanfile): - node.binary = BINARY_BUILD - else: - node.binary = BINARY_MISSING node.prev = None + node.binary = BINARY_MISSING return recipe_hash, remote @@ -162,33 +159,37 @@ def _evaluate_node(self, node, build_mode, update, remotes): if locked and locked.pref.id == node.package_id: pref = locked.pref # Keep the locked with PREV self._process_node(node, pref, build_mode, update, remotes) + if node.binary == BINARY_MISSING and build_mode.allowed(node.conanfile): + node.binary = BINARY_BUILD else: assert node.prev is None, "Non locked node shouldn't have PREV in evaluate_node" pref = PackageReference(node.ref, node.package_id) self._process_node(node, pref, build_mode, update, remotes) - if node.binary == BINARY_MISSING and node.conanfile.compatible_packages: - compatible_build_mode = BuildMode(None, self._out) - for compatible_package in node.conanfile.compatible_packages: - package_id = compatible_package.package_id() - if package_id == node.package_id: - node.conanfile.output.info("Compatible package ID %s equal to the default " - "package ID" % package_id) - continue - pref = PackageReference(node.ref, package_id) - node.binary = None # Invalidate it - # NO Build mode - self._process_node(node, pref, compatible_build_mode, update, remotes) - if node.binary and node.binary != BINARY_MISSING: - node.conanfile.output.info("Main binary package '%s' missing. Using " - "compatible package '%s'" - % (node.package_id, package_id)) - node._package_id = package_id - # So they are available in package_info() method - node.conanfile.settings.values = compatible_package.settings - node.conanfile.options.values = compatible_package.options - break - else: - node.binary = BINARY_MISSING + if node.binary == BINARY_MISSING: + if node.conanfile.compatible_packages: + compatible_build_mode = BuildMode(None, self._out) + for compatible_package in node.conanfile.compatible_packages: + package_id = compatible_package.package_id() + if package_id == node.package_id: + node.conanfile.output.info("Compatible package ID %s equal to the " + "default package ID" % package_id) + continue + pref = PackageReference(node.ref, package_id) + node.binary = None # Invalidate it + # NO Build mode + self._process_node(node, pref, compatible_build_mode, update, remotes) + assert node.binary is not None + if node.binary != BINARY_MISSING: + node.conanfile.output.info("Main binary package '%s' missing. Using " + "compatible package '%s'" + % (node.package_id, package_id)) + node._package_id = package_id + # So they are available in package_info() method + node.conanfile.settings.values = compatible_package.settings + node.conanfile.options.values = compatible_package.options + break + if node.binary == BINARY_MISSING and build_mode.allowed(node.conanfile): + node.binary = BINARY_BUILD def _process_node(self, node, pref, build_mode, update, remotes): # Check that this same reference hasn't already been checked @@ -221,7 +222,7 @@ def _process_node(self, node, pref, build_mode, update, remotes): recipe_hash = None else: # Binary does NOT exist locally # Returned remote might be different than the passed one if iterating remotes - recipe_hash, remote = self._evaluate_remote_pkg(node, pref, remote, remotes, build_mode) + recipe_hash, remote = self._evaluate_remote_pkg(node, pref, remote, remotes) if build_mode.outdated: if node.binary in (BINARY_CACHE, BINARY_DOWNLOAD, BINARY_UPDATE): diff --git a/conans/test/functional/package_id/compatible_test.py b/conans/test/functional/package_id/compatible_test.py index 6523605010c..36b54527506 100644 --- a/conans/test/functional/package_id/compatible_test.py +++ b/conans/test/functional/package_id/compatible_test.py @@ -440,3 +440,28 @@ def package_info(self): client.out) self.assertIn("consumer/0.1@user/stable: Package 'fca9e94084ed6fe0ca149dc9c2d54c0f336f0d7e'" " created", client.out) + + def build_missing_test(self): + # https://github.com/conan-io/conan/issues/6133 + client = TestClient() + conanfile = textwrap.dedent(""" + from conans import ConanFile + + class Conan(ConanFile): + settings = "os" + + def package_id(self): + if self.settings.os == "Windows": + compatible = self.info.clone() + compatible.settings.os = "Linux" + self.compatible_packages.append(compatible) + """) + + client.save({"conanfile.py": conanfile}) + client.run("create . pkg/0.1@user/testing -s os=Linux") + + client.save({"conanfile.py": GenConanfile().with_require_plain("pkg/0.1@user/testing")}) + client.run("install . -s os=Windows --build=missing") + self.assertIn("pkg/0.1@user/testing:cb054d0b3e1ca595dc66bc2339d40f1f8f04ab31 - Cache", + client.out) + self.assertIn("pkg/0.1@user/testing: Already installed!", client.out)