Skip to content

Commit

Permalink
don't emit empty assembly references to package resolution file (dotn…
Browse files Browse the repository at this point in the history
  • Loading branch information
brettfo authored Oct 1, 2020
1 parent 83c6440 commit 8b361cf
Show file tree
Hide file tree
Showing 13 changed files with 106 additions and 54 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,9 @@
<Compile Include="..\..\utils\PathMap.fs">
<Link>Utilities\PathMap.fs</Link>
</Compile>
<Compile Include="..\..\utils\RidHelpers.fs">
<Link>Utilities\RidHelpers.fs</Link>
</Compile>
<Compile Include="..\range.fsi">
<Link>ErrorLogging\range.fsi</Link>
</Compile>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -210,11 +210,11 @@ $(PACKAGEREFERENCES)
<ItemGroup>
<ResolvedReferenceLines Remove='*' />
<ResolvedReferenceLines
Condition=" ('%(InteractiveResolvedFile.NugetPackageId)'!='FSharp.Core') or ('$(SCRIPTEXTENSION)'!='.fsx' and '%(InteractiveResolvedFile.NugetPackageId)'=='FSharp.Core')"
Condition="(@(InteractiveResolvedFile->Count()) &gt; 0) AND (('%(InteractiveResolvedFile.NugetPackageId)'!='FSharp.Core') or ('$(SCRIPTEXTENSION)'!='.fsx' and '%(InteractiveResolvedFile.NugetPackageId)'=='FSharp.Core'))"
Include='%(InteractiveResolvedFile.NugetPackageId),%(InteractiveResolvedFile.NugetPackageVersion),%(InteractiveResolvedFile.PackageRoot),%(InteractiveResolvedFile.FullPath),%(InteractiveResolvedFile.AssetType),%(InteractiveResolvedFile.IsNotImplementationReference),%(InteractiveResolvedFile.InitializeSourcePath),'
KeepDuplicates="false" />
<ResolvedReferenceLines
Condition="('%(NativeIncludeRoots.NugetPackageId)'!='FSharp.Core') or ('$(SCRIPTEXTENSION)'!='.fsx' and '%(NativeIncludeRoots.NugetPackageId)'=='FSharp.Core')"
Condition="(@(NativeIncludeRoots->Count()) &gt; 0) AND (('%(NativeIncludeRoots.NugetPackageId)'!='FSharp.Core') or ('$(SCRIPTEXTENSION)'!='.fsx' and '%(NativeIncludeRoots.NugetPackageId)'=='FSharp.Core'))"
Include='%(NativeIncludeRoots.NugetPackageId),%(NativeIncludeRoots.NugetPackageVersion),%(NativeIncludeRoots.PackageRoot),,%(NativeIncludeRoots.AssetType),,,%(NativeIncludeRoots.Path)'
KeepDuplicates="false" />
</ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,14 @@ open System.Reflection
[<AttributeUsage(AttributeTargets.Assembly ||| AttributeTargets.Class , AllowMultiple = false)>]
type DependencyManagerAttribute() = inherit System.Attribute()

/// The result of building the package resolution files.
type PackageBuildResolutionResult =
{ success: bool
projectPath: string
stdOut: string array
stdErr: string array
resolutionsFile: string option }

module internal Utilities =

/// Return a string array delimited by commas
Expand Down Expand Up @@ -202,7 +210,7 @@ module internal Utilities =

let workingDir = Path.GetDirectoryName projectPath

let succeeded, stdOut, stdErr =
let success, stdOut, stdErr =
if not (isRunningOnCoreClr) then
// The Desktop build uses "msbuild" to build
executeBuild msbuildExePath (arguments "-v:quiet") workingDir
Expand All @@ -211,5 +219,9 @@ module internal Utilities =
executeBuild dotnetHostPath (arguments "msbuild -v:quiet") workingDir

