Skip to content
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

Update schema for combining TargetFramework info to allow for invalid xml names such as including '+' #6699

Merged

Conversation

Forgind
Copy link
Member

@Forgind Forgind commented Jul 21, 2021

Fixes #6603

Context

The ability to gather extra properties from referenced projects was added in #5994. It used XML transformations to couch that logic in a way that MSBuild could understand.

Unfortunately, the XML-based logic assumed everything was a valid XML element. Ultimately, the goal of the change, at least as I understand it, was just to pass information.

Changes Made

TargetFrameworks had been XML elements, but some are not valid XML names. This was changed to being a property on the more generically named TargetFramework element. This also allows for escaping.

Testing

Verified that a simple case that had not previously worked now works and looked at what it produced in a debugger.

Notes

After this PR, the SDK can opt in. Then MSBuild can turn it on by default, and the SDK can stop specifying the property.

Copy link
Member

@benvillalobos benvillalobos left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. I'd be fine with a simple local test of comparing the strings between the way this was done previously, and the new way. Then verify that a stage1 build succesfully builds the repro listed in the original bug. Or just the latter.

foreach (var item in PropertiesAndValues)
{
root.Add(new XElement(item.ItemSpec, item.GetMetadata("Value")));
sb.AppendLine($" <{item.ItemSpec}>{item.GetMetadata("value")}</{item.ItemSpec}>");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the getmetadata search case sensitive? And should there be a tab in the append line?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should be case-insensitive, but there's no reason to test that here...

I had two spaces. That seemed to be how it was with XElement rather than the tab when I was inspecting its escaped form.

Copy link
Member Author

@Forgind Forgind Jul 22, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, I verified that this can build the repro but not that it actually produces correct results, which is why I said it isn't properly tested yet 🙂 In my list of things to do. A test is a good plan.

@Forgind Forgind requested a review from dsplaisted July 22, 2021 21:22
@dsplaisted
Copy link
Member

I think this data is parsed as XML elsewhere, so I don't think this will fix the problem. Instead of allowing invalid XML, I think we should escape characters that aren't valid.

@Forgind
Copy link
Member Author

Forgind commented Jul 23, 2021

I think this data is parsed as XML elsewhere, so I don't think this will fix the problem. Instead of allowing invalid XML, I think we should escape characters that aren't valid.

I just went with this because it made the repro not work anymore.

As far as escaping invalid characters, I tried replacing + with %2b, &2b;, or +, and all of those failed. Is there some other escaping standard I should be using? Should I be replacing it with something like 'literalPlus' in CombineTargetFrameworkInfoProperties and looking for that in CombineXmlElements and replacing it again with +?

@dsplaisted
Copy link
Member

Looks like there's not much we can do to escape characters in an XML name: https://stackoverflow.com/questions/19049954/escape-in-a-element-name-in-xml-file

I think what we should do is that if the ItemSpec isn't a valid XML name, then we should come up with a name that is valid (perhaps by removing invalid characters), and put the real name in an attribute value.

@Forgind
Copy link
Member Author

Forgind commented Jul 26, 2021

So were you thinking something more like this:
Forgind@2525a15
?

(Cleaned up a bit)

@rainersigwald
Copy link
Member

I think what we should do is that if the ItemSpec isn't a valid XML name, then we should come up with a name that is valid (perhaps by removing invalid characters), and put the real name in an attribute value.

Can we instead change the schema to be something like

<Property Name="..." Value="..." />

And then use standard XML escaping to represent anything?

@dsplaisted
Copy link
Member

I think what we should do is that if the ItemSpec isn't a valid XML name, then we should come up with a name that is valid (perhaps by removing invalid characters), and put the real name in an attribute value.

Can we instead change the schema to be something like

<Property Name="..." Value="..." />

And then use standard XML escaping to represent anything?

That would be better, but there's the ValidateExecutableReferences task in dotnet/sdk consumes this XML. So we'd have to figure out how to change the format in a compatible way. It's also possible (though probably unlikely, as this is new code) that there are other consumers of this XML.

@Forgind Forgind force-pushed the combinetargetframeworkproperties-with-plus branch from d597f16 to 7b41f2c Compare July 30, 2021 18:58
@Forgind
Copy link
Member Author

Forgind commented Aug 4, 2021

Hopefully you're fine with how I did this—I made the new schema only activate if you set the UseNewSchema input to be true (it defaults to false), so this should have no impact unless you ask it to.

In SDK-land, then, we can opt into using that and make the relevant changes to ValidateExecutableReferences.

Then MSBuild can remove the UseNewSchema flag and just always use it, and the SDK can stop setting it.

If we don't document it, and we keep it all within one release, hopefully it's fine to tempt users with an extra flag then take it away.

Any other comments or concerns?

They didn't autogenerate for some reason with build.cmd. Had to use the CIBuild.
@dsplaisted
Copy link
Member

I think this is a good idea, but we need a better name for UseNewSchema. For the property, it should probably start with an underscore, and be something like _UseAttributeForTargetFrameworkInfoPropertyNames. Also, the example XML in the documentation should also be updated: https://github.com/dotnet/msbuild/blob/main/documentation/ProjectReference-Protocol.md

@Forgind
Copy link
Member Author

Forgind commented Aug 5, 2021

I can fix that. I was thinking it doesn't matter too much if we want it taken out later, but we definitely don't want someone making explicit use of it before that happens 🙂

I think I should hold off on the documentation change until Then MSBuild can remove the UseNewSchema flag and just always use it, and the SDK can stop setting it. because otherwise anyone trying to understand it would be confused. Hopefully that's no one, but not being able to get something to work in the moment can be frustrating. Maybe I should add a comment saying it's changing so don't assume it's static?

Copy link
Member

@dsplaisted dsplaisted left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

Were you able to do any sanity testing of this?

@Forgind
Copy link
Member Author

Forgind commented Aug 6, 2021

👍

Were you able to do any sanity testing of this?

I know how to do one kind of sanity testing, that is, checking whether the repro still reproduces, in this case with the property enabled, and I can inspect it in the debugger. Is there a more definitive test I can try?

@dsplaisted
Copy link
Member

That sounds good

@Forgind
Copy link
Member Author

Forgind commented Aug 6, 2021

This is what it looks like, by the way:

<Property Name="AdditionalProjectProperties">
  <Property Name="netstandard1.3">
    <SelfContained></SelfContained>
    <_IsExecutable></_IsExecutable>
    <ShouldBeValidatedAsExecutableReference></ShouldBeValidatedAsExecutableReference>
  </Property>
  <Property Name="portable-net45+win8+wp8">
    <SelfContained></SelfContained>
    <_IsExecutable></_IsExecutable>
    <ShouldBeValidatedAsExecutableReference></ShouldBeValidatedAsExecutableReference>
  </Property>
</Property>

I wasn't 100% sure that the second level of escaping was necessary (in CombineXmlElements), but at worst, it shouldn't hurt.

@dsplaisted
Copy link
Member

Actually, let's not do it in CombineXmlElements, that's probably always just going to be AdditionalProjectProperties, and if it's not we still shouldn't need arbitrary property names there, because it's the root element of the XML document.

@Forgind
Copy link
Member Author

Forgind commented Aug 6, 2021

Sounds good. I changed it to look like:

<AdditionalProjectProperties>
  <Property Name="netstandard1.3">
    <SelfContained></SelfContained>
    <_IsExecutable></_IsExecutable>
    <ShouldBeValidatedAsExecutableReference></ShouldBeValidatedAsExecutableReference>
  </Property>
  <Property Name="portable-net45+win8+wp8">
    <SelfContained></SelfContained>
    <_IsExecutable></_IsExecutable>
    <ShouldBeValidatedAsExecutableReference></ShouldBeValidatedAsExecutableReference>
  </Property>
</AdditionalProjectProperties>

@@ -36,9 +37,11 @@ public override bool Execute()
{
if (PropertiesAndValues != null)
{
XElement root = new XElement(RootElementName);
XElement root = UseAttributeForTargetFrameworkInfoPropertyNames ?
new("Property", new XAttribute("Name", EscapingUtilities.Escape(RootElementName))) :
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR Triage: TargetFramework Name=...

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change title pre-merge

@Forgind Forgind changed the title Switch XML manipulations to string manipulations Update schema for combining TargetFramework info to allow for invalid xml names such as including '+' Aug 16, 2021
@Forgind Forgind added the merge-when-branch-open PRs that are approved, except that there is a problem that means we are not merging stuff right now. label Aug 16, 2021
@Forgind Forgind merged commit 00166eb into dotnet:main Aug 16, 2021
@Forgind Forgind deleted the combinetargetframeworkproperties-with-plus branch August 16, 2021 23:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
merge-when-branch-open PRs that are approved, except that there is a problem that means we are not merging stuff right now.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

CombineTargetFrameworkInfoProperties fails on portable framework names
4 participants