Add runtimeconfig types (#93)

This commit is contained in:
Patrick Stevens
2025-05-16 15:04:33 +01:00
committed by GitHub
parent bbdabd8206
commit a013fc415e
12 changed files with 241 additions and 43 deletions

View File

@@ -1,17 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<SelfContained>true</SelfContained>
</PropertyGroup>
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<SelfContained>true</SelfContained>
</PropertyGroup>
<ItemGroup>
<Compile Include="Program.fs"/>
</ItemGroup>
<ItemGroup>
<Compile Include="Program.fs"/>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\WoofWare.DotnetRuntimeLocator\WoofWare.DotnetRuntimeLocator.csproj" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\WoofWare.DotnetRuntimeLocator\WoofWare.DotnetRuntimeLocator.csproj"/>
</ItemGroup>
</Project>

View File

@@ -20,4 +20,6 @@ The easiest way to make sure we can find a `dotnet` is to have one on your PATH.
If you have a *very* strange setup, we may be unable to locate the `libhostfxr` library we use to find the runtimes.
In that case, you can supply the environment variable `WOOFWARE_DOTNET_LOCATOR_LIBHOSTFXR`,
which should be a full path to a `libhostfxr` DLL on your system.
(Normally this is in `/usr/share/dotnet/host/fxr/{runtime}/libhostfxr.so`; you must make sure your version is from runtime 6 or greater, because the required symbols were not added until then.)
(Normally this is in `/usr/share/dotnet/host/fxr/{runtime}/libhostfxr.so`;
you must make sure your version is from runtime 6 or greater,
because the required symbols were not added until then.)

View File

@@ -117,7 +117,10 @@ public record DotnetEnvironmentInfo(
/// <summary>
/// Get the environment information that is available to the specified `dotnet` executable.
/// </summary>
/// <param name="dotnetExe">A `dotnet` (or `dotnet.exe`) executable, e.g. one from /usr/bin/dotnet. Set this to null if you want us to just do our best.</param>
/// <param name="dotnetExe">
/// A `dotnet` (or `dotnet.exe`) executable, e.g. one from /usr/bin/dotnet. Set this to null if you
/// want us to just do our best.
/// </param>
/// <returns>Information about the environment available to the given executable.</returns>
/// <exception cref="Exception">Throws on any failure; handles nothing gracefully.</exception>
public static DotnetEnvironmentInfo GetSpecific(FileInfo? dotnetExe)
@@ -140,6 +143,7 @@ public record DotnetEnvironmentInfo(
dotnetParent = parent.FullName;
}
}
return CallDelegate(dotnetParent, f);
}
finally
@@ -169,10 +173,7 @@ public record DotnetEnvironmentInfo(
foreach (var component in path.Split(':'))
{
var dotnet = Path.Combine(component, "dotnet");
if (File.Exists(dotnet))
{
return new FileInfo(dotnet);
}
if (File.Exists(dotnet)) return new FileInfo(dotnet);
}
}

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Runtime.InteropServices;
namespace WoofWare.DotnetRuntimeLocator;

View File