let outputFile = projectPath + ".resolvedReferences.paths"
let resultOutFile = if succeeded && File.Exists(outputFile) then Some outputFile else None
succeeded, stdOut, stdErr, resultOutFile
let resolutionsFile = if success && File.Exists(outputFile) then Some outputFile else None
{ success = success
projectPath = projectPath
stdOut = stdOut
stdErr = stdErr
resolutionsFile = resolutionsFile }
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,6 @@ module FSharpDependencyManager =
|> List.distinct
|> (fun l -> l, binLogPath)


/// The results of ResolveDependencies
type ResolveDependenciesResult (success: bool, stdOut: string array, stdError: string array, resolutions: string seq, sourceFiles: string seq, roots: string seq) =

Expand Down Expand Up @@ -195,12 +194,12 @@ type FSharpDependencyManager (outputDir:string option) =
sprintf """ #r "nuget:FSharp.Data";; // %s 'FSharp.Data' %s""" (SR.loadNugetPackage()) (SR.highestVersion())
|]

member _.ResolveDependencies(scriptExt:string, packageManagerTextLines: (string *string) seq, tfm: string, rid: string) : obj =
member _.PrepareDependencyResolutionFiles(scriptExt: string, packageManagerTextLines: (string * string) seq, targetFrameworkMoniker: string, runtimeIdentifier: string): PackageBuildResolutionResult =

let scriptExt, poundRprefix =
let scriptExt =
match scriptExt with
| ".csx" -> csxExt, "#r \""
| _ -> fsxExt, "#r @\""
| ".csx" -> csxExt
| _ -> fsxExt

let packageReferences, binLogPath =
packageManagerTextLines
Expand All @@ -214,39 +213,50 @@ type FSharpDependencyManager (outputDir:string option) =

let packageReferenceText = String.Join(Environment.NewLine, packageReferenceLines)

// Generate a project files
let projectPath = Path.Combine(scriptsPath, "Project.fsproj")

// Generate project files
let generateAndBuildProjectArtifacts =
let writeFile path body =
if not (generatedScripts.ContainsKey(body.GetHashCode().ToString())) then
emitFile path body

let projectPath = Path.Combine(scriptsPath, "Project.fsproj")

let generateProjBody =
generateProjectBody.Replace("$(TARGETFRAMEWORK)", tfm)
.Replace("$(RUNTIMEIDENTIFIER)", rid)
generateProjectBody.Replace("$(TARGETFRAMEWORK)", targetFrameworkMoniker)
.Replace("$(RUNTIMEIDENTIFIER)", runtimeIdentifier)
.Replace("$(PACKAGEREFERENCES)", packageReferenceText)
.Replace("$(SCRIPTEXTENSION)", scriptExt)

writeFile projectPath generateProjBody
buildProject projectPath binLogPath

generateAndBuildProjectArtifacts

member this.ResolveDependencies(scriptExt: string, packageManagerTextLines: (string * string) seq, targetFramework: string, runtimeIdentifier: string) : obj =
let poundRprefix =
match scriptExt with
| ".csx" -> "#r \""
| _ -> "#r @\""

let generateAndBuildProjectArtifacts =

let result, stdOut, stdErr, resolutionsFile = buildProject projectPath binLogPath
match resolutionsFile with
let resolutionResult = this.PrepareDependencyResolutionFiles(scriptExt, packageManagerTextLines, targetFramework, runtimeIdentifier)
match resolutionResult.resolutionsFile with
| Some file ->
let resolutions = getResolutionsFromFile file
let references = (findReferencesFromResolutions resolutions) |> Array.toSeq
let scripts =
let scriptPath = projectPath + scriptExt
let scriptPath = resolutionResult.projectPath + scriptExt
let scriptBody = makeScriptFromReferences references poundRprefix
emitFile scriptPath scriptBody
let loads = (findLoadsFromResolutions resolutions) |> Array.toList
List.concat [ [scriptPath]; loads] |> List.toSeq
let includes = (findIncludesFromResolutions resolutions) |> Array.toSeq

ResolveDependenciesResult(result, stdOut, stdErr, references, scripts, includes)
ResolveDependenciesResult(resolutionResult.success, resolutionResult.stdOut, resolutionResult.stdErr, references, scripts, includes)

