diff --git a/conan/internal/api/detect_api.py b/conan/internal/api/detect_api.py index e9df56f3cb2..cc0fa762559 100644 --- a/conan/internal/api/detect_api.py +++ b/conan/internal/api/detect_api.py @@ -204,6 +204,11 @@ def default_msvc_runtime(compiler): return None, None +def detect_msvc_update(version): + from conans.client.conf.detect_vs import vs_detect_update + return vs_detect_update(version) + + def default_cppstd(compiler, compiler_version): """ returns the default cppstd for the compiler-version. This is not detected, just the default """ diff --git a/conans/client/conf/detect_vs.py b/conans/client/conf/detect_vs.py index f8eb3eb9b6c..f0c48c7491c 100644 --- a/conans/client/conf/detect_vs.py +++ b/conans/client/conf/detect_vs.py @@ -8,58 +8,51 @@ def vs_installation_path(version): + return _vs_installation_path(version)[0] + + +def vs_detect_update(version): + version = {"193": "17", "192": "16", "191": "15"}.get(str(version)) + full_version = _vs_installation_path(version)[1] + components = full_version.split(".") + if len(components) > 1: + return components[1] + + +def _vs_installation_path(version): # TODO: Preference hardcoded, [conf] must be defined preference = ["Enterprise", "Professional", "Community", "BuildTools"] # Try with vswhere() try: legacy_products = vswhere(legacy=True) - all_products = vswhere(products=["*"]) - products = legacy_products + all_products + products = vswhere(products=["*"]) + products.extend(p for p in legacy_products if p not in products) except ConanException: products = None - vs_paths = [] - - if products: - # remove repeated products - seen_products = [] - for product in products: - if product not in seen_products: - seen_products.append(product) - - # Append products with "productId" by order of preference + if products: # First matching for product_type in preference: - for product in seen_products: - product = dict(product) - if (product["installationVersion"].startswith(("%d." % int(version))) - and "productId" in product): - if product_type in product["productId"]: - vs_paths.append(product["installationPath"]) + for product in products: + if product["installationVersion"].startswith(f"{version}."): + if product_type in product.get("productId", ""): + return product["installationPath"], product["installationVersion"] # Append products without "productId" (Legacy installations) - for product in seen_products: - product = dict(product) - if (product["installationVersion"].startswith(("%d." % int(version))) + for product in products: + if (product["installationVersion"].startswith(f"{version}.") and "productId" not in product): - vs_paths.append(product["installationPath"]) + return product["installationPath"], product["installationVersion"] # If vswhere does not find anything or not available, try with vs_comntools - if not vs_paths: - env_var = "vs%s0comntools" % version - vs_path = os.getenv(env_var) - - if vs_path: - sub_path_to_remove = os.path.join("", "Common7", "Tools", "") - # Remove '\\Common7\\Tools\\' to get same output as vswhere - if vs_path.endswith(sub_path_to_remove): - vs_path = vs_path[:-(len(sub_path_to_remove)+1)] - - result_vs_installation_path = vs_path - else: - result_vs_installation_path = vs_paths[0] - - return result_vs_installation_path + vs_path = os.getenv("vs%s0comntools" % version) + if vs_path: + sub_path_to_remove = os.path.join("", "Common7", "Tools", "") + # Remove '\\Common7\\Tools\\' to get same output as vswhere + if vs_path.endswith(sub_path_to_remove): + vs_path = vs_path[:-(len(sub_path_to_remove)+1)] + + return vs_path, None def vswhere(all_=False, prerelease=True, products=None, requires=None, version="", latest=False, diff --git a/conans/test/functional/test_profile_detect_api.py b/conans/test/functional/test_profile_detect_api.py index 1601e97ac77..84748d01733 100644 --- a/conans/test/functional/test_profile_detect_api.py +++ b/conans/test/functional/test_profile_detect_api.py @@ -2,6 +2,7 @@ import pytest +from conan.internal.api import detect_api from conans.test.utils.tools import TestClient @@ -19,6 +20,7 @@ def test_profile_detect_compiler(self): compiler.runtime={{runtime}} compiler.libcxx={{detect_api.detect_libcxx(compiler, version, compiler_exe)}} compiler.cppstd={{detect_api.default_cppstd(compiler, version)}} + compiler.update={{detect_api.detect_msvc_update(version)}} [conf] tools.microsoft.msbuild:vs_version={{detect_api.default_msvc_ide_version(version)}} @@ -26,6 +28,7 @@ def test_profile_detect_compiler(self): client.save({"profile1": tpl1}) client.run("profile show -pr=profile1") + update = detect_api.detect_msvc_update("193") expected = textwrap.dedent(f"""\ Host profile: [settings] @@ -33,6 +36,7 @@ def test_profile_detect_compiler(self): compiler.cppstd=14 compiler.runtime=dynamic compiler.runtime_type=Release + compiler.update={update} compiler.version=193 [conf] tools.microsoft.msbuild:vs_version=17