Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improved the logic of adding default assembly references for Desktop CLR CSX scripts #898

Merged
merged 5 commits into from
Jul 7, 2017
Merged
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 43 additions & 25 deletions src/OmniSharp.Script/ScriptProjectSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,19 @@ public class ScriptProjectSystem : IProjectSystem
private readonly OmniSharpWorkspace _workspace;
private readonly IOmniSharpEnvironment _env;
private readonly ILogger _logger;
private readonly IAssemblyLoader _assemblyLoader;

private readonly IScriptProjectProvider _scriptProjectProvider;
private static readonly Lazy<string> _targetFrameWork = new Lazy<string>(ResolveTargetFramework);

[ImportingConstructor]
public ScriptProjectSystem(OmniSharpWorkspace workspace, IOmniSharpEnvironment env, ILoggerFactory loggerFactory, MetadataFileReferenceCache metadataFileReferenceCache)
public ScriptProjectSystem(OmniSharpWorkspace workspace, IOmniSharpEnvironment env, ILoggerFactory loggerFactory,
MetadataFileReferenceCache metadataFileReferenceCache, IAssemblyLoader assemblyLoader)
{
_metadataFileReferenceCache = metadataFileReferenceCache;
_workspace = workspace;
_env = env;
_assemblyLoader = assemblyLoader;
_logger = loggerFactory.CreateLogger<ScriptProjectSystem>();
_projects = new Dictionary<string, ProjectInfo>();
_scriptProjectProvider = ScriptProjectProvider.Create(loggerFactory);
Expand All @@ -64,7 +68,7 @@ public void Initalize(IConfiguration configuration)

_logger.LogInformation($"Found {allCsxFiles.Length} CSX files.");

// explicitly inherit scripting library references to all global script object (InteractiveScriptGlobals) to be recognized
// explicitly inherit scripting library references to all global script object (CommandLineScriptGlobals) to be recognized
var inheritedCompileLibraries = DependencyContext.Default.CompileLibraries.Where(x =>
x.Name.ToLowerInvariant().StartsWith("microsoft.codeanalysis")).ToList();

Expand All @@ -73,9 +77,6 @@ public void Initalize(IConfiguration configuration)
x.Name.ToLowerInvariant().StartsWith("system.valuetuple")));

var runtimeContexts = File.Exists(Path.Combine(_env.TargetDirectory, "project.json")) ? ProjectContext.CreateContextForEachTarget(_env.TargetDirectory) : null;

var commonReferences = new HashSet<MetadataReference>();

if (!bool.TryParse(configuration["enableScriptNuGetReferences"], out var enableScriptNuGetReferences))
{
enableScriptNuGetReferences = false;
Expand All @@ -86,25 +87,23 @@ public void Initalize(IConfiguration configuration)
runtimeContexts = TryCreateRuntimeContextsFromScriptFiles();
}

var runtimeContext = runtimeContexts?.FirstOrDefault();
var commonReferences = new HashSet<MetadataReference>();

// if we have no context, then we also have no dependencies
// we can assume desktop framework
// and add mscorlib
if (runtimeContexts == null || runtimeContexts.Any() == false)
// we will assume desktop framework
// and add default CLR references
// same applies for having a context that is not a .NET Core app
AddDefaultClrMetadataReferences(runtimeContext, commonReferences);
if (runtimeContext == null)
{
_logger.LogInformation("Unable to find project context for CSX files. Will default to non-context usage.");

AddMetadataReference(commonReferences, typeof(object).GetTypeInfo().Assembly.Location);
AddMetadataReference(commonReferences, typeof(Enumerable).GetTypeInfo().Assembly.Location);

inheritedCompileLibraries.AddRange(DependencyContext.Default.CompileLibraries.Where(x =>
x.Name.ToLowerInvariant().StartsWith("system.runtime")));
_logger.LogInformation("Unable to find project context for CSX files. Will default to non-context usage (Destkop CLR scripts).");
}
// otherwise we will grab dependencies for the script from the runtime context
else
{
// assume the first one
var runtimeContext = runtimeContexts.First();
_logger.LogInformation($"Found script runtime context '{runtimeContext?.TargetFramework.Framework}' for '{runtimeContext.ProjectFile.ProjectFilePath}'.");
_logger.LogInformation($"Found script runtime context '{runtimeContext.TargetFramework.Framework}' for '{runtimeContext.ProjectFile.ProjectFilePath}'.");

var projectExporter = runtimeContext.CreateExporter("Release");
var projectDependencies = projectExporter.GetDependencies();
Expand All @@ -116,14 +115,6 @@ public void Initalize(IConfiguration configuration)
_logger.LogDebug("Discovered script compilation assembly reference: " + compilationAssembly.ResolvedPath);
AddMetadataReference(commonReferences, compilationAssembly.ResolvedPath);
}

// for non .NET Core, include System.Runtime
if (runtimeContext.TargetFramework.Framework != ".NETCoreApp")
{

inheritedCompileLibraries.AddRange(DependencyContext.Default.CompileLibraries.Where(x =>
x.Name.ToLowerInvariant().StartsWith("system.runtime")));
}
}

// inject all inherited assemblies
Expand Down Expand Up @@ -155,6 +146,33 @@ public void Initalize(IConfiguration configuration)
}
}

private void AddDefaultClrMetadataReferences(ProjectContext projectContext, HashSet<MetadataReference> commonReferences)
{
if (projectContext == null || projectContext.TargetFramework?.Framework != ".NETCoreApp")
{
var assemblies = new[]
{
typeof(object).GetTypeInfo().Assembly,
typeof(Enumerable).GetTypeInfo().Assembly,
typeof(Stack<>).GetTypeInfo().Assembly,
typeof(Lazy<,>).GetTypeInfo().Assembly,
_assemblyLoader.Load("System.Runtime"),
_assemblyLoader.Load("mscorlib")
};

var references = assemblies
.Where(a => a != null)
.Select(a => a.Location)
.Distinct()
.Select(l => _metadataFileReferenceCache.GetMetadataReference(l));

foreach (var reference in references)
{
commonReferences.Add(reference);
}
}
}

private IEnumerable<ProjectContext> TryCreateRuntimeContextsFromScriptFiles()
{
_logger.LogInformation($"Attempting to create runtime context from script files. Default target framework {_targetFrameWork.Value}");
Expand Down