| None ->
let empty = Seq.empty<string>
ResolveDependenciesResult(result, stdOut, stdErr, empty, empty, empty)
ResolveDependenciesResult(resolutionResult.success, resolutionResult.stdOut, resolutionResult.stdErr, empty, empty, empty)

generateAndBuildProjectArtifacts :> obj
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ type ResolveDependenciesResult =
/// The roots to package directories
member Roots: seq<string>

[<DependencyManagerAttribute>]
[<DependencyManagerAttribute>]
type FSharpDependencyManager =
new: outputDir:string option -> FSharpDependencyManager

Expand All @@ -39,4 +39,6 @@ type FSharpDependencyManager =

member HelpMessages:string[]

member ResolveDependencies: scriptExt:string * packageManagerTextLines: (string * string) seq * tfm: string * rid: string -> obj
member PrepareDependencyResolutionFiles: scriptExt: string * packageManagerTextLines: (string * string) seq * targetFrameworkMoniker: string * runtimeIdentifier: string -> PackageBuildResolutionResult

member ResolveDependencies: scriptExt: string * packageManagerTextLines: (string * string) seq * targetFrameworkMoniker: string * runtimeIdentifier: string -> obj
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ open System
open System.IO
open System.Reflection
open System.Runtime.InteropServices
open Internal.Utilities
open Internal.Utilities.FSharpEnvironment
open Microsoft.FSharp.Reflection
open System.Collections.Concurrent
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
<ItemGroup>
<EmbeddedText Include="DependencyManager.txt" />
<EmbeddedText Include="..\..\utils\UtilsStrings.txt" />
<Compile Include="..\..\utils\RidHelpers.fs" />
<Compile Include="..\..\utils\CompilerLocationUtils.fs" />
<Compile Include="AssemblyResolveHandler.fsi" />
<Compile Include="AssemblyResolveHandler.fs" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,38 +3,16 @@
namespace Microsoft.DotNet.DependencyManager

open System
open System.Collections.Generic
open System.IO
open System.Reflection
open System.Runtime.InteropServices
open Internal.Utilities
open Internal.Utilities.FSharpEnvironment

/// Signature for Native library resolution probe callback
/// host implements this, it's job is to return a list of package roots to probe.
type NativeResolutionProbe = delegate of Unit -> seq<string>

module internal RidHelpers =

// Computer valid dotnet-rids for this environment:
// https://docs.microsoft.com/en-us/dotnet/core/rid-catalog
//
// Where rid is: win, win-x64, win-x86, osx-x64, linux-x64 etc ...
let probingRids, baseRid, platformRid =
let processArchitecture = RuntimeInformation.ProcessArchitecture
let baseRid =
if RuntimeInformation.IsOSPlatform(OSPlatform.Windows) then "win"
elif RuntimeInformation.IsOSPlatform(OSPlatform.OSX) then "osx"
else "linux"
let platformRid =
match processArchitecture with
| Architecture.X64 -> baseRid + "-x64"
| Architecture.X86 -> baseRid + "-x86"
| Architecture.Arm64 -> baseRid + "-arm64"
| _ -> baseRid + "-arm"
[| "any"; baseRid; platformRid |], baseRid, platformRid

open RidHelpers

#if NETSTANDARD
open System.Runtime.Loader

Expand Down Expand Up @@ -109,7 +87,7 @@ type NativeDllResolveHandlerCoreClr (_nativeProbingRoots: NativeResolutionProbe)
if File.Exists(path) then
Some path
else
probingRids |> Seq.tryPick(fun rid -> probeForNativeLibrary root rid name)))
RidHelpers.probingRids |> Seq.tryPick(fun rid -> probeForNativeLibrary root rid name)))

match probe with
| Some path -> NativeAssemblyLoadContext.NativeLoadContext.LoadNativeLibrary(path)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,6 @@
namespace Microsoft.DotNet.DependencyManager

open System
open System.Collections.Generic

module internal RidHelpers =
val probingRids:string []
val baseRid:string
val platformRid:string


