Obtain a compatible runtime from runconfig (#35)

This commit is contained in:
Patrick Stevens
2024-06-07 20:22:43 +01:00
committed by GitHub
parent 9a0eb1d8fc
commit 4c2045c3ec
7 changed files with 194 additions and 1 deletions

1
.gitignore vendored
View File

@@ -10,3 +10,4 @@ result
.analyzerpackages/
analysis.sarif
.direnv/
Generated*.fs

View File

@@ -1,8 +1,10 @@
namespace TestRunner
open System
open WoofWare.DotnetRuntimeLocator
open System.IO
open System.Reflection
open System.Runtime.Loader
// Fix for https://github.com/Smaug123/unofficial-nunit-runner/issues/8
// Set AppContext.BaseDirectory to where the test DLL is.
@@ -15,7 +17,91 @@ type SetBaseDir (testDll : FileInfo) =
member _.Dispose () =
AppContext.SetData ("APP_CONTEXT_BASE_DIRECTORY", oldBaseDir)
type Ctx (dll : FileInfo, runtimes : DirectoryInfo list) =
inherit AssemblyLoadContext ()
override this.Load (target : AssemblyName) : Assembly =
let path = Path.Combine (dll.Directory.FullName, $"%s{target.Name}.dll")
if File.Exists path then
this.LoadFromAssemblyPath path
else
runtimes
|> List.tryPick (fun di ->
let path = Path.Combine (di.FullName, $"%s{target.Name}.dll")
if File.Exists path then
this.LoadFromAssemblyPath path |> Some
else
None
)
|> Option.defaultValue null
module Program =
let selectRuntime
(config : RuntimeOptions)
(f : DotnetEnvironmentInfo)
: Choice<DotnetEnvironmentFrameworkInfo, DotnetEnvironmentSdkInfo> 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 desired = Version config.Framework.Version
match rollForward with
| RollForward.Minor ->
let available =
f.Frameworks
|> Seq.choose (fun fi ->
if fi.Name = config.Framework.Name then
Some (fi, Version fi.Version)
else
None
)
|> Seq.filter (fun (_, version) -> version.Major = desired.Major && version.Minor >= desired.Minor)
|> Seq.tryMinBy (fun (_, version) -> version.Minor, version.Build)
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 runtime.Path ]
| Some (Choice2Of2 sdk) -> [ dll.Directory ; DirectoryInfo sdk.Path ]
let main argv =
let testDll, filter =
match argv |> List.ofSeq with
@@ -32,7 +118,8 @@ module Program =
use _ = new SetBaseDir (testDll)
let assy = Assembly.LoadFrom testDll.FullName
let ctx = Ctx (testDll, locateRuntimes testDll)
let assy = ctx.LoadFromAssemblyPath testDll.FullName
let anyFailures =
assy.ExportedTypes

View File

@@ -0,0 +1,50 @@
namespace TestRunner
open System
open WoofWare.Myriad.Plugins
[<JsonParse>]
type FrameworkDescription =
{
Name : string
Version : string
}
[<JsonParse>]
type RuntimeOptions =
{
Tfm : string
Framework : FrameworkDescription
RollForward : string option
}
[<JsonParse>]
type RuntimeConfig =
{
RuntimeOptions : RuntimeOptions
}
[<RequireQualifiedAccess>]
type RollForward =
| Minor
| Major
| LatestPatch
| LatestMinor
| LatestMajor
| Disable
static member Parse (s : string) : RollForward =
if s.Equals ("minor", StringComparison.OrdinalIgnoreCase) then
RollForward.Minor
elif s.Equals ("major", StringComparison.OrdinalIgnoreCase) then
RollForward.Major
elif s.Equals ("latestpatch", StringComparison.OrdinalIgnoreCase) then
RollForward.LatestPatch
elif s.Equals ("latestminor", StringComparison.OrdinalIgnoreCase) then
RollForward.LatestMinor
elif s.Equals ("latestmajor", StringComparison.OrdinalIgnoreCase) then
RollForward.LatestMajor
elif s.Equals ("disable", StringComparison.OrdinalIgnoreCase) then
RollForward.Disable
else
failwith $"Could not interpret '%s{s}' as a RollForward"

