@@ -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,91 @@ 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 )
435
468
{
436
- if ( tryWithoutNugetConfig && res . HasNugetPackageSourceError && nugetConfig is not null )
469
+ return true ;
470
+ }
471
+
472
+ if ( tryWithoutNugetConfig && res . HasNugetPackageSourceError && nugetConfig is not null )
473
+ {
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
+ }
482
+
483
+ logger . LogInfo ( $ "Failed to restore nuget package { package } ") ;
484
+ return false ;
485
+ }
441
486
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.
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 ) ) ;
445
490
446
- if ( ! res . Success )
491
+ if ( ! res . Success && tryPrereleaseVersion && res . HasNugetNoStablePackageVersionError )
492
+ {
493
+ logger . LogDebug ( $ "Failed to restore nuget package { package } because no stable version was found.") ;
494
+ try
447
495
{
448
- logger . LogInfo ( $ "Failed to restore nuget package { package } ") ;
449
- return false ;
496
+ TryChangePackageVersion ( tempDir . DirInfo , "*-*" ) ;
497
+
498
+ res = dotnet . Restore ( new ( tempDir . DirInfo . FullName , missingPackageDirectory . DirInfo . FullName , ForceDotnetRefAssemblyFetching : false , PathToNugetConfig : nugetConfig , ForceReevaluation : true ) ) ;
499
+ return res ;
500
+ }
501
+ finally
502
+ {
503
+ TryChangePackageVersion ( tempDir . DirInfo , "*" ) ;
450
504
}
451
505
}
452
506
453
- return true ;
507
+ return res ;
454
508
}
455
509
456
510
private void TryChangeTargetFrameworkMoniker ( DirectoryInfo tempDir )
511
+ {
512
+ TryChangeProjectFile ( tempDir , TargetFramework ( ) , $ "<TargetFramework>{ FrameworkPackageNames . LatestNetFrameworkMoniker } </TargetFramework>", "target framework moniker" ) ;
513
+ }
514
+
515
+ private void TryChangePackageVersion ( DirectoryInfo tempDir , string newVersion )
516
+ {
517
+ TryChangeProjectFile ( tempDir , PackageReferenceVersion ( ) , $ "Version=\" { newVersion } \" ", "package reference version" ) ;
518
+ }
519
+
520
+ private bool TryChangeProjectFile ( DirectoryInfo projectDir , Regex pattern , string replacement , string patternName )
457
521
{
458
522
try
459
523
{
460
- logger . LogInfo ( $ "Changing the target framework moniker in { tempDir . FullName } ...") ;
524
+ logger . LogDebug ( $ "Changing the { patternName } in { projectDir . FullName } ...") ;
461
525
462
- var csprojs = tempDir . GetFiles ( "*.csproj" , new EnumerationOptions { RecurseSubdirectories = false , MatchCasing = MatchCasing . CaseInsensitive } ) ;
526
+ var csprojs = projectDir . GetFiles ( "*.csproj" , new EnumerationOptions { RecurseSubdirectories = false , MatchCasing = MatchCasing . CaseInsensitive } ) ;
463
527
if ( csprojs . Length != 1 )
464
528
{
465
- logger . LogError ( $ "Could not find the .csproj file in { tempDir . FullName } , count = { csprojs . Length } ") ;
466
- return ;
529
+ logger . LogError ( $ "Could not find the .csproj file in { projectDir . FullName } , count = { csprojs . Length } ") ;
530
+ return false ;
467
531
}
468
532
469
533
var csproj = csprojs [ 0 ] ;
470
534
var content = File . ReadAllText ( csproj . FullName ) ;
471
- var matches = TargetFramework ( ) . Matches ( content ) ;
535
+ var matches = pattern . Matches ( content ) ;
472
536
if ( matches . Count == 0 )
473
537
{
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 ) ;
538
+ logger . LogError ( $ "Could not find the { patternName } in { csproj . FullName } ") ;
539
+ return false ;
480
540
}
541
+
542
+ content = pattern . Replace ( content , replacement , 1 ) ;
543
+ File . WriteAllText ( csproj . FullName , content ) ;
544
+ return true ;
481
545
}
482
546
catch ( Exception exc )
483
547
{
484
- logger . LogError ( $ "Failed to update target framework in { tempDir . FullName } : { exc } ") ;
548
+ logger . LogError ( $ "Failed to change the { patternName } in { projectDir . FullName } : { exc } ") ;
485
549
}
550
+ return false ;
486
551
}
487
552
488
553
private static async Task ExecuteGetRequest ( string address , HttpClient httpClient , CancellationToken cancellationToken )
@@ -664,6 +729,9 @@ private IEnumerable<string> GetFeeds(Func<IList<string>> getNugetFeeds)
664
729
[ GeneratedRegex ( @"<TargetFramework>.*</TargetFramework>" , RegexOptions . IgnoreCase | RegexOptions . Compiled | RegexOptions . Singleline ) ]
665
730
private static partial Regex TargetFramework ( ) ;
666
731
732
+ [ GeneratedRegex ( @"Version=""[*|*-*]""" , RegexOptions . IgnoreCase | RegexOptions . Compiled | RegexOptions . Singleline ) ]
733
+ private static partial Regex PackageReferenceVersion ( ) ;
734
+
667
735
[ GeneratedRegex ( @"^(.+)\.(\d+\.\d+\.\d+(-(.+))?)$" , RegexOptions . IgnoreCase | RegexOptions . Compiled | RegexOptions . Singleline ) ]
668
736
private static partial Regex LegacyNugetPackage ( ) ;
669
737
0 commit comments