mirror of
https://github.com/Smaug123/WoofWare.Whippet
synced 2025-10-07 16:58:39 +00:00
First release (#10)
Some checks are pending
.NET / build (Debug) (push) Waiting to run
.NET / build (Release) (push) Waiting to run
.NET / analyzers (push) Waiting to run
.NET / check-dotnet-format (push) Waiting to run
.NET / check-nix-format (push) Waiting to run
.NET / Check links (push) Waiting to run
.NET / Check flake (push) Waiting to run
.NET / nuget-pack (push) Waiting to run
.NET / expected-pack (push) Blocked by required conditions
.NET / check-accurate-generations (push) Waiting to run
.NET / all-required-checks-complete (push) Blocked by required conditions
.NET / nuget-publish (push) Blocked by required conditions
.NET / nuget-publish-fantomas (push) Blocked by required conditions
.NET / nuget-publish-json-plugin (push) Blocked by required conditions
.NET / nuget-publish-json-attrs (push) Blocked by required conditions
.NET / nuget-publish-argparser-plugin (push) Blocked by required conditions
.NET / nuget-publish-argparser-attrs (push) Blocked by required conditions
Some checks are pending
.NET / build (Debug) (push) Waiting to run
.NET / build (Release) (push) Waiting to run
.NET / analyzers (push) Waiting to run
.NET / check-dotnet-format (push) Waiting to run
.NET / check-nix-format (push) Waiting to run
.NET / Check links (push) Waiting to run
.NET / Check flake (push) Waiting to run
.NET / nuget-pack (push) Waiting to run
.NET / expected-pack (push) Blocked by required conditions
.NET / check-accurate-generations (push) Waiting to run
.NET / all-required-checks-complete (push) Blocked by required conditions
.NET / nuget-publish (push) Blocked by required conditions
.NET / nuget-publish-fantomas (push) Blocked by required conditions
.NET / nuget-publish-json-plugin (push) Blocked by required conditions
.NET / nuget-publish-json-attrs (push) Blocked by required conditions
.NET / nuget-publish-argparser-plugin (push) Blocked by required conditions
.NET / nuget-publish-argparser-attrs (push) Blocked by required conditions
This commit is contained in:
33
WoofWare.Whippet.App/AppContext.fs
Normal file
33
WoofWare.Whippet.App/AppContext.fs
Normal file
@@ -0,0 +1,33 @@
|
||||
namespace WoofWare.Whippet
|
||||
|
||||
open System
|
||||
open System.IO
|
||||
open System.Reflection
|
||||
|
||||
// Fix for https://github.com/Smaug123/unofficial-nunit-runner/issues/8
|
||||
// (This tells the DLL loader to look next to the input DLL for dependencies.)
|
||||
/// Context manager to set the AppContext.BaseDirectory of the executing DLL.
|
||||
type SetBaseDir (testDll : FileInfo) =
|
||||
let oldBaseDir = AppContext.BaseDirectory
|
||||
|
||||
let setData =
|
||||
let appContext = Type.GetType "System.AppContext"
|
||||
|
||||
if Object.ReferenceEquals (appContext, (null : obj)) then
|
||||
ignore<string * string>
|
||||
else
|
||||
|
||||
let setDataMethod =
|
||||
appContext.GetMethod ("SetData", BindingFlags.Static ||| BindingFlags.Public)
|
||||
|
||||
if Object.ReferenceEquals (setDataMethod, (null : obj)) then
|
||||
ignore<string * string>
|
||||
else
|
||||
|
||||
fun (k, v) -> setDataMethod.Invoke ((null : obj), [| k ; v |]) |> unbox<unit>
|
||||
|
||||
do setData ("APP_CONTEXT_BASE_DIRECTORY", testDll.Directory.FullName)
|
||||
|
||||
interface IDisposable with
|
||||
member _.Dispose () =
|
||||
setData ("APP_CONTEXT_BASE_DIRECTORY", oldBaseDir)
|
26
WoofWare.Whippet.App/Context.fs
Normal file
26
WoofWare.Whippet.App/Context.fs
Normal file
@@ -0,0 +1,26 @@
|
||||
namespace WoofWare.Whippet
|
||||
|
||||
open System.IO
|
||||
open System.Reflection
|
||||
open System.Runtime.Loader
|
||||
|
||||
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
|
219
WoofWare.Whippet.App/Program.fs
Normal file
219
WoofWare.Whippet.App/Program.fs
Normal file
@@ -0,0 +1,219 @@
|
||||
namespace WoofWare.Whippet
|
||||
|
||||
open System
|
||||
open System.IO
|
||||
open System.Reflection
|
||||
open Ionide.ProjInfo
|
||||
open Ionide.ProjInfo.Types
|
||||
|
||||
open WoofWare.Whippet.Core
|
||||
|
||||
type Args =
|
||||
{
|
||||
InputFile : FileInfo
|
||||
Plugins : FileInfo list
|
||||
}
|
||||
|
||||
type WhippetTarget =
|
||||
{
|
||||
InputSource : FileInfo
|
||||
GeneratedDest : FileInfo
|
||||
Params : Map<string, string>
|
||||
}
|
||||
|
||||
module Program =
|
||||
let parseArgs (argv : string array) =
|
||||
let inputFile = argv.[0] |> FileInfo
|
||||
|
||||
{
|
||||
InputFile = inputFile
|
||||
Plugins = argv.[1..] |> Seq.map FileInfo |> Seq.toList
|
||||
}
|
||||
|
||||
let getGenerateRawFromRaw (host : obj) : (RawSourceGenerationArgs -> string option) option =
|
||||
let pluginType = host.GetType ()
|
||||
|
||||
let generateRawFromRaw =
|
||||
match
|
||||
pluginType.GetMethod (
|
||||
"GenerateRawFromRaw",
|
||||
BindingFlags.Instance ||| BindingFlags.Public ||| BindingFlags.FlattenHierarchy
|
||||
)
|
||||
|> Option.ofObj
|
||||
with
|
||||
| None ->
|
||||
pluginType.GetInterfaces ()
|
||||
|> Array.tryPick (fun interf ->
|
||||
interf.GetMethod (
|
||||
"GenerateRawFromRaw",
|
||||
BindingFlags.Instance ||| BindingFlags.Public ||| BindingFlags.FlattenHierarchy
|
||||
)
|
||||
|> Option.ofObj
|
||||
)
|
||||
| Some generateRawFromRaw -> Some generateRawFromRaw
|
||||
|
||||
match generateRawFromRaw with
|
||||
| None -> None
|
||||
| Some generateRawFromRaw ->
|
||||
let pars = generateRawFromRaw.GetParameters ()
|
||||
|
||||
if pars.Length <> 1 then
|
||||
failwith
|
||||
$"Expected GenerateRawFromRaw to take exactly one parameter: a RawSourceGenerationArgs. Got %i{pars.Length}"
|
||||
|
||||
if pars.[0].ParameterType.FullName <> typeof<RawSourceGenerationArgs>.FullName then
|
||||
failwith
|
||||
$"Expected GenerateRawFromRaw to take exactly one parameter: a RawSourceGenerationArgs. Got %s{pars.[0].ParameterType.FullName}"
|
||||
|
||||
let retType = generateRawFromRaw.ReturnType
|
||||
|
||||
if retType <> typeof<string> then
|
||||
failwith
|
||||
$"Expected GenerateRawFromRaw method to have return type `string`, but was: %s{retType.FullName}"
|
||||
|
||||
fun args ->
|
||||
let args =
|
||||
Activator.CreateInstance (
|
||||
pars.[0].ParameterType,
|
||||
[| box args.FilePath ; box args.FileContents ; box args.Parameters |]
|
||||
)
|
||||
|
||||
generateRawFromRaw.Invoke (host, [| args |]) |> unbox<string> |> Option.ofObj
|
||||
|> Some
|
||||
|
||||
[<EntryPoint>]
|
||||
let main argv =
|
||||
let args = parseArgs argv
|
||||
|
||||
let projectDirectory = args.InputFile.Directory
|
||||
let toolsPath = Init.init projectDirectory None
|
||||
let defaultLoader = WorkspaceLoader.Create (toolsPath, [])
|
||||
|
||||
use subscription =
|
||||
defaultLoader.Notifications.Subscribe (fun msg ->
|
||||
match msg with
|
||||
| WorkspaceProjectState.Loading projectFilePath ->
|
||||
Console.Error.WriteLine $"Loading: %s{projectFilePath}"
|
||||
| WorkspaceProjectState.Loaded (loadedProject, _knownProjects, fromCache) ->
|
||||
let fromCache = if fromCache then " (from cache)" else ""
|
||||
Console.Error.WriteLine $"Loaded %s{loadedProject.ProjectFileName}%s{fromCache}"
|
||||
| WorkspaceProjectState.Failed (projectFilePath, errors) ->
|
||||
let errors = errors.ToString ()
|
||||
failwith $"Failed to load project %s{projectFilePath}: %s{errors}"
|
||||
)
|
||||
|
||||
let projectOptions =
|
||||
defaultLoader.LoadProjects [ args.InputFile.FullName ] |> Seq.toArray
|
||||
|
||||
let desiredProject =
|
||||
projectOptions
|
||||
|> Array.find (fun po -> po.ProjectFileName = args.InputFile.FullName)
|
||||
|
||||
let toGenerate =
|
||||
desiredProject.Items
|
||||
|> List.choose (fun (ProjectItem.Compile (_name, fullPath, metadata)) ->
|
||||
match metadata with
|
||||
| None -> None
|
||||
| Some metadata ->
|
||||
|
||||
match Map.tryFind "WhippetFile" metadata with
|
||||
| None -> None
|
||||
| Some myriadFile ->
|
||||
|
||||
let pars =
|
||||
metadata
|
||||
|> Map.toSeq
|
||||
|> Seq.choose (fun (key, value) ->
|
||||
if key.StartsWith ("WhippetParam", StringComparison.Ordinal) then
|
||||
Some (key.Substring "WhippetParam".Length, value)
|
||||
else
|
||||
None
|
||||
)
|
||||
|> Map.ofSeq
|
||||
|
||||
let inputSource =
|
||||
FileInfo (Path.Combine (Path.GetDirectoryName desiredProject.ProjectFileName, myriadFile))
|
||||
|
||||
let generatedDest = FileInfo fullPath
|
||||
|
||||
if inputSource.FullName = generatedDest.FullName then
|
||||
failwith $"Input source %s{inputSource.FullName} was identical to output path; aborting."
|
||||
|
||||
{
|
||||
GeneratedDest = generatedDest
|
||||
InputSource = inputSource
|
||||
Params = pars
|
||||
}
|
||||
|> Some
|
||||
)
|
||||
|
||||
let runtime =
|
||||
DotnetRuntime.locate (Assembly.GetExecutingAssembly().Location |> FileInfo)
|
||||
|
||||
let pluginDll =
|
||||
match args.Plugins with
|
||||
| [] -> failwith "must supply a plugin!"
|
||||
| [ plugin ] -> plugin
|
||||
| _ -> failwith "We don't yet support running more than one Whippet plugin in a given project file"
|
||||
|
||||
// TODO: should ideally loop over files, not plugins, so we fully generate a file before moving on to the next
|
||||
// one
|
||||
|
||||
Console.Error.WriteLine $"Loading plugin: %s{pluginDll.FullName}"
|
||||
|
||||
let ctx = Ctx (pluginDll, runtime)
|
||||
|
||||
let pluginAssembly = ctx.LoadFromAssemblyPath pluginDll.FullName
|
||||
|
||||
// We will look up any member called GenerateRawFromRaw and/or GenerateFromRaw.
|
||||
// It's your responsibility to decide whether to do anything with this call; you return null if you don't want
|
||||
// to do anything.
|
||||
// Alternatively, return the text you want to output.
|
||||
// We provide you with the input file contents.
|
||||
// GenerateRawFromRaw should return plain text.
|
||||
// GenerateFromRaw should return a Fantomas AST.
|
||||
let applicablePlugins =
|
||||
pluginAssembly.ExportedTypes
|
||||
|> Seq.choose (fun ty ->
|
||||
if
|
||||
ty.CustomAttributes
|
||||
|> Seq.exists (fun attr -> attr.AttributeType.Name = typeof<WhippetGeneratorAttribute>.Name)
|
||||
then
|
||||
Some (ty, Activator.CreateInstance ty)
|
||||
else
|
||||
None
|
||||
)
|
||||
|> Seq.toList
|
||||
|
||||
for item in toGenerate do
|
||||
use output = item.GeneratedDest.Open (FileMode.Create, FileAccess.Write)
|
||||
use outputWriter = new StreamWriter (output, leaveOpen = true)
|
||||
|
||||
for plugin, hostClass in applicablePlugins do
|
||||
match getGenerateRawFromRaw hostClass with
|
||||
| None -> ()
|
||||
| Some generateRawFromRaw ->
|
||||
let fileContents = File.ReadAllBytes item.InputSource.FullName
|
||||
|
||||
let args =
|
||||
{
|
||||
RawSourceGenerationArgs.FilePath = item.InputSource.FullName
|
||||
FileContents = fileContents
|
||||
Parameters = item.Params
|
||||
}
|
||||
|
||||
let result = generateRawFromRaw args
|
||||
|
||||
match result with
|
||||
| None
|
||||
| Some null -> ()
|
||||
| Some result ->
|
||||
Console.Error.WriteLine
|
||||
$"Writing output for generator %s{plugin.Name} to file %s{item.GeneratedDest.FullName}"
|
||||
|
||||
outputWriter.Write result
|
||||
outputWriter.Write "\n"
|
||||
|
||||
()
|
||||
|
||||
0
|
47
WoofWare.Whippet.App/RuntimeConfig.fs
Normal file
47
WoofWare.Whippet.App/RuntimeConfig.fs
Normal file
@@ -0,0 +1,47 @@
|
||||
namespace WoofWare.Whippet
|
||||
|
||||
open System
|
||||
|
||||
type FrameworkDescription =
|
||||
{
|
||||
Name : string
|
||||
Version : string
|
||||
}
|
||||
|
||||
type RuntimeOptions =
|
||||
{
|
||||
Tfm : string
|
||||
Framework : FrameworkDescription option
|
||||
Frameworks : FrameworkDescription list option
|
||||
RollForward : string option
|
||||
}
|
||||
|
||||
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"
|
103
WoofWare.Whippet.App/RuntimeConfigGen.fs
Normal file
103
WoofWare.Whippet.App/RuntimeConfigGen.fs
Normal file
@@ -0,0 +1,103 @@
|
||||
namespace WoofWare.Whippet
|
||||
|
||||
(* File originally generated by Myriad. *)
|
||||
|
||||
/// Module containing JSON parsing methods for the FrameworkDescription type
|
||||
[<RequireQualifiedAccess ; CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
module FrameworkDescription =
|
||||
/// Parse from a JSON node.
|
||||
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : FrameworkDescription =
|
||||
let arg_1 =
|
||||
(match node.["version"] with
|
||||
| null ->
|
||||
raise (
|
||||
System.Collections.Generic.KeyNotFoundException (
|
||||
sprintf "Required key '%s' not found on JSON object" ("version")
|
||||
)
|
||||
)
|
||||
| v -> v)
|
||||
.AsValue()
|
||||
.GetValue<System.String> ()
|
||||
|
||||
let arg_0 =
|
||||
(match node.["name"] with
|
||||
| null ->
|
||||
raise (
|
||||
System.Collections.Generic.KeyNotFoundException (
|
||||
sprintf "Required key '%s' not found on JSON object" ("name")
|
||||
)
|
||||
)
|
||||
| v -> v)
|
||||
.AsValue()
|
||||
.GetValue<System.String> ()
|
||||
|
||||
{
|
||||
Name = arg_0
|
||||
Version = arg_1
|
||||
}
|
||||
namespace WoofWare.Whippet
|
||||
|
||||
/// Module containing JSON parsing methods for the RuntimeOptions type
|
||||
[<RequireQualifiedAccess ; CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
module RuntimeOptions =
|
||||
/// Parse from a JSON node.
|
||||
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : RuntimeOptions =
|
||||
let arg_3 =
|
||||
match node.["rollForward"] with
|
||||
| null -> None
|
||||
| v -> v.AsValue().GetValue<System.String> () |> Some
|
||||
|
||||
let arg_2 =
|
||||
match node.["frameworks"] with
|
||||
| null -> None
|
||||
| v ->
|
||||
v.AsArray ()
|
||||
|> Seq.map (fun elt -> FrameworkDescription.jsonParse elt)
|
||||
|> List.ofSeq
|
||||
|> Some
|
||||
|
||||
let arg_1 =
|
||||
match node.["framework"] with
|
||||
| null -> None
|
||||
| v -> FrameworkDescription.jsonParse v |> Some
|
||||
|
||||
let arg_0 =
|
||||
(match node.["tfm"] with
|
||||
| null ->
|
||||
raise (
|
||||
System.Collections.Generic.KeyNotFoundException (
|
||||
sprintf "Required key '%s' not found on JSON object" ("tfm")
|
||||
)
|
||||
)
|
||||
| v -> v)
|
||||
.AsValue()
|
||||
.GetValue<System.String> ()
|
||||
|
||||
{
|
||||
Tfm = arg_0
|
||||
Framework = arg_1
|
||||
Frameworks = arg_2
|
||||
RollForward = arg_3
|
||||
}
|
||||
namespace WoofWare.Whippet
|
||||
|
||||
/// Module containing JSON parsing methods for the RuntimeConfig type
|
||||
[<RequireQualifiedAccess ; CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
module RuntimeConfig =
|
||||
/// Parse from a JSON node.
|
||||
let jsonParse (node : System.Text.Json.Nodes.JsonNode) : RuntimeConfig =
|
||||
let arg_0 =
|
||||
RuntimeOptions.jsonParse (
|
||||
match node.["runtimeOptions"] with
|
||||
| null ->
|
||||
raise (
|
||||
System.Collections.Generic.KeyNotFoundException (
|
||||
sprintf "Required key '%s' not found on JSON object" ("runtimeOptions")
|
||||
)
|
||||
)
|
||||
| v -> v
|
||||
)
|
||||
|
||||
{
|
||||
RuntimeOptions = arg_0
|
||||
}
|
104
WoofWare.Whippet.App/RuntimeLocator.fs
Normal file
104
WoofWare.Whippet.App/RuntimeLocator.fs
Normal file
@@ -0,0 +1,104 @@
|
||||
namespace WoofWare.Whippet
|
||||
|
||||
open System
|
||||
open System.IO
|
||||
open WoofWare.DotnetRuntimeLocator
|
||||
|
||||
/// Functions for locating .NET runtimes.
|
||||
[<RequireQualifiedAccess>]
|
||||
module DotnetRuntime =
|
||||
let private 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 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 ]
|
27
WoofWare.Whippet.App/WoofWare.Whippet.App.fsproj
Normal file
27
WoofWare.Whippet.App/WoofWare.Whippet.App.fsproj
Normal file
@@ -0,0 +1,27 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="RuntimeConfig.fs" />
|
||||
<Compile Include="RuntimeConfigGen.fs" />
|
||||
<Compile Include="AppContext.fs" />
|
||||
<Compile Include="RuntimeLocator.fs" />
|
||||
<Compile Include="Context.fs" />
|
||||
<Compile Include="Program.fs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="WoofWare.DotnetRuntimeLocator" Version="0.1.9" />
|
||||
<PackageReference Include="Ionide.ProjInfo" Version="0.67.0" PrivateAssets="compile" />
|
||||
<PackageReference Include="Microsoft.Build.Framework" Version="17.2.0" ExcludeAssets="runtime" PrivateAssets="all" />
|
||||
<PackageReference Include="NuGet.Frameworks" Version="6.11.1" ExcludeAssets="runtime" PrivateAssets="all" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\WoofWare.Whippet.Core\WoofWare.Whippet.Core.fsproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
Reference in New Issue
Block a user