/// Signature for Native library resolution probe callback
/// host implements this, it's job is to return a list of package roots to probe.
Expand Down
23 changes: 23 additions & 0 deletions src/utils/RidHelpers.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
namespace Internal.Utilities

open System.Runtime.InteropServices

module internal RidHelpers =

// Computer valid dotnet-rids for this environment:
// https://docs.microsoft.com/en-us/dotnet/core/rid-catalog
//
// Where rid is: win, win-x64, win-x86, osx-x64, linux-x64 etc ...
let probingRids, baseRid, platformRid =
let processArchitecture = RuntimeInformation.ProcessArchitecture
let baseRid =
if RuntimeInformation.IsOSPlatform(OSPlatform.Windows) then "win"
elif RuntimeInformation.IsOSPlatform(OSPlatform.OSX) then "osx"
else "linux"
let platformRid =
match processArchitecture with
| Architecture.X64 -> baseRid + "-x64"
| Architecture.X86 -> baseRid + "-x86"
| Architecture.Arm64 -> baseRid + "-arm64"
| _ -> baseRid + "-arm"
[| "any"; baseRid; platformRid |], baseRid, platformRid
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
namespace FSharp.Compiler.Scripting.DependencyManager.UnitTests

open System
open System.Collections.Generic
open System.IO
open System.Reflection
open System.Runtime.InteropServices
Expand All @@ -13,8 +12,11 @@ open FSharp.Compiler.Interactive.Shell
open FSharp.Compiler.Scripting
open FSharp.Compiler.SourceCodeServices
open FSharp.Compiler.Scripting.UnitTests
open FSharp.DependencyManager.Nuget
open Microsoft.DotNet.DependencyManager

open Internal.Utilities

open Xunit

module Native =
Expand Down Expand Up @@ -743,3 +745,16 @@ x |> Seq.iter(fun r ->
let opt = script.Eval(text) |> getValue
Assert.True(sawExpectedOutput.WaitOne(TimeSpan.FromSeconds(5.0)), sprintf "Expected to see error sentinel value written\nexpected:%A\nactual:%A" expected lines)

[<Fact>]
member __.``Ensure resolutions file doesn't contain lines with only empty values``() =
use tempDir = getTempDir ()
let dpm = new FSharpDependencyManager(Some(tempDir.ToString()))
let resolutionResult = dpm.PrepareDependencyResolutionFiles(".fsx", [("r", "FParsec,Version=1.1.1")], "netcoreapp3.1", RidHelpers.platformRid)
let resolutionLines =
match resolutionResult.resolutionsFile with
| Some path -> File.ReadAllLines(path)
| None -> failwith "Expected resolutions file to be created."
let improperResolutionLines =
resolutionLines
|> Array.filter (fun l -> l.StartsWith(","))
Assert.Empty(improperResolutionLines)
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

<ItemGroup>
<Compile Include="ConsoleHelpers.fs" />
<Compile Include="$(FSharpSourcesRoot)\utils\RidHelpers.fs" />
<Compile Include="TestHelpers.fs" />
<Compile Include="DependencyManagerInteractiveTests.fs" />
<Compile Include="DependencyManagerLineParserTests.fs" />
Expand Down
13 changes: 13 additions & 0 deletions tests/FSharp.Compiler.Private.Scripting.UnitTests/TestHelpers.fs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace FSharp.Compiler.Scripting.UnitTests

open System
open System.IO
open FSharp.Compiler.Interactive.Shell
open FSharp.Compiler.SourceCodeServices

Expand All @@ -17,3 +18,15 @@ module TestHelpers =
| Error ex -> raise ex

let ignoreValue = getValue >> ignore

let getTempDir () =
let sysTempDir = Path.GetTempPath()
let customTempDirName = Guid.NewGuid().ToString("D")
let fullDirName = Path.Combine(sysTempDir, customTempDirName)
let dirInfo = Directory.CreateDirectory(fullDirName)
{ new Object() with
member __.ToString() = dirInfo.FullName
interface IDisposable with
member __.Dispose() =
dirInfo.Delete(true)
}

0 comments on commit 8b361cf

Please sign in to comment.