@@ -47,9 +47,12 @@ public DependencyManager(string srcDir, IDependencyOptions options, ILogger logg
4747 this . progressMonitor = new ProgressMonitor ( logger ) ;
4848 this . sourceDir = new DirectoryInfo ( srcDir ) ;
4949
50+ packageDirectory = new TemporaryDirectory ( ComputeTempDirectory ( sourceDir . FullName ) ) ;
51+ tempWorkingDirectory = new TemporaryDirectory ( FileUtils . GetTemporaryWorkingDirectory ( out cleanupTempWorkingDirectory ) ) ;
52+
5053 try
5154 {
52- this . dotnet = DotNet . Make ( options , progressMonitor ) ;
55+ this . dotnet = DotNet . Make ( options , progressMonitor , tempWorkingDirectory ) ;
5356 }
5457 catch
5558 {
@@ -59,8 +62,6 @@ public DependencyManager(string srcDir, IDependencyOptions options, ILogger logg
5962
6063 this . progressMonitor . FindingFiles ( srcDir ) ;
6164
62- packageDirectory = new TemporaryDirectory ( ComputeTempDirectory ( sourceDir . FullName ) ) ;
63- tempWorkingDirectory = new TemporaryDirectory ( FileUtils . GetTemporaryWorkingDirectory ( out cleanupTempWorkingDirectory ) ) ;
6465
6566 var allFiles = GetAllFiles ( ) ;
6667 var binaryFileExtensions = new HashSet < string > ( new [ ] { ".dll" , ".exe" } ) ; // TODO: add more binary file extensions.
@@ -77,21 +78,6 @@ public DependencyManager(string srcDir, IDependencyOptions options, ILogger logg
7778 ? allFiles . SelectFileNamesByExtension ( ".dll" ) . ToList ( )
7879 : options . DllDirs . Select ( Path . GetFullPath ) . ToList ( ) ;
7980
80- // Find DLLs in the .Net / Asp.Net Framework
81- if ( options . ScanNetFrameworkDlls )
82- {
83- var runtime = new Runtime ( dotnet ) ;
84- var runtimeLocation = runtime . GetRuntime ( options . UseSelfContainedDotnet ) ;
85- progressMonitor . LogInfo ( $ ".NET runtime location selected: { runtimeLocation } ") ;
86- dllDirNames . Add ( runtimeLocation ) ;
87-
88- if ( fileContent . UseAspNetDlls && runtime . GetAspRuntime ( ) is string aspRuntime )
89- {
90- progressMonitor . LogInfo ( $ "ASP.NET runtime location selected: { aspRuntime } ") ;
91- dllDirNames . Add ( aspRuntime ) ;
92- }
93- }
94-
9581 if ( options . UseNuGet )
9682 {
9783 dllDirNames . Add ( packageDirectory . DirInfo . FullName ) ;
@@ -111,6 +97,26 @@ public DependencyManager(string srcDir, IDependencyOptions options, ILogger logg
11197 DownloadMissingPackages ( allNonBinaryFiles ) ;
11298 }
11399
100+ var existsNetCoreRefNugetPackage = false ;
101+ var existsNetFrameworkRefNugetPackage = false ;
102+
103+ // Find DLLs in the .Net / Asp.Net Framework
104+ // This block needs to come after the nuget restore, because the nuget restore might fetch the .NET Core/Framework reference assemblies.
105+ if ( options . ScanNetFrameworkDlls )
106+ {
107+ existsNetCoreRefNugetPackage = IsNugetPackageAvailable ( "microsoft.netcore.app.ref" ) ;
108+ existsNetFrameworkRefNugetPackage = IsNugetPackageAvailable ( "microsoft.netframework.referenceassemblies" ) ;
109+
110+ if ( existsNetCoreRefNugetPackage || existsNetFrameworkRefNugetPackage )
111+ {
112+ progressMonitor . LogInfo ( "Found .NET Core/Framework DLLs in NuGet packages. Not adding installation directory." ) ;
113+ }
114+ else
115+ {
116+ AddNetFrameworkDlls ( dllDirNames ) ;
117+ }
118+ }
119+
114120 assemblyCache = new AssemblyCache ( dllDirNames , progressMonitor ) ;
115121 AnalyseSolutions ( solutions ) ;
116122
@@ -119,7 +125,7 @@ public DependencyManager(string srcDir, IDependencyOptions options, ILogger logg
119125 UseReference ( filename ) ;
120126 }
121127
122- RemoveRuntimeNugetPackageReferences ( ) ;
128+ RemoveUnnecessaryNugetPackages ( existsNetCoreRefNugetPackage , existsNetFrameworkRefNugetPackage ) ;
123129 ResolveConflicts ( ) ;
124130
125131 // Output the findings
@@ -154,38 +160,158 @@ public DependencyManager(string srcDir, IDependencyOptions options, ILogger logg
154160 DateTime . Now - startTime ) ;
155161 }
156162
157- private void RemoveRuntimeNugetPackageReferences ( )
163+ private void RemoveUnnecessaryNugetPackages ( bool existsNetCoreRefNugetPackage , bool existsNetFrameworkRefNugetPackage )
164+ {
165+ RemoveNugetAnalyzerReferences ( ) ;
166+ RemoveRuntimeNugetPackageReferences ( ) ;
167+
168+ if ( fileContent . IsNewProjectStructureUsed
169+ && ! fileContent . UseAspNetCoreDlls )
170+ {
171+ // This might have been restored by the CLI even though the project isn't an asp.net core one.
172+ RemoveNugetPackageReference ( "microsoft.aspnetcore.app.ref" ) ;
173+ }
174+
175+ if ( existsNetCoreRefNugetPackage && existsNetFrameworkRefNugetPackage )
176+ {
177+ // Multiple packages are available, we keep only one:
178+ RemoveNugetPackageReference ( "microsoft.netframework.referenceassemblies." ) ;
179+ }
180+
181+ // TODO: There could be multiple `microsoft.netframework.referenceassemblies` packages,
182+ // we could keep the newest one, but this is covered by the conflict resolution logic
183+ // (if the file names match)
184+ }
185+
186+ private void RemoveNugetAnalyzerReferences ( )
158187 {
159188 if ( ! options . UseNuGet )
160189 {
161190 return ;
162191 }
163192
164193 var packageFolder = packageDirectory . DirInfo . FullName . ToLowerInvariant ( ) ;
165- var runtimePackageNamePrefixes = new [ ]
194+ if ( packageFolder == null )
195+ {
196+ return ;
197+ }
198+
199+ foreach ( var filename in usedReferences . Keys )
166200 {
167- Path . Combine ( packageFolder , "microsoft.netcore.app.runtime" ) ,
168- Path . Combine ( packageFolder , "microsoft.aspnetcore.app.runtime" ) ,
169- Path . Combine ( packageFolder , "microsoft.windowsdesktop.app.runtime" ) ,
201+ var lowerFilename = filename . ToLowerInvariant ( ) ;
202+
203+ if ( lowerFilename . StartsWith ( packageFolder ) )
204+ {
205+ var firstDirectorySeparatorCharIndex = lowerFilename . IndexOf ( Path . DirectorySeparatorChar , packageFolder . Length + 1 ) ;
206+ if ( firstDirectorySeparatorCharIndex == - 1 )
207+ {
208+ continue ;
209+ }
210+ var secondDirectorySeparatorCharIndex = lowerFilename . IndexOf ( Path . DirectorySeparatorChar , firstDirectorySeparatorCharIndex + 1 ) ;
211+ if ( secondDirectorySeparatorCharIndex == - 1 )
212+ {
213+ continue ;
214+ }
215+ var subFolderIndex = secondDirectorySeparatorCharIndex + 1 ;
216+ var isInAnalyzersFolder = lowerFilename . IndexOf ( "analyzers" , subFolderIndex ) == subFolderIndex ;
217+ if ( isInAnalyzersFolder )
218+ {
219+ usedReferences . Remove ( filename ) ;
220+ progressMonitor . RemovedReference ( filename ) ;
221+ }
222+ }
223+ }
224+ }
225+ private void AddNetFrameworkDlls ( List < string > dllDirNames )
226+ {
227+ var runtime = new Runtime ( dotnet ) ;
228+ string ? runtimeLocation = null ;
229+
230+ if ( options . UseSelfContainedDotnet )
231+ {
232+ runtimeLocation = runtime . ExecutingRuntime ;
233+ }
234+ else if ( fileContent . IsNewProjectStructureUsed )
235+ {
236+ runtimeLocation = runtime . NetCoreRuntime ;
237+ }
238+ else if ( fileContent . IsLegacyProjectStructureUsed )
239+ {
240+ runtimeLocation = runtime . DesktopRuntime ;
241+ }
242+
243+ runtimeLocation ??= runtime . ExecutingRuntime ;
244+
245+ progressMonitor . LogInfo ( $ ".NET runtime location selected: { runtimeLocation } ") ;
246+ dllDirNames . Add ( runtimeLocation ) ;
247+
248+ if ( fileContent . IsNewProjectStructureUsed
249+ && fileContent . UseAspNetCoreDlls
250+ && runtime . AspNetCoreRuntime is string aspRuntime )
251+ {
252+ progressMonitor . LogInfo ( $ "ASP.NET runtime location selected: { aspRuntime } ") ;
253+ dllDirNames . Add ( aspRuntime ) ;
254+ }
255+ }
256+
257+ private void RemoveRuntimeNugetPackageReferences ( )
258+ {
259+ var runtimePackagePrefixes = new [ ]
260+ {
261+ "microsoft.netcore.app.runtime" ,
262+ "microsoft.aspnetcore.app.runtime" ,
263+ "microsoft.windowsdesktop.app.runtime" ,
170264
171265 // legacy runtime packages:
172- Path . Combine ( packageFolder , "runtime.linux-x64.microsoft.netcore.app" ) ,
173- Path . Combine ( packageFolder , "runtime.osx-x64.microsoft.netcore.app" ) ,
174- Path . Combine ( packageFolder , "runtime.win-x64.microsoft.netcore.app" ) ,
266+ "runtime.linux-x64.microsoft.netcore.app" ,
267+ "runtime.osx-x64.microsoft.netcore.app" ,
268+ "runtime.win-x64.microsoft.netcore.app" ,
269+
270+ // Internal implementation packages not meant for direct consumption:
271+ "runtime."
175272 } ;
273+ RemoveNugetPackageReference ( runtimePackagePrefixes ) ;
274+ }
275+
276+ private void RemoveNugetPackageReference ( params string [ ] packagePrefixes )
277+ {
278+ if ( ! options . UseNuGet )
279+ {
280+ return ;
281+ }
282+
283+ var packageFolder = packageDirectory . DirInfo . FullName . ToLowerInvariant ( ) ;
284+ if ( packageFolder == null )
285+ {
286+ return ;
287+ }
288+
289+ var packagePathPrefixes = packagePrefixes . Select ( p => Path . Combine ( packageFolder , p . ToLowerInvariant ( ) ) ) ;
176290
177291 foreach ( var filename in usedReferences . Keys )
178292 {
179293 var lowerFilename = filename . ToLowerInvariant ( ) ;
180294
181- if ( runtimePackageNamePrefixes . Any ( prefix => lowerFilename . StartsWith ( prefix ) ) )
295+ if ( packagePathPrefixes . Any ( prefix => lowerFilename . StartsWith ( prefix ) ) )
182296 {
183297 usedReferences . Remove ( filename ) ;
184298 progressMonitor . RemovedReference ( filename ) ;
185299 }
186300 }
187301 }
188302
303+ private bool IsNugetPackageAvailable ( string packagePrefix )
304+ {
305+ if ( ! options . UseNuGet )
306+ {
307+ return false ;
308+ }
309+
310+ return new DirectoryInfo ( packageDirectory . DirInfo . FullName )
311+ . EnumerateDirectories ( packagePrefix + "*" , new EnumerationOptions { MatchCasing = MatchCasing . CaseInsensitive , RecurseSubdirectories = false } )
312+ . Any ( ) ;
313+ }
314+
189315 private void GenerateSourceFileFromImplicitUsings ( )
190316 {
191317 var usings = new HashSet < string > ( ) ;
@@ -198,7 +324,7 @@ private void GenerateSourceFileFromImplicitUsings()
198324 usings . UnionWith ( new [ ] { "System" , "System.Collections.Generic" , "System.IO" , "System.Linq" , "System.Net.Http" , "System.Threading" ,
199325 "System.Threading.Tasks" } ) ;
200326
201- if ( fileContent . UseAspNetDlls )
327+ if ( fileContent . UseAspNetCoreDlls )
202328 {
203329 usings . UnionWith ( new [ ] { "System.Net.Http.Json" , "Microsoft.AspNetCore.Builder" , "Microsoft.AspNetCore.Hosting" ,
204330 "Microsoft.AspNetCore.Http" , "Microsoft.AspNetCore.Routing" , "Microsoft.Extensions.Configuration" ,
@@ -461,11 +587,11 @@ private void AnalyseProject(FileInfo project)
461587
462588 }
463589
464- private bool RestoreProject ( string project , string ? pathToNugetConfig = null ) =>
465- dotnet . RestoreProjectToDirectory ( project , packageDirectory . DirInfo . FullName , pathToNugetConfig ) ;
590+ private bool RestoreProject ( string project , bool forceDotnetRefAssemblyFetching , string ? pathToNugetConfig = null ) =>
591+ dotnet . RestoreProjectToDirectory ( project , packageDirectory . DirInfo . FullName , forceDotnetRefAssemblyFetching , pathToNugetConfig ) ;
466592
467593 private bool RestoreSolution ( string solution , out IEnumerable < string > projects ) =>
468- dotnet . RestoreSolutionToDirectory ( solution , packageDirectory . DirInfo . FullName , out projects ) ;
594+ dotnet . RestoreSolutionToDirectory ( solution , packageDirectory . DirInfo . FullName , forceDotnetRefAssemblyFetching : true , out projects ) ;
469595
470596 /// <summary>
471597 /// Executes `dotnet restore` on all solution files in solutions.
@@ -491,7 +617,7 @@ private void RestoreProjects(IEnumerable<string> projects)
491617 {
492618 Parallel . ForEach ( projects , new ParallelOptions { MaxDegreeOfParallelism = options . Threads } , project =>
493619 {
494- RestoreProject ( project ) ;
620+ RestoreProject ( project , forceDotnetRefAssemblyFetching : true ) ;
495621 } ) ;
496622 }
497623
@@ -536,7 +662,7 @@ private void DownloadMissingPackages(List<FileInfo> allFiles)
536662 return ;
537663 }
538664
539- success = RestoreProject ( tempDir . DirInfo . FullName , nugetConfig ) ;
665+ success = RestoreProject ( tempDir . DirInfo . FullName , forceDotnetRefAssemblyFetching : false , pathToNugetConfig : nugetConfig ) ;
540666 // TODO: the restore might fail, we could retry with a prerelease (*-* instead of *) version of the package.
541667 if ( ! success )
542668 {
@@ -564,9 +690,25 @@ private void AnalyseSolutions(IEnumerable<string> solutions)
564690
565691 public void Dispose ( )
566692 {
567- packageDirectory ? . Dispose ( ) ;
693+ try
694+ {
695+ packageDirectory ? . Dispose ( ) ;
696+ }
697+ catch ( Exception exc )
698+ {
699+ progressMonitor . LogInfo ( "Couldn't delete package directory: " + exc . Message ) ;
700+ }
568701 if ( cleanupTempWorkingDirectory )
569- tempWorkingDirectory ? . Dispose ( ) ;
702+ {
703+ try
704+ {
705+ tempWorkingDirectory ? . Dispose ( ) ;
706+ }
707+ catch ( Exception exc )
708+ {
709+ progressMonitor . LogInfo ( "Couldn't delete temporary working directory: " + exc . Message ) ;
710+ }
711+ }
570712 }
571713 }
572714}
0 commit comments