Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update logic of resolving SdkReferenceAssemblies. #2639

Merged
merged 1 commit into from
Jan 30, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
138 changes: 105 additions & 33 deletions src/app/Fake.Runtime/SdkAssemblyResolver.fs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
module Fake.Runtime.SdkAssemblyResolver

open System
open System.IO
open System.Net
open System.Net.Http
open System.Threading
open System.Runtime.InteropServices
open Fake.Core
open Fake.IO.FileSystemOperators
open Fake.DotNet
Expand Down Expand Up @@ -124,41 +126,111 @@ type SdkAssemblyResolver(logLevel:Trace.VerboseLevel) =
resolved.Runtime.Version.ToString()

member this.SdkReferenceAssemblies() =
let dotnetHost =
match Environment.isUnix with
| true -> "dotnet"
| false -> "dotnet.exe"

let userInstallDir = DotNet.defaultUserInstallDir
let systemInstallDir = DotNet.defaultSystemInstallDir

let dotnetHostPath =
if not(String.isNullOrEmpty CustomDotNetHostPath)
then CustomDotNetHostPath
let isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
let isMac = RuntimeInformation.IsOSPlatform(OSPlatform.OSX)
let isLinux = RuntimeInformation.IsOSPlatform(OSPlatform.Linux)
let isUnix = isLinux || isMac

let dotnetBinaryName =
if Environment.isUnix then
"dotnet"
else
match File.Exists(userInstallDir </> dotnetHost) with
| true -> userInstallDir
| false -> systemInstallDir

"dotnet.exe"

let potentialDotnetHostEnvVars =
[ "DOTNET_HOST_PATH", id // is a full path to dotnet binary
"DOTNET_ROOT", (fun s -> Path.Combine(s, dotnetBinaryName)) // needs dotnet binary appended
"DOTNET_ROOT(x86)", (fun s -> Path.Combine(s, dotnetBinaryName)) ] // needs dotnet binary appended

let existingEnvVarValue envVarValue =
match envVarValue with
| null
| "" -> None
| other -> Some other

let tryFindFromEnvVar () =
potentialDotnetHostEnvVars
|> List.tryPick (fun (envVar, transformer) ->
match Environment.GetEnvironmentVariable envVar |> existingEnvVarValue with
| Some varValue -> Some(transformer varValue |> FileInfo)
| None -> None)

let PATHSeparator =
if isUnix then
':'
else
';'

let tryFindFromPATH () =
Environment
.GetEnvironmentVariable("PATH")
.Split(PATHSeparator, StringSplitOptions.RemoveEmptyEntries ||| StringSplitOptions.TrimEntries)
|> Array.tryPick (fun d ->
let fi = Path.Combine(d, dotnetBinaryName) |> FileInfo

if fi.Exists then
Some fi
else
None)

let tryFindFromDefaultDirs () =
let windowsPath = $"C:\\Program Files\\dotnet\\{dotnetBinaryName}"
let macosPath = $"/usr/local/share/dotnet/{dotnetBinaryName}"
let linuxPath = $"/usr/share/dotnet/{dotnetBinaryName}"

let tryFindFile p =
let f = FileInfo p

if f.Exists then
Some f
else
None

if isWindows then
tryFindFile windowsPath
else if isMac then
tryFindFile macosPath
else if isLinux then
tryFindFile linuxPath
else
None

/// <summary>
/// provides the path to the `dotnet` binary running this library, respecting various dotnet <see href="https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-environment-variables#dotnet_root-dotnet_rootx86%5D">environment variables</see>.
/// Also probes the PATH and checks the default installation locations
/// </summary>
let dotnetRoot =
if not(String.isNullOrEmpty CustomDotNetHostPath) then
Some CustomDotNetHostPath
else
tryFindFromEnvVar ()
|> Option.orElseWith tryFindFromPATH
|> Option.orElseWith tryFindFromDefaultDirs
|> Option.map (fun dotnetRoot -> dotnetRoot.Directory.FullName)

let referenceAssembliesPath =
dotnetHostPath
</> "packs"
</> "Microsoft.NETCore.App.Ref"
</> this.ResolveSdkRuntimeVersion()
</> "ref"
</> "net" + this.SdkVersionRaw

if this.LogLevel.PrintVerbose then
Trace.tracefn $"Resolved referenced SDK path: {referenceAssembliesPath}"
match Directory.Exists referenceAssembliesPath with
| true ->
Directory.GetFiles(
referenceAssembliesPath,
"*.dll"
)
|> Seq.toList
| false ->
failwithf "Could not find referenced assemblies in path: '%s', please check installed SDK and runtime versions" referenceAssembliesPath
dotnetRoot
|> Option.map (fun dotnetRoot ->
dotnetRoot
</> "packs"
</> "Microsoft.NETCore.App.Ref"
</> this.ResolveSdkRuntimeVersion()
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not something I want to tackle in this PR but this.ResolveSdkRuntimeVersion() is just going to throw if no global.json is present. This feels wrong, could the version not be extracted from running dotnet --version instead if no global.json is present?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agree here, we can't assume the presence of global.json. the safest path is to invoke the dotnet found from the new code you added and call --version. Proj-Info also does this here

Copy link
Contributor

@mclark1129 mclark1129 Mar 25, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why doesn't dotnet --version work for all cases? Why care if global.json exists or not?

</> "ref"
</> "net" + this.SdkVersionRaw)

match referenceAssembliesPath with
| None -> failwithf "Could not find referenced assemblies, please check installed SDK and runtime versions"
| Some referenceAssembliesPath ->
if this.LogLevel.PrintVerbose then
Trace.tracefn $"Resolved referenced SDK path: {referenceAssembliesPath}"
if Directory.Exists referenceAssembliesPath then
Directory.GetFiles(
referenceAssembliesPath,
"*.dll"
)
|> Seq.toList
else
failwithf "Could not find referenced assemblies in path: '%s', please check installed SDK and runtime versions" referenceAssembliesPath

member this.NetStandard20ReferenceAssemblies
(
Expand Down