diff --git a/WoofWare.DotnetRuntimeLocator/DotnetRuntime.cs b/WoofWare.DotnetRuntimeLocator/DotnetRuntime.cs index acfa246..5791afe 100644 --- a/WoofWare.DotnetRuntimeLocator/DotnetRuntime.cs +++ b/WoofWare.DotnetRuntimeLocator/DotnetRuntime.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Text.Json; +using System.Text.Json.Serialization; namespace WoofWare.DotnetRuntimeLocator; @@ -257,6 +258,18 @@ public static class DotnetRuntime } } + private static JsonSerializerOptions _options = new() {PropertyNameCaseInsensitive = true, Converters = { new JsonStringEnumConverter() }}; + + /// + /// Parse a runtimeconfig.json file. + /// + /// Contents of the runtimeconfig.json file to parse. + /// I think this can't happen, but the docs suggest that deserialization might return null. + public static RuntimeConfig? DeserializeRuntimeConfig(string contents) + { + return JsonSerializer.Deserialize(contents, _options); + } + /// /// Given a .NET executable DLL, identify the most appropriate .NET runtime to run it. /// This is pretty half-baked at the moment; test this yourself to make sure it does what you want it to! @@ -285,9 +298,8 @@ public static class DotnetRuntime // It appears to be undocumented why this returns a nullable, and the Rider decompiler doesn't suggest there are // any code paths where it can return null? - var runtimeConfig = - JsonSerializer.Deserialize(File.ReadAllText(configFilePath)) ?? - throw new NullReferenceException($"Failed to parse contents of file {configFilePath} as a runtime config"); + var contents = File.ReadAllText(configFilePath); + var runtimeConfig = DeserializeRuntimeConfig(contents) ?? throw new NullReferenceException($"Failed to parse contents of file {configFilePath} as a runtime config"); var availableRuntimes = dotnet == null ? DotnetEnvironmentInfo.Get() diff --git a/WoofWare.DotnetRuntimeLocator/SurfaceBaseline.txt b/WoofWare.DotnetRuntimeLocator/SurfaceBaseline.txt index df58d7e..95aeb77 100644 --- a/WoofWare.DotnetRuntimeLocator/SurfaceBaseline.txt +++ b/WoofWare.DotnetRuntimeLocator/SurfaceBaseline.txt @@ -46,6 +46,7 @@ WoofWare.DotnetRuntimeLocator.DotnetEnvironmentSdkInfo.set_Path [method]: string WoofWare.DotnetRuntimeLocator.DotnetEnvironmentSdkInfo.set_Version [method]: string -> unit WoofWare.DotnetRuntimeLocator.DotnetEnvironmentSdkInfo.Version [property]: string WoofWare.DotnetRuntimeLocator.DotnetRuntime inherit obj +WoofWare.DotnetRuntimeLocator.DotnetRuntime.DeserializeRuntimeConfig [static method]: string -> WoofWare.DotnetRuntimeLocator.RuntimeConfig WoofWare.DotnetRuntimeLocator.DotnetRuntime.SelectForDll [static method]: (string, string) -> string System.Collections.Generic.IReadOnlyList WoofWare.DotnetRuntimeLocator.RollForward inherit System.Enum WoofWare.DotnetRuntimeLocator.RollForward.Disable [static field]: WoofWare.DotnetRuntimeLocator.RollForward = Disable diff --git a/WoofWare.DotnetRuntimeLocator/Test/Assembly.fs b/WoofWare.DotnetRuntimeLocator/Test/Assembly.fs new file mode 100644 index 0000000..3b0b2dd --- /dev/null +++ b/WoofWare.DotnetRuntimeLocator/Test/Assembly.fs @@ -0,0 +1,21 @@ +namespace WoofWare.DotnetRuntimeLocator.Test + +open System +open System.IO +open System.Reflection + +[] +module Assembly = + let getEmbeddedResource (assembly : Assembly) (name : string) : string = + let names = assembly.GetManifestResourceNames () + + let names = + names |> Seq.filter (fun s -> s.EndsWith (name, StringComparison.Ordinal)) + + use s = + names + |> Seq.exactlyOne + |> assembly.GetManifestResourceStream + |> fun s -> new StreamReader (s) + + s.ReadToEnd () diff --git a/WoofWare.DotnetRuntimeLocator/Test/Test.fsproj b/WoofWare.DotnetRuntimeLocator/Test/Test.fsproj index fc1cfe2..1f4900c 100644 --- a/WoofWare.DotnetRuntimeLocator/Test/Test.fsproj +++ b/WoofWare.DotnetRuntimeLocator/Test/Test.fsproj @@ -8,10 +8,12 @@ + + diff --git a/WoofWare.DotnetRuntimeLocator/Test/TestRuntimeConfigParse.fs b/WoofWare.DotnetRuntimeLocator/Test/TestRuntimeConfigParse.fs index 80771cf..88ec9b6 100644 --- a/WoofWare.DotnetRuntimeLocator/Test/TestRuntimeConfigParse.fs +++ b/WoofWare.DotnetRuntimeLocator/Test/TestRuntimeConfigParse.fs @@ -30,3 +30,20 @@ module TestRuntimeConfigParse = ) actual |> shouldEqual expected + + [] + let ``Example 1`` () = + let content = + Assembly.getEmbeddedResource (Assembly.GetExecutingAssembly ()) "runtimeconfig1.json" + + let expected = + RuntimeConfig ( + RuntimeOptions = + RuntimeOptions ( + Tfm = "net8.0", + RollForward = RollForward.Major, + Framework = RuntimeConfigFramework (Name = "Microsoft.NETCore.App", Version = "8.0.0") + ) + ) + + DotnetRuntime.DeserializeRuntimeConfig content |> shouldEqual expected diff --git a/WoofWare.DotnetRuntimeLocator/Test/runtimeconfig1.json b/WoofWare.DotnetRuntimeLocator/Test/runtimeconfig1.json new file mode 100644 index 0000000..d7aecb5 --- /dev/null +++ b/WoofWare.DotnetRuntimeLocator/Test/runtimeconfig1.json @@ -0,0 +1,13 @@ +{ + "runtimeOptions": { + "tfm": "net8.0", + "rollForward": "Major", + "framework": { + "name": "Microsoft.NETCore.App", + "version": "8.0.0" + }, + "configProperties": { + "System.Runtime.Serialization.EnableUnsafeBinaryFormatterSerialization": false + } + } +} diff --git a/WoofWare.DotnetRuntimeLocator/version.json b/WoofWare.DotnetRuntimeLocator/version.json index 0158ffa..c7c4e81 100644 --- a/WoofWare.DotnetRuntimeLocator/version.json +++ b/WoofWare.DotnetRuntimeLocator/version.json @@ -1,5 +1,5 @@ { - "version": "0.3", + "version": "0.4", "publicReleaseRefSpec": [ "^refs/heads/main$" ], @@ -9,4 +9,4 @@ ":/Directory.Build.props", ":/README.md" ] -} +} \ No newline at end of file