6
6
using System . IO ;
7
7
using System . Linq ;
8
8
using System . Runtime . InteropServices ;
9
+ using System . Text . RegularExpressions ;
9
10
using Microsoft . Build . Framework ;
10
11
using Microsoft . Build . Utilities ;
12
+ using Newtonsoft . Json ;
11
13
using NuGet . Frameworks ;
12
14
13
15
namespace Microsoft . NET . Build . Tasks
@@ -50,6 +52,8 @@ public class ProcessFrameworkReferences : TaskBase
50
52
51
53
public ITaskItem [ ] KnownFrameworkReferences { get ; set ; } = Array . Empty < ITaskItem > ( ) ;
52
54
55
+ public ITaskItem [ ] KnownRuntimePacks { get ; set ; } = Array . Empty < ITaskItem > ( ) ;
56
+
53
57
public ITaskItem [ ] KnownCrossgen2Packs { get ; set ; } = Array . Empty < ITaskItem > ( ) ;
54
58
55
59
[ Required ]
@@ -90,6 +94,21 @@ protected override void ExecuteCore()
90
94
NormalizeVersion ( kfr . TargetFramework . Version ) == normalizedTargetFrameworkVersion )
91
95
. ToList ( ) ;
92
96
97
+ // Get known runtime packs from known framework references.
98
+ // Only use items where the framework reference name matches the RuntimeFrameworkName.
99
+ // This will filter out known framework references for "profiles", ie WindowsForms and WPF
100
+ var knownRuntimePacksForTargetFramework =
101
+ knownFrameworkReferencesForTargetFramework
102
+ . Where ( kfr => kfr . Name == kfr . RuntimeFrameworkName )
103
+ . Select ( kfr => kfr . ToKnownRuntimePack ( ) )
104
+ . ToList ( ) ;
105
+
106
+ // Add additional known runtime packs
107
+ knownRuntimePacksForTargetFramework . AddRange (
108
+ KnownRuntimePacks . Select ( item => new KnownRuntimePack ( item ) )
109
+ . Where ( krp => krp . TargetFramework . Framework . Equals ( TargetFrameworkIdentifier , StringComparison . OrdinalIgnoreCase ) &&
110
+ NormalizeVersion ( krp . TargetFramework . Version ) == normalizedTargetFrameworkVersion ) ) ;
111
+
93
112
var frameworkReferenceMap = FrameworkReferences . ToDictionary ( fr => fr . ItemSpec , StringComparer . OrdinalIgnoreCase ) ;
94
113
95
114
List < ITaskItem > packagesToDownload = new List < ITaskItem > ( ) ;
@@ -120,20 +139,23 @@ protected override void ExecuteCore()
120
139
continue ;
121
140
}
122
141
142
+ KnownRuntimePack selectedRuntimePack = SelectRuntimePack ( frameworkReference , knownFrameworkReference , knownRuntimePacksForTargetFramework ) ;
143
+
144
+ // Add targeting pack and all known runtime packs to "preferred packages" list.
145
+ // These are packages that will win in conflict resolution for assets that have identical assembly and file versions
123
146
List < string > preferredPackages = new List < string > ( ) ;
124
147
preferredPackages . Add ( knownFrameworkReference . TargetingPackName ) ;
125
148
126
- var knownFrameworkReferenceRuntimePackRuntimeIdentifiers = knownFrameworkReference . RuntimePackRuntimeIdentifiers . Split ( ';' ) ;
149
+ var knownFrameworkReferenceRuntimePackRuntimeIdentifiers = selectedRuntimePack . RuntimePackRuntimeIdentifiers . Split ( ';' ) ;
127
150
foreach ( var runtimeIdentifier in knownFrameworkReferenceRuntimePackRuntimeIdentifiers )
128
151
{
129
- foreach ( var runtimePackNamePattern in knownFrameworkReference . RuntimePackNamePatterns . Split ( ';' ) )
152
+ foreach ( var runtimePackNamePattern in selectedRuntimePack . RuntimePackNamePatterns . Split ( ';' ) )
130
153
{
131
154
string runtimePackName = runtimePackNamePattern . Replace ( "**RID**" , runtimeIdentifier ) ;
132
155
preferredPackages . Add ( runtimePackName ) ;
133
156
}
134
157
}
135
-
136
- // Get the path of the targeting pack in the targeting pack root (e.g. dotnet/ref)
158
+
137
159
TaskItem targetingPack = new TaskItem ( knownFrameworkReference . Name ) ;
138
160
targetingPack . SetMetadata ( MetadataKeys . NuGetPackageId , knownFrameworkReference . TargetingPackName ) ;
139
161
targetingPack . SetMetadata ( MetadataKeys . PackageConflictPreferredPackages , string . Join ( ";" , preferredPackages ) ) ;
@@ -152,13 +174,14 @@ protected override void ExecuteCore()
152
174
targetingPack . SetMetadata ( "TargetingPackFormat" , knownFrameworkReference . TargetingPackFormat ) ;
153
175
targetingPack . SetMetadata ( "TargetFramework" , knownFrameworkReference . TargetFramework . GetShortFolderName ( ) ) ;
154
176
targetingPack . SetMetadata ( MetadataKeys . RuntimeFrameworkName , knownFrameworkReference . RuntimeFrameworkName ) ;
155
- targetingPack . SetMetadata ( MetadataKeys . RuntimePackRuntimeIdentifiers , knownFrameworkReference . RuntimePackRuntimeIdentifiers ) ;
177
+ targetingPack . SetMetadata ( MetadataKeys . RuntimePackRuntimeIdentifiers , selectedRuntimePack . RuntimePackRuntimeIdentifiers ) ;
156
178
157
179
if ( ! string . IsNullOrEmpty ( knownFrameworkReference . Profile ) )
158
180
{
159
181
targetingPack . SetMetadata ( "Profile" , knownFrameworkReference . Profile ) ;
160
182
}
161
183
184
+ // Get the path of the targeting pack in the targeting pack root (e.g. dotnet/packs)
162
185
string targetingPackPath = null ;
163
186
if ( ! string . IsNullOrEmpty ( TargetingPackRoot ) )
164
187
{
@@ -186,7 +209,8 @@ protected override void ExecuteCore()
186
209
187
210
var runtimeFrameworkVersion = GetRuntimeFrameworkVersion (
188
211
frameworkReference ,
189
- knownFrameworkReference ,
212
+ knownFrameworkReference ,
213
+ selectedRuntimePack ,
190
214
out string runtimePackVersion ) ;
191
215
192
216
string isTrimmable = null ;
@@ -197,16 +221,16 @@ protected override void ExecuteCore()
197
221
}
198
222
if ( string . IsNullOrEmpty ( isTrimmable ) )
199
223
{
200
- isTrimmable = knownFrameworkReference . IsTrimmable ;
224
+ isTrimmable = selectedRuntimePack . IsTrimmable ;
201
225
}
202
226
203
227
bool processedPrimaryRuntimeIdentifier = false ;
204
228
205
229
if ( ( SelfContained || ReadyToRunEnabled ) &&
206
230
! string . IsNullOrEmpty ( RuntimeIdentifier ) &&
207
- ! string . IsNullOrEmpty ( knownFrameworkReference . RuntimePackNamePatterns ) )
231
+ ! string . IsNullOrEmpty ( selectedRuntimePack . RuntimePackNamePatterns ) )
208
232
{
209
- ProcessRuntimeIdentifier ( RuntimeIdentifier , knownFrameworkReference , runtimePackVersion ,
233
+ ProcessRuntimeIdentifier ( RuntimeIdentifier , selectedRuntimePack , runtimePackVersion ,
210
234
unrecognizedRuntimeIdentifiers , unavailableRuntimePacks , runtimePacks , packagesToDownload , isTrimmable ) ;
211
235
212
236
processedPrimaryRuntimeIdentifier = true ;
@@ -224,7 +248,7 @@ protected override void ExecuteCore()
224
248
225
249
// Pass in null for the runtimePacks list, as for these runtime identifiers we only want to
226
250
// download the runtime packs, but not use the assets from them
227
- ProcessRuntimeIdentifier ( runtimeIdentifier , knownFrameworkReference , runtimePackVersion ,
251
+ ProcessRuntimeIdentifier ( runtimeIdentifier , selectedRuntimePack , runtimePackVersion ,
228
252
unrecognizedRuntimeIdentifiers , unavailableRuntimePacks , runtimePacks : null , packagesToDownload , isTrimmable ) ;
229
253
}
230
254
}
@@ -280,9 +304,57 @@ protected override void ExecuteCore()
280
304
}
281
305
}
282
306
307
+ private KnownRuntimePack SelectRuntimePack ( ITaskItem frameworkReference , KnownFrameworkReference knownFrameworkReference , List < KnownRuntimePack > knownRuntimePacks )
308
+ {
309
+ var requiredLabelsMetadata = frameworkReference ? . GetMetadata ( MetadataKeys . RuntimePackLabels ) ?? "" ;
310
+
311
+ HashSet < string > requiredRuntimePackLabels = null ;
312
+ if ( frameworkReference != null )
313
+ {
314
+ requiredRuntimePackLabels = new HashSet < string > ( requiredLabelsMetadata . Split ( new [ ] { ';' } , StringSplitOptions . RemoveEmptyEntries ) , StringComparer . OrdinalIgnoreCase ) ;
315
+ }
316
+
317
+ // The runtime pack name matches the RuntimeFrameworkName on the KnownFrameworkReference
318
+ var matchingRuntimePacks = knownRuntimePacks . Where ( krp => krp . Name . Equals ( knownFrameworkReference . RuntimeFrameworkName , StringComparison . OrdinalIgnoreCase ) )
319
+ . Where ( krp =>
320
+ {
321
+ if ( requiredRuntimePackLabels == null )
322
+ {
323
+ return krp . RuntimePackLabels . Length == 0 ;
324
+ }
325
+ else
326
+ {
327
+ return requiredRuntimePackLabels . SetEquals ( krp . RuntimePackLabels ) ;
328
+ }
329
+ } )
330
+ . ToList ( ) ;
331
+
332
+ if ( matchingRuntimePacks . Count == 1 )
333
+ {
334
+ return matchingRuntimePacks [ 0 ] ;
335
+ }
336
+ else
337
+ {
338
+ string runtimePackDescriptionForErrorMessage = knownFrameworkReference . RuntimeFrameworkName +
339
+ ( requiredLabelsMetadata == string . Empty ? string . Empty : ":" + requiredLabelsMetadata ) ;
340
+
341
+ if ( matchingRuntimePacks . Count == 0 )
342
+ {
343
+ Log . LogError ( Strings . NoRuntimePackInformation , runtimePackDescriptionForErrorMessage ) ;
344
+ }
345
+ else
346
+ {
347
+ Log . LogError ( Strings . ConflictingRuntimePackInformation , runtimePackDescriptionForErrorMessage ,
348
+ string . Join ( Environment . NewLine , matchingRuntimePacks . Select ( rp => rp . RuntimePackNamePatterns ) ) ) ;
349
+ }
350
+
351
+ return knownFrameworkReference . ToKnownRuntimePack ( ) ;
352
+ }
353
+ }
354
+
283
355
private void ProcessRuntimeIdentifier (
284
356
string runtimeIdentifier ,
285
- KnownFrameworkReference knownFrameworkReference ,
357
+ KnownRuntimePack selectedRuntimePack ,
286
358
string runtimePackVersion ,
287
359
HashSet < string > unrecognizedRuntimeIdentifiers ,
288
360
List < ITaskItem > unavailableRuntimePacks ,
@@ -291,7 +363,7 @@ private void ProcessRuntimeIdentifier(
291
363
string isTrimmable )
292
364
{
293
365
var runtimeGraph = new RuntimeGraphCache ( this ) . GetRuntimeGraph ( RuntimeGraphPath ) ;
294
- var knownFrameworkReferenceRuntimePackRuntimeIdentifiers = knownFrameworkReference . RuntimePackRuntimeIdentifiers . Split ( ';' ) ;
366
+ var knownFrameworkReferenceRuntimePackRuntimeIdentifiers = selectedRuntimePack . RuntimePackRuntimeIdentifiers . Split ( ';' ) ;
295
367
296
368
string runtimePackRuntimeIdentifier = NuGetUtils . GetBestMatchingRid (
297
369
runtimeGraph ,
@@ -308,7 +380,7 @@ private void ProcessRuntimeIdentifier(
308
380
// framework we don't directly reference. But we don't want to immediately error out
309
381
// here if a runtime pack that we might not need to reference isn't available for the
310
382
// targeted RID (e.g. Microsoft.WindowsDesktop.App for a linux RID).
311
- var unavailableRuntimePack = new TaskItem ( knownFrameworkReference . Name ) ;
383
+ var unavailableRuntimePack = new TaskItem ( selectedRuntimePack . Name ) ;
312
384
unavailableRuntimePack . SetMetadata ( MetadataKeys . RuntimeIdentifier , runtimeIdentifier ) ;
313
385
unavailableRuntimePacks . Add ( unavailableRuntimePack ) ;
314
386
}
@@ -321,7 +393,7 @@ private void ProcessRuntimeIdentifier(
321
393
}
322
394
else
323
395
{
324
- foreach ( var runtimePackNamePattern in knownFrameworkReference . RuntimePackNamePatterns . Split ( ';' ) )
396
+ foreach ( var runtimePackNamePattern in selectedRuntimePack . RuntimePackNamePatterns . Split ( ';' ) )
325
397
{
326
398
string runtimePackName = runtimePackNamePattern . Replace ( "**RID**" , runtimePackRuntimeIdentifier ) ;
327
399
@@ -330,7 +402,7 @@ private void ProcessRuntimeIdentifier(
330
402
TaskItem runtimePackItem = new TaskItem ( runtimePackName ) ;
331
403
runtimePackItem . SetMetadata ( MetadataKeys . NuGetPackageId , runtimePackName ) ;
332
404
runtimePackItem . SetMetadata ( MetadataKeys . NuGetPackageVersion , runtimePackVersion ) ;
333
- runtimePackItem . SetMetadata ( MetadataKeys . FrameworkName , knownFrameworkReference . Name ) ;
405
+ runtimePackItem . SetMetadata ( MetadataKeys . FrameworkName , selectedRuntimePack . Name ) ;
334
406
runtimePackItem . SetMetadata ( MetadataKeys . RuntimeIdentifier , runtimePackRuntimeIdentifier ) ;
335
407
runtimePackItem . SetMetadata ( MetadataKeys . IsTrimmable , isTrimmable ) ;
336
408
@@ -392,6 +464,7 @@ private bool AddCrossgen2Package(Version normalizedTargetFrameworkVersion, List<
392
464
private string GetRuntimeFrameworkVersion (
393
465
ITaskItem frameworkReference ,
394
466
KnownFrameworkReference knownFrameworkReference ,
467
+ KnownRuntimePack knownRuntimePack ,
395
468
out string runtimePackVersion )
396
469
{
397
470
// Precedence order for selecting runtime framework version
@@ -417,11 +490,11 @@ private string GetRuntimeFrameworkVersion(
417
490
return knownFrameworkReference . DefaultRuntimeFrameworkVersion ;
418
491
419
492
case RuntimePatchRequest . UseLatestVersion :
420
- runtimePackVersion = knownFrameworkReference . LatestRuntimeFrameworkVersion ;
421
- return knownFrameworkReference . LatestRuntimeFrameworkVersion ;
493
+ runtimePackVersion = knownRuntimePack . LatestRuntimeFrameworkVersion ;
494
+ return knownRuntimePack . LatestRuntimeFrameworkVersion ;
422
495
423
496
case RuntimePatchRequest . UseDefaultVersionWithLatestRuntimePack :
424
- runtimePackVersion = knownFrameworkReference . LatestRuntimeFrameworkVersion ;
497
+ runtimePackVersion = knownRuntimePack . LatestRuntimeFrameworkVersion ;
425
498
return knownFrameworkReference . DefaultRuntimeFrameworkVersion ;
426
499
427
500
default :
@@ -501,13 +574,58 @@ public KnownFrameworkReference(ITaskItem item)
501
574
// The framework name to write to the runtimeconfig file (and the name of the folder under dotnet/shared)
502
575
public string RuntimeFrameworkName => _item . GetMetadata ( MetadataKeys . RuntimeFrameworkName ) ;
503
576
public string DefaultRuntimeFrameworkVersion => _item . GetMetadata ( "DefaultRuntimeFrameworkVersion" ) ;
504
- public string LatestRuntimeFrameworkVersion => _item . GetMetadata ( "LatestRuntimeFrameworkVersion" ) ;
577
+ // public string LatestRuntimeFrameworkVersion => _item.GetMetadata("LatestRuntimeFrameworkVersion");
505
578
506
579
// The ID of the targeting pack NuGet package to reference
507
580
public string TargetingPackName => _item . GetMetadata ( "TargetingPackName" ) ;
508
581
public string TargetingPackVersion => _item . GetMetadata ( "TargetingPackVersion" ) ;
509
582
public string TargetingPackFormat => _item . GetMetadata ( "TargetingPackFormat" ) ;
510
583
584
+ //public string RuntimePackNamePatterns => _item.GetMetadata("RuntimePackNamePatterns");
585
+
586
+ //public string RuntimePackRuntimeIdentifiers => _item.GetMetadata(MetadataKeys.RuntimePackRuntimeIdentifiers);
587
+
588
+ //public string IsTrimmable => _item.GetMetadata(MetadataKeys.IsTrimmable);
589
+
590
+ public bool IsWindowsOnly => _item . HasMetadataValue ( "IsWindowsOnly" , "true" ) ;
591
+
592
+ public string Profile => _item . GetMetadata ( "Profile" ) ;
593
+
594
+ public NuGetFramework TargetFramework { get ; }
595
+
596
+ public KnownRuntimePack ToKnownRuntimePack ( )
597
+ {
598
+ return new KnownRuntimePack ( _item ) ;
599
+ }
600
+ }
601
+
602
+ private struct KnownRuntimePack
603
+ {
604
+ ITaskItem _item ;
605
+
606
+ public KnownRuntimePack ( ITaskItem item )
607
+ {
608
+ _item = item ;
609
+ TargetFramework = NuGetFramework . Parse ( item . GetMetadata ( "TargetFramework" ) ) ;
610
+ string runtimePackLabels = item . GetMetadata ( MetadataKeys . RuntimePackLabels ) ;
611
+ if ( string . IsNullOrEmpty ( runtimePackLabels ) )
612
+ {
613
+ RuntimePackLabels = Array . Empty < string > ( ) ;
614
+ }
615
+ else
616
+ {
617
+ RuntimePackLabels = runtimePackLabels . Split ( ';' ) ;
618
+ }
619
+ }
620
+
621
+ // The name / itemspec of the FrameworkReference used in the project
622
+ public string Name => _item . ItemSpec ;
623
+
624
+ //// The framework name to write to the runtimeconfig file (and the name of the folder under dotnet/shared)
625
+ //public string RuntimeFrameworkName => _item.GetMetadata(MetadataKeys.RuntimeFrameworkName);
626
+ //public string DefaultRuntimeFrameworkVersion => _item.GetMetadata("DefaultRuntimeFrameworkVersion");
627
+ public string LatestRuntimeFrameworkVersion => _item . GetMetadata ( "LatestRuntimeFrameworkVersion" ) ;
628
+
511
629
public string RuntimePackNamePatterns => _item . GetMetadata ( "RuntimePackNamePatterns" ) ;
512
630
513
631
public string RuntimePackRuntimeIdentifiers => _item . GetMetadata ( MetadataKeys . RuntimePackRuntimeIdentifiers ) ;
@@ -516,7 +634,7 @@ public KnownFrameworkReference(ITaskItem item)
516
634
517
635
public bool IsWindowsOnly => _item . HasMetadataValue ( "IsWindowsOnly" , "true" ) ;
518
636
519
- public string Profile => _item . GetMetadata ( "Profile" ) ;
637
+ public string [ ] RuntimePackLabels { get ; }
520
638
521
639
public NuGetFramework TargetFramework { get ; }
522
640
}
0 commit comments