diff --git a/conan/tools/cmake/presets.py b/conan/tools/cmake/presets.py index 81461199df5..ca5bf0d3060 100644 --- a/conan/tools/cmake/presets.py +++ b/conan/tools/cmake/presets.py @@ -95,18 +95,15 @@ def write_cmake_presets(conanfile, toolchain_file, generator): # We append the new configuration making sure that we don't overwrite it data = json.loads(load(preset_path)) if multiconfig: - build_presets = data["buildPresets"] - build_preset_name = _build_preset_name(conanfile) - already_exist = any([b["configuration"] - for b in build_presets if b == build_preset_name]) + new_build_preset_name = _build_preset_name(conanfile) + already_exist = any([b["name"] for b in data["buildPresets"] + if b["name"] == new_build_preset_name]) if not already_exist: data["buildPresets"].append(_add_build_preset(conanfile, multiconfig)) else: - configure_presets = data["configurePresets"] - configure_preset_name = _configure_preset_name(conanfile, multiconfig) - already_exist = any([c["name"] - for c in configure_presets - if c["name"] == configure_preset_name]) + new_configure_preset_name = _configure_preset_name(conanfile, multiconfig) + already_exist = any([c["name"] for c in data["configurePresets"] + if c["name"] == new_configure_preset_name]) if not already_exist: conf_preset = _add_configure_preset(conanfile, generator, cache_variables, toolchain_file, multiconfig) @@ -126,6 +123,8 @@ def write_cmake_presets(conanfile, toolchain_file, generator): data = {"version": 4, "include": [preset_path]} else: data = json.loads(load(user_presets_path)) + # Clear the folders that have been deleted + data["include"] = [i for i in data["include"] if os.path.exists(i)] if preset_path not in data["include"]: data["include"].append(preset_path) diff --git a/conans/test/functional/toolchains/cmake/test_cmake_toolchain.py b/conans/test/functional/toolchains/cmake/test_cmake_toolchain.py index 8b1311a599e..4f6e67e30a9 100644 --- a/conans/test/functional/toolchains/cmake/test_cmake_toolchain.py +++ b/conans/test/functional/toolchains/cmake/test_cmake_toolchain.py @@ -12,7 +12,7 @@ from conans.test.assets.cmake import gen_cmakelists from conans.test.assets.genconanfile import GenConanfile from conans.test.utils.tools import TestClient, TurboTestClient -from conans.util.files import save, load +from conans.util.files import save, load, rmdir @pytest.mark.skipif(platform.system() != "Windows", reason="Only for windows") @@ -622,6 +622,56 @@ def test_cmake_presets_multiple_settings_single_config(): assert "__cplusplus2020" in client.out +@pytest.mark.parametrize("multiconfig", [True, False]) +def test_cmake_presets_duplicated_install(multiconfig): + # https://github.com/conan-io/conan/issues/11409 + """Only failed when using a multiconfig generator""" + client = TestClient(path_with_spaces=False) + client.run("new hello/0.1 --template=cmake_exe") + settings = '-s compiler=gcc -s compiler.version=5 -s compiler.libcxx=libstdc++11 ' \ + '-c tools.cmake.cmake_layout:build_folder_vars=' \ + '\'["settings.compiler", "settings.compiler.version"]\' ' + if multiconfig: + settings += '-c tools.cmake.cmaketoolchain:generator="Multi-Config"' + client.run("install . {}".format(settings)) + client.run("install . {}".format(settings)) + presets_path = os.path.join(client.current_folder, "build", "gcc-5", "generators", + "CMakePresets.json") + assert os.path.exists(presets_path) + contents = json.loads(load(presets_path)) + assert len(contents["buildPresets"]) == 1 + + +def test_remove_missing_presets(): + # https://github.com/conan-io/conan/issues/11413 + client = TestClient(path_with_spaces=False) + client.run("new hello/0.1 --template=cmake_exe") + settings = '-s compiler=gcc -s compiler.version=5 -s compiler.libcxx=libstdc++11 ' \ + '-c tools.cmake.cmake_layout:build_folder_vars=' \ + '\'["settings.compiler", "settings.compiler.version"]\' ' + client.run("install . {}".format(settings)) + client.run("install . {} -s compiler.version=6".format(settings)) + + presets_path_5 = os.path.join(client.current_folder, "build", "gcc-5") + assert os.path.exists(presets_path_5) + + presets_path_6 = os.path.join(client.current_folder, "build", "gcc-6") + assert os.path.exists(presets_path_6) + + rmdir(presets_path_5) + + # If we generate another configuration, the missing one (removed) for gcc-5 is not included + client.run("install . {} -s compiler.version=11".format(settings)) + + user_presets_path = os.path.join(client.current_folder, "CMakeUserPresets.json") + assert os.path.exists(user_presets_path) + + contents = json.loads(load(user_presets_path)) + assert len(contents["include"]) == 2 + assert "gcc-6" in contents["include"][0] + assert "gcc-11" in contents["include"][1] + + @pytest.mark.tool_cmake(version="3.23") def test_cmake_presets_options_single_config(): client = TestClient(path_with_spaces=False)