From 13f636df3df7f85eeaf64183d48addac1ac8c896 Mon Sep 17 00:00:00 2001 From: Patrick Stevens <3138005+Smaug123@users.noreply.github.com> Date: Sat, 15 Jun 2024 22:55:30 +0100 Subject: [PATCH] Promote runtime stuff to lib (#74) --- WoofWare.NUnitTestRunner.Lib/DotnetRuntime.fs | 104 ++++++++++++++++++ .../RuntimeConfig.fs | 8 +- .../SurfaceBaseline.txt | 4 +- .../WoofWare.NUnitTestRunner.Lib.fsproj | 16 ++- WoofWare.NUnitTestRunner.Lib/myriad.toml | 0 WoofWare.NUnitTestRunner.Lib/version.json | 4 +- WoofWare.NUnitTestRunner/Program.fs | 98 +---------------- .../WoofWare.NUnitTestRunner.fsproj | 13 --- WoofWare.NUnitTestRunner/version.json | 1 + nix/deps.nix | 79 +++++++++++-- 10 files changed, 202 insertions(+), 125 deletions(-) create mode 100644 WoofWare.NUnitTestRunner.Lib/DotnetRuntime.fs rename {WoofWare.NUnitTestRunner => WoofWare.NUnitTestRunner.Lib}/RuntimeConfig.fs (91%) create mode 100644 WoofWare.NUnitTestRunner.Lib/myriad.toml diff --git a/WoofWare.NUnitTestRunner.Lib/DotnetRuntime.fs b/WoofWare.NUnitTestRunner.Lib/DotnetRuntime.fs new file mode 100644 index 0000000..e0f00ec --- /dev/null +++ b/WoofWare.NUnitTestRunner.Lib/DotnetRuntime.fs @@ -0,0 +1,104 @@ +namespace WoofWare.NUnitTestRunner + +open System +open System.IO +open WoofWare.DotnetRuntimeLocator + +/// Functions for locating .NET runtimes. +[] +module DotnetRuntime = + let private selectRuntime + (config : RuntimeOptions) + (f : DotnetEnvironmentInfo) + : Choice option + = + let rollForward = + match Environment.GetEnvironmentVariable "DOTNET_ROLL_FORWARD" with + | null -> + config.RollForward + |> Option.map RollForward.Parse + |> Option.defaultValue RollForward.Minor + | s -> RollForward.Parse s + + let desiredVersions = + match config.Framework with + | Some f -> [ Version f.Version, f.Name ] + | None -> + + match config.Frameworks with + | Some f -> f |> List.map (fun f -> Version f.Version, f.Name) + | None -> + failwith + "Could not deduce a framework version due to lack of either Framework or Frameworks in runtimeconfig" + + let compatiblyNamedRuntimes = + f.Frameworks + |> Seq.collect (fun availableFramework -> + desiredVersions + |> List.choose (fun (desiredVersion, desiredName) -> + if desiredName = availableFramework.Name then + Some + {| + Desired = desiredVersion + Name = desiredName + Installed = availableFramework + InstalledVersion = Version availableFramework.Version + |} + else + None + ) + ) + |> Seq.toList + + match rollForward with + | RollForward.Minor -> + let available = + compatiblyNamedRuntimes + |> Seq.filter (fun data -> + data.InstalledVersion.Major = data.Desired.Major + && data.InstalledVersion.Minor >= data.Desired.Minor + ) + |> Seq.groupBy (fun data -> data.Name) + |> Seq.map (fun (name, data) -> + let data = + data + |> Seq.minBy (fun data -> data.InstalledVersion.Minor, data.InstalledVersion.Build) + + name, data.Installed + ) + // TODO: how do we select between many available frameworks? + |> Seq.tryHead + + match available with + | Some (_, f) -> Some (Choice1Of2 f) + | None -> + // TODO: maybe we can ask the SDK. But we keep on trucking: maybe we're self-contained, + // and we'll actually find all the runtime next to the DLL. + None + | _ -> failwith "non-minor RollForward not supported yet; please shout if you want it" + + /// Given an executable DLL, locate the .NET runtime that can best run it. + let locate (dll : FileInfo) : DirectoryInfo list = + let runtimeConfig = + let name = + if not (dll.Name.EndsWith (".dll", StringComparison.OrdinalIgnoreCase)) then + failwith $"Expected DLL %s{dll.FullName} to end in .dll" + + dll.Name.Substring (0, dll.Name.Length - 4) + + Path.Combine (dll.Directory.FullName, $"%s{name}.runtimeconfig.json") + |> File.ReadAllText + |> System.Text.Json.Nodes.JsonNode.Parse + |> RuntimeConfig.jsonParse + |> fun f -> f.RuntimeOptions + + let availableRuntimes = DotnetEnvironmentInfo.Get () + + let runtime = selectRuntime runtimeConfig availableRuntimes + + match runtime with + | None -> + // Keep on trucking: let's be optimistic and hope that we're self-contained. + [ dll.Directory ] + | Some (Choice1Of2 runtime) -> [ dll.Directory ; DirectoryInfo $"%s{runtime.Path}/%s{runtime.Version}" ] + | Some (Choice2Of2 sdk) -> [ dll.Directory ; DirectoryInfo sdk.Path ] diff --git a/WoofWare.NUnitTestRunner/RuntimeConfig.fs b/WoofWare.NUnitTestRunner.Lib/RuntimeConfig.fs similarity index 91% rename from WoofWare.NUnitTestRunner/RuntimeConfig.fs rename to WoofWare.NUnitTestRunner.Lib/RuntimeConfig.fs index bade52e..28904bb 100644 --- a/WoofWare.NUnitTestRunner/RuntimeConfig.fs +++ b/WoofWare.NUnitTestRunner.Lib/RuntimeConfig.fs @@ -4,14 +4,14 @@ open System open WoofWare.Myriad.Plugins [] -type FrameworkDescription = +type internal FrameworkDescription = { Name : string Version : string } [] -type RuntimeOptions = +type internal RuntimeOptions = { Tfm : string Framework : FrameworkDescription option @@ -20,13 +20,13 @@ type RuntimeOptions = } [] -type RuntimeConfig = +type internal RuntimeConfig = { RuntimeOptions : RuntimeOptions } [] -type RollForward = +type internal RollForward = | Minor | Major | LatestPatch diff --git a/WoofWare.NUnitTestRunner.Lib/SurfaceBaseline.txt b/WoofWare.NUnitTestRunner.Lib/SurfaceBaseline.txt index 0f1fffd..be778eb 100644 --- a/WoofWare.NUnitTestRunner.Lib/SurfaceBaseline.txt +++ b/WoofWare.NUnitTestRunner.Lib/SurfaceBaseline.txt @@ -12,6 +12,8 @@ WoofWare.NUnitTestRunner.Combinatorial.IsCombinatorial [property]: [read-only] b WoofWare.NUnitTestRunner.Combinatorial.IsSequential [property]: [read-only] bool WoofWare.NUnitTestRunner.Combinatorial.Sequential [static property]: [read-only] WoofWare.NUnitTestRunner.Combinatorial WoofWare.NUnitTestRunner.Combinatorial.Tag [property]: [read-only] int +WoofWare.NUnitTestRunner.DotnetRuntime inherit obj +WoofWare.NUnitTestRunner.DotnetRuntime.locate [static method]: System.IO.FileInfo -> System.IO.DirectoryInfo list WoofWare.NUnitTestRunner.Filter inherit obj, implements WoofWare.NUnitTestRunner.Filter System.IEquatable, System.Collections.IStructuralEquatable, WoofWare.NUnitTestRunner.Filter System.IComparable, System.IComparable, System.Collections.IStructuralComparable - union type with 6 cases WoofWare.NUnitTestRunner.Filter+And inherit WoofWare.NUnitTestRunner.Filter WoofWare.NUnitTestRunner.Filter+And.get_Item1 [method]: unit -> WoofWare.NUnitTestRunner.Filter @@ -532,4 +534,4 @@ WoofWare.NUnitTestRunner.UserMethodFailure.IsThrew [property]: [read-only] bool WoofWare.NUnitTestRunner.UserMethodFailure.Name [property]: [read-only] string WoofWare.NUnitTestRunner.UserMethodFailure.NewReturnedNonUnit [static method]: (string, obj) -> WoofWare.NUnitTestRunner.UserMethodFailure WoofWare.NUnitTestRunner.UserMethodFailure.NewThrew [static method]: (string, System.Exception) -> WoofWare.NUnitTestRunner.UserMethodFailure -WoofWare.NUnitTestRunner.UserMethodFailure.Tag [property]: [read-only] int +WoofWare.NUnitTestRunner.UserMethodFailure.Tag [property]: [read-only] int \ No newline at end of file diff --git a/WoofWare.NUnitTestRunner.Lib/WoofWare.NUnitTestRunner.Lib.fsproj b/WoofWare.NUnitTestRunner.Lib/WoofWare.NUnitTestRunner.Lib.fsproj index cea3342..8e4a2e3 100644 --- a/WoofWare.NUnitTestRunner.Lib/WoofWare.NUnitTestRunner.Lib.fsproj +++ b/WoofWare.NUnitTestRunner.Lib/WoofWare.NUnitTestRunner.Lib.fsproj @@ -1,7 +1,7 @@ - netstandard2.1 + net6.0 true Patrick Stevens Copyright (c) Patrick Stevens 2024 @@ -14,10 +14,16 @@ WoofWare.NUnitTestRunner.Lib true FS3559 + 2.1.44 + + + RuntimeConfig.fs + + @@ -38,6 +44,14 @@ + + + + + + + + diff --git a/WoofWare.NUnitTestRunner.Lib/myriad.toml b/WoofWare.NUnitTestRunner.Lib/myriad.toml new file mode 100644 index 0000000..e69de29 diff --git a/WoofWare.NUnitTestRunner.Lib/version.json b/WoofWare.NUnitTestRunner.Lib/version.json index 57ef466..e128f3c 100644 --- a/WoofWare.NUnitTestRunner.Lib/version.json +++ b/WoofWare.NUnitTestRunner.Lib/version.json @@ -1,5 +1,5 @@ { - "version": "0.9", + "version": "0.10", "publicReleaseRefSpec": [ "^refs/heads/main$" ], @@ -8,4 +8,4 @@ ":/Directory.Build.props", ":/README.md" ] -} +} \ No newline at end of file diff --git a/WoofWare.NUnitTestRunner/Program.fs b/WoofWare.NUnitTestRunner/Program.fs index b9b2584..f78a777 100644 --- a/WoofWare.NUnitTestRunner/Program.fs +++ b/WoofWare.NUnitTestRunner/Program.fs @@ -1,7 +1,6 @@ namespace WoofWare.NUnitTestRunner open System -open WoofWare.DotnetRuntimeLocator open System.IO open System.Reflection open System.Runtime.Loader @@ -41,101 +40,6 @@ type Ctx (dll : FileInfo, runtimes : DirectoryInfo list) = module Program = - let selectRuntime - (config : RuntimeOptions) - (f : DotnetEnvironmentInfo) - : Choice option - = - let rollForward = - match Environment.GetEnvironmentVariable "DOTNET_ROLL_FORWARD" with - | null -> - config.RollForward - |> Option.map RollForward.Parse - |> Option.defaultValue RollForward.Minor - | s -> RollForward.Parse s - - let desiredVersions = - match config.Framework with - | Some f -> [ Version f.Version, f.Name ] - | None -> - - match config.Frameworks with - | Some f -> f |> List.map (fun f -> Version f.Version, f.Name) - | None -> - failwith - "Could not deduce a framework version due to lack of either Framework or Frameworks in runtimeconfig" - - let compatiblyNamedRuntimes = - f.Frameworks - |> Seq.collect (fun availableFramework -> - desiredVersions - |> List.choose (fun (desiredVersion, desiredName) -> - if desiredName = availableFramework.Name then - Some - {| - Desired = desiredVersion - Name = desiredName - Installed = availableFramework - InstalledVersion = Version availableFramework.Version - |} - else - None - ) - ) - |> Seq.toList - - match rollForward with - | RollForward.Minor -> - let available = - compatiblyNamedRuntimes - |> Seq.filter (fun data -> - data.InstalledVersion.Major = data.Desired.Major - && data.InstalledVersion.Minor >= data.Desired.Minor - ) - |> Seq.groupBy (fun data -> data.Name) - |> Seq.map (fun (name, data) -> - let data = - data - |> Seq.minBy (fun data -> data.InstalledVersion.Minor, data.InstalledVersion.Build) - - name, data.Installed - ) - // TODO: how do we select between many available frameworks? - |> Seq.tryHead - - match available with - | Some (_, f) -> Some (Choice1Of2 f) - | None -> - // TODO: maybe we can ask the SDK. But we keep on trucking: maybe we're self-contained, - // and we'll actually find all the runtime next to the DLL. - None - | _ -> failwith "non-minor RollForward not supported yet; please shout if you want it" - - let locateRuntimes (dll : FileInfo) : DirectoryInfo list = - let runtimeConfig = - let name = - if not (dll.Name.EndsWith (".dll", StringComparison.OrdinalIgnoreCase)) then - failwith $"Expected DLL %s{dll.FullName} to end in .dll" - - dll.Name.Substring (0, dll.Name.Length - 4) - - Path.Combine (dll.Directory.FullName, $"%s{name}.runtimeconfig.json") - |> File.ReadAllText - |> System.Text.Json.Nodes.JsonNode.Parse - |> RuntimeConfig.jsonParse - |> fun f -> f.RuntimeOptions - - let availableRuntimes = DotnetEnvironmentInfo.Get () - - let runtime = selectRuntime runtimeConfig availableRuntimes - - match runtime with - | None -> - // Keep on trucking: let's be optimistic and hope that we're self-contained. - [ dll.Directory ] - | Some (Choice1Of2 runtime) -> [ dll.Directory ; DirectoryInfo $"%s{runtime.Path}/%s{runtime.Version}" ] - | Some (Choice2Of2 sdk) -> [ dll.Directory ; DirectoryInfo sdk.Path ] - let main argv = let startTime = DateTimeOffset.Now @@ -161,7 +65,7 @@ module Program = use _ = new SetBaseDir (testDll) - let ctx = Ctx (testDll, locateRuntimes testDll) + let ctx = Ctx (testDll, DotnetRuntime.locate testDll) let assy = ctx.LoadFromAssemblyPath testDll.FullName let testFixtures = assy.ExportedTypes |> Seq.map TestFixture.parse |> Seq.toList diff --git a/WoofWare.NUnitTestRunner/WoofWare.NUnitTestRunner.fsproj b/WoofWare.NUnitTestRunner/WoofWare.NUnitTestRunner.fsproj index a92b983..73dcb48 100644 --- a/WoofWare.NUnitTestRunner/WoofWare.NUnitTestRunner.fsproj +++ b/WoofWare.NUnitTestRunner/WoofWare.NUnitTestRunner.fsproj @@ -16,14 +16,9 @@ WoofWare.NUnitTestRunner true FS3559 - 2.1.42 - - - RuntimeConfig.fs - @@ -39,14 +34,6 @@ - - - - - - - - diff --git a/WoofWare.NUnitTestRunner/version.json b/WoofWare.NUnitTestRunner/version.json index eef70cf..7e129b7 100644 --- a/WoofWare.NUnitTestRunner/version.json +++ b/WoofWare.NUnitTestRunner/version.json @@ -5,6 +5,7 @@ ], "pathFilters": [ "./", + "^./WoofWare.NUnitTestRunner.Test", ":/WoofWare.NUnitTestRunner.Lib", ":/Directory.Build.props", ":/README.md" diff --git a/nix/deps.nix b/nix/deps.nix index 04ea003..c004918 100644 --- a/nix/deps.nix +++ b/nix/deps.nix @@ -36,6 +36,31 @@ version = "6.0.0"; sha256 = "18q3p0z155znwj1l0qq3vq9nh9wl2i4mlfx4pmrnia4czr0xdkmb"; }) + (fetchNuGet { + pname = "Microsoft.AspNetCore.App.Ref"; + version = "6.0.30"; + sha256 = "17k3l8xd5bsyk69bm5q4nxbpb4i0izw1kzmzi7j3p8pmm9prgrpy"; + }) + (fetchNuGet { + pname = "Microsoft.AspNetCore.App.Runtime.linux-arm64"; + version = "6.0.30"; + sha256 = "1n4v5przbrjhzj01b6qijpdc2jbsxr66ijvd0483qxh4s0b4jppr"; + }) + (fetchNuGet { + pname = "Microsoft.AspNetCore.App.Runtime.linux-x64"; + version = "6.0.30"; + sha256 = "18v0l07q74m5xxaf6y6dkmr6and8ivya0nslffnr4djrxcbiygdr"; + }) + (fetchNuGet { + pname = "Microsoft.AspNetCore.App.Runtime.osx-arm64"; + version = "6.0.30"; + sha256 = "0p53lyqmr5n2ym202pbgmsd9b9aa6jar7ic04dcq86h2g77r5jqk"; + }) + (fetchNuGet { + pname = "Microsoft.AspNetCore.App.Runtime.osx-x64"; + version = "6.0.30"; + sha256 = "009srl8vazkjnd93xr6k1m353spbki9gn1yzp4zgazgbrini6rqc"; + }) (fetchNuGet { pname = "Microsoft.CodeCoverage"; version = "17.10.0"; @@ -46,6 +71,51 @@ version = "17.10.0"; sha256 = "13g8fwl09li8fc71nk13dgkb7gahd4qhamyg2xby7am63nlchhdf"; }) + (fetchNuGet { + pname = "Microsoft.NETCore.App.Host.linux-arm64"; + version = "6.0.30"; + sha256 = "0l3gjhmnjd5n67w83smqyhmfcwzszafjgcbq8kdwxiwwh2m6nh2i"; + }) + (fetchNuGet { + pname = "Microsoft.NETCore.App.Host.linux-x64"; + version = "6.0.30"; + sha256 = "0ss3108c2h7afypvliyqixv4dll60sq9iwqy90k1p132znpszrmb"; + }) + (fetchNuGet { + pname = "Microsoft.NETCore.App.Host.osx-arm64"; + version = "6.0.30"; + sha256 = "08k5v35mvcs712kb0vcfjd1dsas5rgwrmv8rn87mzjb2p6ajl3n3"; + }) + (fetchNuGet { + pname = "Microsoft.NETCore.App.Host.osx-x64"; + version = "6.0.30"; + sha256 = "02x38c68xan8hlr59mindcl4rcx49bbh4bibh6fw1l4rrijb38lw"; + }) + (fetchNuGet { + pname = "Microsoft.NETCore.App.Ref"; + version = "6.0.30"; + sha256 = "1wqqjhhlqz4dmijcx3kg3hnwq0s0jzqsddaksskzhq8avr4ziy18"; + }) + (fetchNuGet { + pname = "Microsoft.NETCore.App.Runtime.linux-arm64"; + version = "6.0.30"; + sha256 = "0xfhcig3gj3986rxp3dhnd8hvnj4nvyhz1fz7kpx342d3g53wb37"; + }) + (fetchNuGet { + pname = "Microsoft.NETCore.App.Runtime.linux-x64"; + version = "6.0.30"; + sha256 = "1s81sj8lnb8szqawxh3vc8wi815ln12cyhrl3f7hwcpay57xgswx"; + }) + (fetchNuGet { + pname = "Microsoft.NETCore.App.Runtime.osx-arm64"; + version = "6.0.30"; + sha256 = "0s71k92daakzwish65gmn4nniy6bf2hv34c0sb6m1hv3criqxmp4"; + }) + (fetchNuGet { + pname = "Microsoft.NETCore.App.Runtime.osx-x64"; + version = "6.0.30"; + sha256 = "0xybqg2wd240r1nm2vrbn2qbfqfnqsmxn1012zzwjn17wa2si9a1"; + }) (fetchNuGet { pname = "Microsoft.NETCore.Platforms"; version = "2.0.0"; @@ -71,11 +141,6 @@ version = "3.6.139"; sha256 = "0npcryhq3r0c2zi940jk39h13mzc4hyg7z8gm6jdmxi1aqv1vh8c"; }) - (fetchNuGet { - pname = "NETStandard.Library.Ref"; - version = "2.1.0"; - sha256 = "12n76gymxq715lkrw841vi5r84kx746cxxssp22pd08as75jzsj6"; - }) (fetchNuGet { pname = "Newtonsoft.Json"; version = "13.0.1"; @@ -188,8 +253,8 @@ }) (fetchNuGet { pname = "WoofWare.Myriad.Plugins"; - version = "2.1.42"; - sha256 = "0px46m734gsn1xa97111v1nwkyc2j52bw7z4bjdljzkmzzmnqa91"; + version = "2.1.44"; + sha256 = "0rp9hpkah60gd9x0ba2izr9ff1g7yhzv5a4pkhi5fbrwf5rpqpwx"; }) (fetchNuGet { pname = "WoofWare.Myriad.Plugins.Attributes";