33
44using System ;
55using System . Collections . Generic ;
6+ using System . ComponentModel . DataAnnotations ;
67using System . IO ;
78using System . Linq ;
89using Microsoft . DotNet . Cli ;
@@ -17,7 +18,7 @@ public class SdkDirectoryWorkloadManifestProvider : IWorkloadManifestProvider
1718 private readonly string [ ] _manifestDirectories ;
1819 private static HashSet < string > _outdatedManifestIds = new HashSet < string > ( StringComparer . OrdinalIgnoreCase ) { "microsoft.net.workload.android" , "microsoft.net.workload.blazorwebassembly" , "microsoft.net.workload.ios" ,
1920 "microsoft.net.workload.maccatalyst" , "microsoft.net.workload.macos" , "microsoft.net.workload.tvos" } ;
20- private readonly HashSet < string > ? _knownManifestIds ;
21+ private readonly Dictionary < string , int > ? _knownManifestIdsAndOrder ;
2122
2223 public SdkDirectoryWorkloadManifestProvider ( string sdkRootPath , string sdkVersion , string ? userProfileDir )
2324 : this ( sdkRootPath , sdkVersion , Environment . GetEnvironmentVariable , userProfileDir )
@@ -44,7 +45,12 @@ internal SdkDirectoryWorkloadManifestProvider(string sdkRootPath, string sdkVers
4445 var knownManifestIdsFilePath = Path . Combine ( _sdkRootPath , "sdk" , sdkVersion , "IncludedWorkloadManifests.txt" ) ;
4546 if ( File . Exists ( knownManifestIdsFilePath ) )
4647 {
47- _knownManifestIds = File . ReadAllLines ( knownManifestIdsFilePath ) . Where ( l => ! string . IsNullOrEmpty ( l ) ) . ToHashSet ( ) ;
48+ _knownManifestIdsAndOrder = new Dictionary < string , int > ( ) ;
49+ int lineNumber = 0 ;
50+ foreach ( var manifestId in File . ReadAllLines ( knownManifestIdsFilePath ) . Where ( l => ! string . IsNullOrEmpty ( l ) ) )
51+ {
52+ _knownManifestIdsAndOrder [ manifestId ] = lineNumber ++ ;
53+ }
4854 }
4955
5056 string ? userManifestsDir = userProfileDir is null ? null : Path . Combine ( userProfileDir , "sdk-manifests" , _sdkVersionBand . ToString ( ) ) ;
@@ -126,9 +132,9 @@ public IEnumerable<string> GetManifestDirectories()
126132 }
127133 }
128134
129- if ( _knownManifestIds != null && _knownManifestIds . Any ( id => ! manifestIdsToDirectories . ContainsKey ( id ) ) )
135+ if ( _knownManifestIdsAndOrder != null && _knownManifestIdsAndOrder . Keys . Any ( id => ! manifestIdsToDirectories . ContainsKey ( id ) ) )
130136 {
131- var missingManifestIds = _knownManifestIds . Where ( id => ! manifestIdsToDirectories . ContainsKey ( id ) ) ;
137+ var missingManifestIds = _knownManifestIdsAndOrder . Keys . Where ( id => ! manifestIdsToDirectories . ContainsKey ( id ) ) ;
132138 foreach ( var missingManifestId in missingManifestIds )
133139 {
134140 var manifestDir = FallbackForMissingManifest ( missingManifestId ) ;
@@ -139,7 +145,21 @@ public IEnumerable<string> GetManifestDirectories()
139145 }
140146 }
141147
142- return manifestIdsToDirectories . Values ;
148+ // Return manifests in a stable order. Manifests in the IncludedWorkloadManifests.txt file will be first, and in the same order they appear in that file.
149+ // Then the rest of the manifests (if any) will be returned in (ordinal case-insensitive) alphabetical order.
150+ return manifestIdsToDirectories
151+ . OrderBy ( kvp =>
152+ {
153+ if ( _knownManifestIdsAndOrder != null &&
154+ _knownManifestIdsAndOrder . TryGetValue ( kvp . Key , out var order ) )
155+ {
156+ return order ;
157+ }
158+ return int . MaxValue ;
159+ } )
160+ . ThenBy ( kvp => kvp . Key , StringComparer . OrdinalIgnoreCase )
161+ . Select ( kvp => kvp . Value )
162+ . ToList ( ) ;
143163 }
144164
145165 private string FallbackForMissingManifest ( string manifestId )
0 commit comments