22
TestRunner/Seq.fs Normal file
View File

@@ -0,0 +1,22 @@
namespace TestRunner
[<RequireQualifiedAccess>]
module internal Seq =
let tryMinBy (f : 'a -> 'b) (s : 'a seq) : 'a option =
use enum = s.GetEnumerator ()
if not (enum.MoveNext ()) then
None
else
let mutable answer = enum.Current
let mutable fAnswer = f enum.Current
while enum.MoveNext () do
let fNext = f enum.Current
if fNext < fAnswer then
answer <- enum.Current
Some answer

View File

@@ -15,9 +15,15 @@
<PackageTags>nunit;test;runner</PackageTags>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<WarnOn>FS3559</WarnOn>
<WoofWareMyriadPluginVersion>2.1.40</WoofWareMyriadPluginVersion>
</PropertyGroup>
<ItemGroup>
<Compile Include="RuntimeConfig.fs" />
<Compile Include="GeneratedRuntimeConfig.fs">
<MyriadFile>RuntimeConfig.fs</MyriadFile>
</Compile>
<Compile Include="Seq.fs" />
<Compile Include="Progress.fs" />
<Compile Include="Program.fs" />
<None Include="..\README.md">
@@ -32,6 +38,13 @@
<ItemGroup>
<PackageReference Include="Spectre.Console" Version="0.49.1" />
<PackageReference Include="WoofWare.DotnetRuntimeLocator" Version="0.1.2" />
<PackageReference Include="WoofWare.Myriad.Plugins.Attributes" Version="3.1.4" />
<PackageReference Include="Myriad.SDK" Version="0.8.3" />
<PackageReference Include="WoofWare.Myriad.Plugins" Version="$(WoofWareMyriadPluginVersion)" PrivateAssets="all" />
</ItemGroup>
<ItemGroup>
<MyriadSdkGenerator Include="$(NuGetPackageRoot)/woofware.myriad.plugins/$(WoofWareMyriadPluginVersion)/lib/net6.0/WoofWare.Myriad.Plugins.dll" />
</ItemGroup>
</Project>

0
TestRunner/myriad.toml Normal file
View File

View File

@@ -61,6 +61,11 @@
version = "17.10.0";
sha256 = "1bl471s7fx9jycr0cc8rylwf34mrvlg9qn1an6l86nisavfcyb7v";
})
(fetchNuGet {
pname = "Myriad.Sdk";
version = "0.8.3";
sha256 = "0qv78c5s5m04xb8h17nnn2ig26zcyya91k2dpj745cm1cbnzvvgc";
})
(fetchNuGet {
pname = "Nerdbank.GitVersioning";
version = "3.6.139";
@@ -176,6 +181,21 @@
version = "7.0.3";
sha256 = "0zjrnc9lshagm6kdb9bdh45dmlnkpwcpyssa896sda93ngbmj8k9";
})
(fetchNuGet {
pname = "WoofWare.DotnetRuntimeLocator";
version = "0.1.2";
sha256 = "0kwkq28ddzc0bpr22jmgcl8dhnhg776gf6l054rsxw8lrvpwhmv9";
})
(fetchNuGet {
pname = "WoofWare.Myriad.Plugins";
version = "2.1.40";
sha256 = "025lv42zjvqpr2di0iaqhqpricqary3l2a3cxgjjl0zxzflfbmx2";
})
(fetchNuGet {
pname = "WoofWare.Myriad.Plugins.Attributes";
version = "3.1.4";
sha256 = "06yw013f2qs2r8bxvja2c5kzbqc5knd3sc3pf6w5gaz4fbzwc2c3";
})
(fetchNuGet {
pname = "WoofWare.PrattParser";
version = "0.1.2";