Skip to content

Commit 3f6a252

Browse files
committed
Fixes and enhancements to native dependencies resolution.
1 parent 74e7848 commit 3f6a252

File tree

5 files changed

+3188
-25
lines changed

5 files changed

+3188
-25
lines changed
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the MIT License. See License.txt in the project root for license information.
3+
4+
using System;
5+
using System.Collections.Generic;
6+
using System.IO;
7+
using System.Linq;
8+
using Microsoft.Extensions.DependencyModel;
9+
using Newtonsoft.Json.Linq;
10+
11+
namespace Microsoft.Azure.WebJobs.Script.Description
12+
{
13+
public static class DependencyHelper
14+
{
15+
private static readonly Lazy<Dictionary<string, string[]>> _ridGraph = new Lazy<Dictionary<string, string[]>>(BuildRuntimesGraph);
16+
17+
private static Dictionary<string, string[]> BuildRuntimesGraph()
18+
{
19+
var ridGraph = new Dictionary<string, string[]>();
20+
string runtimesJson = GetRuntimesGraphJson();
21+
var runtimes = (JObject)JObject.Parse(runtimesJson)["runtimes"];
22+
23+
foreach (var runtime in runtimes)
24+
{
25+
string[] imports = ((JObject)runtime.Value)["#import"]
26+
?.Values<string>()
27+
.ToArray();
28+
29+
ridGraph.Add(runtime.Key, imports);
30+
}
31+
32+
return ridGraph;
33+
}
34+
35+
public static IEnumerable<string> GetFallbacks(Dictionary<string, string[]> ridGraph, string rid)
36+
{
37+
var fallbacks = new HashSet<string>();
38+
var queue = new Queue<string>(ridGraph[rid]);
39+
40+
while (queue.Count > 0)
41+
{
42+
var currentRid = queue.Dequeue();
43+
44+
if (fallbacks.Contains(currentRid))
45+
{
46+
continue;
47+
}
48+
49+
fallbacks.Add(currentRid);
50+
51+
foreach (var fallbackRid in ridGraph[currentRid])
52+
{
53+
if (!fallbacks.Contains(fallbackRid))
54+
{
55+
queue.Enqueue(fallbackRid);
56+
}
57+
}
58+
}
59+
60+
return fallbacks;
61+
}
62+
63+
private static string GetRuntimeAssembliesJson()
64+
{
65+
return GetResourceFileContents("runtimeassemblies.json");
66+
}
67+
68+
private static string GetRuntimesGraphJson()
69+
{
70+
return GetResourceFileContents("runtimes.json");
71+
}
72+
73+
private static string GetResourceFileContents(string fileName)
74+
{
75+
var assembly = typeof(DependencyHelper).Assembly;
76+
using (Stream resource = assembly.GetManifestResourceStream($"{assembly.GetName().Name}.{fileName}"))
77+
using (var reader = new StreamReader(resource))
78+
{
79+
return reader.ReadToEnd();
80+
}
81+
}
82+
83+
internal static Dictionary<string, ScriptRuntimeAssembly> GetRuntimeAssemblies()
84+
{
85+
string assembliesJson = GetRuntimeAssembliesJson();
86+
JObject assemblies = JObject.Parse(assembliesJson);
87+
88+
return assemblies["runtimeAssemblies"]
89+
.ToObject<ScriptRuntimeAssembly[]>()
90+
.ToDictionary(a => a.Name, StringComparer.OrdinalIgnoreCase);
91+
}
92+
93+
/// <summary>
94+
/// Gets the default runtime fallback RIDs for a given RID.
95+
/// The graph used to build the fallback list is static and
96+
/// useful in self-contained scenarios, where this information
97+
/// is not available at runtime
98+
/// </summary>
99+
/// <param name="rid">The runtime identifier to lookup.</param>
100+
/// <returns>The runtime fallbacks for the provided identifier.</returns>
101+
public static RuntimeFallbacks GetDefaultRuntimeFallbacks(string rid)
102+
{
103+
IEnumerable<string> fallbacks = GetFallbacks(_ridGraph.Value, rid);
104+
105+
return new RuntimeFallbacks(rid, fallbacks);
106+
}
107+
}
108+
}

src/WebJobs.Script/Description/DotNet/FunctionAssemblyLoadContext.cs

