Repository: conan-io/conan
Pull request #16346 (2024-05-27 22:25:08)

fix cppstd compat
Changelog: Bugfix: Allow default ``compatibility.py`` plugin to fallback from MSVC ``compiler.version=194->193`` and to other ``cppstd`` values.
Docs: Omit



Patch:
diff --git a/conan/tools/cmake/toolchain/blocks.py b/conan/tools/cmake/toolchain/blocks.py
index adb338e5b..5e0c8316c 100644
--- a/conan/tools/cmake/toolchain/blocks.py
+++ b/conan/tools/cmake/toolchain/blocks.py
@@ -810,9 +810,10 @@ class GenericSystemBlock(Block):
             toolset = settings.get_safe("compiler.toolset")
             if toolset is None:
                 compiler_version = str(settings.compiler.version)
-                compiler_update = str(settings.compiler.update)
+                msvc_update = conanfile.conf.get("tools.microsoft:msvc_update")
+                compiler_update = msvc_update or settings.get_safe("compiler.update")
                 toolset = msvc_version_to_toolset_version(compiler_version)
-                if compiler_update != "None":  # It is full one(19.28), not generic 19.2X
+                if compiler_update is not None:  # It is full one(19.28), not generic 19.2X
                     # The equivalent of compiler 19.26 is toolset 14.26
                     toolset += ",version=14.{}{}".format(compiler_version[-1], compiler_update)
         elif compiler == "clang":
diff --git a/conan/tools/microsoft/visual.py b/conan/tools/microsoft/visual.py
index 9313c4222..844031489 100644
--- a/conan/tools/microsoft/visual.py
+++ b/conan/tools/microsoft/visual.py
@@ -33,7 +33,8 @@ def check_min_vs(conanfile, version, raise_invalid=True):
                             "11": "170"}.get(compiler_version)
     elif compiler == "msvc":
         compiler_version = conanfile.settings.get_safe("compiler.version")
-        compiler_update = conanfile.settings.get_safe("compiler.update")
+        msvc_update = conanfile.conf.get("tools.microsoft:msvc_update")
+        compiler_update = msvc_update or conanfile.settings.get_safe("compiler.update")
         if compiler_version and compiler_update is not None:
             compiler_version += ".{}".format(compiler_update)
 
diff --git a/conans/client/graph/compatibility.py b/conans/client/graph/compatibility.py
index 967ddc90e..1d67e7cf5 100644
--- a/conans/client/graph/compatibility.py
+++ b/conans/client/graph/compatibility.py
@@ -41,8 +41,8 @@ def cppstd_compat(conanfile):
         cppstd_possible_values = supported_cppstd(conanfile)
         if cppstd_possible_values is None:
             conanfile.output.warning(f'No cppstd compatibility defined for compiler "{compiler}"')
-        else:
-            factors.append([{"compiler.cppstd": v} for v in cppstd_possible_values if v != cppstd])
+        else: # The current cppst must be included in case there is other factor
+            factors.append([{"compiler.cppstd": v} for v in cppstd_possible_values])
 
     if compiler == "msvc":
         msvc_fallback = {"194": "193"}.get(compiler_version)
diff --git a/conans/client/rest_client_local_recipe_index.py b/conans/client/rest_client_local_recipe_index.py
index 5aa92690f..f86ecfd36 100644
--- a/conans/client/rest_client_local_recipe_index.py
+++ b/conans/client/rest_client_local_recipe_index.py
@@ -191,6 +191,9 @@ class _LocalRecipesIndexLayout:
         ret = []
         excluded = set()
         for r in recipes:
+            if r.startswith("."):
+                # Skip hidden folders, no recipes should start with a dot
+                continue
             if not fnmatch(r, name_pattern):
                 continue
             folder = self._get_base_folder(r)
