From 113e04821561ad82e7b0eb7c70b0dd2ebc62a102 Mon Sep 17 00:00:00 2001 From: memsharded Date: Tue, 11 Mar 2025 23:55:00 +0100 Subject: [PATCH 1/2] improve relative paths in generators --- conan/internal/api/install/generators.py | 22 +++++----- .../functional/command/test_install_deploy.py | 40 ++++++++++++++++++- 2 files changed, 51 insertions(+), 11 deletions(-) diff --git a/conan/internal/api/install/generators.py b/conan/internal/api/install/generators.py index fe553891f79..db0afd87049 100644 --- a/conan/internal/api/install/generators.py +++ b/conan/internal/api/install/generators.py @@ -243,14 +243,18 @@ def relativize_paths(conanfile, placeholder): def relativize_path(path, conanfile, placeholder): - abs_base_path, new_path = relativize_paths(conanfile, placeholder) - if abs_base_path is None: + """ + relative path from the "generators_folder" to "path", asuming the root file, like + conan_toolchain.cmake will be directly in the "generators_folder" + """ + base_common_folder = conanfile.folders._base_generators # noqa + if not base_common_folder or not os.path.isabs(base_common_folder): return path - if path.startswith(abs_base_path): - path = path.replace(abs_base_path, new_path, 1) - else: - abs_base_path = abs_base_path.replace("\\", "/") - new_path = new_path.replace("\\", "/") - if path.startswith(abs_base_path): - path = path.replace(abs_base_path, new_path, 1) + try: + common_path = os.path.commonpath([path, conanfile.generators_folder, base_common_folder]) + if common_path == base_common_folder: + rel_path = os.path.relpath(path, conanfile.generators_folder) + return os.path.join(placeholder, rel_path).replace("\\", "/") + except ValueError: # In case the unit in Windows is different, path cannot be made relative + pass return path diff --git a/test/functional/command/test_install_deploy.py b/test/functional/command/test_install_deploy.py index faaeb98cf7b..0a824b06faf 100644 --- a/test/functional/command/test_install_deploy.py +++ b/test/functional/command/test_install_deploy.py @@ -511,9 +511,10 @@ def package_info(self): expected = sorted(["pkga.so", "pkgb.so", "pkga.dll"]) assert sorted(os.listdir(os.path.join(c.current_folder, "myruntime"))) == expected + @pytest.mark.parametrize("symlink, expected", [(True, ["libfoo.so.0.1.0", "libfoo.so.0", "libfoo.so"]), - (False, ["libfoo.so.0.1.0",])]) + (False, ["libfoo.so.0.1.0"])]) def test_runtime_deploy_symlinks(symlink, expected): """ The deployer runtime_deploy should preserve symlinks when deploying shared libraries """ @@ -531,7 +532,7 @@ def package(self): os.symlink(src="libfoo.so.0", dst="libfoo.so") """) c.save({"foo/conanfile.py": conanfile, - "foo/lib/libfoo.so.0.1.0": "",}) + "foo/lib/libfoo.so.0.1.0": ""}) c.run("export-pkg foo/ --name=foo --version=0.1.0") c.run(f"install --requires=foo/0.1.0 --deployer=runtime_deploy --deployer-folder=output -c:a tools.deployer:symlinks={symlink}") @@ -565,3 +566,38 @@ def test_deployer_errors(): c.run("install . --deployer=mydeploy2.py", assert_error=True) # The error message says conanfile, not a big deal still path to file is shown assert "ERROR: Unable to load conanfile" in c.out + + +def test_deploy_relative_paths(): + c = TestClient() + consumer = textwrap.dedent(""" + import os + from conan import ConanFile + class Consumer(ConanFile): + requires = "pkg/0.1" + settings = "build_type" + os = "build_type" + generators = "CMakeDeps" + def layout(self): + self.folders.build = os.path.join("some/sub/folders") + self.folders.generators = os.path.join(self.folders.build, "generators") + """) + deploy = textwrap.dedent(""" + import os, shutil + def deploy(graph, output_folder): + conanfile = graph.root.conanfile + output_folder = os.path.join(conanfile.build_folder, "installed") + for dep in conanfile.dependencies.values(): + new_folder = os.path.join(output_folder, dep.ref.name) + shutil.copytree(dep.package_folder, new_folder, symlinks=True) + dep.set_deploy_folder(new_folder) + """) + c.save({"pkg/conanfile.py": GenConanfile("pkg", "0.1"), + "consumer/conanfile.py": consumer, + "mydeploy.py": deploy}) + c.run("create pkg") + + # If we don't change to another folder, the full_deploy will be recursive and fail + c.run("install consumer --build=missing --deployer=mydeploy.py") + data = c.load("consumer/some/sub/folders/generators/pkg-release-data.cmake") + assert 'set(pkg_PACKAGE_FOLDER_RELEASE "${CMAKE_CURRENT_LIST_DIR}/../installed/pkg")' in data From 3c55f7c41ca34fcba552b4ef94bd6200c3ee0318 Mon Sep 17 00:00:00 2001 From: memsharded Date: Thu, 13 Mar 2025 20:07:44 +0100 Subject: [PATCH 2/2] fix msbuild test --- conan/internal/api/install/generators.py | 5 +++-- conan/tools/microsoft/msbuilddeps.py | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/conan/internal/api/install/generators.py b/conan/internal/api/install/generators.py index db0afd87049..946133a7d4b 100644 --- a/conan/internal/api/install/generators.py +++ b/conan/internal/api/install/generators.py @@ -242,7 +242,7 @@ def relativize_paths(conanfile, placeholder): return abs_base_path, new_path -def relativize_path(path, conanfile, placeholder): +def relativize_path(path, conanfile, placeholder, normalize=True): """ relative path from the "generators_folder" to "path", asuming the root file, like conan_toolchain.cmake will be directly in the "generators_folder" @@ -254,7 +254,8 @@ def relativize_path(path, conanfile, placeholder): common_path = os.path.commonpath([path, conanfile.generators_folder, base_common_folder]) if common_path == base_common_folder: rel_path = os.path.relpath(path, conanfile.generators_folder) - return os.path.join(placeholder, rel_path).replace("\\", "/") + new_path = os.path.join(placeholder, rel_path) + return new_path.replace("\\", "/") if normalize else new_path except ValueError: # In case the unit in Windows is different, path cannot be made relative pass return path diff --git a/conan/tools/microsoft/msbuilddeps.py b/conan/tools/microsoft/msbuilddeps.py index 58b0d87ddd4..c3b359b8d07 100644 --- a/conan/tools/microsoft/msbuilddeps.py +++ b/conan/tools/microsoft/msbuilddeps.py @@ -185,7 +185,7 @@ def join_paths(paths): root_folder = escape_path(root_folder) # Make the root_folder relative to the generated conan_vars_xxx.props file relative_root_folder = relativize_path(root_folder, self._conanfile, - "$(MSBuildThisFileDirectory)") + "$(MSBuildThisFileDirectory)", normalize=False) bin_dirs = join_paths(cpp_info.bindirs) res_dirs = join_paths(cpp_info.resdirs)