77using System . IO . Compression ;
88using System . Linq ;
99using System . Text . RegularExpressions ;
10+ using System . Threading ;
1011using System . Threading . Tasks ;
1112using System . Xml . Linq ;
1213using ApiView ;
14+ using NuGet . Common ;
15+ using NuGet . Packaging ;
16+ using NuGet . Protocol ;
17+ using NuGet . Protocol . Core . Types ;
18+ using NuGet . Versioning ;
1319
1420namespace APIViewWeb
1521{
@@ -44,9 +50,10 @@ public override bool CanUpdate(string versionString)
4450 return versionString != CodeFileBuilder . CurrentVersion ;
4551 }
4652
47- public override Task < CodeFile > GetCodeFileAsync ( string originalName , Stream stream , bool runAnalysis )
53+ public override async Task < CodeFile > GetCodeFileAsync ( string originalName , Stream stream , bool runAnalysis )
4854 {
4955 ZipArchive archive = null ;
56+ string dependencyFilesTempDir = null ;
5057 try
5158 {
5259 Stream dllStream = stream ;
@@ -62,7 +69,7 @@ public override Task<CodeFile> GetCodeFileAsync(string originalName, Stream stre
6269 var dllEntries = archive . Entries . Where ( entry => IsDll ( entry . Name ) ) . ToArray ( ) ;
6370 if ( dllEntries . Length == 0 )
6471 {
65- return Task . FromResult ( GetDummyReviewCodeFile ( originalName , dependencies ) ) ;
72+ return GetDummyReviewCodeFile ( originalName , dependencies ) ;
6673 }
6774
6875 var dllEntry = dllEntries . First ( ) ;
@@ -99,17 +106,24 @@ public override Task<CodeFile> GetCodeFileAsync(string originalName, Stream stre
99106 }
100107 }
101108
102- var assemblySymbol = CompilationFactory . GetCompilation ( dllStream , docStream ) ;
109+ dependencyFilesTempDir = await ExtractNugetDependencies ( dependencies ) . ConfigureAwait ( false ) ;
110+ var dependencyFilePaths = Directory . EnumerateFiles ( dependencyFilesTempDir , "*.dll" , SearchOption . AllDirectories ) ;
111+
112+ var assemblySymbol = CompilationFactory . GetCompilation ( dllStream , docStream , dependencyFilePaths ) ;
103113 if ( assemblySymbol == null )
104114 {
105- return Task . FromResult ( GetDummyReviewCodeFile ( originalName , dependencies ) ) ;
115+ return GetDummyReviewCodeFile ( originalName , dependencies ) ;
106116 }
107117
108- return Task . FromResult ( new CodeFileBuilder ( ) . Build ( assemblySymbol , runAnalysis , dependencies ) ) ;
118+ return new CodeFileBuilder ( ) . Build ( assemblySymbol , runAnalysis , dependencies ) ;
109119 }
110120 finally
111121 {
112122 archive ? . Dispose ( ) ;
123+ if ( dependencyFilesTempDir != null && Directory . Exists ( dependencyFilesTempDir ) )
124+ {
125+ Directory . Delete ( dependencyFilesTempDir , true ) ;
126+ }
113127 }
114128 }
115129
@@ -132,13 +146,58 @@ private CodeFile GetDummyReviewCodeFile(string originalName, List<DependencyInfo
132146 CodeFileBuilder . BuildDependencies ( builder , dependencies ) ;
133147
134148 return new CodeFile ( )
135- {
149+ {
136150 Name = reviewName ,
137151 Language = "C#" ,
138152 VersionString = CodeFileBuilder . CurrentVersion ,
139153 PackageName = packageName ,
140154 Tokens = builder . Tokens . ToArray ( )
141155 } ;
142156 }
157+
158+ /// <summary>
159+ /// Resolves the NuGet package dependencies and extracts them to a temporary folder. It is the responsibility of teh caller to clean up the folder.
160+ /// </summary>
161+ /// <param name="dependencyInfos">The dependency infos</param>
162+ /// <returns>A temporary path where the dependency files were extracted.</returns>
163+ private async Task < string > ExtractNugetDependencies ( List < DependencyInfo > dependencyInfos )
164+ {
165+ string tempFolder = Path . Combine ( Path . GetTempPath ( ) , Guid . NewGuid ( ) . ToString ( ) ) ;
166+ SourceCacheContext cache = new SourceCacheContext ( ) ;
167+ SourceRepository repository = NuGet . Protocol . Core . Types . Repository . Factory . GetCoreV3 ( "https://api.nuget.org/v3/index.json" ) ;
168+ try
169+ {
170+ FindPackageByIdResource resource = await repository . GetResourceAsync < FindPackageByIdResource > ( ) . ConfigureAwait ( false ) ;
171+ foreach ( var dep in dependencyInfos )
172+ {
173+ using ( MemoryStream packageStream = new MemoryStream ( ) )
174+ {
175+ if ( await resource . CopyNupkgToStreamAsync (
176+ dep . Name ,
177+ new NuGetVersion ( dep . Version ) ,
178+ packageStream ,
179+ cache ,
180+ NullLogger . Instance ,
181+ CancellationToken . None ) )
182+ {
183+ using PackageArchiveReader reader = new PackageArchiveReader ( packageStream ) ;
184+ NuspecReader nuspec = reader . NuspecReader ;
185+ var file = reader . GetFiles ( ) . FirstOrDefault ( f => f . EndsWith ( dep . Name + ".dll" ) ) ;
186+ if ( file != null )
187+ {
188+ var fileInfo = new FileInfo ( file ) ;
189+ var path = Path . Combine ( tempFolder , dep . Name , fileInfo . Name ) ;
190+ var tmp = reader . ExtractFile ( file , path , NullLogger . Instance ) ;
191+ }
192+ }
193+ }
194+ }
195+ }
196+ finally
197+ {
198+ cache . Dispose ( ) ;
199+ }
200+ return tempFolder ;
201+ }
143202 }
144203}
0 commit comments