11// Copyright (c) .NET Foundation. All rights reserved.
22// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33
4+ using System ;
45using System . Collections . Generic ;
56using System . Globalization ;
67using System . Linq ;
@@ -15,6 +16,8 @@ public class GetReferenceNearestTargetFrameworkTask : Task
1516 {
1617 private const string NEAREST_TARGET_FRAMEWORK = "NearestTargetFramework" ;
1718 private const string TARGET_FRAMEWORKS = "TargetFrameworks" ;
19+ private const string TARGET_FRAMEWORK_MONIKERS = "TargetFrameworkMonikers" ;
20+ private const string TARGET_PLATFORM_MONIKERS = "TargetPlatformMonikers" ;
1821 private const string MSBUILD_SOURCE_PROJECT_FILE = "MSBuildSourceProjectFile" ;
1922
2023 /// <summary>
@@ -28,6 +31,11 @@ public class GetReferenceNearestTargetFrameworkTask : Task
2831 [ Required ]
2932 public string CurrentProjectTargetFramework { get ; set ; }
3033
34+ /// <summary>
35+ /// Optional TargetPlatformMoniker
36+ /// </summary>
37+ public string CurrentProjectTargetPlatform { get ; set ; }
38+
3139 /// <summary>
3240 /// Optional list of target frameworks to be used as Fallback target frameworks.
3341 /// </summary>
@@ -51,6 +59,8 @@ public override bool Execute()
5159
5260 BuildTasksUtility . LogInputParam ( logger , nameof ( CurrentProjectTargetFramework ) , CurrentProjectTargetFramework ) ;
5361
62+ BuildTasksUtility . LogInputParam ( logger , nameof ( CurrentProjectTargetPlatform ) , CurrentProjectTargetPlatform ) ;
63+
5464 BuildTasksUtility . LogInputParam ( logger , nameof ( FallbackTargetFrameworks ) ,
5565 FallbackTargetFrameworks == null
5666 ? ""
@@ -69,8 +79,8 @@ public override bool Execute()
6979 var fallbackNuGetFrameworks = new List < NuGetFramework > ( ) ;
7080
7181 // validate current project framework
72- var errorMessage = string . Format ( Strings . UnsupportedTargetFramework , CurrentProjectTargetFramework ) ;
73- if ( ! TryParseFramework ( CurrentProjectTargetFramework , errorMessage , logger , out var projectNuGetFramework ) )
82+ var errorMessage = string . Format ( CultureInfo . CurrentCulture , Strings . UnsupportedTargetFramework , $ "TargetFrameworkMoniker: { CurrentProjectTargetFramework } , TargetPlatformMoniker: { CurrentProjectTargetPlatform } " ) ;
83+ if ( ! TryParseFramework ( CurrentProjectTargetFramework , CurrentProjectTargetPlatform , errorMessage , logger , out var projectNuGetFramework ) )
7484 {
7585 return false ;
7686 }
@@ -81,7 +91,7 @@ public override bool Execute()
8191 foreach ( var fallbackFramework in FallbackTargetFrameworks )
8292 {
8393 // validate ATF project frameworks
84- errorMessage = string . Format ( Strings . UnsupportedFallbackFramework , fallbackFramework ) ;
94+ errorMessage = string . Format ( CultureInfo . CurrentCulture , Strings . UnsupportedFallbackFramework , fallbackFramework ) ;
8595 if ( ! TryParseFramework ( fallbackFramework , errorMessage , logger , out var nugetFramework ) )
8696 {
8797 return false ;
@@ -112,6 +122,9 @@ private ITaskItem AssignNearestFrameworkForSingleReference(
112122 {
113123 var itemWithProperties = new TaskItem ( project ) ;
114124 var referencedProjectFrameworkString = project . GetMetadata ( TARGET_FRAMEWORKS ) ;
125+ var referenceTargetFrameworkMonikers = project . GetMetadata ( TARGET_FRAMEWORK_MONIKERS ) ;
126+ var referencedProjectPlatformString = project . GetMetadata ( TARGET_PLATFORM_MONIKERS ) ;
127+
115128 var referencedProjectFile = project . GetMetadata ( MSBUILD_SOURCE_PROJECT_FILE ) ;
116129
117130 if ( string . IsNullOrEmpty ( referencedProjectFrameworkString ) )
@@ -121,19 +134,43 @@ private ITaskItem AssignNearestFrameworkForSingleReference(
121134 }
122135
123136 var referencedProjectFrameworks = MSBuildStringUtility . Split ( referencedProjectFrameworkString ) ;
137+ var referencedProjectTargetFrameworkMonikers = MSBuildStringUtility . Split ( referenceTargetFrameworkMonikers ) ;
138+ var referencedProjectTargetPlatformMonikers = MSBuildStringUtility . Split ( referencedProjectPlatformString ) ;
139+
140+ if ( referencedProjectTargetFrameworkMonikers . Length > 0 &&
141+ ( referencedProjectTargetFrameworkMonikers . Length != referencedProjectTargetPlatformMonikers . Length ||
142+ referencedProjectTargetFrameworkMonikers . Length != referencedProjectFrameworks . Length ) )
143+ {
144+ logger . LogError ( $ "Internal error for { CurrentProjectName } ." +
145+ $ " Expected { TARGET_FRAMEWORKS } :{ referencedProjectFrameworks } , " +
146+ $ "{ TARGET_FRAMEWORK_MONIKERS } :{ referenceTargetFrameworkMonikers } , " +
147+ $ "{ TARGET_PLATFORM_MONIKERS } :{ referencedProjectPlatformString } to have the same number of elements.") ;
148+ return itemWithProperties ;
149+ }
150+ // TargetFrameworks, TargetFrameworkMoniker, TargetPlatforMoniker
151+ var targetFrameworkInformations = new List < TargetFrameworkInformation > ( ) ;
152+ var useTargetMonikers = referencedProjectTargetFrameworkMonikers . Length > 0 ;
153+ for ( int i = 0 ; i < referencedProjectFrameworks . Length ; i ++ )
154+ {
155+
156+ targetFrameworkInformations . Add ( new TargetFrameworkInformation (
157+ referencedProjectFrameworks [ i ] ,
158+ useTargetMonikers ? referencedProjectTargetFrameworkMonikers [ i ] : null ,
159+ useTargetMonikers ? referencedProjectTargetPlatformMonikers [ i ] : null ) ) ;
160+ }
124161
125162 // try project framework
126- var nearestNuGetFramework = NuGetFrameworkUtility . GetNearest ( referencedProjectFrameworks , projectNuGetFramework , NuGetFramework . Parse ) ;
163+ var nearestNuGetFramework = NuGetFrameworkUtility . GetNearest ( targetFrameworkInformations , projectNuGetFramework , GetNuGetFramework ) ;
127164 if ( nearestNuGetFramework != null )
128165 {
129- itemWithProperties . SetMetadata ( NEAREST_TARGET_FRAMEWORK , nearestNuGetFramework ) ;
166+ itemWithProperties . SetMetadata ( NEAREST_TARGET_FRAMEWORK , nearestNuGetFramework . _targetFrameworkAlias ) ;
130167 return itemWithProperties ;
131168 }
132169
133170 // try project fallback frameworks
134171 foreach ( var currentProjectTargetFramework in fallbackNuGetFrameworks )
135172 {
136- nearestNuGetFramework = NuGetFrameworkUtility . GetNearest ( referencedProjectFrameworks , currentProjectTargetFramework , NuGetFramework . Parse ) ;
173+ nearestNuGetFramework = NuGetFrameworkUtility . GetNearest ( targetFrameworkInformations , currentProjectTargetFramework , GetNuGetFramework ) ;
137174
138175 if ( nearestNuGetFramework != null )
139176 {
@@ -150,13 +187,13 @@ private ITaskItem AssignNearestFrameworkForSingleReference(
150187 // log NU1702 for ATF on project reference
151188 logger . Log ( warning ) ;
152189
153- itemWithProperties . SetMetadata ( NEAREST_TARGET_FRAMEWORK , nearestNuGetFramework ) ;
190+ itemWithProperties . SetMetadata ( NEAREST_TARGET_FRAMEWORK , nearestNuGetFramework . _targetFrameworkAlias ) ;
154191 return itemWithProperties ;
155192 }
156193 }
157194
158195 // no match found
159- logger . LogError ( string . Format ( Strings . NoCompatibleTargetFramework , project . ItemSpec , CurrentProjectTargetFramework , referencedProjectFrameworkString ) ) ;
196+ logger . LogError ( string . Format ( CultureInfo . CurrentCulture , Strings . NoCompatibleTargetFramework , project . ItemSpec , projectNuGetFramework . DotNetFrameworkName , referencedProjectFrameworkString ) ) ;
160197 return itemWithProperties ;
161198 }
162199
@@ -173,5 +210,51 @@ private static bool TryParseFramework(string framework, string errorMessage, MSB
173210
174211 return true ;
175212 }
213+
214+ private static bool TryParseFramework ( string targetFrameworkMoniker , string targetPlatformMoniker , string errorMessage , MSBuildLogger logger , out NuGetFramework nugetFramework )
215+ {
216+ // Check if we have a long name.
217+ nugetFramework = targetFrameworkMoniker . Contains ( ',' )
218+ ? NuGetFramework . ParseComponents ( targetFrameworkMoniker , targetPlatformMoniker )
219+ : NuGetFramework . Parse ( targetFrameworkMoniker ) ;
220+
221+ // validate framework
222+ if ( nugetFramework . IsUnsupported )
223+ {
224+ logger . LogError ( errorMessage ) ;
225+ return false ;
226+ }
227+
228+ return true ;
229+ }
230+
231+ private static NuGetFramework GetNuGetFramework ( TargetFrameworkInformation targetFrameworkInformation )
232+ {
233+ // Legacy path, process targetFrameworks if empty
234+ if ( string . IsNullOrEmpty ( targetFrameworkInformation . _targetFrameworkMoniker ) )
235+ {
236+ return NuGetFramework . Parse ( targetFrameworkInformation . _targetFrameworkAlias ) ;
237+ }
238+
239+ // TargetFrameworkMoniker is always expected to be set. TargetPlatformMoniker will have a `None` value when empty, for frameworks like net5.0.
240+ return NuGetFramework . ParseComponents ( targetFrameworkInformation . _targetFrameworkMoniker ,
241+ targetFrameworkInformation . _targetPlatformMoniker . Equals ( "None" , StringComparison . OrdinalIgnoreCase ) ?
242+ string . Empty :
243+ targetFrameworkInformation . _targetPlatformMoniker ) ;
244+ }
245+ }
246+
247+ internal class TargetFrameworkInformation
248+ {
249+ internal readonly string _targetFrameworkAlias ;
250+ internal readonly string _targetFrameworkMoniker ;
251+ internal readonly string _targetPlatformMoniker ;
252+
253+ public TargetFrameworkInformation ( string targetFrameworkAlias , string targetFrameworkMoniker , string targetPlatformMoniker )
254+ {
255+ _targetFrameworkAlias = targetFrameworkAlias ;
256+ _targetFrameworkMoniker = targetFrameworkMoniker ;
257+ _targetPlatformMoniker = targetPlatformMoniker ;
258+ }
176259 }
177260}
0 commit comments