-
Notifications
You must be signed in to change notification settings - Fork 1.4k
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
Implementation of implicit imports during evaluation instead of parsing #1492
Changes from all commits
13ad21e
c4736ca
479d25c
f6601ed
8b83d81
98a3d6f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
// Copyright (c) Microsoft. All rights reserved. | ||
// Licensed under the MIT license. See LICENSE file in the project root for full license information. | ||
|
||
namespace Microsoft.Build.Construction | ||
{ | ||
/// <summary> | ||
/// Represents the location of an implicit import. | ||
/// </summary> | ||
public enum ImplicitImportLocation | ||
{ | ||
/// <summary> | ||
/// The import is not implicitly added and is explicitly added in a user-specified location. | ||
/// </summary> | ||
None, | ||
/// <summary> | ||
/// The import was implicitly added at the top of the project. | ||
/// </summary> | ||
Top, | ||
/// <summary> | ||
/// The import was implicitly added at the bottom of the project. | ||
/// </summary> | ||
Bottom | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -157,11 +157,6 @@ public class ProjectRootElement : ProjectElementContainer | |
/// </summary> | ||
private BuildEventContext _buildEventContext; | ||
|
||
/// <summary> | ||
/// Xpath expression that will find any element with the implicit attribute | ||
/// </summary> | ||
private static readonly string ImplicitAttributeXpath = $"//*[@{XMakeAttributes.@implicit}]"; | ||
|
||
/// <summary> | ||
/// Initialize a ProjectRootElement instance from a XmlReader. | ||
/// May throw InvalidProjectFileException. | ||
|
@@ -654,6 +649,28 @@ public string InitialTargets | |
} | ||
} | ||
|
||
/// <summary> | ||
/// Gets or sets a semicolon delimited list of software development kits (SDK) that the project uses. | ||
/// If a value is specified, an Sdk.props is simplicity imported at the top of the project and an | ||
/// Sdk.targets is simplicity imported at the bottom from the specified SDK. | ||
/// If the value is null or empty, removes the attribute. | ||
/// </summary> | ||
public string Sdk | ||
{ | ||
[DebuggerStepThrough] | ||
get | ||
{ | ||
return ProjectXmlUtilities.GetAttributeValue(XmlElement, XMakeAttributes.sdk); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As things get more involved with the SDKs, it might be worth creating a new SDKProjectElement which is represented as an attribute (reusing the way metadata as attributes represent themselves). This type would be a valid child for ProjectRootElements and ProjectImportElements. Then, the new type could gain responsibilities such as parsing the semicolon delimited string into a {name, version} object, doing data validation, etc There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm in favor of putting duplicated logic in a central place, but here I don't think it's helpful to represent it as a child element expressed as an attribute. That just complicates the object model without any benefit that I see, and we can centralize the logic into utility methods or similar without changing the object model. |
||
} | ||
|
||
[DebuggerStepThrough] | ||
set | ||
{ | ||
ProjectXmlUtilities.SetOrRemoveAttribute(XmlElement, XMakeAttributes.sdk, value); | ||
MarkDirty("Set project Sdk to '{0}'", value); | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Gets or sets the value of TreatAsLocalProperty. If there is no tag, returns empty string. | ||
/// If the value being set is null or empty, removes the attribute. | ||
|
@@ -710,10 +727,8 @@ public string RawXml | |
{ | ||
using (ProjectWriter projectWriter = new ProjectWriter(stringWriter)) | ||
{ | ||
var xmlWithNoImplicits = RemoveImplicits(); | ||
|
||
projectWriter.Initialize(xmlWithNoImplicits); | ||
xmlWithNoImplicits.Save(projectWriter); | ||
projectWriter.Initialize(XmlDocument); | ||
XmlDocument.Save(projectWriter); | ||
} | ||
|
||
return stringWriter.ToString(); | ||
|
@@ -848,6 +863,14 @@ public ElementLocation InitialTargetsLocation | |
get { return XmlElement.GetAttributeLocation(XMakeAttributes.initialTargets); } | ||
} | ||
|
||
/// <summary> | ||
/// Location of the Sdk attribute, if any | ||
/// </summary> | ||
public ElementLocation SdkLocation | ||
{ | ||
get { return XmlElement.GetAttributeLocation(XMakeAttributes.sdk); } | ||
} | ||
|
||
/// <summary> | ||
/// Location of the TreatAsLocalProperty attribute, if any | ||
/// </summary> | ||
|
@@ -1752,10 +1775,8 @@ public void Save(Encoding saveEncoding) | |
{ | ||
using (ProjectWriter projectWriter = new ProjectWriter(_projectFileLocation.File, saveEncoding)) | ||
{ | ||
var xmlWithNoImplicits = RemoveImplicits(); | ||
|
||
projectWriter.Initialize(xmlWithNoImplicits); | ||
xmlWithNoImplicits.Save(projectWriter); | ||
projectWriter.Initialize(XmlDocument); | ||
XmlDocument.Save(projectWriter); | ||
} | ||
|
||
_encoding = saveEncoding; | ||
|
@@ -1784,26 +1805,6 @@ public void Save(Encoding saveEncoding) | |
#endif | ||
} | ||
|
||
private XmlDocument RemoveImplicits() | ||
{ | ||
if (XmlDocument.SelectSingleNode(ImplicitAttributeXpath) == null) | ||
{ | ||
return XmlDocument; | ||
} | ||
|
||
var xmlWithNoImplicits = (XmlDocument) XmlDocument.CloneNode(deep: true); | ||
|
||
var implicitElements = | ||
xmlWithNoImplicits.SelectNodes(ImplicitAttributeXpath); | ||
|
||
foreach (XmlNode implicitElement in implicitElements) | ||
{ | ||
implicitElement.ParentNode.RemoveChild(implicitElement); | ||
} | ||
|
||
return xmlWithNoImplicits; | ||
} | ||
|
||
/// <summary> | ||
/// Save the project to the file system, if dirty or the path is different. | ||
/// Creates any necessary directories. | ||
|
@@ -1837,10 +1838,8 @@ public void Save(TextWriter writer) | |
{ | ||
using (ProjectWriter projectWriter = new ProjectWriter(writer)) | ||
{ | ||
var xmlWithNoImplicits = RemoveImplicits(); | ||
|
||
projectWriter.Initialize(xmlWithNoImplicits); | ||
xmlWithNoImplicits.Save(projectWriter); | ||
projectWriter.Initialize(XmlDocument); | ||
XmlDocument.Save(projectWriter); | ||
} | ||
|
||
_versionOnDisk = Version; | ||
|
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 looks like a change in behavior. Does it need to happen for Remove just above this? Or others?
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 is removed because I'm reverting the original implementation where the stuff is added to the XML DOM. There is no
IsImplicit
property anymore so theif
is removed.The change above this is removed for the same reason.