Skip to content

Commit 6287e62

Browse files
Update Parser Logic (#8565)
1 parent 211cf7d commit 6287e62

3 files changed

Lines changed: 64 additions & 50 deletions

File tree

src/dotnet/APIView/APIViewWeb/Languages/CSharpLanguageService.cs

Lines changed: 0 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -86,50 +86,5 @@ private CodeFile GetDummyReviewCodeFile(string originalName, List<DependencyInfo
8686
Tokens = builder.Tokens.ToArray()
8787
};
8888
}
89-
90-
/// <summary>
91-
/// Resolves the NuGet package dependencies and extracts them to a temporary folder. It is the responsibility of teh caller to clean up the folder.
92-
/// </summary>
93-
/// <param name="dependencyInfos">The dependency infos</param>
94-
/// <returns>A temporary path where the dependency files were extracted.</returns>
95-
private async Task<string> ExtractNugetDependencies(List<DependencyInfo> dependencyInfos)
96-
{
97-
string tempFolder = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
98-
SourceCacheContext cache = new SourceCacheContext();
99-
SourceRepository repository = NuGet.Protocol.Core.Types.Repository.Factory.GetCoreV3("https://api.nuget.org/v3/index.json");
100-
try
101-
{
102-
FindPackageByIdResource resource = await repository.GetResourceAsync<FindPackageByIdResource>().ConfigureAwait(false);
103-
foreach (var dep in dependencyInfos)
104-
{
105-
using (MemoryStream packageStream = new MemoryStream())
106-
{
107-
if (await resource.CopyNupkgToStreamAsync(
108-
dep.Name,
109-
new NuGetVersion(dep.Version),
110-
packageStream,
111-
cache,
112-
NullLogger.Instance,
113-
CancellationToken.None))
114-
{
115-
using PackageArchiveReader reader = new PackageArchiveReader(packageStream);
116-
NuspecReader nuspec = reader.NuspecReader;
117-
var file = reader.GetFiles().FirstOrDefault(f => f.EndsWith(dep.Name + ".dll"));
118-
if (file != null)
119-
{
120-
var fileInfo = new FileInfo(file);
121-
var path = Path.Combine(tempFolder, dep.Name, fileInfo.Name);
122-
var tmp = reader.ExtractFile(file, path, NullLogger.Instance);
123-
}
124-
}
125-
}
126-
}
127-
}
128-
finally
129-
{
130-
cache.Dispose();
131-
}
132-
return tempFolder;
133-
}
13489
}
13590
}

tools/apiview/parsers/csharp-api-parser/CSharpAPIParser/CSharpAPIParser.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
</PropertyGroup>
1212

1313
<ItemGroup>
14+
<PackageReference Include="NuGet.Protocol" Version="6.10.1" />
1415
<PackageReference Include="System.CommandLine" Version="2.0.0-beta4.22272.1" />
1516
</ItemGroup>
1617

tools/apiview/parsers/csharp-api-parser/CSharpAPIParser/Program.cs

Lines changed: 63 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@
44
using System.Text.Json.Serialization;
55
using System.Xml.Linq;
66
using ApiView;
7+
using NuGet.Common;
8+
using NuGet.Packaging;
9+
using NuGet.Protocol;
10+
using NuGet.Protocol.Core.Types;
11+
using NuGet.Versioning;
712

813
var inputOption = new Option<FileInfo>("--packageFilePath", "C# Package (.nupkg) file").ExistingOnly();
914
inputOption.IsRequired = true;
@@ -21,13 +26,13 @@
2126
runAnalysis
2227
};
2328

