Skip to content
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
Expand Up @@ -101,7 +101,7 @@ folder "InstallDir:Common7\IDE\CommonExtensions\Microsoft\FSharp"
file source="$(BinariesFolder)\FSharp.Core\$(Configuration)\netstandard2.0\FSharp.Core.dll" vs.file.ngen=yes vs.file.ngenArchitecture=All vs.file.ngenPriority=2
file source="$(BinariesFolder)\FSharp.Core\$(Configuration)\netstandard2.0\FSharp.Core.xml"
file source="$(BinariesFolder)\FSharp.Build\$(Configuration)\$(TargetFramework)\FSharp.Build.dll" vs.file.ngen=yes vs.file.ngenArchitecture=All vs.file.ngenPriority=2
file source="$(BinariesFolder)\Microsoft.DotNet.DependencyManager\$(Configuration)\net472\Microsoft.DotNet.DependencyManager.dll" vs.file.ngen=yes vs.file.ngenArchitecture=All vs.file.ngenPriority=2
file source="$(BinariesFolder)\Microsoft.DotNet.DependencyManager\$(Configuration)\netstandard2.0\Microsoft.DotNet.DependencyManager.dll" vs.file.ngen=yes vs.file.ngenArchitecture=All vs.file.ngenPriority=2
file source="$(BinariesFolder)\FSharp.Build\$(Configuration)\$(TargetFramework)\Microsoft.Build.Framework.dll"
file source="$(BinariesFolder)\FSharp.Build\$(Configuration)\$(TargetFramework)\Microsoft.Build.Tasks.Core.dll"
file source="$(BinariesFolder)\FSharp.Build\$(Configuration)\$(TargetFramework)\Microsoft.Build.Utilities.Core.dll"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,13 @@ module internal ProjectFile =
resolutions
|> Array.filter(fun r ->
not(String.IsNullOrEmpty(r.NugetPackageId) ||
String.IsNullOrEmpty(r.NativePath)) &&
Directory.Exists(r.NativePath))
|> Array.map(fun r -> r.NativePath)
String.IsNullOrEmpty(r.NativePath)))
|> Array.map(fun r ->
if Directory.Exists(r.NativePath) then Some (r.NativePath)
elif File.Exists(r.NativePath) then Some (Path.GetDirectoryName(r.NativePath).Replace('\\', '/'))
else None)
|> Array.filter(fun r -> r.IsSome)
|> Array.map(fun r -> r.Value)

Array.concat [|managedRoots; nativeRoots|] |> Array.distinct

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,6 @@ type ReflectionDependencyManagerProvider(theType: Type,
resolveDeps: MethodInfo option,
resolveDepsEx: MethodInfo option,
outputDir: string option) =

