From cc75ecb293151bfe7fbbc31a907e82ab8b17650a Mon Sep 17 00:00:00 2001 From: Christopher Scott Date: Wed, 29 May 2024 15:29:58 -0500 Subject: [PATCH 1/5] fix tests --- .../APIView/Languages/CompilationFactory.cs | 4 +++- .../APIView/Properties/launchSettings.json | 18 +++++++++++------- .../ExactFormatting/Inheritance.cs | 14 +++++++++++++- 3 files changed, 27 insertions(+), 9 deletions(-) diff --git a/src/dotnet/APIView/APIView/Languages/CompilationFactory.cs b/src/dotnet/APIView/APIView/Languages/CompilationFactory.cs index 8ae475a7d50..ba196de9c72 100644 --- a/src/dotnet/APIView/APIView/Languages/CompilationFactory.cs +++ b/src/dotnet/APIView/APIView/Languages/CompilationFactory.cs @@ -13,7 +13,9 @@ public static class CompilationFactory { private static HashSet AllowedAssemblies = new HashSet(new[] { - "Microsoft.Bcl.AsyncInterfaces" + "Microsoft.Bcl.AsyncInterfaces", + "System.ClientModel" + }, StringComparer.InvariantCultureIgnoreCase); public static IAssemblySymbol GetCompilation(string file) diff --git a/src/dotnet/APIView/APIView/Properties/launchSettings.json b/src/dotnet/APIView/APIView/Properties/launchSettings.json index 68de47267c5..4bf1a506551 100644 --- a/src/dotnet/APIView/APIView/Properties/launchSettings.json +++ b/src/dotnet/APIView/APIView/Properties/launchSettings.json @@ -1,8 +1,12 @@ -{ - "profiles": { - "TypeList": { - "commandName": "Project", - "commandLineArgs": "..\\..\\..\\TestLibrary\\Debug\\netcoreapp2.1\\TestLibrary.dll" - } - } +{ + "profiles": { + "TypeList": { + "commandName": "Project", + "commandLineArgs": "\"C:\\Users\\chriss\\nuget\\Azure.Core.1.40.0-alpha.20240523.1.nupkg\" C:\\Users\\chriss\\Desktop\\" + }, + "WSL": { + "commandName": "WSL2", + "distributionName": "" + } + } } \ No newline at end of file diff --git a/src/dotnet/APIView/APIViewUnitTests/ExactFormatting/Inheritance.cs b/src/dotnet/APIView/APIViewUnitTests/ExactFormatting/Inheritance.cs index 1125228f4cc..f216b9354aa 100644 --- a/src/dotnet/APIView/APIViewUnitTests/ExactFormatting/Inheritance.cs +++ b/src/dotnet/APIView/APIViewUnitTests/ExactFormatting/Inheritance.cs @@ -1,4 +1,4 @@ -/*-*/using System; +/*-*/using System; using System.Threading.Tasks; internal interface IInternal @@ -34,4 +34,16 @@ public class OClass/*-*/ : IInternal/*-*/ { void IInternal.N(){} /*-*/ } + public/*-*/ partial/*-*/ class PClass : I2/*@, I1@*/ { + public PClass()/*-*/{/*-*/;/*-*/}/*-*/ + } + /*-*/public partial class PClass : I1 { + }/*-*/ + public/*-*/ partial/*-*/ struct S : I2/*@, I1@*/ { + public S()/*-*/{/*-*/;/*-*/}/*-*/ + } + /*-*/public partial struct S : I1 + { + }/*-*/ + } From 4e3afa101b1becf6b429ea646779d9748a88c0ed Mon Sep 17 00:00:00 2001 From: Christopher Scott Date: Thu, 6 Jun 2024 14:55:52 -0500 Subject: [PATCH 2/5] Add allowed nupkg dependencies to the compilation --- .../APIView/Languages/CompilationFactory.cs | 17 ++++- .../APIView/APIViewWeb/APIViewWeb.csproj | 1 + .../Languages/CSharpLanguageService.cs | 65 +++++++++++++++++-- 3 files changed, 75 insertions(+), 8 deletions(-) diff --git a/src/dotnet/APIView/APIView/Languages/CompilationFactory.cs b/src/dotnet/APIView/APIView/Languages/CompilationFactory.cs index 8ae475a7d50..62f9a6fcd90 100644 --- a/src/dotnet/APIView/APIView/Languages/CompilationFactory.cs +++ b/src/dotnet/APIView/APIView/Languages/CompilationFactory.cs @@ -13,7 +13,9 @@ public static class CompilationFactory { private static HashSet AllowedAssemblies = new HashSet(new[] { - "Microsoft.Bcl.AsyncInterfaces" + "Microsoft.Bcl.AsyncInterfaces", + "System.ClientModel" + }, StringComparer.InvariantCultureIgnoreCase); public static IAssemblySymbol GetCompilation(string file) @@ -24,7 +26,7 @@ public static IAssemblySymbol GetCompilation(string file) } } - public static IAssemblySymbol GetCompilation(Stream stream, Stream documentationStream) + public static IAssemblySymbol GetCompilation(Stream stream, Stream documentationStream, IEnumerable dependencyPaths = null) { PortableExecutableReference reference; @@ -59,6 +61,17 @@ public static IAssemblySymbol GetCompilation(Stream stream, Stream documentation compilation = compilation.AddReferences(MetadataReference.CreateFromFile(tpl)); } } + if (dependencyPaths != null) + { + foreach (var dependencyFile in dependencyPaths) + { + if (!File.Exists(dependencyFile) || !AllowedAssemblies.Contains(Path.GetFileNameWithoutExtension(dependencyFile))) + { + continue; + } + compilation = compilation.AddReferences(MetadataReference.CreateFromFile(dependencyFile)); + } + } return (IAssemblySymbol)compilation.GetAssemblyOrModuleSymbol(reference); } diff --git a/src/dotnet/APIView/APIViewWeb/APIViewWeb.csproj b/src/dotnet/APIView/APIViewWeb/APIViewWeb.csproj index 9957e6ba219..70d91dba9b6 100644 --- a/src/dotnet/APIView/APIViewWeb/APIViewWeb.csproj +++ b/src/dotnet/APIView/APIViewWeb/APIViewWeb.csproj @@ -57,6 +57,7 @@ + diff --git a/src/dotnet/APIView/APIViewWeb/Languages/CSharpLanguageService.cs b/src/dotnet/APIView/APIViewWeb/Languages/CSharpLanguageService.cs index 133a3d1ce55..065df2935ee 100644 --- a/src/dotnet/APIView/APIViewWeb/Languages/CSharpLanguageService.cs +++ b/src/dotnet/APIView/APIViewWeb/Languages/CSharpLanguageService.cs @@ -7,9 +7,15 @@ using System.IO.Compression; using System.Linq; using System.Text.RegularExpressions; +using System.Threading; using System.Threading.Tasks; using System.Xml.Linq; using ApiView; +using NuGet.Common; +using NuGet.Packaging; +using NuGet.Protocol; +using NuGet.Protocol.Core.Types; +using NuGet.Versioning; namespace APIViewWeb { @@ -44,9 +50,10 @@ public override bool CanUpdate(string versionString) return versionString != CodeFileBuilder.CurrentVersion; } - public override Task GetCodeFileAsync(string originalName, Stream stream, bool runAnalysis) + public override async Task GetCodeFileAsync(string originalName, Stream stream, bool runAnalysis) { ZipArchive archive = null; + string dependencyFilesTempDir = null; try { Stream dllStream = stream; @@ -62,7 +69,7 @@ public override Task GetCodeFileAsync(string originalName, Stream stre var dllEntries = archive.Entries.Where(entry => IsDll(entry.Name)).ToArray(); if (dllEntries.Length == 0) { - return Task.FromResult(GetDummyReviewCodeFile(originalName, dependencies)); + return GetDummyReviewCodeFile(originalName, dependencies); } var dllEntry = dllEntries.First(); @@ -99,17 +106,24 @@ public override Task GetCodeFileAsync(string originalName, Stream stre } } - var assemblySymbol = CompilationFactory.GetCompilation(dllStream, docStream); + dependencyFilesTempDir = await ExtractNugetDependencies(dependencies).ConfigureAwait(false); + var dependencyFilePaths = Directory.EnumerateFiles(dependencyFilesTempDir, "*.dll", SearchOption.AllDirectories); + + var assemblySymbol = CompilationFactory.GetCompilation(dllStream, docStream, dependencyFilePaths); if (assemblySymbol == null) { - return Task.FromResult(GetDummyReviewCodeFile(originalName, dependencies)); + return GetDummyReviewCodeFile(originalName, dependencies); } - return Task.FromResult(new CodeFileBuilder().Build(assemblySymbol, runAnalysis, dependencies)); + return new CodeFileBuilder().Build(assemblySymbol, runAnalysis, dependencies); } finally { archive?.Dispose(); + if (dependencyFilesTempDir != null && Directory.Exists(dependencyFilesTempDir)) + { + Directory.Delete(dependencyFilesTempDir, true); + } } } @@ -132,7 +146,7 @@ private CodeFile GetDummyReviewCodeFile(string originalName, List + /// Resolves the NuGet package dependencies and extracts them to a temporary folder. It is the responsibility of teh caller to clean up the folder. + /// + /// The dependency infos + /// A temporary path where the dependency files were extracted. + private async Task ExtractNugetDependencies(List dependencyInfos) + { + string tempFolder = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); + SourceCacheContext cache = new SourceCacheContext(); + SourceRepository repository = NuGet.Protocol.Core.Types.Repository.Factory.GetCoreV3("https://api.nuget.org/v3/index.json"); + + FindPackageByIdResource resource = await repository.GetResourceAsync().ConfigureAwait(false); + foreach (var dep in dependencyInfos) + { + using (MemoryStream packageStream = new MemoryStream()) + { + if (await resource.CopyNupkgToStreamAsync( + dep.Name, + new NuGetVersion(dep.Version), + packageStream, + cache, + NullLogger.Instance, + CancellationToken.None)) + { + using PackageArchiveReader reader = new PackageArchiveReader(packageStream); + NuspecReader nuspec = reader.NuspecReader; + var file = reader.GetFiles().FirstOrDefault(f => f.EndsWith(dep.Name + ".dll")); + if (file != null) + { + var fileInfo = new FileInfo(file); + var path = Path.Combine(tempFolder, dep.Name, fileInfo.Name); + var tmp = reader.ExtractFile(file, path, NullLogger.Instance); + } + } + } + } + return tempFolder; + } } } From 38801d0f5539697773998a955c9ed0340cf6bd29 Mon Sep 17 00:00:00 2001 From: Christopher Scott Date: Thu, 6 Jun 2024 14:59:26 -0500 Subject: [PATCH 3/5] revert old changes --- .../APIView/Properties/launchSettings.json | 18 +++++++----------- .../ExactFormatting/Inheritance.cs | 14 +------------- 2 files changed, 8 insertions(+), 24 deletions(-) diff --git a/src/dotnet/APIView/APIView/Properties/launchSettings.json b/src/dotnet/APIView/APIView/Properties/launchSettings.json index 4bf1a506551..68de47267c5 100644 --- a/src/dotnet/APIView/APIView/Properties/launchSettings.json +++ b/src/dotnet/APIView/APIView/Properties/launchSettings.json @@ -1,12 +1,8 @@ -{ - "profiles": { - "TypeList": { - "commandName": "Project", - "commandLineArgs": "\"C:\\Users\\chriss\\nuget\\Azure.Core.1.40.0-alpha.20240523.1.nupkg\" C:\\Users\\chriss\\Desktop\\" - }, - "WSL": { - "commandName": "WSL2", - "distributionName": "" - } - } +{ + "profiles": { + "TypeList": { + "commandName": "Project", + "commandLineArgs": "..\\..\\..\\TestLibrary\\Debug\\netcoreapp2.1\\TestLibrary.dll" + } + } } \ No newline at end of file diff --git a/src/dotnet/APIView/APIViewUnitTests/ExactFormatting/Inheritance.cs b/src/dotnet/APIView/APIViewUnitTests/ExactFormatting/Inheritance.cs index f216b9354aa..1125228f4cc 100644 --- a/src/dotnet/APIView/APIViewUnitTests/ExactFormatting/Inheritance.cs +++ b/src/dotnet/APIView/APIViewUnitTests/ExactFormatting/Inheritance.cs @@ -1,4 +1,4 @@ -/*-*/using System; +/*-*/using System; using System.Threading.Tasks; internal interface IInternal @@ -34,16 +34,4 @@ public class OClass/*-*/ : IInternal/*-*/ { void IInternal.N(){} /*-*/ } - public/*-*/ partial/*-*/ class PClass : I2/*@, I1@*/ { - public PClass()/*-*/{/*-*/;/*-*/}/*-*/ - } - /*-*/public partial class PClass : I1 { - }/*-*/ - public/*-*/ partial/*-*/ struct S : I2/*@, I1@*/ { - public S()/*-*/{/*-*/;/*-*/}/*-*/ - } - /*-*/public partial struct S : I1 - { - }/*-*/ - } From f3a524300cbe021ab7a3b12437988f16fec13403 Mon Sep 17 00:00:00 2001 From: Christopher Scott Date: Thu, 6 Jun 2024 15:02:25 -0500 Subject: [PATCH 4/5] try/catch nuget restore --- .../APIView/APIViewWeb/Languages/CSharpLanguageService.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/dotnet/APIView/APIViewWeb/Languages/CSharpLanguageService.cs b/src/dotnet/APIView/APIViewWeb/Languages/CSharpLanguageService.cs index 065df2935ee..0d3a064aea0 100644 --- a/src/dotnet/APIView/APIViewWeb/Languages/CSharpLanguageService.cs +++ b/src/dotnet/APIView/APIViewWeb/Languages/CSharpLanguageService.cs @@ -165,7 +165,7 @@ private async Task ExtractNugetDependencies(List depende string tempFolder = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); SourceCacheContext cache = new SourceCacheContext(); SourceRepository repository = NuGet.Protocol.Core.Types.Repository.Factory.GetCoreV3("https://api.nuget.org/v3/index.json"); - +try{ FindPackageByIdResource resource = await repository.GetResourceAsync().ConfigureAwait(false); foreach (var dep in dependencyInfos) { @@ -191,6 +191,7 @@ private async Task ExtractNugetDependencies(List depende } } } +} return tempFolder; } } From 626f5abf516d6264f552f4aafed84e274f46d762 Mon Sep 17 00:00:00 2001 From: Christopher Scott Date: Thu, 6 Jun 2024 15:13:27 -0500 Subject: [PATCH 5/5] formatting --- .../Languages/CSharpLanguageService.cs | 43 +++++++++++-------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/src/dotnet/APIView/APIViewWeb/Languages/CSharpLanguageService.cs b/src/dotnet/APIView/APIViewWeb/Languages/CSharpLanguageService.cs index 0d3a064aea0..52ab9d51d59 100644 --- a/src/dotnet/APIView/APIViewWeb/Languages/CSharpLanguageService.cs +++ b/src/dotnet/APIView/APIViewWeb/Languages/CSharpLanguageService.cs @@ -165,33 +165,38 @@ private async Task ExtractNugetDependencies(List depende string tempFolder = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); SourceCacheContext cache = new SourceCacheContext(); SourceRepository repository = NuGet.Protocol.Core.Types.Repository.Factory.GetCoreV3("https://api.nuget.org/v3/index.json"); -try{ - FindPackageByIdResource resource = await repository.GetResourceAsync().ConfigureAwait(false); - foreach (var dep in dependencyInfos) + try { - using (MemoryStream packageStream = new MemoryStream()) + FindPackageByIdResource resource = await repository.GetResourceAsync().ConfigureAwait(false); + foreach (var dep in dependencyInfos) { - if (await resource.CopyNupkgToStreamAsync( - dep.Name, - new NuGetVersion(dep.Version), - packageStream, - cache, - NullLogger.Instance, - CancellationToken.None)) + using (MemoryStream packageStream = new MemoryStream()) { - using PackageArchiveReader reader = new PackageArchiveReader(packageStream); - NuspecReader nuspec = reader.NuspecReader; - var file = reader.GetFiles().FirstOrDefault(f => f.EndsWith(dep.Name + ".dll")); - if (file != null) + if (await resource.CopyNupkgToStreamAsync( + dep.Name, + new NuGetVersion(dep.Version), + packageStream, + cache, + NullLogger.Instance, + CancellationToken.None)) { - var fileInfo = new FileInfo(file); - var path = Path.Combine(tempFolder, dep.Name, fileInfo.Name); - var tmp = reader.ExtractFile(file, path, NullLogger.Instance); + using PackageArchiveReader reader = new PackageArchiveReader(packageStream); + NuspecReader nuspec = reader.NuspecReader; + var file = reader.GetFiles().FirstOrDefault(f => f.EndsWith(dep.Name + ".dll")); + if (file != null) + { + var fileInfo = new FileInfo(file); + var path = Path.Combine(tempFolder, dep.Name, fileInfo.Name); + var tmp = reader.ExtractFile(file, path, NullLogger.Instance); + } } } } } -} + finally + { + cache.Dispose(); + } return tempFolder; } }