diff --git a/conans/model/conf.py b/conans/model/conf.py
index ef758d342..7809f4d9d 100644
--- a/conans/model/conf.py
+++ b/conans/model/conf.py
@@ -93,6 +93,7 @@ BUILT_IN_CONFS = {
     "tools.meson.mesontoolchain:backend": "Any Meson backend: ninja, vs, vs2010, vs2012, vs2013, vs2015, vs2017, vs2019, xcode",
     "tools.meson.mesontoolchain:extra_machine_files": "List of paths for any additional native/cross file references to be appended to the existing Conan ones",
     "tools.microsoft:winsdk_version": "Use this winsdk_version in vcvars",
+    "tools.microsoft:msvc_update": "Force the specific update irrespective of compiler.update (CMakeToolchain and VCVars)",
     "tools.microsoft.msbuild:vs_version": "Defines the IDE version (15, 16, 17) when using the msvc compiler. Necessary if compiler.version specifies a toolset that is not the IDE default",
     "tools.microsoft.msbuild:max_cpu_count": "Argument for the /m when running msvc to build parallel projects",
     "tools.microsoft.msbuild:installation_path": "VS install path, to avoid auto-detect via vswhere, like C:/Program Files (x86)/Microsoft Visual Studio/2019/Community. Use empty string to disable",


Test patch:
diff --git a/conans/test/integration/package_id/test_cache_compatibles.py b/conans/test/integration/package_id/test_cache_compatibles.py
index 702b11e6d..1e2358952 100644
--- a/conans/test/integration/package_id/test_cache_compatibles.py
+++ b/conans/test/integration/package_id/test_cache_compatibles.py
@@ -398,6 +398,13 @@ class TestDefaultCompat:
         assert "mylib/1.0: Main binary package 'e340edd75790e7156c595edebd3d98b10a2e091e' missing."\
                f"Using compatible package '{package_id1}'"
 
+        c.run("install --requires=mylib/1.0@ -s os=Windows -s arch=x86_64 -s build_type=Release "
+              "-s compiler=msvc "
+              "-s compiler.version=194 -s compiler.cppstd=17 "
+              "-s compiler.runtime=dynamic -pr:b=profile_build")
+        assert "mylib/1.0: Main binary package 'e340edd75790e7156c595edebd3d98b10a2e091e' missing." \
+               f"Using compatible package '{package_id1}'"
+
 
 class TestErrorsCompatibility:
     """ when the plugin fails, we want a clear message and a helpful trace
diff --git a/conans/test/integration/remote/test_local_recipes_index.py b/conans/test/integration/remote/test_local_recipes_index.py
index b53465f70..3b5fe1bf1 100644
--- a/conans/test/integration/remote/test_local_recipes_index.py
+++ b/conans/test/integration/remote/test_local_recipes_index.py
@@ -59,12 +59,15 @@ def c3i_folder():
             """))
     save(os.path.join(recipes_folder, "libcurl", "all", "conanfile.py"),
          str(GenConanfile().with_require("openssl/2.0")))
+
+    save(os.path.join(recipes_folder, ".DS_Store", "foo"), "")
+
     return folder
 
 
 class TestSearchList:
     def test_basic_search(self, c3i_folder):
-        client = TestClient()
+        client = TestClient(light=True)
         client.run(f"remote add local '{c3i_folder}' --type=local-recipes-index")  # Keep --type test
         assert "WARN" not in client.out  # Make sure it does not complain about url
         client.run("search *")
