diff --git a/src/installer/tests/Assets/TestProjects/HostApiInvokerApp/HostFXR.cs b/src/installer/tests/Assets/TestProjects/HostApiInvokerApp/HostFXR.cs index f15e4d198a077..76dc6db1d65f2 100644 --- a/src/installer/tests/Assets/TestProjects/HostApiInvokerApp/HostFXR.cs +++ b/src/installer/tests/Assets/TestProjects/HostApiInvokerApp/HostFXR.cs @@ -22,6 +22,7 @@ internal enum hostfxr_resolve_sdk2_result_key_t : int { resolved_sdk_dir = 0, global_json_path = 1, + requested_version = 2, } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] diff --git a/src/installer/tests/HostActivation.Tests/NativeHostApis.cs b/src/installer/tests/HostActivation.Tests/NativeHostApis.cs index 869c264239e2f..f55f4c40b1523 100644 --- a/src/installer/tests/HostActivation.Tests/NativeHostApis.cs +++ b/src/installer/tests/HostActivation.Tests/NativeHostApis.cs @@ -97,7 +97,7 @@ public SdkResolutionFixture(SharedTestState state) Directory.CreateDirectory(WorkingDir); - // start with an empty global.json, it will be ignored, but prevent one lying on disk + // start with an empty global.json, it will be ignored, but prevent one lying on disk // on a given machine from impacting the test. File.WriteAllText(GlobalJson, "{}"); @@ -224,17 +224,19 @@ public void Hostfxr_resolve_sdk2_without_global_json_and_disallowing_previews() [Fact] public void Hostfxr_resolve_sdk2_with_global_json_and_disallowing_previews() { - // With global.json specifying a preview, roll forward to preview + // With global.json specifying a preview, roll forward to preview // since flag has no impact if global.json specifies a preview. // Also check that global.json that impacted resolution is reported. var f = new SdkResolutionFixture(sharedTestState); - File.WriteAllText(f.GlobalJson, "{ \"sdk\": { \"version\": \"5.6.6-preview\" } }"); + string requestedVersion = "5.6.6-preview"; + File.WriteAllText(f.GlobalJson, "{ \"sdk\": { \"version\": \"" + requestedVersion + "\" } }"); string expectedData = string.Join(';', new[] { ("resolved_sdk_dir", Path.Combine(f.LocalSdkDir, "5.6.7-preview")), ("global_json_path", f.GlobalJson), + ("requested_version", requestedVersion), }); f.Dotnet.Exec(f.AppDll, new[] { "hostfxr_resolve_sdk2", f.ExeDir, f.WorkingDir, "disallow_prerelease" }) @@ -425,7 +427,7 @@ public void Hostfxr_get_dotnet_environment_info_with_multilevel_lookup_only_self public void Hostfxr_get_dotnet_environment_info_global_install_path() { var f = new SdkResolutionFixture(sharedTestState); - + f.Dotnet.Exec(f.AppDll, new[] { "hostfxr_get_dotnet_environment_info" }) .CaptureStdOut() .CaptureStdErr() diff --git a/src/native/corehost/fxr/hostfxr.cpp b/src/native/corehost/fxr/hostfxr.cpp index 8790083e9885d..28a12e2d32622 100644 --- a/src/native/corehost/fxr/hostfxr.cpp +++ b/src/native/corehost/fxr/hostfxr.cpp @@ -170,6 +170,7 @@ enum class hostfxr_resolve_sdk2_result_key_t : int32_t { resolved_sdk_dir = 0, global_json_path = 1, + requested_version = 2, }; typedef void (HOSTFXR_CALLTYPE *hostfxr_resolve_sdk2_result_fn)( @@ -208,17 +209,22 @@ typedef void (HOSTFXR_CALLTYPE *hostfxr_resolve_sdk2_result_fn)( // than once. String values passed are valid only for the // duration of a call. // -// If resolution succeeds, result will be invoked with -// resolved_sdk_dir key and the value will hold the -// path to the resolved SDK director, otherwise it will -// be null. +// If resolution succeeds, then result will be invoked with +// resolved_sdk_dir key and the value will hold the path to +// the resolved SDK directory. // -// If global.json is used then result will be invoked with -// global_json_path key and the value will hold the path +// If global.json is used, then result will be invoked with +// global_json_path key and the value will hold the path // to global.json. If there was no global.json found, // or the contents of global.json did not impact resolution // (e.g. no version specified), then result will not be -// invoked with global_json_path key. +// invoked with global_json_path key. This will occur for +// both resolution success and failure. +// +// If a specific version is requested (via global.json), then +// result will be invoked with requested_version key and the +// value will hold the requested version. This will occur for +// both resolution success and failure. // // Return value: // 0 on success, otherwise failure @@ -265,6 +271,13 @@ SHARED_API int32_t HOSTFXR_CALLTYPE hostfxr_resolve_sdk2( resolver.global_file_path().c_str()); } + if (!resolver.get_requested_version().is_empty()) + { + result( + hostfxr_resolve_sdk2_result_key_t::requested_version, + resolver.get_requested_version().as_str().c_str()); + } + return !resolved_sdk_dir.empty() ? StatusCode::Success : StatusCode::SdkResolverResolveFailure; diff --git a/src/native/corehost/fxr/sdk_resolver.cpp b/src/native/corehost/fxr/sdk_resolver.cpp index 3a1f01105b0b7..6f532042ef44a 100644 --- a/src/native/corehost/fxr/sdk_resolver.cpp +++ b/src/native/corehost/fxr/sdk_resolver.cpp @@ -34,22 +34,27 @@ sdk_resolver::sdk_resolver(bool allow_prerelease) : } sdk_resolver::sdk_resolver(fx_ver_t version, sdk_roll_forward_policy roll_forward, bool allow_prerelease) : - version(move(version)), + requested_version(move(version)), roll_forward(roll_forward), allow_prerelease(allow_prerelease) { } -pal::string_t const& sdk_resolver::global_file_path() const +const pal::string_t& sdk_resolver::global_file_path() const { return global_file; } +const fx_ver_t& sdk_resolver::get_requested_version() const +{ + return requested_version; +} + pal::string_t sdk_resolver::resolve(const pal::string_t& dotnet_root, bool print_errors) const { if (trace::is_enabled()) { - auto requested = version.is_empty() ? pal::string_t{} : version.as_str(); + auto requested = requested_version.is_empty() ? pal::string_t{} : requested_version.as_str(); trace::verbose( _X("Resolving SDKs with version = '%s', rollForward = '%s', allowPrerelease = %s"), requested.empty() ? _X("latest") : requested.c_str(), @@ -98,9 +103,9 @@ void sdk_resolver::print_resolution_error(const pal::string_t& dotnet_root, cons { bool sdk_exists = false; const pal::char_t *no_sdk_message = _X("No .NET SDKs were found."); - if (!version.is_empty()) + if (!requested_version.is_empty()) { - pal::string_t requested = version.as_str(); + pal::string_t requested = requested_version.as_str(); trace::error( _X("%sA compatible .NET SDK was not found.\n") _X("\n") @@ -176,7 +181,7 @@ sdk_resolver sdk_resolver::from_nearest_global_file(const pal::string_t& cwd, bo } // If the requested version is a prerelease, always allow prerelease versions - if (resolver.version.is_prerelease()) + if (resolver.requested_version.is_prerelease()) { resolver.allow_prerelease = true; } @@ -285,7 +290,7 @@ bool sdk_resolver::parse_global_file(pal::string_t global_file_path) return false; } - if (!fx_ver_t::parse(version_value->value.GetString(), &version, false)) + if (!fx_ver_t::parse(version_value->value.GetString(), &requested_version, false)) { trace::warning( _X("Version '%s' is not valid for the 'sdk/version' value in [%s]"), @@ -324,7 +329,7 @@ bool sdk_resolver::parse_global_file(pal::string_t global_file_path) } // All policies other than 'latestMajor' require a version to operate - if (roll_forward != sdk_roll_forward_policy::latest_major && version.is_empty()) + if (roll_forward != sdk_roll_forward_policy::latest_major && requested_version.is_empty()) { trace::warning( _X("The roll-forward policy '%s' requires a 'sdk/version' value in [%s]"), @@ -350,7 +355,7 @@ bool sdk_resolver::parse_global_file(pal::string_t global_file_path) allow_prerelease = allow_prerelease_value->value.GetBool(); - if (!allow_prerelease && version.is_prerelease()) + if (!allow_prerelease && requested_version.is_prerelease()) { trace::warning(_X("Ignoring the 'sdk/allowPrerelease' value in [%s] because a prerelease version was specified"), global_file_path.c_str()); allow_prerelease = true; @@ -373,18 +378,18 @@ bool sdk_resolver::matches_policy(const fx_ver_t& current) const } // If no version was requested, then all versions match - if (version.is_empty()) + if (requested_version.is_empty()) { return true; } - int requested_feature = version.get_patch() / 100; + int requested_feature = requested_version.get_patch() / 100; int current_feature = current.get_patch() / 100; - int requested_minor = version.get_minor(); + int requested_minor = requested_version.get_minor(); int current_minor = current.get_minor(); - int requested_major = version.get_major(); + int requested_major = requested_version.get_major(); int current_major = current.get_major(); // Rolling forward on patch requires the same major/minor/feature @@ -415,7 +420,7 @@ bool sdk_resolver::matches_policy(const fx_ver_t& current) const } // The version must be at least what was requested - return current >= version; + return current >= requested_version; } bool sdk_resolver::is_better_match(const fx_ver_t& current, const fx_ver_t& previous) const @@ -430,7 +435,7 @@ bool sdk_resolver::is_better_match(const fx_ver_t& current, const fx_ver_t& prev // Use the later of the two if there is no requested version, the policy requires it, // or if everything is equal up to the feature level (latest patch always wins) - if (version.is_empty() || + if (requested_version.is_empty() || is_policy_use_latest() || (current.get_major() == previous.get_major() && current.get_minor() == previous.get_minor() && @@ -463,16 +468,16 @@ bool sdk_resolver::resolve_sdk_path_and_version(const pal::string_t& dir, pal::s trace::verbose(_X("Searching for SDK versions in [%s]"), dir.c_str()); // If an exact match is preferred, check for the existence of the version - if (exact_match_preferred() && !version.is_empty()) + if (exact_match_preferred() && !requested_version.is_empty()) { auto probe_path = dir; - append_path(&probe_path, version.as_str().c_str()); + append_path(&probe_path, requested_version.as_str().c_str()); if (pal::directory_exists(probe_path)) { trace::verbose(_X("Found requested SDK directory [%s]"), probe_path.c_str()); sdk_path = move(probe_path); - resolved_version = version; + resolved_version = requested_version; // The SDK path has been resolved return true; diff --git a/src/native/corehost/fxr/sdk_resolver.h b/src/native/corehost/fxr/sdk_resolver.h index 15342603ab764..936a6d950c61b 100644 --- a/src/native/corehost/fxr/sdk_resolver.h +++ b/src/native/corehost/fxr/sdk_resolver.h @@ -37,7 +37,9 @@ class sdk_resolver explicit sdk_resolver(bool allow_prerelease = true); sdk_resolver(fx_ver_t version, sdk_roll_forward_policy roll_forward, bool allow_prerelease); - pal::string_t const& global_file_path() const; + const pal::string_t& global_file_path() const; + + const fx_ver_t& get_requested_version() const; pal::string_t resolve(const pal::string_t& dotnet_root, bool print_errors = true) const; @@ -62,7 +64,7 @@ class sdk_resolver bool resolve_sdk_path_and_version(const pal::string_t& dir, pal::string_t& sdk_path, fx_ver_t& resolved_version) const; pal::string_t global_file; - fx_ver_t version; + fx_ver_t requested_version; sdk_roll_forward_policy roll_forward; bool allow_prerelease; };