let instance = Activator.CreateInstance(theType, [| outputDir :> obj |])
let nameProperty = nameProperty.GetValue >> string
let keyProperty = keyProperty.GetValue >> string
Expand Down Expand Up @@ -226,7 +225,6 @@ type ReflectionDependencyManagerProvider(theType: Type,

/// Resolve the dependencies for the given arguments
member this.ResolveDependencies(scriptDir, mainScriptName, scriptName, scriptExt, packageManagerTextLines, tfm, rid): IResolveDependenciesResult =

// The ResolveDependencies method, has two signatures, the original signaature in the variable resolveDeps and the updated signature resolveDepsEx
// the resolve method can return values in two different tuples:
// (bool * string list * string list * string list)
Expand Down Expand Up @@ -275,10 +273,7 @@ type ReflectionDependencyManagerProvider(theType: Type,
type DependencyProvider (assemblyProbingPaths: AssemblyResolutionProbe, nativeProbingRoots: NativeResolutionProbe) =

// Note: creating a NativeDllResolveHandler currently installs process-wide handlers
let dllResolveHandler =
match nativeProbingRoots with
| null -> { new IDisposable with member _.Dispose() = () }
| _ -> new NativeDllResolveHandler(nativeProbingRoots) :> IDisposable
let dllResolveHandler = new NativeDllResolveHandler(nativeProbingRoots)

// Note: creating a AssemblyResolveHandler currently installs process-wide handlers
let assemblyResolveHandler =
Expand Down Expand Up @@ -384,7 +379,6 @@ type DependencyProvider (assemblyProbingPaths: AssemblyResolutionProbe, nativePr

/// Fetch a dependencymanager that supports a specific key
member _.TryFindDependencyManagerByKey (compilerTools: string seq, outputDir: string, reportError: ResolvingErrorReport, key: string): IDependencyManagerProvider =

try
RegisteredDependencyManagers compilerTools (Option.ofString outputDir) reportError
|> Map.tryFind key
Expand All @@ -407,7 +401,7 @@ type DependencyProvider (assemblyProbingPaths: AssemblyResolutionProbe, nativePr
[<Optional;DefaultParameterValue("")>]implicitIncludeDir: string,
[<Optional;DefaultParameterValue("")>]mainScriptName: string,
[<Optional;DefaultParameterValue("")>]fileName: string): IResolveDependenciesResult =

let key = (packageManager.Key, scriptExt, Seq.toArray packageManagerTextLines, executionTfm, executionRid, implicitIncludeDir, mainScriptName, fileName)

let result =
Expand All @@ -424,8 +418,10 @@ type DependencyProvider (assemblyProbingPaths: AssemblyResolutionProbe, nativePr
let e = stripTieWrapper e
Error (DependencyManager.SR.packageManagerError(e.Message))
))
match result with
| Ok res -> res
match result with
| Ok res ->
dllResolveHandler.RefreshPathsInEnvironment(res.Roots)
res
| Error (errorNumber, errorData) ->
reportError.Invoke(ErrorReportType.Error, errorNumber, errorData)
ReflectionDependencyManagerProvider.MakeResultFromFields(false, arrEmpty, arrEmpty, seqEmpty, seqEmpty, seqEmpty)
Expand All @@ -436,5 +432,5 @@ type DependencyProvider (assemblyProbingPaths: AssemblyResolutionProbe, nativePr

// Unregister everything
registeredDependencyManagers <- None
dllResolveHandler.Dispose()
(dllResolveHandler :> IDisposable).Dispose()
assemblyResolveHandler.Dispose()
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,8 @@

<PropertyGroup>
<OutputType>Library</OutputType>
<TargetFrameworks>netstandard2.0;net472</TargetFrameworks>
<TargetFrameworks>netstandard2.0</TargetFrameworks>
<IsPackable>true</IsPackable>
<TargetFrameworks Condition="'$(OS)' == 'Unix'">netstandard2.0</TargetFrameworks>
<AssemblyName>Microsoft.DotNet.DependencyManager</AssemblyName>
<NoWarn>$(NoWarn);45;55;62;75;1204</NoWarn>
<AllowCrossTargeting>true</AllowCrossTargeting>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace Microsoft.DotNet.DependencyManager

open System
open System.Collections.Concurrent
open System.IO
open System.Reflection
open System.Runtime.InteropServices
Expand All @@ -13,7 +14,6 @@ open Internal.Utilities.FSharpEnvironment
/// host implements this, it's job is to return a list of package roots to probe.
type NativeResolutionProbe = delegate of Unit -> seq<string>

#if NETSTANDARD
open System.Runtime.Loader

// Cut down AssemblyLoadContext, for loading native libraries
Expand All @@ -28,7 +28,6 @@ type NativeAssemblyLoadContext () =

static member NativeLoadContext = new NativeAssemblyLoadContext()


/// Type that encapsulates Native library probing for managed packages
type NativeDllResolveHandlerCoreClr (nativeProbingRoots: NativeResolutionProbe) =
let probingFileNames (name: string) =
Expand Down Expand Up @@ -65,7 +64,6 @@ type NativeDllResolveHandlerCoreClr (nativeProbingRoots: NativeResolutionProbe)
|]

let _resolveUnmanagedDll (_: Assembly) (name: string): IntPtr =

// Enumerate probing roots looking for a dll that matches the probing name in the probed locations
let probeForNativeLibrary root rid name =
// Look for name in root
Expand All @@ -79,7 +77,7 @@ type NativeDllResolveHandlerCoreClr (nativeProbingRoots: NativeResolutionProbe)
let probe =
match nativeProbingRoots with
| null -> None
| _ ->
| _ ->
nativeProbingRoots.Invoke()
|> Seq.tryPick(fun root ->
probingFileNames name |> Seq.tryPick(fun name ->
Expand All @@ -98,28 +96,54 @@ type NativeDllResolveHandlerCoreClr (nativeProbingRoots: NativeResolutionProbe)
let eventInfo = typeof<AssemblyLoadContext>.GetEvent("ResolvingUnmanagedDll")
let handler = Func<Assembly, string, IntPtr> (_resolveUnmanagedDll)

do if not (isNull eventInfo) then eventInfo.AddEventHandler(AssemblyLoadContext.Default, handler)
do
if not (isNull eventInfo) then
eventInfo.AddEventHandler(AssemblyLoadContext.Default, handler)

interface IDisposable with
member _x.Dispose() =
if not (isNull eventInfo) then
eventInfo.RemoveEventHandler(AssemblyLoadContext.Default, handler)
()

#endif

type NativeDllResolveHandler (_nativeProbingRoots: NativeResolutionProbe) =

type NativeDllResolveHandler (nativeProbingRoots: NativeResolutionProbe) =
let handler:IDisposable option =
#if NETSTANDARD
if isRunningOnCoreClr then
Some (new NativeDllResolveHandlerCoreClr(_nativeProbingRoots) :> IDisposable)
Some (new NativeDllResolveHandlerCoreClr(nativeProbingRoots) :> IDisposable)
else
#endif
None

let appendSemiColon (p:string) =
if not(p.EndsWith(";", StringComparison.OrdinalIgnoreCase)) then
p + ";"
else
p

let addedPaths = ConcurrentBag<string>()

let addProbeToProcessPath probePath =
let probe = appendSemiColon probePath
let path = appendSemiColon (Environment.GetEnvironmentVariable("PATH"))
if not (path.Contains(probe)) then
Environment.SetEnvironmentVariable("PATH", path + probe)
addedPaths.Add probe

let removeProbeFromProcessPath probePath =
if not(String.IsNullOrWhiteSpace(probePath)) then
let probe = appendSemiColon probePath
let path = appendSemiColon (Environment.GetEnvironmentVariable("PATH"))
if path.Contains(probe) then Environment.SetEnvironmentVariable("PATH", path.Replace(probe, ""))

member internal _.RefreshPathsInEnvironment(roots: string seq) =
for probePath in roots do
addProbeToProcessPath probePath

interface IDisposable with
member _.Dispose() =
match handler with
| None -> ()
| Some handler -> handler.Dispose()

let mutable probe:string = null
while (addedPaths.TryTake(&probe)) do
removeProbeFromProcessPath probe
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ type NativeResolutionProbe = delegate of Unit -> seq<string>
type NativeDllResolveHandler =

/// Construct a new NativeDllResolveHandler
new: _nativeProbingRoots: NativeResolutionProbe -> NativeDllResolveHandler
new: nativeProbingRoots: NativeResolutionProbe -> NativeDllResolveHandler

member internal RefreshPathsInEnvironment: string seq -> unit

interface IDisposable
Original file line number Diff line number Diff line change
Expand Up @@ -657,6 +657,55 @@ x |> Seq.iter(fun r ->
try Assembly.Load("NoneSuchAssembly") |> ignore with _ -> ()
Assert.False (assemblyFound, "Invoke the assemblyProbingRoots callback -- Error the AssemblyResolve still fired ")

[<Fact>]
member __.``Verify that Dispose cleans up the native paths added``() =
let nativeProbingRoots () = Seq.empty<string>

let appendSemiColon (p:string) =
if not(p.EndsWith(";", StringComparison.OrdinalIgnoreCase)) then
p + ";"
else
p

let reportError =
let report errorType code message =
match errorType with
| ErrorReportType.Error -> printfn "PackageManagementError %d : %s" code message
| ErrorReportType.Warning -> printfn "PackageManagementWarning %d : %s" code message
ResolvingErrorReport (report)

let mutable initialPath:string = null
let mutable currentPath:string = null
let mutable finalPath:string = null
do
initialPath <- appendSemiColon (Environment.GetEnvironmentVariable("PATH"))
use dp = new DependencyProvider(NativeResolutionProbe(nativeProbingRoots))
let idm = dp.TryFindDependencyManagerByKey(Seq.empty, "", reportError, "nuget")
let mutable currentPath:string = null
if RuntimeInformation.IsOSPlatform(OSPlatform.Windows) then
let result = dp.Resolve(idm, ".fsx", [|"r", "Microsoft.Data.Sqlite,3.1.7"|], reportError, "netstandard2.0")
Assert.Equal(true, result.Success)
currentPath <- appendSemiColon (Environment.GetEnvironmentVariable("PATH"))
finalPath <- appendSemiColon (Environment.GetEnvironmentVariable("PATH"))
Assert.True(currentPath <> initialPath) // The path was modified by #r "nuget: ..."
Assert.Equal(finalPath, initialPath) // IDispose correctly cleaned up the path

initialPath <- null
currentPath <- null
finalPath <- null
do
initialPath <- appendSemiColon (Environment.GetEnvironmentVariable("PATH"))
let mutable currentPath:string = null
use dp = new DependencyProvider(NativeResolutionProbe(nativeProbingRoots))
let idm = dp.TryFindDependencyManagerByKey(Seq.empty, "", reportError, "nuget")
let result = dp.Resolve(idm, ".fsx", [|"r", "Microsoft.Data.Sqlite,3.1.7"|], reportError, "netcoreapp3.1")
Assert.Equal(true, result.Success)
currentPath <- appendSemiColon (Environment.GetEnvironmentVariable("PATH"))
finalPath <- appendSemiColon (Environment.GetEnvironmentVariable("PATH"))
Assert.True(currentPath <> initialPath) // The path was modified by #r "nuget: ..."
Assert.Equal(finalPath, initialPath) // IDispose correctly cleaned up the path

()

[<Fact>]
member __.``Verify that #help produces help text for fsi + dependency manager``() =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@
<NgenArchitecture>All</NgenArchitecture>
<NgenPriority>2</NgenPriority>
<Private>True</Private>
<AdditionalProperties>TargetFramework=net472</AdditionalProperties>
<AdditionalProperties>TargetFramework=netstandard2.0</AdditionalProperties>
</ProjectReference>
<ProjectReference Include="$(FSharpSourcesRoot)\fsharp\FSharp.Core\FSharp.Core.fsproj">
<Project>{DED3BBD7-53F4-428A-8C9F-27968E768605}</Project>
Expand Down