@@ -48,16 +48,48 @@ public NugetPackageRestorer(
48
48
missingPackageDirectory = new TemporaryDirectory ( ComputeTempDirectoryPath ( fileProvider . SourceDir . FullName , "missingpackages" ) , "missing package" , logger ) ;
49
49
}
50
50
51
- public string ? TryRestoreLatestNetFrameworkReferenceAssemblies ( )
51
+ public string ? TryRestore ( string package )
52
52
{
53
- if ( TryRestorePackageManually ( FrameworkPackageNames . LatestNetFrameworkReferenceAssemblies ) )
53
+ if ( TryRestorePackageManually ( package ) )
54
54
{
55
- return DependencyManager . GetPackageDirectory ( FrameworkPackageNames . LatestNetFrameworkReferenceAssemblies , missingPackageDirectory . DirInfo ) ;
55
+ var packageDir = DependencyManager . GetPackageDirectory ( package , missingPackageDirectory . DirInfo ) ;
56
+ if ( packageDir is not null )
57
+ {
58
+ return GetNewestNugetPackageVersionFolder ( packageDir , package ) ;
59
+ }
56
60
}
57
61
58
62
return null ;
59
63
}
60
64
65
+ public string GetNewestNugetPackageVersionFolder ( string packagePath , string packageFriendlyName )
66
+ {
67
+ var versionFolders = GetOrderedPackageVersionSubDirectories ( packagePath ) ;
68
+ if ( versionFolders . Length > 1 )
69
+ {
70
+ var versions = string . Join ( ", " , versionFolders . Select ( d => d . Name ) ) ;
71
+ logger . LogDebug ( $ "Found multiple { packageFriendlyName } DLLs in NuGet packages at { packagePath } . Using the latest version ({ versionFolders [ 0 ] . Name } ) from: { versions } .") ;
72
+ }
73
+
74
+ var selectedFrameworkFolder = versionFolders . FirstOrDefault ( ) ? . FullName ;
75
+ if ( selectedFrameworkFolder is null )
76
+ {
77
+ logger . LogDebug ( $ "Found { packageFriendlyName } DLLs in NuGet packages at { packagePath } , but no version folder was found.") ;
78
+ selectedFrameworkFolder = packagePath ;
79
+ }
80
+
81
+ logger . LogDebug ( $ "Found { packageFriendlyName } DLLs in NuGet packages at { selectedFrameworkFolder } .") ;
82
+ return selectedFrameworkFolder ;
83
+ }
84
+
85
+ public static DirectoryInfo [ ] GetOrderedPackageVersionSubDirectories ( string packagePath )
86
+ {
87
+ return new DirectoryInfo ( packagePath )
88
+ . EnumerateDirectories ( "*" , new EnumerationOptions { MatchCasing = MatchCasing . CaseInsensitive , RecurseSubdirectories = false } )
89
+ . OrderByDescending ( d => d . Name ) // TODO: Improve sorting to handle pre-release versions.
90
+ . ToArray ( ) ;
91
+ }
92
+
61
93
public HashSet < AssemblyLookupLocation > Restore ( )
62
94
{
63
95
var assemblyLookupLocations = new HashSet < AssemblyLookupLocation > ( ) ;
@@ -408,7 +440,8 @@ private static IEnumerable<string> GetRestoredPackageDirectoryNames(DirectoryInf
408
440
. Select ( d => Path . GetFileName ( d ) . ToLowerInvariant ( ) ) ;
409
441
}
410
442
411
- private bool TryRestorePackageManually ( string package , string ? nugetConfig = null , PackageReferenceSource packageReferenceSource = PackageReferenceSource . SdkCsProj , bool tryWithoutNugetConfig = true )
443
+ private bool TryRestorePackageManually ( string package , string ? nugetConfig = null , PackageReferenceSource packageReferenceSource = PackageReferenceSource . SdkCsProj ,
444
+ bool tryWithoutNugetConfig = true , bool tryPrereleaseVersion = true )
412
445
{
413
446
logger . LogInfo ( $ "Restoring package { package } ...") ;
414
447
using var tempDir = new TemporaryDirectory (
@@ -430,59 +463,87 @@ private bool TryRestorePackageManually(string package, string? nugetConfig = nul
430
463
return false ;
431
464
}
432
465
433
- var res = dotnet . Restore ( new ( tempDir . DirInfo . FullName , missingPackageDirectory . DirInfo . FullName , ForceDotnetRefAssemblyFetching : false , PathToNugetConfig : nugetConfig ) ) ;
434
- if ( ! res . Success )
466
+ var res = TryRestorePackageManually ( package , nugetConfig , tempDir , tryPrereleaseVersion ) ;
467
+ if ( res . Success )
468
+ {
469
+ return true ;
470
+ }
471
+
472
+ if ( tryWithoutNugetConfig && res . HasNugetPackageSourceError && nugetConfig is not null )
435
473
{
436
- if ( tryWithoutNugetConfig && res . HasNugetPackageSourceError && nugetConfig is not null )
474
+ logger . LogDebug ( $ "Trying to restore '{ package } ' without nuget.config.") ;
475
+ // Restore could not be completed because the listed source is unavailable. Try without the nuget.config:
476
+ res = TryRestorePackageManually ( package , nugetConfig : null , tempDir , tryPrereleaseVersion ) ;
477
+ if ( res . Success )
437
478
{
438
- // Restore could not be completed because the listed source is unavailable. Try without the nuget.config:
439
- res = dotnet . Restore ( new ( tempDir . DirInfo . FullName , missingPackageDirectory . DirInfo . FullName , ForceDotnetRefAssemblyFetching : false , PathToNugetConfig : null , ForceReevaluation : true ) ) ;
479
+ return true ;
440
480
}
481
+ }
441
482
442
- // TODO: the restore might fail, we could retry with
443
- // - a prerelease (*-* instead of *) version of the package,
444
- // - a different target framework moniker.
483
+ logger . LogInfo ( $ "Failed to restore nuget package { package } ") ;
484
+ return false ;
485
+ }
486
+
487
+ private RestoreResult TryRestorePackageManually ( string package , string ? nugetConfig , TemporaryDirectory tempDir , bool tryPrereleaseVersion )
488
+ {
489
+ var res = dotnet . Restore ( new ( tempDir . DirInfo . FullName , missingPackageDirectory . DirInfo . FullName , ForceDotnetRefAssemblyFetching : false , PathToNugetConfig : nugetConfig , ForceReevaluation : true ) ) ;
490
+
491
+ if ( ! res . Success && tryPrereleaseVersion && res . HasNugetNoStablePackageVersionError )
492
+ {
493
+ logger . LogDebug ( $ "Failed to restore nuget package { package } because no stable version was found.") ;
494
+ TryChangePackageVersion ( tempDir . DirInfo , "*-*" ) ;
445
495
496
+ res = dotnet . Restore ( new ( tempDir . DirInfo . FullName , missingPackageDirectory . DirInfo . FullName , ForceDotnetRefAssemblyFetching : false , PathToNugetConfig : nugetConfig , ForceReevaluation : true ) ) ;
446
497
if ( ! res . Success )
447
498
{
448
- logger . LogInfo ( $ "Failed to restore nuget package { package } ") ;
449
- return false ;
499
+ TryChangePackageVersion ( tempDir . DirInfo , "*" ) ;
450
500
}
451
501
}
452
502
453
- return true ;
503
+ return res ;
454
504
}
455
505
456
506
private void TryChangeTargetFrameworkMoniker ( DirectoryInfo tempDir )
507
+ {
508
+ TryChangeProjectFile ( tempDir , TargetFramework ( ) , $ "<TargetFramework>{ FrameworkPackageNames . LatestNetFrameworkMoniker } </TargetFramework>", "target framework moniker" ) ;
509
+ }
510
+
511
+ private void TryChangePackageVersion ( DirectoryInfo tempDir , string newVersion )
512
+ {
513
+ TryChangeProjectFile ( tempDir , PackageReferenceVersion ( ) , $ "Version=\" { newVersion } \" ", "package reference version" ) ;
514
+ }
515
+
516
+ private bool TryChangeProjectFile ( DirectoryInfo projectDir , Regex pattern , string replacement , string patternName )
457
517
{
458
518
try
459
519
{
460
- logger . LogInfo ( $ "Changing the target framework moniker in { tempDir . FullName } ...") ;
520
+ logger . LogDebug ( $ "Changing the { patternName } in { projectDir . FullName } ...") ;
461
521
462
- var csprojs = tempDir . GetFiles ( "*.csproj" , new EnumerationOptions { RecurseSubdirectories = false , MatchCasing = MatchCasing . CaseInsensitive } ) ;
522
+ var csprojs = projectDir . GetFiles ( "*.csproj" , new EnumerationOptions { RecurseSubdirectories = false , MatchCasing = MatchCasing . CaseInsensitive } ) ;
463
523
if ( csprojs . Length != 1 )
464
524
{
465
- logger . LogError ( $ "Could not find the .csproj file in { tempDir . FullName } , count = { csprojs . Length } ") ;
466
- return ;
525
+ logger . LogError ( $ "Could not find the .csproj file in { projectDir . FullName } , count = { csprojs . Length } ") ;
526
+ return false ;
467
527
}
468
528
469
529
var csproj = csprojs [ 0 ] ;
470
530
var content = File . ReadAllText ( csproj . FullName ) ;
471
- var matches = TargetFramework ( ) . Matches ( content ) ;
531
+ var matches = pattern . Matches ( content ) ;
472
532
if ( matches . Count == 0 )
473
533
{
474
- logger . LogError ( $ "Could not find target framework in { csproj . FullName } ") ;
475
- }
476
- else
477
- {
478
- content = TargetFramework ( ) . Replace ( content , $ "<TargetFramework>{ FrameworkPackageNames . LatestNetFrameworkMoniker } </TargetFramework>", 1 ) ;
479
- File . WriteAllText ( csproj . FullName , content ) ;
534
+ logger . LogError ( $ "Could not find the { patternName } in { csproj . FullName } ") ;
535
+ return false ;
480
536
}
537
+
538
+ content = pattern . Replace ( content , replacement , 1 ) ;
539
+ File . WriteAllText ( csproj . FullName , content ) ;
540
+ return true ;
481
541
}
482
542
catch ( Exception exc )
483
543
{
484
- logger . LogError ( $ "Failed to update target framework in { tempDir . FullName } : { exc } ") ;
544
+ logger . LogError ( $ "Failed to change the { patternName } in { projectDir . FullName } : { exc } ") ;
485
545
}
546
+ return false ;
486
547
}
487
548
488
549
private static async Task ExecuteGetRequest ( string address , HttpClient httpClient , CancellationToken cancellationToken )
@@ -664,6 +725,9 @@ private IEnumerable<string> GetFeeds(Func<IList<string>> getNugetFeeds)
664
725
[ GeneratedRegex ( @"<TargetFramework>.*</TargetFramework>" , RegexOptions . IgnoreCase | RegexOptions . Compiled | RegexOptions . Singleline ) ]
665
726
private static partial Regex TargetFramework ( ) ;
666
727
728
+ [ GeneratedRegex ( @"Version=""(\*|\*-\*)""" , RegexOptions . IgnoreCase | RegexOptions . Compiled | RegexOptions . Singleline ) ]
729
+ private static partial Regex PackageReferenceVersion ( ) ;
730
+
667
731
[ GeneratedRegex ( @"^(.+)\.(\d+\.\d+\.\d+(-(.+))?)$" , RegexOptions . IgnoreCase | RegexOptions . Compiled | RegexOptions . Singleline ) ]
668
732
private static partial Regex LegacyNugetPackage ( ) ;
669
733
0 commit comments