Remove DependencyModel dependency
This commit is contained in:
parent
cef81adb21
commit
4299a4d50b
|
|
@ -0,0 +1,45 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.Extensions.DependencyModel.Resolution;
|
||||
|
||||
namespace Microsoft.Extensions.DependencyModel
|
||||
{
|
||||
internal class CompilationLibrary : Library
|
||||
{
|
||||
public CompilationLibrary(string type,
|
||||
string name,
|
||||
string version,
|
||||
string hash,
|
||||
IEnumerable<string> assemblies,
|
||||
IEnumerable<Dependency> dependencies,
|
||||
bool serviceable)
|
||||
: base(type, name, version, hash, dependencies, serviceable)
|
||||
{
|
||||
Assemblies = assemblies.ToArray();
|
||||
}
|
||||
|
||||
public IReadOnlyList<string> Assemblies { get; }
|
||||
|
||||
internal static ICompilationAssemblyResolver DefaultResolver { get; } = new CompositeCompilationAssemblyResolver(new ICompilationAssemblyResolver[]
|
||||
{
|
||||
new PackageCacheCompilationAssemblyResolver(),
|
||||
new AppBaseCompilationAssemblyResolver(),
|
||||
new ReferenceAssemblyPathResolver(),
|
||||
new PackageCompilationAssemblyResolver()
|
||||
});
|
||||
|
||||
public IEnumerable<string> ResolveReferencePaths()
|
||||
{
|
||||
var assemblies = new List<string>();
|
||||
if (!DefaultResolver.TryResolveAssemblyPaths(this, assemblies))
|
||||
{
|
||||
throw new InvalidOperationException($"Can not find compilation library location for package '{Name}'");
|
||||
}
|
||||
return assemblies;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Microsoft.Extensions.DependencyModel
|
||||
{
|
||||
internal class CompilationOptions
|
||||
{
|
||||
public IEnumerable<string> Defines { get; }
|
||||
|
||||
public string LanguageVersion { get; }
|
||||
|
||||
public string Platform { get; }
|
||||
|
||||
public bool? AllowUnsafe { get; }
|
||||
|
||||
public bool? WarningsAsErrors { get; }
|
||||
|
||||
public bool? Optimize { get; }
|
||||
|
||||
public string KeyFile { get; }
|
||||
|
||||
public bool? DelaySign { get; }
|
||||
|
||||
public bool? PublicSign { get; }
|
||||
|
||||
public string DebugType { get; }
|
||||
|
||||
public bool? EmitEntryPoint { get; }
|
||||
|
||||
public bool? GenerateXmlDocumentation { get; }
|
||||
|
||||
public static CompilationOptions Default { get; } = new CompilationOptions(
|
||||
defines: Enumerable.Empty<string>(),
|
||||
languageVersion: null,
|
||||
platform: null,
|
||||
allowUnsafe: null,
|
||||
warningsAsErrors: null,
|
||||
optimize: null,
|
||||
keyFile: null,
|
||||
delaySign: null,
|
||||
publicSign: null,
|
||||
debugType: null,
|
||||
emitEntryPoint: null,
|
||||
generateXmlDocumentation: null);
|
||||
|
||||
public CompilationOptions(IEnumerable<string> defines,
|
||||
string languageVersion,
|
||||
string platform,
|
||||
bool? allowUnsafe,
|
||||
bool? warningsAsErrors,
|
||||
bool? optimize,
|
||||
string keyFile,
|
||||
bool? delaySign,
|
||||
bool? publicSign,
|
||||
string debugType,
|
||||
bool? emitEntryPoint,
|
||||
bool? generateXmlDocumentation)
|
||||
{
|
||||
Defines = defines;
|
||||
LanguageVersion = languageVersion;
|
||||
Platform = platform;
|
||||
AllowUnsafe = allowUnsafe;
|
||||
WarningsAsErrors = warningsAsErrors;
|
||||
Optimize = optimize;
|
||||
KeyFile = keyFile;
|
||||
DelaySign = delaySign;
|
||||
PublicSign = publicSign;
|
||||
DebugType = debugType;
|
||||
EmitEntryPoint = emitEntryPoint;
|
||||
GenerateXmlDocumentation = generateXmlDocumentation;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using Microsoft.Extensions.Internal;
|
||||
|
||||
namespace Microsoft.Extensions.DependencyModel
|
||||
{
|
||||
internal struct Dependency
|
||||
{
|
||||
public Dependency(string name, string version)
|
||||
{
|
||||
Name = name;
|
||||
Version = version;
|
||||
}
|
||||
|
||||
public string Name { get; }
|
||||
public string Version { get; }
|
||||
|
||||
public bool Equals(Dependency other)
|
||||
{
|
||||
return string.Equals(Name, other.Name) && string.Equals(Version, other.Version);
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (ReferenceEquals(null, obj)) return false;
|
||||
return obj is Dependency && Equals((Dependency) obj);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
var combiner = HashCodeCombiner.Start();
|
||||
combiner.Add(Name);
|
||||
combiner.Add(Version);
|
||||
return combiner.CombinedHash;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,115 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Microsoft.Extensions.DependencyModel
|
||||
{
|
||||
internal class DependencyContext
|
||||
{
|
||||
private static readonly Lazy<DependencyContext> _defaultContext = new Lazy<DependencyContext>(LoadDefault);
|
||||
|
||||
public DependencyContext(string targetFramework,
|
||||
string runtime,
|
||||
bool isPortable,
|
||||
CompilationOptions compilationOptions,
|
||||
IEnumerable<CompilationLibrary> compileLibraries,
|
||||
IEnumerable<RuntimeLibrary> runtimeLibraries,
|
||||
IEnumerable<RuntimeFallbacks> runtimeGraph)
|
||||
{
|
||||
if (targetFramework == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(targetFramework));
|
||||
}
|
||||
if (runtime == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(runtime));
|
||||
}
|
||||
if (compilationOptions == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(compilationOptions));
|
||||
}
|
||||
if (compileLibraries == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(compileLibraries));
|
||||
}
|
||||
if (runtimeLibraries == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(runtimeLibraries));
|
||||
}
|
||||
if (runtimeGraph == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(runtimeGraph));
|
||||
}
|
||||
|
||||
TargetFramework = targetFramework;
|
||||
Runtime = runtime;
|
||||
IsPortable = isPortable;
|
||||
CompilationOptions = compilationOptions;
|
||||
CompileLibraries = compileLibraries.ToArray();
|
||||
RuntimeLibraries = runtimeLibraries.ToArray();
|
||||
RuntimeGraph = runtimeGraph.ToArray();
|
||||
}
|
||||
|
||||
public static DependencyContext Default => _defaultContext.Value;
|
||||
|
||||
public string TargetFramework { get; }
|
||||
|
||||
public string Runtime { get; }
|
||||
|
||||
public bool IsPortable { get; }
|
||||
|
||||
public CompilationOptions CompilationOptions { get; }
|
||||
|
||||
public IReadOnlyList<CompilationLibrary> CompileLibraries { get; }
|
||||
|
||||
public IReadOnlyList<RuntimeLibrary> RuntimeLibraries { get; }
|
||||
|
||||
public IReadOnlyList<RuntimeFallbacks> RuntimeGraph { get; }
|
||||
|
||||
public DependencyContext Merge(DependencyContext other)
|
||||
{
|
||||
if (other == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(other));
|
||||
}
|
||||
|
||||
return new DependencyContext(
|
||||
TargetFramework,
|
||||
Runtime,
|
||||
IsPortable,
|
||||
CompilationOptions,
|
||||
CompileLibraries.Union(other.CompileLibraries, new LibraryMergeEqualityComparer<CompilationLibrary>()),
|
||||
RuntimeLibraries.Union(other.RuntimeLibraries, new LibraryMergeEqualityComparer<RuntimeLibrary>()),
|
||||
RuntimeGraph.Union(other.RuntimeGraph)
|
||||
);
|
||||
}
|
||||
|
||||
private static DependencyContext LoadDefault()
|
||||
{
|
||||
return DependencyContextLoader.Default.Load(Assembly.GetEntryAssembly());
|
||||
}
|
||||
|
||||
public static DependencyContext Load(Assembly assembly)
|
||||
{
|
||||
return DependencyContextLoader.Default.Load(assembly);
|
||||
}
|
||||
|
||||
private class LibraryMergeEqualityComparer<T>: IEqualityComparer<T> where T:Library
|
||||
{
|
||||
public bool Equals(T x, T y)
|
||||
{
|
||||
return string.Equals(x.Name, y.Name, StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
public int GetHashCode(T obj)
|
||||
{
|
||||
return obj.Name.GetHashCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,135 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Microsoft.Extensions.DependencyModel
|
||||
{
|
||||
internal class DependencyContextCsvReader: IDependencyContextReader
|
||||
{
|
||||
public DependencyContext Read(Stream stream)
|
||||
{
|
||||
var lines = new List<DepsFileLine>();
|
||||
using (var reader = new StreamReader(stream))
|
||||
{
|
||||
while (!reader.EndOfStream)
|
||||
{
|
||||
var line = new DepsFileLine();
|
||||
line.LibraryType = ReadValue(reader);
|
||||
line.PackageName = ReadValue(reader);
|
||||
line.PackageVersion = ReadValue(reader);
|
||||
line.PackageHash = ReadValue(reader);
|
||||
line.AssetType = ReadValue(reader);
|
||||
line.AssetName = ReadValue(reader);
|
||||
line.AssetPath = ReadValue(reader);
|
||||
|
||||
if (line.AssetType == "runtime" &&
|
||||
!line.AssetPath.EndsWith(".ni.dll"))
|
||||
{
|
||||
lines.Add(line);
|
||||
}
|
||||
SkipWhitespace(reader);
|
||||
}
|
||||
}
|
||||
|
||||
var runtimeLibraries = new List<RuntimeLibrary>();
|
||||
var packageGroups = lines.GroupBy(PackageIdentity);
|
||||
foreach (var packageGroup in packageGroups)
|
||||
{
|
||||
var identity = packageGroup.Key;
|
||||
runtimeLibraries.Add(new RuntimeLibrary(
|
||||
type: identity.Item1,
|
||||
name: identity.Item2,
|
||||
version: identity.Item3,
|
||||
hash: identity.Item4,
|
||||
assemblies: packageGroup.Select(l => RuntimeAssembly.Create(l.AssetPath)),
|
||||
nativeLibraries: Enumerable.Empty<string>(),
|
||||
resourceAssemblies: Enumerable.Empty<ResourceAssembly>(),
|
||||
subTargets: Enumerable.Empty<RuntimeTarget>(),
|
||||
dependencies: Enumerable.Empty<Dependency>(),
|
||||
serviceable: false
|
||||
));
|
||||
}
|
||||
|
||||
return new DependencyContext(
|
||||
targetFramework: string.Empty,
|
||||
runtime: string.Empty,
|
||||
isPortable: false,
|
||||
compilationOptions: CompilationOptions.Default,
|
||||
compileLibraries: Enumerable.Empty<CompilationLibrary>(),
|
||||
runtimeLibraries: runtimeLibraries.ToArray(),
|
||||
runtimeGraph: Enumerable.Empty<RuntimeFallbacks>());
|
||||
}
|
||||
|
||||
private Tuple<string, string, string, string> PackageIdentity(DepsFileLine line)
|
||||
{
|
||||
return Tuple.Create(line.LibraryType, line.PackageName, line.PackageVersion, line.PackageHash);
|
||||
}
|
||||
|
||||
private void SkipWhitespace(StreamReader reader)
|
||||
{
|
||||
// skip all whitespace
|
||||
while (!reader.EndOfStream && char.IsWhiteSpace((char)reader.Peek()))
|
||||
{
|
||||
reader.Read();
|
||||
}
|
||||
}
|
||||
|
||||
private string ReadValue(StreamReader reader)
|
||||
{
|
||||
SkipWhitespace(reader);
|
||||
|
||||
var c = ReadSucceed(reader.Read());
|
||||
if (c != '"')
|
||||
{
|
||||
throw new FormatException("Deps file value should start with '\"'");
|
||||
}
|
||||
|
||||
var value = new StringBuilder();
|
||||
while (ReadSucceed(reader.Peek()) != '"')
|
||||
{
|
||||
c = ReadSucceed(reader.Read());
|
||||
if (c == '\\')
|
||||
{
|
||||
value.Append(ReadSucceed(reader.Read()));
|
||||
}
|
||||
else
|
||||
{
|
||||
value.Append(c);
|
||||
}
|
||||
}
|
||||
// Read last "
|
||||
ReadSucceed(reader.Read());
|
||||
// Read comment
|
||||
if (reader.Peek() == ',')
|
||||
{
|
||||
reader.Read();
|
||||
}
|
||||
return value.ToString();
|
||||
}
|
||||
|
||||
private char ReadSucceed(int c)
|
||||
{
|
||||
if (c == -1)
|
||||
{
|
||||
throw new FormatException("Unexpected end of file");
|
||||
}
|
||||
return (char) c;
|
||||
}
|
||||
|
||||
private struct DepsFileLine
|
||||
{
|
||||
public string LibraryType;
|
||||
public string PackageName;
|
||||
public string PackageVersion;
|
||||
public string PackageHash;
|
||||
public string AssetType;
|
||||
public string AssetName;
|
||||
public string AssetPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,294 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace Microsoft.Extensions.DependencyModel
|
||||
{
|
||||
internal class DependencyContextJsonReader: IDependencyContextReader
|
||||
{
|
||||
public DependencyContext Read(Stream stream)
|
||||
{
|
||||
using (var streamReader = new StreamReader(stream))
|
||||
{
|
||||
using (var reader = new JsonTextReader(streamReader))
|
||||
{
|
||||
var root = JObject.Load(reader);
|
||||
return Read(root);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsRuntimeTarget(string name) => name.Contains(DependencyContextStrings.VersionSeperator);
|
||||
|
||||
private DependencyContext Read(JObject root)
|
||||
{
|
||||
var runtime = string.Empty;
|
||||
var target = string.Empty;
|
||||
var isPortable = true;
|
||||
|
||||
var runtimeTargetName = root[DependencyContextStrings.RuntimeTargetPropertyName]?.Value<string>();
|
||||
|
||||
var libraryStubs = ReadLibraryStubs((JObject) root[DependencyContextStrings.LibrariesPropertyName]);
|
||||
var targetsObject = (JObject) root[DependencyContextStrings.TargetsPropertyName];
|
||||
|
||||
JObject runtimeTarget = null;
|
||||
JObject compileTarget = null;
|
||||
if (targetsObject != null)
|
||||
{
|
||||
var compileTargetProperty = targetsObject.Properties()
|
||||
.FirstOrDefault(p => !IsRuntimeTarget(p.Name));
|
||||
|
||||
compileTarget = (JObject)compileTargetProperty.Value;
|
||||
target = compileTargetProperty.Name;
|
||||
|
||||
if (!string.IsNullOrEmpty(runtimeTargetName))
|
||||
{
|
||||
runtimeTarget = (JObject) targetsObject[runtimeTargetName];
|
||||
if (runtimeTarget == null)
|
||||
{
|
||||
throw new FormatException($"Target with name {runtimeTargetName} not found");
|
||||
}
|
||||
|
||||
var seperatorIndex = runtimeTargetName.IndexOf(DependencyContextStrings.VersionSeperator);
|
||||
if (seperatorIndex > -1 && seperatorIndex < runtimeTargetName.Length)
|
||||
{
|
||||
runtime = runtimeTargetName.Substring(seperatorIndex + 1);
|
||||
isPortable = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
runtimeTarget = compileTarget;
|
||||
}
|
||||
}
|
||||
|
||||
return new DependencyContext(
|
||||
target,
|
||||
runtime,
|
||||
isPortable,
|
||||
ReadCompilationOptions((JObject)root[DependencyContextStrings.CompilationOptionsPropertName]),
|
||||
ReadLibraries(compileTarget, false, libraryStubs).Cast<CompilationLibrary>().ToArray(),
|
||||
ReadLibraries(runtimeTarget, true, libraryStubs).Cast<RuntimeLibrary>().ToArray(),
|
||||
ReadRuntimeGraph((JObject)root[DependencyContextStrings.RuntimesPropertyName]).ToArray()
|
||||
);
|
||||
}
|
||||
|
||||
private IEnumerable<RuntimeFallbacks> ReadRuntimeGraph(JObject runtimes)
|
||||
{
|
||||
if (runtimes == null)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
foreach (var pair in runtimes)
|
||||
{
|
||||
yield return new RuntimeFallbacks(pair.Key, pair.Value.Values<string>().ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
private CompilationOptions ReadCompilationOptions(JObject compilationOptionsObject)
|
||||
{
|
||||
if (compilationOptionsObject == null)
|
||||
{
|
||||
return CompilationOptions.Default;
|
||||
}
|
||||
|
||||
return new CompilationOptions(
|
||||
compilationOptionsObject[DependencyContextStrings.DefinesPropertyName]?.Values<string>(),
|
||||
compilationOptionsObject[DependencyContextStrings.LanguageVersionPropertyName]?.Value<string>(),
|
||||
compilationOptionsObject[DependencyContextStrings.PlatformPropertyName]?.Value<string>(),
|
||||
compilationOptionsObject[DependencyContextStrings.AllowUnsafePropertyName]?.Value<bool>(),
|
||||
compilationOptionsObject[DependencyContextStrings.WarningsAsErrorsPropertyName]?.Value<bool>(),
|
||||
compilationOptionsObject[DependencyContextStrings.OptimizePropertyName]?.Value<bool>(),
|
||||
compilationOptionsObject[DependencyContextStrings.KeyFilePropertyName]?.Value<string>(),
|
||||
compilationOptionsObject[DependencyContextStrings.DelaySignPropertyName]?.Value<bool>(),
|
||||
compilationOptionsObject[DependencyContextStrings.PublicSignPropertyName]?.Value<bool>(),
|
||||
compilationOptionsObject[DependencyContextStrings.DebugTypePropertyName]?.Value<string>(),
|
||||
compilationOptionsObject[DependencyContextStrings.EmitEntryPointPropertyName]?.Value<bool>(),
|
||||
compilationOptionsObject[DependencyContextStrings.GenerateXmlDocumentationPropertyName]?.Value<bool>()
|
||||
);
|
||||
}
|
||||
|
||||
private IEnumerable<Library> ReadLibraries(JObject librariesObject, bool runtime, Dictionary<string, LibraryStub> libraryStubs)
|
||||
{
|
||||
if (librariesObject == null)
|
||||
{
|
||||
return Enumerable.Empty<Library>();
|
||||
}
|
||||
return librariesObject.Properties().Select(property => ReadLibrary(property, runtime, libraryStubs));
|
||||
}
|
||||
|
||||
private Library ReadLibrary(JProperty property, bool runtime, Dictionary<string, LibraryStub> libraryStubs)
|
||||
{
|
||||
var nameWithVersion = property.Name;
|
||||
LibraryStub stub;
|
||||
|
||||
if (!libraryStubs.TryGetValue(nameWithVersion, out stub))
|
||||
{
|
||||
throw new InvalidOperationException($"Cannot find library information for {nameWithVersion}");
|
||||
}
|
||||
|
||||
var seperatorPosition = nameWithVersion.IndexOf(DependencyContextStrings.VersionSeperator);
|
||||
|
||||
var name = nameWithVersion.Substring(0, seperatorPosition);
|
||||
var version = nameWithVersion.Substring(seperatorPosition + 1);
|
||||
|
||||
var libraryObject = (JObject) property.Value;
|
||||
|
||||
var dependencies = ReadDependencies(libraryObject);
|
||||
|
||||
if (runtime)
|
||||
{
|
||||
var runtimeTargets = new List<RuntimeTarget>();
|
||||
var runtimeTargetsObject = (JObject)libraryObject[DependencyContextStrings.RuntimeTargetsPropertyName];
|
||||
|
||||
var entries = ReadRuntimeTargetEntries(runtimeTargetsObject).ToArray();
|
||||
|
||||
foreach (var ridGroup in entries.GroupBy(e => e.Rid))
|
||||
{
|
||||
var runtimeAssets = entries.Where(e => e.Type == DependencyContextStrings.RuntimeAssetType)
|
||||
.Select(e => RuntimeAssembly.Create(e.Path))
|
||||
.ToArray();
|
||||
|
||||
var nativeAssets = entries.Where(e => e.Type == DependencyContextStrings.NativeAssetType)
|
||||
.Select(e => e.Path)
|
||||
.ToArray();
|
||||
|
||||
runtimeTargets.Add(new RuntimeTarget(
|
||||
ridGroup.Key,
|
||||
runtimeAssets,
|
||||
nativeAssets
|
||||
));
|
||||
}
|
||||
|
||||
var assemblies = ReadAssetList(libraryObject, DependencyContextStrings.RuntimeAssembliesKey)
|
||||
.Select(RuntimeAssembly.Create)
|
||||
.ToArray();
|
||||
|
||||
var nativeLibraries = ReadAssetList(libraryObject, DependencyContextStrings.NativeLibrariesKey);
|
||||
|
||||
var resourceAssemblies = ReadResourceAssemblies((JObject)libraryObject[DependencyContextStrings.ResourceAssembliesPropertyName]);
|
||||
|
||||
return new RuntimeLibrary(
|
||||
type: stub.Type,
|
||||
name: name,
|
||||
version: version,
|
||||
hash: stub.Hash,
|
||||
assemblies: assemblies,
|
||||
nativeLibraries: nativeLibraries,
|
||||
resourceAssemblies: resourceAssemblies,
|
||||
subTargets: runtimeTargets.ToArray(),
|
||||
dependencies: dependencies,
|
||||
serviceable: stub.Serviceable);
|
||||
}
|
||||
else
|
||||
{
|
||||
var assemblies = ReadAssetList(libraryObject, DependencyContextStrings.CompileTimeAssembliesKey);
|
||||
return new CompilationLibrary(stub.Type, name, version, stub.Hash, assemblies, dependencies, stub.Serviceable);
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<ResourceAssembly> ReadResourceAssemblies(JObject resourcesObject)
|
||||
{
|
||||
if (resourcesObject == null)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
foreach (var resourceProperty in resourcesObject)
|
||||
{
|
||||
yield return new ResourceAssembly(
|
||||
locale: resourceProperty.Value[DependencyContextStrings.LocalePropertyName]?.Value<string>(),
|
||||
path: resourceProperty.Key
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private static IEnumerable<RuntimeTargetEntryStub> ReadRuntimeTargetEntries(JObject runtimeTargetObject)
|
||||
{
|
||||
if (runtimeTargetObject == null)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
foreach (var libraryProperty in runtimeTargetObject)
|
||||
{
|
||||
var libraryObject = (JObject)libraryProperty.Value;
|
||||
yield return new RuntimeTargetEntryStub()
|
||||
{
|
||||
Path = libraryProperty.Key,
|
||||
Rid = libraryObject[DependencyContextStrings.RidPropertyName].Value<string>(),
|
||||
Type = libraryObject[DependencyContextStrings.AssetTypePropertyName].Value<string>()
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private static string[] ReadAssetList(JObject libraryObject, string name)
|
||||
{
|
||||
var assembliesObject = (JObject) libraryObject[name];
|
||||
|
||||
if (assembliesObject == null)
|
||||
{
|
||||
return new string[] {};
|
||||
}
|
||||
|
||||
return assembliesObject.Properties().Select(property => property.Name).ToArray();
|
||||
}
|
||||
|
||||
private static Dependency[] ReadDependencies(JObject libraryObject)
|
||||
{
|
||||
var dependenciesObject = (JObject) libraryObject[DependencyContextStrings.DependenciesPropertyName];
|
||||
|
||||
if (dependenciesObject == null)
|
||||
{
|
||||
return new Dependency[]{ };
|
||||
}
|
||||
|
||||
return dependenciesObject.Properties()
|
||||
.Select(property => new Dependency(property.Name, (string) property.Value)).ToArray();
|
||||
}
|
||||
|
||||
private Dictionary<string, LibraryStub> ReadLibraryStubs(JObject librariesObject)
|
||||
{
|
||||
var libraries = new Dictionary<string, LibraryStub>();
|
||||
if (librariesObject != null)
|
||||
{
|
||||
foreach (var libraryProperty in librariesObject)
|
||||
{
|
||||
var value = (JObject) libraryProperty.Value;
|
||||
var stub = new LibraryStub
|
||||
{
|
||||
Name = libraryProperty.Key,
|
||||
Hash = value[DependencyContextStrings.Sha512PropertyName]?.Value<string>(),
|
||||
Type = value[DependencyContextStrings.TypePropertyName].Value<string>(),
|
||||
Serviceable = value[DependencyContextStrings.ServiceablePropertyName]?.Value<bool>() == true
|
||||
};
|
||||
libraries.Add(stub.Name, stub);
|
||||
}
|
||||
}
|
||||
return libraries;
|
||||
}
|
||||
|
||||
private struct RuntimeTargetEntryStub
|
||||
{
|
||||
public string Type;
|
||||
public string Path;
|
||||
public string Rid;
|
||||
}
|
||||
|
||||
private struct LibraryStub
|
||||
{
|
||||
public string Name;
|
||||
|
||||
public string Hash;
|
||||
|
||||
public string Type;
|
||||
|
||||
public bool Serviceable;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,170 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Microsoft.Extensions.DependencyModel
|
||||
{
|
||||
internal class DependencyContextLoader
|
||||
{
|
||||
private static Lazy<string[]> _depsFiles = new Lazy<string[]>(GetHostDepsList);
|
||||
|
||||
private const string DepsJsonExtension = ".deps.json";
|
||||
private const string DepsExtension = ".deps";
|
||||
|
||||
private readonly string _entryPointDepsLocation;
|
||||
private readonly string _runtimeDepsLocation;
|
||||
private readonly IDependencyContextReader _jsonReader;
|
||||
private readonly IDependencyContextReader _csvReader;
|
||||
|
||||
public DependencyContextLoader() : this(
|
||||
GetDefaultEntrypointDepsLocation(),
|
||||
GetDefaultRuntimeDepsLocation(),
|
||||
new DependencyContextJsonReader(),
|
||||
new DependencyContextCsvReader())
|
||||
{
|
||||
}
|
||||
|
||||
internal DependencyContextLoader(
|
||||
string entryPointDepsLocation,
|
||||
string runtimeDepsLocation,
|
||||
IDependencyContextReader jsonReader,
|
||||
IDependencyContextReader csvReader)
|
||||
{
|
||||
_entryPointDepsLocation = entryPointDepsLocation;
|
||||
_runtimeDepsLocation = runtimeDepsLocation;
|
||||
_jsonReader = jsonReader;
|
||||
_csvReader = csvReader;
|
||||
}
|
||||
|
||||
public static DependencyContextLoader Default { get; } = new DependencyContextLoader();
|
||||
|
||||
internal virtual bool IsEntryAssembly(Assembly assembly)
|
||||
{
|
||||
return assembly.GetName() == Assembly.GetEntryAssembly()?.GetName();
|
||||
}
|
||||
|
||||
internal virtual Stream GetResourceStream(Assembly assembly, string name)
|
||||
{
|
||||
return assembly.GetManifestResourceStream(name);
|
||||
}
|
||||
|
||||
public DependencyContext Load(Assembly assembly)
|
||||
{
|
||||
if (assembly == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(assembly));
|
||||
}
|
||||
|
||||
DependencyContext context = null;
|
||||
|
||||
if (IsEntryAssembly(assembly))
|
||||
{
|
||||
context = LoadEntryAssemblyContext();
|
||||
}
|
||||
|
||||
if (context == null)
|
||||
{
|
||||
context = LoadAssemblyContext(assembly);
|
||||
}
|
||||
|
||||
if (context?.IsPortable == true)
|
||||
{
|
||||
var runtimeContext = LoadRuntimeContext();
|
||||
if (runtimeContext != null)
|
||||
{
|
||||
context = context.Merge(runtimeContext);
|
||||
}
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
private DependencyContext LoadEntryAssemblyContext()
|
||||
{
|
||||
if (!string.IsNullOrEmpty(_entryPointDepsLocation))
|
||||
{
|
||||
Debug.Assert(File.Exists(_entryPointDepsLocation));
|
||||
using (var stream = File.OpenRead(_entryPointDepsLocation))
|
||||
{
|
||||
return _jsonReader.Read(stream);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private DependencyContext LoadRuntimeContext()
|
||||
{
|
||||
if (!string.IsNullOrEmpty(_runtimeDepsLocation))
|
||||
{
|
||||
Debug.Assert(File.Exists(_runtimeDepsLocation));
|
||||
using (var stream = File.OpenRead(_runtimeDepsLocation))
|
||||
{
|
||||
return _jsonReader.Read(stream);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private DependencyContext LoadAssemblyContext(Assembly assembly)
|
||||
{
|
||||
using (var stream = GetResourceStream(assembly, assembly.GetName().Name + DepsJsonExtension))
|
||||
{
|
||||
if (stream != null)
|
||||
{
|
||||
return _jsonReader.Read(stream);
|
||||
}
|
||||
}
|
||||
|
||||
var depsJsonFile = Path.ChangeExtension(assembly.Location, DepsJsonExtension);
|
||||
if (File.Exists(depsJsonFile))
|
||||
{
|
||||
using (var stream = File.OpenRead(depsJsonFile))
|
||||
{
|
||||
return _jsonReader.Read(stream);
|
||||
}
|
||||
}
|
||||
|
||||
var depsFile = Path.ChangeExtension(assembly.Location, DepsExtension);
|
||||
if (File.Exists(depsFile))
|
||||
{
|
||||
using (var stream = File.OpenRead(depsFile))
|
||||
{
|
||||
return _csvReader.Read(stream);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static string GetDefaultRuntimeDepsLocation()
|
||||
{
|
||||
var deps = _depsFiles.Value;
|
||||
if (deps != null && deps.Length > 1)
|
||||
{
|
||||
return deps[1];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static string GetDefaultEntrypointDepsLocation()
|
||||
{
|
||||
var deps = _depsFiles.Value;
|
||||
if (deps != null && deps.Length > 0)
|
||||
{
|
||||
return deps[0];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static string[] GetHostDepsList()
|
||||
{
|
||||
// TODO: Were going to replace this with AppContext.GetData
|
||||
var appDomainType = typeof(object).GetTypeInfo().Assembly?.GetType("System.AppDomain");
|
||||
var currentDomain = appDomainType?.GetProperty("CurrentDomain")?.GetValue(null);
|
||||
var deps = appDomainType?.GetMethod("GetData")?.Invoke(currentDomain, new[] { "APP_CONTEXT_DEPS_FILES" });
|
||||
|
||||
return (deps as string)?.Split(new [] { ';' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
namespace Microsoft.Extensions.DependencyModel
|
||||
{
|
||||
internal class DependencyContextStrings
|
||||
{
|
||||
internal const char VersionSeperator = '/';
|
||||
|
||||
internal const string CompileTimeAssembliesKey = "compile";
|
||||
|
||||
internal const string RuntimeAssembliesKey = "runtime";
|
||||
|
||||
internal const string NativeLibrariesKey = "native";
|
||||
|
||||
internal const string RuntimeTargetPropertyName = "runtimeTarget";
|
||||
|
||||
internal const string LibrariesPropertyName = "libraries";
|
||||
|
||||
internal const string TargetsPropertyName = "targets";
|
||||
|
||||
internal const string DependenciesPropertyName = "dependencies";
|
||||
|
||||
internal const string Sha512PropertyName = "sha512";
|
||||
|
||||
internal const string TypePropertyName = "type";
|
||||
|
||||
internal const string ServiceablePropertyName = "serviceable";
|
||||
|
||||
internal const string CompilationOptionsPropertName = "compilationOptions";
|
||||
|
||||
internal const string DefinesPropertyName = "defines";
|
||||
|
||||
internal const string LanguageVersionPropertyName = "languageVersion";
|
||||
|
||||
internal const string PlatformPropertyName = "platform";
|
||||
|
||||
internal const string AllowUnsafePropertyName = "allowUnsafe";
|
||||
|
||||
internal const string WarningsAsErrorsPropertyName = "warningsAsErrors";
|
||||
|
||||
internal const string OptimizePropertyName = "optimize";
|
||||
|
||||
internal const string KeyFilePropertyName = "keyFile";
|
||||
|
||||
internal const string DelaySignPropertyName = "delaySign";
|
||||
|
||||
internal const string PublicSignPropertyName = "publicSign";
|
||||
|
||||
internal const string DebugTypePropertyName = "debugType";
|
||||
|
||||
internal const string EmitEntryPointPropertyName = "emitEntryPoint";
|
||||
|
||||
internal const string GenerateXmlDocumentationPropertyName = "xmlDoc";
|
||||
|
||||
internal const string PortablePropertyName = "portable";
|
||||
|
||||
internal const string RuntimeTargetNamePropertyName = "name";
|
||||
|
||||
internal const string RuntimesPropertyName = "runtimes";
|
||||
|
||||
internal const string RuntimeTargetsPropertyName = "runtimeTargets";
|
||||
|
||||
internal const string RidPropertyName = "rid";
|
||||
|
||||
internal const string AssetTypePropertyName = "assetType";
|
||||
|
||||
internal const string RuntimeAssetType = "runtime";
|
||||
|
||||
internal const string NativeAssetType = "native";
|
||||
|
||||
internal const string ResourceAssembliesPropertyName = "resources";
|
||||
|
||||
internal const string LocalePropertyName = "locale";
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,309 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Microsoft.Extensions.PlatformAbstractions;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace Microsoft.Extensions.DependencyModel
|
||||
{
|
||||
internal class DependencyContextWriter
|
||||
{
|
||||
public void Write(DependencyContext context, Stream stream)
|
||||
{
|
||||
using (var writer = new StreamWriter(stream))
|
||||
{
|
||||
using (var jsonWriter = new JsonTextWriter(writer) { Formatting = Formatting.Indented })
|
||||
{
|
||||
Write(context).WriteTo(jsonWriter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private JObject Write(DependencyContext context)
|
||||
{
|
||||
var contextObject = new JObject(
|
||||
new JProperty(DependencyContextStrings.RuntimeTargetPropertyName, WriteRuntimeTargetInfo(context)),
|
||||
new JProperty(DependencyContextStrings.CompilationOptionsPropertName, WriteCompilationOptions(context.CompilationOptions)),
|
||||
new JProperty(DependencyContextStrings.TargetsPropertyName, WriteTargets(context)),
|
||||
new JProperty(DependencyContextStrings.LibrariesPropertyName, WriteLibraries(context))
|
||||
);
|
||||
if (context.RuntimeGraph.Any())
|
||||
{
|
||||
contextObject.Add(new JProperty(DependencyContextStrings.RuntimesPropertyName, WriteRuntimeGraph(context)));
|
||||
}
|
||||
return contextObject;
|
||||
}
|
||||
|
||||
private string WriteRuntimeTargetInfo(DependencyContext context)
|
||||
{
|
||||
return context.IsPortable?
|
||||
context.TargetFramework :
|
||||
context.TargetFramework + DependencyContextStrings.VersionSeperator + context.Runtime;
|
||||
}
|
||||
|
||||
private JObject WriteRuntimeGraph(DependencyContext context)
|
||||
{
|
||||
return new JObject(
|
||||
context.RuntimeGraph.Select(g => new JProperty(g.Runtime, new JArray(g.Fallbacks)))
|
||||
);
|
||||
}
|
||||
|
||||
private JObject WriteCompilationOptions(CompilationOptions compilationOptions)
|
||||
{
|
||||
var o = new JObject();
|
||||
if (compilationOptions.Defines?.Any() == true)
|
||||
{
|
||||
o[DependencyContextStrings.DefinesPropertyName] = new JArray(compilationOptions.Defines);
|
||||
}
|
||||
AddPropertyIfNotNull(o, DependencyContextStrings.LanguageVersionPropertyName, compilationOptions.LanguageVersion);
|
||||
AddPropertyIfNotNull(o, DependencyContextStrings.PlatformPropertyName, compilationOptions.Platform);
|
||||
AddPropertyIfNotNull(o, DependencyContextStrings.AllowUnsafePropertyName, compilationOptions.AllowUnsafe);
|
||||
AddPropertyIfNotNull(o, DependencyContextStrings.WarningsAsErrorsPropertyName, compilationOptions.WarningsAsErrors);
|
||||
AddPropertyIfNotNull(o, DependencyContextStrings.OptimizePropertyName, compilationOptions.Optimize);
|
||||
AddPropertyIfNotNull(o, DependencyContextStrings.KeyFilePropertyName, compilationOptions.KeyFile);
|
||||
AddPropertyIfNotNull(o, DependencyContextStrings.DelaySignPropertyName, compilationOptions.DelaySign);
|
||||
AddPropertyIfNotNull(o, DependencyContextStrings.PublicSignPropertyName, compilationOptions.PublicSign);
|
||||
AddPropertyIfNotNull(o, DependencyContextStrings.EmitEntryPointPropertyName, compilationOptions.EmitEntryPoint);
|
||||
AddPropertyIfNotNull(o, DependencyContextStrings.GenerateXmlDocumentationPropertyName, compilationOptions.GenerateXmlDocumentation);
|
||||
AddPropertyIfNotNull(o, DependencyContextStrings.DebugTypePropertyName, compilationOptions.DebugType);
|
||||
return o;
|
||||
}
|
||||
|
||||
private void AddPropertyIfNotNull<T>(JObject o, string name, T value)
|
||||
{
|
||||
if (value != null)
|
||||
{
|
||||
o.Add(new JProperty(name, value));
|
||||
}
|
||||
}
|
||||
|
||||
private JObject WriteTargets(DependencyContext context)
|
||||
{
|
||||
if (context.IsPortable)
|
||||
{
|
||||
return new JObject(
|
||||
new JProperty(context.TargetFramework, WritePortableTarget(context.RuntimeLibraries, context.CompileLibraries))
|
||||
);
|
||||
}
|
||||
|
||||
return new JObject(
|
||||
new JProperty(context.TargetFramework, WriteTarget(context.CompileLibraries)),
|
||||
new JProperty(context.TargetFramework + DependencyContextStrings.VersionSeperator + context.Runtime,
|
||||
WriteTarget(context.RuntimeLibraries))
|
||||
);
|
||||
}
|
||||
|
||||
private JObject WriteTarget(IReadOnlyList<Library> libraries)
|
||||
{
|
||||
return new JObject(
|
||||
libraries.Select(library =>
|
||||
new JProperty(library.Name + DependencyContextStrings.VersionSeperator + library.Version, WriteTargetLibrary(library))));
|
||||
}
|
||||
|
||||
private JObject WritePortableTarget(IReadOnlyList<RuntimeLibrary> runtimeLibraries, IReadOnlyList<CompilationLibrary> compilationLibraries)
|
||||
{
|
||||
var runtimeLookup = runtimeLibraries.ToDictionary(l => l.Name);
|
||||
var compileLookup = compilationLibraries.ToDictionary(l => l.Name);
|
||||
|
||||
var targetObject = new JObject();
|
||||
|
||||
foreach (var packageName in runtimeLookup.Keys.Concat(compileLookup.Keys).Distinct())
|
||||
{
|
||||
RuntimeLibrary runtimeLibrary;
|
||||
runtimeLookup.TryGetValue(packageName, out runtimeLibrary);
|
||||
|
||||
CompilationLibrary compilationLibrary;
|
||||
compileLookup.TryGetValue(packageName, out compilationLibrary);
|
||||
|
||||
if (compilationLibrary != null && runtimeLibrary != null)
|
||||
{
|
||||
Debug.Assert(compilationLibrary.Serviceable == runtimeLibrary.Serviceable);
|
||||
Debug.Assert(compilationLibrary.Version == runtimeLibrary.Version);
|
||||
Debug.Assert(compilationLibrary.Hash == runtimeLibrary.Hash);
|
||||
Debug.Assert(compilationLibrary.Type == runtimeLibrary.Type);
|
||||
}
|
||||
|
||||
var library = (Library)compilationLibrary ?? (Library)runtimeLibrary;
|
||||
targetObject.Add(
|
||||
new JProperty(library.Name + DependencyContextStrings.VersionSeperator + library.Version,
|
||||
WritePortableTargetLibrary(runtimeLibrary, compilationLibrary)
|
||||
)
|
||||
);
|
||||
|
||||
}
|
||||
return targetObject;
|
||||
}
|
||||
|
||||
private void AddCompilationAssemblies(JObject libraryObject, IEnumerable<string> compilationAssemblies)
|
||||
{
|
||||
if (!compilationAssemblies.Any())
|
||||
{
|
||||
return;
|
||||
}
|
||||
libraryObject.Add(new JProperty(DependencyContextStrings.CompileTimeAssembliesKey,
|
||||
WriteAssetList(compilationAssemblies))
|
||||
);
|
||||
}
|
||||
|
||||
private void AddRuntimeAssemblies(JObject libraryObject, IEnumerable<RuntimeAssembly> runtimeAssemblies)
|
||||
{
|
||||
if (!runtimeAssemblies.Any())
|
||||
{
|
||||
return;
|
||||
}
|
||||
libraryObject.Add(new JProperty(DependencyContextStrings.RuntimeAssembliesKey,
|
||||
WriteAssetList(runtimeAssemblies.Select(a => a.Path)))
|
||||
);
|
||||
}
|
||||
|
||||
private void AddDependencies(JObject libraryObject, IEnumerable<Dependency> dependencies)
|
||||
{
|
||||
if (!dependencies.Any())
|
||||
{
|
||||
return;
|
||||
}
|
||||
libraryObject.AddFirst(
|
||||
new JProperty(DependencyContextStrings.DependenciesPropertyName,
|
||||
new JObject(
|
||||
dependencies.Select(dependency => new JProperty(dependency.Name, dependency.Version))))
|
||||
);
|
||||
}
|
||||
|
||||
private void AddResourceAssemblies(JObject libraryObject, IEnumerable<ResourceAssembly> resourceAssemblies)
|
||||
{
|
||||
if (!resourceAssemblies.Any())
|
||||
{
|
||||
return;
|
||||
}
|
||||
libraryObject.Add(DependencyContextStrings.ResourceAssembliesPropertyName,
|
||||
new JObject(resourceAssemblies.Select(a =>
|
||||
new JProperty(NormalizePath(a.Path), new JObject(new JProperty(DependencyContextStrings.LocalePropertyName, a.Locale))))
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private JObject WriteTargetLibrary(Library library)
|
||||
{
|
||||
var runtimeLibrary = library as RuntimeLibrary;
|
||||
if (runtimeLibrary != null)
|
||||
{
|
||||
var libraryObject = new JObject();
|
||||
AddDependencies(libraryObject, runtimeLibrary.Dependencies);
|
||||
AddRuntimeAssemblies(libraryObject, runtimeLibrary.Assemblies);
|
||||
AddResourceAssemblies(libraryObject, runtimeLibrary.ResourceAssemblies);
|
||||
|
||||
if (runtimeLibrary.NativeLibraries.Any())
|
||||
{
|
||||
libraryObject.Add(DependencyContextStrings.NativeLibrariesKey, WriteAssetList(runtimeLibrary.NativeLibraries));
|
||||
}
|
||||
|
||||
return libraryObject;
|
||||
}
|
||||
|
||||
var compilationLibrary = library as CompilationLibrary;
|
||||
if (compilationLibrary != null)
|
||||
{
|
||||
var libraryObject = new JObject();
|
||||
AddDependencies(libraryObject, compilationLibrary.Dependencies);
|
||||
AddCompilationAssemblies(libraryObject, compilationLibrary.Assemblies);
|
||||
return libraryObject;
|
||||
}
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
private JObject WritePortableTargetLibrary(RuntimeLibrary runtimeLibrary, CompilationLibrary compilationLibrary)
|
||||
{
|
||||
var libraryObject = new JObject();
|
||||
|
||||
var dependencies = new HashSet<Dependency>();
|
||||
if (runtimeLibrary != null)
|
||||
{
|
||||
|
||||
if (runtimeLibrary.RuntimeTargets.Any())
|
||||
{
|
||||
libraryObject.Add(new JProperty(
|
||||
DependencyContextStrings.RuntimeTargetsPropertyName,
|
||||
new JObject(runtimeLibrary.RuntimeTargets.SelectMany(WriteRuntimeTarget)))
|
||||
);
|
||||
}
|
||||
AddRuntimeAssemblies(libraryObject, runtimeLibrary.Assemblies);
|
||||
AddResourceAssemblies(libraryObject, runtimeLibrary.ResourceAssemblies);
|
||||
libraryObject.Add(DependencyContextStrings.NativeLibrariesKey, WriteAssetList(runtimeLibrary.NativeLibraries));
|
||||
|
||||
dependencies.UnionWith(runtimeLibrary.Dependencies);
|
||||
}
|
||||
|
||||
if (compilationLibrary != null)
|
||||
{
|
||||
AddCompilationAssemblies(libraryObject, compilationLibrary.Assemblies);
|
||||
|
||||
dependencies.UnionWith(compilationLibrary.Dependencies);
|
||||
}
|
||||
|
||||
AddDependencies(libraryObject, dependencies);
|
||||
return libraryObject;
|
||||
}
|
||||
|
||||
private IEnumerable<JProperty> WriteRuntimeTarget(RuntimeTarget target)
|
||||
{
|
||||
var runtime = WriteRuntimeTargetAssemblies(
|
||||
target.Assemblies.Select(a => a.Path),
|
||||
target.Runtime,
|
||||
DependencyContextStrings.RuntimeAssetType);
|
||||
|
||||
var native = WriteRuntimeTargetAssemblies(
|
||||
target.NativeLibraries,
|
||||
target.Runtime,
|
||||
DependencyContextStrings.NativeAssetType);
|
||||
|
||||
return runtime.Concat(native);
|
||||
}
|
||||
|
||||
private IEnumerable<JProperty> WriteRuntimeTargetAssemblies(IEnumerable<string> assemblies, string runtime, string assetType)
|
||||
{
|
||||
foreach (var assembly in assemblies)
|
||||
{
|
||||
yield return new JProperty(NormalizePath(assembly),
|
||||
new JObject(
|
||||
new JProperty(DependencyContextStrings.RidPropertyName, runtime),
|
||||
new JProperty(DependencyContextStrings.AssetTypePropertyName, assetType)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private JObject WriteAssetList(IEnumerable<string> assetPaths)
|
||||
{
|
||||
return new JObject(assetPaths.Select(assembly => new JProperty(NormalizePath(assembly), new JObject())));
|
||||
}
|
||||
|
||||
private JObject WriteLibraries(DependencyContext context)
|
||||
{
|
||||
var allLibraries =
|
||||
context.RuntimeLibraries.Cast<Library>().Concat(context.CompileLibraries)
|
||||
.GroupBy(library => library.Name + DependencyContextStrings.VersionSeperator + library.Version);
|
||||
|
||||
return new JObject(allLibraries.Select(libraries=> new JProperty(libraries.Key, WriteLibrary(libraries.First()))));
|
||||
}
|
||||
|
||||
private JObject WriteLibrary(Library library)
|
||||
{
|
||||
return new JObject(
|
||||
new JProperty(DependencyContextStrings.TypePropertyName, library.Type),
|
||||
new JProperty(DependencyContextStrings.ServiceablePropertyName, library.Serviceable),
|
||||
new JProperty(DependencyContextStrings.Sha512PropertyName, library.Hash)
|
||||
);
|
||||
}
|
||||
|
||||
private string NormalizePath(string path)
|
||||
{
|
||||
return path.Replace('\\', '/');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
using System.IO;
|
||||
|
||||
namespace Microsoft.Extensions.DependencyModel
|
||||
{
|
||||
internal interface IDependencyContextReader
|
||||
{
|
||||
DependencyContext Read(Stream stream);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.Extensions.DependencyModel
|
||||
{
|
||||
internal class Library
|
||||
{
|
||||
public Library(string type, string name, string version, string hash, IEnumerable<Dependency> dependencies, bool serviceable)
|
||||
{
|
||||
Type = type;
|
||||
Name = name;
|
||||
Version = version;
|
||||
Hash = hash;
|
||||
Dependencies = dependencies.ToArray();
|
||||
Serviceable = serviceable;
|
||||
}
|
||||
|
||||
public string Type { get; }
|
||||
|
||||
public string Name { get; }
|
||||
|
||||
public string Version { get; }
|
||||
|
||||
public string Hash { get; }
|
||||
|
||||
public IReadOnlyList<Dependency> Dependencies { get; }
|
||||
|
||||
public bool Serviceable { get; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Microsoft.Extensions.PlatformAbstractions;
|
||||
|
||||
namespace Microsoft.Extensions.DependencyModel.Resolution
|
||||
{
|
||||
internal class AppBaseCompilationAssemblyResolver : ICompilationAssemblyResolver
|
||||
{
|
||||
private readonly string _basePath;
|
||||
|
||||
public AppBaseCompilationAssemblyResolver()
|
||||
{
|
||||
_basePath = PlatformServices.Default.Application.ApplicationBasePath;
|
||||
}
|
||||
|
||||
public bool TryResolveAssemblyPaths(CompilationLibrary library, List<string> assemblies)
|
||||
{
|
||||
var isProject = string.Equals(library.Type, "project", StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
if (!isProject &&
|
||||
!string.Equals(library.Type, "package", StringComparison.OrdinalIgnoreCase) &&
|
||||
!string.Equals(library.Type, "referenceassembly", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var refsPath = Path.Combine(_basePath, "refs");
|
||||
var hasRefs = Directory.Exists(refsPath);
|
||||
|
||||
// Resolving packages and reference assebmlies requires refs folder to exist
|
||||
if (!isProject && !hasRefs)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var directories = new List<string>()
|
||||
{
|
||||
_basePath
|
||||
};
|
||||
|
||||
if (hasRefs)
|
||||
{
|
||||
directories.Insert(0, refsPath);
|
||||
}
|
||||
|
||||
foreach (var assembly in library.Assemblies)
|
||||
{
|
||||
bool resolved = false;
|
||||
var assemblyFile = Path.GetFileName(assembly);
|
||||
foreach (var directory in directories)
|
||||
{
|
||||
string fullName;
|
||||
if (ResolverUtils.TryResolveAssemblyFile(directory, assemblyFile, out fullName))
|
||||
{
|
||||
assemblies.Add(fullName);
|
||||
resolved = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!resolved)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
$"Can not find assembly file {assemblyFile} at '{string.Join(",", directories)}'");
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.Extensions.DependencyModel.Resolution
|
||||
{
|
||||
internal class CompositeCompilationAssemblyResolver: ICompilationAssemblyResolver
|
||||
{
|
||||
private readonly ICompilationAssemblyResolver[] _resolvers;
|
||||
|
||||
public CompositeCompilationAssemblyResolver(ICompilationAssemblyResolver[] resolvers)
|
||||
{
|
||||
_resolvers = resolvers;
|
||||
}
|
||||
|
||||
public bool TryResolveAssemblyPaths(CompilationLibrary library, List<string> assemblies)
|
||||
{
|
||||
foreach (var resolver in _resolvers)
|
||||
{
|
||||
if (resolver.TryResolveAssemblyPaths(library, assemblies))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using Microsoft.Extensions.PlatformAbstractions;
|
||||
|
||||
namespace Microsoft.Extensions.DependencyModel.Resolution
|
||||
{
|
||||
internal class DotNetReferenceAssembliesPathResolver
|
||||
{
|
||||
public static readonly string DotNetReferenceAssembliesPathEnv = "DOTNET_REFERENCE_ASSEMBLIES_PATH";
|
||||
|
||||
internal static string Resolve(IRuntimeEnvironment runtimeEnvironment)
|
||||
{
|
||||
var path = Environment.GetEnvironmentVariable(DotNetReferenceAssembliesPathEnv);
|
||||
if (!string.IsNullOrEmpty(path))
|
||||
{
|
||||
return path;
|
||||
}
|
||||
|
||||
return GetDefaultDotNetReferenceAssembliesPath(runtimeEnvironment);
|
||||
}
|
||||
|
||||
public static string Resolve()
|
||||
{
|
||||
return Resolve(PlatformServices.Default.Runtime);
|
||||
}
|
||||
|
||||
private static string GetDefaultDotNetReferenceAssembliesPath(IRuntimeEnvironment runtimeEnvironment)
|
||||
{
|
||||
var os = runtimeEnvironment.OperatingSystemPlatform;
|
||||
|
||||
if (os == Platform.Windows)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (os == Platform.Darwin &&
|
||||
Directory.Exists("/Library/Frameworks/Mono.framework/Versions/Current/lib/mono/xbuild-frameworks"))
|
||||
{
|
||||
return "/Library/Frameworks/Mono.framework/Versions/Current/lib/mono/xbuild-frameworks";
|
||||
}
|
||||
|
||||
if (Directory.Exists("/usr/local/lib/mono/xbuild-frameworks"))
|
||||
{
|
||||
return "/usr/local/lib/mono/xbuild-frameworks";
|
||||
}
|
||||
|
||||
if (Directory.Exists("/usr/lib/mono/xbuild-frameworks"))
|
||||
{
|
||||
return "/usr/lib/mono/xbuild-frameworks";
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.Extensions.DependencyModel.Resolution
|
||||
{
|
||||
internal interface ICompilationAssemblyResolver
|
||||
{
|
||||
bool TryResolveAssemblyPaths(CompilationLibrary library, List<string> assemblies);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace Microsoft.Extensions.DependencyModel.Resolution
|
||||
{
|
||||
internal class PackageCacheCompilationAssemblyResolver: ICompilationAssemblyResolver
|
||||
{
|
||||
private readonly string _packageCacheDirectory;
|
||||
|
||||
internal PackageCacheCompilationAssemblyResolver()
|
||||
{
|
||||
_packageCacheDirectory = Environment.GetEnvironmentVariable("DOTNET_PACKAGES_CACHE");
|
||||
}
|
||||
|
||||
public bool TryResolveAssemblyPaths(CompilationLibrary library, List<string> assemblies)
|
||||
{
|
||||
if (!string.Equals(library.Type, "package", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(_packageCacheDirectory))
|
||||
{
|
||||
var hashSplitterPos = library.Hash.IndexOf('-');
|
||||
if (hashSplitterPos <= 0 || hashSplitterPos == library.Hash.Length - 1)
|
||||
{
|
||||
throw new InvalidOperationException($"Invalid hash entry '{library.Hash}' for package '{library.Name}'");
|
||||
}
|
||||
|
||||
string packagePath;
|
||||
if (ResolverUtils.TryResolvePackagePath(library, _packageCacheDirectory, out packagePath))
|
||||
{
|
||||
var hashAlgorithm = library.Hash.Substring(0, hashSplitterPos);
|
||||
var cacheHashPath = Path.Combine(packagePath, $"{library.Name}.{library.Version}.nupkg.{hashAlgorithm}");
|
||||
|
||||
if (File.Exists(cacheHashPath) &&
|
||||
File.ReadAllText(cacheHashPath) == library.Hash.Substring(hashSplitterPos + 1))
|
||||
{
|
||||
assemblies.AddRange(ResolverUtils.ResolveFromPackagePath(library, packagePath));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Microsoft.Extensions.PlatformAbstractions;
|
||||
|
||||
namespace Microsoft.Extensions.DependencyModel.Resolution
|
||||
{
|
||||
internal class PackageCompilationAssemblyResolver: ICompilationAssemblyResolver
|
||||
{
|
||||
private readonly string _nugetPackageDirectory;
|
||||
|
||||
internal PackageCompilationAssemblyResolver()
|
||||
{
|
||||
_nugetPackageDirectory = GetDefaultPackageDirectory(PlatformServices.Default.Runtime);
|
||||
}
|
||||
|
||||
internal static string GetDefaultPackageDirectory(IRuntimeEnvironment runtimeEnvironment)
|
||||
{
|
||||
var packageDirectory = Environment.GetEnvironmentVariable("NUGET_PACKAGES");
|
||||
|
||||
if (!string.IsNullOrEmpty(packageDirectory))
|
||||
{
|
||||
return packageDirectory;
|
||||
}
|
||||
|
||||
string basePath;
|
||||
if (runtimeEnvironment.OperatingSystemPlatform == Platform.Windows)
|
||||
{
|
||||
basePath = Environment.GetEnvironmentVariable("USERPROFILE");
|
||||
}
|
||||
else
|
||||
{
|
||||
basePath = Environment.GetEnvironmentVariable("HOME");
|
||||
}
|
||||
if (string.IsNullOrEmpty(basePath))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return Path.Combine(basePath, ".nuget", "packages");
|
||||
}
|
||||
|
||||
public bool TryResolveAssemblyPaths(CompilationLibrary library, List<string> assemblies)
|
||||
{
|
||||
if (string.IsNullOrEmpty(_nugetPackageDirectory) ||
|
||||
!string.Equals(library.Type, "package", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
string packagePath;
|
||||
|
||||
if (ResolverUtils.TryResolvePackagePath(library, _nugetPackageDirectory, out packagePath))
|
||||
{
|
||||
assemblies.AddRange(ResolverUtils.ResolveFromPackagePath(library, packagePath));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,121 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Microsoft.Extensions.PlatformAbstractions;
|
||||
|
||||
namespace Microsoft.Extensions.DependencyModel.Resolution
|
||||
{
|
||||
internal class ReferenceAssemblyPathResolver: ICompilationAssemblyResolver
|
||||
{
|
||||
private readonly string _defaultReferenceAssembliesPath;
|
||||
private readonly string[] _fallbackSearchPaths;
|
||||
|
||||
internal ReferenceAssemblyPathResolver()
|
||||
{
|
||||
_defaultReferenceAssembliesPath = GetDefaultReferenceAssembliesPath(PlatformServices.Default.Runtime);
|
||||
_fallbackSearchPaths = GetFallbackSearchPaths(PlatformServices.Default.Runtime);
|
||||
}
|
||||
|
||||
public bool TryResolveAssemblyPaths(CompilationLibrary library, List<string> assemblies)
|
||||
{
|
||||
if (!string.Equals(library.Type, "referenceassembly", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
foreach (var assembly in library.Assemblies)
|
||||
{
|
||||
string fullName;
|
||||
if (!TryResolveReferenceAssembly(assembly, out fullName))
|
||||
{
|
||||
throw new InvalidOperationException($"Can not find reference assembly '{assembly}' file for package {library.Name}");
|
||||
}
|
||||
assemblies.Add(fullName);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool TryResolveReferenceAssembly(string path, out string fullPath)
|
||||
{
|
||||
fullPath = null;
|
||||
|
||||
if (_defaultReferenceAssembliesPath != null)
|
||||
{
|
||||
var relativeToReferenceAssemblies = Path.Combine(_defaultReferenceAssembliesPath, path);
|
||||
if (File.Exists(relativeToReferenceAssemblies))
|
||||
{
|
||||
fullPath = relativeToReferenceAssemblies;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
var name = Path.GetFileName(path);
|
||||
foreach (var fallbackPath in _fallbackSearchPaths)
|
||||
{
|
||||
var fallbackFile = Path.Combine(fallbackPath, name);
|
||||
if (File.Exists(fallbackFile))
|
||||
{
|
||||
fullPath = fallbackFile;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
internal static string[] GetFallbackSearchPaths(IRuntimeEnvironment runtimeEnvironment)
|
||||
{
|
||||
if (runtimeEnvironment.OperatingSystemPlatform != Platform.Windows)
|
||||
{
|
||||
return new string[0];
|
||||
}
|
||||
|
||||
var net20Dir = Path.Combine(Environment.GetEnvironmentVariable("WINDIR"), "Microsoft.NET", "Framework", "v2.0.50727");
|
||||
|
||||
if (!Directory.Exists(net20Dir))
|
||||
{
|
||||
return new string[0];
|
||||
}
|
||||
return new[] { net20Dir };
|
||||
}
|
||||
|
||||
internal static string GetDefaultReferenceAssembliesPath(IRuntimeEnvironment runtimeEnvironment)
|
||||
{
|
||||
// Allow setting the reference assemblies path via an environment variable
|
||||
var referenceAssembliesPath = DotNetReferenceAssembliesPathResolver.Resolve(runtimeEnvironment);
|
||||
if (!string.IsNullOrEmpty(referenceAssembliesPath))
|
||||
{
|
||||
return referenceAssembliesPath;
|
||||
}
|
||||
|
||||
if (runtimeEnvironment.OperatingSystemPlatform != Platform.Windows)
|
||||
{
|
||||
// There is no reference assemblies path outside of windows
|
||||
// The environment variable can be used to specify one
|
||||
return null;
|
||||
}
|
||||
|
||||
// References assemblies are in %ProgramFiles(x86)% on
|
||||
// 64 bit machines
|
||||
var programFiles = Environment.GetEnvironmentVariable("ProgramFiles(x86)");
|
||||
|
||||
if (string.IsNullOrEmpty(programFiles))
|
||||
{
|
||||
// On 32 bit machines they are in %ProgramFiles%
|
||||
programFiles = Environment.GetEnvironmentVariable("ProgramFiles");
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(programFiles))
|
||||
{
|
||||
// Reference assemblies aren't installed
|
||||
return null;
|
||||
}
|
||||
|
||||
return Path.Combine(
|
||||
programFiles,
|
||||
"Reference Assemblies", "Microsoft", "Framework");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace Microsoft.Extensions.DependencyModel.Resolution
|
||||
{
|
||||
internal static class ResolverUtils
|
||||
{
|
||||
internal static bool TryResolvePackagePath(CompilationLibrary library, string basePath, out string packagePath)
|
||||
{
|
||||
packagePath = Path.Combine(basePath, library.Name, library.Version);
|
||||
if (Directory.Exists(packagePath))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
internal static IEnumerable<string> ResolveFromPackagePath(CompilationLibrary library, string basePath)
|
||||
{
|
||||
foreach (var assembly in library.Assemblies)
|
||||
{
|
||||
string fullName;
|
||||
if (!TryResolveAssemblyFile(basePath, assembly, out fullName))
|
||||
{
|
||||
throw new InvalidOperationException($"Can not find assembly file for package {library.Name} at '{fullName}'");
|
||||
}
|
||||
yield return fullName;
|
||||
}
|
||||
}
|
||||
|
||||
internal static bool TryResolveAssemblyFile(string basePath, string assemblyPath, out string fullName)
|
||||
{
|
||||
fullName = Path.Combine(basePath, assemblyPath);
|
||||
if (File.Exists(fullName))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
namespace Microsoft.Extensions.DependencyModel
|
||||
{
|
||||
internal class ResourceAssembly
|
||||
{
|
||||
public ResourceAssembly(string path, string locale)
|
||||
{
|
||||
Locale = locale;
|
||||
Path = path;
|
||||
}
|
||||
|
||||
public string Locale { get; set; }
|
||||
|
||||
public string Path { get; set; }
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Microsoft.Extensions.DependencyModel
|
||||
{
|
||||
internal class RuntimeAssembly
|
||||
{
|
||||
private const string NativeImageSufix = ".ni";
|
||||
private readonly string _assemblyName;
|
||||
|
||||
public RuntimeAssembly(string assemblyName, string path)
|
||||
{
|
||||
_assemblyName = assemblyName;
|
||||
Path = path;
|
||||
}
|
||||
|
||||
public AssemblyName Name => new AssemblyName(_assemblyName);
|
||||
|
||||
public string Path { get; }
|
||||
|
||||
public static RuntimeAssembly Create(string path)
|
||||
{
|
||||
var assemblyName = System.IO.Path.GetFileNameWithoutExtension(path);
|
||||
if (assemblyName == null)
|
||||
{
|
||||
throw new ArgumentException($"Provided path has empty file name '{path}'", nameof(path));
|
||||
}
|
||||
|
||||
if (assemblyName.EndsWith(NativeImageSufix))
|
||||
{
|
||||
assemblyName = assemblyName.Substring(0, assemblyName.Length - NativeImageSufix.Length);
|
||||
}
|
||||
return new RuntimeAssembly(assemblyName, path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Microsoft.Extensions.DependencyModel
|
||||
{
|
||||
internal class RuntimeFallbacks
|
||||
{
|
||||
public string Runtime { get; set; }
|
||||
public IReadOnlyList<string> Fallbacks { get; set; }
|
||||
|
||||
public RuntimeFallbacks(string runtime, IEnumerable<string> fallbacks)
|
||||
{
|
||||
if (runtime == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(runtime));
|
||||
}
|
||||
if (fallbacks == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(fallbacks));
|
||||
}
|
||||
Runtime = runtime;
|
||||
Fallbacks = fallbacks.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Microsoft.Extensions.DependencyModel
|
||||
{
|
||||
internal class RuntimeLibrary : Library
|
||||
{
|
||||
public RuntimeLibrary(
|
||||
string type,
|
||||
string name,
|
||||
string version,
|
||||
string hash,
|
||||
IEnumerable<RuntimeAssembly> assemblies,
|
||||
IEnumerable<string> nativeLibraries,
|
||||
IEnumerable<ResourceAssembly> resourceAssemblies,
|
||||
IEnumerable<RuntimeTarget> subTargets,
|
||||
IEnumerable<Dependency> dependencies,
|
||||
bool serviceable)
|
||||
: base(type, name, version, hash, dependencies, serviceable)
|
||||
{
|
||||
Assemblies = assemblies.ToArray();
|
||||
ResourceAssemblies = resourceAssemblies.ToArray();
|
||||
RuntimeTargets = subTargets.ToArray();
|
||||
NativeLibraries = nativeLibraries.ToArray();
|
||||
}
|
||||
|
||||
public IReadOnlyList<RuntimeAssembly> Assemblies { get; }
|
||||
|
||||
public IReadOnlyList<string> NativeLibraries { get; }
|
||||
|
||||
public IReadOnlyList<ResourceAssembly> ResourceAssemblies { get; }
|
||||
|
||||
public IReadOnlyList<RuntimeTarget> RuntimeTargets { get; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Microsoft.Extensions.DependencyModel
|
||||
{
|
||||
internal class RuntimeTarget
|
||||
{
|
||||
public RuntimeTarget(string runtime, IEnumerable<RuntimeAssembly> assemblies, IEnumerable<string> nativeLibraries)
|
||||
{
|
||||
Runtime = runtime;
|
||||
Assemblies = assemblies.ToArray();
|
||||
NativeLibraries = nativeLibraries.ToArray();
|
||||
}
|
||||
|
||||
public string Runtime { get; }
|
||||
|
||||
public IReadOnlyList<RuntimeAssembly> Assemblies { get; }
|
||||
|
||||
public IReadOnlyList<string> NativeLibraries { get; }
|
||||
}
|
||||
}
|
||||
|
|
@ -88,7 +88,7 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure
|
|||
/// </summary>
|
||||
/// <returns>A set of <see cref="Library"/>.</returns>
|
||||
// Internal for unit testing
|
||||
protected internal virtual IEnumerable<RuntimeLibrary> GetCandidateLibraries()
|
||||
internal virtual IEnumerable<RuntimeLibrary> GetCandidateLibraries()
|
||||
{
|
||||
if (ReferenceAssemblies == null)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -24,7 +24,6 @@
|
|||
"version": "1.0.0-*"
|
||||
},
|
||||
"Microsoft.Extensions.FileProviders.Abstractions": "1.0.0-*",
|
||||
"Microsoft.Extensions.DependencyModel": "1.0.0-*",
|
||||
"Microsoft.Extensions.ClosedGenericMatcher.Sources": {
|
||||
"version": "1.0.0-*",
|
||||
"type": "build"
|
||||
|
|
@ -34,6 +33,7 @@
|
|||
"type": "build",
|
||||
"version": "1.0.0-*"
|
||||
},
|
||||
"Microsoft.Extensions.PlatformAbstractions": "1.0.0-*",
|
||||
"Microsoft.Extensions.PropertyActivator.Sources": {
|
||||
"version": "1.0.0-*",
|
||||
"type": "build"
|
||||
|
|
@ -46,6 +46,7 @@
|
|||
"version": "1.0.0-*",
|
||||
"type": "build"
|
||||
},
|
||||
"Newtonsoft.Json": "8.0.3",
|
||||
"System.Buffers": "4.0.0-*",
|
||||
"System.Diagnostics.DiagnosticSource": "4.0.0-*"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal
|
|||
{
|
||||
var parseOptions = options.ParseOptions;
|
||||
parseOptions = parseOptions.WithPreprocessorSymbols(
|
||||
parseOptions.PreprocessorSymbolNames.Concat(compilationOptions.Defines));
|
||||
parseOptions.PreprocessorSymbolNames.Concat(compilationOptions.Defines ?? Enumerable.Empty<string>()));
|
||||
|
||||
LanguageVersion languageVersion;
|
||||
if (!string.IsNullOrEmpty(compilationOptions.LanguageVersion) &&
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
],
|
||||
"xmlDoc": true
|
||||
},
|
||||
"compile": "../Microsoft.AspNetCore.Mvc.Core/DependencyContext/**/*.cs",
|
||||
"dependencies": {
|
||||
"Microsoft.AspNetCore.Mvc.Razor.Host": "1.0.0-*",
|
||||
"Microsoft.AspNetCore.Mvc.ViewFeatures": "1.0.0-*",
|
||||
|
|
@ -44,7 +45,7 @@
|
|||
"netstandard1.5": {
|
||||
"imports": [
|
||||
"dotnet5.6",
|
||||
"portable-net45+win8"
|
||||
"portable-net451+win8"
|
||||
],
|
||||
"dependencies": {
|
||||
"System.Text.Encoding": "4.0.11-*",
|
||||
|
|
|
|||
|
|
@ -1,220 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyModel;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.Infrastructure
|
||||
{
|
||||
public class DefaultAssemblyProviderTests
|
||||
{
|
||||
private static readonly Assembly CurrentAssembly = typeof(DefaultAssemblyProviderTests).GetTypeInfo().Assembly;
|
||||
|
||||
[Fact]
|
||||
public void GetCandidateLibraries_IgnoresMvcAssemblies()
|
||||
{
|
||||
// Arrange
|
||||
var expected = GetLibrary("SomeRandomAssembly", "Microsoft.AspNetCore.Mvc.Abstractions");
|
||||
var dependencyContext = new DependencyContext(
|
||||
target: null,
|
||||
runtime: null,
|
||||
compilationOptions: CompilationOptions.Default,
|
||||
compileLibraries: new CompilationLibrary[0],
|
||||
runtimeLibraries: new[]
|
||||
{
|
||||
GetLibrary("Microsoft.AspNetCore.Mvc.Core"),
|
||||
GetLibrary("Microsoft.AspNetCore.Mvc"),
|
||||
GetLibrary("Microsoft.AspNetCore.Mvc.Abstractions"),
|
||||
expected,
|
||||
});
|
||||
var provider = new DefaultAssemblyProvider(CurrentAssembly, dependencyContext);
|
||||
|
||||
// Act
|
||||
var candidates = provider.GetCandidateLibraries();
|
||||
|
||||
// Assert
|
||||
Assert.Equal(new[] { expected }, candidates);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CandidateAssemblies_ReturnsEntryAssemblyIfDependencyContextIsNull()
|
||||
{
|
||||
// Arrange
|
||||
var provider = new DefaultAssemblyProvider(CurrentAssembly, dependencyContext: null);
|
||||
|
||||
// Act
|
||||
var candidates = provider.CandidateAssemblies;
|
||||
|
||||
// Assert
|
||||
Assert.Equal(new[] { CurrentAssembly }, candidates);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetCandidateLibraries_ReturnsLibrariesReferencingAnyMvcAssembly()
|
||||
{
|
||||
// Arrange
|
||||
var dependencyContext = new DependencyContext(
|
||||
target: null,
|
||||
runtime: null,
|
||||
compilationOptions: CompilationOptions.Default,
|
||||
compileLibraries: new CompilationLibrary[0],
|
||||
runtimeLibraries: new[]
|
||||
{
|
||||
GetLibrary("Foo", "Microsoft.AspNetCore.Mvc.Core"),
|
||||
GetLibrary("Bar", "Microsoft.AspNetCore.Mvc"),
|
||||
GetLibrary("Qux", "Not.Mvc.Assembly", "Unofficial.Microsoft.AspNetCore.Mvc"),
|
||||
GetLibrary("Baz", "Microsoft.AspNetCore.Mvc.Abstractions"),
|
||||
});
|
||||
var provider = new DefaultAssemblyProvider(CurrentAssembly, dependencyContext);
|
||||
|
||||
// Act
|
||||
var candidates = provider.GetCandidateLibraries();
|
||||
|
||||
// Assert
|
||||
Assert.Equal(new[] { "Foo", "Bar", "Baz" }, candidates.Select(a => a.PackageName));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetCandidateLibraries_ReturnsLibrariesReferencingOverriddenAssemblies()
|
||||
{
|
||||
// Arrange
|
||||
var dependencyContext = new DependencyContext(
|
||||
target: null,
|
||||
runtime: null,
|
||||
compilationOptions: CompilationOptions.Default,
|
||||
compileLibraries: new CompilationLibrary[0],
|
||||
runtimeLibraries: new[]
|
||||
{
|
||||
GetLibrary("Foo", "CustomMvc.Modules"),
|
||||
GetLibrary("Bar", "CustomMvc.Application.Loader"),
|
||||
GetLibrary("Baz", "Microsoft.AspNetCore.Mvc.Abstractions"),
|
||||
});
|
||||
var referenceAssemblies = new HashSet<string>
|
||||
{
|
||||
"CustomMvc.Modules",
|
||||
"CustomMvc.Application.Loader"
|
||||
};
|
||||
var assemblyProvider = new OverridenAssemblyProvider(
|
||||
CurrentAssembly,
|
||||
dependencyContext,
|
||||
referenceAssemblies);
|
||||
|
||||
// Act
|
||||
var candidates = assemblyProvider.GetCandidateLibraries();
|
||||
|
||||
// Assert
|
||||
Assert.Equal(new[] { "Foo", "Bar" }, candidates.Select(a => a.PackageName));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetCandidateLibraries_ReturnsEmptySequenceWhenReferenceAssembliesIsNull()
|
||||
{
|
||||
// Arrange
|
||||
var dependencyContext = new DependencyContext(
|
||||
target: null,
|
||||
runtime: null,
|
||||
compilationOptions: CompilationOptions.Default,
|
||||
compileLibraries: new CompilationLibrary[0],
|
||||
runtimeLibraries: new[]
|
||||
{
|
||||
GetLibrary("Foo", "CustomMvc.Modules"),
|
||||
GetLibrary("Bar", "CustomMvc.Application.Loader"),
|
||||
GetLibrary("Baz", "Microsoft.AspNetCore.Mvc.Abstractions"),
|
||||
});
|
||||
var assemblyProvider = new OverridenAssemblyProvider(
|
||||
CurrentAssembly,
|
||||
dependencyContext,
|
||||
referenceAssemblies: null);
|
||||
|
||||
// Act
|
||||
var candidates = assemblyProvider.GetCandidateLibraries();
|
||||
|
||||
// Assert
|
||||
Assert.Empty(candidates);
|
||||
}
|
||||
|
||||
// This test verifies DefaultAssemblyProvider.ReferenceAssemblies reflects the actual loadable assemblies
|
||||
// of the libraries that Microsoft.AspNetCore.Mvc dependes on.
|
||||
// If we add or remove dependencies, this test should be changed together.
|
||||
[Fact]
|
||||
public void ReferenceAssemblies_ReturnsLoadableReferenceAssemblies()
|
||||
{
|
||||
// Arrange
|
||||
var provider = new TestableAssemblyProvider(CurrentAssembly, dependencyContext: null);
|
||||
var excludeAssemblies = new string[]
|
||||
{
|
||||
"Microsoft.AspNetCore.Mvc.WebApiCompatShim",
|
||||
"Microsoft.AspNetCore.Mvc.TestCommon",
|
||||
"Microsoft.AspNetCore.Mvc.Core.Test",
|
||||
"Microsoft.AspNetCore.Mvc.TestDiagnosticListener.Sources",
|
||||
};
|
||||
|
||||
var additionalAssemblies = new[]
|
||||
{
|
||||
// The following assemblies are not reachable from Microsoft.AspNetCore.Mvc
|
||||
"Microsoft.AspNetCore.Mvc.TagHelpers",
|
||||
"Microsoft.AspNetCore.Mvc.Formatters.Xml",
|
||||
};
|
||||
|
||||
var expected = DependencyContext.Load(CurrentAssembly)
|
||||
.RuntimeLibraries
|
||||
.Where(r => r.PackageName.StartsWith("Microsoft.AspNetCore.Mvc", StringComparison.Ordinal) &&
|
||||
!excludeAssemblies.Contains(r.PackageName, StringComparer.OrdinalIgnoreCase))
|
||||
.Select(r => r.PackageName)
|
||||
.Concat(additionalAssemblies)
|
||||
.Distinct()
|
||||
.OrderBy(p => p, StringComparer.Ordinal);
|
||||
|
||||
// Act
|
||||
var referenceAssemblies = provider.ReferenceAssemblies.OrderBy(p => p, StringComparer.Ordinal);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expected, referenceAssemblies);
|
||||
}
|
||||
|
||||
private static RuntimeLibrary GetLibrary(string name, params string[] dependencyNames)
|
||||
{
|
||||
var dependencies = dependencyNames?.Select(d => new Dependency(d, "42.0.0")) ?? new Dependency[0];
|
||||
|
||||
return new RuntimeLibrary(
|
||||
"package",
|
||||
name,
|
||||
"23.0.0",
|
||||
"hash",
|
||||
new[] { $"{name}.dll" },
|
||||
dependencies: dependencies.ToArray(),
|
||||
serviceable: true);
|
||||
}
|
||||
|
||||
private class OverridenAssemblyProvider : DefaultAssemblyProvider
|
||||
{
|
||||
public OverridenAssemblyProvider(
|
||||
Assembly entryAssembly,
|
||||
DependencyContext dependencyContext,
|
||||
HashSet<string> referenceAssemblies)
|
||||
: base(entryAssembly, dependencyContext)
|
||||
{
|
||||
ReferenceAssemblies = referenceAssemblies;
|
||||
}
|
||||
|
||||
protected override HashSet<string> ReferenceAssemblies { get; }
|
||||
}
|
||||
|
||||
private class TestableAssemblyProvider : DefaultAssemblyProvider
|
||||
{
|
||||
public TestableAssemblyProvider(
|
||||
Assembly entryAssembly,
|
||||
DependencyContext dependencyContext)
|
||||
: base(entryAssembly, dependencyContext)
|
||||
{
|
||||
}
|
||||
|
||||
public new HashSet<string> ReferenceAssemblies => base.ReferenceAssemblies;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,425 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using Microsoft.AspNetCore.Mvc.Razor.Compilation;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.Text;
|
||||
using Microsoft.Extensions.DependencyModel;
|
||||
using Microsoft.Extensions.FileProviders;
|
||||
using Microsoft.Extensions.Logging.Testing;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.Razor.Internal
|
||||
{
|
||||
public class DefaultRoslynCompilationServiceTest
|
||||
{
|
||||
[Fact]
|
||||
public void Compile_ReturnsCompilationResult()
|
||||
{
|
||||
// Arrange
|
||||
var content = @"
|
||||
public class MyTestType {}";
|
||||
|
||||
var compilationService = new DefaultRoslynCompilationService(
|
||||
GetDependencyContext(),
|
||||
GetOptions(),
|
||||
GetFileProviderAccessor(),
|
||||
NullLoggerFactory.Instance);
|
||||
var relativeFileInfo = new RelativeFileInfo(
|
||||
new TestFileInfo { PhysicalPath = "SomePath" },
|
||||
"some-relative-path");
|
||||
|
||||
// Act
|
||||
var result = compilationService.Compile(relativeFileInfo, content);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("MyTestType", result.CompiledType.Name);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Compile_ReturnsCompilationFailureWithPathsFromLinePragmas()
|
||||
{
|
||||
// Arrange
|
||||
var viewPath = "some-relative-path";
|
||||
var fileContent = "test file content";
|
||||
var content = $@"
|
||||
#line 1 ""{viewPath}""
|
||||
this should fail";
|
||||
var fileProvider = new TestFileProvider();
|
||||
var fileInfo = fileProvider.AddFile(viewPath, fileContent);
|
||||
|
||||
var compilationService = new DefaultRoslynCompilationService(
|
||||
GetDependencyContext(),
|
||||
GetOptions(),
|
||||
GetFileProviderAccessor(fileProvider),
|
||||
NullLoggerFactory.Instance);
|
||||
var relativeFileInfo = new RelativeFileInfo(fileInfo, "some-relative-path");
|
||||
|
||||
// Act
|
||||
var result = compilationService.Compile(relativeFileInfo, content);
|
||||
|
||||
// Assert
|
||||
Assert.IsType<CompilationResult>(result);
|
||||
Assert.Null(result.CompiledType);
|
||||
var compilationFailure = Assert.Single(result.CompilationFailures);
|
||||
Assert.Equal(relativeFileInfo.RelativePath, compilationFailure.SourceFilePath);
|
||||
Assert.Equal(fileContent, compilationFailure.SourceFileContent);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Compile_ReturnsGeneratedCodePath_IfLinePragmaIsNotAvailable()
|
||||
{
|
||||
// Arrange
|
||||
var fileContent = "file content";
|
||||
var content = @"this should fail";
|
||||
|
||||
var compilationService = new DefaultRoslynCompilationService(
|
||||
GetDependencyContext(),
|
||||
GetOptions(),
|
||||
GetFileProviderAccessor(),
|
||||
NullLoggerFactory.Instance);
|
||||
var relativeFileInfo = new RelativeFileInfo(
|
||||
new TestFileInfo { Content = fileContent },
|
||||
"some-relative-path");
|
||||
|
||||
// Act
|
||||
var result = compilationService.Compile(relativeFileInfo, content);
|
||||
|
||||
// Assert
|
||||
Assert.IsType<CompilationResult>(result);
|
||||
Assert.Null(result.CompiledType);
|
||||
|
||||
var compilationFailure = Assert.Single(result.CompilationFailures);
|
||||
Assert.Equal("Generated Code", compilationFailure.SourceFilePath);
|
||||
Assert.Equal(content, compilationFailure.SourceFileContent);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Compile_DoesNotThrow_IfFileCannotBeRead()
|
||||
{
|
||||
// Arrange
|
||||
var path = "some-relative-path";
|
||||
var content = $@"
|
||||
#line 1 ""{path}""
|
||||
this should fail";
|
||||
|
||||
var mockFileInfo = new Mock<IFileInfo>();
|
||||
mockFileInfo.Setup(f => f.CreateReadStream())
|
||||
.Throws(new Exception());
|
||||
var fileProvider = new TestFileProvider();
|
||||
fileProvider.AddFile(path, mockFileInfo.Object);
|
||||
|
||||
var compilationService = new DefaultRoslynCompilationService(
|
||||
GetDependencyContext(),
|
||||
GetOptions(),
|
||||
GetFileProviderAccessor(),
|
||||
NullLoggerFactory.Instance);
|
||||
var relativeFileInfo = new RelativeFileInfo(mockFileInfo.Object, path);
|
||||
|
||||
// Act
|
||||
var result = compilationService.Compile(relativeFileInfo, content);
|
||||
|
||||
// Assert
|
||||
Assert.IsType<CompilationResult>(result);
|
||||
Assert.Null(result.CompiledType);
|
||||
var compilationFailure = Assert.Single(result.CompilationFailures);
|
||||
Assert.Equal(path, compilationFailure.SourceFilePath);
|
||||
Assert.Null(compilationFailure.SourceFileContent);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Compile_UsesApplicationsCompilationSettings_ForParsingAndCompilation()
|
||||
{
|
||||
// Arrange
|
||||
var content = @"
|
||||
#if MY_CUSTOM_DEFINE
|
||||
public class MyCustomDefinedClass {}
|
||||
#else
|
||||
public class MyNonCustomDefinedClass {}
|
||||
#endif
|
||||
";
|
||||
|
||||
var options = GetOptions();
|
||||
options.ParseOptions = options.ParseOptions.WithPreprocessorSymbols("MY_CUSTOM_DEFINE");
|
||||
|
||||
var compilationService = new DefaultRoslynCompilationService(
|
||||
GetDependencyContext(),
|
||||
options,
|
||||
GetFileProviderAccessor(),
|
||||
NullLoggerFactory.Instance);
|
||||
var relativeFileInfo = new RelativeFileInfo(
|
||||
new TestFileInfo { PhysicalPath = "SomePath" },
|
||||
"some-relative-path");
|
||||
|
||||
// Act
|
||||
var result = compilationService.Compile(relativeFileInfo, content);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result.CompiledType);
|
||||
Assert.Equal("MyCustomDefinedClass", result.CompiledType.Name);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetCompilationFailedResult_ReturnsCompilationResult_WithGroupedMessages()
|
||||
{
|
||||
// Arrange
|
||||
var viewPath = "Views/Home/Index";
|
||||
var generatedCodeFileName = "Generated Code";
|
||||
var fileProvider = new TestFileProvider();
|
||||
fileProvider.AddFile(viewPath, "view-content");
|
||||
var options = new RazorViewEngineOptions();
|
||||
options.FileProviders.Add(fileProvider);
|
||||
|
||||
var compilationService = new DefaultRoslynCompilationService(
|
||||
GetDependencyContext(),
|
||||
options,
|
||||
GetFileProviderAccessor(fileProvider),
|
||||
NullLoggerFactory.Instance);
|
||||
|
||||
var assemblyName = "random-assembly-name";
|
||||
|
||||
var diagnostics = new[]
|
||||
{
|
||||
Diagnostic.Create(
|
||||
GetDiagnosticDescriptor("message-1"),
|
||||
Location.Create(
|
||||
viewPath,
|
||||
new TextSpan(10, 5),
|
||||
new LinePositionSpan(new LinePosition(10, 1), new LinePosition(10, 2)))),
|
||||
Diagnostic.Create(
|
||||
GetDiagnosticDescriptor("message-2"),
|
||||
Location.Create(
|
||||
assemblyName,
|
||||
new TextSpan(1, 6),
|
||||
new LinePositionSpan(new LinePosition(1, 2), new LinePosition(3, 4)))),
|
||||
Diagnostic.Create(
|
||||
GetDiagnosticDescriptor("message-3"),
|
||||
Location.Create(
|
||||
viewPath,
|
||||
new TextSpan(40, 50),
|
||||
new LinePositionSpan(new LinePosition(30, 5), new LinePosition(40, 12)))),
|
||||
};
|
||||
|
||||
// Act
|
||||
var compilationResult = compilationService.GetCompilationFailedResult(
|
||||
viewPath,
|
||||
"compilation-content",
|
||||
assemblyName,
|
||||
diagnostics);
|
||||
|
||||
// Assert
|
||||
Assert.Collection(compilationResult.CompilationFailures,
|
||||
failure =>
|
||||
{
|
||||
Assert.Equal(viewPath, failure.SourceFilePath);
|
||||
Assert.Equal("view-content", failure.SourceFileContent);
|
||||
Assert.Collection(failure.Messages,
|
||||
message =>
|
||||
{
|
||||
Assert.Equal("message-1", message.Message);
|
||||
Assert.Equal(viewPath, message.SourceFilePath);
|
||||
Assert.Equal(11, message.StartLine);
|
||||
Assert.Equal(2, message.StartColumn);
|
||||
Assert.Equal(11, message.EndLine);
|
||||
Assert.Equal(3, message.EndColumn);
|
||||
},
|
||||
message =>
|
||||
{
|
||||
Assert.Equal("message-3", message.Message);
|
||||
Assert.Equal(viewPath, message.SourceFilePath);
|
||||
Assert.Equal(31, message.StartLine);
|
||||
Assert.Equal(6, message.StartColumn);
|
||||
Assert.Equal(41, message.EndLine);
|
||||
Assert.Equal(13, message.EndColumn);
|
||||
});
|
||||
},
|
||||
failure =>
|
||||
{
|
||||
Assert.Equal(generatedCodeFileName, failure.SourceFilePath);
|
||||
Assert.Equal("compilation-content", failure.SourceFileContent);
|
||||
Assert.Collection(failure.Messages,
|
||||
message =>
|
||||
{
|
||||
Assert.Equal("message-2", message.Message);
|
||||
Assert.Equal(assemblyName, message.SourceFilePath);
|
||||
Assert.Equal(2, message.StartLine);
|
||||
Assert.Equal(3, message.StartColumn);
|
||||
Assert.Equal(4, message.EndLine);
|
||||
Assert.Equal(5, message.EndColumn);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Compile_RunsCallback()
|
||||
{
|
||||
// Arrange
|
||||
var content = "public class MyTestType {}";
|
||||
RoslynCompilationContext usedCompilation = null;
|
||||
|
||||
var compilationService = new DefaultRoslynCompilationService(
|
||||
GetDependencyContext(),
|
||||
GetOptions(callback: c => usedCompilation = c),
|
||||
GetFileProviderAccessor(),
|
||||
NullLoggerFactory.Instance);
|
||||
|
||||
var relativeFileInfo = new RelativeFileInfo(
|
||||
new TestFileInfo { PhysicalPath = "SomePath" },
|
||||
"some-relative-path");
|
||||
|
||||
// Act
|
||||
var result = compilationService.Compile(relativeFileInfo, content);
|
||||
|
||||
Assert.NotNull(usedCompilation);
|
||||
Assert.Single(usedCompilation.Compilation.SyntaxTrees);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Compile_ThrowsIfDependencyContextIsNullAndTheApplicationFailsToCompileWithNoReferences()
|
||||
{
|
||||
// Arrange
|
||||
var content = "public class MyTestType {}";
|
||||
var compilationService = new DefaultRoslynCompilationService(
|
||||
dependencyContext: null,
|
||||
viewEngineOptions: GetOptions(),
|
||||
fileProviderAccessor: GetFileProviderAccessor(),
|
||||
loggerFactory: NullLoggerFactory.Instance);
|
||||
|
||||
var relativeFileInfo = new RelativeFileInfo(
|
||||
new TestFileInfo { PhysicalPath = "SomePath" },
|
||||
"some-relative-path.cshtml");
|
||||
|
||||
var expected = "The Razor page 'some-relative-path.cshtml' failed to compile. Ensure that your "
|
||||
+ "application's project.json sets the 'preserveCompilationContext' compilation property.";
|
||||
|
||||
// Act and Assert
|
||||
var ex = Assert.Throws<InvalidOperationException>(() =>
|
||||
compilationService.Compile(relativeFileInfo, content));
|
||||
Assert.Equal(expected, ex.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Compile_ThrowsIfDependencyContextReturnsNoReferencesAndTheApplicationFailsToCompile()
|
||||
{
|
||||
// Arrange
|
||||
var content = "public class MyTestType {}";
|
||||
var dependencyContext = new DependencyContext(
|
||||
target: null,
|
||||
runtime: null,
|
||||
compilationOptions: Extensions.DependencyModel.CompilationOptions.Default,
|
||||
compileLibraries: new CompilationLibrary[0],
|
||||
runtimeLibraries: new RuntimeLibrary[0]);
|
||||
var compilationService = new DefaultRoslynCompilationService(
|
||||
dependencyContext: dependencyContext,
|
||||
viewEngineOptions: GetOptions(),
|
||||
fileProviderAccessor: GetFileProviderAccessor(),
|
||||
loggerFactory: NullLoggerFactory.Instance);
|
||||
|
||||
var relativeFileInfo = new RelativeFileInfo(
|
||||
new TestFileInfo { PhysicalPath = "SomePath" },
|
||||
"some-relative-path.cshtml");
|
||||
|
||||
var expected = "The Razor page 'some-relative-path.cshtml' failed to compile. Ensure that your "
|
||||
+ "application's project.json sets the 'preserveCompilationContext' compilation property.";
|
||||
|
||||
// Act and Assert
|
||||
var ex = Assert.Throws<InvalidOperationException>(() =>
|
||||
compilationService.Compile(relativeFileInfo, content));
|
||||
Assert.Equal(expected, ex.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Compile_DoesNotThrowIfReferencesWereClearedInCallback()
|
||||
{
|
||||
// Arrange
|
||||
var options = GetOptions(context =>
|
||||
{
|
||||
context.Compilation = context.Compilation.RemoveAllReferences();
|
||||
});
|
||||
var content = "public class MyTestType {}";
|
||||
var compilationService = new DefaultRoslynCompilationService(
|
||||
dependencyContext: GetDependencyContext(),
|
||||
viewEngineOptions: options,
|
||||
fileProviderAccessor: GetFileProviderAccessor(),
|
||||
loggerFactory: NullLoggerFactory.Instance);
|
||||
|
||||
var relativeFileInfo = new RelativeFileInfo(
|
||||
new TestFileInfo { PhysicalPath = "SomePath" },
|
||||
"some-relative-path.cshtml");
|
||||
|
||||
// Act
|
||||
var result = compilationService.Compile(relativeFileInfo, content);
|
||||
|
||||
// Assert
|
||||
Assert.Single(result.CompilationFailures);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Compile_SucceedsIfReferencesAreAddedInCallback()
|
||||
{
|
||||
// Arrange
|
||||
var options = GetOptions(context =>
|
||||
{
|
||||
var assemblyLocation = typeof(object).GetTypeInfo().Assembly.Location;
|
||||
|
||||
context.Compilation = context
|
||||
.Compilation
|
||||
.AddReferences(MetadataReference.CreateFromFile(assemblyLocation));
|
||||
});
|
||||
var content = "public class MyTestType {}";
|
||||
var compilationService = new DefaultRoslynCompilationService(
|
||||
dependencyContext: null,
|
||||
viewEngineOptions: options,
|
||||
fileProviderAccessor: GetFileProviderAccessor(),
|
||||
loggerFactory: NullLoggerFactory.Instance);
|
||||
|
||||
var relativeFileInfo = new RelativeFileInfo(
|
||||
new TestFileInfo { PhysicalPath = "SomePath" },
|
||||
"some-relative-path.cshtml");
|
||||
|
||||
// Act
|
||||
var result = compilationService.Compile(relativeFileInfo, content);
|
||||
|
||||
// Assert
|
||||
Assert.Null(result.CompilationFailures);
|
||||
Assert.NotNull(result.CompiledType);
|
||||
}
|
||||
|
||||
private static DiagnosticDescriptor GetDiagnosticDescriptor(string messageFormat)
|
||||
{
|
||||
return new DiagnosticDescriptor(
|
||||
id: "someid",
|
||||
title: "sometitle",
|
||||
messageFormat: messageFormat,
|
||||
category: "some-category",
|
||||
defaultSeverity: DiagnosticSeverity.Error,
|
||||
isEnabledByDefault: true);
|
||||
}
|
||||
|
||||
private static RazorViewEngineOptions GetOptions(Action<RoslynCompilationContext> callback = null)
|
||||
{
|
||||
return new RazorViewEngineOptions
|
||||
{
|
||||
CompilationCallback = callback ?? (c => { }),
|
||||
};
|
||||
}
|
||||
|
||||
private IRazorViewEngineFileProviderAccessor GetFileProviderAccessor(IFileProvider fileProvider = null)
|
||||
{
|
||||
var options = new Mock<IRazorViewEngineFileProviderAccessor>();
|
||||
options.SetupGet(o => o.FileProvider)
|
||||
.Returns(fileProvider ?? new TestFileProvider());
|
||||
|
||||
return options.Object;
|
||||
}
|
||||
|
||||
private DependencyContext GetDependencyContext()
|
||||
{
|
||||
var assembly = typeof(DefaultRoslynCompilationServiceTest).GetTypeInfo().Assembly;
|
||||
return DependencyContext.Load(assembly);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue