提交 ffe0709d 编写于 作者: T Tomas Matousek

Use TPA to resolve Core assemblies

上级 a37aa8f0
......@@ -49,18 +49,6 @@ private static class CultureTypes
}
}
private static class _RuntimeEnvironment
{
internal static readonly Type TypeOpt = ReflectionUtilities.TryGetType("System.Runtime.InteropServices.RuntimeEnvironment, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
internal static readonly Func<string> GetRuntimeDirectoryOpt = TypeOpt?
.GetTypeInfo()
.GetDeclaredMethod("GetRuntimeDirectory", Array.Empty<Type>())?
.CreateDelegate<Func<string>>();
}
internal static string TryGetRuntimeDirectory() => _RuntimeEnvironment.GetRuntimeDirectoryOpt?.Invoke();
private static class _Assembly
{
internal static readonly Type Type = typeof(Assembly);
......
......@@ -295,7 +295,7 @@ internal static MetadataReference CreateFromAssemblyInternal(Assembly assembly)
return CreateFromAssemblyInternal(assembly, properties, documentation);
}
internal static MetadataReference CreateFromAssemblyInternal(
internal static PortableExecutableReference CreateFromAssemblyInternal(
Assembly assembly,
MetadataReferenceProperties properties,
DocumentationProvider documentation = null)
......
......@@ -2,6 +2,7 @@
using Roslyn.Utilities;
using System;
using System.Reflection;
namespace Microsoft.CodeAnalysis.Scripting
{
......@@ -15,5 +16,15 @@ internal static class AssemblyLoadContext
internal static readonly Type Type = ReflectionUtilities.TryGetType(
"System.Runtime.Loader.AssemblyLoadContext, System.Runtime.Loader, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a");
}
internal static class AppContext
{
internal static readonly Type Type = ReflectionUtilities.TryGetType(
"System.AppContext, System.AppContext, Version=4.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a");
// only available in netstandard 1.6+
internal static readonly Func<string, object> GetData =
Type.GetTypeInfo().GetDeclaredMethod("GetData")?.CreateDelegate<Func<string, object>>();
}
}
}
// Copyright (c) Microsoft. 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.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Reflection;
using Microsoft.CodeAnalysis.Scripting.Hosting;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CSharp.Scripting.Hosting
{
......@@ -17,14 +15,18 @@ internal static int Main(string[] args)
{
try
{
var responseFile = Path.Combine(AppContext.BaseDirectory, InteractiveResponseFileName);
// Note that AppContext.BaseDirectory isn't necessarily the directory containing csi.exe.
// For example, when executed via corerun it's the directory containing corerun.
string csiDirectory = Path.GetDirectoryName(typeof(Csi).GetTypeInfo().Assembly.ManifestModule.FullyQualifiedName);
var buildPaths = new BuildPaths(
clientDir: AppContext.BaseDirectory,
clientDir: csiDirectory,
workingDir: Directory.GetCurrentDirectory(),
sdkDir: CorLightup.Desktop.TryGetRuntimeDirectory(),
sdkDir: RuntimeMetadataReferenceResolver.GetDesktopFrameworkDirectory(),
tempDir: Path.GetTempPath());
var compiler = new CSharpInteractiveCompiler(
responseFile: responseFile,
responseFile: Path.Combine(csiDirectory, InteractiveResponseFileName),
buildPaths: buildPaths,
args: args,
analyzerLoader: new NotImplementedAnalyzerLoader());
......
# references
/r:System.Collections.dll
/r:System.Console.dll
/r:System.Diagnostics.Process.dll
/r:System.Dynamic.Runtime.dll
/r:System.Globalization.dll
/r:System.IO.dll
/r:System.IO.FileSystem.dll
/r:System.IO.FileSystem.Primitives.dll
/r:System.Linq.dll
/r:System.Linq.Expressions.dll
/r:System.Reflection.dll
/r:System.Reflection.Primitives.dll
/r:System.Runtime.dll
/r:System.Runtime.Numerics.dll
/r:System.Runtime.Serialization.Json.dll
/r:System.Runtime.Serialization.Primitives.dll
/r:System.Text.Encoding.CodePages.dll
/r:System.Text.Encoding.dll
/r:System.Text.Encoding.Extensions.dll
/r:System.Text.RegularExpressions.dll
/r:System.Threading.dll
/r:System.Threading.Tasks.dll
/r:System.Threading.Tasks.Parallel.dll
/r:System.Threading.Thread.dll
# basic references
/r:System.Collections
/r:System.Collections.Concurrent
/r:System.Console
/r:System.Diagnostics.Debug
/r:System.Diagnostics.Process
/r:System.Diagnostics.StackTrace
/r:System.Globalization
/r:System.IO
/r:System.IO.FileSystem
/r:System.IO.FileSystem.Primitives
/r:System.Reflection
/r:System.Reflection.Primitives
/r:System.Runtime
/r:System.Runtime.InteropServices
/r:System.Text.Encoding
/r:System.Text.Encoding.CodePages
/r:System.Text.Encoding.Extensions
/r:System.Text.RegularExpressions
/r:System.Threading
/r:System.Threading.Tasks
/r:System.Threading.Tasks.Parallel
/r:System.Threading.Thread
# extra references
/r:System.Linq
/r:System.Linq.Expressions
/r:System.Runtime.Numerics
/r:System.Dynamic.Runtime
/r:System.ValueTuple.dll
/r:Microsoft.CSharp
# imports
/u:System
/u:System.IO
......
......@@ -262,11 +262,13 @@ private void ProcessStarting(bool initialize)
private static MetadataReferenceResolver CreateMetadataReferenceResolver(IMetadataService metadataService, ImmutableArray<string> searchPaths, string baseDirectory)
{
// TODO: We need to do reference resolution in the remote process (InteractiveHost.exe), in order to support other platforms than Desktop FX
return new RuntimeMetadataReferenceResolver(
new RelativePathResolver(searchPaths, baseDirectory),
null,
GacFileResolver.IsAvailable ? new GacFileResolver(preferredCulture: CultureInfo.CurrentCulture) : null,
(path, properties) => metadataService.GetReference(path, properties));
packageResolver: null,
gacFileResolver: GacFileResolver.IsAvailable ? new GacFileResolver(preferredCulture: CultureInfo.CurrentCulture) : null,
useCoreResolver: false,
fileReferenceProvider: (path, properties) => metadataService.GetReference(path, properties));
}
private static SourceReferenceResolver CreateSourceReferenceResolver(ImmutableArray<string> searchPaths, string baseDirectory)
......
......@@ -172,9 +172,10 @@ private MetadataReferenceResolver CreateMetadataReferenceResolver(ImmutableArray
{
return new RuntimeMetadataReferenceResolver(
new RelativePathResolver(searchPaths, baseDirectory),
null,
GacFileResolver.IsAvailable ? new GacFileResolver(preferredCulture: CultureInfo.CurrentCulture) : null,
(path, properties) => new ShadowCopyReference(_metadataFileProvider, path, properties));
packageResolver: null,
gacFileResolver: GacFileResolver.IsAvailable ? new GacFileResolver(preferredCulture: CultureInfo.CurrentCulture) : null,
useCoreResolver: !GacFileResolver.IsAvailable,
fileReferenceProvider: (path, properties) => new ShadowCopyReference(_metadataFileProvider, path, properties));
}
private SourceReferenceResolver CreateSourceReferenceResolver(ImmutableArray<string> searchPaths, string baseDirectory)
......
' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
Imports System.IO
Imports System.Reflection
Imports Microsoft.CodeAnalysis.Scripting.Hosting
Imports Roslyn.Utilities
Namespace Microsoft.CodeAnalysis.VisualBasic.Scripting.Hosting
......@@ -11,18 +11,21 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Scripting.Hosting
Public Shared Function Main(args As String()) As Integer
Try
Dim responseFile = Path.Combine(AppContext.BaseDirectory, InteractiveResponseFileName)
' Note that AppContext.BaseDirectory isn't necessarily the directory containing vbi.exe.
' For example, when executed via corerun it's the directory containing corerun.
Dim vbiDirectory = Path.GetDirectoryName(GetType(Vbi).GetTypeInfo().Assembly.ManifestModule.FullyQualifiedName)
Dim buildPaths = New BuildPaths(
clientDir:=AppContext.BaseDirectory,
workingDir:=CorLightup.Desktop.TryGetRuntimeDirectory(),
sdkDir:=AppContext.BaseDirectory,
clientDir:=vbiDirectory,
workingDir:=Directory.GetCurrentDirectory(),
sdkDir:=RuntimeMetadataReferenceResolver.GetDesktopFrameworkDirectory(),
tempDir:=Path.GetTempPath())
Dim compiler = New VisualBasicInteractiveCompiler(
responseFile,
buildPaths,
args,
New NotImplementedAnalyzerLoader())
responseFile:=Path.Combine(vbiDirectory, InteractiveResponseFileName),
buildPaths:=buildPaths,
args:=args,
analyzerLoader:=New NotImplementedAnalyzerLoader())
Dim runner = New CommandLineRunner(
ConsoleIO.Default,
......
// Copyright (c) Microsoft. 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.IO;
using System.Linq;
using System.Reflection;
......@@ -11,8 +12,8 @@
using Microsoft.CodeAnalysis.Scripting.Test;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
using Xunit;
using Roslyn.Utilities;
using Xunit;
namespace Microsoft.CodeAnalysis.CSharp.Scripting.UnitTests
{
......@@ -26,10 +27,55 @@ public class CommandLineRunnerTests : TestBase
// default csi.rsp
private static readonly string[] s_defaultArgs = new[]
{
"/r:System;System.Core;Microsoft.CSharp;System.ValueTuple.dll",
"/r:" + string.Join(";", GetReferences()),
"/u:System;System.IO;System.Collections.Generic;System.Diagnostics;System.Dynamic;System.Linq;System.Linq.Expressions;System.Text;System.Threading.Tasks",
};
private static IEnumerable<string> GetReferences()
{
if (GacFileResolver.IsAvailable)
{
// keep in sync with list in csi.rsp
yield return "System";
yield return "System.Core";
yield return "Microsoft.CSharp";
yield return "System.ValueTuple.dll";
}
else
{
// keep in sync with list in core csi.rsp
yield return "System.Collections";
yield return "System.Collections.Concurrent";
yield return "System.Console";
yield return "System.Diagnostics.Debug";
yield return "System.Diagnostics.Process";
yield return "System.Diagnostics.StackTrace";
yield return "System.Globalization";
yield return "System.IO";
yield return "System.IO.FileSystem";
yield return "System.IO.FileSystem.Primitives";
yield return "System.Reflection";
yield return "System.Reflection.Extensions";
yield return "System.Reflection.Primitives";
yield return "System.Runtime";
yield return "System.Runtime.InteropServices";
yield return "System.Text.Encoding";
yield return "System.Text.Encoding.CodePages";
yield return "System.Text.Encoding.Extensions";
yield return "System.Text.RegularExpressions";
yield return "System.Threading";
yield return "System.Threading.Tasks";
yield return "System.Threading.Tasks.Parallel";
yield return "System.Threading.Thread";
yield return "System.Linq";
yield return "System.Linq.Expressions";
yield return "System.Runtime.Numerics";
yield return "System.Dynamic.Runtime";
yield return "System.ValueTuple";
yield return "Microsoft.CSharp";
}
}
private static CommandLineRunner CreateRunner(
string[] args = null,
string input = "",
......@@ -46,7 +92,7 @@ public class CommandLineRunnerTests : TestBase
var compiler = new CSharpInteractiveCompiler(
responseFile,
buildPaths,
args ?? s_defaultArgs,
args?.Where(a => a != null).ToArray() ?? s_defaultArgs,
new NotImplementedAnalyzerLoader());
return new CommandLineRunner(io, compiler, CSharpScriptCompiler.Instance, CSharpObjectFormatter.Instance);
......@@ -94,10 +140,10 @@ public void Await()
public void TestDisplayResultsWithCurrentUICulture()
{
var runner = CreateRunner(input:
@"using static System.Globalization.CultureInfo;
DefaultThreadCurrentUICulture = GetCultureInfo(""en-GB"")
@"using System.Globalization;
CultureInfo.DefaultThreadCurrentUICulture = new CultureInfo(""en-GB"")
Math.PI
DefaultThreadCurrentUICulture = GetCultureInfo(""de-DE"")
CultureInfo.DefaultThreadCurrentUICulture = new CultureInfo(""de-DE"")
Math.PI
");
runner.RunInteractive();
......@@ -107,12 +153,12 @@ public void TestDisplayResultsWithCurrentUICulture()
Copyright (C) Microsoft Corporation. All rights reserved.
Type ""#help"" for more information.
> using static System.Globalization.CultureInfo;
> DefaultThreadCurrentUICulture = GetCultureInfo(""en-GB"")
> using System.Globalization;
> CultureInfo.DefaultThreadCurrentUICulture = new CultureInfo(""en-GB"")
[en-GB]
> Math.PI
3.1415926535897931
> DefaultThreadCurrentUICulture = GetCultureInfo(""de-DE"")
> CultureInfo.DefaultThreadCurrentUICulture = new CultureInfo(""de-DE"")
[de-DE]
> Math.PI
3,1415926535897931
......@@ -120,11 +166,11 @@ > Math.PI
// Tests that DefaultThreadCurrentUICulture is respected and not DefaultThreadCurrentCulture.
runner = CreateRunner(input:
@"using static System.Globalization.CultureInfo;
DefaultThreadCurrentUICulture = GetCultureInfo(""en-GB"")
DefaultThreadCurrentCulture = GetCultureInfo(""en-GB"")
@"using System.Globalization;
CultureInfo.DefaultThreadCurrentUICulture = new CultureInfo(""en-GB"")
CultureInfo.DefaultThreadCurrentCulture = new CultureInfo(""en-GB"")
Math.PI
DefaultThreadCurrentCulture = GetCultureInfo(""de-DE"")
CultureInfo.DefaultThreadCurrentCulture = new CultureInfo(""de-DE"")
Math.PI
");
runner.RunInteractive();
......@@ -134,14 +180,14 @@ > Math.PI
Copyright (C) Microsoft Corporation. All rights reserved.
Type ""#help"" for more information.
> using static System.Globalization.CultureInfo;
> DefaultThreadCurrentUICulture = GetCultureInfo(""en-GB"")
> using System.Globalization;
> CultureInfo.DefaultThreadCurrentUICulture = new CultureInfo(""en-GB"")
[en-GB]
> DefaultThreadCurrentCulture = GetCultureInfo(""en-GB"")
> CultureInfo.DefaultThreadCurrentCulture = new CultureInfo(""en-GB"")
[en-GB]
> Math.PI
3.1415926535897931
> DefaultThreadCurrentCulture = GetCultureInfo(""de-DE"")
> CultureInfo.DefaultThreadCurrentCulture = new CultureInfo(""de-DE"")
[de-DE]
> Math.PI
3.1415926535897931
......@@ -482,11 +528,16 @@ public void Script_BadUsings()
{
var script = Temp.CreateFile(extension: ".csx").WriteAllText("WriteLine(42);");
var runner = CreateRunner(new[] { "/u:System.Console;Foo.Bar", script.Path });
var runner = CreateRunner(new[]
{
GacFileResolver.IsAvailable ? null : "/r:System.Console",
"/u:System.Console;Alpha.Beta",
script.Path
});
Assert.Equal(1, runner.RunInteractive());
const string error = @"error CS0246: The type or namespace name 'Foo' could not be found (are you missing a using directive or an assembly reference?)";
const string error = @"error CS0246: The type or namespace name 'Alpha' could not be found (are you missing a using directive or an assembly reference?)";
AssertEx.AssertEqualToleratingWhitespaceDifferences(error, runner.Console.Out.ToString());
AssertEx.AssertEqualToleratingWhitespaceDifferences(error, runner.Console.Error.ToString());
}
......
......@@ -418,7 +418,16 @@ public void DebuggerProxy_FrameworkTypes_IEnumerable()
obj = Enumerable.Range(0, 10);
str = s_formatter.FormatObject(obj, SingleLineOptions);
Assert.Equal("RangeIterator { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }", str);
// the implementation differs between .NET Core and .NET FX
if (str.StartsWith("Enumerable"))
{
Assert.Equal("Enumerable.RangeIterator { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }", str);
}
else
{
Assert.Equal("RangeIterator { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }", str);
}
}
[Fact]
......
......@@ -155,10 +155,11 @@ private static ScriptOptions GetScriptOptions(CommandLineArguments arguments, st
internal static MetadataReferenceResolver GetMetadataReferenceResolver(CommandLineArguments arguments, TouchedFileLogger loggerOpt)
{
return new RuntimeMetadataReferenceResolver(
new RelativePathResolver(arguments.ReferencePaths, arguments.BaseDirectory),
null,
GacFileResolver.IsAvailable ? new GacFileResolver(preferredCulture: CultureInfo.CurrentCulture) : null,
(path, properties) =>
pathResolver: new RelativePathResolver(arguments.ReferencePaths, arguments.BaseDirectory),
packageResolver: null,
gacFileResolver: GacFileResolver.IsAvailable ? new GacFileResolver(preferredCulture: CultureInfo.CurrentCulture) : null,
useCoreResolver: !GacFileResolver.IsAvailable,
fileReferenceProvider: (path, properties) =>
{
loggerOpt?.AddRead(path);
return MetadataReference.CreateFromFile(path, properties);
......
......@@ -3,9 +3,13 @@
#pragma warning disable 436 // The type 'RelativePathResolver' conflicts with imported type
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Loader;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.Scripting.Hosting
......@@ -19,23 +23,34 @@ namespace Microsoft.CodeAnalysis.Scripting.Hosting
internal sealed class RuntimeMetadataReferenceResolver : MetadataReferenceResolver, IEquatable<RuntimeMetadataReferenceResolver>
{
// Ideally we'd use properties with no aliases, but currently that's not possible since empty aliases mean {global}.
private static readonly MetadataReferenceProperties s_resolvedMissingAssemblyReferenceProperties = MetadataReferenceProperties.Assembly.WithAliases(ImmutableArray.Create("<implicit>"));
private static readonly MetadataReferenceProperties s_resolvedMissingAssemblyReferenceProperties =
MetadataReferenceProperties.Assembly.WithAliases(ImmutableArray.Create("<implicit>"));
public static readonly RuntimeMetadataReferenceResolver Default = new RuntimeMetadataReferenceResolver(ImmutableArray<string>.Empty, baseDirectory: null);
internal static string GetDesktopFrameworkDirectory() => GacFileResolver.IsAvailable ?
PathUtilities.GetDirectoryName(typeof(object).GetTypeInfo().Assembly.ManifestModule.FullyQualifiedName) : null;
// file name to path:
private static ImmutableDictionary<string, string> _lazyTrustedPlatformAssemblies;
public static readonly RuntimeMetadataReferenceResolver Default =
new RuntimeMetadataReferenceResolver(ImmutableArray<string>.Empty, baseDirectory: null);
internal readonly RelativePathResolver PathResolver;
internal readonly NuGetPackageResolver PackageResolver;
internal readonly GacFileResolver GacFileResolver;
private readonly Func<string, MetadataReferenceProperties, PortableExecutableReference> _fileReferenceProvider;
private readonly bool _useCoreResolver;
// TODO: Look for .winmd, but only if the identity has content WindowsRuntime (https://github.com/dotnet/roslyn/issues/6483)
// The extensions are in order in which the CLR loader looks for assembly files.
internal static ImmutableArray<string> AssemblyExtensions = ImmutableArray.Create(".dll", ".exe");
internal RuntimeMetadataReferenceResolver(
ImmutableArray<string> searchPaths,
string baseDirectory)
: this(new RelativePathResolver(searchPaths, baseDirectory), null, GacFileResolver.IsAvailable ? new GacFileResolver() : null)
internal RuntimeMetadataReferenceResolver(ImmutableArray<string> searchPaths, string baseDirectory)
: this(pathResolver: new RelativePathResolver(searchPaths, baseDirectory),
packageResolver: null,
gacFileResolver: GacFileResolver.IsAvailable ? new GacFileResolver() : null,
useCoreResolver: !GacFileResolver.IsAvailable,
fileReferenceProvider: null)
{
}
......@@ -43,11 +58,13 @@ internal sealed class RuntimeMetadataReferenceResolver : MetadataReferenceResolv
RelativePathResolver pathResolver,
NuGetPackageResolver packageResolver,
GacFileResolver gacFileResolver,
bool useCoreResolver,
Func<string, MetadataReferenceProperties, PortableExecutableReference> fileReferenceProvider = null)
{
PathResolver = pathResolver;
PackageResolver = packageResolver;
GacFileResolver = gacFileResolver;
_useCoreResolver = useCoreResolver;
_fileReferenceProvider = fileReferenceProvider ??
new Func<string, MetadataReferenceProperties, PortableExecutableReference>((path, properties) => MetadataReference.CreateFromFile(path, properties));
}
......@@ -66,14 +83,24 @@ public override PortableExecutableReference ResolveMissingAssembly(MetadataRefer
}
}
// look into a directory containing CorLib:
if (_useCoreResolver)
{
var result = ResolveTrustedPlatformAssemblyCore(referenceIdentity.Name, s_resolvedMissingAssemblyReferenceProperties);
if (result != null)
{
return result;
}
}
// look in the directory of the requesting definition:
var definitionPath = (definition as PortableExecutableReference)?.FilePath;
string definitionPath = (definition as PortableExecutableReference)?.FilePath;
if (definitionPath != null)
{
var pathWithoutExtension = PathUtilities.CombinePathsUnchecked(PathUtilities.GetDirectoryName(definitionPath), referenceIdentity.Name);
foreach (var extension in AssemblyExtensions)
string pathWithoutExtension = PathUtilities.CombinePathsUnchecked(PathUtilities.GetDirectoryName(definitionPath), referenceIdentity.Name);
foreach (string extension in AssemblyExtensions)
{
var fullPath = pathWithoutExtension + extension;
string fullPath = pathWithoutExtension + extension;
if (File.Exists(fullPath))
{
return CreateResolvedMissingReference(fullPath);
......@@ -91,9 +118,7 @@ private PortableExecutableReference CreateResolvedMissingReference(string fullPa
public override ImmutableArray<PortableExecutableReference> ResolveReference(string reference, string baseFilePath, MetadataReferenceProperties properties)
{
string packageName;
string packageVersion;
if (NuGetPackageResolver.TryParsePackageReference(reference, out packageName, out packageVersion))
if (NuGetPackageResolver.TryParsePackageReference(reference, out string packageName, out string packageVersion))
{
if (PackageResolver != null)
{
......@@ -106,28 +131,90 @@ public override ImmutableArray<PortableExecutableReference> ResolveReference(str
{
if (PathResolver != null)
{
var resolvedPath = PathResolver.ResolvePath(reference, baseFilePath);
string resolvedPath = PathResolver.ResolvePath(reference, baseFilePath);
if (resolvedPath != null)
{
return ImmutableArray.Create(_fileReferenceProvider(resolvedPath, properties));
}
}
}
else if (GacFileResolver != null)
else
{
var path = GacFileResolver.Resolve(reference);
if (path != null)
if (GacFileResolver != null)
{
string path = GacFileResolver.Resolve(reference);
if (path != null)
{
return ImmutableArray.Create(_fileReferenceProvider(path, properties));
}
}
if (_useCoreResolver && AssemblyIdentity.TryParseDisplayName(reference, out var identity, out var identityParts))
{
return ImmutableArray.Create(_fileReferenceProvider(path, properties));
var result = ResolveTrustedPlatformAssemblyCore(identity.Name, properties);
if (result != null)
{
return ImmutableArray.Create(result);
}
}
}
return ImmutableArray<PortableExecutableReference>.Empty;
}
private PortableExecutableReference ResolveTrustedPlatformAssemblyCore(string name, MetadataReferenceProperties properties)
{
if (_lazyTrustedPlatformAssemblies == null)
{
_lazyTrustedPlatformAssemblies = GetTrustedPlatformAssemblyMap();
}
if (_lazyTrustedPlatformAssemblies.TryGetValue(name, out string path) && File.Exists(path))
{
return MetadataReference.CreateFromFile(path, properties);
}
return null;
}
private static ImmutableDictionary<string, string> GetTrustedPlatformAssemblyMap()
{
var set = ImmutableDictionary.CreateBuilder<string, string>(StringComparer.OrdinalIgnoreCase);
if (CoreClrShim.AppContext.GetData("TRUSTED_PLATFORM_ASSEMBLIES") is string paths)
{
foreach (var path in paths.Split(Path.PathSeparator))
{
try
{
if (Path.GetExtension(path) == ".dll")
{
string fileName = Path.GetFileNameWithoutExtension(path);
if (fileName.EndsWith(".ni", StringComparison.OrdinalIgnoreCase))
{
fileName = fileName.Substring(0, fileName.Length - ".ni".Length);
}
// last one wins:
set[fileName] = path;
}
}
catch (Exception)
{
// skip invalid paths
}
}
}
return set.ToImmutable();
}
public override int GetHashCode()
{
return Hash.Combine(PathResolver, Hash.Combine(PackageResolver, Hash.Combine(GacFileResolver, 0)));
return Hash.Combine(PathResolver,
Hash.Combine(PackageResolver,
Hash.Combine(GacFileResolver,
Hash.Combine(_useCoreResolver, 0))));
}
public bool Equals(RuntimeMetadataReferenceResolver other)
......@@ -136,7 +223,8 @@ public bool Equals(RuntimeMetadataReferenceResolver other)
other != null &&
Equals(PathResolver, other.PathResolver) &&
Equals(PackageResolver, other.PackageResolver) &&
Equals(GacFileResolver, other.GacFileResolver);
Equals(GacFileResolver, other.GacFileResolver) &&
_useCoreResolver == other._useCoreResolver;
}
public override bool Equals(object other) => Equals(other as RuntimeMetadataReferenceResolver);
......@@ -144,7 +232,7 @@ public bool Equals(RuntimeMetadataReferenceResolver other)
internal RuntimeMetadataReferenceResolver WithRelativePathResolver(RelativePathResolver resolver)
{
return Equals(resolver, PathResolver) ? this :
new RuntimeMetadataReferenceResolver(resolver, PackageResolver, GacFileResolver, _fileReferenceProvider);
new RuntimeMetadataReferenceResolver(resolver, PackageResolver, GacFileResolver, _useCoreResolver, _fileReferenceProvider);
}
}
}
......@@ -4,9 +4,11 @@
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Threading;
using Microsoft.CodeAnalysis.Scripting.Hosting;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.Scripting
{
......@@ -19,11 +21,50 @@ public sealed class ScriptOptions
{
public static ScriptOptions Default { get; } = new ScriptOptions(
filePath: "",
references: ImmutableArray<MetadataReference>.Empty,
references: GetDefaultMetadataReferences(),
namespaces: ImmutableArray<string>.Empty,
metadataResolver: RuntimeMetadataReferenceResolver.Default,
sourceResolver: SourceFileResolver.Default);
private static ImmutableArray<MetadataReference> GetDefaultMetadataReferences()
{
if (GacFileResolver.IsAvailable)
{
return ImmutableArray<MetadataReference>.Empty;
}
// Provide similar surface to mscorlib (netstandard 2.0).
// These references are resolved lazily. Keep in sync with list in core csi.rsp.
var files = new[]
{
"System.Collections",
"System.Collections.Concurrent",
"System.Console",
"System.Diagnostics.Debug",
"System.Diagnostics.Process",
"System.Diagnostics.StackTrace",
"System.Globalization",
"System.IO",
"System.IO.FileSystem",
"System.IO.FileSystem.Primitives",
"System.Reflection",
"System.Reflection.Extensions",
"System.Reflection.Primitives",
"System.Runtime",
"System.Runtime.InteropServices",
"System.Text.Encoding",
"System.Text.Encoding.CodePages",
"System.Text.Encoding.Extensions",
"System.Text.RegularExpressions",
"System.Threading",
"System.Threading.Tasks",
"System.Threading.Tasks.Parallel",
"System.Threading.Thread",
};
return ImmutableArray.CreateRange(files.Select(CreateUnresolvedReference));
}
/// <summary>
/// An array of <see cref="MetadataReference"/>s to be added to the script.
/// </summary>
......
......@@ -18,8 +18,10 @@
<Name>CodeAnalysis</Name>
</ProjectReference>
</ItemGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|Any CPU' "></PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|Any CPU' "></PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|Any CPU' ">
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|Any CPU' ">
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|ARM' ">
<PlatformTarget>ARM</PlatformTarget>
</PropertyGroup>
......@@ -40,28 +42,28 @@
</ItemGroup>
<ItemGroup>
<Compile Include="..\..\Compilers\Core\Portable\FileSystem\RelativePathResolver.cs">
<Link>Resolvers\RelativePathResolver.cs</Link>
<Link>Hosting\Resolvers\RelativePathResolver.cs</Link>
</Compile>
<Compile Include="..\..\Compilers\Shared\CoreClrShim.cs">
<Link>CoreClrShim.cs</Link>
</Compile>
<Compile Include="..\..\Compilers\Shared\GlobalAssemblyCacheHelpers\ClrGlobalAssemblyCache.cs">
<Link>Resolvers\ClrGlobalAssemblyCache.cs</Link>
<Link>Hosting\Resolvers\ClrGlobalAssemblyCache.cs</Link>
</Compile>
<Compile Include="..\..\Compilers\Shared\GlobalAssemblyCacheHelpers\FusionAssemblyIdentity.cs">
<Link>Resolvers\FusionAssemblyIdentity.cs</Link>
<Link>Hosting\Resolvers\FusionAssemblyIdentity.cs</Link>
</Compile>
<Compile Include="..\..\Compilers\Shared\GlobalAssemblyCacheHelpers\GacFileResolver.cs">
<Link>Resolvers\GacFileResolver.cs</Link>
<Link>Hosting\Resolvers\GacFileResolver.cs</Link>
</Compile>
<Compile Include="..\..\Compilers\Shared\GlobalAssemblyCacheHelpers\GlobalAssemblyCache.cs">
<Link>Resolvers\GlobalAssemblyCache.cs</Link>
<Link>Hosting\Resolvers\GlobalAssemblyCache.cs</Link>
</Compile>
<Compile Include="..\..\Compilers\Shared\GlobalAssemblyCacheHelpers\GlobalAssemblyCacheLocation.cs">
<Link>Resolvers\GlobalAssemblyCache.Location.cs</Link>
<Link>Hosting\Resolvers\GlobalAssemblyCacheLocation.cs</Link>
</Compile>
<Compile Include="..\..\Compilers\Shared\GlobalAssemblyCacheHelpers\MonoGlobalAssemblyCache.cs">
<Link>Resolvers\MonoGlobalAssemblyCache.cs</Link>
<Link>Hosting\Resolvers\MonoGlobalAssemblyCache.cs</Link>
</Compile>
<Compile Include="Hosting\AssemblyLoader\AssemblyAndLocation.cs" />
<Compile Include="Hosting\AssemblyLoader\AssemblyLoadResult.cs" />
......@@ -157,4 +159,4 @@
<PublicAPI Include="PublicAPI.Unshipped.txt" />
</ItemGroup>
<Import Project="..\..\..\build\Targets\Imports.targets" />
</Project>
</Project>
\ No newline at end of file
......@@ -26,7 +26,9 @@ public void Resolve()
var resolver = new RuntimeMetadataReferenceResolver(
new RelativePathResolver(ImmutableArray.Create(directory.Path), baseDirectory: directory.Path),
new PackageResolver(ImmutableDictionary<string, ImmutableArray<string>>.Empty.Add("nuget:N/1.0", ImmutableArray.Create(assembly1.Path, assembly2.Path))),
gacFileResolver: null);
gacFileResolver: null,
useCoreResolver: false);
// Recognized NuGet reference.
var actualReferences = resolver.ResolveReference("nuget:N/1.0", baseFilePath: null, properties: MetadataReferenceProperties.Assembly);
AssertEx.SetEqual(actualReferences.SelectAsArray(r => r.FilePath), assembly1.Path, assembly2.Path);
......@@ -44,7 +46,9 @@ public void Resolve()
resolver = new RuntimeMetadataReferenceResolver(
new RelativePathResolver(ImmutableArray.Create(directory.Path), baseDirectory: directory.Path),
packageResolver: null,
gacFileResolver: null);
gacFileResolver: null,
useCoreResolver: false);
// Unrecognized NuGet reference.
actualReferences = resolver.ResolveReference("nuget:N/1.0", baseFilePath: null, properties: MetadataReferenceProperties.Assembly);
Assert.True(actualReferences.IsEmpty);
......
......@@ -3,9 +3,8 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.IO;
using System.Linq;
using System.Reflection;
using Microsoft.CodeAnalysis.Scripting.Hosting;
using Roslyn.Test.Utilities;
using Xunit;
......@@ -23,7 +22,7 @@ public void AddReferences()
AddReferences("System.Linq").
AddReferences("System.Linq");
Assert.Equal(5, options.MetadataReferences.Length);
Assert.Equal(GacFileResolver.IsAvailable ? 5 : 28, options.MetadataReferences.Length);
}
[Fact]
......@@ -31,7 +30,7 @@ public void AddReferences_Errors()
{
var moduleRef = ModuleMetadata.CreateFromImage(TestResources.MetadataTests.NetModule01.ModuleCS00).GetReference();
var options = ScriptOptions.Default;
var options = ScriptOptions.Default.WithReferences(ImmutableArray<MetadataReference>.Empty);
Assert.Throws<ArgumentNullException>("references", () => options.AddReferences((MetadataReference[])null));
Assert.Throws<ArgumentNullException>("references[0]", () => options.AddReferences(new MetadataReference[] { null }));
......@@ -54,15 +53,17 @@ public void AddReferences_Errors()
[Fact]
public void WithReferences()
{
var options = ScriptOptions.Default.WithReferences("System.Linq", "system.linq");
var empty = ScriptOptions.Default.WithReferences(ImmutableArray<MetadataReference>.Empty);
var options = empty.WithReferences("System.Linq", "system.linq");
Assert.Equal(2, options.MetadataReferences.Length);
options = ScriptOptions.Default.WithReferences(typeof(int).GetTypeInfo().Assembly, typeof(int).GetTypeInfo().Assembly);
options = empty.WithReferences(typeof(int).GetTypeInfo().Assembly, typeof(int).GetTypeInfo().Assembly);
Assert.Equal(2, options.MetadataReferences.Length);
var assemblyRef = ModuleMetadata.CreateFromImage(TestResources.SymbolsTests.Methods.CSMethods).GetReference();
options = ScriptOptions.Default.WithReferences(assemblyRef, assemblyRef);
options = empty.WithReferences(assemblyRef, assemblyRef);
Assert.Equal(2, options.MetadataReferences.Length);
}
......@@ -71,7 +72,7 @@ public void WithReferences_Errors()
{
var moduleRef = ModuleMetadata.CreateFromImage(TestResources.MetadataTests.NetModule01.ModuleCS00).GetReference();
var options = ScriptOptions.Default;
var options = ScriptOptions.Default.WithReferences(ImmutableArray<MetadataReference>.Empty);
Assert.Throws<ArgumentNullException>("references", () => options.WithReferences((MetadataReference[])null));
Assert.Throws<ArgumentNullException>("references", () => options.WithReferences((IEnumerable<MetadataReference>)null));
Assert.Throws<ArgumentNullException>("references", () => options.WithReferences(default(ImmutableArray<MetadataReference>)));
......
......@@ -2,16 +2,21 @@
using System;
using System.IO;
using System.Threading;
namespace Microsoft.CodeAnalysis.Scripting
{
public sealed class OutputRedirect : IDisposable
{
private static readonly object s_guard = new object();
private readonly TextWriter _oldOut;
private readonly StringWriter _newOut;
public OutputRedirect(IFormatProvider formatProvider)
{
Monitor.Enter(s_guard);
_oldOut = Console.Out;
_newOut = new StringWriter(formatProvider);
Console.SetOut(_newOut);
......@@ -23,6 +28,8 @@ void IDisposable.Dispose()
{
Console.SetOut(_oldOut);
_newOut.Dispose();
Monitor.Exit(s_guard);
}
}
}
......@@ -32,7 +32,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Scripting.UnitTests
Dim buildPaths = New BuildPaths(
clientDir:=AppContext.BaseDirectory,
workingDir:=If(workingDirectory, AppContext.BaseDirectory),
sdkDir:=CorLightup.Desktop.TryGetRuntimeDirectory(),
sdkDir:=RuntimeMetadataReferenceResolver.GetDesktopFrameworkDirectory(),
tempDir:=Path.GetTempPath())
Dim compiler = New VisualBasicInteractiveCompiler(
......
......@@ -65,6 +65,10 @@
<Project>{12a68549-4e8c-42d6-8703-a09335f97997}</Project>
<Name>Scripting</Name>
</ProjectReference>
<ProjectReference Include="..\..\Scripting\CSharpTest\CSharpScriptingTest.csproj">
<Project>{2dae4406-7a89-4b5f-95c3-bc5422ce47ce}</Project>
<Name>CSharpScriptingTest</Name>
</ProjectReference>
<ProjectReference Include="..\..\Scripting\CSharp\CSharpScripting.csproj">
<Project>{066f0dbd-c46c-4c20-afec-99829a172625}</Project>
<Name>CSharpScripting</Name>
......@@ -87,4 +91,4 @@
</ProjectReference>
</ItemGroup>
<Import Project="..\..\..\build\Targets\Imports.targets" />
</Project>
</Project>
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册