Lines changed: 15 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ namespace Microsoft.Azure.WebJobs.Script.Description
2424
/// </summary>
2525
public partial class FunctionAssemblyLoadContext : AssemblyLoadContext
2626
{
27-
private static readonly Lazy<Dictionary<string, ScriptRuntimeAssembly>> _runtimeAssemblies = new Lazy<Dictionary<string, ScriptRuntimeAssembly>>(GetRuntimeAssemblies);
27+
private static readonly Lazy<Dictionary<string, ScriptRuntimeAssembly>> _runtimeAssemblies = new Lazy<Dictionary<string, ScriptRuntimeAssembly>>(DependencyHelper.GetRuntimeAssemblies);
2828
private static readonly Lazy<Dictionary<string, ResolutionPolicyEvaluator>> _resolutionPolicyEvaluators = new Lazy<Dictionary<string, ResolutionPolicyEvaluator>>(InitializeLoadPolicyEvaluators);
2929
private static Lazy<FunctionAssemblyLoadContext> _defaultContext = new Lazy<FunctionAssemblyLoadContext>(() => new FunctionAssemblyLoadContext(ResolveFunctionBaseProbingPath()), true);
3030

@@ -201,16 +201,26 @@ private string GetRuntimeAssetPath(string assetFileName, bool isNativeAsset)
201201
string ridSubFolder = isNativeAsset ? "native" : string.Empty;
202202
string runtimesPath = Path.Combine(basePath, "runtimes");
203203

204+
List<string> rids = GetRuntimeFallbacks();
205+
206+
return rids.Select(r => Path.Combine(runtimesPath, r, ridSubFolder, assetFileName))
207+
.Union(_probingPaths)
208+
.FirstOrDefault(p => File.Exists(p));
209+
}
210+
211+
private static List<string> GetRuntimeFallbacks()
212+
{
204213
string currentRuntimeIdentifier = GetRuntimeIdentifier();
214+
205215
RuntimeFallbacks fallbacks = DependencyContext.Default
206216
.RuntimeGraph
207-
.FirstOrDefault(f => string.Equals(f.Runtime, currentRuntimeIdentifier, StringComparison.OrdinalIgnoreCase));
217+
.FirstOrDefault(f => string.Equals(f.Runtime, currentRuntimeIdentifier, StringComparison.OrdinalIgnoreCase))
218+
?? DependencyHelper.GetDefaultRuntimeFallbacks(currentRuntimeIdentifier)
219+
?? new RuntimeFallbacks("any");
208220

209221
var rids = new List<string> { fallbacks.Runtime };
210222
rids.AddRange(fallbacks.Fallbacks);
211-
212-
return rids.Select(r => Path.Combine(runtimesPath, r, ridSubFolder, assetFileName))
213-
.FirstOrDefault(p => File.Exists(p));
223+
return rids;
214224
}
215225

216226
internal string GetUnmanagedLibraryFileName(string unmanagedLibraryName)
@@ -263,25 +273,5 @@ protected static string ResolveFunctionBaseProbingPath()
263273

264274
return Path.Combine(basePath, "bin");
265275
}
266-
267-
private static Dictionary<string, ScriptRuntimeAssembly> GetRuntimeAssemblies()
268-
{
269-
string assembliesJson = GetRuntimeAssembliesJson();
270-
JObject assemblies = JObject.Parse(assembliesJson);
271-
272-
return assemblies["runtimeAssemblies"]
273-
.ToObject<ScriptRuntimeAssembly[]>()
274-
.ToDictionary(a => a.Name, StringComparer.OrdinalIgnoreCase);
275-
}
276-
277-
private static string GetRuntimeAssembliesJson()
278-
{
279-
var assembly = typeof(FunctionAssemblyLoadContext).Assembly;
280-
using (Stream resource = assembly.GetManifestResourceStream(assembly.GetName().Name + ".runtimeassemblies.json"))
281-
using (var reader = new StreamReader(resource))
282-
{
283-
return reader.ReadToEnd();
284-
}
285-
}
286276
}
287277
}

src/WebJobs.Script/WebJobs.Script.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,13 @@
1212
</PropertyGroup>
1313
<ItemGroup>
1414
<None Remove="runtimeassemblies.json" />
15+
<None Remove="runtimes.json" />
1516
</ItemGroup>
1617
<ItemGroup>
1718
<EmbeddedResource Include="runtimeassemblies.json">
1819
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
1920
</EmbeddedResource>
21+
<EmbeddedResource Include="runtimes.json" />
2022
</ItemGroup>
2123

2224
<ItemGroup>

0 commit comments

Comments
 (0)