55using System . Linq ;
66using System . Security . Cryptography ;
77using System . Text ;
8+ using System . Text . RegularExpressions ;
89using System . Threading . Tasks ;
910using Semmle . Util ;
1011using Semmle . Util . Logging ;
@@ -14,7 +15,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
1415 /// <summary>
1516 /// Main implementation of the build analysis.
1617 /// </summary>
17- public sealed class DependencyManager : IDisposable
18+ public sealed partial class DependencyManager : IDisposable
1819 {
1920 private readonly AssemblyCache assemblyCache ;
2021 private readonly ILogger logger ;
@@ -783,13 +784,53 @@ private void RestoreProjects(IEnumerable<string> projects, out IEnumerable<strin
783784 CompilationInfos . Add ( ( "Successfully restored project files" , successCount . ToString ( ) ) ) ;
784785 }
785786
786- private void DownloadMissingPackages ( List < FileInfo > allFiles , ISet < string > dllPaths )
787+ [ GeneratedRegex ( @"^(.+)\.(\d+\.\d+\.\d+(-(.+))?)$" , RegexOptions . IgnoreCase | RegexOptions . Compiled | RegexOptions . Singleline ) ]
788+ private static partial Regex LegacyNugetPackage ( ) ;
789+
790+
791+ private static IEnumerable < string > GetRestoredPackageDirectoryNames ( DirectoryInfo root )
787792 {
788- var alreadyDownloadedPackages = Directory . GetDirectories ( packageDirectory . DirInfo . FullName )
793+ return Directory . GetDirectories ( root . FullName )
789794 . Select ( d => Path . GetFileName ( d ) . ToLowerInvariant ( ) ) ;
790- var notYetDownloadedPackages = fileContent . AllPackages
791- . Except ( alreadyDownloadedPackages )
792- . ToList ( ) ;
795+ }
796+
797+ private IEnumerable < string > GetRestoredLegacyPackageNames ( )
798+ {
799+ var oldPackageDirectories = GetRestoredPackageDirectoryNames ( legacyPackageDirectory . DirInfo ) ;
800+ foreach ( var oldPackageDirectory in oldPackageDirectories )
801+ {
802+ // nuget install restores packages to 'packagename.version' folders (dotnet restore to 'packagename/version' folders)
803+ // typical folder names look like:
804+ // newtonsoft.json.13.0.3
805+ // there are more complex ones too, such as:
806+ // runtime.tizen.4.0.0-armel.Microsoft.NETCore.DotNetHostResolver.2.0.0-preview2-25407-01
807+
808+ var match = LegacyNugetPackage ( ) . Match ( oldPackageDirectory ) ;
809+ if ( ! match . Success )
810+ {
811+ logger . LogWarning ( $ "Package directory '{ oldPackageDirectory } ' doesn't match the expected pattern.") ;
812+ continue ;
813+ }
814+
815+ yield return match . Groups [ 1 ] . Value . ToLowerInvariant ( ) ;
816+ }
817+ }
818+
819+ private void DownloadMissingPackages ( List < FileInfo > allFiles , ISet < string > dllPaths )
820+ {
821+ var alreadyDownloadedPackages = GetRestoredPackageDirectoryNames ( packageDirectory . DirInfo ) ;
822+ var alreadyDownloadedLegacyPackages = GetRestoredLegacyPackageNames ( ) ;
823+
824+ var notYetDownloadedPackages = new HashSet < string > ( fileContent . AllPackages ) ;
825+ foreach ( var alreadyDownloadedPackage in alreadyDownloadedPackages )
826+ {
827+ notYetDownloadedPackages . Remove ( alreadyDownloadedPackage ) ;
828+ }
829+ foreach ( var alreadyDownloadedLegacyPackage in alreadyDownloadedLegacyPackages )
830+ {
831+ notYetDownloadedPackages . Remove ( alreadyDownloadedLegacyPackage ) ;
832+ }
833+
793834 if ( notYetDownloadedPackages . Count == 0 )
794835 {
795836 return ;
0 commit comments