@@ -34,6 +34,9 @@ public sealed class DependencyManager : IDisposable
3434 private readonly TemporaryDirectory tempWorkingDirectory ;
3535 private readonly bool cleanupTempWorkingDirectory ;
3636
37+ private readonly Lazy < Runtime > runtimeLazy ;
38+ private Runtime Runtime => runtimeLazy . Value ;
39+
3740 /// <summary>
3841 /// Performs C# dependency fetching.
3942 /// </summary>
@@ -53,6 +56,7 @@ public DependencyManager(string srcDir, IDependencyOptions options, ILogger logg
5356 try
5457 {
5558 this . dotnet = DotNet . Make ( options , progressMonitor , tempWorkingDirectory ) ;
59+ runtimeLazy = new Lazy < Runtime > ( ( ) => new Runtime ( dotnet ) ) ;
5660 }
5761 catch
5862 {
@@ -80,7 +84,6 @@ public DependencyManager(string srcDir, IDependencyOptions options, ILogger logg
8084
8185 if ( options . UseNuGet )
8286 {
83- dllDirNames . Add ( packageDirectory . DirInfo . FullName ) ;
8487 try
8588 {
8689 var nuget = new NugetPackages ( sourceDir . FullName , packageDirectory , progressMonitor ) ;
@@ -91,37 +94,27 @@ public DependencyManager(string srcDir, IDependencyOptions options, ILogger logg
9194 progressMonitor . MissingNuGet ( ) ;
9295 }
9396
94- var restoredProjects = RestoreSolutions ( solutions ) ;
97+ var restoredProjects = RestoreSolutions ( solutions , out var assets1 ) ;
9598 var projects = allProjects . Except ( restoredProjects ) ;
96- RestoreProjects ( projects ) ;
99+ RestoreProjects ( projects , out var assets2 ) ;
100+
101+ var dependencies = Assets . GetCompilationDependencies ( progressMonitor , assets1 . Union ( assets2 ) ) ;
102+
103+ var paths = dependencies
104+ . Select ( d => Path . Combine ( packageDirectory . DirInfo . FullName , d ) )
105+ . ToList ( ) ;
106+
107+ // TODO: Rename the dllDirNames var - it's not only dirs anymore.
108+ dllDirNames . AddRange ( paths ) ;
97109 DownloadMissingPackages ( allNonBinaryFiles ) ;
98110 }
99111
100- var existsNetCoreRefNugetPackage = false ;
101- var existsNetFrameworkRefNugetPackage = false ;
102- var existsNetstandardLibRefNugetPackage = false ;
103- var existsNetstandardLibNugetPackage = false ;
104-
105112 // Find DLLs in the .Net / Asp.Net Framework
106113 // This block needs to come after the nuget restore, because the nuget restore might fetch the .NET Core/Framework reference assemblies.
107114 if ( options . ScanNetFrameworkDlls )
108115 {
109- existsNetCoreRefNugetPackage = IsNugetPackageAvailable ( "microsoft.netcore.app.ref" ) ;
110- existsNetFrameworkRefNugetPackage = IsNugetPackageAvailable ( "microsoft.netframework.referenceassemblies" ) ;
111- existsNetstandardLibRefNugetPackage = IsNugetPackageAvailable ( "netstandard.library.ref" ) ;
112- existsNetstandardLibNugetPackage = IsNugetPackageAvailable ( "netstandard.library" ) ;
113-
114- if ( existsNetCoreRefNugetPackage
115- || existsNetFrameworkRefNugetPackage
116- || existsNetstandardLibRefNugetPackage
117- || existsNetstandardLibNugetPackage )
118- {
119- progressMonitor . LogInfo ( "Found .NET Core/Framework DLLs in NuGet packages. Not adding installation directory." ) ;
120- }
121- else
122- {
123- AddNetFrameworkDlls ( dllDirNames ) ;
124- }
116+ AddNetFrameworkDlls ( dllDirNames ) ;
117+ AddAspNetFrameworkDlls ( dllDirNames ) ;
125118 }
126119
127120 assemblyCache = new AssemblyCache ( dllDirNames , progressMonitor ) ;
@@ -132,7 +125,7 @@ public DependencyManager(string srcDir, IDependencyOptions options, ILogger logg
132125 UseReference ( filename ) ;
133126 }
134127
135- RemoveUnnecessaryNugetPackages ( existsNetCoreRefNugetPackage , existsNetFrameworkRefNugetPackage , existsNetstandardLibRefNugetPackage , existsNetstandardLibNugetPackage ) ;
128+ RemoveUnnecessaryNugetPackages ( ) ;
136129 ResolveConflicts ( ) ;
137130
138131 // Output the findings
@@ -167,8 +160,7 @@ public DependencyManager(string srcDir, IDependencyOptions options, ILogger logg
167160 DateTime . Now - startTime ) ;
168161 }
169162
170- private void RemoveUnnecessaryNugetPackages ( bool existsNetCoreRefNugetPackage , bool existsNetFrameworkRefNugetPackage ,
171- bool existsNetstandardLibRefNugetPackage , bool existsNetstandardLibNugetPackage )
163+ private void RemoveUnnecessaryNugetPackages ( )
172164 {
173165 RemoveNugetAnalyzerReferences ( ) ;
174166 RemoveRuntimeNugetPackageReferences ( ) ;
@@ -180,40 +172,6 @@ private void RemoveUnnecessaryNugetPackages(bool existsNetCoreRefNugetPackage, b
180172 RemoveNugetPackageReference ( "microsoft.aspnetcore.app.ref" ) ;
181173 }
182174
183- // Multiple dotnet framework packages could be present. We keep only one.
184- // The order of the packages is important, we're keeping the first one that is present in the nuget cache.
185- var packagesInPrioOrder = new ( bool isPresent , string prefix ) [ ]
186- {
187- // net7.0, ... net5.0, netcoreapp3.1, netcoreapp3.0
188- ( existsNetCoreRefNugetPackage , "microsoft.netcore.app.ref" ) ,
189- // net48, ..., net20
190- ( existsNetFrameworkRefNugetPackage , "microsoft.netframework.referenceassemblies." ) ,
191- // netstandard2.1
192- ( existsNetstandardLibRefNugetPackage , "netstandard.library.ref" ) ,
193- // netstandard2.0
194- ( existsNetstandardLibNugetPackage , "netstandard.library" )
195- } ;
196-
197- for ( var i = 0 ; i < packagesInPrioOrder . Length ; i ++ )
198- {
199- var ( isPresent , _) = packagesInPrioOrder [ i ] ;
200- if ( ! isPresent )
201- {
202- continue ;
203- }
204-
205- // Package is present, remove all the lower priority packages:
206- for ( var j = i + 1 ; j < packagesInPrioOrder . Length ; j ++ )
207- {
208- var ( otherIsPresent , otherPrefix ) = packagesInPrioOrder [ j ] ;
209- if ( otherIsPresent )
210- {
211- RemoveNugetPackageReference ( otherPrefix ) ;
212- }
213- }
214- break ;
215- }
216-
217175 // TODO: There could be multiple `microsoft.netframework.referenceassemblies` packages,
218176 // we could keep the newest one, but this is covered by the conflict resolution logic
219177 // (if the file names match)
@@ -258,35 +216,68 @@ private void RemoveNugetAnalyzerReferences()
258216 }
259217 }
260218 }
219+
261220 private void AddNetFrameworkDlls ( List < string > dllDirNames )
262221 {
263- var runtime = new Runtime ( dotnet ) ;
222+ // Multiple dotnet framework packages could be present.
223+ // The order of the packages is important, we're adding the first one that is present in the nuget cache.
224+ var packagesInPrioOrder = new string [ ]
225+ {
226+ "microsoft.netcore.app.ref" , // net7.0, ... net5.0, netcoreapp3.1, netcoreapp3.0
227+ "microsoft.netframework.referenceassemblies." , // net48, ..., net20
228+ "netstandard.library.ref" , // netstandard2.1
229+ "netstandard.library" // netstandard2.0
230+ } ;
231+
232+ var frameworkPath = packagesInPrioOrder
233+ . Select ( GetPackageDirectory )
234+ . FirstOrDefault ( dir => dir is not null ) ;
235+
236+ if ( frameworkPath is not null )
237+ {
238+ dllDirNames . Add ( frameworkPath ) ;
239+ progressMonitor . LogInfo ( "Found .NET Core/Framework DLLs in NuGet packages. Not adding installation directory." ) ;
240+ return ;
241+ }
242+
264243 string ? runtimeLocation = null ;
265244
266245 if ( options . UseSelfContainedDotnet )
267246 {
268- runtimeLocation = runtime . ExecutingRuntime ;
247+ runtimeLocation = Runtime . ExecutingRuntime ;
269248 }
270249 else if ( fileContent . IsNewProjectStructureUsed )
271250 {
272- runtimeLocation = runtime . NetCoreRuntime ;
251+ runtimeLocation = Runtime . NetCoreRuntime ;
273252 }
274253 else if ( fileContent . IsLegacyProjectStructureUsed )
275254 {
276- runtimeLocation = runtime . DesktopRuntime ;
255+ runtimeLocation = Runtime . DesktopRuntime ;
277256 }
278257
279- runtimeLocation ??= runtime . ExecutingRuntime ;
258+ runtimeLocation ??= Runtime . ExecutingRuntime ;
280259
281260 progressMonitor . LogInfo ( $ ".NET runtime location selected: { runtimeLocation } ") ;
282261 dllDirNames . Add ( runtimeLocation ) ;
262+ }
283263
284- if ( fileContent . IsNewProjectStructureUsed
285- && fileContent . UseAspNetCoreDlls
286- && runtime . AspNetCoreRuntime is string aspRuntime )
264+ private void AddAspNetFrameworkDlls ( List < string > dllDirNames )
265+ {
266+ if ( ! fileContent . IsNewProjectStructureUsed || ! fileContent . UseAspNetCoreDlls )
267+ {
268+ return ;
269+ }
270+
271+ // First try to find ASP.NET assemblies in the NuGet packages
272+ if ( GetPackageDirectory ( "microsoft.aspnetcore.app.ref" ) is string aspNetCorePackage )
273+ {
274+ progressMonitor . LogInfo ( $ "Found ASP.NET Core in NuGet packages. Not adding installation directory.") ;
275+ dllDirNames . Add ( aspNetCorePackage ) ;
276+ }
277+ else if ( Runtime . AspNetCoreRuntime is string aspNetCoreRuntime )
287278 {
288- progressMonitor . LogInfo ( $ "ASP.NET runtime location selected: { aspRuntime } ") ;
289- dllDirNames . Add ( aspRuntime ) ;
279+ progressMonitor . LogInfo ( $ "ASP.NET runtime location selected: { aspNetCoreRuntime } ") ;
280+ dllDirNames . Add ( aspNetCoreRuntime ) ;
290281 }
291282 }
292283
@@ -336,16 +327,17 @@ private void RemoveNugetPackageReference(params string[] packagePrefixes)
336327 }
337328 }
338329
339- private bool IsNugetPackageAvailable ( string packagePrefix )
330+ private string ? GetPackageDirectory ( string packagePrefix )
340331 {
341332 if ( ! options . UseNuGet )
342333 {
343- return false ;
334+ return null ;
344335 }
345336
346337 return new DirectoryInfo ( packageDirectory . DirInfo . FullName )
347338 . EnumerateDirectories ( packagePrefix + "*" , new EnumerationOptions { MatchCasing = MatchCasing . CaseInsensitive , RecurseSubdirectories = false } )
348- . Any ( ) ;
339+ . FirstOrDefault ( ) ?
340+ . FullName ;
349341 }
350342
351343 private void GenerateSourceFileFromImplicitUsings ( )
@@ -634,27 +626,38 @@ private bool RestoreSolution(string solution, out IEnumerable<string> projects,
634626 /// As opposed to RestoreProjects this is not run in parallel using PLINQ
635627 /// as `dotnet restore` on a solution already uses multiple threads for restoring
636628 /// the projects (this can be disabled with the `--disable-parallel` flag).
629+ /// Populates assets with the relative paths to the assets files generated by the restore.
637630 /// Returns a list of projects that are up to date with respect to restore.
638631 /// </summary>
639632 /// <param name="solutions">A list of paths to solution files.</param>
640- private IEnumerable < string > RestoreSolutions ( IEnumerable < string > solutions ) =>
641- solutions . SelectMany ( solution =>
633+ private IEnumerable < string > RestoreSolutions ( IEnumerable < string > solutions , out IEnumerable < string > assets )
634+ {
635+ var assetFiles = new List < string > ( ) ;
636+ var projects = solutions . SelectMany ( solution =>
642637 {
643- RestoreSolution ( solution , out var restoredProjects , out var assets ) ;
638+ RestoreSolution ( solution , out var restoredProjects , out var a ) ;
639+ assetFiles . AddRange ( a ) ;
644640 return restoredProjects ;
645641 } ) ;
642+ assets = assetFiles ;
643+ return projects ;
644+ }
646645
647646 /// <summary>
648647 /// Executes `dotnet restore` on all projects in projects.
649648 /// This is done in parallel for performance reasons.
649+ /// Populates assets with the relative paths to the assets files generated by the restore.
650650 /// </summary>
651651 /// <param name="projects">A list of paths to project files.</param>
652- private void RestoreProjects ( IEnumerable < string > projects )
652+ private void RestoreProjects ( IEnumerable < string > projects , out IEnumerable < string > assets )
653653 {
654+ var assetFiles = new List < string > ( ) ;
654655 Parallel . ForEach ( projects , new ParallelOptions { MaxDegreeOfParallelism = options . Threads } , project =>
655656 {
656- RestoreProject ( project , forceDotnetRefAssemblyFetching : true , out var assets ) ;
657+ RestoreProject ( project , forceDotnetRefAssemblyFetching : true , out var a ) ;
658+ assetFiles . AddRange ( a ) ;
657659 } ) ;
660+ assets = assetFiles ;
658661 }
659662
660663 private void DownloadMissingPackages ( List < FileInfo > allFiles )
0 commit comments