Add runtime lookup (#94)

This commit is contained in:
Patrick Stevens
2025-05-16 20:25:40 +01:00
committed by GitHub
parent a013fc415e
commit 1b534018e9
13 changed files with 390 additions and 10 deletions

View File

@@ -31,7 +31,7 @@ jobs:
- name: Publish - name: Publish
run: dotnet publish Example run: dotnet publish Example
- name: Run example - name: Run example
run: ".\\Example\\bin\\Release\\net8.0\\win-x64\\Example.exe" run: ".\\Example\\bin\\Release\\net8.0\\Example.exe"
build: build:
strategy: strategy:
@@ -57,10 +57,14 @@ jobs:
run: nix develop --command dotnet build --no-restore --configuration ${{matrix.config}} run: nix develop --command dotnet build --no-restore --configuration ${{matrix.config}}
- name: Test - name: Test
run: nix develop --command dotnet test --no-build --verbosity normal --configuration ${{matrix.config}} run: nix develop --command dotnet test --no-build --verbosity normal --configuration ${{matrix.config}}
- name: Publish example - name: Publish example self-contained
run: nix develop --command dotnet publish --no-build --verbosity normal --configuration ${{matrix.config}} Example run: nix develop --command dotnet publish --self-contained --runtime linux-x64 --verbosity normal --configuration ${{matrix.config}} Example
- name: Run example self-contained - name: Run example self-contained
run: "./Example/bin/${{matrix.config}}/*/*/Example" run: "./Example/bin/${{matrix.config}}/net*/*-*/Example"
- name: Publish example non-self-contained
run: nix develop --command dotnet publish --verbosity normal --configuration ${{matrix.config}} Example
- name: Run example non-self-contained
run: "./Example/bin/${{matrix.config}}/net*/Example"
build-nix: build-nix:
runs-on: ubuntu-latest runs-on: ubuntu-latest

View File

@@ -3,7 +3,6 @@
<PropertyGroup> <PropertyGroup>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework> <TargetFramework>net8.0</TargetFramework>
<SelfContained>true</SelfContained>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

View File

@@ -1,6 +1,8 @@
namespace Example namespace Example
open System open System
open System.IO
open System.Reflection
open WoofWare.DotnetRuntimeLocator open WoofWare.DotnetRuntimeLocator
module Program = module Program =
@@ -18,4 +20,16 @@ module Program =
for f in info.Frameworks do for f in info.Frameworks do
Console.WriteLine $"Framework: %O{f}" Console.WriteLine $"Framework: %O{f}"
// Identify the runtime which would execute this DLL
let self = Assembly.GetExecutingAssembly().Location
let runtimeSearchDirs = DotnetRuntime.SelectForDll self
// For example, the System.Text.Json.dll which this DLL would load:
runtimeSearchDirs
|> Seq.tryPick (fun dir ->
let attempt = Path.Combine (dir, "System.Text.Json.dll")
if File.Exists attempt then Some attempt else None
)
|> Option.get
|> fun s -> Console.WriteLine $"System.Text.Json location: %s{s}"
0 0

View File

@@ -11,6 +11,11 @@ See [the example](Example/Program.fs).
let info = DotnetEnvironmentInfo.Get () let info = DotnetEnvironmentInfo.Get ()
// or, if you already know a path to the `dotnet` executable... // or, if you already know a path to the `dotnet` executable...
let info = DotnetEnvironmentInfo.GetSpecific "/path/to/dotnet" let info = DotnetEnvironmentInfo.GetSpecific "/path/to/dotnet"
// identify the directories containing the framework which would execute a given DLL
let dirsToSearch : string seq = DotnetRuntime.SelectForDll "/path/to/dll.dll"
// or, if you would be running with a specific `/path/to/dotnet exec /path/to/dll.dll`:
let dirsToSearch : string seq = DotnetRuntime.SelectForDll ("/path/to/dll.dll", "/path/to/dotnet")
``` ```
## Troubleshooting ## Troubleshooting

View File

@@ -0,0 +1,307 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.Json;
namespace WoofWare.DotnetRuntimeLocator;
/// <summary>
/// The result of a call to `DotnetRuntime.Select`.
/// This is `type DotnetRuntimeSelection = | Framework of DotnetEnvironmentFrameworkInfo | Sdk of
/// DotnetEnvironmentSdkInfo | Absent`.
/// </summary>
internal class DotnetRuntimeSelection
{
private readonly int _discriminator;
private readonly DotnetEnvironmentFrameworkInfo? _framework;
private readonly DotnetEnvironmentSdkInfo? _sdk;
/// <summary>
/// The constructor which means "We found the right runtime, and it's from this framework".
/// </summary>
/// <param name="framework">For example, </param>
public DotnetRuntimeSelection(DotnetEnvironmentFrameworkInfo framework)
{
_discriminator = 1;
_framework = framework;
}
/// <summary>
/// The constructor which means "We found the right runtime, and it's from this SDK".
/// </summary>
/// <param name="sdk">For example, </param>
public DotnetRuntimeSelection(DotnetEnvironmentSdkInfo sdk)
{
_discriminator = 2;
_sdk = sdk;
}
/// <summary>
/// The constructor which means "We were unable to find an appropriate runtime".
/// </summary>
public DotnetRuntimeSelection()
{
_discriminator = 3;
}
/// <summary>
/// Exhaustive match on this discriminated union.
/// </summary>
/// <param name="withFramework">If `this` is a `Framework`, call this continuation with its value.</param>
/// <param name="withSdk">If `this` is a `Sdk`, call this continuation with its value.</param>
/// <param name="withNone">If `this` represents the absence of a result, call this continuation.</param>
/// <returns>The result of the continuation which was called.</returns>
public TRet Visit<TRet>(Func<DotnetEnvironmentFrameworkInfo, TRet> withFramework,
Func<DotnetEnvironmentSdkInfo, TRet> withSdk,
Func<TRet> withNone)
{
return _discriminator switch
{
1 => withFramework.Invoke(_framework!),
2 => withSdk.Invoke(_sdk!),
3 => withNone.Invoke(),
_ => throw new InvalidOperationException($"unrecognised union discriminator %i{_discriminator}")
};
}
}
/// <summary>
/// Module to hold methods for automatically identifying a .NET runtime.
/// </summary>
public static class DotnetRuntime
{
/// <returns>For each requested runtime in the RuntimeOptions, the resolved place in which to find that runtime.</returns>
private static IReadOnlyDictionary<string, DotnetRuntimeSelection> SelectRuntime(RuntimeOptions options,
DotnetEnvironmentInfo env)
{
var rollForwardEnvVar = Environment.GetEnvironmentVariable("DOTNET_ROLL_FORWARD");
RollForward rollForward;
if (rollForwardEnvVar == null)
{
rollForward = options.RollForward ?? RollForward.Minor;
}
else
{
if (!Enum.TryParse(rollForwardEnvVar, out rollForward))
throw new ArgumentException(
$"Unable to parse the value of environment variable DOTNET_ROLL_FORWARD, which was: {rollForwardEnvVar}");
}
IReadOnlyDictionary<string, Version> desiredVersions;
if (options.IncludedFrameworks == null)
{
if (options.Framework == null)
{
if (options.Frameworks == null)
throw new InvalidDataException(
"Expected runtimeconfig.json file to have either a framework or frameworks entry, but it had neither");
desiredVersions = options.Frameworks.Select(x => (x.Name, new Version(x.Version))).GroupBy(x => x.Name)
.Select(data =>
{
var versions = (IReadOnlyList<Version>)data.Select(datum => datum.Item2).ToList();
if (versions.Count != 1)
{
var description = string.Join(", ", versions.Select(x => x.ToString()));
throw new InvalidDataException(
$"Unexpectedly had not-exactly-one version desired for framework {data.Key}: {description}");
}
return (data.Key, versions[0]);
})
.ToDictionary();
}
else
{
var result = new Dictionary<string, Version>
{ { options.Framework.Name, new Version(options.Framework.Version) } };
desiredVersions = result;
}
}
else
{
desiredVersions = options.IncludedFrameworks.Select(x => (x.Name, new Version(x.Version)))
.GroupBy(x => x.Name)
.Select(data =>
{
var versions = (IReadOnlyList<Version>)data.Select(datum => datum.Item2).ToList();
if (versions.Count != 1)
{
var description = string.Join(", ", versions.Select(x => x.ToString()));
throw new InvalidDataException(
$"Unexpectedly had not-exactly-one version desired for framework {data.Key}: {description}");
}
return (data.Key, versions[0]);
})
.ToDictionary();
}
IReadOnlyDictionary<string, IReadOnlyList<RuntimeOnDisk>> availableRuntimes = env
.Frameworks.SelectMany(availableFramework =>
{
var availableVersion = new Version(availableFramework.Version);
if (!desiredVersions.TryGetValue(availableFramework.Name, out var desiredVersion))
{
// we don't desire this framework at any version; skip it
return [];
}
if (availableVersion < desiredVersion)
{
// It's never desired to roll *backward*.
return [];
}
return new List<(string, DotnetEnvironmentFrameworkInfo)>
{ (availableFramework.Name, availableFramework) };
}).GroupBy(x => x.Item1)
.Select(group =>
{
var grouping = group.Select(x => new RuntimeOnDisk(x.Item2, new Version(x.Item2.Version))).ToList();
return (group.Key, (IReadOnlyList<RuntimeOnDisk>)grouping);
})
.ToDictionary();
switch (rollForward)
{
case RollForward.Minor:
{
return desiredVersions.Select(desired =>
{
if (!availableRuntimes.TryGetValue(desired.Key, out var available))
{
return (desired.Key, new DotnetRuntimeSelection());
}
if (ReferenceEquals(available, null))
{
throw new NullReferenceException("logic error: contents of non-nullable dict can't be null");
}
// If there's a correct major and minor version, take the latest patch.
var correctMajorAndMinorVersion =
available.Where(data =>
data.InstalledVersion.Major == desired.Value.Major &&
data.InstalledVersion.Minor == desired.Value.Minor).ToList();
if (correctMajorAndMinorVersion.Count > 0)
{
return (desired.Key, new DotnetRuntimeSelection(correctMajorAndMinorVersion.MaxBy(v => v.InstalledVersion)!.Installed));
}
// Otherwise roll forward to lowest higher minor version
var candidate = available.Where(data => data.InstalledVersion.Major == desired.Value.Major)
.MinBy(v => (v.InstalledVersion.Minor, -v.InstalledVersion.Build));
return (desired.Key, candidate == null ? new DotnetRuntimeSelection() : new DotnetRuntimeSelection(candidate.Installed));
}).ToDictionary();
}
case RollForward.Major:
{
throw new NotImplementedException();
}
case RollForward.LatestPatch:
{
return desiredVersions.Select(desired =>
{
var matches = availableRuntimes[desired.Key]
.Where(data =>
data.InstalledVersion.Minor == desired.Value.Minor &&
data.InstalledVersion.Major == desired.Value.Major).MaxBy(data => data.InstalledVersion);
return matches == null
? (desired.Key, new DotnetRuntimeSelection())
: (desired.Key, new DotnetRuntimeSelection(matches.Installed));
}).ToDictionary();
}
case RollForward.LatestMinor:
{
return desiredVersions.Select(desired =>
{
var matches = availableRuntimes[desired.Key]
.Where(data =>
data.InstalledVersion.Major == desired.Value.Major).MaxBy(data => data.InstalledVersion);
return matches == null
? (desired.Key, new DotnetRuntimeSelection())
: (desired.Key, new DotnetRuntimeSelection(matches.Installed));
}).ToDictionary();
}
case RollForward.LatestMajor:
{
return desiredVersions.Select(desired =>
{
var match = availableRuntimes[desired.Key].MaxBy(data => data.InstalledVersion);
return match == null ? (desired.Key, new DotnetRuntimeSelection()) : (desired.Key, new DotnetRuntimeSelection(match.Installed));
}).ToDictionary();
}
case RollForward.Disable:
{
return desiredVersions.Select(desired =>
{
var exactMatch = availableRuntimes[desired.Key]
.FirstOrDefault(available => available.InstalledVersion == desired.Value);
if (exactMatch != null)
{
return (desired.Key, new DotnetRuntimeSelection(exactMatch.Installed));
}
else
{
return (desired.Key, new DotnetRuntimeSelection());
}
}
).ToDictionary();
}
default:
{
throw new ArgumentOutOfRangeException();
}
}
}
/// <summary>
/// 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!
/// </summary>
/// <param name="dllPath">Path to an OutputType=Exe .dll file.</param>
/// <param name="dotnet">
/// Path to the `dotnet` binary which you would use e.g. in `dotnet exec` to run the DLL specified by
/// `dllPath`.
/// </param>
/// <returns>
/// An ordered collection of folder paths. When resolving any particular DLL during the execution of the input
/// DLL, search these folders; if a DLL name appears in multiple of these folders, the earliest is correct for that
/// DLL.
/// </returns>
public static IReadOnlyList<string> SelectForDll(string dllPath, string? dotnet = null)
{
if (!dllPath.EndsWith(".dll", StringComparison.Ordinal))
throw new ArgumentException(
$"SelectForDll requires the input DLL to have the extension '.dll'; provided: {dllPath}");
var dll = new FileInfo(dllPath);
var dllParentDir = dll.Directory ?? throw new ArgumentException($"dll path {dllPath} had no parent");
var name = dll.Name.Substring(0, dll.Name.Length - ".dll".Length);
var configFilePath = Path.Combine(dllParentDir.FullName, $"{name}.runtimeconfig.json");
// 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<RuntimeConfig>(File.ReadAllText(configFilePath)) ??
throw new NullReferenceException($"Failed to parse contents of file {configFilePath} as a runtime config");
var availableRuntimes = dotnet == null
? DotnetEnvironmentInfo.Get()
: DotnetEnvironmentInfo.GetSpecific(new FileInfo(dotnet));
var runtimes = SelectRuntime(runtimeConfig.RuntimeOptions, availableRuntimes);
return runtimes.SelectMany(runtime => runtime.Value.Visit(framework => new[] { $"{framework.Path}/{framework.Version}" },
sdk => [sdk.Path],
() => []
)).Prepend(dllParentDir.FullName).ToList();
}
private record RuntimeOnDisk(
DotnetEnvironmentFrameworkInfo Installed,
Version InstalledVersion);
}

View File

@@ -86,6 +86,12 @@ public record RuntimeOptions
[JsonPropertyName("frameworks")] [JsonPropertyName("frameworks")]
public IReadOnlyList<RuntimeConfigFramework>? Frameworks { get; init; } public IReadOnlyList<RuntimeConfigFramework>? Frameworks { get; init; }
/// <summary>
/// This is a self-contained executable which has these framework entirely contained next to it.
/// </summary>
[JsonPropertyName("includedFrameworks")]
public IReadOnlyList<RuntimeConfigFramework>? IncludedFrameworks { get; init; }
/// <summary> /// <summary>
/// This application advertises that it's fine with running under this roll-forward. /// This application advertises that it's fine with running under this roll-forward.
/// </summary> /// </summary>

View File

@@ -45,6 +45,8 @@ WoofWare.DotnetRuntimeLocator.DotnetEnvironmentSdkInfo.Path [property]: string
WoofWare.DotnetRuntimeLocator.DotnetEnvironmentSdkInfo.set_Path [method]: string -> unit WoofWare.DotnetRuntimeLocator.DotnetEnvironmentSdkInfo.set_Path [method]: string -> unit
WoofWare.DotnetRuntimeLocator.DotnetEnvironmentSdkInfo.set_Version [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.DotnetRuntime inherit obj
WoofWare.DotnetRuntimeLocator.DotnetRuntime.SelectForDll [static method]: (string, string) -> string System.Collections.Generic.IReadOnlyList
WoofWare.DotnetRuntimeLocator.RollForward inherit System.Enum WoofWare.DotnetRuntimeLocator.RollForward inherit System.Enum
WoofWare.DotnetRuntimeLocator.RollForward.Disable [static field]: WoofWare.DotnetRuntimeLocator.RollForward = Disable WoofWare.DotnetRuntimeLocator.RollForward.Disable [static field]: WoofWare.DotnetRuntimeLocator.RollForward = Disable
WoofWare.DotnetRuntimeLocator.RollForward.LatestMajor [static field]: WoofWare.DotnetRuntimeLocator.RollForward = LatestMajor WoofWare.DotnetRuntimeLocator.RollForward.LatestMajor [static field]: WoofWare.DotnetRuntimeLocator.RollForward = LatestMajor
@@ -79,13 +81,16 @@ WoofWare.DotnetRuntimeLocator.RuntimeOptions.Framework [property]: WoofWare.Dotn
WoofWare.DotnetRuntimeLocator.RuntimeOptions.Frameworks [property]: WoofWare.DotnetRuntimeLocator.RuntimeConfigFramework System.Collections.Generic.IReadOnlyList 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_Framework [method]: unit -> WoofWare.DotnetRuntimeLocator.RuntimeConfigFramework
WoofWare.DotnetRuntimeLocator.RuntimeOptions.get_Frameworks [method]: unit -> WoofWare.DotnetRuntimeLocator.RuntimeConfigFramework System.Collections.Generic.IReadOnlyList WoofWare.DotnetRuntimeLocator.RuntimeOptions.get_Frameworks [method]: unit -> WoofWare.DotnetRuntimeLocator.RuntimeConfigFramework System.Collections.Generic.IReadOnlyList
WoofWare.DotnetRuntimeLocator.RuntimeOptions.get_IncludedFrameworks [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_RollForward [method]: unit -> WoofWare.DotnetRuntimeLocator.RollForward System.Nullable
WoofWare.DotnetRuntimeLocator.RuntimeOptions.get_Tfm [method]: unit -> string WoofWare.DotnetRuntimeLocator.RuntimeOptions.get_Tfm [method]: unit -> string
WoofWare.DotnetRuntimeLocator.RuntimeOptions.IncludedFrameworks [property]: WoofWare.DotnetRuntimeLocator.RuntimeConfigFramework System.Collections.Generic.IReadOnlyList
WoofWare.DotnetRuntimeLocator.RuntimeOptions.op_Equality [static method]: (WoofWare.DotnetRuntimeLocator.RuntimeOptions, WoofWare.DotnetRuntimeLocator.RuntimeOptions) -> bool 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.op_Inequality [static method]: (WoofWare.DotnetRuntimeLocator.RuntimeOptions, WoofWare.DotnetRuntimeLocator.RuntimeOptions) -> bool
WoofWare.DotnetRuntimeLocator.RuntimeOptions.RollForward [property]: WoofWare.DotnetRuntimeLocator.RollForward System.Nullable WoofWare.DotnetRuntimeLocator.RuntimeOptions.RollForward [property]: WoofWare.DotnetRuntimeLocator.RollForward System.Nullable
WoofWare.DotnetRuntimeLocator.RuntimeOptions.set_Framework [method]: WoofWare.DotnetRuntimeLocator.RuntimeConfigFramework -> unit 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_Frameworks [method]: WoofWare.DotnetRuntimeLocator.RuntimeConfigFramework System.Collections.Generic.IReadOnlyList -> unit
WoofWare.DotnetRuntimeLocator.RuntimeOptions.set_IncludedFrameworks [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_RollForward [method]: WoofWare.DotnetRuntimeLocator.RollForward System.Nullable -> unit
WoofWare.DotnetRuntimeLocator.RuntimeOptions.set_Tfm [method]: string -> unit WoofWare.DotnetRuntimeLocator.RuntimeOptions.set_Tfm [method]: string -> unit
WoofWare.DotnetRuntimeLocator.RuntimeOptions.Tfm [property]: string WoofWare.DotnetRuntimeLocator.RuntimeOptions.Tfm [property]: string

View File

@@ -8,6 +8,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Compile Include="TestDotnetRuntime.fs" />
<Compile Include="TestRuntimeConfigParse.fs"/> <Compile Include="TestRuntimeConfigParse.fs"/>
<Compile Include="TestSurface.fs"/> <Compile Include="TestSurface.fs"/>
<Compile Include="TestDotnetEnvironmentInfo.fs"/> <Compile Include="TestDotnetEnvironmentInfo.fs"/>

View File

@@ -0,0 +1,36 @@
namespace WoofWare.DotnetRuntimeLocator.Test
open System.IO
open System.Reflection
open NUnit.Framework
open WoofWare.DotnetRuntimeLocator
[<TestFixture>]
module TestDotnetRuntime =
let inline shouldBeSome (x : 'a option) : unit =
match x with
| None -> failwith "option was None"
| Some _ -> ()
let inline shouldBeNone (x : 'a option) : unit =
match x with
| Some x -> failwith $"expectd None, but option was Some %O{x}"
| None -> ()
[<Test>]
let ``Test DotnetRuntime`` () =
let assy = Assembly.GetExecutingAssembly ()
let selectedRuntime = DotnetRuntime.SelectForDll assy.Location
let existsDll (name : string) =
selectedRuntime
|> Seq.tryPick (fun dir ->
let attempt = Path.Combine (dir, name)
if File.Exists attempt then Some attempt else None
)
existsDll "System.Private.CoreLib.dll" |> shouldBeSome
existsDll "System.Text.Json.dll" |> shouldBeSome
existsDll "Test.dll" |> shouldBeSome
existsDll "blah-de-blah.dll" |> shouldBeNone

View File

@@ -18,6 +18,7 @@ module TestSurface =
let ``Ensure public API is fully documented`` () = let ``Ensure public API is fully documented`` () =
DocCoverage.assertFullyDocumented assembly DocCoverage.assertFullyDocumented assembly
[<Test ; Explicit "Not yet published">] [<Test>]
let ``Ensure version is monotonic`` () = // https://github.com/nunit/nunit3-vs-adapter/issues/876
let ``EnsureVersionIsMonotonic`` () =
MonotonicVersion.validate assembly "WoofWare.DotnetRuntimeLocator" MonotonicVersion.validate assembly "WoofWare.DotnetRuntimeLocator"

View File

@@ -23,6 +23,7 @@
<Compile Include="DotnetEnvironmentFrameworkInfo.cs"/> <Compile Include="DotnetEnvironmentFrameworkInfo.cs"/>
<Compile Include="DotnetEnvironmentInfo.cs"/> <Compile Include="DotnetEnvironmentInfo.cs"/>
<Compile Include="DotnetEnvironmentSdkInfo.cs"/> <Compile Include="DotnetEnvironmentSdkInfo.cs"/>
<Compile Include="DotnetRuntime.cs" />
<Compile Include="InteropStructs.cs"/> <Compile Include="InteropStructs.cs"/>
<Compile Include="Boilerplate.cs"/> <Compile Include="Boilerplate.cs"/>
<Compile Include="RuntimeConfigOptions.cs"/> <Compile Include="RuntimeConfigOptions.cs"/>

View File

@@ -1,5 +1,5 @@
{ {
"version": "0.2", "version": "0.3",
"publicReleaseRefSpec": [ "publicReleaseRefSpec": [
"^refs/heads/main$" "^refs/heads/main$"
], ],

View File

@@ -48,10 +48,11 @@
fantomas = dotnetTool null "fantomas" (builtins.fromJSON (builtins.readFile ./.config/dotnet-tools.json)).tools.fantomas.version (builtins.head (builtins.filter (elem: elem.pname == "fantomas") deps)).hash; fantomas = dotnetTool null "fantomas" (builtins.fromJSON (builtins.readFile ./.config/dotnet-tools.json)).tools.fantomas.version (builtins.head (builtins.filter (elem: elem.pname == "fantomas") deps)).hash;
default = pkgs.buildDotnetModule { default = pkgs.buildDotnetModule {
inherit pname version dotnet-sdk dotnet-runtime; inherit pname version dotnet-sdk dotnet-runtime;
name = "WoofWare.Myriad.Plugins"; name = "WoofWare.DotnetRuntimeLocator";
src = ./.; src = ./.;
projectFile = "./WoofWare.DotnetRuntimeLocator/WoofWare.DotnetRuntimeLocator.csproj"; projectFile = "./WoofWare.DotnetRuntimeLocator/WoofWare.DotnetRuntimeLocator.csproj";
testProjectFile = "./WoofWare.DotnetRuntimeLocator/Test/Test.fsproj"; testProjectFile = "./WoofWare.DotnetRuntimeLocator/Test/Test.fsproj";
disabledTests = ["WoofWare.DotnetRuntimeLocator.Test.TestSurface.EnsureVersionIsMonotonic"];
nugetDeps = ./nix/deps.json; # `nix build .#default.fetch-deps && ./result nix/deps.json` nugetDeps = ./nix/deps.json; # `nix build .#default.fetch-deps && ./result nix/deps.json`
doCheck = true; doCheck = true;
}; };