@@ -82,7 +85,7 @@ class TestSearchList:
             """) in client.out
 
     def test_list_refs(self, c3i_folder):
-        client = TestClient()
+        client = TestClient(light=True)
         client.run(f"remote add local '{c3i_folder}'")
         client.run("list *#* -r=local --format=json")
         listjson = json.loads(client.stdout)
@@ -100,7 +103,7 @@ class TestSearchList:
         assert len(revs) == 1 and "6f5c31bb1219e9393743d1fbf2ee1b52" in revs
 
     def test_list_rrevs(self, c3i_folder):
-        client = TestClient()
+        client = TestClient(light=True)
         client.run(f"remote add local '{c3i_folder}'")
         client.run("list libcurl/1.0#* -r=local --format=json")
         listjson = json.loads(client.stdout)
@@ -108,7 +111,7 @@ class TestSearchList:
         assert len(revs) == 1 and "e468388f0e4e098d5b62ad68979aebd5" in revs
 
     def test_list_binaries(self, c3i_folder):
-        client = TestClient()
+        client = TestClient(light=True)
         client.run(f"remote add local '{c3i_folder}'")
         client.run("list libcurl/1.0:* -r=local --format=json")
         listjson = json.loads(client.stdout)
@@ -118,7 +121,7 @@ class TestSearchList:
 
 class TestInstall:
     def test_install(self, c3i_folder):
-        c = TestClient()
+        c = TestClient(light=True)
         c.run(f"remote add local '{c3i_folder}'")
         c.run("install --requires=libcurl/1.0 --build missing")
         assert "zlib/1.2.11: CONANDATA: {}" in c.out
@@ -178,7 +181,7 @@ class TestInstall:
                    {"boost/config.yml": boost_config,
                     "boost/all/conanfile.py": boost,
                     "boost/all/dependencies/myfile.json": deps_json})
-        c = TestClient()
+        c = TestClient(light=True)
         c.run(f"remote add local '{folder}'")
         c.run("install --requires=boost/[*] --build missing")
         assert 'boost/1.0: {"potato": 42}' in c.out
@@ -204,7 +207,7 @@ class TestInstall:
                    {"pkg/config.yml": config,
                     "pkg/all/conanfile.py": str(GenConanfile("pkg")),
                     "pkg/all/conandata.yml": conandata})
-        c = TestClient()
+        c = TestClient(light=True)
         c.run(f"remote add local '{folder}'")
         c.run("install --requires=pkg/1.0 --build missing -vvv")
         assert "pkg/1.0#86b609916bbdfe63c579f034ad0edfe7" in c.out
@@ -264,7 +267,7 @@ class TestInstall:
                     "zlib/all/conandata.yml": conandata_yml,
                     "zlib/all/patches/patch1": patch,
                     "zlib/all/main.cpp": "\n"})
-        client = TestClient()
+        client = TestClient(light=True)
         client.run(f"remote add local '{folder}'")
         client.run("install --requires=zlib/0.1 --build=missing -vv")
         assert "zlib/0.1: Copied 1 file: patch1" in client.out
@@ -276,7 +279,7 @@ class TestRestrictedOperations:
         folder = temp_folder()
         c3i_folder = os.path.join(folder, "recipes")
         mkdir(c3i_folder)
-        c = TestClient()
+        c = TestClient(light=True)
         c.run(f"remote add local '{c3i_folder}'")
         c.save({"conanfile.py": GenConanfile("pkg", "0.1")})
         c.run("create .")
@@ -300,7 +303,7 @@ class TestErrorsUx:
         save_files(recipes_folder,
                    {"zlib/config.yml": zlib_config,
                     "zlib/all/conanfile.py": zlib})
-        c = TestClient()
+        c = TestClient(light=True)
         c.run(f"remote add local '{folder}'")
         c.run("install --requires=zlib/[*] --build missing", assert_error=True)
         assert "NameError: name 'ConanFile' is not defined" in c.out
diff --git a/conans/test/unittests/tools/cmake/test_cmaketoolchain.py b/conans/test/unittests/tools/cmake/test_cmaketoolchain.py
index 8bba79509..3d66adada 100644
--- a/conans/test/unittests/tools/cmake/test_cmaketoolchain.py
+++ b/conans/test/unittests/tools/cmake/test_cmaketoolchain.py
@@ -201,7 +201,7 @@ def conanfile_msvc():
     c.settings.build_type = "Release"
     c.settings.arch = "x86"
     c.settings.compiler = "msvc"
-    c.settings.compiler.version = "193"
+    c.settings.compiler.version = "194"
     c.settings.compiler.cppstd = "20"
     c.settings.os = "Windows"
     c.settings_build = c.settings
@@ -221,11 +221,27 @@ def test_toolset(conanfile_msvc):
 
 
 def test_toolset_update_version(conanfile_msvc):
+    conanfile_msvc.settings.compiler.version = "193"
     conanfile_msvc.settings.compiler.update = "8"
     toolchain = CMakeToolchain(conanfile_msvc)
     assert 'set(CMAKE_GENERATOR_TOOLSET "v143,version=14.38" CACHE STRING "" FORCE)' in toolchain.content
 
 
+def test_toolset_update_version_conf(conanfile_msvc):
+    conanfile_msvc.settings.compiler.version = "193"
+    conanfile_msvc.conf.define("tools.microsoft:msvc_update", "7")
+    toolchain = CMakeToolchain(conanfile_msvc)
+    assert 'set(CMAKE_GENERATOR_TOOLSET "v143,version=14.37" CACHE STRING "" FORCE)' in toolchain.content
+
+
+def test_toolset_update_version_forced_conf(conanfile_msvc):
+    conanfile_msvc.settings.compiler.version = "193"
+    conanfile_msvc.settings.compiler.update = "8"
+    conanfile_msvc.conf.define("tools.microsoft:msvc_update", "7")
+    toolchain = CMakeToolchain(conanfile_msvc)
+    assert 'set(CMAKE_GENERATOR_TOOLSET "v143,version=14.37" CACHE STRING "" FORCE)' in toolchain.content
+
+
 def test_toolset_update_version_overflow(conanfile_msvc):
     # https://github.com/conan-io/conan/issues/15583
     conanfile_msvc.settings.compiler.version = "194"