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

Fix sdk resolver for net6 assemblies. Using offical .NET release JSON to get runtime version #2625

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
2 changes: 1 addition & 1 deletion .config/dotnet-tools.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
]
},
"fake-cli": {
"version": "5.20.4",
"version": "5.21.0-alpha003",
"commands": [
"fake"
]
Expand Down
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."
1 change: 1 addition & 0 deletions paket.dependencies
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ group netcorerunner
storage: none

nuget FSharp.Core
nuget Microsoft.Deployment.DotNet.Releases
nuget Paket.Core
nuget Mono.Cecil
nuget Microsoft.NETCore.App framework: netstandard1.6, netstandard2.0, netcoreapp1.1
Expand Down
38 changes: 21 additions & 17 deletions paket.lock

Large diffs are not rendered by default.

5 changes: 4 additions & 1 deletion src/app/Fake.DotNet.Cli/DotNet.fs
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,8 @@ module DotNet =
DryRun: bool
/// Do not update path variable
NoPath: bool
/// Command working directory
WorkingDirectory: string
}

/// Parameter default values.
Expand All @@ -243,6 +245,7 @@ module DotNet =
DebugSymbols = false
DryRun = false
NoPath = true
WorkingDirectory = "."
}

/// The a list of well-known versions to install
Expand Down Expand Up @@ -940,7 +943,7 @@ module DotNet =
match checkVersion with
| Some version ->
let passVersion = if fromGlobalJson then None else Some version
withGlobalJson "." passVersion (fun () ->
withGlobalJson param.WorkingDirectory passVersion (fun () ->
dotnetInstallations
|> Seq.tryFind (fun dotnet ->
try
Expand Down
2 changes: 1 addition & 1 deletion src/app/Fake.Runtime/CompileRunner.fs
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ let compile (context:FakeContext) outDll =
let co = context.Config.CompileOptions

let targetProfile =
if SdkAssemblyResolver().IsResolvedSdkVersionSameAsLTSVersion()
if SdkAssemblyResolver().IsSdkVersionFromGlobalJsonSameAsSdkVersion()
then "--targetprofile:netcore"
else "--targetprofile:netstandard"

Expand Down
2 changes: 1 addition & 1 deletion src/app/Fake.Runtime/FakeRuntime.fs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ let paketCachingProvider (config:FakeConfig) cacheDir (paketApi:Paket.Dependenci

#if DOTNETCORE
let sdkAssemblyResolver = SdkAssemblyResolver()
let framework = sdkAssemblyResolver.SdkVersion
let framework = sdkAssemblyResolver.PaketFrameworkIdentifier
let rid = Paket.Rid.Of(RuntimeInformation.RuntimeIdentifier)
let ridNotVersionSpecific =
let osShortName =
Expand Down
2 changes: 1 addition & 1 deletion src/app/Fake.Runtime/HashGeneration.fs
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ let getStringHash (s:string) =
let getCombinedString pathsAndContents compileOptions =
let sb = new System.Text.StringBuilder()
let inline appendSeq sequence =
for s in sequence do sb.AppendLine s |> ignore
for s:string in sequence do sb.AppendLine s |> ignore
appendSeq (getAllScriptContents pathsAndContents)
appendSeq (pathsAndContents |> Seq.map(fun x -> x.Location |> Path.normalizePath))
appendSeq compileOptions
Expand Down
103 changes: 75 additions & 28 deletions src/app/Fake.Runtime/SdkAssemblyResolver.fs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
module Fake.Runtime.SdkAssemblyResolver

open System.IO
open System.Runtime.InteropServices
open Fake.Core
open Fake.IO.FileSystemOperators
open Fake.DotNet
open Fake.Runtime
open Paket
open Microsoft.Deployment.DotNet.Releases

/// here we will pin Fake runner execution framework to .NET 6 as in `SdkVersion`
/// We will also try to resolve the current SDK that the runner is executing, if it is the same as pinned
Expand All @@ -15,42 +15,89 @@ open Paket
/// package extract them a and reference them.
type SdkAssemblyResolver() =
#if DOTNETCORE
let CustomDotNetHostPath = Environment.environVarOrDefault "FAKE_SDK_RESOLVER_CUSTOM_DOTNET_PATH" ""

member this.SdkVersion =
Paket.FrameworkIdentifier.DotNetFramework Paket.FrameworkVersion.V6
member this.SdkVersionRaw = "6.0"

member this.IsResolvedSdkVersionSameAsLTSVersion() =
match DotNet.tryGetSDKVersionFromGlobalJson () with
| Some version -> version.StartsWith "6" // this need to be kept in sync with SdkVersion number
member this.SdkVersion = ReleaseVersion("6.0.0")

member this.PaketFrameworkIdentifier =
FrameworkIdentifier.DotNetFramework (
FrameworkVersion.TryParse(this.SdkVersion.Major.ToString()).Value
)

member this.SdkVersionFromGlobalJson = DotNet.tryGetSDKVersionFromGlobalJson ()

member this.IsSdkVersionFromGlobalJsonSameAsSdkVersion() =
match this.SdkVersionFromGlobalJson with
| Some version -> ReleaseVersion(version).Major.Equals(this.SdkVersion.Major)
| None -> false

member this.ResolveSdkRuntimeVersion() =
let resolvedSdkVersion =
this.SdkVersionFromGlobalJson
|> Option.get
|> ReleaseVersion

let sdkVersionReleases =
ProductCollection.GetAsync()
|> Async.AwaitTask
|> Async.RunSynchronously
|> List.ofSeq
|> List.find (fun product -> product.ProductVersion.Equals(this.SdkVersionRaw))

let sdkVersionRelease =
sdkVersionReleases.GetReleasesAsync()
|> Async.AwaitTask
|> Async.RunSynchronously
|> List.ofSeq
|> List.tryFind
(fun release ->
release.Sdks
|> List.ofSeq
|> List.exists (fun sdk -> sdk.Version.Equals(resolvedSdkVersion)))
|> Option.orElseWith
(fun _ ->
failwithf "Could not find a sutable runtime version matching SDK version: %s" (resolvedSdkVersion.ToString()))
|> Option.get

sdkVersionRelease.Runtime.Version.ToString()

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

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

let dotnet6ReferenceAssembliesPath =
match File.Exists(userInstallDir </> fileName) with
| true -> userInstallDir
| false -> systemInstallDir

let dotnet6RuntimeVersion =
RuntimeInformation.FrameworkDescription.Replace(".NET ", "")
let dotnetHostPath =
if not(String.isNullOrEmpty CustomDotNetHostPath)
then CustomDotNetHostPath
else
match File.Exists(userInstallDir </> dotnetHost) with
| true -> userInstallDir
| false -> systemInstallDir

Directory.GetFiles(
dotnet6ReferenceAssembliesPath
let referenceAssembliesPath =
dotnetHostPath
</> "packs"
</> "Microsoft.NETCore.App.Ref"
</> dotnet6RuntimeVersion
</> this.ResolveSdkRuntimeVersion()
</> "ref"
</> "net6.0",
"*.dll"
)
|> Seq.toList
</> "net" + this.SdkVersionRaw

Trace.traceVerbose <| sprintf "Resolved referenced SDK path: %s" 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

member this.NetStandard20ReferenceAssemblies
(
Expand Down Expand Up @@ -131,13 +178,15 @@ type SdkAssemblyResolver() =

Directory.GetFiles(sdkDir, "*.dll") |> Seq.toList

member this.ResolveSdkReferenceAssemblies(groupName: Domain.GroupName, paketDependenciesFile: Lazy<Paket.DependenciesFile>) =
// here we will match for .NET 6 sdk from a global.json file. If found we will use
// .NET 6 runtime assemblies. Otherwise we will default to .Netstandard 2.0.3
match this.IsResolvedSdkVersionSameAsLTSVersion() with
member this.ResolveSdkReferenceAssemblies
(
groupName: Domain.GroupName,
paketDependenciesFile: Lazy<Paket.DependenciesFile>
) =
match this.IsSdkVersionFromGlobalJsonSameAsSdkVersion() with
| true ->
Trace.traceVerbose
<| (sprintf "%s" "Using .Net 6 assemblies")
<| (sprintf "Using .Net %i assemblies" this.SdkVersion.Major)

this.SdkReferenceAssemblies()
| false ->
Expand All @@ -151,6 +200,4 @@ type SdkAssemblyResolver() =
groupName,
paketDependenciesFile
)
#else
member this.IsSdkVersionDotNet6() = false
#endif
1 change: 1 addition & 0 deletions src/app/Fake.Runtime/paket.references
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
group netcorerunner

Paket.Core
nuget Microsoft.Deployment.DotNet.Releases
Mono.Cecil
FSharp.Core

Expand Down
5 changes: 2 additions & 3 deletions src/app/fake-cli/paket.references
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
group netcorerunner
FSharp.Core

Paket.Core
Mono.Cecil
Microsoft.NETCore.App
NETStandard.Library

Packaging.Targets
Packaging.Targets
Microsoft.Deployment.DotNet.Releases
107 changes: 77 additions & 30 deletions src/test/Fake.Core.IntegrationTests/Fake.DotNet.sdkAssemblyResolver.fs
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,16 @@ open System.IO
open Fake.IO.FileSystemOperators
open Expecto
open Fake.Core.IntegrationTests.TestHelpers
open Fake.Runtime

[<Tests>]
let tests =
testList
"Fake.DotNet.sdkAssemblyResolverTests"
[ testCase "Runner run script with NETStandard2.0 SDK assemblies"
<| fun _ ->
"Fake.DotNet.sdkAssemblyResolverTests" [
testCase "Runner run script with NETStandard2.0 SDK assemblies" <| fun _ ->
let result =
handleAndFormat
<| fun _ ->
fakeRunAndCheck
Ctx.Verbose
"reference_fake-runtime.fsx"
"reference_fake-runtime.fsx"
"core-runtime-reference-assemblies-netstandard20"
handleAndFormat <| fun _ ->
fakeRunAndCheck Ctx.Verbose "reference-assemblies.fsx" "reference-assemblies.fsx" "core-reference-assemblies-netstandard20"

let stdOut =
String.Join("\n", result.Messages).Trim()
Expand All @@ -36,26 +31,78 @@ let tests =
(sprintf "stdout should contain '%s', but was: '%s'" expectedNetStandardPathPortion stdOut)
|> Expect.isTrue (stdOut.Contains expectedNetStandardPathPortion)

testCase "Runner run script with .Net6 SDK assemblies"
<| fun _ ->
let result =
handleAndFormat
<| fun _ ->
fakeRunAndCheck
Ctx.Verbose
"reference_fake-runtime.fsx"
"reference_fake-runtime.fsx"
"core-runtime-reference-assemblies-net60"
testCase "Runner run script with 6.0.100-preview.3.21202.5 SDK version assemblies" <| fun _ ->
try
use d = createTestDir()
let installerDir = Path.Combine(d.Dir, "Temp Dir")
Directory.create installerDir
let preparedDir = Path.Combine(d.Dir, "Install Dir")
Directory.create preparedDir

let stdOut =
String.Join("\n", result.Messages).Trim()
DotNet.install (fun option ->
{ option with
InstallerOptions = fun o ->
{ option.InstallerOptions o with
CustomDownloadDir = Some installerDir }
ForceInstall = true
WorkingDirectory = scenarioTempPath "core-reference-assemblies-net60-preview"
CustomInstallDir = Some preparedDir
Channel = DotNet.CliChannel.Version 6 0
Version = DotNet.CliVersion.Version "6.0.100-preview.3.21202.5" })
|> ignore

Environment.setEnvironVar "FAKE_SDK_RESOLVER_CUSTOM_DOTNET_PATH" preparedDir

let result =
handleAndFormat <| fun _ ->
fakeRunAndCheck Ctx.Verbose "reference-assemblies.fsx" "reference-assemblies.fsx" "core-reference-assemblies-net60-preview"

let stdOut =
String.Join("\n", result.Messages).Trim()

let expectedNet6PathPortion = "packs"</>"Microsoft.NETCore.App.Ref"</>"6.0.0-preview.3.21201.4"</>"ref"</>"net6.0"

(sprintf "stdout should contain path like '%s', but was: '%s'" expectedNet6PathPortion stdOut)
|> Expect.isTrue (stdOut.Contains expectedNet6PathPortion)
finally
// clean up after the test run
Environment.setEnvironVar "FAKE_SDK_RESOLVER_CUSTOM_DOTNET_PATH" ""

testCase "Runner run script with 6.0.100 SDK version assemblies" <| fun _ ->
try
use d = createTestDir()
let installerDir = Path.Combine(d.Dir, "Temp Dir")
Directory.create installerDir
let preparedDir = Path.Combine(d.Dir, "Install Dir")
Directory.create preparedDir

DotNet.install (fun option ->
{ option with
InstallerOptions = fun o ->
{ option.InstallerOptions o with
CustomDownloadDir = Some installerDir }
ForceInstall = true
WorkingDirectory = scenarioTempPath "core-reference-assemblies-net60"
CustomInstallDir = Some preparedDir
Channel = DotNet.CliChannel.Version 6 0
Version = DotNet.CliVersion.Version "6.0.100" })
|> ignore

Environment.setEnvironVar "FAKE_SDK_RESOLVER_CUSTOM_DOTNET_PATH" preparedDir

let result =
handleAndFormat <| fun _ ->
fakeRunAndCheck Ctx.Verbose "reference-assemblies.fsx" "reference-assemblies.fsx" "core-reference-assemblies-net60"

let stdOut =
String.Join("\n", result.Messages).Trim()

let expectedNet6PathPortion = "packs"</>"Microsoft.NETCore.App.Ref"</>"6.0.0"</>"ref"</>"net6.0"

// the * is for runtime version
let expectedNet6PathPortion =
"[\s\S]*[\/|\\\\]packs[\/|\\\\]Microsoft[\/.|\\\\.]NETCore[\/.|\\\\.]App[\/.|\\\\.]Ref[\/|\\\\][\s\S]*[\/|\\\\]ref[\/|\\\\]net6[\/.|\\\\.]0[\/|\\\\]*"
(sprintf "stdout should contain path like '%s', but was: '%s'" expectedNet6PathPortion stdOut)
|> Expect.isTrue (stdOut.Contains expectedNet6PathPortion)
finally
// clean up after the test run
Environment.setEnvironVar "FAKE_SDK_RESOLVER_CUSTOM_DOTNET_PATH" ""

(sprintf
"stdout should contain path like '%s', but was: '%s'"
"packs/Microsoft.NETCore.App.Ref/*/ref/net6.0"
stdOut)
|> Expect.isTrue (Regex.IsMatch(stdOut, expectedNet6PathPortion)) ]
]