Add requested version to hostfxr_resolve_sdk2 (#68355)
authorElinor Fung <elfung@microsoft.com>
Mon, 25 Apr 2022 17:27:54 +0000 (10:27 -0700)
committerGitHub <noreply@github.com>
Mon, 25 Apr 2022 17:27:54 +0000 (10:27 -0700)
src/installer/tests/Assets/TestProjects/HostApiInvokerApp/HostFXR.cs
src/installer/tests/HostActivation.Tests/NativeHostApis.cs
src/native/corehost/fxr/hostfxr.cpp
src/native/corehost/fxr/sdk_resolver.cpp
src/native/corehost/fxr/sdk_resolver.h

index f15e4d1..76dc6db 100644 (file)
@@ -22,6 +22,7 @@ namespace HostApiInvokerApp
             {
                 resolved_sdk_dir = 0,
                 global_json_path = 1,
+                requested_version = 2,
             }
 
             [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
index 869c264..f55f4c4 100644 (file)
@@ -97,7 +97,7 @@ namespace Microsoft.DotNet.CoreSetup.Test.HostActivation
 
                 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 @@ namespace Microsoft.DotNet.CoreSetup.Test.HostActivation
         [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 @@ namespace Microsoft.DotNet.CoreSetup.Test.HostActivation
         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()
index 8790083..28a12e2 100644 (file)
@@ -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;
index 3a1f011..6f53204 100644 (file)
@@ -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;
index 1534260..936a6d9 100644 (file)
@@ -37,7 +37,9 @@ public:
     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 @@ private:
     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;
 };