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

Bugfix/2641 resolve local sdk #1

Merged
merged 6 commits into from
Apr 26, 2022
Merged
Show file tree
Hide file tree
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"sdk" : {
"version": "6.0.100"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#r "paket:
storage: none
source https://api.nuget.org/v3/index.json
source ../../../release/dotnetcore
nuget Fake.Runtime prerelease
nuget FSharp.Core prerelease"

open Fake.Runtime

printfn "Starting Build."
Trace.traceFAKE "Some Info from FAKE"
printfn "Ending Build."
18 changes: 9 additions & 9 deletions src/app/Fake.DotNet.Cli/DotNet.fs
Original file line number Diff line number Diff line change
Expand Up @@ -661,10 +661,8 @@ module DotNet =
// make sure to write global.json if we did not read the version from it
// We need to do this as the SDK will use this file to select the actual version
// See https://github.com/fsharp/FAKE/pull/1963 and related discussions
if File.Exists globalJsonPath then
let readVersion = getSDKVersionFromGlobalJsonDir workDir
if readVersion <> version then failwithf "Existing global.json with a different version found!"
false
if File.Exists globalJsonPath
then false
else
let template = sprintf """{ "sdk": { "version": "%s" } }""" version
File.WriteAllText(globalJsonPath, template)
Expand Down Expand Up @@ -1838,14 +1836,16 @@ module DotNet =
let args = Args.toWindowsCommandLine(buildTemplateUninstallArgs param)
let result = exec (fun _ -> param.Common) "new" args

// we will check if the uninstall command has returned error and message is template is not found.
// if that is the case, then we will just redirect output as success and change process result to
// exit code of zero.
// If the process returns error (exit code != 0) then check to see if a message is
// that the template was not found. If this message exists, assume the process
// completed with success
let templateIsNotFoundToUninstall =
result.Results
|> List.exists(fun (result:ConsoleMessage) -> result.Message.Contains $"The template package '{templateName}' is not found.")

match templateIsNotFoundToUninstall with
| true -> ignore ""
let success = (result.ExitCode = 0) || templateIsNotFoundToUninstall
match success with
| true -> ()
| false -> failwithf $"dotnet new --uninstall failed with code %i{result.ExitCode}"

__.MarkSuccess()
210 changes: 106 additions & 104 deletions src/app/Fake.Runtime/SdkAssemblyResolver.fs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ type SdkAssemblyResolver(logLevel:Trace.VerboseLevel) =
let CustomDotNetHostPath = Environment.environVarOrDefault "FAKE_SDK_RESOLVER_CUSTOM_DOTNET_PATH" ""
let RuntimeResolverResolveMethod = Environment.environVarOrDefault "FAKE_SDK_RESOLVER_RUNTIME_VERSION_RESOLVE_METHOD" ""


member this.LogLevel = logLevel

member this.SdkVersionRaw = "6.0"
Expand All @@ -50,97 +49,26 @@ type SdkAssemblyResolver(logLevel:Trace.VerboseLevel) =
| Some version -> ReleaseVersion(version).Major.Equals(this.SdkVersion.Major)
| None -> false

member this.TryResolveSdkRuntimeVersionFromNetwork() =
if this.LogLevel.PrintVerbose then
Trace.tracefn "Trying to resolve runtime version from network.."
try
let sdkVersionReleases =
ProductCollection.GetAsync()
|> Async.AwaitTask
|> Async.RunSynchronously
|> List.ofSeq
|> List.find (fun product -> product.ProductVersion.Equals(this.SdkVersionRaw))

sdkVersionReleases.GetReleasesAsync()
|> Async.AwaitTask
|> Async.RunSynchronously
|> List.ofSeq
|> Some
with ex ->
Trace.traceError $"Could not get SDK runtime version from network due to: {ex.Message}"
None

member this.TryResolveSdkRuntimeVersionFromCache() =
if this.LogLevel.PrintVerbose then
Trace.tracefn "Trying to resolve runtime version from cache.."
try
System.Reflection.Assembly.GetExecutingAssembly().Location
|> Path.GetDirectoryName
</> "cachedDotnetSdkReleases.json"
|> Product.GetReleasesAsync
|> Async.AwaitTask
|> Async.RunSynchronously
|> List.ofSeq
|> Some
with ex ->
Trace.traceError $"Could not get SDK runtime version from cache due to: {ex.Message}"
None

member this.ResolveSdkRuntimeVersion() =

let resolvedSdkVersion =
this.SdkVersionFromGlobalJson
|> Option.get
|> ReleaseVersion

let resolutionMethod =
match not(String.isNullOrEmpty RuntimeResolverResolveMethod) with
| true ->
// for testing only!
match RuntimeResolverResolveMethod = "cache" with
| true -> this.TryResolveSdkRuntimeVersionFromCache()
| false -> this.TryResolveSdkRuntimeVersionFromNetwork()
| false ->
// this is the default case, we will try the network, if we could not, then we will reach for cached file.
this.TryResolveSdkRuntimeVersionFromNetwork()
|> Option.orElseWith(fun _ ->
this.TryResolveSdkRuntimeVersionFromCache()
)


let resolved =
resolutionMethod
|> Option.orElseWith(fun _ ->
failwithf $"Could not find a suitable runtime version matching SDK version: {resolvedSdkVersion.ToString()}"
)
|> Option.get
|> List.tryFind
(fun release ->
release.Sdks
|> List.ofSeq
|> List.exists (fun sdk -> sdk.Version.Equals(resolvedSdkVersion)))
|> Option.get

if this.LogLevel.PrintVerbose then
Trace.tracefn $"resolved runtime version: {resolved.Runtime.Version.ToString()}"
resolved.Runtime.Version.ToString()

member this.SdkReferenceAssemblies() =
member this.DotNetBinaryName =
if Environment.isUnix then
"dotnet"
else
"dotnet.exe"

/// <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>
member this.ResolveDotNetRoot() =
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
"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
"DOTNET_ROOT", (fun s -> Path.Combine(s, this.DotNetBinaryName)) // needs dotnet binary appended
"DOTNET_ROOT(x86)", (fun s -> Path.Combine(s, this.DotNetBinaryName)) ] // needs dotnet binary appended