@@ -0,0 +1,114 @@
using System.Collections.Generic;
using System.Text.Json.Serialization;
namespace WoofWare.DotnetRuntimeLocator;
/// <summary>
/// The type of a "framework" entry in the "runtimeOptions" setting of a runtimeconfig.json file.
/// </summary>
public record RuntimeConfigFramework
{
/// <summary>
/// For example, "Microsoft.NETCore.App".
/// </summary>
[JsonPropertyName("name")]
public required string Name { get; init; }
/// <summary>
/// For example, "9.0.0".
/// </summary>
[JsonPropertyName("version")]
public required string Version { get; init; }
}
/// <summary>
/// The value of e.g. `--roll-forward` or DOTNET_ROLL_FORWARD.
/// </summary>
public enum RollForward
{
/// <summary>
/// If the requested version is missing, roll forward to the lowest available minor version higher than requested.
/// If the requested version is available, silently use the LatestPatch policy.
/// Minor is the default if unspecified.
/// </summary>
Minor,
/// <summary>
/// If the requested version is missing, roll forward to the lowest available major version higher than requested,
/// at "lowest minor version" (the docs are unclear whether this means "lowest *available*", or "0").
/// If the requested version is available, silently use the Minor policy.
/// </summary>
Major,
/// <summary>
/// Roll forward to the highest patch version at exactly the requested major and minor versions.
/// </summary>
LatestPatch,
/// <summary>
/// Roll forward to the highest minor version, even if the requested minor version is available.
/// </summary>
LatestMinor,
/// <summary>
/// Roll forward to the highest available major version and highest available minor version at that major version,
/// even if the requested version is available.
/// </summary>
LatestMajor,
/// <summary>
/// Suppress all rolling forward: use only the exact specified version.
/// </summary>
Disable
}
/// <summary>
/// The contents of the "runtimeOptions" key in a runtimeconfig.json file.
/// </summary>
public record RuntimeOptions
{
/// Target framework moniker, such as "net9.0".
[JsonPropertyName("tfm")]
public required string Tfm { get; init; }
/// <summary>
/// The .NET runtime which this executable expects.
/// This is optional, because you can instead specify multiple Frameworks, in which case any of the frameworks
/// is acceptable (according to Claude; the MS docs are impenetrable as ever).
/// </summary>
[JsonPropertyName("framework")]
public RuntimeConfigFramework? Framework { get; init; }
/// <summary>
/// Any of these runtimes by itself would be enough to run this executable.
/// It's much more normal to see a single `framework` instead of this.
/// </summary>
[JsonPropertyName("frameworks")]
public IReadOnlyList<RuntimeConfigFramework>? Frameworks { get; init; }
/// <summary>
/// This application advertises that it's fine with running under this roll-forward.
/// </summary>
[JsonPropertyName("rollForward")]
public RollForward? RollForward { get; init; }
}
/// <summary>
/// The contents of a runtimeconfig.json file.
/// Note that this record doesn't capture everything: for example, "configProperties" might be present in the file,
/// but is not represented in this type.
/// </summary>
public record RuntimeConfig
{
/// <summary>
/// The contents of the file.
/// </summary>
[JsonPropertyName("runtimeOptions")]
public required RuntimeOptions RuntimeOptions { get; init; }
}
[JsonSourceGenerationOptions(WriteIndented = true)]
[JsonSerializable(typeof(RuntimeConfig))]
internal partial class SourceGenerationContext : JsonSerializerContext
{
}

View File

