-
Notifications
You must be signed in to change notification settings - Fork 674
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add AssignReferenceProperties task for MSBuild #1737
Conversation
@panopticoncentral, |
|
||
var possibleTargetFrameworks = MSBuildStringUtility.Split(targetFramework); | ||
var possibleNuGetFrameworks = possibleTargetFrameworks.Select(ParseFramework).ToList(); | ||
var nearestNuGetFramework = NuGetFrameworkUtility.GetNearest(possibleTargetFrameworks, currentProjectTargetFramework, NuGetFramework.Parse); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this preserve the spelling of the target framework in possibleTargetFrameworks: e.g. net4.0 vs net40?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, this utility returns the original object back that is associated with the nearest framework, in this case it is the original string
{ | ||
var itemWithProperties = new TaskItem(project); | ||
|
||
var targetFramework = project.GetMetadata("TargetFrameworks"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: This should be named targetFrameworks
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
itemWithProperties.SetMetadata("UndefineProperties", | ||
string.IsNullOrEmpty(undefineProperties) | ||
? "TargetFramework" | ||
: undefineProperties + ";TargetFramework"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMHO, this is moving too much build logic in to NuGet. I was expecting the nuget task to be responsible for calculating nearest target framework and nothing else.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suspect some handling of Rid-agnostic is missing here, which adds to my concern that we're handling this sort of thing here in nuget.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See above
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
minor questions/comments
|
||
var possibleTargetFrameworks = MSBuildStringUtility.Split(targetFramework); | ||
var possibleNuGetFrameworks = possibleTargetFrameworks.Select(ParseFramework).ToList(); | ||
var nearestNuGetFramework = NuGetFrameworkUtility.GetNearest(possibleTargetFrameworks, currentProjectTargetFramework, NuGetFramework.Parse); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, this utility returns the original object back that is associated with the nearest framework, in this case it is the original string
} | ||
|
||
var possibleTargetFrameworks = MSBuildStringUtility.Split(targetFramework); | ||
var possibleNuGetFrameworks = possibleTargetFrameworks.Select(ParseFramework).ToList(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this trying to validate all frameworks up front? Should this be put in the else block where it is used instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, I don't know that there's value in doing this at all, to be honest.
In reply to: 143551005 [](ancestors = 143551005)
{ | ||
var framework = NuGetFramework.Parse(name); | ||
|
||
if (framework == null) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
.Parse
will return NuGetFramework.UnsupportedFramework
for unknown frameworks, it will never return null.
|
||
if (nearestNuGetFramework != null) | ||
{ | ||
if (TryConvertItemMetadataToBool(project, "HasSingleTargetFramework", out var singleTargetFramework) && singleTargetFramework) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if (MSBuildStringUtility.IsTrue(project.GetMetadata("HasSingleTargetFramework")))
I think this could be simplified to the above, it should only need to check if this value is true
otherwise is false. I might be missing something here though, I don't see where the 2nd bool to see if the metadata was there at all comes into play here.
Log.LogError(string.Format(Strings.NoCompatibleTargetFramework, CurrentProjectTargetFramework, string.Join("; ", possibleNuGetFrameworks))); | ||
} | ||
|
||
return itemWithProperties; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: log output params?
@@ -81,6 +81,7 @@ Copyright (c) .NET Foundation. All rights reserved. | |||
<UsingTask TaskName="NuGet.Build.Tasks.GetRestoreSolutionProjectsTask" AssemblyFile="$(RestoreTaskAssemblyFile)" /> | |||
<UsingTask TaskName="NuGet.Build.Tasks.GetRestoreSettingsTask" AssemblyFile="$(RestoreTaskAssemblyFile)" /> | |||
<UsingTask TaskName="NuGet.Build.Tasks.WarnForInvalidProjectsTask" AssemblyFile="$(RestoreTaskAssemblyFile)" /> | |||
<UsingTask TaskName="NuGet.Build.Tasks.AssignReferenceProperties" AssemblyFile="$(RestoreTaskAssemblyFile)" /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs to be updated to the new task name with Task
on the end.
return false; | ||
} | ||
|
||
AssignedProjects = AnnotatedProjectReferences.Select(project => AssignPropertiesForSingleReference(project, frameworkToMatch)).ToArray(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Allocations?
@@ -117,6 +117,9 @@ | |||
<resheader name="writer"> | |||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> | |||
</resheader> | |||
<data name="NoCompatibleTargetFramework" xml:space="preserve"> | |||
<value>Cannot find a compatible framework for '{0}' in the following frameworks: {1}.</value> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should use the same error message as before here:
@panopticoncentral Would it make more sense to have a task that only finds the nearest framework from a set of strings? Or would it impact perf to have to make multiple calls to this task instead? I'm fine with this change overall, my thought is just that if there was a task that just found the nearest compatible framework it could save adding another task in the future. |
@@ -118,7 +118,7 @@ | |||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> | |||
</resheader> | |||
<data name="NoCompatibleTargetFramework" xml:space="preserve"> | |||
<value>Cannot find a compatible framework for '{0}' in the following frameworks: {1}.</value> | |||
<value>Project '{0}' targets '{2}'. It cannot be referenced by a project that targets '{1}'.</value> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like the placeholder ordering is different here than the call site.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I reordered the callsite, so the message is:
Project '{0}' targets '{2}'. It cannot be referenced by a project that targets '{1}'.
and the callsite is:
string.Format(Strings.NoCompatibleTargetFramework, project.ItemSpec, CurrentProjectTargetFramework, targetFrameworks)
It looked correct in the unit tests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right, I read wrong.
@emgarten We did talk about that but we felt it was better performance to do it all at once. |
Looks good. Verified works in my testing. |
Bug
Link: dotnet/msbuild#1276
Regression: No
Fix
Details: This adds a new task, AssignReferenceProperties, that allows MSBuild to specify a project's target framework and that project's references, and have NuGet resolve what target frameworks should be used for each reference. This avoids having to add logic into MSBuild to figure out the compatibility matrix.
Testing/Validation
Tests Added: Yes
Validation done: Tests + been validated against MSBuild modified to use the task.