From feec4931bda20d61c4244ff7898b9bb2750248e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Abril=20Rinc=C3=B3n=20Blanco?= Date: Wed, 10 Jul 2024 14:02:57 +0200 Subject: [PATCH 01/49] Sketch first approach for install method in ConanFile --------- Co-authored-by: PerseoGI --- .../internal/cache/conan_reference_layout.py | 8 +- conan/test/assets/genconanfile.py | 27 +++- conans/client/installer.py | 9 ++ conans/model/conan_file.py | 4 + conans/model/layout.py | 8 ++ .../conanfile/test_install_method.py | 119 ++++++++++++++++++ 6 files changed, 172 insertions(+), 3 deletions(-) create mode 100644 test/integration/conanfile/test_install_method.py diff --git a/conan/internal/cache/conan_reference_layout.py b/conan/internal/cache/conan_reference_layout.py index 9933dcbbbb8..4817e024635 100644 --- a/conan/internal/cache/conan_reference_layout.py +++ b/conan/internal/cache/conan_reference_layout.py @@ -10,6 +10,7 @@ SRC_FOLDER = "s" BUILD_FOLDER = "b" PACKAGES_FOLDER = "p" +INSTALL_FOLDER = "i" EXPORT_FOLDER = "e" EXPORT_SRC_FOLDER = "es" DOWNLOAD_EXPORT_FOLDER = "d" @@ -55,7 +56,7 @@ def export_sources(self): return os.path.join(self._base_folder, EXPORT_SRC_FOLDER) def metadata(self): - return os.path.join(self.download_export(), "metadata") + return os.path.join(self.download_export(), METADATA) def download_export(self): return os.path.join(self._base_folder, DOWNLOAD_EXPORT_FOLDER) @@ -99,11 +100,14 @@ def build(self): def package(self): return os.path.join(self._base_folder, PACKAGES_FOLDER) + def install(self): + return os.path.join(self._base_folder, INSTALL_FOLDER) + def download_package(self): return os.path.join(self._base_folder, DOWNLOAD_EXPORT_FOLDER) def metadata(self): - return os.path.join(self.download_package(), "metadata") + return os.path.join(self.download_package(), METADATA) def package_manifests(self): package_folder = self.package() diff --git a/conan/test/assets/genconanfile.py b/conan/test/assets/genconanfile.py index ebd4ae121a5..fea77cbd434 100644 --- a/conan/test/assets/genconanfile.py +++ b/conan/test/assets/genconanfile.py @@ -27,6 +27,7 @@ def __init__(self, name=None, version=None): self._provides = None self._deprecated = None self._package_lines = None + self._install_lines = None self._package_files = None self._package_files_env = None self._package_files_link = None @@ -207,6 +208,12 @@ def with_package(self, *lines): self._package_lines.append(line) return self + def with_install(self, *lines): + self._install_lines = self._install_lines or [] + for line in lines: + self._install_lines.append(line) + return self + def with_build_msg(self, msg): self._build_messages = self._build_messages or [] self._build_messages.append(msg) @@ -360,6 +367,10 @@ def _package_method(self): return (self._package_lines or self._package_files or self._package_files_env or self._package_files_link) + @property + def _install_method(self): + return self._install_lines + @property def _package_method_render(self): lines = [] @@ -388,6 +399,19 @@ def package(self): {} """.format("\n".join(lines)) + @property + def _install_method_render(self): + lines = [] + if self._install_lines: + lines.extend(" {}".format(line) for line in self._install_lines) + + if not lines: + return "" + return """ + def install(self): + {} + """.format("\n".join(lines)) + @property def _build_render(self): if not self._build_messages and not self._cmake_build: @@ -463,7 +487,8 @@ def __repr__(self): "exports_sources", "exports", "generators", "requires", "build_requires", "tool_requires", "test_requires", "requirements", "python_requires", "revision_mode", "settings", "options", "default_options", "build", - "package_method", "package_info", "package_id_lines", "test_lines" + "package_method", "package_info", "package_id_lines", "test_lines", + "install_method" ): if member == "requirements": # FIXME: This seems exclusive, but we could mix them? diff --git a/conans/client/installer.py b/conans/client/installer.py index ea679f44e56..1762276c2cc 100644 --- a/conans/client/installer.py +++ b/conans/client/installer.py @@ -338,6 +338,15 @@ def _handle_package(self, package, install_reference, handled_count, total_count # Call the info method conanfile.folders.set_base_package(pkg_folder) conanfile.folders.set_base_pkg_metadata(pkg_metadata) + # TODO: Add install() method call and redirect package_folder to the install folder + if hasattr(conanfile, "install"): + install_folder = package_layout.install() + conanfile.folders.set_install_folder(install_folder) + if not os.path.exists(install_folder): + mkdir(install_folder) + with conanfile_exception_formatter(conanfile, "install"): + conanfile.install() + conanfile.folders.set_base_package(install_folder) self._call_package_info(conanfile, pkg_folder, is_editable=False) def _handle_node_editable(self, install_node): diff --git a/conans/model/conan_file.py b/conans/model/conan_file.py index 0c6bedc7e6d..64297587a6e 100644 --- a/conans/model/conan_file.py +++ b/conans/model/conan_file.py @@ -318,6 +318,10 @@ def package_folder(self): """ return self.folders.base_package + @property + def install_folder(self): + return self.folders.install_folder + @property def generators_folder(self): return self.folders.generators_folder diff --git a/conans/model/layout.py b/conans/model/layout.py index a06795550f8..b89b7f4dcfe 100644 --- a/conans/model/layout.py +++ b/conans/model/layout.py @@ -49,6 +49,7 @@ def __init__(self): self.source = "" self.build = "" self.package = "" + self.install = "" self.generators = "" # Relative location of the project root, if the conanfile is not in that project root, but # in a subfolder: e.g: If the conanfile is in a subfolder then self.root = ".." @@ -142,6 +143,13 @@ def package_folder(self): """For the cache, the package folder is only the base""" return self._base_package + def set_install_folder(self, folder): + self.install = folder + + @property + def install_folder(self): + return self.install + @property def generators_folder(self): if self._base_generators is None: diff --git a/test/integration/conanfile/test_install_method.py b/test/integration/conanfile/test_install_method.py new file mode 100644 index 00000000000..dc22da2c87d --- /dev/null +++ b/test/integration/conanfile/test_install_method.py @@ -0,0 +1,119 @@ +import os +import textwrap + +from conan.test.assets.genconanfile import GenConanfile + +from conan.test.utils.tools import TestClient + + +def test_basic_install_method(): + tc = TestClient(light=True) + conanfile = textwrap.dedent(""" + import os + from conan import ConanFile + from conan.tools.files import save, copy + + class TestConan(ConanFile): + name = "app" + version = "1.0" + def package(self): + save(self, os.path.join(self.package_folder, "file.txt"), "Hello World! - {}") + + def install(self): + self.output.info(f"Running install method in {self.install_folder}") + # copy(self, "*", src=self.package_folder, dst=self.install_folder) + copy(self, "file.txt", src=self.package_folder, dst=self.install_folder) + + def package_info(self): + self.output.info(f"Running package_info method in {self.package_folder}") + """) + tc.save({"conanfile.py": conanfile}) + tc.run("create .") + print() + tc.run("install --requires=app/1.0") + print() + + +def test_dependency_install_method(): + tc = TestClient(light=True) + conanfile = textwrap.dedent(""" + import os + from conan import ConanFile + from conan.tools.files import save, copy + + class TestConan(ConanFile): + name = "dep" + version = "1.0" + def package(self): + save(self, os.path.join(self.package_folder, "file.txt"), "Hello World! - {}") + + def install(self): + self.output.info(f"Running install method in {self.install_folder}") + # copy(self, "*", src=self.package_folder, dst=self.install_folder) + copy(self, "file.txt", src=self.package_folder, dst=self.install_folder) + + def package_info(self): + self.output.info(f"Running package_info method in {self.package_folder}") + """) + tc.save({"dep/conanfile.py": conanfile, + "conanfile.py": textwrap.dedent(""" + from conan import ConanFile + class TestConan(ConanFile): + name = "app" + version = "1.0" + requires = "dep/1.0" + def generate(self): + self.output.info("Running generate method") + dep_pkg_folder = self.dependencies["dep"].package_folder + self.output.info(f"Dep package folder: {dep_pkg_folder}") + """)}) + tc.run("create dep") + tc.run("create .") + print() + + +def test_remote_upload_install_method(): + tc = TestClient(light=True, default_server_user=True) + conanfile = textwrap.dedent(""" + import os + from conan import ConanFile + from conan.tools.files import save, copy + + class TestConan(ConanFile): + name = "dep" + version = "1.0" + def package(self): + save(self, os.path.join(self.package_folder, "file.txt"), "Hello World! - {}") + + def install(self): + self.output.info(f"Running install method in {self.install_folder}") + # copy(self, "*", src=self.package_folder, dst=self.install_folder) + copy(self, "file.txt", src=self.package_folder, dst=self.install_folder) + save(self, os.path.join(self.install_folder, "installed.txt"), "Installed file") + + def package_info(self): + self.output.info(f"Running package_info method in {self.package_folder}") + """) + tc.save({"conanfile.py": conanfile}) + tc.run("create .") + created_package = tc.created_package_reference("dep/1.0") + tc.run("upload * -r=default -c") + # TODO: Check what is in the server - it ought to be the real package folder, not the install folder + print() + tc.run("remove * -c") + tc.run(f"download {created_package} -r=default") + # No install folder yet because it has not been used in any graph, we just get the normal package folder + + print() + tc.run(f"cache path {created_package}") + package_folder = tc.out.strip() + assert package_folder.endswith("p") + assert "file.txt" in os.listdir(package_folder) + assert "installed.txt" not in os.listdir(package_folder) + assert not os.path.exists(os.path.join(package_folder, "..", "i")) + # Now this install will run the install method + tc.run("install --requires=dep/1.0") + + tc.run("remove * -c") + tc.run("install --requires=dep/1.0 -r=default") + print() From 0affd24ea4fcae6f5d6ff4d51db192c1a9ec311c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Abril=20Rinc=C3=B3n=20Blanco?= Date: Wed, 10 Jul 2024 16:18:12 +0200 Subject: [PATCH 02/49] Refactor --- conans/client/installer.py | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/conans/client/installer.py b/conans/client/installer.py index 1762276c2cc..68ae28ebb14 100644 --- a/conans/client/installer.py +++ b/conans/client/installer.py @@ -338,15 +338,7 @@ def _handle_package(self, package, install_reference, handled_count, total_count # Call the info method conanfile.folders.set_base_package(pkg_folder) conanfile.folders.set_base_pkg_metadata(pkg_metadata) - # TODO: Add install() method call and redirect package_folder to the install folder - if hasattr(conanfile, "install"): - install_folder = package_layout.install() - conanfile.folders.set_install_folder(install_folder) - if not os.path.exists(install_folder): - mkdir(install_folder) - with conanfile_exception_formatter(conanfile, "install"): - conanfile.install() - conanfile.folders.set_base_package(install_folder) + self._call_install_method(conanfile, package_layout.install()) self._call_package_info(conanfile, pkg_folder, is_editable=False) def _handle_node_editable(self, install_node): @@ -382,6 +374,8 @@ def _handle_node_editable(self, install_node): # Need a temporary package revision for package_revision_mode # Cannot be PREV_UNKNOWN otherwise the consumers can't compute their packageID node.prev = "editable" + # TODO: Run install method + # self._call_install_method(conanfile, os.path.join(output_folder or rooted_base_path, "i")) # TODO: Check this base_path usage for editable when not defined self._call_package_info(conanfile, package_folder=rooted_base_path, is_editable=True) @@ -463,3 +457,12 @@ def _call_package_info(self, conanfile, package_folder, is_editable): self._hook_manager.execute("post_package_info", conanfile=conanfile) conanfile.cpp_info.check_component_requires(conanfile) + + def _call_install_method(self, conanfile, install_folder): + if hasattr(conanfile, "install"): + conanfile.folders.set_install_folder(install_folder) + if not os.path.exists(install_folder): + mkdir(install_folder) + with conanfile_exception_formatter(conanfile, "install"): + conanfile.install() + conanfile.folders.set_base_package(install_folder) From b3f20c64e57251091f39f2acd78ed04dd93f1107 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Abril=20Rinc=C3=B3n=20Blanco?= Date: Wed, 10 Jul 2024 16:18:59 +0200 Subject: [PATCH 03/49] Refactor --- conans/client/installer.py | 1 + 1 file changed, 1 insertion(+) diff --git a/conans/client/installer.py b/conans/client/installer.py index 68ae28ebb14..1c575bfd5a1 100644 --- a/conans/client/installer.py +++ b/conans/client/installer.py @@ -461,6 +461,7 @@ def _call_package_info(self, conanfile, package_folder, is_editable): def _call_install_method(self, conanfile, install_folder): if hasattr(conanfile, "install"): conanfile.folders.set_install_folder(install_folder) + # TODO: If tis is editable, we probably need to regenerate the install nontheless if not os.path.exists(install_folder): mkdir(install_folder) with conanfile_exception_formatter(conanfile, "install"): From bb9d775cb85f71ca21014c28ffa729fd0a0be195 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Abril=20Rinc=C3=B3n=20Blanco?= Date: Wed, 10 Jul 2024 16:19:52 +0200 Subject: [PATCH 04/49] Typos --- conans/client/installer.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/conans/client/installer.py b/conans/client/installer.py index 1c575bfd5a1..ab602967e4a 100644 --- a/conans/client/installer.py +++ b/conans/client/installer.py @@ -461,7 +461,8 @@ def _call_package_info(self, conanfile, package_folder, is_editable): def _call_install_method(self, conanfile, install_folder): if hasattr(conanfile, "install"): conanfile.folders.set_install_folder(install_folder) - # TODO: If tis is editable, we probably need to regenerate the install nontheless + # TODO: If this is editable, we probably need to regenerate the install nontheless + # TODO: Think if it makes sense to have hooks for install if not os.path.exists(install_folder): mkdir(install_folder) with conanfile_exception_formatter(conanfile, "install"): From cdbebfbcfa3b7eb1d0ab44b5b1161dcee06d971f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Abril=20Rinc=C3=B3n=20Blanco?= Date: Wed, 10 Jul 2024 16:41:47 +0200 Subject: [PATCH 05/49] Refactor tests --- .../conanfile/test_install_method.py | 187 +++++++++--------- 1 file changed, 92 insertions(+), 95 deletions(-) diff --git a/test/integration/conanfile/test_install_method.py b/test/integration/conanfile/test_install_method.py index dc22da2c87d..3f34e1fb9b1 100644 --- a/test/integration/conanfile/test_install_method.py +++ b/test/integration/conanfile/test_install_method.py @@ -1,42 +1,19 @@ import os import textwrap +import pytest + from conan.test.assets.genconanfile import GenConanfile from conan.test.utils.tools import TestClient -def test_basic_install_method(): - tc = TestClient(light=True) - conanfile = textwrap.dedent(""" - import os - from conan import ConanFile - from conan.tools.files import save, copy - - class TestConan(ConanFile): - name = "app" - version = "1.0" - def package(self): - save(self, os.path.join(self.package_folder, "file.txt"), "Hello World! - {}") - - def install(self): - self.output.info(f"Running install method in {self.install_folder}") - # copy(self, "*", src=self.package_folder, dst=self.install_folder) - copy(self, "file.txt", src=self.package_folder, dst=self.install_folder) - - def package_info(self): - self.output.info(f"Running package_info method in {self.package_folder}") - """) - tc.save({"conanfile.py": conanfile}) - tc.run("create .") - print() - tc.run("install --requires=app/1.0") - print() - - -def test_dependency_install_method(): - tc = TestClient(light=True) - conanfile = textwrap.dedent(""" +class TestLocalFlows: + + @pytest.fixture + def client(): + tc = TestClient(light=True) + tc.save({"dep/conanfile.py": textwrap.dedent(""" import os from conan import ConanFile from conan.tools.files import save, copy @@ -45,7 +22,7 @@ class TestConan(ConanFile): name = "dep" version = "1.0" def package(self): - save(self, os.path.join(self.package_folder, "file.txt"), "Hello World! - {}") + save(self, os.path.join(self.package_folder, "file.txt"), "Hello World!") def install(self): self.output.info(f"Running install method in {self.install_folder}") @@ -54,66 +31,86 @@ def install(self): def package_info(self): self.output.info(f"Running package_info method in {self.package_folder}") - """) - tc.save({"dep/conanfile.py": conanfile, - "conanfile.py": textwrap.dedent(""" - from conan import ConanFile - class TestConan(ConanFile): - name = "app" - version = "1.0" - requires = "dep/1.0" - def generate(self): - self.output.info("Running generate method") - dep_pkg_folder = self.dependencies["dep"].package_folder - self.output.info(f"Dep package folder: {dep_pkg_folder}") - """)}) - tc.run("create dep") - tc.run("create .") - print() - - -def test_remote_upload_install_method(): - tc = TestClient(light=True, default_server_user=True) - conanfile = textwrap.dedent(""" - import os - from conan import ConanFile - from conan.tools.files import save, copy - - class TestConan(ConanFile): - name = "dep" - version = "1.0" - def package(self): - save(self, os.path.join(self.package_folder, "file.txt"), "Hello World! - {}") - - def install(self): - self.output.info(f"Running install method in {self.install_folder}") - # copy(self, "*", src=self.package_folder, dst=self.install_folder) - copy(self, "file.txt", src=self.package_folder, dst=self.install_folder) - save(self, os.path.join(self.install_folder, "installed.txt"), "Installed file") - - def package_info(self): - self.output.info(f"Running package_info method in {self.package_folder}") - """) - tc.save({"conanfile.py": conanfile}) - tc.run("create .") - created_package = tc.created_package_reference("dep/1.0") - tc.run("upload * -r=default -c") - # TODO: Check what is in the server - it ought to be the real package folder, not the install folder - print() - tc.run("remove * -c") - tc.run(f"download {created_package} -r=default") - # No install folder yet because it has not been used in any graph, we just get the normal package folder - - print() - tc.run(f"cache path {created_package}") - package_folder = tc.out.strip() - assert package_folder.endswith("p") - assert "file.txt" in os.listdir(package_folder) - assert "installed.txt" not in os.listdir(package_folder) - assert not os.path.exists(os.path.join(package_folder, "..", "i")) - # Now this install will run the install method - tc.run("install --requires=dep/1.0") - - tc.run("remove * -c") - tc.run("install --requires=dep/1.0 -r=default") - print() + """)}) + tc.run("export dep") + return tc + + + def test_basic_install_method(client): + client.run("create dep") + layout = client.created_layout() + assert layout.package().endswith("p") + assert f"Package folder {layout.package()}" in client.out + assert f"Running install method in {layout.install()}" in client.out + assert f"Running package_info method in {layout.install()}" in client.out + client.run("install --requires=dep/1.0") + assert f"Running package_info method in {layout.install()}" in client.out + + + @pytest.mark.parametrize("build_missing", [True, False]) + def test_dependency_install_method(client, build_missing): + client.save({"app/conanfile.py": textwrap.dedent(""" + from conan import ConanFile + class TestConan(ConanFile): + name = "app" + version = "1.0" + requires = "dep/1.0" + def generate(self): + self.output.info("Running generate method") + dep_pkg_folder = self.dependencies["dep"].package_folder + self.output.info(f"Dep package folder: {dep_pkg_folder}") + """)}) + if not build_missing: + client.run("create dep") + build_flag = "--build=missing" if build_missing else "" + client.run(f"create app {build_flag}") + # Dep package folder: /private/var/folders/lw/6bflvp3s3t5b56n2p_bj_vx80000gn/T/tmpy1wku27hconans/path with spaces/.conan2/p/b/depadc6c4067b602/i + # TODO: Check that the package_folder printed here is the installed folder, not the package folder + + +class TestRemoteFlows: + def test_remote_upload_install_method(): + tc = TestClient(light=True, default_server_user=True) + conanfile = textwrap.dedent(""" + import os + from conan import ConanFile + from conan.tools.files import save, copy + + class TestConan(ConanFile): + name = "dep" + version = "1.0" + def package(self): + save(self, os.path.join(self.package_folder, "file.txt"), "Hello World! - {}") + + def install(self): + self.output.info(f"Running install method in {self.install_folder}") + # copy(self, "*", src=self.package_folder, dst=self.install_folder) + copy(self, "file.txt", src=self.package_folder, dst=self.install_folder) + save(self, os.path.join(self.install_folder, "installed.txt"), "Installed file") + + def package_info(self): + self.output.info(f"Running package_info method in {self.package_folder}") + """) + tc.save({"conanfile.py": conanfile}) + tc.run("create .") + created_package = tc.created_package_reference("dep/1.0") + tc.run("upload * -r=default -c") + # TODO: Check what is in the server - it ought to be the real package folder, not the install folder + print() + tc.run("remove * -c") + tc.run(f"download {created_package} -r=default") + # No install folder yet because it has not been used in any graph, we just get the normal package folder + + print() + tc.run(f"cache path {created_package}") + package_folder = tc.out.strip() + assert package_folder.endswith("p") + assert "file.txt" in os.listdir(package_folder) + assert "installed.txt" not in os.listdir(package_folder) + assert not os.path.exists(os.path.join(package_folder, "..", "i")) + # Now this install will run the install method + tc.run("install --requires=dep/1.0") + + tc.run("remove * -c") + tc.run("install --requires=dep/1.0 -r=default") + print() From 1d4d44c2136ecdd75544a859dcfe74c4d315b698 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Abril=20Rinc=C3=B3n=20Blanco?= Date: Wed, 10 Jul 2024 21:44:47 +0200 Subject: [PATCH 06/49] Improve tests, start to think about editables --- .../conanfile/test_install_method.py | 162 ++++++++++-------- 1 file changed, 87 insertions(+), 75 deletions(-) diff --git a/test/integration/conanfile/test_install_method.py b/test/integration/conanfile/test_install_method.py index 3f34e1fb9b1..81643dd5b2e 100644 --- a/test/integration/conanfile/test_install_method.py +++ b/test/integration/conanfile/test_install_method.py @@ -6,37 +6,40 @@ from conan.test.assets.genconanfile import GenConanfile from conan.test.utils.tools import TestClient +from conans.util.files import load +conanfile_dep = textwrap.dedent(""" + import os + from conan import ConanFile + from conan.tools.files import save, copy -class TestLocalFlows: + class TestConan(ConanFile): + name = "dep" + version = "1.0" + def package(self): + save(self, os.path.join(self.package_folder, "file.txt"), "Hello World!") + + def install(self): + self.output.info(f"Running install method in {self.install_folder}") + # copy(self, "*", src=self.package_folder, dst=self.install_folder) + copy(self, "file.txt", src=self.package_folder, dst=self.install_folder) + save(self, os.path.join(self.install_folder, "installed.txt"), "Installed file") + + def package_info(self): + self.output.info(f"Running package_info method in {self.package_folder}") + """) + + +class TestBasicLocalFlows: @pytest.fixture - def client(): + def client(self): tc = TestClient(light=True) - tc.save({"dep/conanfile.py": textwrap.dedent(""" - import os - from conan import ConanFile - from conan.tools.files import save, copy - - class TestConan(ConanFile): - name = "dep" - version = "1.0" - def package(self): - save(self, os.path.join(self.package_folder, "file.txt"), "Hello World!") - - def install(self): - self.output.info(f"Running install method in {self.install_folder}") - # copy(self, "*", src=self.package_folder, dst=self.install_folder) - copy(self, "file.txt", src=self.package_folder, dst=self.install_folder) - - def package_info(self): - self.output.info(f"Running package_info method in {self.package_folder}") - """)}) + tc.save({"dep/conanfile.py": conanfile_dep}) tc.run("export dep") return tc - - def test_basic_install_method(client): + def test_basic_install_method(self, client): client.run("create dep") layout = client.created_layout() assert layout.package().endswith("p") @@ -45,10 +48,12 @@ def test_basic_install_method(client): assert f"Running package_info method in {layout.install()}" in client.out client.run("install --requires=dep/1.0") assert f"Running package_info method in {layout.install()}" in client.out + # Only issue is that the PackageLayout has no idea about the redirected package folder + # So we have to know to check for it in tests, but oh well + assert "installed.txt" in os.listdir(layout.install()) + assert "installed.txt" not in os.listdir(layout.package()) - - @pytest.mark.parametrize("build_missing", [True, False]) - def test_dependency_install_method(client, build_missing): + def test_dependency_install_method(self, client): client.save({"app/conanfile.py": textwrap.dedent(""" from conan import ConanFile class TestConan(ConanFile): @@ -60,57 +65,64 @@ def generate(self): dep_pkg_folder = self.dependencies["dep"].package_folder self.output.info(f"Dep package folder: {dep_pkg_folder}") """)}) - if not build_missing: - client.run("create dep") - build_flag = "--build=missing" if build_missing else "" - client.run(f"create app {build_flag}") - # Dep package folder: /private/var/folders/lw/6bflvp3s3t5b56n2p_bj_vx80000gn/T/tmpy1wku27hconans/path with spaces/.conan2/p/b/depadc6c4067b602/i - # TODO: Check that the package_folder printed here is the installed folder, not the package folder + client.run("create dep") + dep_layout = client.created_layout() + client.run("create app") + assert f"Dep package folder: {dep_layout.package()}" not in client.out + assert f"Dep package folder: {dep_layout.install()}" in client.out class TestRemoteFlows: - def test_remote_upload_install_method(): + + @pytest.fixture + def client(self): tc = TestClient(light=True, default_server_user=True) - conanfile = textwrap.dedent(""" - import os - from conan import ConanFile - from conan.tools.files import save, copy - - class TestConan(ConanFile): - name = "dep" - version = "1.0" - def package(self): - save(self, os.path.join(self.package_folder, "file.txt"), "Hello World! - {}") - - def install(self): - self.output.info(f"Running install method in {self.install_folder}") - # copy(self, "*", src=self.package_folder, dst=self.install_folder) - copy(self, "file.txt", src=self.package_folder, dst=self.install_folder) - save(self, os.path.join(self.install_folder, "installed.txt"), "Installed file") - - def package_info(self): - self.output.info(f"Running package_info method in {self.package_folder}") - """) - tc.save({"conanfile.py": conanfile}) - tc.run("create .") - created_package = tc.created_package_reference("dep/1.0") - tc.run("upload * -r=default -c") - # TODO: Check what is in the server - it ought to be the real package folder, not the install folder - print() - tc.run("remove * -c") - tc.run(f"download {created_package} -r=default") - # No install folder yet because it has not been used in any graph, we just get the normal package folder - - print() - tc.run(f"cache path {created_package}") - package_folder = tc.out.strip() + tc.save({"dep/conanfile.py": conanfile_dep}) + tc.run("export dep") + return tc + + def test_remote_upload_install_method(self, client): + client.run("create dep") + created_pref = client.created_package_reference("dep/1.0") + client.run("upload * -r=default -c") + + # Only the package folder is uploaded, not the install folder + uploaded_pref_path = client.servers["default"].test_server.server_store.package(created_pref) + manifest_contents = load(os.path.join(uploaded_pref_path, "conanmanifest.txt")) + assert "file.txt" in manifest_contents + assert "installed.txt" not in manifest_contents + + client.run("remove * -c") + client.run(f"download {created_pref} -r=default") + downloaded_pref_layout = client.get_latest_pkg_layout(created_pref) + assert "file.txt" in os.listdir(downloaded_pref_layout.package()) + assert "installed.txt" not in os.listdir(downloaded_pref_layout.package()) + assert not os.path.exists(os.path.join(downloaded_pref_layout.install())) + + client.run(f"cache path {created_pref}") + package_folder = client.out.strip() + assert package_folder == downloaded_pref_layout.package() assert package_folder.endswith("p") - assert "file.txt" in os.listdir(package_folder) - assert "installed.txt" not in os.listdir(package_folder) - assert not os.path.exists(os.path.join(package_folder, "..", "i")) - # Now this install will run the install method - tc.run("install --requires=dep/1.0") - - tc.run("remove * -c") - tc.run("install --requires=dep/1.0 -r=default") - print() + # Now this install will run the install() method + client.run("install --requires=dep/1.0") + assert f"Running install method in {downloaded_pref_layout.install()}" in client.out + + client.run("remove * -c") + client.run("install --requires=dep/1.0 -r=default") + assert f"Running install method in {downloaded_pref_layout.install()}" in client.out + + +class TestEditableFlows: + @pytest.fixture + def client(self): + tc = TestClient(light=True) + tc.save({"dep/conanfile.py": conanfile_dep}) + return tc + + def test_editable_install_method(self, client): + client.run("editable add dep") + # If we try to consume it, it will run the install() method + client.run("install --requires=dep/1.0") + # TODO: Make this not fail + assert "Running install method in" in client.out + From 2d41063a15552e27c5777d86353dcef01ca1817a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Abril=20Rinc=C3=B3n=20Blanco?= Date: Wed, 10 Jul 2024 22:37:53 +0200 Subject: [PATCH 07/49] Minimal tool_requires test --- .../conanfile/test_install_method.py | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/test/integration/conanfile/test_install_method.py b/test/integration/conanfile/test_install_method.py index 81643dd5b2e..505c363ffec 100644 --- a/test/integration/conanfile/test_install_method.py +++ b/test/integration/conanfile/test_install_method.py @@ -72,6 +72,51 @@ def generate(self): assert f"Dep package folder: {dep_layout.install()}" in client.out +class TestToolRequiresFlows: + def test_tool_requires(self): + tc = TestClient(light=True) + tc.save({"dep/conanfile.py": textwrap.dedent(""" + import os + from conan import ConanFile + from conan.tools.files import save, copy + + class TestConan(ConanFile): + name = "dep" + version = "1.0" + package_type = "application" + def package(self): + save(self, os.path.join(self.package_folder, "bin", "executable.txt"), "Base") + + def install(self): + self.output.info(f"Running install method in {self.install_folder}") + copy(self, "*", src=self.package_folder, dst=self.install_folder) + save(self, os.path.join(self.install_folder, "installed.txt"), "Installed file") + + def package_info(self): + self.output.info(f"Running package_info method in {self.package_folder}") + self.cpp_info.bindirs = ["bin"] + + """), "app/conanfile.py": textwrap.dedent(""" + from conan import ConanFile + import os + + class TestConan(ConanFile): + name = "app" + version = "1.0" + + def build_requirements(self): + self.tool_requires("dep/1.0") + + def build(self): + self.output.info("Running build method") + self.output.info(f"Dep bindir: {self.dependencies.build['dep'].cpp_info.bindir}") + self.output.info(f"Is installed? {os.path.join(self.dependencies.build['dep'].cpp_info.bindir, 'installed,.txt')}") + """)}) + tc.run("create dep --build-require") + tc.run("create app") + assert "app/1.0: Is installed? True" + + class TestRemoteFlows: @pytest.fixture From 4fee15f6978265230bb98353e1ee845432928de1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Abril=20Rinc=C3=B3n=20Blanco?= Date: Wed, 10 Jul 2024 22:41:21 +0200 Subject: [PATCH 08/49] Add failing tool_require test, cpp_info path releated --- test/integration/conanfile/test_install_method.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/test/integration/conanfile/test_install_method.py b/test/integration/conanfile/test_install_method.py index 505c363ffec..88ed34e93ba 100644 --- a/test/integration/conanfile/test_install_method.py +++ b/test/integration/conanfile/test_install_method.py @@ -109,12 +109,16 @@ def build_requirements(self): def build(self): self.output.info("Running build method") - self.output.info(f"Dep bindir: {self.dependencies.build['dep'].cpp_info.bindir}") - self.output.info(f"Is installed? {os.path.join(self.dependencies.build['dep'].cpp_info.bindir, 'installed,.txt')}") + bindir = self.dependencies.build['dep'].cpp_info.bindir + self.output.info(f"Dep bindir: {bindir}") + self.output.info(f"Is installed? {os.path.exists(os.path.join(bindir, 'installed.txt'))}") """)}) tc.run("create dep --build-require") + dep_layout = tc.created_layout() tc.run("create app") - assert "app/1.0: Is installed? True" + # This fails. cpp_info is using the original package folder to construct the final path + assert f"Dep bindir: {dep_layout.install()}" in tc.out + assert "app/1.0: Is installed? True" in tc.out class TestRemoteFlows: From c33186ea995262a1932e9ed41e2ca6adcb244417 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Abril=20Rinc=C3=B3n=20Blanco?= Date: Thu, 11 Jul 2024 08:19:25 +0200 Subject: [PATCH 09/49] Make package_info understand installed package --- conans/client/installer.py | 3 ++- test/integration/conanfile/test_install_method.py | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/conans/client/installer.py b/conans/client/installer.py index ab602967e4a..8ffe22f66a8 100644 --- a/conans/client/installer.py +++ b/conans/client/installer.py @@ -339,7 +339,8 @@ def _handle_package(self, package, install_reference, handled_count, total_count conanfile.folders.set_base_package(pkg_folder) conanfile.folders.set_base_pkg_metadata(pkg_metadata) self._call_install_method(conanfile, package_layout.install()) - self._call_package_info(conanfile, pkg_folder, is_editable=False) + # TODO: Improve API to avoid this branch + self._call_package_info(conanfile, package_layout.install() if hasattr(conanfile, "install") else pkg_folder, is_editable=False) def _handle_node_editable(self, install_node): # It will only run generation diff --git a/test/integration/conanfile/test_install_method.py b/test/integration/conanfile/test_install_method.py index 88ed34e93ba..5007d3b403d 100644 --- a/test/integration/conanfile/test_install_method.py +++ b/test/integration/conanfile/test_install_method.py @@ -90,7 +90,7 @@ def package(self): def install(self): self.output.info(f"Running install method in {self.install_folder}") copy(self, "*", src=self.package_folder, dst=self.install_folder) - save(self, os.path.join(self.install_folder, "installed.txt"), "Installed file") + save(self, os.path.join(self.install_folder, "bin", "installed.txt"), "Installed file") def package_info(self): self.output.info(f"Running package_info method in {self.package_folder}") From 9f086d2b78992eaa6be274a91b7f1ab3f07909c6 Mon Sep 17 00:00:00 2001 From: PerseoGI Date: Thu, 11 Jul 2024 13:09:34 +0200 Subject: [PATCH 10/49] Use package_folder instead of cheking again install method --- conans/client/installer.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/conans/client/installer.py b/conans/client/installer.py index 8ffe22f66a8..28cdea522a0 100644 --- a/conans/client/installer.py +++ b/conans/client/installer.py @@ -339,8 +339,8 @@ def _handle_package(self, package, install_reference, handled_count, total_count conanfile.folders.set_base_package(pkg_folder) conanfile.folders.set_base_pkg_metadata(pkg_metadata) self._call_install_method(conanfile, package_layout.install()) - # TODO: Improve API to avoid this branch - self._call_package_info(conanfile, package_layout.install() if hasattr(conanfile, "install") else pkg_folder, is_editable=False) + # Use package_folder which has been updated previously by install_method if necessary + self._call_package_info(conanfile, conanfile.package_folder, is_editable=False) def _handle_node_editable(self, install_node): # It will only run generation From f2843bfac88f74ef582f973bb4c549820bb3723b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Abril=20Rinc=C3=B3n=20Blanco?= Date: Fri, 12 Jul 2024 12:13:09 +0200 Subject: [PATCH 11/49] Fixes and additions, do not support editables --- conans/client/installer.py | 5 +-- conans/model/layout.py | 8 ++++ .../conanfile/test_install_method.py | 39 +++++++++++-------- 3 files changed, 32 insertions(+), 20 deletions(-) diff --git a/conans/client/installer.py b/conans/client/installer.py index 28cdea522a0..6d1feb9ced8 100644 --- a/conans/client/installer.py +++ b/conans/client/installer.py @@ -375,8 +375,6 @@ def _handle_node_editable(self, install_node): # Need a temporary package revision for package_revision_mode # Cannot be PREV_UNKNOWN otherwise the consumers can't compute their packageID node.prev = "editable" - # TODO: Run install method - # self._call_install_method(conanfile, os.path.join(output_folder or rooted_base_path, "i")) # TODO: Check this base_path usage for editable when not defined self._call_package_info(conanfile, package_folder=rooted_base_path, is_editable=True) @@ -462,10 +460,9 @@ def _call_package_info(self, conanfile, package_folder, is_editable): def _call_install_method(self, conanfile, install_folder): if hasattr(conanfile, "install"): conanfile.folders.set_install_folder(install_folder) - # TODO: If this is editable, we probably need to regenerate the install nontheless - # TODO: Think if it makes sense to have hooks for install if not os.path.exists(install_folder): mkdir(install_folder) with conanfile_exception_formatter(conanfile, "install"): conanfile.install() + # TODO: Keep the orignal info in something like "invariante_package_folder" conanfile.folders.set_base_package(install_folder) diff --git a/conans/model/layout.py b/conans/model/layout.py index b89b7f4dcfe..ffaf2b67975 100644 --- a/conans/model/layout.py +++ b/conans/model/layout.py @@ -45,6 +45,8 @@ def __init__(self): self._base_recipe_metadata = None self._base_pkg_metadata = None + # TODO: Think about adding invariant package fodlder ref in case of install() + # self._invariant_package_folder = None self.source = "" self.build = "" @@ -144,12 +146,18 @@ def package_folder(self): return self._base_package def set_install_folder(self, folder): + # TODO: Store when the install folder is set, to be able to access the old package later + #self._invariant_package_folder = self.package_folder self.install = folder @property def install_folder(self): return self.install + @property + def invariant_package_folder(self): + return self._invariant_package_folder + @property def generators_folder(self): if self._base_generators is None: diff --git a/test/integration/conanfile/test_install_method.py b/test/integration/conanfile/test_install_method.py index 5007d3b403d..b6b8fcd43bb 100644 --- a/test/integration/conanfile/test_install_method.py +++ b/test/integration/conanfile/test_install_method.py @@ -71,6 +71,26 @@ def generate(self): assert f"Dep package folder: {dep_layout.package()}" not in client.out assert f"Dep package folder: {dep_layout.install()}" in client.out + def test_save_restore_cache(self): + pass + + def test_lockfile_interaction(self): + pass + + def test_remove_deletes_correct_folders(self): + pass + + def test_graph_info_output(self): + # The output should serialize the orignal package folder path to give users the info + pass + + def test_create_pkglist_output(self): + pass + + def test_vendorized(self): + # TODO: Should this be handled? Or are vendoring packages meant to know if they are dealing with localized versions? + pass + class TestToolRequiresFlows: def test_tool_requires(self): @@ -120,6 +140,9 @@ def build(self): assert f"Dep bindir: {dep_layout.install()}" in tc.out assert "app/1.0: Is installed? True" in tc.out + def test_update_recipe(self): + pass + class TestRemoteFlows: @@ -159,19 +182,3 @@ def test_remote_upload_install_method(self, client): client.run("remove * -c") client.run("install --requires=dep/1.0 -r=default") assert f"Running install method in {downloaded_pref_layout.install()}" in client.out - - -class TestEditableFlows: - @pytest.fixture - def client(self): - tc = TestClient(light=True) - tc.save({"dep/conanfile.py": conanfile_dep}) - return tc - - def test_editable_install_method(self, client): - client.run("editable add dep") - # If we try to consume it, it will run the install() method - client.run("install --requires=dep/1.0") - # TODO: Make this not fail - assert "Running install method in" in client.out - From 5ac885fcc9e7de8eb6b064e0f528c96ba92ce76a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Abril=20Rinc=C3=B3n=20Blanco?= Date: Mon, 22 Jul 2024 11:23:36 +0200 Subject: [PATCH 12/49] Update conans/model/layout.py Co-authored-by: PerseoGI --- conans/model/layout.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/conans/model/layout.py b/conans/model/layout.py index ffaf2b67975..2341aed6170 100644 --- a/conans/model/layout.py +++ b/conans/model/layout.py @@ -155,8 +155,8 @@ def install_folder(self): return self.install @property - def invariant_package_folder(self): - return self._invariant_package_folder + def original_package_folder(self): + return self._original_package_folder @property def generators_folder(self): From 0b36d5eda5b499c1acf3c2d3b0b4bafd5b500a8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Abril=20Rinc=C3=B3n=20Blanco?= Date: Mon, 22 Jul 2024 11:23:41 +0200 Subject: [PATCH 13/49] Update conans/model/layout.py Co-authored-by: PerseoGI --- conans/model/layout.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conans/model/layout.py b/conans/model/layout.py index 2341aed6170..5ea28b8429f 100644 --- a/conans/model/layout.py +++ b/conans/model/layout.py @@ -147,7 +147,7 @@ def package_folder(self): def set_install_folder(self, folder): # TODO: Store when the install folder is set, to be able to access the old package later - #self._invariant_package_folder = self.package_folder + self._original_package_folder = self.package_folder self.install = folder @property From 0194c400cfec04096882756ae389979ac5d92ae7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Abril=20Rinc=C3=B3n=20Blanco?= Date: Mon, 22 Jul 2024 11:23:48 +0200 Subject: [PATCH 14/49] Update conans/model/layout.py Co-authored-by: PerseoGI --- conans/model/layout.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conans/model/layout.py b/conans/model/layout.py index 5ea28b8429f..1be2237ff3c 100644 --- a/conans/model/layout.py +++ b/conans/model/layout.py @@ -46,7 +46,7 @@ def __init__(self): self._base_recipe_metadata = None self._base_pkg_metadata = None # TODO: Think about adding invariant package fodlder ref in case of install() - # self._invariant_package_folder = None + self._original_package_folder = None self.source = "" self.build = "" From b3f0ec4cce725bbff7b60e697bbb6b326566ae47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Abril=20Rinc=C3=B3n=20Blanco?= Date: Mon, 22 Jul 2024 11:25:41 +0200 Subject: [PATCH 15/49] Update conans/client/installer.py Co-authored-by: PerseoGI --- conans/client/installer.py | 1 - 1 file changed, 1 deletion(-) diff --git a/conans/client/installer.py b/conans/client/installer.py index 6d1feb9ced8..4a510440248 100644 --- a/conans/client/installer.py +++ b/conans/client/installer.py @@ -464,5 +464,4 @@ def _call_install_method(self, conanfile, install_folder): mkdir(install_folder) with conanfile_exception_formatter(conanfile, "install"): conanfile.install() - # TODO: Keep the orignal info in something like "invariante_package_folder" conanfile.folders.set_base_package(install_folder) From e88936aa255cf3077851551cfc7511dac59986ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Abril=20Rinc=C3=B3n=20Blanco?= Date: Mon, 22 Jul 2024 11:25:48 +0200 Subject: [PATCH 16/49] Update conans/model/layout.py Co-authored-by: PerseoGI --- conans/model/layout.py | 1 - 1 file changed, 1 deletion(-) diff --git a/conans/model/layout.py b/conans/model/layout.py index 1be2237ff3c..71f4f1a9128 100644 --- a/conans/model/layout.py +++ b/conans/model/layout.py @@ -146,7 +146,6 @@ def package_folder(self): return self._base_package def set_install_folder(self, folder): - # TODO: Store when the install folder is set, to be able to access the old package later self._original_package_folder = self.package_folder self.install = folder From 5f191379aa132f742022daeb1cba6886a227f1c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Abril=20Rinc=C3=B3n=20Blanco?= Date: Mon, 22 Jul 2024 11:25:52 +0200 Subject: [PATCH 17/49] Update conans/model/layout.py Co-authored-by: PerseoGI --- conans/model/layout.py | 1 - 1 file changed, 1 deletion(-) diff --git a/conans/model/layout.py b/conans/model/layout.py index 71f4f1a9128..6d614f64715 100644 --- a/conans/model/layout.py +++ b/conans/model/layout.py @@ -45,7 +45,6 @@ def __init__(self): self._base_recipe_metadata = None self._base_pkg_metadata = None - # TODO: Think about adding invariant package fodlder ref in case of install() self._original_package_folder = None self.source = "" From 43f537d930830a0cd4c7a25ce9012be7a4e3bb30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Abril=20Rinc=C3=B3n=20Blanco?= Date: Mon, 22 Jul 2024 11:27:08 +0200 Subject: [PATCH 18/49] Update test/integration/conanfile/test_install_method.py --- test/integration/conanfile/test_install_method.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/integration/conanfile/test_install_method.py b/test/integration/conanfile/test_install_method.py index b6b8fcd43bb..bba8d861194 100644 --- a/test/integration/conanfile/test_install_method.py +++ b/test/integration/conanfile/test_install_method.py @@ -90,7 +90,8 @@ def test_create_pkglist_output(self): def test_vendorized(self): # TODO: Should this be handled? Or are vendoring packages meant to know if they are dealing with localized versions? pass - + def test_original_package_available_graph_info(self): + pass class TestToolRequiresFlows: def test_tool_requires(self): From 05eebfa5b2a47349aa639fb22c98d29ee0392a52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Abril=20Rinc=C3=B3n=20Blanco?= Date: Mon, 22 Jul 2024 11:31:02 +0200 Subject: [PATCH 19/49] More tests --- test/integration/conanfile/test_install_method.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/integration/conanfile/test_install_method.py b/test/integration/conanfile/test_install_method.py index bba8d861194..1f5fab7bcc6 100644 --- a/test/integration/conanfile/test_install_method.py +++ b/test/integration/conanfile/test_install_method.py @@ -90,9 +90,14 @@ def test_create_pkglist_output(self): def test_vendorized(self): # TODO: Should this be handled? Or are vendoring packages meant to know if they are dealing with localized versions? pass + def test_original_package_available_graph_info(self): pass + def test_check_integrity(self): + pass + + class TestToolRequiresFlows: def test_tool_requires(self): tc = TestClient(light=True) From 821fec6beaaa6b421dbab1580a0433ea8588d937 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Abril=20Rinc=C3=B3n=20Blanco?= Date: Mon, 22 Jul 2024 11:32:09 +0200 Subject: [PATCH 20/49] More tests --- test/integration/conanfile/test_install_method.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/integration/conanfile/test_install_method.py b/test/integration/conanfile/test_install_method.py index 1f5fab7bcc6..6d9b8cf0d42 100644 --- a/test/integration/conanfile/test_install_method.py +++ b/test/integration/conanfile/test_install_method.py @@ -97,6 +97,9 @@ def test_original_package_available_graph_info(self): def test_check_integrity(self): pass + def test_test_package_uses_created_tool_which_modifies_pkgfolder(self): + pass + class TestToolRequiresFlows: def test_tool_requires(self): From 830b922f1777d4454e9ca4480c05b095b995bdea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Abril=20Rinc=C3=B3n=20Blanco?= Date: Mon, 22 Jul 2024 13:58:19 +0200 Subject: [PATCH 21/49] Reorder, add new test --- test/integration/conanfile/test_install_method.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/test/integration/conanfile/test_install_method.py b/test/integration/conanfile/test_install_method.py index 6d9b8cf0d42..0f246d17e37 100644 --- a/test/integration/conanfile/test_install_method.py +++ b/test/integration/conanfile/test_install_method.py @@ -97,9 +97,6 @@ def test_original_package_available_graph_info(self): def test_check_integrity(self): pass - def test_test_package_uses_created_tool_which_modifies_pkgfolder(self): - pass - class TestToolRequiresFlows: def test_tool_requires(self): @@ -152,6 +149,9 @@ def build(self): def test_update_recipe(self): pass + def test_test_package_uses_created_tool_which_modifies_pkgfolder(self): + pass + class TestRemoteFlows: @@ -191,3 +191,6 @@ def test_remote_upload_install_method(self, client): client.run("remove * -c") client.run("install --requires=dep/1.0 -r=default") assert f"Running install method in {downloaded_pref_layout.install()}" in client.out + + def test_graph_info_of_remote_downloaded(self): + pass From cbb9ea572318053665b0ae381190a86036ad7dbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Abril=20Rinc=C3=B3n=20Blanco?= Date: Mon, 22 Jul 2024 15:01:48 +0200 Subject: [PATCH 22/49] First tool_requires test --- conan/test/assets/genconanfile.py | 29 ++++++++++++++----- .../conanfile/test_install_method.py | 19 +++++++++++- 2 files changed, 40 insertions(+), 8 deletions(-) diff --git a/conan/test/assets/genconanfile.py b/conan/test/assets/genconanfile.py index fea77cbd434..a2915211e94 100644 --- a/conan/test/assets/genconanfile.py +++ b/conan/test/assets/genconanfile.py @@ -49,6 +49,8 @@ def __init__(self, name=None, version=None): self._cmake_build = False self._class_attributes = None + self._is_tested_ref_build_require = None + def with_package_type(self, value): self._package_type = value return self @@ -144,6 +146,10 @@ def with_test_requires(self, *refs): self._test_requires.append(ref_str) return self + def with_test_reference_as_build_require(self): + self._is_tested_ref_build_require = True + return self + def with_build_requirement(self, ref, **kwargs): self._build_requirements = self._build_requirements or [] ref_str = self._get_full_ref_str(ref) @@ -403,12 +409,12 @@ def package(self): def _install_method_render(self): lines = [] if self._install_lines: - lines.extend(" {}".format(line) for line in self._install_lines) + lines.extend(" {}".format(line) for line in self._install_lines) if not lines: return "" return """ - def install(self): + def install(self): {} """.format("\n".join(lines)) @@ -456,11 +462,20 @@ def package_id(self): @property def _test_lines_render(self): - lines = ["", - " def requirements(self):", - ' self.requires(self.tested_reference_str)', - "", - ' def test(self):'] + [' %s' % m for m in self._test_lines] + if self._is_tested_ref_build_require: + lines = ["", + " def build_requirements(self):", + ' self.tool_requires(self.tested_reference_str)', + "", + ' def test(self):'] + else: + lines = ["", + " def requirements(self):", + ' self.requires(self.tested_reference_str)', + "", + ' def test(self):'] + + lines += [' %s' % m for m in self._test_lines] return "\n".join(lines) @property diff --git a/test/integration/conanfile/test_install_method.py b/test/integration/conanfile/test_install_method.py index 0f246d17e37..2bf3af9a356 100644 --- a/test/integration/conanfile/test_install_method.py +++ b/test/integration/conanfile/test_install_method.py @@ -150,7 +150,24 @@ def test_update_recipe(self): pass def test_test_package_uses_created_tool_which_modifies_pkgfolder(self): - pass + tc = TestClient(light=True) + tc.save({"conanfile.py": GenConanfile("app", "1.0") + .with_import("from conan.tools.files import save") + .with_package_type("application") + .with_package("save(self, 'file.txt', 'Hello World!')") + .with_package_info({"bindirs": ["bin"]}, {}) + .with_install("save(self, 'installed.txt', 'Installed file')"), + "test_package/conanfile.py": GenConanfile() + .with_import("from conan.tools.files import save") + .with_import("import os") + .with_test_reference_as_build_require() + .with_test( + "bindir = self.dependencies.build[self.tested_reference_str].cpp_info.bindir", + "save(self, os.path.join(bindir, 'test.txt'), 'Test file')")}) + tc.run("create . --build-require") + created_ref = tc.created_package_reference("app/1.0") + tc.run(f"cache check-integrity {created_ref}") + assert "There are corrupted artifacts" not in tc.out class TestRemoteFlows: From 8a2c8b034ae3b2a30c59011a8fa224968ed569fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Abril=20Rinc=C3=B3n=20Blanco?= Date: Mon, 22 Jul 2024 15:04:12 +0200 Subject: [PATCH 23/49] Fix test --- test/integration/conanfile/test_install_method.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/test/integration/conanfile/test_install_method.py b/test/integration/conanfile/test_install_method.py index 2bf3af9a356..88203c7f9c6 100644 --- a/test/integration/conanfile/test_install_method.py +++ b/test/integration/conanfile/test_install_method.py @@ -161,9 +161,8 @@ def test_test_package_uses_created_tool_which_modifies_pkgfolder(self): .with_import("from conan.tools.files import save") .with_import("import os") .with_test_reference_as_build_require() - .with_test( - "bindir = self.dependencies.build[self.tested_reference_str].cpp_info.bindir", - "save(self, os.path.join(bindir, 'test.txt'), 'Test file')")}) + .with_test("bindir = self.dependencies.build[self.tested_reference_str].cpp_info.bindir") + .with_test("save(self, os.path.join(bindir, '__pycache__.pyc'), 'Test file')")}) tc.run("create . --build-require") created_ref = tc.created_package_reference("app/1.0") tc.run(f"cache check-integrity {created_ref}") From cf807af2da39f428da3d3fdfe894b97b0d1fb435 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Abril=20Rinc=C3=B3n=20Blanco?= Date: Mon, 22 Jul 2024 15:06:06 +0200 Subject: [PATCH 24/49] Improve with_test api --- conan/test/assets/genconanfile.py | 5 +++-- test/integration/conanfile/test_install_method.py | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/conan/test/assets/genconanfile.py b/conan/test/assets/genconanfile.py index a2915211e94..3e6eb9c6b18 100644 --- a/conan/test/assets/genconanfile.py +++ b/conan/test/assets/genconanfile.py @@ -240,9 +240,10 @@ def with_package_id(self, line): self._package_id_lines.append(line) return self - def with_test(self, line): + def with_test(self, *lines): self._test_lines = self._test_lines or [] - self._test_lines.append(line) + for line in lines: + self._test_lines.append(line) return self def with_cmake_build(self): diff --git a/test/integration/conanfile/test_install_method.py b/test/integration/conanfile/test_install_method.py index 88203c7f9c6..712774e3a3c 100644 --- a/test/integration/conanfile/test_install_method.py +++ b/test/integration/conanfile/test_install_method.py @@ -161,8 +161,8 @@ def test_test_package_uses_created_tool_which_modifies_pkgfolder(self): .with_import("from conan.tools.files import save") .with_import("import os") .with_test_reference_as_build_require() - .with_test("bindir = self.dependencies.build[self.tested_reference_str].cpp_info.bindir") - .with_test("save(self, os.path.join(bindir, '__pycache__.pyc'), 'Test file')")}) + .with_test("bindir = self.dependencies.build[self.tested_reference_str].cpp_info.bindir", + "save(self, os.path.join(bindir, '__pycache__.pyc'), 'Test file')")}) tc.run("create . --build-require") created_ref = tc.created_package_reference("app/1.0") tc.run(f"cache check-integrity {created_ref}") From c1cfaeda093f4d14df916f332c7f6ffccd12df46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Abril=20Rinc=C3=B3n=20Blanco?= Date: Mon, 22 Jul 2024 15:14:11 +0200 Subject: [PATCH 25/49] Remove duplicate future test --- test/integration/conanfile/test_install_method.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/test/integration/conanfile/test_install_method.py b/test/integration/conanfile/test_install_method.py index 712774e3a3c..7eb4b753d30 100644 --- a/test/integration/conanfile/test_install_method.py +++ b/test/integration/conanfile/test_install_method.py @@ -81,7 +81,8 @@ def test_remove_deletes_correct_folders(self): pass def test_graph_info_output(self): - # The output should serialize the orignal package folder path to give users the info + # The output should serialize the orignal package folder path to give users the info, + # but maybe also the install one? pass def test_create_pkglist_output(self): @@ -91,9 +92,6 @@ def test_vendorized(self): # TODO: Should this be handled? Or are vendoring packages meant to know if they are dealing with localized versions? pass - def test_original_package_available_graph_info(self): - pass - def test_check_integrity(self): pass From 784e207bc762b80d9dfd4e912ebe3916de6d2432 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Abril=20Rinc=C3=B3n=20Blanco?= Date: Mon, 22 Jul 2024 17:15:33 +0200 Subject: [PATCH 26/49] Add support for install() in conan cache path, add a few tests to show as example --- conan/api/subapi/cache.py | 2 ++ .../conanfile/test_install_method.py | 33 +++++++++++++++++-- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/conan/api/subapi/cache.py b/conan/api/subapi/cache.py index 19a6db3dace..b1e10714d66 100644 --- a/conan/api/subapi/cache.py +++ b/conan/api/subapi/cache.py @@ -63,6 +63,8 @@ def package_path(self, pref: PkgReference): app = ConanApp(self.conan_api) pref = _resolve_latest_pref(app, pref) ref_layout = app.cache.pkg_layout(pref) + if os.path.exists(ref_layout.install()): + return ref_layout.install() return _check_folder_existence(pref, "package", ref_layout.package()) def check_integrity(self, package_list): diff --git a/test/integration/conanfile/test_install_method.py b/test/integration/conanfile/test_install_method.py index 7eb4b753d30..113c5199f3d 100644 --- a/test/integration/conanfile/test_install_method.py +++ b/test/integration/conanfile/test_install_method.py @@ -1,3 +1,4 @@ +import json import os import textwrap @@ -71,8 +72,33 @@ def generate(self): assert f"Dep package folder: {dep_layout.package()}" not in client.out assert f"Dep package folder: {dep_layout.install()}" in client.out - def test_save_restore_cache(self): - pass + def test_cache_path_command(self, client): + client.run("create dep") + dep_layout = client.created_layout() + pref = client.created_package_reference("dep/1.0") + client.run(f"cache path {pref}") + assert dep_layout.package() not in client.out + assert dep_layout.install() in client.out + + def test_save_restore_cache(self, client): + # Not created in the cache, just exported, nothing breaks because there is not even a package there + client.run("cache save *:*") + client.run("remove * -c") + client.run("cache restore conan_cache_save.tgz") + # Now create the package and then save/restore + client.run("create dep") + dep_layout = client.created_layout() + client.run("cache save *:* -f=json", redirect_stdout="saved.json") + saved = json.loads(client.load("saved.json")) + pref = dep_layout.reference + assert saved["Local Cache"]["dep/1.0"]["revisions"][pref.ref.revision]["packages"][pref.package_id]["revisions"][pref.revision]["package_folder"] in dep_layout.package() + client.run("remove * -c") + assert not os.path.exists(dep_layout.package()) + assert not os.path.exists(dep_layout.install()) + client.run("cache restore conan_cache_save.tgz") + client.run(f"cache path {dep_layout.reference}") + package_folder = client.out.strip() + assert "installed.txt" in os.listdir(package_folder) def test_lockfile_interaction(self): pass @@ -95,6 +121,9 @@ def test_vendorized(self): def test_check_integrity(self): pass + def test_access_invariant_from_consumer(self): + pass + class TestToolRequiresFlows: def test_tool_requires(self): From 0019e7b23baa7e24bab30df68c5585b90ea65b81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Abril=20Rinc=C3=B3n=20Blanco?= Date: Mon, 22 Jul 2024 17:18:25 +0200 Subject: [PATCH 27/49] Better name for original_package_folder, fallback to package_folder when no install() is called --- conans/model/layout.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/conans/model/layout.py b/conans/model/layout.py index 6d614f64715..e51fa00a441 100644 --- a/conans/model/layout.py +++ b/conans/model/layout.py @@ -45,7 +45,7 @@ def __init__(self): self._base_recipe_metadata = None self._base_pkg_metadata = None - self._original_package_folder = None + self._immutable_package_folder = None self.source = "" self.build = "" @@ -145,7 +145,7 @@ def package_folder(self): return self._base_package def set_install_folder(self, folder): - self._original_package_folder = self.package_folder + self._immutable_package_folder = self.package_folder self.install = folder @property @@ -153,8 +153,8 @@ def install_folder(self): return self.install @property - def original_package_folder(self): - return self._original_package_folder + def immutable_package_folder(self): + return self._immutable_package_folder or self.package_folder @property def generators_folder(self): From 42610cc884ee29d963a7b1881063d3a61d1f0a6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Abril=20Rinc=C3=B3n=20Blanco?= Date: Mon, 22 Jul 2024 17:25:12 +0200 Subject: [PATCH 28/49] Codify install() not running in a restore --- test/integration/conanfile/test_install_method.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/integration/conanfile/test_install_method.py b/test/integration/conanfile/test_install_method.py index 113c5199f3d..91f34058bf9 100644 --- a/test/integration/conanfile/test_install_method.py +++ b/test/integration/conanfile/test_install_method.py @@ -98,7 +98,9 @@ def test_save_restore_cache(self, client): client.run("cache restore conan_cache_save.tgz") client.run(f"cache path {dep_layout.reference}") package_folder = client.out.strip() - assert "installed.txt" in os.listdir(package_folder) + # The install() folder does not exist as restoring is not considered usage, so it never runs + # so this is just the immutable package_folder + assert "installed.txt" not in os.listdir(package_folder) def test_lockfile_interaction(self): pass From 73f5167aff5456d4126b520705ad026b397518de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Abril=20Rinc=C3=B3n=20Blanco?= Date: Mon, 22 Jul 2024 17:25:37 +0200 Subject: [PATCH 29/49] Add access to immutable_package_folder from conanfile/conanfileinterfaze --- conans/model/conan_file.py | 4 ++++ conans/model/conanfile_interface.py | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/conans/model/conan_file.py b/conans/model/conan_file.py index 64297587a6e..27bb337087a 100644 --- a/conans/model/conan_file.py +++ b/conans/model/conan_file.py @@ -318,6 +318,10 @@ def package_folder(self): """ return self.folders.base_package + @property + def immutable_package_folder(self): + return self.folders.immutable_package_folder + @property def install_folder(self): return self.folders.install_folder diff --git a/conans/model/conanfile_interface.py b/conans/model/conanfile_interface.py index 2130ff85be2..29a1607923f 100644 --- a/conans/model/conanfile_interface.py +++ b/conans/model/conanfile_interface.py @@ -39,6 +39,10 @@ def recipe_metadata_folder(self): def package_folder(self): return self._conanfile.package_folder + @property + def immutable_package_folder(self): + return self._conanfile.immutable_package_folder + @property def package_metadata_folder(self): return self._conanfile.package_metadata_folder From 1c89195111db67e552435ab6ded4f74e0c07141c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Abril=20Rinc=C3=B3n=20Blanco?= Date: Mon, 22 Jul 2024 17:33:09 +0200 Subject: [PATCH 30/49] Add test comment --- test/integration/conanfile/test_install_method.py | 1 + 1 file changed, 1 insertion(+) diff --git a/test/integration/conanfile/test_install_method.py b/test/integration/conanfile/test_install_method.py index 91f34058bf9..bea3b497f8d 100644 --- a/test/integration/conanfile/test_install_method.py +++ b/test/integration/conanfile/test_install_method.py @@ -222,6 +222,7 @@ def test_remote_upload_install_method(self, client): client.run(f"download {created_pref} -r=default") downloaded_pref_layout = client.get_latest_pkg_layout(created_pref) assert "file.txt" in os.listdir(downloaded_pref_layout.package()) + # Download is not an "usage" of the package, so no install() is yet executed assert "installed.txt" not in os.listdir(downloaded_pref_layout.package()) assert not os.path.exists(os.path.join(downloaded_pref_layout.install())) From 0eeeff32d32c0de7039a7b6f7cc0b1ec9c095252 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Abril=20Rinc=C3=B3n=20Blanco?= Date: Mon, 22 Jul 2024 17:43:43 +0200 Subject: [PATCH 31/49] conan cache check-integrity test --- .../conanfile/test_install_method.py | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/test/integration/conanfile/test_install_method.py b/test/integration/conanfile/test_install_method.py index bea3b497f8d..23b4c3d48f2 100644 --- a/test/integration/conanfile/test_install_method.py +++ b/test/integration/conanfile/test_install_method.py @@ -7,7 +7,7 @@ from conan.test.assets.genconanfile import GenConanfile from conan.test.utils.tools import TestClient -from conans.util.files import load +from conans.util.files import load, save conanfile_dep = textwrap.dedent(""" import os @@ -120,8 +120,19 @@ def test_vendorized(self): # TODO: Should this be handled? Or are vendoring packages meant to know if they are dealing with localized versions? pass - def test_check_integrity(self): - pass + def test_check_integrity(self, client): + client.run("create dep") + dep_layout = client.created_layout() + client.run(f"cache check-integrity {dep_layout.reference}") + assert "There are corrupted artifacts" not in client.out + # Even if we re-change the install folder contents, it should still be fine + save(os.path.join(dep_layout.install(), "installed.txt"), "Modified!") + client.run(f"cache check-integrity {dep_layout.reference}") + assert "There are corrupted artifacts" not in client.out + # But as soon as we change the package, it should still fail like a normal package would + save(os.path.join(dep_layout.package(), "file.txt"), "Modified!") + client.run(f"cache check-integrity {dep_layout.reference}", assert_error=True) + assert "There are corrupted artifacts" in client.out def test_access_invariant_from_consumer(self): pass From a2c93e4cc4925e58d5f8285ddb816d5501b6274b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Abril=20Rinc=C3=B3n=20Blanco?= Date: Mon, 22 Jul 2024 17:44:23 +0200 Subject: [PATCH 32/49] Reorder --- test/integration/conanfile/test_install_method.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/integration/conanfile/test_install_method.py b/test/integration/conanfile/test_install_method.py index 23b4c3d48f2..56c1a0cd580 100644 --- a/test/integration/conanfile/test_install_method.py +++ b/test/integration/conanfile/test_install_method.py @@ -80,6 +80,9 @@ def test_cache_path_command(self, client): assert dep_layout.package() not in client.out assert dep_layout.install() in client.out + def test_remove_deletes_correct_folders(self): + pass + def test_save_restore_cache(self, client): # Not created in the cache, just exported, nothing breaks because there is not even a package there client.run("cache save *:*") @@ -105,9 +108,6 @@ def test_save_restore_cache(self, client): def test_lockfile_interaction(self): pass - def test_remove_deletes_correct_folders(self): - pass - def test_graph_info_output(self): # The output should serialize the orignal package folder path to give users the info, # but maybe also the install one? From 6037bb3fe1cd93c429e5a180091b672eeb7adec9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Abril=20Rinc=C3=B3n=20Blanco?= Date: Mon, 22 Jul 2024 17:57:45 +0200 Subject: [PATCH 33/49] Extra step for cache save/restore --- test/integration/conanfile/test_install_method.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/integration/conanfile/test_install_method.py b/test/integration/conanfile/test_install_method.py index 56c1a0cd580..11dc3519822 100644 --- a/test/integration/conanfile/test_install_method.py +++ b/test/integration/conanfile/test_install_method.py @@ -104,6 +104,12 @@ def test_save_restore_cache(self, client): # The install() folder does not exist as restoring is not considered usage, so it never runs # so this is just the immutable package_folder assert "installed.txt" not in os.listdir(package_folder) + # But as soon as you call conan install, install() is called and so it's used, + # so package_folder will be the install folder + client.run("install --requires=dep/1.0") + client.run(f"cache path {dep_layout.reference}") + package_folder = client.out.strip() + assert "installed.txt" in os.listdir(package_folder) def test_lockfile_interaction(self): pass From 63fac5a7c332b0077cbdc83d11c9dd868da9197d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Abril=20Rinc=C3=B3n=20Blanco?= Date: Mon, 22 Jul 2024 18:12:46 +0200 Subject: [PATCH 34/49] Add immutable access test from consumer --- .../conanfile/test_install_method.py | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/test/integration/conanfile/test_install_method.py b/test/integration/conanfile/test_install_method.py index 11dc3519822..40e92ae2631 100644 --- a/test/integration/conanfile/test_install_method.py +++ b/test/integration/conanfile/test_install_method.py @@ -140,8 +140,26 @@ def test_check_integrity(self, client): client.run(f"cache check-integrity {dep_layout.reference}", assert_error=True) assert "There are corrupted artifacts" in client.out - def test_access_invariant_from_consumer(self): - pass + @pytest.mark.parametrize("with_install_method", [True, False]) + def test_access_immutable_from_consumer(self, client, with_install_method): + if not with_install_method: + client.save({"dep/conanfile.py": GenConanfile("dep", "1.0")}) + client.save({"app/conanfile.py": GenConanfile("app", "1.0") + .with_requires("dep/1.0") + .with_package("dep = self.dependencies['dep/1.0']", + "self.output.info(f'Immutable package: {dep.immutable_package_folder}')", + # TODO: Think about if we want this interface + # "self.output.info(f'Install: {dep.install_folder}')", + "self.output.info(f'Package: {dep.package_folder}')")}) + client.run("create dep") + dep_layout = client.created_layout() + client.run("create app") + assert f"app/1.0: Immutable package: {dep_layout.package()}" in client.out + # assert f"app/1.0: Install: {dep_layout.install()}" in client.out + if with_install_method: + assert f"app/1.0: Package: {dep_layout.install()}" in client.out + else: + assert f"app/1.0: Package: {dep_layout.package()}" in client.out class TestToolRequiresFlows: From 308f2dc771f20fef236d86cb6e35fddadeabc099 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Abril=20Rinc=C3=B3n=20Blanco?= Date: Tue, 23 Jul 2024 13:19:13 +0200 Subject: [PATCH 35/49] More tests, one failing for package_id reasons, add logging for install --- conan/test/assets/genconanfile.py | 16 +++--- conans/client/installer.py | 4 +- .../conanfile/test_install_method.py | 52 ++++++++++++++++--- 3 files changed, 58 insertions(+), 14 deletions(-) diff --git a/conan/test/assets/genconanfile.py b/conan/test/assets/genconanfile.py index 3e6eb9c6b18..fc41cb78286 100644 --- a/conan/test/assets/genconanfile.py +++ b/conan/test/assets/genconanfile.py @@ -162,9 +162,10 @@ def with_tool_requirement(self, ref, **kwargs): self._tool_requirements.append((ref_str, kwargs)) return self - def with_import(self, i): - if i not in self._imports: - self._imports.append(i) + def with_import(self, *imports): + for i in imports: + if i not in self._imports: + self._imports.append(i) return self def with_setting(self, setting): @@ -235,9 +236,10 @@ def with_package_info(self, cpp_info=None, env_info=None): self._package_info["env_info"] = env_info return self - def with_package_id(self, line): + def with_package_id(self, *lines): self._package_id_lines = self._package_id_lines or [] - self._package_id_lines.append(line) + for line in lines: + self._package_id_lines.append(line) return self def with_test(self, *lines): @@ -410,13 +412,13 @@ def package(self): def _install_method_render(self): lines = [] if self._install_lines: - lines.extend(" {}".format(line) for line in self._install_lines) + lines.extend(" {}".format(line) for line in self._install_lines) if not lines: return "" return """ def install(self): - {} +{} """.format("\n".join(lines)) @property diff --git a/conans/client/installer.py b/conans/client/installer.py index 4a510440248..724f7582f39 100644 --- a/conans/client/installer.py +++ b/conans/client/installer.py @@ -462,6 +462,8 @@ def _call_install_method(self, conanfile, install_folder): conanfile.folders.set_install_folder(install_folder) if not os.path.exists(install_folder): mkdir(install_folder) + conanfile.output.highlight("Calling install()") with conanfile_exception_formatter(conanfile, "install"): - conanfile.install() + with conanfile_remove_attr(conanfile, ['info'], 'install'): + conanfile.install() conanfile.folders.set_base_package(install_folder) diff --git a/test/integration/conanfile/test_install_method.py b/test/integration/conanfile/test_install_method.py index 40e92ae2631..259317e0c38 100644 --- a/test/integration/conanfile/test_install_method.py +++ b/test/integration/conanfile/test_install_method.py @@ -72,6 +72,13 @@ def generate(self): assert f"Dep package folder: {dep_layout.package()}" not in client.out assert f"Dep package folder: {dep_layout.install()}" in client.out + def test_no_info_access(self): + client = TestClient(light=True) + client.save({"conanfile.py": GenConanfile("dep", "1.0") + .with_install("self.output.info('Info.settings.os: ' + self.info.settings.os)")}) + client.run("create .", assert_error=True) + assert "'self.info' access in 'install()' method is forbidden" in client.out + def test_cache_path_command(self, client): client.run("create dep") dep_layout = client.created_layout() @@ -88,6 +95,7 @@ def test_save_restore_cache(self, client): client.run("cache save *:*") client.run("remove * -c") client.run("cache restore conan_cache_save.tgz") + # Now create the package and then save/restore client.run("create dep") dep_layout = client.created_layout() @@ -101,9 +109,11 @@ def test_save_restore_cache(self, client): client.run("cache restore conan_cache_save.tgz") client.run(f"cache path {dep_layout.reference}") package_folder = client.out.strip() + # The install() folder does not exist as restoring is not considered usage, so it never runs # so this is just the immutable package_folder assert "installed.txt" not in os.listdir(package_folder) + # But as soon as you call conan install, install() is called and so it's used, # so package_folder will be the install folder client.run("install --requires=dep/1.0") @@ -119,8 +129,10 @@ def test_graph_info_output(self): # but maybe also the install one? pass - def test_create_pkglist_output(self): - pass + def test_create_pkglist_output(self, client): + client.run("create dep -f=json", redirect_stdout="created.json") + client.run("list --graph=created.json --graph-binaries=build") + print() def test_vendorized(self): # TODO: Should this be handled? Or are vendoring packages meant to know if they are dealing with localized versions? @@ -161,6 +173,29 @@ def test_access_immutable_from_consumer(self, client, with_install_method): else: assert f"app/1.0: Package: {dep_layout.package()}" in client.out + def test_cache_modification_of_custom_conf_based_on_settings(self): + tc = TestClient(light=True) + tc.save({"conanfile.py": GenConanfile("dep", "1.0") + .with_import("from conan.tools.files import save", + "import os") + .with_option("myoption", [True, False]) + .with_option("otheroption", [True, False]) + .with_default_option("myoption", False) + .with_default_option("otheroption", False) + .with_setting("os") + .with_package_id("del self.info.options.myoption") + .with_install("save(self, os.path.join(self.install_folder, 'file.txt'), 'Hello World!')", + "save(self, os.path.join(self.install_folder, 'os.conf'), str(self.settings.os))", + "save(self, os.path.join(self.install_folder, 'option.conf'), str(self.options.get_safe('myoption')))", + "save(self, os.path.join(self.install_folder, 'otheroption.conf'), str(self.options.otheroption))")}) + tc.run("create . -s=os=Linux -o=&:myoption=True -o=&:otheroption=True") + layout = tc.created_layout() + assert "file.txt" in os.listdir(layout.install()) + assert tc.load(os.path.join(layout.install(), "os.conf")) == "Linux" + # This is problematic, it means that the mapping for install() and package_id would not be 1:1 and could be outdated + assert tc.load(os.path.join(layout.install(), "option.conf")) == "None" + assert tc.load(os.path.join(layout.install(), "otheroption.conf")) == "True" + class TestToolRequiresFlows: def test_tool_requires(self): @@ -222,14 +257,16 @@ def test_test_package_uses_created_tool_which_modifies_pkgfolder(self): .with_package_info({"bindirs": ["bin"]}, {}) .with_install("save(self, 'installed.txt', 'Installed file')"), "test_package/conanfile.py": GenConanfile() - .with_import("from conan.tools.files import save") - .with_import("import os") + .with_import("from conan.tools.files import save", + "import os") .with_test_reference_as_build_require() .with_test("bindir = self.dependencies.build[self.tested_reference_str].cpp_info.bindir", + "self.output.info(f'Bindir: {bindir}')", "save(self, os.path.join(bindir, '__pycache__.pyc'), 'Test file')")}) tc.run("create . --build-require") - created_ref = tc.created_package_reference("app/1.0") - tc.run(f"cache check-integrity {created_ref}") + app_layout = tc.created_layout() + assert f"Bindir: {os.path.join(app_layout.install(), 'bin')}" in tc.out + tc.run(f"cache check-integrity {app_layout.reference}") assert "There are corrupted artifacts" not in tc.out @@ -275,3 +312,6 @@ def test_remote_upload_install_method(self, client): def test_graph_info_of_remote_downloaded(self): pass + + def test_upload_verify_integrity(self): + pass From 993510fecf45ee325dee429e4cc85ad4cdf4b5bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Abril=20Rinc=C3=B3n=20Blanco?= Date: Tue, 23 Jul 2024 13:29:14 +0200 Subject: [PATCH 36/49] Allow only info access in install() --- conans/client/installer.py | 2 +- test/integration/conanfile/test_install_method.py | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/conans/client/installer.py b/conans/client/installer.py index 724f7582f39..458fe12d436 100644 --- a/conans/client/installer.py +++ b/conans/client/installer.py @@ -464,6 +464,6 @@ def _call_install_method(self, conanfile, install_folder): mkdir(install_folder) conanfile.output.highlight("Calling install()") with conanfile_exception_formatter(conanfile, "install"): - with conanfile_remove_attr(conanfile, ['info'], 'install'): + with conanfile_remove_attr(conanfile, ['cpp_info', 'settings', 'options'], 'install'): conanfile.install() conanfile.folders.set_base_package(install_folder) diff --git a/test/integration/conanfile/test_install_method.py b/test/integration/conanfile/test_install_method.py index 259317e0c38..ee1a5726679 100644 --- a/test/integration/conanfile/test_install_method.py +++ b/test/integration/conanfile/test_install_method.py @@ -72,12 +72,12 @@ def generate(self): assert f"Dep package folder: {dep_layout.package()}" not in client.out assert f"Dep package folder: {dep_layout.install()}" in client.out - def test_no_info_access(self): + def test_no_non_info_access(self): client = TestClient(light=True) client.save({"conanfile.py": GenConanfile("dep", "1.0") - .with_install("self.output.info('Info.settings.os: ' + self.info.settings.os)")}) + .with_install("self.output.info('settings.os: ' + self.settings.os)")}) client.run("create .", assert_error=True) - assert "'self.info' access in 'install()' method is forbidden" in client.out + assert "'self.settings' access in 'install()' method is forbidden" in client.out def test_cache_path_command(self, client): client.run("create dep") @@ -185,9 +185,9 @@ def test_cache_modification_of_custom_conf_based_on_settings(self): .with_setting("os") .with_package_id("del self.info.options.myoption") .with_install("save(self, os.path.join(self.install_folder, 'file.txt'), 'Hello World!')", - "save(self, os.path.join(self.install_folder, 'os.conf'), str(self.settings.os))", - "save(self, os.path.join(self.install_folder, 'option.conf'), str(self.options.get_safe('myoption')))", - "save(self, os.path.join(self.install_folder, 'otheroption.conf'), str(self.options.otheroption))")}) + "save(self, os.path.join(self.install_folder, 'os.conf'), str(self.info.settings.os))", + "save(self, os.path.join(self.install_folder, 'option.conf'), str(self.info,options.get_safe('myoption')))", + "save(self, os.path.join(self.install_folder, 'otheroption.conf'), str(self.info.options.otheroption))")}) tc.run("create . -s=os=Linux -o=&:myoption=True -o=&:otheroption=True") layout = tc.created_layout() assert "file.txt" in os.listdir(layout.install()) From 551b4810e1a518fddb822d082037e4c2866bde08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Abril=20Rinc=C3=B3n=20Blanco?= Date: Tue, 23 Jul 2024 13:30:00 +0200 Subject: [PATCH 37/49] Typo --- test/integration/conanfile/test_install_method.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/integration/conanfile/test_install_method.py b/test/integration/conanfile/test_install_method.py index ee1a5726679..f2ca41beaef 100644 --- a/test/integration/conanfile/test_install_method.py +++ b/test/integration/conanfile/test_install_method.py @@ -186,7 +186,7 @@ def test_cache_modification_of_custom_conf_based_on_settings(self): .with_package_id("del self.info.options.myoption") .with_install("save(self, os.path.join(self.install_folder, 'file.txt'), 'Hello World!')", "save(self, os.path.join(self.install_folder, 'os.conf'), str(self.info.settings.os))", - "save(self, os.path.join(self.install_folder, 'option.conf'), str(self.info,options.get_safe('myoption')))", + "save(self, os.path.join(self.install_folder, 'option.conf'), str(self.info.options.get_safe('myoption')))", "save(self, os.path.join(self.install_folder, 'otheroption.conf'), str(self.info.options.otheroption))")}) tc.run("create . -s=os=Linux -o=&:myoption=True -o=&:otheroption=True") layout = tc.created_layout() From 6599fdeaa096ab4b4cb253b09ee19a32c3ac3461 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Abril=20Rinc=C3=B3n=20Blanco?= Date: Tue, 23 Jul 2024 14:36:23 +0200 Subject: [PATCH 38/49] Fix Windows test --- test/integration/conanfile/test_install_method.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/integration/conanfile/test_install_method.py b/test/integration/conanfile/test_install_method.py index f2ca41beaef..e9c9c3c48c0 100644 --- a/test/integration/conanfile/test_install_method.py +++ b/test/integration/conanfile/test_install_method.py @@ -102,7 +102,8 @@ def test_save_restore_cache(self, client): client.run("cache save *:* -f=json", redirect_stdout="saved.json") saved = json.loads(client.load("saved.json")) pref = dep_layout.reference - assert saved["Local Cache"]["dep/1.0"]["revisions"][pref.ref.revision]["packages"][pref.package_id]["revisions"][pref.revision]["package_folder"] in dep_layout.package() + saved_pkg_folder = saved["Local Cache"]["dep/1.0"]["revisions"][pref.ref.revision]["packages"][pref.package_id]["revisions"][pref.revision]["package_folder"] + assert saved_pkg_folder in dep_layout.package().replace("\\", "/") client.run("remove * -c") assert not os.path.exists(dep_layout.package()) assert not os.path.exists(dep_layout.install()) From 3ff678c229c853253e2c4210543296568043967b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Abril=20Rinc=C3=B3n=20Blanco?= Date: Tue, 23 Jul 2024 15:29:54 +0200 Subject: [PATCH 39/49] More logging --- conans/client/installer.py | 1 + test/integration/conanfile/test_install_method.py | 1 + 2 files changed, 2 insertions(+) diff --git a/conans/client/installer.py b/conans/client/installer.py index 458fe12d436..b76111f8c82 100644 --- a/conans/client/installer.py +++ b/conans/client/installer.py @@ -467,3 +467,4 @@ def _call_install_method(self, conanfile, install_folder): with conanfile_remove_attr(conanfile, ['cpp_info', 'settings', 'options'], 'install'): conanfile.install() conanfile.folders.set_base_package(install_folder) + conanfile.output.success(f"Install folder {install_folder}") diff --git a/test/integration/conanfile/test_install_method.py b/test/integration/conanfile/test_install_method.py index e9c9c3c48c0..620e873e75b 100644 --- a/test/integration/conanfile/test_install_method.py +++ b/test/integration/conanfile/test_install_method.py @@ -309,6 +309,7 @@ def test_remote_upload_install_method(self, client): client.run("remove * -c") client.run("install --requires=dep/1.0 -r=default") + assert "dep/1.0: Calling install()" assert f"Running install method in {downloaded_pref_layout.install()}" in client.out def test_graph_info_of_remote_downloaded(self): From 70d17cfc064f2ae959fa57db535d962fb3684550 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Abril=20Rinc=C3=B3n=20Blanco?= Date: Tue, 23 Jul 2024 20:34:33 +0200 Subject: [PATCH 40/49] Add conan upload ... --check test --- test/integration/conanfile/test_install_method.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/test/integration/conanfile/test_install_method.py b/test/integration/conanfile/test_install_method.py index 620e873e75b..c33b3cbc025 100644 --- a/test/integration/conanfile/test_install_method.py +++ b/test/integration/conanfile/test_install_method.py @@ -315,5 +315,9 @@ def test_remote_upload_install_method(self, client): def test_graph_info_of_remote_downloaded(self): pass - def test_upload_verify_integrity(self): - pass + def test_upload_verify_integrity(self, client): + client.run("create dep") + dep_layout = client.created_layout() + client.run("upload * -r=default -c --check") + assert f"dep/1.0:{dep_layout.reference.package_id}: Integrity checked: ok" in client.out + assert "There are corrupted artifacts" not in client.out From 0211903f5ee0bac9cc196ccc4cb1fc11ebbcce07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Abril=20Rinc=C3=B3n=20Blanco?= Date: Fri, 2 Aug 2024 14:13:44 +0200 Subject: [PATCH 41/49] Add new tests and serialize immutable_package folder in ConanFile Co-authored-by: PerseoGI --- conans/model/conan_file.py | 1 + .../conanfile/test_install_method.py | 77 ++++++++++++++----- 2 files changed, 59 insertions(+), 19 deletions(-) diff --git a/conans/model/conan_file.py b/conans/model/conan_file.py index 27bb337087a..13e4de3617c 100644 --- a/conans/model/conan_file.py +++ b/conans/model/conan_file.py @@ -164,6 +164,7 @@ def serialize(self): result["build_folder"] = self.build_folder result["generators_folder"] = self.generators_folder result["package_folder"] = self.package_folder + result["immutable_package_folder"] = self.immutable_package_folder result["cpp_info"] = self.cpp_info.serialize() result["conf_info"] = self.conf_info.serialize() diff --git a/test/integration/conanfile/test_install_method.py b/test/integration/conanfile/test_install_method.py index c33b3cbc025..c523b3a4b1b 100644 --- a/test/integration/conanfile/test_install_method.py +++ b/test/integration/conanfile/test_install_method.py @@ -19,6 +19,7 @@ class TestConan(ConanFile): version = "1.0" def package(self): save(self, os.path.join(self.package_folder, "file.txt"), "Hello World!") + save(self, os.path.join(self.package_folder, "file2.txt"), "Hello World 2!") def install(self): self.output.info(f"Running install method in {self.install_folder}") @@ -79,6 +80,31 @@ def test_no_non_info_access(self): client.run("create .", assert_error=True) assert "'self.settings' access in 'install()' method is forbidden" in client.out + def test_install_moves_from_package(self): + client = TestClient(light=True) + client.save({"conanfile.py": GenConanfile("dep", "1.0") + .with_import("from conan.tools.files import save, rename", + "import os") + .with_option("move", [True, False]) + .with_package('save(self, os.path.join(self.package_folder, "file.txt"), "Hello World!")', + "save(self, os.path.join(self.package_folder, 'file2.txt'), 'Hello World 2!')") + # This is NOT allowed, moving from package to install is forbidden, only as test to ensure consistency + .with_install("rename(self, os.path.join(self.package_folder, 'file.txt'), os.path.join(self.install_folder, 'file.txt')) if self.info.options.move else None")}) + client.run("create . -o=dep/*:move=True") + dep_moved_layout = client.created_layout() + dep_moved_pkgid = client.created_package_id("dep/1.0") + assert "file.txt" in os.listdir(dep_moved_layout.install()) + assert "file.txt" not in os.listdir(dep_moved_layout.package()) + + client.run("create . -o=dep/*:move=False") + dep_kept_layout = client.created_layout() + dep_kept_pkgid = client.created_package_id("dep/1.0") + assert "file.txt" not in os.listdir(dep_kept_layout.install()) + assert "file.txt" in os.listdir(dep_kept_layout.package()) + + # Now we can check that the package_id is the same for both + assert dep_moved_pkgid != dep_kept_pkgid + def test_cache_path_command(self, client): client.run("create dep") dep_layout = client.created_layout() @@ -87,8 +113,12 @@ def test_cache_path_command(self, client): assert dep_layout.package() not in client.out assert dep_layout.install() in client.out - def test_remove_deletes_correct_folders(self): - pass + def test_remove_deletes_correct_folders(self, client): + client.run("create dep") + dep_layout = client.created_layout() + client.run("remove * -c") + assert not os.path.exists(dep_layout.package()) + assert not os.path.exists(dep_layout.install()) def test_save_restore_cache(self, client): # Not created in the cache, just exported, nothing breaks because there is not even a package there @@ -122,22 +152,37 @@ def test_save_restore_cache(self, client): package_folder = client.out.strip() assert "installed.txt" in os.listdir(package_folder) - def test_lockfile_interaction(self): - pass - - def test_graph_info_output(self): - # The output should serialize the orignal package folder path to give users the info, - # but maybe also the install one? - pass + def test_graph_info_output(self, client): + client.run("create dep") + dep_layout = client.created_layout() + client.run("install --requires=dep/1.0 -f=json", redirect_stdout="install.json") + install_output = json.loads(client.load("install.json")) + assert install_output["graph"]["nodes"]["1"]["package_folder"] == dep_layout.install() + assert install_output["graph"]["nodes"]["1"]["immutable_package_folder"] == dep_layout.package() def test_create_pkglist_output(self, client): client.run("create dep -f=json", redirect_stdout="created.json") + created_pkgid = client.created_package_id("dep/1.0") client.run("list --graph=created.json --graph-binaries=build") - print() + assert created_pkgid in client.out - def test_vendorized(self): - # TODO: Should this be handled? Or are vendoring packages meant to know if they are dealing with localized versions? - pass + def test_vendorized_basic(self, client): + client.run("create dep") + client.save({"vendor/conanfile.py": GenConanfile("vendor", "1.0") + .with_import("from conan.tools.files import copy") + .with_class_attribute("vendor=True") + .with_requires("dep/1.0") + .with_package("copy(self, 'file.txt', src=self.dependencies['dep'].package_folder, dst=self.package_folder)", + "copy(self, 'installed.txt', src=self.dependencies['dep'].package_folder, dst=self.package_folder)", + "copy(self, 'file2.txt', src=self.dependencies['dep'].immutable_package_folder, dst=self.package_folder)")}) + client.run("create vendor") + vendor_layout = client.created_layout() + assert "file.txt" in os.listdir(vendor_layout.package()) + assert "installed.txt" in os.listdir(vendor_layout.package()) + assert "file2.txt" in os.listdir(vendor_layout.package()) + + client.save("app/conanfile.py", GenConanfile("app", "1.0") + .with_requires("vendor/1.0")) def test_check_integrity(self, client): client.run("create dep") @@ -246,9 +291,6 @@ def build(self): assert f"Dep bindir: {dep_layout.install()}" in tc.out assert "app/1.0: Is installed? True" in tc.out - def test_update_recipe(self): - pass - def test_test_package_uses_created_tool_which_modifies_pkgfolder(self): tc = TestClient(light=True) tc.save({"conanfile.py": GenConanfile("app", "1.0") @@ -312,9 +354,6 @@ def test_remote_upload_install_method(self, client): assert "dep/1.0: Calling install()" assert f"Running install method in {downloaded_pref_layout.install()}" in client.out - def test_graph_info_of_remote_downloaded(self): - pass - def test_upload_verify_integrity(self, client): client.run("create dep") dep_layout = client.created_layout() From c0a5d5812d305d2aae24e9d4d795f8691f7423ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Abril=20Rinc=C3=B3n=20Blanco?= Date: Fri, 2 Aug 2024 14:21:08 +0200 Subject: [PATCH 42/49] Extra check that it in fact would break --- test/integration/conanfile/test_install_method.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/test/integration/conanfile/test_install_method.py b/test/integration/conanfile/test_install_method.py index c523b3a4b1b..21c5ad3091e 100644 --- a/test/integration/conanfile/test_install_method.py +++ b/test/integration/conanfile/test_install_method.py @@ -92,18 +92,23 @@ def test_install_moves_from_package(self): .with_install("rename(self, os.path.join(self.package_folder, 'file.txt'), os.path.join(self.install_folder, 'file.txt')) if self.info.options.move else None")}) client.run("create . -o=dep/*:move=True") dep_moved_layout = client.created_layout() - dep_moved_pkgid = client.created_package_id("dep/1.0") assert "file.txt" in os.listdir(dep_moved_layout.install()) assert "file.txt" not in os.listdir(dep_moved_layout.package()) client.run("create . -o=dep/*:move=False") dep_kept_layout = client.created_layout() - dep_kept_pkgid = client.created_package_id("dep/1.0") assert "file.txt" not in os.listdir(dep_kept_layout.install()) assert "file.txt" in os.listdir(dep_kept_layout.package()) # Now we can check that the package_id is the same for both - assert dep_moved_pkgid != dep_kept_pkgid + assert dep_moved_layout.reference.package_id != dep_kept_layout.reference.package_id + + # This now breaks if we try to cache check-integrity the moved package + client.run(f"cache check-integrity {dep_moved_layout.reference}", assert_error=True) + assert "There are corrupted artifacts" in client.out + + client.run(f"cache check-integrity {dep_kept_layout.reference}") + assert "There are corrupted artifacts" not in client.out def test_cache_path_command(self, client): client.run("create dep") From 65c2bdfd8c5a6fe896cf2ffb525de25551ae8c1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Abril=20Rinc=C3=B3n=20Blanco?= Date: Fri, 2 Aug 2024 14:26:27 +0200 Subject: [PATCH 43/49] Simplify --- test/integration/conanfile/test_install_method.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/test/integration/conanfile/test_install_method.py b/test/integration/conanfile/test_install_method.py index 21c5ad3091e..b1181c2f05a 100644 --- a/test/integration/conanfile/test_install_method.py +++ b/test/integration/conanfile/test_install_method.py @@ -186,9 +186,6 @@ def test_vendorized_basic(self, client): assert "installed.txt" in os.listdir(vendor_layout.package()) assert "file2.txt" in os.listdir(vendor_layout.package()) - client.save("app/conanfile.py", GenConanfile("app", "1.0") - .with_requires("vendor/1.0")) - def test_check_integrity(self, client): client.run("create dep") dep_layout = client.created_layout() From c448709ec608a4e9430d749d0b0e8c6bb72ef80a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Abril=20Rinc=C3=B3n=20Blanco?= Date: Mon, 12 Aug 2024 21:36:05 +0200 Subject: [PATCH 44/49] Rename install() to localize(), remove conanfile.localize_folder --- conan/api/subapi/cache.py | 4 +- .../internal/cache/conan_reference_layout.py | 6 +- conan/test/assets/genconanfile.py | 22 +-- conans/client/installer.py | 25 ++-- conans/model/conan_file.py | 4 - conans/model/layout.py | 10 +- ...tall_method.py => test_localize_method.py} | 141 +++++++++--------- 7 files changed, 104 insertions(+), 108 deletions(-) rename test/integration/conanfile/{test_install_method.py => test_localize_method.py} (71%) diff --git a/conan/api/subapi/cache.py b/conan/api/subapi/cache.py index b1e10714d66..5a466650f79 100644 --- a/conan/api/subapi/cache.py +++ b/conan/api/subapi/cache.py @@ -63,8 +63,8 @@ def package_path(self, pref: PkgReference): app = ConanApp(self.conan_api) pref = _resolve_latest_pref(app, pref) ref_layout = app.cache.pkg_layout(pref) - if os.path.exists(ref_layout.install()): - return ref_layout.install() + if os.path.exists(ref_layout.localize()): + return ref_layout.localize() return _check_folder_existence(pref, "package", ref_layout.package()) def check_integrity(self, package_list): diff --git a/conan/internal/cache/conan_reference_layout.py b/conan/internal/cache/conan_reference_layout.py index 4817e024635..d8b2c95eab3 100644 --- a/conan/internal/cache/conan_reference_layout.py +++ b/conan/internal/cache/conan_reference_layout.py @@ -10,7 +10,7 @@ SRC_FOLDER = "s" BUILD_FOLDER = "b" PACKAGES_FOLDER = "p" -INSTALL_FOLDER = "i" +LOCALIZE_FOLDER = "l" EXPORT_FOLDER = "e" EXPORT_SRC_FOLDER = "es" DOWNLOAD_EXPORT_FOLDER = "d" @@ -100,8 +100,8 @@ def build(self): def package(self): return os.path.join(self._base_folder, PACKAGES_FOLDER) - def install(self): - return os.path.join(self._base_folder, INSTALL_FOLDER) + def localize(self): + return os.path.join(self._base_folder, LOCALIZE_FOLDER) def download_package(self): return os.path.join(self._base_folder, DOWNLOAD_EXPORT_FOLDER) diff --git a/conan/test/assets/genconanfile.py b/conan/test/assets/genconanfile.py index fc41cb78286..8949b8ad81b 100644 --- a/conan/test/assets/genconanfile.py +++ b/conan/test/assets/genconanfile.py @@ -27,7 +27,7 @@ def __init__(self, name=None, version=None): self._provides = None self._deprecated = None self._package_lines = None - self._install_lines = None + self._localize_lines = None self._package_files = None self._package_files_env = None self._package_files_link = None @@ -215,10 +215,10 @@ def with_package(self, *lines): self._package_lines.append(line) return self - def with_install(self, *lines): - self._install_lines = self._install_lines or [] + def with_localize(self, *lines): + self._localize_lines = self._localize_lines or [] for line in lines: - self._install_lines.append(line) + self._localize_lines.append(line) return self def with_build_msg(self, msg): @@ -377,8 +377,8 @@ def _package_method(self): self._package_files_link) @property - def _install_method(self): - return self._install_lines + def _localize_method(self): + return self._localize_lines @property def _package_method_render(self): @@ -409,15 +409,15 @@ def package(self): """.format("\n".join(lines)) @property - def _install_method_render(self): + def _localize_method_render(self): lines = [] - if self._install_lines: - lines.extend(" {}".format(line) for line in self._install_lines) + if self._localize_lines: + lines.extend(" {}".format(line) for line in self._localize_lines) if not lines: return "" return """ - def install(self): + def localize(self): {} """.format("\n".join(lines)) @@ -506,7 +506,7 @@ def __repr__(self): "tool_requires", "test_requires", "requirements", "python_requires", "revision_mode", "settings", "options", "default_options", "build", "package_method", "package_info", "package_id_lines", "test_lines", - "install_method" + "localize_method" ): if member == "requirements": # FIXME: This seems exclusive, but we could mix them? diff --git a/conans/client/installer.py b/conans/client/installer.py index b76111f8c82..83532c33e9f 100644 --- a/conans/client/installer.py +++ b/conans/client/installer.py @@ -338,7 +338,7 @@ def _handle_package(self, package, install_reference, handled_count, total_count # Call the info method conanfile.folders.set_base_package(pkg_folder) conanfile.folders.set_base_pkg_metadata(pkg_metadata) - self._call_install_method(conanfile, package_layout.install()) + self._call_localize_method(conanfile, package_layout.localize()) # Use package_folder which has been updated previously by install_method if necessary self._call_package_info(conanfile, conanfile.package_folder, is_editable=False) @@ -457,14 +457,15 @@ def _call_package_info(self, conanfile, package_folder, is_editable): conanfile.cpp_info.check_component_requires(conanfile) - def _call_install_method(self, conanfile, install_folder): - if hasattr(conanfile, "install"): - conanfile.folders.set_install_folder(install_folder) - if not os.path.exists(install_folder): - mkdir(install_folder) - conanfile.output.highlight("Calling install()") - with conanfile_exception_formatter(conanfile, "install"): - with conanfile_remove_attr(conanfile, ['cpp_info', 'settings', 'options'], 'install'): - conanfile.install() - conanfile.folders.set_base_package(install_folder) - conanfile.output.success(f"Install folder {install_folder}") + def _call_localize_method(self, conanfile, localize_folder): + if hasattr(conanfile, "localize"): + conanfile.folders.set_localize_folder(localize_folder) + conanfile.folders.set_base_package(localize_folder) + if not os.path.exists(localize_folder): + mkdir(localize_folder) + conanfile.output.highlight("Calling localize()") + with conanfile_exception_formatter(conanfile, "localize_folder"): + with conanfile_remove_attr(conanfile, ['cpp_info', 'settings', 'options'], 'localize'): + conanfile.localize() + + conanfile.output.success(f"Localize folder {localize_folder}") diff --git a/conans/model/conan_file.py b/conans/model/conan_file.py index 13e4de3617c..50cecb9b01e 100644 --- a/conans/model/conan_file.py +++ b/conans/model/conan_file.py @@ -323,10 +323,6 @@ def package_folder(self): def immutable_package_folder(self): return self.folders.immutable_package_folder - @property - def install_folder(self): - return self.folders.install_folder - @property def generators_folder(self): return self.folders.generators_folder diff --git a/conans/model/layout.py b/conans/model/layout.py index e51fa00a441..ad7b99d9df7 100644 --- a/conans/model/layout.py +++ b/conans/model/layout.py @@ -50,7 +50,7 @@ def __init__(self): self.source = "" self.build = "" self.package = "" - self.install = "" + self.localize = "" self.generators = "" # Relative location of the project root, if the conanfile is not in that project root, but # in a subfolder: e.g: If the conanfile is in a subfolder then self.root = ".." @@ -144,13 +144,13 @@ def package_folder(self): """For the cache, the package folder is only the base""" return self._base_package - def set_install_folder(self, folder): + def set_localize_folder(self, folder): self._immutable_package_folder = self.package_folder - self.install = folder + self.localize = folder @property - def install_folder(self): - return self.install + def localize_folder(self): + return self.localize @property def immutable_package_folder(self): diff --git a/test/integration/conanfile/test_install_method.py b/test/integration/conanfile/test_localize_method.py similarity index 71% rename from test/integration/conanfile/test_install_method.py rename to test/integration/conanfile/test_localize_method.py index b1181c2f05a..3ac99edfe32 100644 --- a/test/integration/conanfile/test_install_method.py +++ b/test/integration/conanfile/test_localize_method.py @@ -21,11 +21,10 @@ def package(self): save(self, os.path.join(self.package_folder, "file.txt"), "Hello World!") save(self, os.path.join(self.package_folder, "file2.txt"), "Hello World 2!") - def install(self): - self.output.info(f"Running install method in {self.install_folder}") - # copy(self, "*", src=self.package_folder, dst=self.install_folder) - copy(self, "file.txt", src=self.package_folder, dst=self.install_folder) - save(self, os.path.join(self.install_folder, "installed.txt"), "Installed file") + def localize(self): + self.output.info(f"Running localize method in {self.package_folder}") + copy(self, "file.txt", src=self.immutable_package_folder, dst=self.package_folder) + save(self, os.path.join(self.package_folder, "localized.txt"), "localized file") def package_info(self): self.output.info(f"Running package_info method in {self.package_folder}") @@ -41,21 +40,21 @@ def client(self): tc.run("export dep") return tc - def test_basic_install_method(self, client): + def test_basic_localize_method(self, client): client.run("create dep") layout = client.created_layout() assert layout.package().endswith("p") assert f"Package folder {layout.package()}" in client.out - assert f"Running install method in {layout.install()}" in client.out - assert f"Running package_info method in {layout.install()}" in client.out + assert f"Running localize method in {layout.localize()}" in client.out + assert f"Running package_info method in {layout.localize()}" in client.out client.run("install --requires=dep/1.0") - assert f"Running package_info method in {layout.install()}" in client.out + assert f"Running package_info method in {layout.localize()}" in client.out # Only issue is that the PackageLayout has no idea about the redirected package folder # So we have to know to check for it in tests, but oh well - assert "installed.txt" in os.listdir(layout.install()) - assert "installed.txt" not in os.listdir(layout.package()) + assert "localized.txt" in os.listdir(layout.localize()) + assert "localized.txt" not in os.listdir(layout.package()) - def test_dependency_install_method(self, client): + def test_dependency_localize_method(self, client): client.save({"app/conanfile.py": textwrap.dedent(""" from conan import ConanFile class TestConan(ConanFile): @@ -71,16 +70,16 @@ def generate(self): dep_layout = client.created_layout() client.run("create app") assert f"Dep package folder: {dep_layout.package()}" not in client.out - assert f"Dep package folder: {dep_layout.install()}" in client.out + assert f"Dep package folder: {dep_layout.localize()}" in client.out def test_no_non_info_access(self): client = TestClient(light=True) client.save({"conanfile.py": GenConanfile("dep", "1.0") - .with_install("self.output.info('settings.os: ' + self.settings.os)")}) + .with_localize("self.output.info('settings.os: ' + self.settings.os)")}) client.run("create .", assert_error=True) - assert "'self.settings' access in 'install()' method is forbidden" in client.out + assert "'self.settings' access in 'localize()' method is forbidden" in client.out - def test_install_moves_from_package(self): + def test_localize_moves_from_package(self): client = TestClient(light=True) client.save({"conanfile.py": GenConanfile("dep", "1.0") .with_import("from conan.tools.files import save, rename", @@ -88,16 +87,16 @@ def test_install_moves_from_package(self): .with_option("move", [True, False]) .with_package('save(self, os.path.join(self.package_folder, "file.txt"), "Hello World!")', "save(self, os.path.join(self.package_folder, 'file2.txt'), 'Hello World 2!')") - # This is NOT allowed, moving from package to install is forbidden, only as test to ensure consistency - .with_install("rename(self, os.path.join(self.package_folder, 'file.txt'), os.path.join(self.install_folder, 'file.txt')) if self.info.options.move else None")}) + # This is NOT allowed, moving from package to localize is forbidden, only as test to ensure consistency + .with_localize("rename(self, os.path.join(self.immutable_package_folder, 'file.txt'), os.path.join(self.package_folder, 'file.txt')) if self.info.options.move else None")}) client.run("create . -o=dep/*:move=True") dep_moved_layout = client.created_layout() - assert "file.txt" in os.listdir(dep_moved_layout.install()) + assert "file.txt" in os.listdir(dep_moved_layout.localize()) assert "file.txt" not in os.listdir(dep_moved_layout.package()) client.run("create . -o=dep/*:move=False") dep_kept_layout = client.created_layout() - assert "file.txt" not in os.listdir(dep_kept_layout.install()) + assert "file.txt" not in os.listdir(dep_kept_layout.localize()) assert "file.txt" in os.listdir(dep_kept_layout.package()) # Now we can check that the package_id is the same for both @@ -116,14 +115,14 @@ def test_cache_path_command(self, client): pref = client.created_package_reference("dep/1.0") client.run(f"cache path {pref}") assert dep_layout.package() not in client.out - assert dep_layout.install() in client.out + assert dep_layout.localize() in client.out def test_remove_deletes_correct_folders(self, client): client.run("create dep") dep_layout = client.created_layout() client.run("remove * -c") assert not os.path.exists(dep_layout.package()) - assert not os.path.exists(dep_layout.install()) + assert not os.path.exists(dep_layout.localize()) def test_save_restore_cache(self, client): # Not created in the cache, just exported, nothing breaks because there is not even a package there @@ -141,29 +140,29 @@ def test_save_restore_cache(self, client): assert saved_pkg_folder in dep_layout.package().replace("\\", "/") client.run("remove * -c") assert not os.path.exists(dep_layout.package()) - assert not os.path.exists(dep_layout.install()) + assert not os.path.exists(dep_layout.localize()) client.run("cache restore conan_cache_save.tgz") client.run(f"cache path {dep_layout.reference}") package_folder = client.out.strip() - # The install() folder does not exist as restoring is not considered usage, so it never runs + # The localize() folder does not exist as restoring is not considered usage, so it never runs # so this is just the immutable package_folder - assert "installed.txt" not in os.listdir(package_folder) + assert "localized.txt" not in os.listdir(package_folder) - # But as soon as you call conan install, install() is called and so it's used, - # so package_folder will be the install folder + # But as soon as you call conan localize, localize() is called and so it's used, + # so package_folder will be the localize folder client.run("install --requires=dep/1.0") client.run(f"cache path {dep_layout.reference}") package_folder = client.out.strip() - assert "installed.txt" in os.listdir(package_folder) + assert "localized.txt" in os.listdir(package_folder) def test_graph_info_output(self, client): client.run("create dep") dep_layout = client.created_layout() - client.run("install --requires=dep/1.0 -f=json", redirect_stdout="install.json") - install_output = json.loads(client.load("install.json")) - assert install_output["graph"]["nodes"]["1"]["package_folder"] == dep_layout.install() - assert install_output["graph"]["nodes"]["1"]["immutable_package_folder"] == dep_layout.package() + client.run("install --requires=dep/1.0 -f=json", redirect_stdout="localize.json") + localize_output = json.loads(client.load("localize.json")) + assert localize_output["graph"]["nodes"]["1"]["package_folder"] == dep_layout.localize() + assert localize_output["graph"]["nodes"]["1"]["immutable_package_folder"] == dep_layout.package() def test_create_pkglist_output(self, client): client.run("create dep -f=json", redirect_stdout="created.json") @@ -178,12 +177,12 @@ def test_vendorized_basic(self, client): .with_class_attribute("vendor=True") .with_requires("dep/1.0") .with_package("copy(self, 'file.txt', src=self.dependencies['dep'].package_folder, dst=self.package_folder)", - "copy(self, 'installed.txt', src=self.dependencies['dep'].package_folder, dst=self.package_folder)", + "copy(self, 'localized.txt', src=self.dependencies['dep'].package_folder, dst=self.package_folder)", "copy(self, 'file2.txt', src=self.dependencies['dep'].immutable_package_folder, dst=self.package_folder)")}) client.run("create vendor") vendor_layout = client.created_layout() assert "file.txt" in os.listdir(vendor_layout.package()) - assert "installed.txt" in os.listdir(vendor_layout.package()) + assert "localized.txt" in os.listdir(vendor_layout.package()) assert "file2.txt" in os.listdir(vendor_layout.package()) def test_check_integrity(self, client): @@ -191,8 +190,8 @@ def test_check_integrity(self, client): dep_layout = client.created_layout() client.run(f"cache check-integrity {dep_layout.reference}") assert "There are corrupted artifacts" not in client.out - # Even if we re-change the install folder contents, it should still be fine - save(os.path.join(dep_layout.install(), "installed.txt"), "Modified!") + # Even if we re-change the localize folder contents, it should still be fine + save(os.path.join(dep_layout.localize(), "localized.txt"), "Modified!") client.run(f"cache check-integrity {dep_layout.reference}") assert "There are corrupted artifacts" not in client.out # But as soon as we change the package, it should still fail like a normal package would @@ -200,24 +199,24 @@ def test_check_integrity(self, client): client.run(f"cache check-integrity {dep_layout.reference}", assert_error=True) assert "There are corrupted artifacts" in client.out - @pytest.mark.parametrize("with_install_method", [True, False]) - def test_access_immutable_from_consumer(self, client, with_install_method): - if not with_install_method: + @pytest.mark.parametrize("with_localize_method", [True, False]) + def test_access_immutable_from_consumer(self, client, with_localize_method): + if not with_localize_method: client.save({"dep/conanfile.py": GenConanfile("dep", "1.0")}) client.save({"app/conanfile.py": GenConanfile("app", "1.0") .with_requires("dep/1.0") .with_package("dep = self.dependencies['dep/1.0']", "self.output.info(f'Immutable package: {dep.immutable_package_folder}')", # TODO: Think about if we want this interface - # "self.output.info(f'Install: {dep.install_folder}')", + # "self.output.info(f'localize: {dep.localize_folder}')", "self.output.info(f'Package: {dep.package_folder}')")}) client.run("create dep") dep_layout = client.created_layout() client.run("create app") assert f"app/1.0: Immutable package: {dep_layout.package()}" in client.out - # assert f"app/1.0: Install: {dep_layout.install()}" in client.out - if with_install_method: - assert f"app/1.0: Package: {dep_layout.install()}" in client.out + # assert f"app/1.0: localize: {dep_layout.localize()}" in client.out + if with_localize_method: + assert f"app/1.0: Package: {dep_layout.localize()}" in client.out else: assert f"app/1.0: Package: {dep_layout.package()}" in client.out @@ -232,17 +231,17 @@ def test_cache_modification_of_custom_conf_based_on_settings(self): .with_default_option("otheroption", False) .with_setting("os") .with_package_id("del self.info.options.myoption") - .with_install("save(self, os.path.join(self.install_folder, 'file.txt'), 'Hello World!')", - "save(self, os.path.join(self.install_folder, 'os.conf'), str(self.info.settings.os))", - "save(self, os.path.join(self.install_folder, 'option.conf'), str(self.info.options.get_safe('myoption')))", - "save(self, os.path.join(self.install_folder, 'otheroption.conf'), str(self.info.options.otheroption))")}) + .with_localize("save(self, os.path.join(self.package_folder, 'file.txt'), 'Hello World!')", + "save(self, os.path.join(self.package_folder, 'os.conf'), str(self.info.settings.os))", + "save(self, os.path.join(self.package_folder, 'option.conf'), str(self.info.options.get_safe('myoption')))", + "save(self, os.path.join(self.package_folder, 'otheroption.conf'), str(self.info.options.otheroption))")}) tc.run("create . -s=os=Linux -o=&:myoption=True -o=&:otheroption=True") layout = tc.created_layout() - assert "file.txt" in os.listdir(layout.install()) - assert tc.load(os.path.join(layout.install(), "os.conf")) == "Linux" - # This is problematic, it means that the mapping for install() and package_id would not be 1:1 and could be outdated - assert tc.load(os.path.join(layout.install(), "option.conf")) == "None" - assert tc.load(os.path.join(layout.install(), "otheroption.conf")) == "True" + assert "file.txt" in os.listdir(layout.localize()) + assert tc.load(os.path.join(layout.localize(), "os.conf")) == "Linux" + # This is problematic, it means that the mapping for localize() and package_id would not be 1:1 and could be outdated + assert tc.load(os.path.join(layout.localize(), "option.conf")) == "None" + assert tc.load(os.path.join(layout.localize(), "otheroption.conf")) == "True" class TestToolRequiresFlows: @@ -260,10 +259,10 @@ class TestConan(ConanFile): def package(self): save(self, os.path.join(self.package_folder, "bin", "executable.txt"), "Base") - def install(self): - self.output.info(f"Running install method in {self.install_folder}") - copy(self, "*", src=self.package_folder, dst=self.install_folder) - save(self, os.path.join(self.install_folder, "bin", "installed.txt"), "Installed file") + def localize(self): + self.output.info(f"Running localize method in {self.package_folder}") + copy(self, "*", src=self.immutable_package_folder, dst=self.package_folder) + save(self, os.path.join(self.package_folder, "bin", "localized.txt"), "localized file") def package_info(self): self.output.info(f"Running package_info method in {self.package_folder}") @@ -284,14 +283,14 @@ def build(self): self.output.info("Running build method") bindir = self.dependencies.build['dep'].cpp_info.bindir self.output.info(f"Dep bindir: {bindir}") - self.output.info(f"Is installed? {os.path.exists(os.path.join(bindir, 'installed.txt'))}") + self.output.info(f"Is localized? {os.path.exists(os.path.join(bindir, 'localized.txt'))}") """)}) tc.run("create dep --build-require") dep_layout = tc.created_layout() tc.run("create app") # This fails. cpp_info is using the original package folder to construct the final path - assert f"Dep bindir: {dep_layout.install()}" in tc.out - assert "app/1.0: Is installed? True" in tc.out + assert f"Dep bindir: {dep_layout.localize()}" in tc.out + assert "app/1.0: Is localized? True" in tc.out def test_test_package_uses_created_tool_which_modifies_pkgfolder(self): tc = TestClient(light=True) @@ -300,7 +299,7 @@ def test_test_package_uses_created_tool_which_modifies_pkgfolder(self): .with_package_type("application") .with_package("save(self, 'file.txt', 'Hello World!')") .with_package_info({"bindirs": ["bin"]}, {}) - .with_install("save(self, 'installed.txt', 'Installed file')"), + .with_localize("save(self, 'localized.txt', 'localized file')"), "test_package/conanfile.py": GenConanfile() .with_import("from conan.tools.files import save", "import os") @@ -310,7 +309,7 @@ def test_test_package_uses_created_tool_which_modifies_pkgfolder(self): "save(self, os.path.join(bindir, '__pycache__.pyc'), 'Test file')")}) tc.run("create . --build-require") app_layout = tc.created_layout() - assert f"Bindir: {os.path.join(app_layout.install(), 'bin')}" in tc.out + assert f"Bindir: {os.path.join(app_layout.localize(), 'bin')}" in tc.out tc.run(f"cache check-integrity {app_layout.reference}") assert "There are corrupted artifacts" not in tc.out @@ -324,37 +323,37 @@ def client(self): tc.run("export dep") return tc - def test_remote_upload_install_method(self, client): + def test_remote_upload_localize_method(self, client): client.run("create dep") created_pref = client.created_package_reference("dep/1.0") client.run("upload * -r=default -c") - # Only the package folder is uploaded, not the install folder + # Only the package folder is uploaded, not the localize folder uploaded_pref_path = client.servers["default"].test_server.server_store.package(created_pref) manifest_contents = load(os.path.join(uploaded_pref_path, "conanmanifest.txt")) assert "file.txt" in manifest_contents - assert "installed.txt" not in manifest_contents + assert "localized.txt" not in manifest_contents client.run("remove * -c") client.run(f"download {created_pref} -r=default") downloaded_pref_layout = client.get_latest_pkg_layout(created_pref) assert "file.txt" in os.listdir(downloaded_pref_layout.package()) - # Download is not an "usage" of the package, so no install() is yet executed - assert "installed.txt" not in os.listdir(downloaded_pref_layout.package()) - assert not os.path.exists(os.path.join(downloaded_pref_layout.install())) + # Download is not an "usage" of the package, so no localize() is yet executed + assert "localized.txt" not in os.listdir(downloaded_pref_layout.package()) + assert not os.path.exists(os.path.join(downloaded_pref_layout.localize())) client.run(f"cache path {created_pref}") package_folder = client.out.strip() assert package_folder == downloaded_pref_layout.package() assert package_folder.endswith("p") - # Now this install will run the install() method + # Now this localize will run the localize() method client.run("install --requires=dep/1.0") - assert f"Running install method in {downloaded_pref_layout.install()}" in client.out + assert f"Running localize method in {downloaded_pref_layout.localize()}" in client.out client.run("remove * -c") client.run("install --requires=dep/1.0 -r=default") - assert "dep/1.0: Calling install()" - assert f"Running install method in {downloaded_pref_layout.install()}" in client.out + assert "dep/1.0: Calling localize()" + assert f"Running localize method in {downloaded_pref_layout.localize()}" in client.out def test_upload_verify_integrity(self, client): client.run("create dep") From c615e52e098888c5f0c209ea2263033d4a0f86d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Abril=20Rinc=C3=B3n=20Blanco?= Date: Tue, 20 Aug 2024 18:24:23 +0200 Subject: [PATCH 45/49] Rename method to finalize() --- conan/api/subapi/cache.py | 4 +- .../internal/cache/conan_reference_layout.py | 6 +- conan/test/assets/genconanfile.py | 22 +-- conans/client/installer.py | 26 ++-- conans/model/layout.py | 10 +- .../conanfile/conanfile_errors_test.py | 1 + ...lize_method.py => test_finalize_method.py} | 130 +++++++++--------- 7 files changed, 100 insertions(+), 99 deletions(-) rename test/integration/conanfile/{test_localize_method.py => test_finalize_method.py} (78%) diff --git a/conan/api/subapi/cache.py b/conan/api/subapi/cache.py index 5a466650f79..83967243151 100644 --- a/conan/api/subapi/cache.py +++ b/conan/api/subapi/cache.py @@ -63,8 +63,8 @@ def package_path(self, pref: PkgReference): app = ConanApp(self.conan_api) pref = _resolve_latest_pref(app, pref) ref_layout = app.cache.pkg_layout(pref) - if os.path.exists(ref_layout.localize()): - return ref_layout.localize() + if os.path.exists(ref_layout.finalize()): + return ref_layout.finalize() return _check_folder_existence(pref, "package", ref_layout.package()) def check_integrity(self, package_list): diff --git a/conan/internal/cache/conan_reference_layout.py b/conan/internal/cache/conan_reference_layout.py index d8b2c95eab3..9bcd58160c7 100644 --- a/conan/internal/cache/conan_reference_layout.py +++ b/conan/internal/cache/conan_reference_layout.py @@ -10,7 +10,7 @@ SRC_FOLDER = "s" BUILD_FOLDER = "b" PACKAGES_FOLDER = "p" -LOCALIZE_FOLDER = "l" +FINALIZE_FOLDER = "f" EXPORT_FOLDER = "e" EXPORT_SRC_FOLDER = "es" DOWNLOAD_EXPORT_FOLDER = "d" @@ -100,8 +100,8 @@ def build(self): def package(self): return os.path.join(self._base_folder, PACKAGES_FOLDER) - def localize(self): - return os.path.join(self._base_folder, LOCALIZE_FOLDER) + def finalize(self): + return os.path.join(self._base_folder, FINALIZE_FOLDER) def download_package(self): return os.path.join(self._base_folder, DOWNLOAD_EXPORT_FOLDER) diff --git a/conan/test/assets/genconanfile.py b/conan/test/assets/genconanfile.py index 8949b8ad81b..717b12b272a 100644 --- a/conan/test/assets/genconanfile.py +++ b/conan/test/assets/genconanfile.py @@ -27,7 +27,7 @@ def __init__(self, name=None, version=None): self._provides = None self._deprecated = None self._package_lines = None - self._localize_lines = None + self._finalize_lines = None self._package_files = None self._package_files_env = None self._package_files_link = None @@ -215,10 +215,10 @@ def with_package(self, *lines): self._package_lines.append(line) return self - def with_localize(self, *lines): - self._localize_lines = self._localize_lines or [] + def with_finalize(self, *lines): + self._finalize_lines = self._finalize_lines or [] for line in lines: - self._localize_lines.append(line) + self._finalize_lines.append(line) return self def with_build_msg(self, msg): @@ -377,8 +377,8 @@ def _package_method(self): self._package_files_link) @property - def _localize_method(self): - return self._localize_lines + def _finalize_method(self): + return self._finalize_lines @property def _package_method_render(self): @@ -409,15 +409,15 @@ def package(self): """.format("\n".join(lines)) @property - def _localize_method_render(self): + def _finalize_method_render(self): lines = [] - if self._localize_lines: - lines.extend(" {}".format(line) for line in self._localize_lines) + if self._finalize_lines: + lines.extend(" {}".format(line) for line in self._finalize_lines) if not lines: return "" return """ - def localize(self): + def finalize(self): {} """.format("\n".join(lines)) @@ -506,7 +506,7 @@ def __repr__(self): "tool_requires", "test_requires", "requirements", "python_requires", "revision_mode", "settings", "options", "default_options", "build", "package_method", "package_info", "package_id_lines", "test_lines", - "localize_method" + "finalize_method" ): if member == "requirements": # FIXME: This seems exclusive, but we could mix them? diff --git a/conans/client/installer.py b/conans/client/installer.py index 83532c33e9f..bae10b537b6 100644 --- a/conans/client/installer.py +++ b/conans/client/installer.py @@ -338,7 +338,7 @@ def _handle_package(self, package, install_reference, handled_count, total_count # Call the info method conanfile.folders.set_base_package(pkg_folder) conanfile.folders.set_base_pkg_metadata(pkg_metadata) - self._call_localize_method(conanfile, package_layout.localize()) + self._call_finalize_method(conanfile, package_layout.finalize()) # Use package_folder which has been updated previously by install_method if necessary self._call_package_info(conanfile, conanfile.package_folder, is_editable=False) @@ -457,15 +457,15 @@ def _call_package_info(self, conanfile, package_folder, is_editable): conanfile.cpp_info.check_component_requires(conanfile) - def _call_localize_method(self, conanfile, localize_folder): - if hasattr(conanfile, "localize"): - conanfile.folders.set_localize_folder(localize_folder) - conanfile.folders.set_base_package(localize_folder) - if not os.path.exists(localize_folder): - mkdir(localize_folder) - conanfile.output.highlight("Calling localize()") - with conanfile_exception_formatter(conanfile, "localize_folder"): - with conanfile_remove_attr(conanfile, ['cpp_info', 'settings', 'options'], 'localize'): - conanfile.localize() - - conanfile.output.success(f"Localize folder {localize_folder}") + def _call_finalize_method(self, conanfile, finalize_folder): + if hasattr(conanfile, "finalize"): + conanfile.folders.set_finalize_folder(finalize_folder) + conanfile.folders.set_base_package(finalize_folder) + if not os.path.exists(finalize_folder): + mkdir(finalize_folder) + conanfile.output.highlight("Calling finalize()") + with conanfile_exception_formatter(conanfile, "finalize"): + with conanfile_remove_attr(conanfile, ['cpp_info', 'settings', 'options'], 'finalize'): + conanfile.finalize() + + conanfile.output.success(f"Finalized folder {finalize_folder}") diff --git a/conans/model/layout.py b/conans/model/layout.py index ad7b99d9df7..c1a0d6e4eec 100644 --- a/conans/model/layout.py +++ b/conans/model/layout.py @@ -50,7 +50,7 @@ def __init__(self): self.source = "" self.build = "" self.package = "" - self.localize = "" + self.finalize = "" self.generators = "" # Relative location of the project root, if the conanfile is not in that project root, but # in a subfolder: e.g: If the conanfile is in a subfolder then self.root = ".." @@ -144,13 +144,13 @@ def package_folder(self): """For the cache, the package folder is only the base""" return self._base_package - def set_localize_folder(self, folder): + def set_finalize_folder(self, folder): self._immutable_package_folder = self.package_folder - self.localize = folder + self.finalize = folder @property - def localize_folder(self): - return self.localize + def finalize_folder(self): + return self.finalize @property def immutable_package_folder(self): diff --git a/test/integration/conanfile/conanfile_errors_test.py b/test/integration/conanfile/conanfile_errors_test.py index 028c974ba91..abbe4f18262 100644 --- a/test/integration/conanfile/conanfile_errors_test.py +++ b/test/integration/conanfile/conanfile_errors_test.py @@ -3,6 +3,7 @@ import pytest +from conan.test.assets.genconanfile import GenConanfile from conan.test.utils.tools import TestClient diff --git a/test/integration/conanfile/test_localize_method.py b/test/integration/conanfile/test_finalize_method.py similarity index 78% rename from test/integration/conanfile/test_localize_method.py rename to test/integration/conanfile/test_finalize_method.py index 3ac99edfe32..0d1f02ce8bd 100644 --- a/test/integration/conanfile/test_localize_method.py +++ b/test/integration/conanfile/test_finalize_method.py @@ -21,10 +21,10 @@ def package(self): save(self, os.path.join(self.package_folder, "file.txt"), "Hello World!") save(self, os.path.join(self.package_folder, "file2.txt"), "Hello World 2!") - def localize(self): - self.output.info(f"Running localize method in {self.package_folder}") + def finalize(self): + self.output.info(f"Running finalize method in {self.package_folder}") copy(self, "file.txt", src=self.immutable_package_folder, dst=self.package_folder) - save(self, os.path.join(self.package_folder, "localized.txt"), "localized file") + save(self, os.path.join(self.package_folder, "finalized.txt"), "finalized file") def package_info(self): self.output.info(f"Running package_info method in {self.package_folder}") @@ -40,21 +40,21 @@ def client(self): tc.run("export dep") return tc - def test_basic_localize_method(self, client): + def test_basic_finalize_method(self, client): client.run("create dep") layout = client.created_layout() assert layout.package().endswith("p") assert f"Package folder {layout.package()}" in client.out - assert f"Running localize method in {layout.localize()}" in client.out - assert f"Running package_info method in {layout.localize()}" in client.out + assert f"Running finalize method in {layout.finalize()}" in client.out + assert f"Running package_info method in {layout.finalize()}" in client.out client.run("install --requires=dep/1.0") - assert f"Running package_info method in {layout.localize()}" in client.out + assert f"Running package_info method in {layout.finalize()}" in client.out # Only issue is that the PackageLayout has no idea about the redirected package folder # So we have to know to check for it in tests, but oh well - assert "localized.txt" in os.listdir(layout.localize()) - assert "localized.txt" not in os.listdir(layout.package()) + assert "finalized.txt" in os.listdir(layout.finalize()) + assert "finalized.txt" not in os.listdir(layout.package()) - def test_dependency_localize_method(self, client): + def test_dependency_finalize_method(self, client): client.save({"app/conanfile.py": textwrap.dedent(""" from conan import ConanFile class TestConan(ConanFile): @@ -70,16 +70,16 @@ def generate(self): dep_layout = client.created_layout() client.run("create app") assert f"Dep package folder: {dep_layout.package()}" not in client.out - assert f"Dep package folder: {dep_layout.localize()}" in client.out + assert f"Dep package folder: {dep_layout.finalize()}" in client.out def test_no_non_info_access(self): client = TestClient(light=True) client.save({"conanfile.py": GenConanfile("dep", "1.0") - .with_localize("self.output.info('settings.os: ' + self.settings.os)")}) + .with_finalize("self.output.info('settings.os: ' + self.settings.os)")}) client.run("create .", assert_error=True) - assert "'self.settings' access in 'localize()' method is forbidden" in client.out + assert "'self.settings' access in 'finalize()' method is forbidden" in client.out - def test_localize_moves_from_package(self): + def test_finalize_moves_from_package(self): client = TestClient(light=True) client.save({"conanfile.py": GenConanfile("dep", "1.0") .with_import("from conan.tools.files import save, rename", @@ -87,16 +87,16 @@ def test_localize_moves_from_package(self): .with_option("move", [True, False]) .with_package('save(self, os.path.join(self.package_folder, "file.txt"), "Hello World!")', "save(self, os.path.join(self.package_folder, 'file2.txt'), 'Hello World 2!')") - # This is NOT allowed, moving from package to localize is forbidden, only as test to ensure consistency - .with_localize("rename(self, os.path.join(self.immutable_package_folder, 'file.txt'), os.path.join(self.package_folder, 'file.txt')) if self.info.options.move else None")}) + # This is NOT allowed, moving from package to finalize is forbidden, only as test to ensure consistency + .with_finalize("rename(self, os.path.join(self.immutable_package_folder, 'file.txt'), os.path.join(self.package_folder, 'file.txt')) if self.info.options.move else None")}) client.run("create . -o=dep/*:move=True") dep_moved_layout = client.created_layout() - assert "file.txt" in os.listdir(dep_moved_layout.localize()) + assert "file.txt" in os.listdir(dep_moved_layout.finalize()) assert "file.txt" not in os.listdir(dep_moved_layout.package()) client.run("create . -o=dep/*:move=False") dep_kept_layout = client.created_layout() - assert "file.txt" not in os.listdir(dep_kept_layout.localize()) + assert "file.txt" not in os.listdir(dep_kept_layout.finalize()) assert "file.txt" in os.listdir(dep_kept_layout.package()) # Now we can check that the package_id is the same for both @@ -115,14 +115,14 @@ def test_cache_path_command(self, client): pref = client.created_package_reference("dep/1.0") client.run(f"cache path {pref}") assert dep_layout.package() not in client.out - assert dep_layout.localize() in client.out + assert dep_layout.finalize() in client.out def test_remove_deletes_correct_folders(self, client): client.run("create dep") dep_layout = client.created_layout() client.run("remove * -c") assert not os.path.exists(dep_layout.package()) - assert not os.path.exists(dep_layout.localize()) + assert not os.path.exists(dep_layout.finalize()) def test_save_restore_cache(self, client): # Not created in the cache, just exported, nothing breaks because there is not even a package there @@ -140,29 +140,29 @@ def test_save_restore_cache(self, client): assert saved_pkg_folder in dep_layout.package().replace("\\", "/") client.run("remove * -c") assert not os.path.exists(dep_layout.package()) - assert not os.path.exists(dep_layout.localize()) + assert not os.path.exists(dep_layout.finalize()) client.run("cache restore conan_cache_save.tgz") client.run(f"cache path {dep_layout.reference}") package_folder = client.out.strip() - # The localize() folder does not exist as restoring is not considered usage, so it never runs + # The finalize() folder does not exist as restoring is not considered usage, so it never runs # so this is just the immutable package_folder - assert "localized.txt" not in os.listdir(package_folder) + assert "finalized.txt" not in os.listdir(package_folder) - # But as soon as you call conan localize, localize() is called and so it's used, - # so package_folder will be the localize folder + # But as soon as you call conan finalize, finalize() is called and so it's used, + # so package_folder will be the finalize folder client.run("install --requires=dep/1.0") client.run(f"cache path {dep_layout.reference}") package_folder = client.out.strip() - assert "localized.txt" in os.listdir(package_folder) + assert "finalized.txt" in os.listdir(package_folder) def test_graph_info_output(self, client): client.run("create dep") dep_layout = client.created_layout() - client.run("install --requires=dep/1.0 -f=json", redirect_stdout="localize.json") - localize_output = json.loads(client.load("localize.json")) - assert localize_output["graph"]["nodes"]["1"]["package_folder"] == dep_layout.localize() - assert localize_output["graph"]["nodes"]["1"]["immutable_package_folder"] == dep_layout.package() + client.run("install --requires=dep/1.0 -f=json", redirect_stdout="finalize.json") + finalize_output = json.loads(client.load("finalize.json")) + assert finalize_output["graph"]["nodes"]["1"]["package_folder"] == dep_layout.finalize() + assert finalize_output["graph"]["nodes"]["1"]["immutable_package_folder"] == dep_layout.package() def test_create_pkglist_output(self, client): client.run("create dep -f=json", redirect_stdout="created.json") @@ -177,12 +177,12 @@ def test_vendorized_basic(self, client): .with_class_attribute("vendor=True") .with_requires("dep/1.0") .with_package("copy(self, 'file.txt', src=self.dependencies['dep'].package_folder, dst=self.package_folder)", - "copy(self, 'localized.txt', src=self.dependencies['dep'].package_folder, dst=self.package_folder)", + "copy(self, 'finalized.txt', src=self.dependencies['dep'].package_folder, dst=self.package_folder)", "copy(self, 'file2.txt', src=self.dependencies['dep'].immutable_package_folder, dst=self.package_folder)")}) client.run("create vendor") vendor_layout = client.created_layout() assert "file.txt" in os.listdir(vendor_layout.package()) - assert "localized.txt" in os.listdir(vendor_layout.package()) + assert "finalized.txt" in os.listdir(vendor_layout.package()) assert "file2.txt" in os.listdir(vendor_layout.package()) def test_check_integrity(self, client): @@ -190,8 +190,8 @@ def test_check_integrity(self, client): dep_layout = client.created_layout() client.run(f"cache check-integrity {dep_layout.reference}") assert "There are corrupted artifacts" not in client.out - # Even if we re-change the localize folder contents, it should still be fine - save(os.path.join(dep_layout.localize(), "localized.txt"), "Modified!") + # Even if we re-change the finalize folder contents, it should still be fine + save(os.path.join(dep_layout.finalize(), "finalized.txt"), "Modified!") client.run(f"cache check-integrity {dep_layout.reference}") assert "There are corrupted artifacts" not in client.out # But as soon as we change the package, it should still fail like a normal package would @@ -199,24 +199,24 @@ def test_check_integrity(self, client): client.run(f"cache check-integrity {dep_layout.reference}", assert_error=True) assert "There are corrupted artifacts" in client.out - @pytest.mark.parametrize("with_localize_method", [True, False]) - def test_access_immutable_from_consumer(self, client, with_localize_method): - if not with_localize_method: + @pytest.mark.parametrize("with_finalize_method", [True, False]) + def test_access_immutable_from_consumer(self, client, with_finalize_method): + if not with_finalize_method: client.save({"dep/conanfile.py": GenConanfile("dep", "1.0")}) client.save({"app/conanfile.py": GenConanfile("app", "1.0") .with_requires("dep/1.0") .with_package("dep = self.dependencies['dep/1.0']", "self.output.info(f'Immutable package: {dep.immutable_package_folder}')", # TODO: Think about if we want this interface - # "self.output.info(f'localize: {dep.localize_folder}')", + # "self.output.info(f'finalize: {dep.finalize_folder}')", "self.output.info(f'Package: {dep.package_folder}')")}) client.run("create dep") dep_layout = client.created_layout() client.run("create app") assert f"app/1.0: Immutable package: {dep_layout.package()}" in client.out - # assert f"app/1.0: localize: {dep_layout.localize()}" in client.out - if with_localize_method: - assert f"app/1.0: Package: {dep_layout.localize()}" in client.out + # assert f"app/1.0: finalize: {dep_layout.finalize()}" in client.out + if with_finalize_method: + assert f"app/1.0: Package: {dep_layout.finalize()}" in client.out else: assert f"app/1.0: Package: {dep_layout.package()}" in client.out @@ -231,17 +231,17 @@ def test_cache_modification_of_custom_conf_based_on_settings(self): .with_default_option("otheroption", False) .with_setting("os") .with_package_id("del self.info.options.myoption") - .with_localize("save(self, os.path.join(self.package_folder, 'file.txt'), 'Hello World!')", + .with_finalize("save(self, os.path.join(self.package_folder, 'file.txt'), 'Hello World!')", "save(self, os.path.join(self.package_folder, 'os.conf'), str(self.info.settings.os))", "save(self, os.path.join(self.package_folder, 'option.conf'), str(self.info.options.get_safe('myoption')))", "save(self, os.path.join(self.package_folder, 'otheroption.conf'), str(self.info.options.otheroption))")}) tc.run("create . -s=os=Linux -o=&:myoption=True -o=&:otheroption=True") layout = tc.created_layout() - assert "file.txt" in os.listdir(layout.localize()) - assert tc.load(os.path.join(layout.localize(), "os.conf")) == "Linux" - # This is problematic, it means that the mapping for localize() and package_id would not be 1:1 and could be outdated - assert tc.load(os.path.join(layout.localize(), "option.conf")) == "None" - assert tc.load(os.path.join(layout.localize(), "otheroption.conf")) == "True" + assert "file.txt" in os.listdir(layout.finalize()) + assert tc.load(os.path.join(layout.finalize(), "os.conf")) == "Linux" + # This is problematic, it means that the mapping for finalize() and package_id would not be 1:1 and could be outdated + assert tc.load(os.path.join(layout.finalize(), "option.conf")) == "None" + assert tc.load(os.path.join(layout.finalize(), "otheroption.conf")) == "True" class TestToolRequiresFlows: @@ -259,10 +259,10 @@ class TestConan(ConanFile): def package(self): save(self, os.path.join(self.package_folder, "bin", "executable.txt"), "Base") - def localize(self): - self.output.info(f"Running localize method in {self.package_folder}") + def finalize(self): + self.output.info(f"Running finalize method in {self.package_folder}") copy(self, "*", src=self.immutable_package_folder, dst=self.package_folder) - save(self, os.path.join(self.package_folder, "bin", "localized.txt"), "localized file") + save(self, os.path.join(self.package_folder, "bin", "finalized.txt"), "finalized file") def package_info(self): self.output.info(f"Running package_info method in {self.package_folder}") @@ -283,14 +283,14 @@ def build(self): self.output.info("Running build method") bindir = self.dependencies.build['dep'].cpp_info.bindir self.output.info(f"Dep bindir: {bindir}") - self.output.info(f"Is localized? {os.path.exists(os.path.join(bindir, 'localized.txt'))}") + self.output.info(f"Is finalized? {os.path.exists(os.path.join(bindir, 'finalized.txt'))}") """)}) tc.run("create dep --build-require") dep_layout = tc.created_layout() tc.run("create app") # This fails. cpp_info is using the original package folder to construct the final path - assert f"Dep bindir: {dep_layout.localize()}" in tc.out - assert "app/1.0: Is localized? True" in tc.out + assert f"Dep bindir: {dep_layout.finalize()}" in tc.out + assert "app/1.0: Is finalized? True" in tc.out def test_test_package_uses_created_tool_which_modifies_pkgfolder(self): tc = TestClient(light=True) @@ -299,7 +299,7 @@ def test_test_package_uses_created_tool_which_modifies_pkgfolder(self): .with_package_type("application") .with_package("save(self, 'file.txt', 'Hello World!')") .with_package_info({"bindirs": ["bin"]}, {}) - .with_localize("save(self, 'localized.txt', 'localized file')"), + .with_finalize("save(self, 'finalized.txt', 'finalized file')"), "test_package/conanfile.py": GenConanfile() .with_import("from conan.tools.files import save", "import os") @@ -309,7 +309,7 @@ def test_test_package_uses_created_tool_which_modifies_pkgfolder(self): "save(self, os.path.join(bindir, '__pycache__.pyc'), 'Test file')")}) tc.run("create . --build-require") app_layout = tc.created_layout() - assert f"Bindir: {os.path.join(app_layout.localize(), 'bin')}" in tc.out + assert f"Bindir: {os.path.join(app_layout.finalize(), 'bin')}" in tc.out tc.run(f"cache check-integrity {app_layout.reference}") assert "There are corrupted artifacts" not in tc.out @@ -323,37 +323,37 @@ def client(self): tc.run("export dep") return tc - def test_remote_upload_localize_method(self, client): + def test_remote_upload_finalize_method(self, client): client.run("create dep") created_pref = client.created_package_reference("dep/1.0") client.run("upload * -r=default -c") - # Only the package folder is uploaded, not the localize folder + # Only the package folder is uploaded, not the finalize folder uploaded_pref_path = client.servers["default"].test_server.server_store.package(created_pref) manifest_contents = load(os.path.join(uploaded_pref_path, "conanmanifest.txt")) assert "file.txt" in manifest_contents - assert "localized.txt" not in manifest_contents + assert "finalized.txt" not in manifest_contents client.run("remove * -c") client.run(f"download {created_pref} -r=default") downloaded_pref_layout = client.get_latest_pkg_layout(created_pref) assert "file.txt" in os.listdir(downloaded_pref_layout.package()) - # Download is not an "usage" of the package, so no localize() is yet executed - assert "localized.txt" not in os.listdir(downloaded_pref_layout.package()) - assert not os.path.exists(os.path.join(downloaded_pref_layout.localize())) + # Download is not an "usage" of the package, so no finalize() is yet executed + assert "finalized.txt" not in os.listdir(downloaded_pref_layout.package()) + assert not os.path.exists(os.path.join(downloaded_pref_layout.finalize())) client.run(f"cache path {created_pref}") package_folder = client.out.strip() assert package_folder == downloaded_pref_layout.package() assert package_folder.endswith("p") - # Now this localize will run the localize() method + # Now this finalize will run the finalize() method client.run("install --requires=dep/1.0") - assert f"Running localize method in {downloaded_pref_layout.localize()}" in client.out + assert f"Running finalize method in {downloaded_pref_layout.finalize()}" in client.out client.run("remove * -c") client.run("install --requires=dep/1.0 -r=default") - assert "dep/1.0: Calling localize()" - assert f"Running localize method in {downloaded_pref_layout.localize()}" in client.out + assert "dep/1.0: Calling finalize()" + assert f"Running finalize method in {downloaded_pref_layout.finalize()}" in client.out def test_upload_verify_integrity(self, client): client.run("create dep") From fb2f4d1570ce2633a63dfba64af9af41cffaad5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Abril=20Rinc=C3=B3n=20Blanco?= Date: Tue, 20 Aug 2024 18:29:25 +0200 Subject: [PATCH 46/49] Cleanup code --- conans/client/installer.py | 1 - conans/model/layout.py | 5 +---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/conans/client/installer.py b/conans/client/installer.py index bae10b537b6..b2937dda895 100644 --- a/conans/client/installer.py +++ b/conans/client/installer.py @@ -460,7 +460,6 @@ def _call_package_info(self, conanfile, package_folder, is_editable): def _call_finalize_method(self, conanfile, finalize_folder): if hasattr(conanfile, "finalize"): conanfile.folders.set_finalize_folder(finalize_folder) - conanfile.folders.set_base_package(finalize_folder) if not os.path.exists(finalize_folder): mkdir(finalize_folder) conanfile.output.highlight("Calling finalize()") diff --git a/conans/model/layout.py b/conans/model/layout.py index c1a0d6e4eec..da0b4352f89 100644 --- a/conans/model/layout.py +++ b/conans/model/layout.py @@ -147,10 +147,7 @@ def package_folder(self): def set_finalize_folder(self, folder): self._immutable_package_folder = self.package_folder self.finalize = folder - - @property - def finalize_folder(self): - return self.finalize + self.set_base_package(folder) @property def immutable_package_folder(self): From b1b4d593cfa220ff97b83398890f001b7a89e254 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Abril=20Rinc=C3=B3n=20Blanco?= Date: Tue, 20 Aug 2024 18:30:42 +0200 Subject: [PATCH 47/49] Discard changes to test/integration/conanfile/conanfile_errors_test.py --- test/integration/conanfile/conanfile_errors_test.py | 1 - 1 file changed, 1 deletion(-) diff --git a/test/integration/conanfile/conanfile_errors_test.py b/test/integration/conanfile/conanfile_errors_test.py index abbe4f18262..028c974ba91 100644 --- a/test/integration/conanfile/conanfile_errors_test.py +++ b/test/integration/conanfile/conanfile_errors_test.py @@ -3,7 +3,6 @@ import pytest -from conan.test.assets.genconanfile import GenConanfile from conan.test.utils.tools import TestClient From a134f6081ce4981aa5cd7b694636703f1f69e5d2 Mon Sep 17 00:00:00 2001 From: James Date: Tue, 20 Aug 2024 18:57:51 +0200 Subject: [PATCH 48/49] Update conans/model/layout.py --- conans/model/layout.py | 1 - 1 file changed, 1 deletion(-) diff --git a/conans/model/layout.py b/conans/model/layout.py index da0b4352f89..946a1b7ffcf 100644 --- a/conans/model/layout.py +++ b/conans/model/layout.py @@ -146,7 +146,6 @@ def package_folder(self): def set_finalize_folder(self, folder): self._immutable_package_folder = self.package_folder - self.finalize = folder self.set_base_package(folder) @property From 0fd1196ac219e3cb4435ce538d77af1b9b69eec8 Mon Sep 17 00:00:00 2001 From: James Date: Tue, 20 Aug 2024 18:58:01 +0200 Subject: [PATCH 49/49] Update conans/model/layout.py --- conans/model/layout.py | 1 - 1 file changed, 1 deletion(-) diff --git a/conans/model/layout.py b/conans/model/layout.py index 946a1b7ffcf..de453f917fe 100644 --- a/conans/model/layout.py +++ b/conans/model/layout.py @@ -50,7 +50,6 @@ def __init__(self): self.source = "" self.build = "" self.package = "" - self.finalize = "" self.generators = "" # Relative location of the project root, if the conanfile is not in that project root, but # in a subfolder: e.g: If the conanfile is in a subfolder then self.root = ".."