@@ -44,4 +44,48 @@ WoofWare.DotnetRuntimeLocator.DotnetEnvironmentSdkInfo.op_Inequality [static met
WoofWare.DotnetRuntimeLocator.DotnetEnvironmentSdkInfo.Path [property]: string
WoofWare.DotnetRuntimeLocator.DotnetEnvironmentSdkInfo.set_Path [method]: string -> unit
WoofWare.DotnetRuntimeLocator.DotnetEnvironmentSdkInfo.set_Version [method]: string -> unit
WoofWare.DotnetRuntimeLocator.DotnetEnvironmentSdkInfo.Version [property]: string
WoofWare.DotnetRuntimeLocator.DotnetEnvironmentSdkInfo.Version [property]: string
WoofWare.DotnetRuntimeLocator.RollForward inherit System.Enum
WoofWare.DotnetRuntimeLocator.RollForward.Disable [static field]: WoofWare.DotnetRuntimeLocator.RollForward = Disable
WoofWare.DotnetRuntimeLocator.RollForward.LatestMajor [static field]: WoofWare.DotnetRuntimeLocator.RollForward = LatestMajor
WoofWare.DotnetRuntimeLocator.RollForward.LatestMinor [static field]: WoofWare.DotnetRuntimeLocator.RollForward = LatestMinor
WoofWare.DotnetRuntimeLocator.RollForward.LatestPatch [static field]: WoofWare.DotnetRuntimeLocator.RollForward = LatestPatch
WoofWare.DotnetRuntimeLocator.RollForward.Major [static field]: WoofWare.DotnetRuntimeLocator.RollForward = Major
WoofWare.DotnetRuntimeLocator.RollForward.Minor [static field]: WoofWare.DotnetRuntimeLocator.RollForward = Minor
WoofWare.DotnetRuntimeLocator.RollForward.value__ [field]: int
WoofWare.DotnetRuntimeLocator.RuntimeConfig inherit obj, implements WoofWare.DotnetRuntimeLocator.RuntimeConfig System.IEquatable
WoofWare.DotnetRuntimeLocator.RuntimeConfig..ctor [constructor]: unit
WoofWare.DotnetRuntimeLocator.RuntimeConfig.<Clone>$ [method]: unit -> WoofWare.DotnetRuntimeLocator.RuntimeConfig
WoofWare.DotnetRuntimeLocator.RuntimeConfig.get_RuntimeOptions [method]: unit -> WoofWare.DotnetRuntimeLocator.RuntimeOptions
WoofWare.DotnetRuntimeLocator.RuntimeConfig.op_Equality [static method]: (WoofWare.DotnetRuntimeLocator.RuntimeConfig, WoofWare.DotnetRuntimeLocator.RuntimeConfig) -> bool
WoofWare.DotnetRuntimeLocator.RuntimeConfig.op_Inequality [static method]: (WoofWare.DotnetRuntimeLocator.RuntimeConfig, WoofWare.DotnetRuntimeLocator.RuntimeConfig) -> bool
WoofWare.DotnetRuntimeLocator.RuntimeConfig.RuntimeOptions [property]: WoofWare.DotnetRuntimeLocator.RuntimeOptions
WoofWare.DotnetRuntimeLocator.RuntimeConfig.set_RuntimeOptions [method]: WoofWare.DotnetRuntimeLocator.RuntimeOptions -> unit
WoofWare.DotnetRuntimeLocator.RuntimeConfigFramework inherit obj, implements WoofWare.DotnetRuntimeLocator.RuntimeConfigFramework System.IEquatable
WoofWare.DotnetRuntimeLocator.RuntimeConfigFramework..ctor [constructor]: unit
WoofWare.DotnetRuntimeLocator.RuntimeConfigFramework.<Clone>$ [method]: unit -> WoofWare.DotnetRuntimeLocator.RuntimeConfigFramework
WoofWare.DotnetRuntimeLocator.RuntimeConfigFramework.get_Name [method]: unit -> string
WoofWare.DotnetRuntimeLocator.RuntimeConfigFramework.get_Version [method]: unit -> string
WoofWare.DotnetRuntimeLocator.RuntimeConfigFramework.Name [property]: string
WoofWare.DotnetRuntimeLocator.RuntimeConfigFramework.op_Equality [static method]: (WoofWare.DotnetRuntimeLocator.RuntimeConfigFramework, WoofWare.DotnetRuntimeLocator.RuntimeConfigFramework) -> bool
WoofWare.DotnetRuntimeLocator.RuntimeConfigFramework.op_Inequality [static method]: (WoofWare.DotnetRuntimeLocator.RuntimeConfigFramework, WoofWare.DotnetRuntimeLocator.RuntimeConfigFramework) -> bool
WoofWare.DotnetRuntimeLocator.RuntimeConfigFramework.set_Name [method]: string -> unit
WoofWare.DotnetRuntimeLocator.RuntimeConfigFramework.set_Version [method]: string -> unit
WoofWare.DotnetRuntimeLocator.RuntimeConfigFramework.Version [property]: string
WoofWare.DotnetRuntimeLocator.RuntimeOptions inherit obj, implements WoofWare.DotnetRuntimeLocator.RuntimeOptions System.IEquatable
WoofWare.DotnetRuntimeLocator.RuntimeOptions..ctor [constructor]: unit
WoofWare.DotnetRuntimeLocator.RuntimeOptions.<Clone>$ [method]: unit -> WoofWare.DotnetRuntimeLocator.RuntimeOptions
WoofWare.DotnetRuntimeLocator.RuntimeOptions.Framework [property]: WoofWare.DotnetRuntimeLocator.RuntimeConfigFramework
WoofWare.DotnetRuntimeLocator.RuntimeOptions.Frameworks [property]: WoofWare.DotnetRuntimeLocator.RuntimeConfigFramework System.Collections.Generic.IReadOnlyList
WoofWare.DotnetRuntimeLocator.RuntimeOptions.get_Framework [method]: unit -> WoofWare.DotnetRuntimeLocator.RuntimeConfigFramework
WoofWare.DotnetRuntimeLocator.RuntimeOptions.get_Frameworks [method]: unit -> WoofWare.DotnetRuntimeLocator.RuntimeConfigFramework System.Collections.Generic.IReadOnlyList
WoofWare.DotnetRuntimeLocator.RuntimeOptions.get_RollForward [method]: unit -> WoofWare.DotnetRuntimeLocator.RollForward System.Nullable
WoofWare.DotnetRuntimeLocator.RuntimeOptions.get_Tfm [method]: unit -> string
WoofWare.DotnetRuntimeLocator.RuntimeOptions.op_Equality [static method]: (WoofWare.DotnetRuntimeLocator.RuntimeOptions, WoofWare.DotnetRuntimeLocator.RuntimeOptions) -> bool
WoofWare.DotnetRuntimeLocator.RuntimeOptions.op_Inequality [static method]: (WoofWare.DotnetRuntimeLocator.RuntimeOptions, WoofWare.DotnetRuntimeLocator.RuntimeOptions) -> bool
WoofWare.DotnetRuntimeLocator.RuntimeOptions.RollForward [property]: WoofWare.DotnetRuntimeLocator.RollForward System.Nullable
WoofWare.DotnetRuntimeLocator.RuntimeOptions.set_Framework [method]: WoofWare.DotnetRuntimeLocator.RuntimeConfigFramework -> unit
WoofWare.DotnetRuntimeLocator.RuntimeOptions.set_Frameworks [method]: WoofWare.DotnetRuntimeLocator.RuntimeConfigFramework System.Collections.Generic.IReadOnlyList -> unit
WoofWare.DotnetRuntimeLocator.RuntimeOptions.set_RollForward [method]: WoofWare.DotnetRuntimeLocator.RollForward System.Nullable -> unit
WoofWare.DotnetRuntimeLocator.RuntimeOptions.set_Tfm [method]: string -> unit
WoofWare.DotnetRuntimeLocator.RuntimeOptions.Tfm [property]: string

View File

@@ -1,27 +1,28 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
<NuGetAudit>false</NuGetAudit>
</PropertyGroup>
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
<NuGetAudit>false</NuGetAudit>
</PropertyGroup>
<ItemGroup>
<Compile Include="TestSurface.fs" />
<Compile Include="TestDotnetEnvironmentInfo.fs" />
</ItemGroup>
<ItemGroup>
<Compile Include="TestRuntimeConfigParse.fs"/>
<Compile Include="TestSurface.fs"/>
<Compile Include="TestDotnetEnvironmentInfo.fs"/>
</ItemGroup>
<ItemGroup>
<PackageReference Include="ApiSurface" Version="4.0.40" />
<PackageReference Include="FsUnit" Version="6.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0"/>
<PackageReference Include="NUnit" Version="4.1.0"/>
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0"/>
</ItemGroup>
<ItemGroup>
<PackageReference Include="ApiSurface" Version="4.0.40"/>
<PackageReference Include="FsUnit" Version="6.0.0"/>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0"/>
<PackageReference Include="NUnit" Version="4.1.0"/>
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0"/>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\WoofWare.DotnetRuntimeLocator.csproj" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\WoofWare.DotnetRuntimeLocator.csproj"/>
</ItemGroup>
</Project>

View File

@@ -0,0 +1,32 @@
namespace WoofWare.DotnetRuntimeLocator.Test
open System.IO
open System.Reflection
open System.Text.Json
open FsUnitTyped
open NUnit.Framework
open WoofWare.DotnetRuntimeLocator
[<TestFixture>]
module TestRuntimeConfigParse =
[<Test>]
let ``Can parse our own runtime config`` () =
let assy = Assembly.GetExecutingAssembly ()
let runtimeConfig =
Path.Combine (FileInfo(assy.Location).Directory.FullName, $"%s{assy.GetName().Name}.runtimeconfig.json")
|> File.ReadAllText
let actual = JsonSerializer.Deserialize<RuntimeConfig> runtimeConfig
let expected =
RuntimeConfig (
RuntimeOptions =
RuntimeOptions (
Tfm = "net8.0",
Framework = RuntimeConfigFramework (Name = "Microsoft.NETCore.App", Version = "8.0.0")
)
)
actual |> shouldEqual expected

View File

@@ -14,7 +14,7 @@ module TestSurface =
let ``Update API surface`` () =
ApiSurface.writeAssemblyBaseline assembly
[<Test>]
[<Test ; Explicit "Bug in ApiSurface: https://github.com/G-Research/ApiSurface/pull/111">]
let ``Ensure public API is fully documented`` () =
DocCoverage.assertFullyDocumented assembly

View File

@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<LangVersion>latest</LangVersion>
<EnableDefaultItems>false</EnableDefaultItems>
@@ -25,6 +25,7 @@
<Compile Include="DotnetEnvironmentSdkInfo.cs"/>
<Compile Include="InteropStructs.cs"/>
<Compile Include="Boilerplate.cs"/>
<Compile Include="RuntimeConfigOptions.cs"/>
<EmbeddedResource Include="SurfaceBaseline.txt"/>
<EmbeddedResource Include="version.json"/>
<None Include="..\README.md">

View File

@@ -1,6 +1,8 @@
{
"version": "0.1",
"publicReleaseRefSpec": ["^refs/heads/main$"],
"version": "0.2",
"publicReleaseRefSpec": [
"^refs/heads/main$"
],
"pathFilters": [
":!Test/",
":/WoofWare.DotnetRuntimeLocator",

View File

@@ -62,6 +62,7 @@
pkgs.alejandra
pkgs.nodePackages.markdown-link-check
pkgs.shellcheck
pkgs.xmlstarlet
];
};
});