From 5adc67f2c95220a49bc5c4817b4796abfb987fa8 Mon Sep 17 00:00:00 2001 From: memsharded Date: Tue, 23 Apr 2024 11:54:18 +0200 Subject: [PATCH 1/2] possibility to require itself, previous version visible=False --- conans/client/graph/graph.py | 2 + .../integration/graph/test_repackaging.py | 112 ++++++++++++++++++ 2 files changed, 114 insertions(+) diff --git a/conans/client/graph/graph.py b/conans/client/graph/graph.py index f6f1ba5cb53..07b070d0db6 100644 --- a/conans/client/graph/graph.py +++ b/conans/client/graph/graph.py @@ -128,6 +128,8 @@ def check_downstream_exists(self, require): if require.build and (self.context == CONTEXT_HOST or # switch context require.ref.version != self.ref.version): # or different version pass + elif require.visible is False and require.ref.version != self.ref.version: + pass # An invisible require doesn't conflict with itself else: return None, self, self # First is the require, as it is a loop => None diff --git a/conans/test/integration/graph/test_repackaging.py b/conans/test/integration/graph/test_repackaging.py index cf3db8ef5c4..9a23d8fa9b5 100644 --- a/conans/test/integration/graph/test_repackaging.py +++ b/conans/test/integration/graph/test_repackaging.py @@ -37,3 +37,115 @@ def package(self): client.run("install .") assert re.search(r"Skipped binaries(\s*)liba/1.0, libb/1.0", client.out) assert "repackager/1.0: Already installed!" in client.out + + +def test_repackage_library_self(): + c = TestClient() + c.save({"conanfile.py": GenConanfile("liba", "1.0").with_package_file("a.txt", "A1.0!")}) + c.run("create .") + + conanfile = textwrap.dedent(""" + import os + from conan import ConanFile + from conan.tools.files import copy + class Pkg(ConanFile): + name = "liba" + version = "2.0" + + def requirements(self): + self.requires("liba/1.0", visible=False) + + def package(self): + for _, dep in self.dependencies.items(): + copy(self, "*", src=dep.package_folder, dst=self.package_folder) + """) + c.save({"conanfile.py": conanfile}) + c.run("create .") + + c.run("install --requires=liba/2.0 --deployer=full_deploy") + assert re.search(r"Skipped binaries(\s*)liba/1.0", c.out) + assert "liba/2.0: Already installed!" in c.out + assert c.load("full_deploy/host/liba/2.0/a.txt") == "A1.0!" + + +def test_repackage_library_self_infinite_loop(): + c = TestClient() + + conanfile = textwrap.dedent(""" + from conan import ConanFile + class Pkg(ConanFile): + name = "liba" + version = "1.0" + + def requirements(self): + self.requires("liba/1.0", visible=False, headers=False, libs=False, run=False) + """) + c.save({"conanfile.py": conanfile}) + c.run("create .", assert_error=True) + assert "There is a cycle/loop in the graph" in c.out + + +def test_repackage_library_self_multiple(): + c = TestClient() + c.save({"1/conanfile.py": GenConanfile("liba", "1.0").with_package_file("a1.txt", "A1.0!"), + "2/conanfile.py": GenConanfile("liba", "2.0").with_package_file("a2.txt", "A2.0!")}) + c.run("create 1") + c.run("create 2") + + conanfile = textwrap.dedent(""" + import os + from conan import ConanFile + from conan.tools.files import copy + class Pkg(ConanFile): + name = "liba" + version = "3.0" + + def requirements(self): + # To avoid conflict among liba versions + self.requires("liba/1.0", headers=False, libs=False, visible=False) + self.requires("liba/2.0", visible=False) + + def package(self): + for _, dep in self.dependencies.items(): + copy(self, "*", src=dep.package_folder, dst=self.package_folder) + """) + c.save({"conanfile.py": conanfile}) + c.run("create .") + + c.run("install --requires=liba/3.0 --deployer=full_deploy") + assert re.search(r"Skipped binaries(\s*)liba/1.0, liba/2.0", c.out) + assert "liba/3.0: Already installed!" in c.out + assert c.load("full_deploy/host/liba/3.0/a1.txt") == "A1.0!" + assert c.load("full_deploy/host/liba/3.0/a2.txt") == "A2.0!" + + +def test_repackage_library_self_transitive(): + c = TestClient() + c.save({"a/conanfile.py": GenConanfile("liba", "1.0").with_package_file("a1.txt", "A1.0!"), + "b/conanfile.py": GenConanfile("libb", "1.0").with_requires("liba/1.0")}) + c.run("create a") + c.run("create b") + + conanfile = textwrap.dedent(""" + import os + from conan import ConanFile + from conan.tools.files import copy + class Pkg(ConanFile): + name = "liba" + version = "3.0" + + def requirements(self): + # libs=True, otherwise transitive liba is skipped + self.requires("libb/1.0", headers=False, libs=True, visible=False, run=False) + + def package(self): + for _, dep in self.dependencies.items(): + copy(self, "*", src=dep.package_folder, dst=self.package_folder) + """) + c.save({"conanfile.py": conanfile}) + c.run("create .") + + c.run("install --requires=liba/3.0 --deployer=full_deploy") + assert re.search(r"Skipped binaries(\s*)liba/1.0, libb/1.0", c.out) + assert "liba/3.0: Already installed!" in c.out + assert c.load("full_deploy/host/liba/3.0/a1.txt") == "A1.0!" From e60f2c3c59deee7ab33d56c3c296ec641d98b362 Mon Sep 17 00:00:00 2001 From: memsharded Date: Wed, 8 May 2024 13:25:13 +0200 Subject: [PATCH 2/2] add comment --- conans/client/graph/graph.py | 1 + 1 file changed, 1 insertion(+) diff --git a/conans/client/graph/graph.py b/conans/client/graph/graph.py index 07b070d0db6..0a3c718e539 100644 --- a/conans/client/graph/graph.py +++ b/conans/client/graph/graph.py @@ -129,6 +129,7 @@ def check_downstream_exists(self, require): require.ref.version != self.ref.version): # or different version pass elif require.visible is False and require.ref.version != self.ref.version: + # Experimental, to support repackaging of openssl previous versions FIPS plugins pass # An invisible require doesn't conflict with itself else: return None, self, self # First is the require, as it is a loop => None