diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md
index 205b9848d71..476a23dfcac 100644
--- a/RELEASE_NOTES.md
+++ b/RELEASE_NOTES.md
@@ -1,3 +1,6 @@
+#### 5.0.0-alpha018 - 24.09.2017
+* BUGFIX: Cache loaded assemblies and redirect later calls.
+
#### 5.0.0-alpha017 - 23.09.2017
* BUGFIX: try to fallback to load framework assemblies from the default AssemblyLoadContext.
diff --git a/build.fsx b/build.fsx
index a5ec0f86acc..97137df365b 100644
--- a/build.fsx
+++ b/build.fsx
@@ -883,6 +883,15 @@ Target.Create "ReleaseDocs" (fun _ ->
open Fake.Api
Target.Create "FastRelease" (fun _ ->
+
+ Git.Staging.StageAll ""
+ Git.Commit.Commit "" (sprintf "Bump version to %s" release.NugetVersion)
+ let branch = Git.Information.getBranchName ""
+ Git.Branches.pushBranch "" "origin" branch
+
+ Git.Branches.tag "" release.NugetVersion
+ Git.Branches.pushTag "" "origin" release.NugetVersion
+
let token =
match Environment.environVarOrDefault "github_token" "" with
| s when not (System.String.IsNullOrWhiteSpace s) -> s
@@ -900,14 +909,6 @@ Target.Create "FastRelease" (fun _ ->
draftWithFiles
|> GitHub.releaseDraft
|> Async.RunSynchronously
-
- Git.Staging.StageAll ""
- Git.Commit.Commit "" (sprintf "Bump version to %s" release.NugetVersion)
- let branch = Git.Information.getBranchName ""
- Git.Branches.pushBranch "" "origin" branch
-
- Git.Branches.tag "" release.NugetVersion
- Git.Branches.pushTag "" "origin" release.NugetVersion
)
open System
diff --git a/src/app/Fake.Core.Targets/Target.fs b/src/app/Fake.Core.Targets/Target.fs
index f6ddebe9f4c..dede1a8130c 100644
--- a/src/app/Fake.Core.Targets/Target.fs
+++ b/src/app/Fake.Core.Targets/Target.fs
@@ -219,7 +219,7 @@ module Target =
/// Represents build errors
type BuildError = {
Target : string
- Message : string }
+ Error : exn }
//let mutable private errors = []
let private errorsVar = "Fake.Core.Targets.errors"
@@ -240,7 +240,7 @@ module Target =
//| BuildException(msg, errs) ->
// let errMsgs = errs |> List.map(fun e -> { Target = targetName; Message = e })
// { Target = targetName; Message = msg } :: (errMsgs @ errors)
- | _ -> { Target = targetName; Message = exn.ToString() } :: GetErrors())
+ | _ -> { Target = targetName; Error = exn } :: GetErrors())
let error e =
match e with
//| BuildException(msg, errs) -> msg + (if PrintStackTraceOnError then Environment.NewLine + e.StackTrace.ToString() else "")
@@ -291,7 +291,7 @@ module Target =
|> Seq.map (fun kv -> kv.Key)
|> Seq.iter (fun name ->
try
- let watch = new System.Diagnostics.Stopwatch()
+ let watch = System.Diagnostics.Stopwatch()
watch.Start()
Trace.tracefn "Starting BuildFailureTarget: %s" name
let target = Get name
@@ -370,7 +370,7 @@ module Target =
let internal WriteErrors () =
Trace.traceLine()
GetErrors()
- |> Seq.mapi(fun i e -> sprintf "%3d) %s" (i + 1) e.Message)
+ |> Seq.mapi(fun i e -> sprintf "%3d) %s" (i + 1) e.Error.Message)
|> Seq.iter Trace.traceError
/// Writes a build time report.
@@ -541,8 +541,13 @@ module Target =
match GetErrors() with
| [] -> ()
- | errors -> failwithf "A target failed: %A" errors
-
+ | errors ->
+ let targets = errors |> Seq.map (fun e -> e.Target) |> Seq.distinct
+ let targetStr = String.Join(", ", targets)
+ AggregateException(
+ sprintf "Targets '%s' failed." targetStr,
+ errors |> Seq.map (fun e -> e.Error))
+ |> raise
/// Registers a BuildFailureTarget (not activated).
let BuildFailureTarget name body =
Create name body
diff --git a/src/app/Fake.Runtime/CoreCache.fs b/src/app/Fake.Runtime/CoreCache.fs
index beccae74976..1d5698cea04 100644
--- a/src/app/Fake.Runtime/CoreCache.fs
+++ b/src/app/Fake.Runtime/CoreCache.fs
@@ -199,6 +199,7 @@ let loadAssembly (loadContext:AssemblyLoadContext) printDetails (assemInfo:Assem
if printDetails then tracefn "Unable to find assembly %A. (Error: %O)" assemInfo ex
None
+
let findAndLoadInRuntimeDeps (loadContext:AssemblyLoadContext) (name:AssemblyName) printDetails (runtimeDependencies:AssemblyInfo list) =
let strName = name.FullName
if printDetails then tracefn "Trying to resolve: %s" strName
@@ -219,33 +220,43 @@ let findAndLoadInRuntimeDeps (loadContext:AssemblyLoadContext) (name:AssemblyNam
| Some a ->
a.FullName = strName, (Some (None, a))
| None ->
- match runtimeDependencies |> List.tryFind (fun r -> r.FullName = strName) with
- | Some a ->
- true, loadAssembly loadContext printDetails a
- | _ ->
- let token = name.GetPublicKeyToken()
- match runtimeDependencies
- |> Seq.map (fun r -> AssemblyName(r.FullName), r)
- |> Seq.tryFind (fun (n, _) ->
- n.Name = name.Name &&
- (isNull token || // When null accept what we have.
- n.GetPublicKeyToken() = token)) with
- | Some (otherName, info) ->
- // Then the version matches and the public token is null we still accept this as perfect match
- (isNull token && otherName.Version = name.Version), loadAssembly loadContext printDetails info
- | _ ->
#if NETSTANDARD1_6
- // One last option is to try and load from the default app-context...
- try let assembly = AssemblyLoadContext.Default.LoadFromAssemblyName(name)
+ // Check if we can resolve to a framework assembly.
+ let result =
+ try let assembly = AssemblyLoadContext.Default.LoadFromAssemblyName(name)
+ let isFramework =
+ assembly.GetCustomAttributes()
+ |> Seq.exists (fun m -> m.Key = ".NETFrameworkAssembly")
+ if not isFramework then
+ None
+ else
let location =
try Some assembly.Location
with e ->
if printDetails then tracefn "Could not get Location from '%s': %O" strName e
None
- true, Some (location, assembly)
- with e ->
- if printDetails then tracefn "Could not find assembly in the default load-context: %s" strName
+ Some (location, assembly)
+ with e -> None
+ match result with
+ | Some r -> true, Some r
+ | None ->
#endif
+ if printDetails then tracefn "Could not find assembly in the default load-context: %s" strName
+ match runtimeDependencies |> List.tryFind (fun r -> r.FullName = strName) with
+ | Some a ->
+ true, loadAssembly loadContext printDetails a
+ | _ ->
+ let token = name.GetPublicKeyToken()
+ match runtimeDependencies
+ |> Seq.map (fun r -> AssemblyName(r.FullName), r)
+ |> Seq.tryFind (fun (n, _) ->
+ n.Name = name.Name &&
+ (isNull token || // When null accept what we have.
+ n.GetPublicKeyToken() = token)) with
+ | Some (otherName, info) ->
+ // Then the version matches and the public token is null we still accept this as perfect match
+ (isNull token && otherName.Version = name.Version), loadAssembly loadContext printDetails info
+ | _ ->
false, None
match result with
| Some (location, a) ->
@@ -260,22 +271,29 @@ let findAndLoadInRuntimeDeps (loadContext:AssemblyLoadContext) (name:AssemblyNam
if printDetails then tracefn "Could not resolve: %s" strName
null
+let findAndLoadInRuntimeDepsCached =
+ let assemblyCache = System.Collections.Concurrent.ConcurrentDictionary<_,Assembly>()
+ fun (loadContext:AssemblyLoadContext) (name:AssemblyName) printDetails (runtimeDependencies:AssemblyInfo list) ->
+ let mutable wasCalled = false
+ let result = assemblyCache.GetOrAdd(name.Name, (fun _ ->
+ wasCalled <- true
+ findAndLoadInRuntimeDeps loadContext name printDetails runtimeDependencies))
+ if not wasCalled then
+ let loadedName = result.GetName()
+ let isPerfectMatch = loadedName.Name = name.Name && loadedName.Version = name.Version
+ if not isPerfectMatch then
+ traceFAKE "Redirect assembly from '%A' to previous loaded assembly '%A'" name loadedName
+ else
+ if printDetails then tracefn "Redirect assembly load to previously loaded assembly: %A" loadedName
+ result
+
#if NETSTANDARD1_6
// See https://github.com/dotnet/coreclr/issues/6411
type FakeLoadContext (printDetails:bool, dependencies:AssemblyInfo list) =
inherit AssemblyLoadContext()
- //let basePath = System.AppContext.BaseDirectory
- //let references =
- // System.IO.Directory.GetFiles(basePath, "*.dll")
- // |> Seq.filter (fun r -> not (System.IO.Path.GetFileName(r).ToLowerInvariant().StartsWith("api-ms")))
- // |> Seq.choose (fun r ->
- // try Some (AssemblyInfo.ofLocation r)
- // with e -> None)
- // |> Seq.toList
- //let allReferences = references @ dependencies
let allReferences = dependencies
override x.Load(assem:AssemblyName) =
- findAndLoadInRuntimeDeps x assem printDetails allReferences
+ findAndLoadInRuntimeDepsCached x assem printDetails allReferences
#endif
let fakeDirectoryName = ".fake"