let existingEnvVarValue envVarValue =
match envVarValue with
Expand Down Expand Up @@ -175,17 +103,17 @@ type SdkAssemblyResolver(logLevel:Trace.VerboseLevel) =
.GetEnvironmentVariable("PATH")
.Split(PATHSeparator, StringSplitOptions.RemoveEmptyEntries ||| StringSplitOptions.TrimEntries)
|> Array.tryPick (fun d ->
let fi = Path.Combine(d, dotnetBinaryName) |> FileInfo
let fi = Path.Combine(d, this.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 windowsPath = $"C:\\Program Files\\dotnet\\{this.DotNetBinaryName}"
let macosPath = $"/usr/local/share/dotnet/{this.DotNetBinaryName}"
let linuxPath = $"/usr/share/dotnet/{this.DotNetBinaryName}"

let tryFindFile p =
let f = FileInfo p
Expand All @@ -204,22 +132,96 @@ type SdkAssemblyResolver(logLevel:Trace.VerboseLevel) =
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.bind resolveFile
|> Option.map (fun dotnetRoot -> dotnetRoot.Directory.FullName)
if not(String.isNullOrEmpty CustomDotNetHostPath) then
Some CustomDotNetHostPath
else
tryFindFromEnvVar ()
|> Option.orElseWith tryFindFromPATH
|> Option.orElseWith tryFindFromDefaultDirs
|> Option.bind resolveFile
|> Option.map (fun dotnetRoot -> dotnetRoot.Directory.FullName)

member this.TryResolveSdkRuntimeVersionFromNetwork() =
if this.LogLevel.PrintVerbose then
Trace.tracefn "Trying to resolve runtime version from network.."
try
let sdkVersionReleases =
ProductCollection.GetAsync()
|> Async.AwaitTask
|> Async.RunSynchronously
|> List.ofSeq
|> List.find (fun product -> product.ProductVersion.Equals(this.SdkVersionRaw))

sdkVersionReleases.GetReleasesAsync()
|> Async.AwaitTask
|> Async.RunSynchronously
|> List.ofSeq
|> Some
with ex ->
Trace.traceError $"Could not get SDK runtime version from network due to: {ex.Message}"
None

member this.TryResolveSdkRuntimeVersionFromCache() =
if this.LogLevel.PrintVerbose then
Trace.tracefn "Trying to resolve runtime version from cache.."
try
System.Reflection.Assembly.GetExecutingAssembly().Location
|> Path.GetDirectoryName
</> "cachedDotnetSdkReleases.json"
|> Product.GetReleasesAsync
|> Async.AwaitTask
|> Async.RunSynchronously
|> List.ofSeq
|> Some
with ex ->
Trace.traceError $"Could not get SDK runtime version from cache due to: {ex.Message}"
None

member this.GetProductReleaseForSdk (version: ReleaseVersion) =
let net60releases =
if RuntimeResolverResolveMethod = "cache" then
// for testing only!
this.TryResolveSdkRuntimeVersionFromCache ()
else
// this is the default case, we will try the network, if we could not, then we will reach for cached file.
this.TryResolveSdkRuntimeVersionFromNetwork ()
|> Option.orElseWith(this.TryResolveSdkRuntimeVersionFromCache)

let sdkRelease (release: ProductRelease) =
release.Sdks
|> List.ofSeq
|> List.exists (fun sdk -> sdk.Version.Equals(version))

net60releases |> Option.bind (List.tryFind sdkRelease)

member this.ResolveSdkRuntimeVersion() =
let versionOptions (options: DotNet.VersionOptions) =
// If a custom CLI path is provided, configure the version command
// to use that path. This really only accomodates a test scenarios
// in which FAKE_SDK_RESOLVER_CUSTOM_DOTNET_PATH is set.
match this.ResolveDotNetRoot() with
| Some root ->
options.WithCommon(fun common ->
{ common with DotNetCliPath = root </> this.DotNetBinaryName } )
| None -> options

let sdkVersion = DotNet.getVersion versionOptions |> ReleaseVersion

match this.GetProductReleaseForSdk sdkVersion with
| Some release ->
let version = release.Runtime.Version.ToString()
if this.LogLevel.PrintVerbose then
Trace.trace $"Resolved runtime version: {version}"

version

| None ->
failwithf $"Could not find a suitable .NET 6 runtime version matching SDK version: {sdkVersion.ToString()}"

member this.SdkReferenceAssemblies() =

let referenceAssembliesPath =
dotnetRoot
this.ResolveDotNetRoot()
|> Option.map (fun dotnetRoot ->
dotnetRoot
</> "packs"
Expand Down
Loading