-
Notifications
You must be signed in to change notification settings - Fork 418
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
Added support for referencing NuGet packages in C# scripts #813
Changes from all commits
02c7124
ad90c6f
f1d6dd7
6252c0d
c3bbfcc
0155e96
63db355
d58e538
a8683af
0e902d1
4607fbd
05756ec
5499e1e
1511099
d8eef4e
a7f7daf
7e52b3c
8316f1c
a603bf5
c9e9de7
e5a341d
ac8974a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,9 @@ | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<configuration> | ||
<packageSources> | ||
<clear /> | ||
<add key="NuGet" value="https://api.nuget.org/v3/index.json" /> | ||
<add key="dotnet-core" value="https://dotnet.myget.org/F/dotnet-core/api/v3/index.json" /> | ||
<add key="cli-deps" value="https://dotnet.myget.org/F/cli-deps/api/v3/index.json" /> | ||
</packageSources> | ||
</configuration> | ||
<packageSources> | ||
<clear /> | ||
<add key="NuGet" value="https://api.nuget.org/v3/index.json" /> | ||
<add key="dotnet-core" value="https://dotnet.myget.org/F/dotnet-core/api/v3/index.json" /> | ||
<add key="cli-deps" value="https://dotnet.myget.org/F/cli-deps/api/v3/index.json" /> | ||
</packageSources> | ||
</configuration> | ||
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,27 +1,31 @@ | ||
using System.Collections.Generic; | ||
using System.Collections.Immutable; | ||
using Microsoft.CodeAnalysis; | ||
using Microsoft.CodeAnalysis.Scripting; | ||
|
||
namespace OmniSharp.Script | ||
{ | ||
public class CachingScriptMetadataResolver : MetadataReferenceResolver | ||
{ | ||
private readonly MetadataReferenceResolver _defaultReferenceResolver; | ||
private static Dictionary<string, ImmutableArray<PortableExecutableReference>> DirectReferenceCache = new Dictionary<string, ImmutableArray<PortableExecutableReference>>(); | ||
private static Dictionary<string, PortableExecutableReference> MissingReferenceCache = new Dictionary<string, PortableExecutableReference>(); | ||
private static MetadataReferenceResolver _defaultRuntimeResolver = ScriptMetadataResolver.Default; | ||
|
||
public CachingScriptMetadataResolver(MetadataReferenceResolver defaultReferenceResolver) | ||
{ | ||
_defaultReferenceResolver = defaultReferenceResolver; | ||
} | ||
|
||
public override bool Equals(object other) | ||
{ | ||
return _defaultRuntimeResolver.Equals(other); | ||
return _defaultReferenceResolver.Equals(other); | ||
} | ||
|
||
public override int GetHashCode() | ||
{ | ||
return _defaultRuntimeResolver.GetHashCode(); | ||
return _defaultReferenceResolver.GetHashCode(); | ||
} | ||
|
||
public override bool ResolveMissingAssemblies => _defaultRuntimeResolver.ResolveMissingAssemblies; | ||
public override bool ResolveMissingAssemblies => _defaultReferenceResolver.ResolveMissingAssemblies; | ||
|
||
public override PortableExecutableReference ResolveMissingAssembly(MetadataReference definition, AssemblyIdentity referenceIdentity) | ||
{ | ||
|
@@ -30,7 +34,7 @@ public override PortableExecutableReference ResolveMissingAssembly(MetadataRefer | |
return MissingReferenceCache[referenceIdentity.Name]; | ||
} | ||
|
||
var result = _defaultRuntimeResolver.ResolveMissingAssembly(definition, referenceIdentity); | ||
var result = _defaultReferenceResolver.ResolveMissingAssembly(definition, referenceIdentity); | ||
if (result != null) | ||
{ | ||
MissingReferenceCache[referenceIdentity.Name] = result; | ||
|
@@ -47,7 +51,7 @@ public override ImmutableArray<PortableExecutableReference> ResolveReference(str | |
return DirectReferenceCache[key]; | ||
} | ||
|
||
var result = _defaultRuntimeResolver.ResolveReference(reference, baseFilePath, properties); | ||
var result = _defaultReferenceResolver.ResolveReference(reference, baseFilePath, properties); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it's not visible what happens here for nuget packages, can you explain a little? do they get installed? what if there is no network? what if there is no There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Any other feedback to @filipw's question above? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @seesharper: did this ever get answered? |
||
if (result.Length > 0) | ||
{ | ||
DirectReferenceCache[key] = result; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,6 +5,7 @@ | |
using System.Linq; | ||
using System.Reflection; | ||
using System.Threading.Tasks; | ||
using Dotnet.Script.NuGetMetadataResolver; | ||
using Microsoft.CodeAnalysis; | ||
using Microsoft.CodeAnalysis.CSharp; | ||
using Microsoft.DotNet.ProjectModel; | ||
|
@@ -15,7 +16,7 @@ | |
using OmniSharp.Services; | ||
|
||
namespace OmniSharp.Script | ||
{ | ||
{ | ||
[Export(typeof(IProjectSystem)), Shared] | ||
public class ScriptProjectSystem : IProjectSystem | ||
{ | ||
|
@@ -29,6 +30,8 @@ public class ScriptProjectSystem : IProjectSystem | |
private readonly OmniSharpWorkspace _workspace; | ||
private readonly IOmniSharpEnvironment _env; | ||
private readonly ILogger _logger; | ||
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) | ||
|
@@ -38,6 +41,7 @@ public ScriptProjectSystem(OmniSharpWorkspace workspace, IOmniSharpEnvironment e | |
_env = env; | ||
_logger = loggerFactory.CreateLogger<ScriptProjectSystem>(); | ||
_projects = new Dictionary<string, ProjectInfo>(); | ||
_scriptProjectProvider = ScriptProjectProvider.Create(loggerFactory); | ||
} | ||
|
||
public string Key => "Script"; | ||
|
@@ -46,6 +50,8 @@ public ScriptProjectSystem(OmniSharpWorkspace workspace, IOmniSharpEnvironment e | |
|
||
public void Initalize(IConfiguration configuration) | ||
{ | ||
var scriptHelper = new ScriptHelper(configuration); | ||
|
||
_logger.LogInformation($"Detecting CSX files in '{_env.TargetDirectory}'."); | ||
|
||
// Nothing to do if there are no CSX files | ||
|
@@ -60,15 +66,25 @@ public void Initalize(IConfiguration configuration) | |
|
||
// explicitly inherit scripting library references to all global script object (InteractiveScriptGlobals) to be recognized | ||
var inheritedCompileLibraries = DependencyContext.Default.CompileLibraries.Where(x => | ||
x.Name.ToLowerInvariant().StartsWith("microsoft.codeanalysis")).ToList(); | ||
x.Name.ToLowerInvariant().StartsWith("microsoft.codeanalysis")).ToList(); | ||
|
||
// explicitly include System.ValueTuple | ||
inheritedCompileLibraries.AddRange(DependencyContext.Default.CompileLibraries.Where(x => | ||
x.Name.ToLowerInvariant().StartsWith("system.valuetuple"))); | ||
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; | ||
} | ||
|
||
if (enableScriptNuGetReferences && (runtimeContexts == null || runtimeContexts.Any() == false)) | ||
{ | ||
runtimeContexts = TryCreateRuntimeContextsFromScriptFiles(); | ||
} | ||
|
||
// if we have no context, then we also have no dependencies | ||
// we can assume desktop framework | ||
|
@@ -81,7 +97,7 @@ public void Initalize(IConfiguration configuration) | |
AddMetadataReference(commonReferences, typeof(Enumerable).GetTypeInfo().Assembly.Location); | ||
|
||
inheritedCompileLibraries.AddRange(DependencyContext.Default.CompileLibraries.Where(x => | ||
x.Name.ToLowerInvariant().StartsWith("system.runtime"))); | ||
x.Name.ToLowerInvariant().StartsWith("system.runtime"))); | ||
} | ||
// otherwise we will grab dependencies for the script from the runtime context | ||
else | ||
|
@@ -106,7 +122,7 @@ public void Initalize(IConfiguration configuration) | |
{ | ||
|
||
inheritedCompileLibraries.AddRange(DependencyContext.Default.CompileLibraries.Where(x => | ||
x.Name.ToLowerInvariant().StartsWith("system.runtime"))); | ||
x.Name.ToLowerInvariant().StartsWith("system.runtime"))); | ||
} | ||
} | ||
|
||
|
@@ -124,7 +140,7 @@ public void Initalize(IConfiguration configuration) | |
try | ||
{ | ||
var csxFileName = Path.GetFileName(csxPath); | ||
var project = ScriptHelper.CreateProject(csxFileName, commonReferences); | ||
var project = scriptHelper.CreateProject(csxFileName, commonReferences); | ||
|
||
// add CSX project to workspace | ||
_workspace.AddProject(project); | ||
|
@@ -139,6 +155,21 @@ public void Initalize(IConfiguration configuration) | |
} | ||
} | ||
|
||
private IEnumerable<ProjectContext> TryCreateRuntimeContextsFromScriptFiles() | ||
{ | ||
_logger.LogInformation($"Attempting to create runtime context from script files. Default target framework {_targetFrameWork.Value}"); | ||
try | ||
{ | ||
var scriptProjectInfo = _scriptProjectProvider.CreateProject(_env.TargetDirectory, _targetFrameWork.Value); | ||
return ProjectContext.CreateContextForEachTarget(Path.GetDirectoryName(scriptProjectInfo.PathToProjectJson)); | ||
} | ||
catch (Exception exception) | ||
{ | ||
_logger.LogError(exception, "Unable to create runtime context from script files."); | ||
} | ||
return null; | ||
} | ||
|
||
private void AddMetadataReference(ISet<MetadataReference> referenceCollection, string fileReference) | ||
{ | ||
if (!File.Exists(fileReference)) | ||
|
@@ -201,5 +232,13 @@ Task<object> IProjectSystem.GetWorkspaceModelAsync(WorkspaceInformationRequest r | |
} | ||
return Task.FromResult<object>(new ScriptContextModelCollection(scriptContextModels)); | ||
} | ||
|
||
private static string ResolveTargetFramework() | ||
{ | ||
return Assembly.GetEntryAssembly().GetCustomAttributes() | ||
.OfType<System.Runtime.Versioning.TargetFrameworkAttribute>() | ||
.Select(x => x.FrameworkName) | ||
.FirstOrDefault(); | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Note that, in VS Code, this will always be net46. |
||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,5 +10,8 @@ | |
"useTabs": false, | ||
"tabSize": 4, | ||
"indentationSize": 4 | ||
}, | ||
"script": { | ||
"enableScriptNuGetReferences" : false | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This contains just unnecessary whitespace changes that you probably didn't mean to include.