24-
rootCommand.SetHandler((FileInfo packageFilePath, DirectoryInfo outputDirectory, string outputFileName, bool runAnalysis) =>
29+
rootCommand.SetHandler(async (FileInfo packageFilePath, DirectoryInfo outputDirectory, string outputFileName, bool runAnalysis) =>
2530
{
2631
try
2732
{
2833
using (var stream = packageFilePath.OpenRead())
2934
{
30-
HandlePackageFileParsing(stream, packageFilePath, outputDirectory, outputFileName, runAnalysis);
35+
await HandlePackageFileParsing(stream, packageFilePath, outputDirectory, outputFileName, runAnalysis);
3136
}
3237
}
3338
catch (Exception ex)
@@ -39,12 +44,13 @@
3944
return rootCommand.InvokeAsync(args).Result;
4045

4146

42-
static void HandlePackageFileParsing(Stream stream, FileInfo packageFilePath, DirectoryInfo OutputDirectory, string outputFileName, bool runAnalysis)
47+
static async Task HandlePackageFileParsing(Stream stream, FileInfo packageFilePath, DirectoryInfo OutputDirectory, string outputFileName, bool runAnalysis)
4348
{
4449
ZipArchive? zipArchive = null;
4550
Stream? dllStream = stream;
4651
Stream? docStream = null;
4752
List<DependencyInfo>? dependencies = null;
53+
string dependencyFilesTempDir = null;
4854

4955
try
5056
{
@@ -94,12 +100,16 @@ static void HandlePackageFileParsing(Stream stream, FileInfo packageFilePath, Di
94100
}
95101
}
96102

97-
var assemblySymbol = CompilationFactory.GetCompilation(dllStream, docStream);
103+
dependencyFilesTempDir = await ExtractNugetDependencies(dependencies).ConfigureAwait(false);
104+
var dependencyFilePaths = Directory.EnumerateFiles(dependencyFilesTempDir, "*.dll", SearchOption.AllDirectories);
105+
var assemblySymbol = CompilationFactory.GetCompilation(dllStream, docStream, dependencyFilePaths);
106+
98107
if (assemblySymbol == null)
99108
{
100109
Console.Error.WriteLine($"PackageFile {packageFilePath.FullName} contains no Assembly Symbol.");
101110
return;
102111
}
112+
103113
var parsedFileName = string.IsNullOrEmpty(outputFileName) ? assemblySymbol.Name : outputFileName;
104114
var treeTokenCodeFile = new CSharpAPIParser.TreeToken.CodeFileBuilder().Build(assemblySymbol, runAnalysis, dependencies);
105115
var gzipJsonTokenFilePath = Path.Combine(OutputDirectory.FullName, $"{parsedFileName}.json.tgz");
@@ -126,8 +136,11 @@ static void HandlePackageFileParsing(Stream stream, FileInfo packageFilePath, Di
126136
finally
127137
{
128138
zipArchive?.Dispose();
139+
if (dependencyFilesTempDir != null && Directory.Exists(dependencyFilesTempDir))
140+
{
141+
Directory.Delete(dependencyFilesTempDir, true);
142+
}
129143
}
130-
131144
}
132145

133146
static bool IsNuget(string name)
@@ -144,3 +157,48 @@ static bool IsDll(string name)
144157
{
145158
return name.EndsWith(".dll", StringComparison.OrdinalIgnoreCase);
146159
}
160+
161+
/// <summary>
162+
/// Resolves the NuGet package dependencies and extracts them to a temporary folder. It is the responsibility of teh caller to clean up the folder.
163+
/// </summary>
164+
/// <param name="dependencyInfos">The dependency infos</param>
165+
/// <returns>A temporary path where the dependency files were extracted.</returns>
166+
static async Task<string> ExtractNugetDependencies(List<DependencyInfo> dependencyInfos)
167+
{
168+
string tempFolder = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
169+
SourceCacheContext cache = new SourceCacheContext();
170+
SourceRepository repository = Repository.Factory.GetCoreV3("https://api.nuget.org/v3/index.json");
171+
try
172+
{
173+
FindPackageByIdResource resource = await repository.GetResourceAsync<FindPackageByIdResource>().ConfigureAwait(false);
174+
foreach (var dep in dependencyInfos)
175+
{
176+
using (MemoryStream packageStream = new MemoryStream())
177+
{
178+
if (await resource.CopyNupkgToStreamAsync(
179+
dep.Name,
180+
new NuGetVersion(dep.Version),
181+
packageStream,
182+
cache,
183+
NullLogger.Instance,
184+
CancellationToken.None))
185+
{
186+
using PackageArchiveReader reader = new PackageArchiveReader(packageStream);
187+
NuspecReader nuspec = reader.NuspecReader;
188+
var file = reader.GetFiles().FirstOrDefault(f => f.EndsWith(dep.Name + ".dll"));
189+
if (file != null)
190+
{
191+
var fileInfo = new FileInfo(file);
192+
var path = Path.Combine(tempFolder, dep.Name, fileInfo.Name);
193+
var tmp = reader.ExtractFile(file, path, NullLogger.Instance);
194+
}
195+
}
196+
}
197+
}
198+
}
199+
finally
200+
{
201+
cache.Dispose();
202+
}
203+
return tempFolder;
204+
}

0 commit comments

Comments
 (0)