-
Notifications
You must be signed in to change notification settings - Fork 23
/
PathResolver.cs
155 lines (140 loc) · 5.72 KB
/
PathResolver.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
using Microsoft.DotNet.PlatformAbstractions;
using Microsoft.Extensions.DependencyModel;
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
namespace NativeLibraryLoader
{
/// <summary>
/// Enumerates possible library load targets.
/// </summary>
public abstract class PathResolver
{
/// <summary>
/// Returns an enumerator which yields possible library load targets, in priority order.
/// </summary>
/// <param name="name">The name of the library to load.</param>
/// <returns>An enumerator yielding load targets.</returns>
public abstract IEnumerable<string> EnumeratePossibleLibraryLoadTargets(string name);
/// <summary>
/// Gets a default path resolver.
/// </summary>
public static PathResolver Default { get; } = new DefaultPathResolver();
}
/// <summary>
/// Enumerates possible library load targets. This default implementation returns the following load targets:
/// First: The library contained in the applications base folder.
/// Second: The simple name, unchanged.
/// Third: The library as resolved via the default DependencyContext, in the default nuget package cache folder.
/// </summary>
public class DefaultPathResolver : PathResolver
{
/// <summary>
/// Returns an enumerator which yields possible library load targets, in priority order.
/// </summary>
/// <param name="name">The name of the library to load.</param>
/// <returns>An enumerator yielding load targets.</returns>
public override IEnumerable<string> EnumeratePossibleLibraryLoadTargets(string name)
{
if (!string.IsNullOrEmpty(AppContext.BaseDirectory))
{
yield return Path.Combine(AppContext.BaseDirectory, name);
}
yield return name;
if (TryLocateNativeAssetFromDeps(name, out string appLocalNativePath, out string depsResolvedPath))
{
yield return appLocalNativePath;
yield return depsResolvedPath;
}
}
private bool TryLocateNativeAssetFromDeps(string name, out string appLocalNativePath, out string depsResolvedPath)
{
DependencyContext defaultContext = DependencyContext.Default;
if (defaultContext == null)
{
appLocalNativePath = null;
depsResolvedPath = null;
return false;
}
string currentRID = Microsoft.DotNet.PlatformAbstractions.RuntimeEnvironment.GetRuntimeIdentifier();
List<string> allRIDs = new List<string>();
allRIDs.Add(currentRID);
if (!AddFallbacks(allRIDs, currentRID, defaultContext.RuntimeGraph))
{
string guessedFallbackRID = GuessFallbackRID(currentRID);
if (guessedFallbackRID != null)
{
allRIDs.Add(guessedFallbackRID);
AddFallbacks(allRIDs, guessedFallbackRID, defaultContext.RuntimeGraph);
}
}
foreach (string rid in allRIDs)
{
foreach (var runtimeLib in defaultContext.RuntimeLibraries)
{
foreach (var nativeAsset in runtimeLib.GetRuntimeNativeAssets(defaultContext, rid))
{
if (Path.GetFileName(nativeAsset) == name || Path.GetFileNameWithoutExtension(nativeAsset) == name)
{
appLocalNativePath = Path.Combine(
AppContext.BaseDirectory,
nativeAsset);
appLocalNativePath = Path.GetFullPath(appLocalNativePath);
depsResolvedPath = Path.Combine(
GetNugetPackagesRootDirectory(),
runtimeLib.Name.ToLowerInvariant(),
runtimeLib.Version,
nativeAsset);
depsResolvedPath = Path.GetFullPath(depsResolvedPath);
return true;
}
}
}
}
appLocalNativePath = null;
depsResolvedPath = null;
return false;
}
private string GuessFallbackRID(string actualRuntimeIdentifier)
{
if (actualRuntimeIdentifier == "osx.10.13-x64")
{
return "osx.10.12-x64";
}
else if (actualRuntimeIdentifier.StartsWith("osx"))
{
return "osx-x64";
}
return null;
}
private bool AddFallbacks(List<string> fallbacks, string rid, IReadOnlyList<RuntimeFallbacks> allFallbacks)
{
foreach (RuntimeFallbacks fb in allFallbacks)
{
if (fb.Runtime == rid)
{
fallbacks.AddRange(fb.Fallbacks);
return true;
}
}
return false;
}
private string GetNugetPackagesRootDirectory()
{
// TODO: Handle alternative package directories, if they are configured.
return Path.Combine(GetUserDirectory(), ".nuget", "packages");
}
private string GetUserDirectory()
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
return Environment.GetEnvironmentVariable("USERPROFILE");
}
else
{
return Environment.GetEnvironmentVariable("HOME");
}
}
}
}