From 65d33d013247a5ec20ef51f3acc67c4ae67d2a5b Mon Sep 17 00:00:00 2001 From: memsharded Date: Fri, 12 Apr 2024 13:20:46 +0200 Subject: [PATCH 01/16] wip --- conan/cli/commands/create.py | 3 + conans/client/graph/compute_pid.py | 3 + conans/client/graph/graph_builder.py | 4 +- conans/client/graph/install_graph.py | 7 +++ conans/model/conan_file.py | 1 + conans/model/conf.py | 1 + conans/test/integration/test_repackage.py | 74 +++++++++++++++++++++++ 7 files changed, 92 insertions(+), 1 deletion(-) create mode 100644 conans/test/integration/test_repackage.py diff --git a/conan/cli/commands/create.py b/conan/cli/commands/create.py index d5b2e186eea..2d3ead7a296 100644 --- a/conan/cli/commands/create.py +++ b/conan/cli/commands/create.py @@ -75,6 +75,9 @@ def create(conan_api, parser, *args): else: requires = [ref] if not is_build else None tool_requires = [ref] if is_build else None + if conanfile.repackage: # Automatically allow repackaging for conan create + pr = profile_build if is_build else profile_host + pr.conf.update("&:tools.graph:repackage", True) deps_graph = conan_api.graph.load_graph_requires(requires, tool_requires, profile_host=profile_host, profile_build=profile_build, diff --git a/conans/client/graph/compute_pid.py b/conans/client/graph/compute_pid.py index d86a146f6e4..496b1a5203f 100644 --- a/conans/client/graph/compute_pid.py +++ b/conans/client/graph/compute_pid.py @@ -38,6 +38,9 @@ def compute_package_id(node, new_config, config_version): else: data[require] = req_info + if conanfile.repackage: # Make the package_id fully independent of dependencies versions + data, build_data = OrderedDict(), OrderedDict() # TODO, cleaner, now minimal diff + reqs_info = RequirementsInfo(data) build_requires_info = RequirementsInfo(build_data) python_requires = PythonRequiresInfo(python_requires, python_mode) diff --git a/conans/client/graph/graph_builder.py b/conans/client/graph/graph_builder.py index 937d32f76a2..5ae2aa23984 100644 --- a/conans/client/graph/graph_builder.py +++ b/conans/client/graph/graph_builder.py @@ -52,7 +52,9 @@ def load_graph(self, root_node, profile_host, profile_build, graph_lock=None): continue new_node = self._expand_require(require, node, dep_graph, profile_host, profile_build, graph_lock) - if new_node: + conanfile = new_node.conanfile + if new_node and (not conanfile.repackage or + conanfile.conf.get("tools.graph:repackage", check_type=bool)): self._initialize_requires(new_node, dep_graph, graph_lock, profile_build, profile_host) open_requires.extendleft((r, new_node) diff --git a/conans/client/graph/install_graph.py b/conans/client/graph/install_graph.py index 2471e1f62a5..9c2b70e78b5 100644 --- a/conans/client/graph/install_graph.py +++ b/conans/client/graph/install_graph.py @@ -462,6 +462,13 @@ def raise_errors(self): missing.append(package) elif package.binary == BINARY_INVALID: invalid.append(package) + elif package.binary == BINARY_BUILD: + conanfile = package.nodes[0].conanfile + if conanfile.repackage and not conanfile.conf.get("tools.graph:repackage", + check_type=bool): + msg = f"The package '{ref}' is repackaging and building but it "\ + "didn't enable 'tools.graph:repackage' to compute its dependencies" + raise ConanException(msg) if invalid: msg = ["There are invalid packages:"] diff --git a/conans/model/conan_file.py b/conans/model/conan_file.py index 554d0938afa..da53b9cff29 100644 --- a/conans/model/conan_file.py +++ b/conans/model/conan_file.py @@ -48,6 +48,7 @@ class ConanFile: default_options = None default_build_options = None package_type = None + repackage = False implements = [] diff --git a/conans/model/conf.py b/conans/model/conf.py index f74ee2107c4..f1f9f9f2fef 100644 --- a/conans/model/conf.py +++ b/conans/model/conf.py @@ -83,6 +83,7 @@ "tools.files.download:retry_wait": "Seconds to wait between download attempts", "tools.files.download:verify": "If set, overrides recipes on whether to perform SSL verification for their downloaded files. Only recommended to be set while testing", "tools.graph:skip_binaries": "Allow the graph to skip binaries not needed in the current configuration (True by default)", + "tools.graph:repackage": "enable re-packaging", "tools.gnu:make_program": "Indicate path to make program", "tools.gnu:define_libcxx11_abi": "Force definition of GLIBCXX_USE_CXX11_ABI=1 for libstdc++11", "tools.gnu:pkg_config": "Path to pkg-config executable used by PkgConfig build helper", diff --git a/conans/test/integration/test_repackage.py b/conans/test/integration/test_repackage.py new file mode 100644 index 00000000000..b99f39dd025 --- /dev/null +++ b/conans/test/integration/test_repackage.py @@ -0,0 +1,74 @@ +import textwrap + +from conans.test.assets.genconanfile import GenConanfile +from conans.test.utils.tools import TestClient + + +def test_repackage(): + c = TestClient() + app = textwrap.dedent(""" + import os + from conan import ConanFile + from conan.tools.files import copy, save + + class App(ConanFile): + name = "app" + version = "0.1" + package_type = "application" + repackage = True + requires = "pkga/0.1" + def package(self): + copy(self, "*", src=self.dependencies["pkga"].package_folder, + dst=self.package_folder) + save(self, os.path.join(self.package_folder, "app.exe"), "app") + """) + + c.save({"pkga/conanfile.py": GenConanfile("pkga", "0.1").with_package_type("shared-library") + .with_package_file("pkga.dll", "dll"), + "app/conanfile.py": app + }) + c.run("create pkga") + c.run("create app") # -c tools.graph:repackage=True will be automatic + assert "app/0.1: package(): Packaged 1 '.dll' file: pkga.dll" in c.out + + # we can safely remove pkga + c.run("remove pkg* -c") + c.run("list app:*") + assert "pkga" not in c.out # The binary doesn't depend on pkga + c.run("install --requires=app/0.1 --deployer=full_deploy") + assert "pkga" not in c.out + assert c.load("full_deploy/host/app/0.1/app.exe") == "app" + assert c.load("full_deploy/host/app/0.1/pkga.dll") == "dll" + + # we can create a modified pkga + c.save({"pkga/conanfile.py": GenConanfile("pkga", "0.1").with_package_type("shared-library") + .with_package_file("pkga.dll", "newdll")}) + c.run("create pkga") + # still using the re-packaged one + c.run("install --requires=app/0.1 --deployer=full_deploy") + assert "pkga" not in c.out + assert c.load("full_deploy/host/app/0.1/app.exe") == "app" + assert c.load("full_deploy/host/app/0.1/pkga.dll") == "dll" + + # but we can force the expansion, still not the rebuild + c.run("install --requires=app/0.1 --deployer=full_deploy -c tools.graph:repackage=True") + assert "pkga" in c.out + assert c.load("full_deploy/host/app/0.1/app.exe") == "app" + assert c.load("full_deploy/host/app/0.1/pkga.dll") == "dll" + + # and finally we can force the expansion and the rebuild + c.run("install --requires=app/0.1 --build=app* --deployer=full_deploy " + "-c tools.graph:repackage=True") + assert "pkga" in c.out + assert c.load("full_deploy/host/app/0.1/app.exe") == "app" + assert c.load("full_deploy/host/app/0.1/pkga.dll") == "newdll" + + # lets remove the binary + c.run("remove app:* -c") + c.run("install --requires=app/0.1", assert_error=True) + assert "Missing binary" in c.out + c.run("install --requires=app/0.1 --build=missing", assert_error=True) + assert "ERROR: The package 'app/0.1' is repackaging and building but it didn't " \ + "enable 'tools.graph:repackage'" in c.out + c.run("install --requires=app/0.1 --build=missing -c tools.graph:repackage=True") + assert "pkga" in c.out # it works From 1cff999b4d3d59f41da7401a8e1f01b97fbda494 Mon Sep 17 00:00:00 2001 From: memsharded Date: Sat, 13 Apr 2024 12:45:09 +0200 Subject: [PATCH 02/16] wip --- conans/client/graph/graph.py | 4 +++ conans/client/graph/graph_builder.py | 4 +-- conans/test/integration/test_repackage.py | 42 +++++++++++++++++++++++ 3 files changed, 48 insertions(+), 2 deletions(-) diff --git a/conans/client/graph/graph.py b/conans/client/graph/graph.py index f6f1ba5cb53..8a64524a53e 100644 --- a/conans/client/graph/graph.py +++ b/conans/client/graph/graph.py @@ -103,6 +103,8 @@ def propagate_downstream(self, require, node, src_node=None): self.transitive_deps.pop(require, None) self.transitive_deps[require] = TransitiveRequirement(require, node) + if self.conanfile.repackage: + return # Check if need to propagate downstream if not self.dependants: return @@ -147,6 +149,8 @@ def check_downstream_exists(self, require): # Seems the algrithm depth-first, would only have 1 dependant at most to propagate down # at any given time + if self.conanfile.repackage: + return result if not self.dependants: return result assert len(self.dependants) == 1 diff --git a/conans/client/graph/graph_builder.py b/conans/client/graph/graph_builder.py index 5ae2aa23984..b2718e1aa65 100644 --- a/conans/client/graph/graph_builder.py +++ b/conans/client/graph/graph_builder.py @@ -5,7 +5,7 @@ from conan.internal.cache.conan_reference_layout import BasicLayout from conans.client.conanfile.configure import run_configure_method from conans.client.graph.graph import DepsGraph, Node, CONTEXT_HOST, \ - CONTEXT_BUILD, TransitiveRequirement, RECIPE_VIRTUAL + CONTEXT_BUILD, TransitiveRequirement, RECIPE_VIRTUAL, RECIPE_EDITABLE from conans.client.graph.graph import RECIPE_PLATFORM from conans.client.graph.graph_error import GraphLoopError, GraphConflictError, GraphMissingError, \ GraphRuntimeError, GraphError @@ -53,7 +53,7 @@ def load_graph(self, root_node, profile_host, profile_build, graph_lock=None): new_node = self._expand_require(require, node, dep_graph, profile_host, profile_build, graph_lock) conanfile = new_node.conanfile - if new_node and (not conanfile.repackage or + if new_node and (not conanfile.repackage or new_node.recipe == RECIPE_EDITABLE or conanfile.conf.get("tools.graph:repackage", check_type=bool)): self._initialize_requires(new_node, dep_graph, graph_lock, profile_build, profile_host) diff --git a/conans/test/integration/test_repackage.py b/conans/test/integration/test_repackage.py index b99f39dd025..1f654ffbb7b 100644 --- a/conans/test/integration/test_repackage.py +++ b/conans/test/integration/test_repackage.py @@ -1,3 +1,4 @@ +import os import textwrap from conans.test.assets.genconanfile import GenConanfile @@ -62,6 +63,8 @@ def package(self): assert "pkga" in c.out assert c.load("full_deploy/host/app/0.1/app.exe") == "app" assert c.load("full_deploy/host/app/0.1/pkga.dll") == "newdll" + # This shoulnd't happen, no visibility over transitive dependencies of app + assert not os.path.exists(os.path.join(c.current_folder, "full_deploy", "host", "pkga")) # lets remove the binary c.run("remove app:* -c") @@ -72,3 +75,42 @@ def package(self): "enable 'tools.graph:repackage'" in c.out c.run("install --requires=app/0.1 --build=missing -c tools.graph:repackage=True") assert "pkga" in c.out # it works + + +def test_repackage_editable(): + c = TestClient() + pkgb = textwrap.dedent(""" + import os + from conan import ConanFile + from conan.tools.files import copy, save + + class App(ConanFile): + name = "pkgb" + version = "0.1" + package_type = "shared-library" + repackage = True + requires = "pkga/0.1" + def layout(self): + self.folders.build = "build" + self.cpp.build.bindirs = ["build"] + def generate(self): + copy(self, "*", src=self.dependencies["pkga"].package_folder, + dst=self.build_folder) + def build(self): + save(self, os.path.join(self.build_folder, "pkgb.dll"), "dll") + """) + + c.save({"pkga/conanfile.py": GenConanfile("pkga", "0.1").with_package_type("shared-library") + .with_package_file("bin/pkga.dll", "d"), + "pkgb/conanfile.py": pkgb, + "app/conanfile.py": GenConanfile("app", "0.1").with_settings("os") + .with_requires("pkgb/0.1") + }) + c.run("create pkga") + c.run("editable add pkgb") + c.run("install app -s os=Linux") + print(c.out) + assert "pkga" in c.out + envfile = c.load("app/conanrunenv.sh") + print(envfile) + From 8a12d6d38dc5efc65d1865b6edd9e89c192a7f20 Mon Sep 17 00:00:00 2001 From: memsharded Date: Mon, 15 Apr 2024 00:33:06 +0200 Subject: [PATCH 03/16] wip --- conans/test/integration/test_repackage.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/conans/test/integration/test_repackage.py b/conans/test/integration/test_repackage.py index 1f654ffbb7b..9a878b62e14 100644 --- a/conans/test/integration/test_repackage.py +++ b/conans/test/integration/test_repackage.py @@ -109,8 +109,10 @@ def build(self): c.run("create pkga") c.run("editable add pkgb") c.run("install app -s os=Linux") - print(c.out) assert "pkga" in c.out - envfile = c.load("app/conanrunenv.sh") - print(envfile) - + # The environment file of "app" doesn't have any visibility of the "pkga" paths + envfile_app = c.load("app/conanrunenv.sh") + assert "pkga" not in envfile_app + # But the environment file needed to build "pkgb" has visibility over the "pkga" paths + envfile_pkgb = c.load("pkgb/conanrunenv.sh") + assert "pkga" in envfile_pkgb From b3874b729c212f9be8adff473cfc4ace2c233a37 Mon Sep 17 00:00:00 2001 From: memsharded Date: Mon, 15 Apr 2024 00:58:23 +0200 Subject: [PATCH 04/16] fix --- conans/client/graph/graph_builder.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/conans/client/graph/graph_builder.py b/conans/client/graph/graph_builder.py index b2718e1aa65..dc8f6a85c54 100644 --- a/conans/client/graph/graph_builder.py +++ b/conans/client/graph/graph_builder.py @@ -52,9 +52,9 @@ def load_graph(self, root_node, profile_host, profile_build, graph_lock=None): continue new_node = self._expand_require(require, node, dep_graph, profile_host, profile_build, graph_lock) - conanfile = new_node.conanfile - if new_node and (not conanfile.repackage or new_node.recipe == RECIPE_EDITABLE or - conanfile.conf.get("tools.graph:repackage", check_type=bool)): + if new_node and (not new_node.conanfile.repackage + or new_node.recipe == RECIPE_EDITABLE or + new_node.conanfile.conf.get("tools.graph:repackage", check_type=bool)): self._initialize_requires(new_node, dep_graph, graph_lock, profile_build, profile_host) open_requires.extendleft((r, new_node) From 94ea8bb29b6835baf361481e42769480e29e8a42 Mon Sep 17 00:00:00 2001 From: memsharded Date: Wed, 22 May 2024 00:23:30 +0200 Subject: [PATCH 05/16] fix test --- test/integration/test_repackage.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/integration/test_repackage.py b/test/integration/test_repackage.py index 9a878b62e14..491dc407eb6 100644 --- a/test/integration/test_repackage.py +++ b/test/integration/test_repackage.py @@ -1,8 +1,8 @@ import os import textwrap -from conans.test.assets.genconanfile import GenConanfile -from conans.test.utils.tools import TestClient +from conan.test.assets.genconanfile import GenConanfile +from conan.test.utils.tools import TestClient def test_repackage(): From 0a44cbe74e3d5a516d0369ba942b01e6a2857905 Mon Sep 17 00:00:00 2001 From: PerseoGI Date: Tue, 28 May 2024 12:23:55 +0200 Subject: [PATCH 06/16] Updated graph serialization and display for re-package nodes --- conan/cli/formatters/graph/info_graph_html.py | 13 +++++++++++++ conans/model/conan_file.py | 1 + conans/model/conf.py | 2 +- 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/conan/cli/formatters/graph/info_graph_html.py b/conan/cli/formatters/graph/info_graph_html.py index 4179698501a..af6c53d14a0 100644 --- a/conan/cli/formatters/graph/info_graph_html.py +++ b/conan/cli/formatters/graph/info_graph_html.py @@ -144,6 +144,11 @@ if (node.recipe == "Platform") { font.background = "Violet"; } + if (node.repackage) { + borderColor = "Red"; + shapeProperties = {borderDashes: [3,5]}; + borderWidth = 2; + } nodes.push({ id: node_id, font: font, @@ -225,6 +230,14 @@ font: {size: 35, color: "white"}, color: {border: "SkyBlue", background: "Black"} }); + counter++; + + legend_nodes.push({x: x + counter*step, y: y, shape: "box", + label: "repackage", font: {size: 35}, + color: {border: "Red"}, + shapeProperties: {borderDashes: [3,5]}, + borderWidth: 2 + }); return {nodes: new vis.DataSet(legend_nodes)}; } let error = document.getElementById("error"); diff --git a/conans/model/conan_file.py b/conans/model/conan_file.py index d3aed3897b8..0cc09c4cfca 100644 --- a/conans/model/conan_file.py +++ b/conans/model/conan_file.py @@ -167,6 +167,7 @@ def serialize(self): result["label"] = self.display_name if self.info is not None: result["info"] = self.info.serialize() + result["repackage"] = self.repackage return result @property diff --git a/conans/model/conf.py b/conans/model/conf.py index 57de53329d1..4944720a576 100644 --- a/conans/model/conf.py +++ b/conans/model/conf.py @@ -82,8 +82,8 @@ "tools.files.download:retry": "Number of retries in case of failure when downloading", "tools.files.download:retry_wait": "Seconds to wait between download attempts", "tools.files.download:verify": "If set, overrides recipes on whether to perform SSL verification for their downloaded files. Only recommended to be set while testing", + "tools.graph:repackage": "(boolean) Enable/Disable re-packaging", "tools.graph:skip_binaries": "Allow the graph to skip binaries not needed in the current configuration (True by default)", - "tools.graph:repackage": "enable re-packaging", "tools.gnu:make_program": "Indicate path to make program", "tools.gnu:define_libcxx11_abi": "Force definition of GLIBCXX_USE_CXX11_ABI=1 for libstdc++11", "tools.gnu:pkg_config": "Path to pkg-config executable used by PkgConfig build helper", From 0789acf3a785921f21aa12e5f32fa53689b17b4b Mon Sep 17 00:00:00 2001 From: PerseoGI Date: Tue, 28 May 2024 14:17:31 +0200 Subject: [PATCH 07/16] Fix broken tests --- test/integration/command_v2/test_inspect.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/test/integration/command_v2/test_inspect.py b/test/integration/command_v2/test_inspect.py index 129ee376181..87cb9a01e04 100644 --- a/test/integration/command_v2/test_inspect.py +++ b/test/integration/command_v2/test_inspect.py @@ -20,8 +20,10 @@ def test_basic_inspect(): 'options_definitions:', " shared: ['True', 'False']", 'package_type: None', + 'repackage: False', 'requires: []', - 'revision_mode: hash'] + 'revision_mode: hash', + ] def test_options_description(): @@ -88,6 +90,7 @@ def test_normal_inspect(): 'options:', 'options_definitions:', 'package_type: None', + 'repackage: False', 'requires: []', 'revision_mode: hash', 'version: 1.0'] @@ -130,6 +133,7 @@ class Pkg(ConanFile): 'options:', 'options_definitions:', 'package_type: None', + 'repackage: False', "requires: [{'ref': 'zlib/1.2.13', 'run': False, 'libs': True, 'skip': " "False, 'test': False, 'force': False, 'direct': True, 'build': " "False, 'transitive_headers': None, 'transitive_libs': None, 'headers': " From 2ed9551754278c4f9de1492e5928a6d9867c91e4 Mon Sep 17 00:00:00 2001 From: PerseoGI Date: Tue, 28 May 2024 17:04:31 +0200 Subject: [PATCH 08/16] Make graph command check tools.graph:repackage is passed when trying to compute graph on a repackage dependency --- conans/client/graph/graph_binaries.py | 8 +++++++ conans/client/graph/install_graph.py | 7 ------ test/integration/command/info/info_test.py | 25 +++++++++++++++++++++- 3 files changed, 32 insertions(+), 8 deletions(-) diff --git a/conans/client/graph/graph_binaries.py b/conans/client/graph/graph_binaries.py index 13030c5b8c4..54f382ce262 100644 --- a/conans/client/graph/graph_binaries.py +++ b/conans/client/graph/graph_binaries.py @@ -186,6 +186,14 @@ def _evaluate_node(self, node, build_mode, remotes, update): # BINARY_BUILD IS NOT A VIABLE fallback for invalid node.binary = BINARY_INVALID + if node.binary == BINARY_BUILD: + conanfile = node.conanfile + if conanfile.repackage and not conanfile.conf.get("tools.graph:repackage", check_type=bool): + node.conanfile.info.invalid = f"The package '{conanfile.ref}' is repackaging and building but it "\ + "didn't enable 'tools.graph:repackage' to compute its dependencies" + + node.binary = BINARY_INVALID + def _process_node(self, node, build_mode, remotes, update): # Check that this same reference hasn't already been checked if self._evaluate_is_cached(node): diff --git a/conans/client/graph/install_graph.py b/conans/client/graph/install_graph.py index cb83ba4b4f3..65befe30de1 100644 --- a/conans/client/graph/install_graph.py +++ b/conans/client/graph/install_graph.py @@ -462,13 +462,6 @@ def raise_errors(self): missing.append(package) elif package.binary == BINARY_INVALID: invalid.append(package) - elif package.binary == BINARY_BUILD: - conanfile = package.nodes[0].conanfile - if conanfile.repackage and not conanfile.conf.get("tools.graph:repackage", - check_type=bool): - msg = f"The package '{ref}' is repackaging and building but it "\ - "didn't enable 'tools.graph:repackage' to compute its dependencies" - raise ConanException(msg) if invalid: msg = ["There are invalid packages:"] diff --git a/test/integration/command/info/info_test.py b/test/integration/command/info/info_test.py index be8b53186f1..b087e2e9675 100644 --- a/test/integration/command/info/info_test.py +++ b/test/integration/command/info/info_test.py @@ -4,7 +4,7 @@ from conan.cli.exit_codes import ERROR_GENERAL from conans.model.recipe_ref import RecipeReference -from conan.test.utils.tools import TestClient, GenConanfile, TurboTestClient +from conan.test.utils.tools import NO_SETTINGS_PACKAGE_ID, TestClient, GenConanfile, TurboTestClient class TestBasicCliOutput: @@ -425,3 +425,26 @@ class Pkg(ConanFile): assert "pkg/0.1@user" in c.out c.run("graph info . --channel=channel") assert "pkg/0.1@user/channel" in c.out + +def test_graph_info_repackage(): + c = TestClient(light=True) + c.save({"subfolder/conanfile.py": GenConanfile("liba", "1.0")}) + c.run("create ./subfolder") + conanfile = textwrap.dedent(""" + from conan import ConanFile + class RepackageRecipe(ConanFile): + name = "repackage-lib" + version = "1.0" + def requirements(self): + self.requires("liba/1.0") + repackage = True + """) + c.save({"conanfile.py": conanfile}) + c.run("create .") + c.save({"conanfile.py": GenConanfile("consumer", "1.0").with_requires("repackage-lib/1.0")}) + + c.run("graph info . --build='repackage-lib*'") + c.assert_listed_binary({"repackage-lib/1.0": (NO_SETTINGS_PACKAGE_ID, "Invalid")}) + + c.run("graph info . -c tools.graph:repackage=True --build='repackage-lib*'") + c.assert_listed_binary({"repackage-lib/1.0": (NO_SETTINGS_PACKAGE_ID, "Build")}) From 8a6e88b8e8cd2cc0aab6b7a6b1bdda72c7941d36 Mon Sep 17 00:00:00 2001 From: PerseoGI Date: Thu, 30 May 2024 12:59:40 +0200 Subject: [PATCH 09/16] Fix integration test, changed error output --- conans/client/graph/graph_binaries.py | 2 +- test/integration/test_repackage.py | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/conans/client/graph/graph_binaries.py b/conans/client/graph/graph_binaries.py index 54f382ce262..7b7ead5f618 100644 --- a/conans/client/graph/graph_binaries.py +++ b/conans/client/graph/graph_binaries.py @@ -189,7 +189,7 @@ def _evaluate_node(self, node, build_mode, remotes, update): if node.binary == BINARY_BUILD: conanfile = node.conanfile if conanfile.repackage and not conanfile.conf.get("tools.graph:repackage", check_type=bool): - node.conanfile.info.invalid = f"The package '{conanfile.ref}' is repackaging and building but it "\ + node.conanfile.info.invalid = f"The package is repackaging and building but it "\ "didn't enable 'tools.graph:repackage' to compute its dependencies" node.binary = BINARY_INVALID diff --git a/test/integration/test_repackage.py b/test/integration/test_repackage.py index 491dc407eb6..388cf827eea 100644 --- a/test/integration/test_repackage.py +++ b/test/integration/test_repackage.py @@ -71,8 +71,9 @@ def package(self): c.run("install --requires=app/0.1", assert_error=True) assert "Missing binary" in c.out c.run("install --requires=app/0.1 --build=missing", assert_error=True) - assert "ERROR: The package 'app/0.1' is repackaging and building but it didn't " \ - "enable 'tools.graph:repackage'" in c.out + assert "app/0.1: Invalid: The package is repackaging and building but it didn't "\ + "enable 'tools.graph:repackage' to compute its dependencies" in c.out + c.run("install --requires=app/0.1 --build=missing -c tools.graph:repackage=True") assert "pkga" in c.out # it works From 5fad438705c89fd15a8f932c0b854f0573be595e Mon Sep 17 00:00:00 2001 From: memsharded Date: Fri, 31 May 2024 20:42:44 +0200 Subject: [PATCH 10/16] renamed to bundle --- conan/cli/commands/create.py | 4 ++-- conan/cli/formatters/graph/info_graph_html.py | 4 ++-- conans/client/graph/compute_pid.py | 2 +- conans/client/graph/graph.py | 4 ++-- conans/client/graph/graph_builder.py | 4 ++-- conans/model/conan_file.py | 4 ++-- conans/model/conf.py | 2 +- test/integration/command/info/info_test.py | 17 +++++++++-------- test/integration/command_v2/test_inspect.py | 6 +++--- ...est_repackage.py => test_package_bundle.py} | 18 +++++++++--------- 10 files changed, 33 insertions(+), 32 deletions(-) rename test/integration/{test_repackage.py => test_package_bundle.py} (92%) diff --git a/conan/cli/commands/create.py b/conan/cli/commands/create.py index 12c1ce75ac1..70a1c9c5981 100644 --- a/conan/cli/commands/create.py +++ b/conan/cli/commands/create.py @@ -95,9 +95,9 @@ def create(conan_api, parser, *args): else: requires = [ref] if not is_build else None tool_requires = [ref] if is_build else None - if conanfile.repackage: # Automatically allow repackaging for conan create + if conanfile.bundle: # Automatically allow repackaging for conan create pr = profile_build if is_build else profile_host - pr.conf.update("&:tools.graph:repackage", True) + pr.conf.update("&:tools.graph:bundle", True) deps_graph = conan_api.graph.load_graph_requires(requires, tool_requires, profile_host=profile_host, profile_build=profile_build, diff --git a/conan/cli/formatters/graph/info_graph_html.py b/conan/cli/formatters/graph/info_graph_html.py index af6c53d14a0..00091c8cbbd 100644 --- a/conan/cli/formatters/graph/info_graph_html.py +++ b/conan/cli/formatters/graph/info_graph_html.py @@ -144,7 +144,7 @@ if (node.recipe == "Platform") { font.background = "Violet"; } - if (node.repackage) { + if (node.bundle) { borderColor = "Red"; shapeProperties = {borderDashes: [3,5]}; borderWidth = 2; @@ -233,7 +233,7 @@ counter++; legend_nodes.push({x: x + counter*step, y: y, shape: "box", - label: "repackage", font: {size: 35}, + label: "bundle", font: {size: 35}, color: {border: "Red"}, shapeProperties: {borderDashes: [3,5]}, borderWidth: 2 diff --git a/conans/client/graph/compute_pid.py b/conans/client/graph/compute_pid.py index 572089a35c2..15221fbc373 100644 --- a/conans/client/graph/compute_pid.py +++ b/conans/client/graph/compute_pid.py @@ -38,7 +38,7 @@ def compute_package_id(node, new_config, config_version): else: data[require] = req_info - if conanfile.repackage: # Make the package_id fully independent of dependencies versions + if conanfile.bundle: # Make the package_id fully independent of dependencies versions data, build_data = OrderedDict(), OrderedDict() # TODO, cleaner, now minimal diff reqs_info = RequirementsInfo(data) diff --git a/conans/client/graph/graph.py b/conans/client/graph/graph.py index 81d86c17273..f10bad819a6 100644 --- a/conans/client/graph/graph.py +++ b/conans/client/graph/graph.py @@ -108,7 +108,7 @@ def propagate_downstream(self, require, node, src_node=None): self.transitive_deps.pop(require, None) self.transitive_deps[require] = TransitiveRequirement(require, node) - if self.conanfile.repackage: + if self.conanfile.bundle: return # Check if need to propagate downstream if not self.dependants: @@ -158,7 +158,7 @@ def check_downstream_exists(self, require): # Seems the algrithm depth-first, would only have 1 dependant at most to propagate down # at any given time - if self.conanfile.repackage: + if self.conanfile.bundle: return result if not self.dependants: return result diff --git a/conans/client/graph/graph_builder.py b/conans/client/graph/graph_builder.py index 7c7bcbed2b5..c09c13b5dac 100644 --- a/conans/client/graph/graph_builder.py +++ b/conans/client/graph/graph_builder.py @@ -52,9 +52,9 @@ def load_graph(self, root_node, profile_host, profile_build, graph_lock=None): continue new_node = self._expand_require(require, node, dep_graph, profile_host, profile_build, graph_lock) - if new_node and (not new_node.conanfile.repackage + if new_node and (not new_node.conanfile.bundle or new_node.recipe == RECIPE_EDITABLE or - new_node.conanfile.conf.get("tools.graph:repackage", check_type=bool)): + new_node.conanfile.conf.get("tools.graph:bundle", check_type=bool)): self._initialize_requires(new_node, dep_graph, graph_lock, profile_build, profile_host) open_requires.extendleft((r, new_node) diff --git a/conans/model/conan_file.py b/conans/model/conan_file.py index 0cc09c4cfca..f432ffed76a 100644 --- a/conans/model/conan_file.py +++ b/conans/model/conan_file.py @@ -47,7 +47,7 @@ class ConanFile: default_options = None default_build_options = None package_type = None - repackage = False + bundle = False implements = [] @@ -167,7 +167,7 @@ def serialize(self): result["label"] = self.display_name if self.info is not None: result["info"] = self.info.serialize() - result["repackage"] = self.repackage + result["bundle"] = self.bundle return result @property diff --git a/conans/model/conf.py b/conans/model/conf.py index 2dde3ea89be..2c136acffa6 100644 --- a/conans/model/conf.py +++ b/conans/model/conf.py @@ -82,7 +82,7 @@ "tools.files.download:retry": "Number of retries in case of failure when downloading", "tools.files.download:retry_wait": "Seconds to wait between download attempts", "tools.files.download:verify": "If set, overrides recipes on whether to perform SSL verification for their downloaded files. Only recommended to be set while testing", - "tools.graph:repackage": "(boolean) Enable/Disable re-packaging", + "tools.graph:bundle": "(Experimental, boolean, default False) Enable the computation of dependencies of package bundles", "tools.graph:skip_binaries": "Allow the graph to skip binaries not needed in the current configuration (True by default)", "tools.gnu:make_program": "Indicate path to make program", "tools.gnu:define_libcxx11_abi": "Force definition of GLIBCXX_USE_CXX11_ABI=1 for libstdc++11", diff --git a/test/integration/command/info/info_test.py b/test/integration/command/info/info_test.py index b087e2e9675..70862585977 100644 --- a/test/integration/command/info/info_test.py +++ b/test/integration/command/info/info_test.py @@ -426,25 +426,26 @@ class Pkg(ConanFile): c.run("graph info . --channel=channel") assert "pkg/0.1@user/channel" in c.out -def test_graph_info_repackage(): + +def test_graph_info_bundle(): c = TestClient(light=True) c.save({"subfolder/conanfile.py": GenConanfile("liba", "1.0")}) c.run("create ./subfolder") conanfile = textwrap.dedent(""" from conan import ConanFile class RepackageRecipe(ConanFile): - name = "repackage-lib" + name = "lib" version = "1.0" def requirements(self): self.requires("liba/1.0") - repackage = True + bundle = True """) c.save({"conanfile.py": conanfile}) c.run("create .") - c.save({"conanfile.py": GenConanfile("consumer", "1.0").with_requires("repackage-lib/1.0")}) + c.save({"conanfile.py": GenConanfile("consumer", "1.0").with_requires("lib/1.0")}) - c.run("graph info . --build='repackage-lib*'") - c.assert_listed_binary({"repackage-lib/1.0": (NO_SETTINGS_PACKAGE_ID, "Invalid")}) + c.run("graph info . --build='lib*'") + c.assert_listed_binary({"lib/1.0": (NO_SETTINGS_PACKAGE_ID, "Invalid")}) - c.run("graph info . -c tools.graph:repackage=True --build='repackage-lib*'") - c.assert_listed_binary({"repackage-lib/1.0": (NO_SETTINGS_PACKAGE_ID, "Build")}) + c.run("graph info . -c tools.graph:bundle=True --build='lib*'") + c.assert_listed_binary({"lib/1.0": (NO_SETTINGS_PACKAGE_ID, "Build")}) diff --git a/test/integration/command_v2/test_inspect.py b/test/integration/command_v2/test_inspect.py index 87cb9a01e04..38bcf7ff0b5 100644 --- a/test/integration/command_v2/test_inspect.py +++ b/test/integration/command_v2/test_inspect.py @@ -20,7 +20,7 @@ def test_basic_inspect(): 'options_definitions:', " shared: ['True', 'False']", 'package_type: None', - 'repackage: False', + 'bundle: False', 'requires: []', 'revision_mode: hash', ] @@ -90,7 +90,7 @@ def test_normal_inspect(): 'options:', 'options_definitions:', 'package_type: None', - 'repackage: False', + 'bundle: False', 'requires: []', 'revision_mode: hash', 'version: 1.0'] @@ -133,7 +133,7 @@ class Pkg(ConanFile): 'options:', 'options_definitions:', 'package_type: None', - 'repackage: False', + 'bundle: False', "requires: [{'ref': 'zlib/1.2.13', 'run': False, 'libs': True, 'skip': " "False, 'test': False, 'force': False, 'direct': True, 'build': " "False, 'transitive_headers': None, 'transitive_libs': None, 'headers': " diff --git a/test/integration/test_repackage.py b/test/integration/test_package_bundle.py similarity index 92% rename from test/integration/test_repackage.py rename to test/integration/test_package_bundle.py index 388cf827eea..b40ef551da8 100644 --- a/test/integration/test_repackage.py +++ b/test/integration/test_package_bundle.py @@ -5,7 +5,7 @@ from conan.test.utils.tools import TestClient -def test_repackage(): +def test_package_bundle(): c = TestClient() app = textwrap.dedent(""" import os @@ -16,7 +16,7 @@ class App(ConanFile): name = "app" version = "0.1" package_type = "application" - repackage = True + bundle = True requires = "pkga/0.1" def package(self): copy(self, "*", src=self.dependencies["pkga"].package_folder, @@ -29,7 +29,7 @@ def package(self): "app/conanfile.py": app }) c.run("create pkga") - c.run("create app") # -c tools.graph:repackage=True will be automatic + c.run("create app") # -c tools.graph:bundle=True will be automatic assert "app/0.1: package(): Packaged 1 '.dll' file: pkga.dll" in c.out # we can safely remove pkga @@ -52,14 +52,14 @@ def package(self): assert c.load("full_deploy/host/app/0.1/pkga.dll") == "dll" # but we can force the expansion, still not the rebuild - c.run("install --requires=app/0.1 --deployer=full_deploy -c tools.graph:repackage=True") + c.run("install --requires=app/0.1 --deployer=full_deploy -c tools.graph:bundle=True") assert "pkga" in c.out assert c.load("full_deploy/host/app/0.1/app.exe") == "app" assert c.load("full_deploy/host/app/0.1/pkga.dll") == "dll" # and finally we can force the expansion and the rebuild c.run("install --requires=app/0.1 --build=app* --deployer=full_deploy " - "-c tools.graph:repackage=True") + "-c tools.graph:bundle=True") assert "pkga" in c.out assert c.load("full_deploy/host/app/0.1/app.exe") == "app" assert c.load("full_deploy/host/app/0.1/pkga.dll") == "newdll" @@ -72,13 +72,13 @@ def package(self): assert "Missing binary" in c.out c.run("install --requires=app/0.1 --build=missing", assert_error=True) assert "app/0.1: Invalid: The package is repackaging and building but it didn't "\ - "enable 'tools.graph:repackage' to compute its dependencies" in c.out + "enable 'tools.graph:bundle' to compute its dependencies" in c.out - c.run("install --requires=app/0.1 --build=missing -c tools.graph:repackage=True") + c.run("install --requires=app/0.1 --build=missing -c tools.graph:bundle=True") assert "pkga" in c.out # it works -def test_repackage_editable(): +def test_package_bundle_editable(): c = TestClient() pkgb = textwrap.dedent(""" import os @@ -89,7 +89,7 @@ class App(ConanFile): name = "pkgb" version = "0.1" package_type = "shared-library" - repackage = True + bundle = True requires = "pkga/0.1" def layout(self): self.folders.build = "build" From feee4125ed899859c20da674c2a1f7fee0f4b957 Mon Sep 17 00:00:00 2001 From: memsharded Date: Sat, 1 Jun 2024 01:39:09 +0200 Subject: [PATCH 11/16] fixes --- conans/client/graph/graph_binaries.py | 9 +++++++++ test/integration/command_v2/test_inspect.py | 12 ++++++------ 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/conans/client/graph/graph_binaries.py b/conans/client/graph/graph_binaries.py index c343ccd2ba1..24b6c7bb9a7 100644 --- a/conans/client/graph/graph_binaries.py +++ b/conans/client/graph/graph_binaries.py @@ -181,6 +181,15 @@ def _evaluate_node(self, node, build_mode, remotes, update): node.build_allowed = True node.binary = BINARY_BUILD if not node.cant_build else BINARY_INVALID + if node.binary == BINARY_BUILD: + conanfile = node.conanfile + if conanfile.bundle and not conanfile.conf.get("tools.graph:bundle", check_type=bool): + node.conanfile.info.invalid = f"The package '{conanfile.ref}' is a package bundle, " \ + f"needs to be built from source, but it " \ + "didn't enable 'tools.graph:bundle' to compute its " \ + "dependencies" + node.binary = BINARY_INVALID + def _process_node(self, node, build_mode, remotes, update): # Check that this same reference hasn't already been checked if self._evaluate_is_cached(node): diff --git a/test/integration/command_v2/test_inspect.py b/test/integration/command_v2/test_inspect.py index 38bcf7ff0b5..e2dcf4a1f1a 100644 --- a/test/integration/command_v2/test_inspect.py +++ b/test/integration/command_v2/test_inspect.py @@ -10,7 +10,8 @@ def test_basic_inspect(): t.save({"foo/conanfile.py": GenConanfile().with_name("foo").with_shared_option()}) t.run("inspect foo/conanfile.py") lines = t.out.splitlines() - assert lines == ['default_options:', + assert lines == ['bundle: False', + 'default_options:', ' shared: False', 'generators: []', 'label: ', @@ -20,7 +21,6 @@ def test_basic_inspect(): 'options_definitions:', " shared: ['True', 'False']", 'package_type: None', - 'bundle: False', 'requires: []', 'revision_mode: hash', ] @@ -81,7 +81,8 @@ def test_normal_inspect(): tc = TestClient() tc.run("new basic -d name=pkg -d version=1.0") tc.run("inspect .") - assert tc.out.splitlines() == ['description: A basic recipe', + assert tc.out.splitlines() == ['bundle: False', + 'description: A basic recipe', 'generators: []', 'homepage: ', 'label: ', @@ -90,7 +91,6 @@ def test_normal_inspect(): 'options:', 'options_definitions:', 'package_type: None', - 'bundle: False', 'requires: []', 'revision_mode: hash', 'version: 1.0'] @@ -127,13 +127,13 @@ class Pkg(ConanFile): """) tc.save({"conanfile.py": conanfile}) tc.run("inspect .") - assert ['generators: []', + assert ['bundle: False', + 'generators: []', 'label: ', "license: ['MIT', 'Apache']", 'options:', 'options_definitions:', 'package_type: None', - 'bundle: False', "requires: [{'ref': 'zlib/1.2.13', 'run': False, 'libs': True, 'skip': " "False, 'test': False, 'force': False, 'direct': True, 'build': " "False, 'transitive_headers': None, 'transitive_libs': None, 'headers': " From 4ff021afa71806ca84baa73e10f87da525847ee1 Mon Sep 17 00:00:00 2001 From: memsharded Date: Sat, 1 Jun 2024 12:45:50 +0200 Subject: [PATCH 12/16] fix test --- test/integration/test_package_bundle.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/integration/test_package_bundle.py b/test/integration/test_package_bundle.py index b40ef551da8..62633923ff6 100644 --- a/test/integration/test_package_bundle.py +++ b/test/integration/test_package_bundle.py @@ -71,8 +71,8 @@ def package(self): c.run("install --requires=app/0.1", assert_error=True) assert "Missing binary" in c.out c.run("install --requires=app/0.1 --build=missing", assert_error=True) - assert "app/0.1: Invalid: The package is repackaging and building but it didn't "\ - "enable 'tools.graph:bundle' to compute its dependencies" in c.out + assert "app/0.1: Invalid: The package 'app/0.1' is a package bundle, needs to be built " \ + "from source, but it didn't enable 'tools.graph:bundle'" in c.out c.run("install --requires=app/0.1 --build=missing -c tools.graph:bundle=True") assert "pkga" in c.out # it works From 4af765a7bb7468379c7fae5dec7077cb2965efad Mon Sep 17 00:00:00 2001 From: memsharded Date: Mon, 3 Jun 2024 16:07:26 +0200 Subject: [PATCH 13/16] rename conf to build_bundle --- conan/cli/commands/create.py | 2 +- conans/client/graph/graph_binaries.py | 4 ++-- conans/client/graph/graph_builder.py | 2 +- conans/model/conf.py | 2 +- test/integration/command/info/info_test.py | 2 +- test/integration/test_package_bundle.py | 10 +++++----- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/conan/cli/commands/create.py b/conan/cli/commands/create.py index 70a1c9c5981..391b0e97498 100644 --- a/conan/cli/commands/create.py +++ b/conan/cli/commands/create.py @@ -97,7 +97,7 @@ def create(conan_api, parser, *args): tool_requires = [ref] if is_build else None if conanfile.bundle: # Automatically allow repackaging for conan create pr = profile_build if is_build else profile_host - pr.conf.update("&:tools.graph:bundle", True) + pr.conf.update("&:tools.graph:build_bundle", True) deps_graph = conan_api.graph.load_graph_requires(requires, tool_requires, profile_host=profile_host, profile_build=profile_build, diff --git a/conans/client/graph/graph_binaries.py b/conans/client/graph/graph_binaries.py index b7eaa1385b5..70d9dd26f68 100644 --- a/conans/client/graph/graph_binaries.py +++ b/conans/client/graph/graph_binaries.py @@ -184,10 +184,10 @@ def _evaluate_node(self, node, build_mode, remotes, update): if node.binary == BINARY_BUILD: conanfile = node.conanfile - if conanfile.bundle and not conanfile.conf.get("tools.graph:bundle", check_type=bool): + if conanfile.bundle and not conanfile.conf.get("tools.graph:build_bundle", check_type=bool): node.conanfile.info.invalid = f"The package '{conanfile.ref}' is a package bundle, " \ f"needs to be built from source, but it " \ - "didn't enable 'tools.graph:bundle' to compute its " \ + "didn't enable 'tools.graph:build_bundle' to compute its " \ "dependencies" node.binary = BINARY_INVALID diff --git a/conans/client/graph/graph_builder.py b/conans/client/graph/graph_builder.py index c09c13b5dac..e3b422f5d85 100644 --- a/conans/client/graph/graph_builder.py +++ b/conans/client/graph/graph_builder.py @@ -54,7 +54,7 @@ def load_graph(self, root_node, profile_host, profile_build, graph_lock=None): profile_build, graph_lock) if new_node and (not new_node.conanfile.bundle or new_node.recipe == RECIPE_EDITABLE or - new_node.conanfile.conf.get("tools.graph:bundle", check_type=bool)): + new_node.conanfile.conf.get("tools.graph:build_bundle", check_type=bool)): self._initialize_requires(new_node, dep_graph, graph_lock, profile_build, profile_host) open_requires.extendleft((r, new_node) diff --git a/conans/model/conf.py b/conans/model/conf.py index 1b9ddf1510e..03abd1f72de 100644 --- a/conans/model/conf.py +++ b/conans/model/conf.py @@ -83,7 +83,7 @@ "tools.files.download:retry": "Number of retries in case of failure when downloading", "tools.files.download:retry_wait": "Seconds to wait between download attempts", "tools.files.download:verify": "If set, overrides recipes on whether to perform SSL verification for their downloaded files. Only recommended to be set while testing", - "tools.graph:bundle": "(Experimental, boolean, default False) Enable the computation of dependencies of package bundles", + "tools.graph:build_bundle": "(Experimental, boolean, default False) Enable the computation of dependencies of package bundles to build them", "tools.graph:skip_binaries": "Allow the graph to skip binaries not needed in the current configuration (True by default)", "tools.gnu:make_program": "Indicate path to make program", "tools.gnu:define_libcxx11_abi": "Force definition of GLIBCXX_USE_CXX11_ABI=1 for libstdc++11", diff --git a/test/integration/command/info/info_test.py b/test/integration/command/info/info_test.py index 70862585977..0771756c540 100644 --- a/test/integration/command/info/info_test.py +++ b/test/integration/command/info/info_test.py @@ -447,5 +447,5 @@ def requirements(self): c.run("graph info . --build='lib*'") c.assert_listed_binary({"lib/1.0": (NO_SETTINGS_PACKAGE_ID, "Invalid")}) - c.run("graph info . -c tools.graph:bundle=True --build='lib*'") + c.run("graph info . -c tools.graph:build_bundle=True --build='lib*'") c.assert_listed_binary({"lib/1.0": (NO_SETTINGS_PACKAGE_ID, "Build")}) diff --git a/test/integration/test_package_bundle.py b/test/integration/test_package_bundle.py index 62633923ff6..cecca7a454a 100644 --- a/test/integration/test_package_bundle.py +++ b/test/integration/test_package_bundle.py @@ -29,7 +29,7 @@ def package(self): "app/conanfile.py": app }) c.run("create pkga") - c.run("create app") # -c tools.graph:bundle=True will be automatic + c.run("create app") # -c tools.graph:build_bundle=True will be automatic assert "app/0.1: package(): Packaged 1 '.dll' file: pkga.dll" in c.out # we can safely remove pkga @@ -52,14 +52,14 @@ def package(self): assert c.load("full_deploy/host/app/0.1/pkga.dll") == "dll" # but we can force the expansion, still not the rebuild - c.run("install --requires=app/0.1 --deployer=full_deploy -c tools.graph:bundle=True") + c.run("install --requires=app/0.1 --deployer=full_deploy -c tools.graph:build_bundle=True") assert "pkga" in c.out assert c.load("full_deploy/host/app/0.1/app.exe") == "app" assert c.load("full_deploy/host/app/0.1/pkga.dll") == "dll" # and finally we can force the expansion and the rebuild c.run("install --requires=app/0.1 --build=app* --deployer=full_deploy " - "-c tools.graph:bundle=True") + "-c tools.graph:build_bundle=True") assert "pkga" in c.out assert c.load("full_deploy/host/app/0.1/app.exe") == "app" assert c.load("full_deploy/host/app/0.1/pkga.dll") == "newdll" @@ -72,9 +72,9 @@ def package(self): assert "Missing binary" in c.out c.run("install --requires=app/0.1 --build=missing", assert_error=True) assert "app/0.1: Invalid: The package 'app/0.1' is a package bundle, needs to be built " \ - "from source, but it didn't enable 'tools.graph:bundle'" in c.out + "from source, but it didn't enable 'tools.graph:build_bundle'" in c.out - c.run("install --requires=app/0.1 --build=missing -c tools.graph:bundle=True") + c.run("install --requires=app/0.1 --build=missing -c tools.graph:build_bundle=True") assert "pkga" in c.out # it works From f1987ca1819f2f075a8b777207c15657ddaafad1 Mon Sep 17 00:00:00 2001 From: memsharded Date: Mon, 3 Jun 2024 20:10:25 +0200 Subject: [PATCH 14/16] renames --- conan/cli/commands/create.py | 4 ++-- conan/cli/formatters/graph/info_graph_html.py | 4 ++-- conans/client/graph/compute_pid.py | 2 +- conans/client/graph/graph.py | 4 ++-- conans/client/graph/graph_binaries.py | 8 ++++---- conans/client/graph/graph_builder.py | 5 +++-- conans/model/conan_file.py | 4 ++-- conans/model/conf.py | 2 +- test/integration/command/info/info_test.py | 4 ++-- test/integration/command_v2/test_inspect.py | 14 +++++++------- ..._package_bundle.py => test_package_vendor.py} | 16 ++++++++-------- 11 files changed, 34 insertions(+), 33 deletions(-) rename test/integration/{test_package_bundle.py => test_package_vendor.py} (91%) diff --git a/conan/cli/commands/create.py b/conan/cli/commands/create.py index 391b0e97498..13fa6d337e5 100644 --- a/conan/cli/commands/create.py +++ b/conan/cli/commands/create.py @@ -95,9 +95,9 @@ def create(conan_api, parser, *args): else: requires = [ref] if not is_build else None tool_requires = [ref] if is_build else None - if conanfile.bundle: # Automatically allow repackaging for conan create + if conanfile.vendor: # Automatically allow repackaging for conan create pr = profile_build if is_build else profile_host - pr.conf.update("&:tools.graph:build_bundle", True) + pr.conf.update("&:tools.graph:vendor", "build") deps_graph = conan_api.graph.load_graph_requires(requires, tool_requires, profile_host=profile_host, profile_build=profile_build, diff --git a/conan/cli/formatters/graph/info_graph_html.py b/conan/cli/formatters/graph/info_graph_html.py index 00091c8cbbd..67db93e2ff9 100644 --- a/conan/cli/formatters/graph/info_graph_html.py +++ b/conan/cli/formatters/graph/info_graph_html.py @@ -144,7 +144,7 @@ if (node.recipe == "Platform") { font.background = "Violet"; } - if (node.bundle) { + if (node.vendor) { borderColor = "Red"; shapeProperties = {borderDashes: [3,5]}; borderWidth = 2; @@ -233,7 +233,7 @@ counter++; legend_nodes.push({x: x + counter*step, y: y, shape: "box", - label: "bundle", font: {size: 35}, + label: "vendor", font: {size: 35}, color: {border: "Red"}, shapeProperties: {borderDashes: [3,5]}, borderWidth: 2 diff --git a/conans/client/graph/compute_pid.py b/conans/client/graph/compute_pid.py index 15221fbc373..cbfff70991f 100644 --- a/conans/client/graph/compute_pid.py +++ b/conans/client/graph/compute_pid.py @@ -38,7 +38,7 @@ def compute_package_id(node, new_config, config_version): else: data[require] = req_info - if conanfile.bundle: # Make the package_id fully independent of dependencies versions + if conanfile.vendor: # Make the package_id fully independent of dependencies versions data, build_data = OrderedDict(), OrderedDict() # TODO, cleaner, now minimal diff reqs_info = RequirementsInfo(data) diff --git a/conans/client/graph/graph.py b/conans/client/graph/graph.py index f10bad819a6..9ef6395022e 100644 --- a/conans/client/graph/graph.py +++ b/conans/client/graph/graph.py @@ -108,7 +108,7 @@ def propagate_downstream(self, require, node, src_node=None): self.transitive_deps.pop(require, None) self.transitive_deps[require] = TransitiveRequirement(require, node) - if self.conanfile.bundle: + if self.conanfile.vendor: return # Check if need to propagate downstream if not self.dependants: @@ -158,7 +158,7 @@ def check_downstream_exists(self, require): # Seems the algrithm depth-first, would only have 1 dependant at most to propagate down # at any given time - if self.conanfile.bundle: + if self.conanfile.vendor: return result if not self.dependants: return result diff --git a/conans/client/graph/graph_binaries.py b/conans/client/graph/graph_binaries.py index 70d9dd26f68..51481d77e57 100644 --- a/conans/client/graph/graph_binaries.py +++ b/conans/client/graph/graph_binaries.py @@ -184,11 +184,11 @@ def _evaluate_node(self, node, build_mode, remotes, update): if node.binary == BINARY_BUILD: conanfile = node.conanfile - if conanfile.bundle and not conanfile.conf.get("tools.graph:build_bundle", check_type=bool): - node.conanfile.info.invalid = f"The package '{conanfile.ref}' is a package bundle, " \ + if conanfile.vendor and not conanfile.conf.get("tools.graph:vendor", choices=("build",)): + node.conanfile.info.invalid = f"The package '{conanfile.ref}' is a vendoring one, " \ f"needs to be built from source, but it " \ - "didn't enable 'tools.graph:build_bundle' to compute its " \ - "dependencies" + "didn't enable 'tools.graph:vendor=build' to compute " \ + "its dependencies" node.binary = BINARY_INVALID def _process_node(self, node, build_mode, remotes, update): diff --git a/conans/client/graph/graph_builder.py b/conans/client/graph/graph_builder.py index e3b422f5d85..f678d958138 100644 --- a/conans/client/graph/graph_builder.py +++ b/conans/client/graph/graph_builder.py @@ -52,9 +52,10 @@ def load_graph(self, root_node, profile_host, profile_build, graph_lock=None): continue new_node = self._expand_require(require, node, dep_graph, profile_host, profile_build, graph_lock) - if new_node and (not new_node.conanfile.bundle + if new_node and (not new_node.conanfile.vendor or new_node.recipe == RECIPE_EDITABLE or - new_node.conanfile.conf.get("tools.graph:build_bundle", check_type=bool)): + new_node.conanfile.conf.get("tools.graph:vendor", + choices=("build",))): self._initialize_requires(new_node, dep_graph, graph_lock, profile_build, profile_host) open_requires.extendleft((r, new_node) diff --git a/conans/model/conan_file.py b/conans/model/conan_file.py index f432ffed76a..94f4acec886 100644 --- a/conans/model/conan_file.py +++ b/conans/model/conan_file.py @@ -47,7 +47,7 @@ class ConanFile: default_options = None default_build_options = None package_type = None - bundle = False + vendor = False implements = [] @@ -167,7 +167,7 @@ def serialize(self): result["label"] = self.display_name if self.info is not None: result["info"] = self.info.serialize() - result["bundle"] = self.bundle + result["vendor"] = self.vendor return result @property diff --git a/conans/model/conf.py b/conans/model/conf.py index 03abd1f72de..49a27c3ff17 100644 --- a/conans/model/conf.py +++ b/conans/model/conf.py @@ -83,7 +83,7 @@ "tools.files.download:retry": "Number of retries in case of failure when downloading", "tools.files.download:retry_wait": "Seconds to wait between download attempts", "tools.files.download:verify": "If set, overrides recipes on whether to perform SSL verification for their downloaded files. Only recommended to be set while testing", - "tools.graph:build_bundle": "(Experimental, boolean, default False) Enable the computation of dependencies of package bundles to build them", + "tools.graph:vendor": "(Experimental) If 'build', enables the computation of dependencies of vendoring packages to build them", "tools.graph:skip_binaries": "Allow the graph to skip binaries not needed in the current configuration (True by default)", "tools.gnu:make_program": "Indicate path to make program", "tools.gnu:define_libcxx11_abi": "Force definition of GLIBCXX_USE_CXX11_ABI=1 for libstdc++11", diff --git a/test/integration/command/info/info_test.py b/test/integration/command/info/info_test.py index 0771756c540..e2bde2a0acb 100644 --- a/test/integration/command/info/info_test.py +++ b/test/integration/command/info/info_test.py @@ -438,7 +438,7 @@ class RepackageRecipe(ConanFile): version = "1.0" def requirements(self): self.requires("liba/1.0") - bundle = True + vendor = True """) c.save({"conanfile.py": conanfile}) c.run("create .") @@ -447,5 +447,5 @@ def requirements(self): c.run("graph info . --build='lib*'") c.assert_listed_binary({"lib/1.0": (NO_SETTINGS_PACKAGE_ID, "Invalid")}) - c.run("graph info . -c tools.graph:build_bundle=True --build='lib*'") + c.run("graph info . -c tools.graph:vendor=build --build='lib*'") c.assert_listed_binary({"lib/1.0": (NO_SETTINGS_PACKAGE_ID, "Build")}) diff --git a/test/integration/command_v2/test_inspect.py b/test/integration/command_v2/test_inspect.py index e2dcf4a1f1a..ef88855f38b 100644 --- a/test/integration/command_v2/test_inspect.py +++ b/test/integration/command_v2/test_inspect.py @@ -10,8 +10,7 @@ def test_basic_inspect(): t.save({"foo/conanfile.py": GenConanfile().with_name("foo").with_shared_option()}) t.run("inspect foo/conanfile.py") lines = t.out.splitlines() - assert lines == ['bundle: False', - 'default_options:', + assert lines == ['default_options:', ' shared: False', 'generators: []', 'label: ', @@ -23,6 +22,7 @@ def test_basic_inspect(): 'package_type: None', 'requires: []', 'revision_mode: hash', + 'vendor: False' ] @@ -81,8 +81,7 @@ def test_normal_inspect(): tc = TestClient() tc.run("new basic -d name=pkg -d version=1.0") tc.run("inspect .") - assert tc.out.splitlines() == ['bundle: False', - 'description: A basic recipe', + assert tc.out.splitlines() == ['description: A basic recipe', 'generators: []', 'homepage: ', 'label: ', @@ -93,6 +92,7 @@ def test_normal_inspect(): 'package_type: None', 'requires: []', 'revision_mode: hash', + 'vendor: False', 'version: 1.0'] @@ -127,8 +127,7 @@ class Pkg(ConanFile): """) tc.save({"conanfile.py": conanfile}) tc.run("inspect .") - assert ['bundle: False', - 'generators: []', + assert ['generators: []', 'label: ', "license: ['MIT', 'Apache']", 'options:', @@ -138,7 +137,8 @@ class Pkg(ConanFile): "False, 'test': False, 'force': False, 'direct': True, 'build': " "False, 'transitive_headers': None, 'transitive_libs': None, 'headers': " "True, 'package_id_mode': None, 'visible': True}]", - 'revision_mode: hash'] == tc.out.splitlines() + 'revision_mode: hash', + 'vendor: False'] == tc.out.splitlines() def test_pythonrequires_remote(): diff --git a/test/integration/test_package_bundle.py b/test/integration/test_package_vendor.py similarity index 91% rename from test/integration/test_package_bundle.py rename to test/integration/test_package_vendor.py index cecca7a454a..f5d81dfd3a9 100644 --- a/test/integration/test_package_bundle.py +++ b/test/integration/test_package_vendor.py @@ -16,7 +16,7 @@ class App(ConanFile): name = "app" version = "0.1" package_type = "application" - bundle = True + vendor = True requires = "pkga/0.1" def package(self): copy(self, "*", src=self.dependencies["pkga"].package_folder, @@ -29,7 +29,7 @@ def package(self): "app/conanfile.py": app }) c.run("create pkga") - c.run("create app") # -c tools.graph:build_bundle=True will be automatic + c.run("create app") # -c tools.graph:vendor=build will be automatic assert "app/0.1: package(): Packaged 1 '.dll' file: pkga.dll" in c.out # we can safely remove pkga @@ -52,14 +52,14 @@ def package(self): assert c.load("full_deploy/host/app/0.1/pkga.dll") == "dll" # but we can force the expansion, still not the rebuild - c.run("install --requires=app/0.1 --deployer=full_deploy -c tools.graph:build_bundle=True") + c.run("install --requires=app/0.1 --deployer=full_deploy -c tools.graph:vendor=build") assert "pkga" in c.out assert c.load("full_deploy/host/app/0.1/app.exe") == "app" assert c.load("full_deploy/host/app/0.1/pkga.dll") == "dll" # and finally we can force the expansion and the rebuild c.run("install --requires=app/0.1 --build=app* --deployer=full_deploy " - "-c tools.graph:build_bundle=True") + "-c tools.graph:vendor=build") assert "pkga" in c.out assert c.load("full_deploy/host/app/0.1/app.exe") == "app" assert c.load("full_deploy/host/app/0.1/pkga.dll") == "newdll" @@ -71,10 +71,10 @@ def package(self): c.run("install --requires=app/0.1", assert_error=True) assert "Missing binary" in c.out c.run("install --requires=app/0.1 --build=missing", assert_error=True) - assert "app/0.1: Invalid: The package 'app/0.1' is a package bundle, needs to be built " \ - "from source, but it didn't enable 'tools.graph:build_bundle'" in c.out + assert "app/0.1: Invalid: The package 'app/0.1' is a vendoring one, needs to be built " \ + "from source, but it didn't enable 'tools.graph:vendor=build'" in c.out - c.run("install --requires=app/0.1 --build=missing -c tools.graph:build_bundle=True") + c.run("install --requires=app/0.1 --build=missing -c tools.graph:vendor=build") assert "pkga" in c.out # it works @@ -89,7 +89,7 @@ class App(ConanFile): name = "pkgb" version = "0.1" package_type = "shared-library" - bundle = True + vendor = True requires = "pkga/0.1" def layout(self): self.folders.build = "build" From 9926b0bc2b23ef0a17c4c773687c7150d9aefd60 Mon Sep 17 00:00:00 2001 From: memsharded Date: Mon, 3 Jun 2024 21:13:48 +0200 Subject: [PATCH 15/16] avoid propagate options --- conans/client/graph/graph_builder.py | 5 +++-- test/integration/test_package_vendor.py | 25 +++++++++++++++++++++++-- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/conans/client/graph/graph_builder.py b/conans/client/graph/graph_builder.py index f678d958138..41793dee9e6 100644 --- a/conans/client/graph/graph_builder.py +++ b/conans/client/graph/graph_builder.py @@ -389,6 +389,7 @@ def _create_new_node(self, node, require, graph, profile_host, profile_build, gr @staticmethod def _compute_down_options(node, require, new_ref): # The consumer "up_options" are the options that come from downstream to this node + visible = require.visible and not node.conanfile.vendor if require.options is not None: # If the consumer has specified "requires(options=xxx)", we need to use it # It will have less priority than downstream consumers @@ -398,11 +399,11 @@ def _compute_down_options(node, require, new_ref): # options["dep"].opt=value only propagate to visible and host dependencies # we will evaluate if necessary a potential "build_options", but recall that it is # now possible to do "self.build_requires(..., options={k:v})" to specify it - if require.visible: + if visible: # Only visible requirements in the host context propagate options from downstream down_options.update_options(node.conanfile.up_options) else: - if require.visible: + if visible: down_options = node.conanfile.up_options elif not require.build: # for requires in "host", like test_requires, pass myoptions down_options = node.conanfile.private_up_options diff --git a/test/integration/test_package_vendor.py b/test/integration/test_package_vendor.py index f5d81dfd3a9..562ae4cd386 100644 --- a/test/integration/test_package_vendor.py +++ b/test/integration/test_package_vendor.py @@ -5,7 +5,7 @@ from conan.test.utils.tools import TestClient -def test_package_bundle(): +def test_package_vendor(): c = TestClient() app = textwrap.dedent(""" import os @@ -78,7 +78,7 @@ def package(self): assert "pkga" in c.out # it works -def test_package_bundle_editable(): +def test_package_vendor_editable(): c = TestClient() pkgb = textwrap.dedent(""" import os @@ -117,3 +117,24 @@ def build(self): # But the environment file needed to build "pkgb" has visibility over the "pkga" paths envfile_pkgb = c.load("pkgb/conanrunenv.sh") assert "pkga" in envfile_pkgb + + +def test_vendor_dont_propagate_options(): + c = TestClient() + app = GenConanfile("app", "0.1").with_requires("pkga/0.1").with_class_attribute("vendor=True") + c.save({"pkga/conanfile.py": GenConanfile("pkga", "0.1").with_shared_option(False), + "app/conanfile.py": app, + "consumer/conanfile.txt": "[requires]\napp/0.1", + "consumer_shared/conanfile.txt": "[requires]\napp/0.1\n[options]\n*:shared=True" + }) + c.run("create pkga") + c.assert_listed_binary({"pkga/0.1": ("55c609fe8808aa5308134cb5989d23d3caffccf2", "Build")}) + c.run("create app") + c.assert_listed_binary({"pkga/0.1": ("55c609fe8808aa5308134cb5989d23d3caffccf2", "Cache"), + "app/0.1": ("da39a3ee5e6b4b0d3255bfef95601890afd80709", "Build")}) + c.run("install consumer --build=app/* -c tools.graph:vendor=build") + c.assert_listed_binary({"pkga/0.1": ("55c609fe8808aa5308134cb5989d23d3caffccf2", "Cache"), + "app/0.1": ("da39a3ee5e6b4b0d3255bfef95601890afd80709", "Build")}) + c.run("install consumer_shared --build=app/* -c tools.graph:vendor=build") + c.assert_listed_binary({"pkga/0.1": ("55c609fe8808aa5308134cb5989d23d3caffccf2", "Cache"), + "app/0.1": ("da39a3ee5e6b4b0d3255bfef95601890afd80709", "Build")}) From cdb1245937ead131eee6889c4c19e8df71f9b5ab Mon Sep 17 00:00:00 2001 From: James Date: Tue, 4 Jun 2024 16:28:07 +0200 Subject: [PATCH 16/16] Update conans/client/graph/graph.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Rubén Rincón Blanco --- conans/client/graph/graph.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/conans/client/graph/graph.py b/conans/client/graph/graph.py index 9ef6395022e..74a7f0273e9 100644 --- a/conans/client/graph/graph.py +++ b/conans/client/graph/graph.py @@ -156,10 +156,10 @@ def check_downstream_exists(self, require): # Check if need to propagate downstream # Then propagate downstream - # Seems the algrithm depth-first, would only have 1 dependant at most to propagate down - # at any given time if self.conanfile.vendor: return result + # Seems the algrithm depth-first, would only have 1 dependant at most to propagate down + # at any given time if not self.dependants: return result assert len(self.dependants) == 1