Last active
July 15, 2021 16:00
-
-
Save andersstorhaug/c7460c7e754f343ae1ad2c6fd8dba051 to your computer and use it in GitHub Desktop.
Roslyn scripting with NuGet references
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System; | |
| using System.Collections.Generic; | |
| using System.IO; | |
| using System.Linq; | |
| using Dotnet.Script.DependencyModel.Environment; | |
| using Dotnet.Script.DependencyModel.Logging; | |
| using Dotnet.Script.DependencyModel.ProjectSystem; | |
| using Microsoft.CodeAnalysis; | |
| using NuGet.Commands; | |
| using NuGet.Configuration; | |
| using NuGet.Frameworks; | |
| using NuGet.LibraryModel; | |
| using NuGet.ProjectModel; | |
| using NuGet.Protocol; | |
| using NuGet.Protocol.Core.Types; | |
| using NuGet.RuntimeModel; | |
| using NuGet.Versioning; | |
| namespace ScriptingSpike | |
| { | |
| public class NugetReferencesResolver | |
| { | |
| private readonly LogFactory _logFactory; | |
| private readonly ScriptFilesResolver _scriptFilesResolver; | |
| private readonly ScriptParser _scriptParser; | |
| public NugetReferencesResolver( | |
| LogFactory logFactory, | |
| ScriptParser scriptParser = null, | |
| ScriptFilesResolver scriptFilesResolver = null) | |
| { | |
| _logFactory = logFactory; | |
| _scriptParser = scriptParser ?? new ScriptParser(logFactory); | |
| _scriptFilesResolver = scriptFilesResolver ?? new ScriptFilesResolver(); | |
| } | |
| public async IAsyncEnumerable<MetadataReference> GetDependencies(string scriptFile, string[] packageSources) | |
| { | |
| var framework = NuGetFramework.Parse(ScriptEnvironment.Default.TargetFramework); | |
| var runtimeIdentifier = ScriptEnvironment.Default.RuntimeIdentifier; | |
| var scriptDirectory = Path.GetDirectoryName(scriptFile) ?? throw new ArgumentException("Must be a valid path", nameof(scriptFile)); | |
| // Performs the standard `NuGet.Config` lookup | |
| var settings = Settings.LoadDefaultSettings(scriptDirectory); | |
| var sourceRepositories = SettingsUtility | |
| .GetEnabledSources(settings) | |
| .Select(value => Repository.Factory.GetCoreV3(value.Source)) | |
| .Concat(packageSources.Select(source => Repository.Factory.GetCoreV3(source))) | |
| .ToList(); | |
| var logger = new NuGetLogger(_logFactory); | |
| using var sourceCacheContext = new SourceCacheContext(); | |
| var providers = RestoreCommandProviders.Create( | |
| SettingsUtility.GetGlobalPackagesFolder(settings), | |
| fallbackPackageFolderPaths: Enumerable.Empty<string>(), | |
| sourceRepositories, | |
| sourceCacheContext, | |
| new LocalPackageFileCache(), | |
| logger); | |
| var parseResult = _scriptParser.ParseFromFiles(_scriptFilesResolver.GetScriptFiles(scriptFile)); | |
| var packageSpec = new PackageSpec | |
| { | |
| FilePath = Path.Combine(scriptDirectory, "script.json"), | |
| Name = "script", | |
| Version = new NuGetVersion(1, 0, 0), | |
| TargetFrameworks = | |
| { | |
| new TargetFrameworkInformation | |
| { | |
| FrameworkName = framework, | |
| Dependencies = parseResult.PackageReferences.Select(package => new LibraryDependency | |
| { | |
| LibraryRange = new LibraryRange( | |
| package.Id.Value, | |
| VersionRange.Parse(package.Version.Value), | |
| LibraryDependencyTarget.Package) | |
| }).ToList() | |
| } | |
| }, | |
| RuntimeGraph = new RuntimeGraph(new[] | |
| { | |
| new RuntimeDescription(runtimeIdentifier) | |
| }) | |
| }; | |
| var command = new RestoreCommand(new RestoreRequest(packageSpec, providers, sourceCacheContext, null, logger)); | |
| // Note, the package file is not created, because `RestoreResult.CommitAsync` is not called | |
| var result = await command.ExecuteAsync(); | |
| var lockFile = result.LockFile; | |
| var target = lockFile.GetTarget(framework, runtimeIdentifier); | |
| // N.B. Native assemblies are not handled here, but, theoretically could be | |
| var paths = target.Libraries | |
| .SelectMany(library => library.CompileTimeAssemblies | |
| .Concat(library.RuntimeAssemblies) | |
| .Select(item => (library.Name, library.Version, item.Path))) | |
| .Where(value => Path.GetExtension(value.Path) == ".dll") | |
| .SelectMany( | |
| _ => lockFile.PackageFolders.Select(folder => folder.Path), | |
| (library, folder) => Path.Combine(folder, library.Name, library.Version.ToString(), library.Path)) | |
| .Where(File.Exists) | |
| .ToList(); | |
| foreach (var dependency in paths) | |
| { | |
| yield return MetadataReference.CreateFromFile(dependency); | |
| } | |
| } | |
| } | |
| } |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This uses a reference to the
NuGet.CommandsNuGet package.