diff --git a/conans/client/conan_api.py b/conans/client/conan_api.py index be31ecb8668..75d19223907 100644 --- a/conans/client/conan_api.py +++ b/conans/client/conan_api.py @@ -478,7 +478,8 @@ def workspace_install(self, path, settings=None, options=None, env=None, node.conanfile.generators = tmp installer = BinaryInstaller(self.app, recorder=recorder) - installer.install(deps_graph, remotes, keep_build=False, graph_info=graph_info) + installer.install(deps_graph, remotes, build, update, keep_build=False, + graph_info=graph_info) install_folder = install_folder or cwd workspace.generate(install_folder, deps_graph, self.app.out) diff --git a/conans/client/graph/graph_binaries.py b/conans/client/graph/graph_binaries.py index 1027aefa5f1..126a55178ef 100644 --- a/conans/client/graph/graph_binaries.py +++ b/conans/client/graph/graph_binaries.py @@ -4,8 +4,7 @@ BINARY_SKIP, BINARY_UPDATE, RECIPE_EDITABLE, BINARY_EDITABLE, RECIPE_CONSUMER, RECIPE_VIRTUAL) -from conans.errors import NoRemoteAvailable, NotFoundException, \ - conanfile_exception_formatter +from conans.errors import NoRemoteAvailable, NotFoundException, conanfile_exception_formatter from conans.model.info import ConanInfo, PACKAGE_ID_UNKNOWN from conans.model.manifest import FileTreeManifest from conans.model.ref import PackageReference @@ -154,6 +153,7 @@ def _evaluate_is_cached(self, node, pref): def _evaluate_node(self, node, build_mode, update, remotes): assert node.binary is None, "Node.binary should be None" assert node.package_id is not None, "Node.package_id shouldn't be None" + assert node.package_id != PACKAGE_ID_UNKNOWN, "Node.package_id shouldn't be Unknown" assert node.prev is None, "Node.prev should be None" if node.package_id == PACKAGE_ID_UNKNOWN: @@ -161,6 +161,7 @@ def _evaluate_node(self, node, build_mode, update, remotes): return ref, conanfile = node.ref, node.conanfile + # If it has lock locked = node.graph_lock_node if locked and locked.pref.id == node.package_id: @@ -219,27 +220,46 @@ def _evaluate_node(self, node, build_mode, update, remotes): node.binary_remote = remote @staticmethod - def _compute_package_id(node, default_package_id_mode): + def _propagate_options(node): + # TODO: This has to be moved to the graph computation, not here in the BinaryAnalyzer + # as this is the graph model conanfile = node.conanfile neighbors = node.neighbors() - direct_reqs = [] # of PackageReference - indirect_reqs = set() # of PackageReference, avoid duplicates + transitive_reqs = set() # of PackageReference, avoid duplicates for neighbor in neighbors: ref, nconan = neighbor.ref, neighbor.conanfile - direct_reqs.append(neighbor.pref) - indirect_reqs.update(nconan.info.requires.refs()) + transitive_reqs.add(neighbor.pref) + transitive_reqs.update(nconan.info.requires.refs()) + conanfile.options.propagate_downstream(ref, nconan.info.full_options) # Might be never used, but update original requirement, just in case conanfile.requires[ref.name].ref = ref - # Make sure not duplicated - indirect_reqs.difference_update(direct_reqs) - # There might be options that are not upstream, backup them, might be - # for build-requires + # There might be options that are not upstream, backup them, might be for build-requires conanfile.build_requires_options = conanfile.options.values - conanfile.options.clear_unused(indirect_reqs.union(direct_reqs)) + conanfile.options.clear_unused(transitive_reqs) conanfile.options.freeze() + @staticmethod + def _compute_package_id(node, default_package_id_mode): + """ + Compute the binary package ID of this node + :param node: the node to compute the package-ID + :param default_package_id_mode: configuration of the package-ID mode + """ + # TODO Conan 2.0. To separate the propagation of the graph (options) of the package-ID + # A bit risky to be done now + conanfile = node.conanfile + neighbors = node.neighbors() + direct_reqs = [] # of PackageReference + indirect_reqs = set() # of PackageReference, avoid duplicates + for neighbor in neighbors: + ref, nconan = neighbor.ref, neighbor.conanfile + direct_reqs.append(neighbor.pref) + indirect_reqs.update(nconan.info.requires.refs()) + + # Make sure not duplicated + indirect_reqs.difference_update(direct_reqs) conanfile.info = ConanInfo.create(conanfile.settings.values, conanfile.options.values, direct_reqs, @@ -270,8 +290,30 @@ def _handle_private(self, node): def evaluate_graph(self, deps_graph, build_mode, update, remotes): default_package_id_mode = self._cache.config.default_package_id_mode for node in deps_graph.ordered_iterate(): + self._propagate_options(node) self._compute_package_id(node, default_package_id_mode) if node.recipe in (RECIPE_CONSUMER, RECIPE_VIRTUAL): continue + if node.package_id == PACKAGE_ID_UNKNOWN: + assert node.binary is None + continue self._evaluate_node(node, build_mode, update, remotes) self._handle_private(node) + + def reevaluate_node(self, node, remotes, build_mode, update): + assert node.binary is None + output = node.conanfile.output + node._package_id = None # Invalidate it, so it can be re-computed + default_package_id_mode = self._cache.config.default_package_id_mode + output.info("Unknown binary for %s, computing updated ID" % str(node.ref)) + self._compute_package_id(node, default_package_id_mode) + output.info("Updated ID: %s" % node.package_id) + if node.recipe in (RECIPE_CONSUMER, RECIPE_VIRTUAL): + return + assert node.package_id != PACKAGE_ID_UNKNOWN + self._evaluate_node(node, build_mode, update, remotes) + output.info("Binary for updated ID from: %s" % node.binary) + if node.binary == BINARY_BUILD: + output.info("Binary for the updated ID has to be built") + else: + output.info("Binary for the updated ID from: %s" % node.binary) diff --git a/conans/client/graph/graph_manager.py b/conans/client/graph/graph_manager.py index 022caa6b94f..c1f911df304 100644 --- a/conans/client/graph/graph_manager.py +++ b/conans/client/graph/graph_manager.py @@ -14,6 +14,7 @@ from conans.model.ref import ConanFileReference from conans.paths import BUILD_INFO from conans.util.files import load +from conans.model.info import PACKAGE_ID_UNKNOWN class _RecipeBuildRequires(OrderedDict): @@ -230,8 +231,9 @@ def _recurse_build_requires(self, graph, subgraph, builder, check_updates, # FIXME: To be improved and build a explicit model for this if node.recipe == RECIPE_VIRTUAL: continue + # Packages with PACKAGE_ID_UNKNOWN might be built in the future, need build requires if (node.binary not in (BINARY_BUILD, BINARY_EDITABLE) - and node.recipe != RECIPE_CONSUMER): + and node.recipe != RECIPE_CONSUMER and node.package_id != PACKAGE_ID_UNKNOWN): continue package_build_requires = self._get_recipe_build_requires(node.conanfile) str_ref = str(node.ref) diff --git a/conans/client/installer.py b/conans/client/installer.py index 342debc208e..5ef60c6ceae 100644 --- a/conans/client/installer.py +++ b/conans/client/installer.py @@ -20,6 +20,7 @@ from conans.model.editable_layout import EditableLayout from conans.model.env_info import EnvInfo from conans.model.graph_info import GraphInfo +from conans.model.info import PACKAGE_ID_UNKNOWN from conans.model.manifest import FileTreeManifest from conans.model.ref import PackageReference from conans.model.user_info import UserInfo @@ -294,17 +295,18 @@ def __init__(self, app, recorder): self._out = app.out self._remote_manager = app.remote_manager self._recorder = recorder + self._binaries_analyzer = app.binaries_analyzer self._hook_manager = app.hook_manager - def install(self, deps_graph, remotes, keep_build=False, graph_info=None): + def install(self, deps_graph, remotes, build_mode, update, keep_build=False, graph_info=None): # order by levels and separate the root node (ref=None) from the rest nodes_by_level = deps_graph.by_levels() root_level = nodes_by_level.pop() root_node = root_level[0] # Get the nodes in order and if we have to build them - self._build(nodes_by_level, keep_build, root_node, graph_info, remotes) + self._build(nodes_by_level, keep_build, root_node, graph_info, remotes, build_mode, update) - def _build(self, nodes_by_level, keep_build, root_node, graph_info, remotes): + def _build(self, nodes_by_level, keep_build, root_node, graph_info, remotes, build_mode, update): processed_package_refs = set() for level in nodes_by_level: for node in level: @@ -324,12 +326,15 @@ def _build(self, nodes_by_level, keep_build, root_node, graph_info, remotes): continue assert ref.revision is not None, "Installer should receive RREV always" _handle_system_requirements(conan_file, node.pref, self._cache, output) + if node.package_id == PACKAGE_ID_UNKNOWN: + self._binaries_analyzer.reevaluate_node(node, remotes, build_mode, update) self._handle_node_cache(node, keep_build, processed_package_refs, remotes) # Finally, propagate information to root node (ref=None) self._propagate_info(root_node) - def _node_concurrently_installed(self, node, package_folder): + @staticmethod + def _node_concurrently_installed(node, package_folder): if node.binary == BINARY_DOWNLOAD and os.path.exists(package_folder): return True elif node.binary == BINARY_UPDATE: @@ -376,7 +381,7 @@ def _handle_node_editable(self, node, graph_info): def _handle_node_cache(self, node, keep_build, processed_package_references, remotes): pref = node.pref assert pref.id, "Package-ID without value" - + assert pref.id != PACKAGE_ID_UNKNOWN, "Package-ID error: %s" % str(pref) conanfile = node.conanfile output = conanfile.output diff --git a/conans/client/manager.py b/conans/client/manager.py index b85066b73c8..5868aacd913 100644 --- a/conans/client/manager.py +++ b/conans/client/manager.py @@ -1,6 +1,7 @@ import os from conans.client.generators import write_generators +from conans.client.graph.build_mode import BuildMode from conans.client.graph.graph import RECIPE_CONSUMER, RECIPE_VIRTUAL from conans.client.graph.printer import print_graph from conans.client.importer import run_deploy, run_imports @@ -61,7 +62,10 @@ def deps_install(app, ref_or_path, install_folder, graph_info, remotes=None, bui pass installer = BinaryInstaller(app, recorder=recorder) - installer.install(deps_graph, remotes, keep_build=keep_build, graph_info=graph_info) + # TODO: Extract this from the GraphManager, reuse same object, check args earlier + build_modes = BuildMode(build_modes, out) + installer.install(deps_graph, remotes, build_modes, update, keep_build=keep_build, + graph_info=graph_info) # GraphLock always != None here (because of graph_manager.load_graph) graph_info.graph_lock.update_check_graph(deps_graph, out) diff --git a/conans/model/graph_lock.py b/conans/model/graph_lock.py index 578d67cdd65..af2c2238c39 100644 --- a/conans/model/graph_lock.py +++ b/conans/model/graph_lock.py @@ -5,6 +5,7 @@ BINARY_BUILD from conans.client.profile_loader import _load_profile from conans.errors import ConanException +from conans.model.info import PACKAGE_ID_UNKNOWN from conans.model.options import OptionsValues from conans.model.ref import PackageReference, ConanFileReference from conans.util.files import load, save @@ -237,7 +238,7 @@ def update_check_graph(self, deps_graph, output): node_pref = node.pref.copy_clear_revs() if not self.revisions_enabled else node.pref # If the update is compatible (resolved complete PREV) or if the node has # been build, then update the graph - if pref.is_compatible_with(node_pref) or \ + if pref.id == PACKAGE_ID_UNKNOWN or pref.is_compatible_with(node_pref) or \ node.binary == BINARY_BUILD or node.id in affected: lock_node.pref = node.pref else: diff --git a/conans/model/options.py b/conans/model/options.py index 651647d527e..878d00716f8 100644 --- a/conans/model/options.py +++ b/conans/model/options.py @@ -610,10 +610,10 @@ def propagate_downstream(self, ref, options): for k, v in options._reqs_options.items(): self._deps_package_values[k] = v.copy() - def clear_unused(self, references): + def clear_unused(self, prefs): """ remove all options not related to the passed references, that should be the upstream requirements """ - existing_names = [r.ref.name for r in references] + existing_names = [pref.ref.name for pref in prefs] self._deps_package_values = {k: v for k, v in self._deps_package_values.items() if k in existing_names} diff --git a/conans/test/functional/command/upload_test.py b/conans/test/functional/command/upload_test.py index cf39e082a4c..67adaf912c7 100644 --- a/conans/test/functional/command/upload_test.py +++ b/conans/test/functional/command/upload_test.py @@ -16,6 +16,7 @@ from conans.test.utils.cpp_test_files import cpp_hello_conan_files from conans.test.utils.tools import NO_SETTINGS_PACKAGE_ID, TestClient, TestServer, \ TurboTestClient, GenConanfile +from conans.util.env_reader import get_env from conans.util.files import gzopen_without_timestamps, is_dirty, save conanfile = """from conans import ConanFile @@ -621,6 +622,7 @@ def upload_login_prompt_disabled_user_authenticated_test(self): self.assertIn("Uploading conanfile.py", client.out) self.assertIn("Uploading conan_export.tgz", client.out) + @unittest.skipUnless(get_env("TESTING_REVISIONS_ENABLED", False), "Only revisions") def upload_key_error_test(self): files = cpp_hello_conan_files("Hello0", "1.2.1", build=False) server1 = TestServer([("*/*@*/*", "*")], [("*/*@*/*", "*")], users={"lasote": "mypass"}) @@ -630,7 +632,6 @@ def upload_key_error_test(self): servers["server2"] = server2 client = TestClient(servers=servers) client.save(files) - client.run("config set general.revisions_enabled=True") client.run("create . user/testing") client.run("user lasote -p mypass") client.run("user lasote -p mypass -r server2") diff --git a/conans/test/functional/graph/full_revision_mode_test.py b/conans/test/functional/graph/full_revision_mode_test.py index df6099574f1..fa553b5d307 100644 --- a/conans/test/functional/graph/full_revision_mode_test.py +++ b/conans/test/functional/graph/full_revision_mode_test.py @@ -60,26 +60,224 @@ def package(self): clienta.run("create . liba/0.1@user/testing") clientc.run("info . --build-order=ALL") - def reusing_artifacts_after_build_test(self): - # An unknown binary that after build results in the exact same PREF with PREV, doesn't - # fire build of downstream - client = TestClient() - client.run("config set general.default_package_id_mode=package_revision_mode") + def binary_id_recomputation_after_build_test(self): + clienta = TestClient() + clienta.run("config set general.default_package_id_mode=recipe_revision_mode") conanfile = dedent(""" from conans import ConanFile + from conans.tools import save + import uuid, os class Pkg(ConanFile): - pass %s + def package(self): + save(os.path.join(self.package_folder, "file.txt"), + str(uuid.uuid1())) """) - client.save({"conanfile.py": conanfile % ""}) + clienta.save({"conanfile.py": conanfile % ""}) + clienta.run("create . liba/0.1@user/testing") + + clientb = TestClient(cache_folder=clienta.cache_folder) + clientb.save({"conanfile.py": conanfile % "requires = 'liba/0.1@user/testing'"}) + clientb.run("config set general.default_package_id_mode=package_revision_mode") + clientb.run("create . libb/0.1@user/testing") + + clientc = TestClient(cache_folder=clienta.cache_folder) + clientc.save({"conanfile.py": conanfile % "requires = 'libb/0.1@user/testing'"}) + clientc.run("config set general.default_package_id_mode=package_revision_mode") + clientc.run("create . libc/0.1@user/testing") + + clientd = TestClient(cache_folder=clienta.cache_folder) + clientd.run("config set general.default_package_id_mode=package_revision_mode") + clientd.save({"conanfile.py": conanfile % "requires = 'libc/0.1@user/testing'"}) + clientd.run("install . libd/0.1@user/testing") + + # Change A PREV + clienta.run("create . liba/0.1@user/testing") + clientd.run("install . libd/0.1@user/testing", assert_error=True) + self.assertIn("ERROR: Missing prebuilt package for 'libb/0.1@user/testing'", clientd.out) + clientd.run("install . libd/0.1@user/testing --build=missing") + + self.assertIn("libc/0.1@user/testing: Unknown binary", clientd.out) + self.assertIn("libc/0.1@user/testing: Updated ID", clientd.out) + self.assertIn("libc/0.1@user/testing: Binary for the updated ID has to be built", + clientd.out) + self.assertIn("libc/0.1@user/testing: Calling build()", clientd.out) + + def binary_id_recomputation_with_build_requires_test(self): + clienta = TestClient() + clienta.save({"conanfile.py": GenConanfile().with_name("Tool").with_version("0.1") + .with_package_info(cpp_info={"libs": + ["tool.lib"]}, + env_info={})}) + clienta.run("create . user/testing") + clienta.run("config set general.default_package_id_mode=recipe_revision_mode") + conanfile = dedent(""" + from conans import ConanFile + from conans.tools import save + import uuid, os + class Pkg(ConanFile): + build_requires = "Tool/0.1@user/testing" + %s + def build(self): + self.output.info("TOOLS LIBS: {}".format(self.deps_cpp_info["Tool"].libs)) + def package(self): + save(os.path.join(self.package_folder, "file.txt"), + str(uuid.uuid1())) + """) + clienta.save({"conanfile.py": conanfile % ""}) + clienta.run("create . liba/0.1@user/testing") + + clientb = TestClient(cache_folder=clienta.cache_folder) + clientb.save({"conanfile.py": conanfile % "requires = 'liba/0.1@user/testing'"}) + clientb.run("config set general.default_package_id_mode=package_revision_mode") + clientb.run("create . libb/0.1@user/testing") + + clientc = TestClient(cache_folder=clienta.cache_folder) + clientc.save({"conanfile.py": conanfile % "requires = 'libb/0.1@user/testing'"}) + clientc.run("config set general.default_package_id_mode=package_revision_mode") + clientc.run("create . libc/0.1@user/testing") + + clientd = TestClient(cache_folder=clienta.cache_folder) + clientd.run("config set general.default_package_id_mode=package_revision_mode") + clientd.save({"conanfile.py": conanfile % "requires = 'libc/0.1@user/testing'"}) + clientd.run("install . libd/0.1@user/testing") + + # Change A PREV + clienta.run("create . liba/0.1@user/testing") + clientd.run("install . libd/0.1@user/testing", assert_error=True) + self.assertIn("ERROR: Missing prebuilt package for 'libb/0.1@user/testing'", clientd.out) + clientd.run("install . libd/0.1@user/testing --build=missing") + + self.assertIn("libc/0.1@user/testing: Unknown binary", clientd.out) + self.assertIn("libc/0.1@user/testing: Updated ID", clientd.out) + self.assertIn("libc/0.1@user/testing: Binary for the updated ID has to be built", + clientd.out) + self.assertIn("libc/0.1@user/testing: Calling build()", clientd.out) + + def reusing_artifacts_after_build_test(self): + # An unknown binary that after build results in the exact same PREF with PREV, doesn't + # fire build of downstream + client = TestClient() + client.run("config set general.default_package_id_mode=package_revision_mode") + client.save({"conanfile.py": GenConanfile()}) client.run("create . liba/0.1@user/testing") - client.save({"conanfile.py": conanfile % "requires = 'liba/0.1@user/testing'"}) + client.save({"conanfile.py": GenConanfile().with_require_plain('liba/0.1@user/testing')}) client.run("create . libb/0.1@user/testing") - client.save({"conanfile.py": conanfile % "requires = 'libb/0.1@user/testing'"}) + client.save({"conanfile.py": GenConanfile().with_require_plain('libb/0.1@user/testing')}) + client.run("create . libc/0.1@user/testing") + + client.save({"conanfile.py": GenConanfile().with_require_plain('libc/0.1@user/testing')}) # Telling to build LibA doesn't change the final result of LibA, which has same ID and PREV - client.run("install . libd/0.1@user/testing --build=liba", assert_error=True) - self.assertIn("liba/0.1@user/testing: Calling build()", client.out) - self.assertIn("ERROR: Missing prebuilt package for 'libb/0.1@user/testing'", client.out) - self.assertIn("Package ID: Package_ID_unknown", client.out) + client.run("install . libd/0.1@user/testing --build=liba") + # So it is not necessary to build the downstream consumers of LibA + for lib in ("libb", "libc"): + self.assertIn("%s/0.1@user/testing: Unknown binary" % lib, client.out) + self.assertIn("%s/0.1@user/testing: Updated ID" % lib, client.out) + self.assertIn("%s/0.1@user/testing: Binary for updated ID from: Cache" % lib, client.out) + self.assertIn("%s/0.1@user/testing: Already installed!" % lib, client.out) + + +class PackageRevisionModeTest(unittest.TestCase): + + def setUp(self): + self.client = TestClient() + self.client.run("config set general.default_package_id_mode=package_revision_mode") + + def _generate_graph(self, dependencies): + for ref, deps in dependencies.items(): + ref = ConanFileReference.loads(ref) + conanfile = GenConanfile().with_name(ref.name).with_version(ref.version) + for dep in deps: + conanfile.with_require(ConanFileReference.loads(dep)) + filename = "%s.py" % ref.name + self.client.save({filename: conanfile}) + self.client.run("export %s %s@" % (filename, ref)) + + def simple_dependency_graph_test(self): + dependencies = { + "Log4Qt/0.3.0": [], + "MccApi/3.0.9": ["Log4Qt/0.3.0"], + "Util/0.3.5": ["MccApi/3.0.9"], + "Invent/1.0": ["Util/0.3.5"] + } + self._generate_graph(dependencies) + + self.client.run("install Invent.py --build missing") + self.assertIn("MccApi/3.0.9: Package '484784c96c359def1283e7354eec200f9f9c5cd8' created", + self.client.out) + self.assertIn("Util/0.3.5: Package 'ba438cd9d192b914edb1669b3e0149822290f7d8' created", + self.client.out) + + def triangle_dependency_graph_test(self): + dependencies = { + "Log4Qt/0.3.0": [], + "MccApi/3.0.9": ["Log4Qt/0.3.0"], + "Util/0.3.5": ["MccApi/3.0.9"], + "GenericSU/1.0": ["Log4Qt/0.3.0", "MccApi/3.0.9", "Util/0.3.5"] + } + self._generate_graph(dependencies) + + self.client.run("install GenericSU.py --build missing") + self.assertIn("MccApi/3.0.9: Package '484784c96c359def1283e7354eec200f9f9c5cd8' created", + self.client.out) + self.assertIn("Util/0.3.5: Package 'ba438cd9d192b914edb1669b3e0149822290f7d8' created", + self.client.out) + + def diamond_dependency_graph_test(self): + dependencies = { + "Log4Qt/0.3.0": [], + "MccApi/3.0.9": ["Log4Qt/0.3.0"], + "Util/0.3.5": ["Log4Qt/0.3.0"], + "GenericSU/0.3.5": ["MccApi/3.0.9", "Util/0.3.5"] + } + self._generate_graph(dependencies) + + self.client.run("install GenericSU.py --build missing") + self.assertIn("MccApi/3.0.9: Package '484784c96c359def1283e7354eec200f9f9c5cd8' created", + self.client.out) + self.assertIn("Util/0.3.5: Package '484784c96c359def1283e7354eec200f9f9c5cd8' created", + self.client.out) + + def full_dependency_graph_test(self): + dependencies = { + "Log4Qt/0.3.0": [], + "MccApi/3.0.9": ["Log4Qt/0.3.0"], + "Util/0.3.5": ["MccApi/3.0.9"], + "GenericSU/0.3.5": ["Log4Qt/0.3.0", "MccApi/3.0.9", "Util/0.3.5"], + "ManagementModule/0.3.5": ["Log4Qt/0.3.0", "MccApi/3.0.9", "Util/0.3.5"], + "StationInterfaceModule/0.13.0": ["ManagementModule/0.3.5", "GenericSU/0.3.5"], + "PleniterGenericSuApp/0.1.8": ["ManagementModule/0.3.5", "GenericSU/0.3.5", + "Log4Qt/0.3.0", "MccApi/3.0.9", "Util/0.3.5"], + "StationinterfaceRpm/2.2.0": ["StationInterfaceModule/0.13.0", + "PleniterGenericSuApp/0.1.8"] + } + self._generate_graph(dependencies) + + # Obtained with with create and reevaluate_node + ids = {"Log4Qt/0.3.0": "5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9", + "MccApi/3.0.9": "484784c96c359def1283e7354eec200f9f9c5cd8", + "Util/0.3.5": "ba438cd9d192b914edb1669b3e0149822290f7d8", + "GenericSU/0.3.5": "c152f6964d097021edab4a508d8fa926bad976fb", + "ManagementModule/0.3.5": "c152f6964d097021edab4a508d8fa926bad976fb", + "StationInterfaceModule/0.13.0": "7184518aa4cb352204d8b00d5424d3e52e5819d8", + "PleniterGenericSuApp/0.1.8": "7184518aa4cb352204d8b00d5424d3e52e5819d8"} + + rev = {"Log4Qt/0.3.0": "ce3408b2884c458b2bcdfeff92404c85", + "MccApi/3.0.9": "45aeac67977b1509a2d02f9a205baccb", + "Util/0.3.5": "f446fb8e24603baafacda66aadd2503f", + "GenericSU/0.3.5": "d5761d4d690ded2003c3cdab86e55d15", + "ManagementModule/0.3.5": "743935f4f5664b059d54d361a232bf94", + "StationInterfaceModule/0.13.0": "fc81fa83c3c134db6ba5af99fd8460cb", + "PleniterGenericSuApp/0.1.8": "7191e6b6eaf79194f1b083c8dc508518"} + + self.client.run("install StationinterfaceRpm.py --build missing") + for pkg, id_ in ids.items(): + self.assertIn("%s: Package '%s' created" % (pkg, id_), self.client.out) + for pkg, r in rev.items(): + self.assertIn("%s: Created package revision %s" % (pkg, r), self.client.out) + + self.client.run("install StationinterfaceRpm.py") + for pkg, id_ in ids.items(): + self.assertIn("%s:%s - Cache" % (pkg, id_), self.client.out) diff --git a/conans/test/functional/graph/graph_manager_base.py b/conans/test/functional/graph/graph_manager_base.py index c3e3e3b8ad1..0d458b7ed44 100644 --- a/conans/test/functional/graph/graph_manager_base.py +++ b/conans/test/functional/graph/graph_manager_base.py @@ -6,6 +6,7 @@ from conans.client.cache.cache import ClientCache from conans.client.cache.remote_registry import Remotes +from conans.client.graph.build_mode import BuildMode from conans.client.graph.graph_binaries import GraphBinariesAnalyzer from conans.client.graph.graph_manager import GraphManager from conans.client.graph.proxy import ConanProxy @@ -43,9 +44,10 @@ def _get_app(self): self.manager = GraphManager(self.output, cache, self.remote_manager, self.loader, proxy, self.resolver, binaries) hook_manager = Mock() - recorder = Mock() - app_type = namedtuple("ConanApp", "cache out remote_manager hook_manager graph_manager") - app = app_type(self.cache, self.output, self.remote_manager, hook_manager, self.manager) + app_type = namedtuple("ConanApp", "cache out remote_manager hook_manager graph_manager" + " binaries_analyzer") + app = app_type(self.cache, self.output, self.remote_manager, hook_manager, self.manager, + binaries) return app def _cache_recipe(self, ref, test_conanfile, revision=None): @@ -82,7 +84,8 @@ def build_graph(self, content, profile_build_requires=None, ref=None, create_ref check_updates, update, remotes, recorder) if install: binary_installer = BinaryInstaller(app, recorder) - binary_installer.install(deps_graph, None, False, graph_info) + build_mode = BuildMode(build_mode, app.out) + binary_installer.install(deps_graph, None, build_mode, update, False, graph_info) return deps_graph def _check_node(self, node, ref, deps, build_deps, dependents, closure): diff --git a/conans/test/functional/graph/package_id_modes_test.py b/conans/test/functional/graph/package_id_modes_test.py index 82673e97ef0..b7c07a1508f 100644 --- a/conans/test/functional/graph/package_id_modes_test.py +++ b/conans/test/functional/graph/package_id_modes_test.py @@ -47,6 +47,7 @@ def _assert_recipe_mode(ref_arg, package_id_arg): def test_package_revision_mode(self): self.cache.config.set_item("general.default_package_id_mode", "package_revision_mode") + liba_ref1 = ConanFileReference.loads("liba/0.1.1@user/testing") libb_ref = ConanFileReference.loads("libb/0.1@user/testing") self._cache_recipe(liba_ref1, GenConanfile().with_name("liba").with_version("0.1.1")) @@ -55,7 +56,7 @@ def test_package_revision_mode(self): deps_graph = self.build_graph(GenConanfile().with_name("app").with_version("0.1") .with_require(libb_ref), - install=False) + install=True) self.assertEqual(3, len(deps_graph.nodes)) app = deps_graph.root @@ -63,4 +64,4 @@ def test_package_revision_mode(self): liba = libb.dependencies[0].dst self.assertEqual(liba.package_id, "5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9") - self.assertEqual(libb.package_id, "Package_ID_unknown") + self.assertEqual(libb.package_id, "d22462afa90bb9e1c2b35ce413111fff04504399") diff --git a/conans/test/functional/graph_lock/graph_lock_ci_test.py b/conans/test/functional/graph_lock/graph_lock_ci_test.py index 92f3fb6ece4..4e56d7e8489 100644 --- a/conans/test/functional/graph_lock/graph_lock_ci_test.py +++ b/conans/test/functional/graph_lock/graph_lock_ci_test.py @@ -7,12 +7,14 @@ from conans.model.graph_lock import LOCKFILE from conans.model.ref import PackageReference from conans.test.utils.tools import TestClient, TestServer +from conans.util.env_reader import get_env from conans.util.files import load class GraphLockCITest(unittest.TestCase): - def test(self): + @unittest.skipUnless(get_env("TESTING_REVISIONS_ENABLED", False), "Only revisions") + def test_revisions(self): conanfile = textwrap.dedent(""" from conans import ConanFile, load import os @@ -55,7 +57,6 @@ def package_info(self): self.assertIn("PkgD/0.1@user/channel: DEP FILE PkgB: HelloB", client.out) self.assertIn("PkgD/0.1@user/channel: DEP FILE PkgC: HelloC", client.out) - client.run("config set general.revisions_enabled=True") client.run("upload * --all --confirm") # FIXME: We need to do this with info, to avoid installing the binaries when we want info @@ -77,7 +78,6 @@ def package_info(self): # Do a change in B clientb = TestClient(cache_folder=client.cache_folder, servers={"default": test_server}) - clientb.run("config set general.revisions_enabled=True") clientb.save({"conanfile.py": conanfile.format(requires='requires="PkgA/0.1@user/channel"'), "myfile.txt": "ByeB World!!", LOCKFILE: lock_file}) @@ -109,7 +109,6 @@ def package_info(self): pkg_ref = PackageReference.loads(pkg_ref) client_aux = TestClient(cache_folder=client.cache_folder, servers={"default": test_server}) - client_aux.run("config set general.revisions_enabled=True") client_aux.save({LOCKFILE: lock_fileaux}) client_aux.run("install %s --build=%s --lockfile" % (pkg_ref.ref, pkg_ref.ref.name)) @@ -140,6 +139,7 @@ def package_info(self): self.assertIn("PkgC/0.1@user/channel: DEP FILE PkgB: ByeB World!!", client.out) self.assertIn("PkgD/0.1@user/channel: DEP FILE PkgB: ByeB World!!", client.out) + @unittest.skipUnless(get_env("TESTING_REVISIONS_ENABLED", False), "Only revisions") def test_package_revision_mode(self): conanfile = textwrap.dedent(""" from conans import ConanFile, load @@ -164,7 +164,6 @@ def package_info(self): client = TestClient(servers={"default": test_server}, users={"default": [("user", "mypass")]}) client.run("config set general.default_package_id_mode=package_revision_mode") - client.run("config set general.revisions_enabled=True") client.save({"conanfile.py": conanfile.format(requires=""), "myfile.txt": "HelloA"}) client.run("create . PkgA/0.1@user/channel") @@ -205,7 +204,6 @@ def package_info(self): # Do a change in B clientb = TestClient(cache_folder=client.cache_folder, servers={"default": test_server}) - clientb.run("config set general.revisions_enabled=True") clientb.run("config set general.default_package_id_mode=package_revision_mode") clientb.save({"conanfile.py": conanfile.format(requires='requires="PkgA/0.1@user/channel"'), "myfile.txt": "ByeB World!!", @@ -238,7 +236,6 @@ def package_info(self): pkg_ref = PackageReference.loads(pkg_ref) client_aux = TestClient(cache_folder=client.cache_folder, servers={"default": test_server}) - client_aux.run("config set general.revisions_enabled=True") client_aux.save({LOCKFILE: lock_fileaux}) client_aux.run("install %s --build=%s --lockfile" % (pkg_ref.ref, pkg_ref.ref.name)) diff --git a/conans/test/functional/graph_lock/graph_lock_test.py b/conans/test/functional/graph_lock/graph_lock_test.py index 430947ef90d..64c8807f030 100644 --- a/conans/test/functional/graph_lock/graph_lock_test.py +++ b/conans/test/functional/graph_lock/graph_lock_test.py @@ -8,6 +8,7 @@ from conans.model.graph_lock import LOCKFILE, LOCKFILE_VERSION from conans.model.ref import ConanFileReference from conans.test.utils.tools import TestClient, TestServer, GenConanfile +from conans.util.env_reader import get_env from conans.util.files import load @@ -229,6 +230,7 @@ class GraphLockVersionRangeGraphLockTest(GraphLockVersionRangeTest): graph_lock_command = "graph lock ." +@unittest.skipUnless(get_env("TESTING_REVISIONS_ENABLED", False), "Only revisions") class GraphLockRevisionTest(unittest.TestCase): pkg_b_revision = "9b64caa2465f7660e6f613b7e87f0cd7" pkg_b_id = "5bf1ba84b5ec8663764a406f08a7f9ae5d3d5fb5" @@ -239,7 +241,6 @@ def setUp(self): servers = {"default": test_server} client = TestClient(servers=servers, users={"default": [("user", "user")]}) # Important to activate revisions - client.run("config set general.revisions_enabled=True") self.client = client client.save({"conanfile.py": GenConanfile().with_name("PkgA").with_version("0.1")}) client.run("create . PkgA/0.1@user/channel") @@ -413,12 +414,9 @@ def export_pkg_test(self): class GraphLockConsumerBuildOrderTest(unittest.TestCase): - @parameterized.expand([(True, ), (False, )]) - def consumer_build_order_local_test(self, enable_revisions): + def consumer_build_order_local_test(self): # https://github.com/conan-io/conan/issues/5727 client = TestClient(default_server_user=True) - if enable_revisions: - client.run("config set general.revisions_enabled=1") consumer_ref = ConanFileReference("test4", "0.1", None, None, None) consumer = GenConanfile().with_name(consumer_ref.name).with_version(consumer_ref.version) @@ -428,12 +426,9 @@ def consumer_build_order_local_test(self, enable_revisions): client.run("graph build-order conan.lock --build=missing") self.assertIn("[]", client.out) - @parameterized.expand([(True,), (False,)]) - def consumer_build_order_test(self, enable_revisions): + def consumer_build_order_test(self): # https://github.com/conan-io/conan/issues/5727 client = TestClient(default_server_user=True) - if enable_revisions: - client.run("config set general.revisions_enabled=1") consumer_ref = ConanFileReference("test4", "0.1", None, None, None) consumer = GenConanfile().with_name(consumer_ref.name).with_version(consumer_ref.version)