From 863a5dd0860f78ed198ae6a041134b4156635708 Mon Sep 17 00:00:00 2001 From: "Arsen.Shnurkov" Date: Sun, 15 Jan 2017 14:36:15 +0300 Subject: [PATCH] adding tasks programmatically --- mpt-core/03_msbuild/ICan.cs | 21 ++ mpt-core/03_msbuild/MSBuildFile.cs | 232 ++++++++++++++++++ mpt-core/03_msbuild/MSBuildImport.cs | 32 +++ mpt-core/03_msbuild/MSBuildItem.cs | 16 ++ mpt-core/03_msbuild/MSBuildItemGroup.cs | 32 +++ mpt-core/03_msbuild/MSBuildProperty.cs | 41 ++++ mpt-core/03_msbuild/MSBuildPropertyGroup.cs | 55 +++++ mpt-core/03_msbuild/MSBuildTarget.cs | 70 ++++++ mpt-core/03_msbuild/MSBuildTask.cs | 118 +++++++++ mpt-core/03_msbuild/MSBuildTaskParameter.cs | 38 +++ mpt-core/03_msbuild/MSBuildTaskResultItem.cs | 50 ++++ .../03_msbuild/MSBuildTaskResultProperty.cs | 50 ++++ mpt-core/04_CSProj/CSharpLibraryProject.cs | 113 +++++++++ .../{CSProj => 04_CSProj}/Configuration.cs | 0 mpt-core/{sln => 04_CSProj}/ProjectTools.cs | 72 +----- mpt-core/CSProj/CSharpLibraryProject.cs | 21 -- mpt-core/mpt-core.csproj | 22 +- mpt-core/sln/SolutionTools.cs | 12 +- mpt-csproj/Program.cs | 8 +- mpt-csproj/mpt-csproj.csproj | 1 + 20 files changed, 904 insertions(+), 100 deletions(-) create mode 100644 mpt-core/03_msbuild/ICan.cs create mode 100644 mpt-core/03_msbuild/MSBuildFile.cs create mode 100644 mpt-core/03_msbuild/MSBuildImport.cs create mode 100644 mpt-core/03_msbuild/MSBuildItem.cs create mode 100644 mpt-core/03_msbuild/MSBuildItemGroup.cs create mode 100644 mpt-core/03_msbuild/MSBuildProperty.cs create mode 100644 mpt-core/03_msbuild/MSBuildPropertyGroup.cs create mode 100644 mpt-core/03_msbuild/MSBuildTarget.cs create mode 100644 mpt-core/03_msbuild/MSBuildTask.cs create mode 100644 mpt-core/03_msbuild/MSBuildTaskParameter.cs create mode 100644 mpt-core/03_msbuild/MSBuildTaskResultItem.cs create mode 100644 mpt-core/03_msbuild/MSBuildTaskResultProperty.cs create mode 100644 mpt-core/04_CSProj/CSharpLibraryProject.cs rename mpt-core/{CSProj => 04_CSProj}/Configuration.cs (100%) rename mpt-core/{sln => 04_CSProj}/ProjectTools.cs (81%) delete mode 100644 mpt-core/CSProj/CSharpLibraryProject.cs diff --git a/mpt-core/03_msbuild/ICan.cs b/mpt-core/03_msbuild/ICan.cs new file mode 100644 index 0000000..5c77b34 --- /dev/null +++ b/mpt-core/03_msbuild/ICan.cs @@ -0,0 +1,21 @@ +using System.Collections.Generic; +using System.Xml; + +public interface IHaveUnderlyingNode +{ + XmlNode UnderlyingNode { get; } +} + +public interface ICanHaveProperties : IHaveUnderlyingNode +{ +} + +public interface ICanHaveItems : IHaveUnderlyingNode +{ +} + +public interface ICanBeConditional +{ + string Condition { get; set; } +} + diff --git a/mpt-core/03_msbuild/MSBuildFile.cs b/mpt-core/03_msbuild/MSBuildFile.cs new file mode 100644 index 0000000..f655a0c --- /dev/null +++ b/mpt-core/03_msbuild/MSBuildFile.cs @@ -0,0 +1,232 @@ +using System; +using System.Collections.Generic; +using System.Xml.XPath; +using System.Xml; + +public class MSBuildFile : IDisposable +{ + public const string NamespaceName = "http://schemas.microsoft.com/developer/msbuild/2003"; + XmlDocument doc; + bool bSaveRequired = false; + string filename = null; + List importNodes = new List(); + List targetNodes = new List(); + public XmlDocument UnderlyingObject + { + get + { + return doc; + } + } + public string FileName + { + get + { + return filename; + } + set + { + filename = value; + } + } + + public MSBuildFile(XmlDocument d) + { + this.doc = d; + } + public MSBuildFile(string filename) + { + XmlDocument d = new XmlDocument(); + d.Load(filename); + this.doc = d; + FindAllImports(); + FindAllTargets(); + } + + public void Dispose() + { + if (bSaveRequired && String.IsNullOrWhiteSpace(filename) == false) + { + doc.Save(filename); + } + } + + public void AddTarget(MSBuildTarget target) + { + // it does not automatically add the new object to the document tree. + // To add the new object, one must explicitly call one of the node insert methods. + XmlNode n = target.UnderlyingObject; + XPathNavigator locator = doc.CreateNavigator(); + locator.MoveToRoot(); + XmlNode root = locator.UnderlyingObject as XmlNode; + if (locator.MoveToFirstChild() == false) + { + root.AppendChild(n); + } + else + { + while (locator.MoveToNext()) { }; + XmlNode sibling = locator.UnderlyingObject as XmlNode; + root.InsertAfter(n, sibling); + } + bSaveRequired = true; + } + + static bool IsAlreadyExists(string import_name, XmlNamespaceManager xmlNamespaceManager, XPathNavigator navigator) + { + var xpath1 = "/ns:Project/ns:Import[@Project='" + import_name + "']"; + XPathExpression expr1 = navigator.Compile(xpath1); + expr1.SetContext(xmlNamespaceManager); + var nodeIterator1 = navigator.Select(expr1); + if (nodeIterator1.Count > 0) + { + return true; + } + return false; + } + + public MSBuildImport CreateImport() + { + var result = new MSBuildImport(this); + return result; + } + + public void FindAllImports() + { + var xmlNamespaceManager = new XmlNamespaceManager(new NameTable()); + xmlNamespaceManager.AddNamespace("ns", MSBuildFile.NamespaceName); + + XPathNavigator navigator = doc.CreateNavigator(); + navigator.MoveToRoot(); + + var xpath = "/ns:Project/ns:Import[@Project]"; + XPathExpression expr = navigator.Compile(xpath); + expr.SetContext(xmlNamespaceManager); + + var nodeIterator = navigator.Select(expr); + if (nodeIterator.Count == 0) + { + return; + } + do + { + if (nodeIterator.Current is IHasXmlNode) + { + XmlElement node = (XmlElement)((IHasXmlNode)nodeIterator.Current).GetNode(); + MSBuildImport wrapperObject = new MSBuildImport(this, node); + importNodes.Add(wrapperObject); + } + } + while (nodeIterator.MoveNext()); // see also https://weblogs.asp.net/cazzu/86609 + } + + // locate if there is import of Microsoft.CSharp.targets + public MSBuildImport FindImport(string v) + { + foreach (MSBuildImport item in this.importNodes) + { + if (string.Compare(item.Project, v) == 0) + { + return item; + } + } + return null; + } + + public void InsertImport(MSBuildImport newImport) + { + if (FindImport(newImport.Project) != null) + { + return; + } + + // запомнить у себя + this.importNodes.Add(newImport); + + // у тебя в руках узел, но оне вставленный в XML-документ + XmlElement newXmlElement = newImport.UnderlyingObject; + + XPathNavigator navigator = doc.CreateNavigator(); + navigator.MoveToRoot(); + + XmlElement root = (XmlElement)navigator.UnderlyingObject; + root.AppendChild(newXmlElement); + } + + public void InsertImportAfter(MSBuildImport existingImport, MSBuildImport newImport) + { + // запомнить у себя + this.importNodes.Add(newImport); + // вставить в нижележащий слой + XmlElement existingElement = existingImport.UnderlyingObject; + XmlElement newElement = newImport.UnderlyingObject; + existingElement.ParentNode.InsertAfter(existingElement, newElement); + } + + public MSBuildTarget CreateTarget() + { + var result = new MSBuildTarget(this); + return result; + } + + public void FindAllTargets() + { + var xmlNamespaceManager = new XmlNamespaceManager(new NameTable()); + xmlNamespaceManager.AddNamespace("ns", MSBuildFile.NamespaceName); + + XPathNavigator navigator = doc.CreateNavigator(); + navigator.MoveToRoot(); + + var xpath = "/ns:Project/ns:Target[@Name]"; + XPathExpression expr = navigator.Compile(xpath); + expr.SetContext(xmlNamespaceManager); + + var nodeIterator = navigator.Select(expr); + if (nodeIterator.Count == 0) + { + return; + } + do + { + if (nodeIterator.Current is IHasXmlNode) + { + XmlElement node = (XmlElement)((IHasXmlNode)nodeIterator.Current).GetNode(); + MSBuildTarget wrapperObject = new MSBuildTarget(this, node); + targetNodes.Add(wrapperObject); + } + } + while (nodeIterator.MoveNext()); // see also https://weblogs.asp.net/cazzu/86609 + } + + public MSBuildTarget FindTarget(string v) + { + foreach (MSBuildTarget item in this.targetNodes) + { + if (string.Compare(item.Name, v) == 0) + { + return item; + } + } + return null; + } + + public void InsertTarget(MSBuildTarget newTarget) + { + if (FindTarget(newTarget.Name) != null) + { + return; + } + + // запомнить у себя + this.targetNodes.Add(newTarget); + + // у тебя в руках узел, но оне вставленный в XML-документ + XmlElement newXmlElement = newTarget.UnderlyingObject; + + XPathNavigator navigator = doc.CreateNavigator(); + navigator.MoveToRoot(); + + XmlElement root = (XmlElement)navigator.UnderlyingObject; + root.AppendChild(newXmlElement); + } +} diff --git a/mpt-core/03_msbuild/MSBuildImport.cs b/mpt-core/03_msbuild/MSBuildImport.cs new file mode 100644 index 0000000..fc25eb0 --- /dev/null +++ b/mpt-core/03_msbuild/MSBuildImport.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Xml; + +public class MSBuildImport +{ + MSBuildFile file; + XmlElement uo; + + public XmlElement UnderlyingObject + { + get + { + return uo; + } + } + + public string Project { get { return uo.Attributes["Project"].Value; } set { uo.Attributes["Project"].Value = value; } } + + public MSBuildImport(MSBuildFile f, XmlElement el) + { + this.file = f; + uo = el; + } + + public MSBuildImport(MSBuildFile f) + { + this.file = f; + // string element = ""; + uo = (XmlElement)file.UnderlyingObject.CreateNode(XmlNodeType.Element, "Import", this.uo.NamespaceURI); + } +} diff --git a/mpt-core/03_msbuild/MSBuildItem.cs b/mpt-core/03_msbuild/MSBuildItem.cs new file mode 100644 index 0000000..905528d --- /dev/null +++ b/mpt-core/03_msbuild/MSBuildItem.cs @@ -0,0 +1,16 @@ +using System; +using System.Xml; + +public class MSBuildItem +{ + XmlElement uo; + + public XmlElement UnderlyingObject { get { return uo; } } + + public MSBuildItem(MSBuildItemGroup parent) + { + XmlDocument doc = parent.UnderlyingObject.OwnerDocument; + uo = (XmlElement)doc.CreateNode(XmlNodeType.Element, "UndefilnedItemName", doc.NamespaceURI); + } +} + diff --git a/mpt-core/03_msbuild/MSBuildItemGroup.cs b/mpt-core/03_msbuild/MSBuildItemGroup.cs new file mode 100644 index 0000000..1d4ad15 --- /dev/null +++ b/mpt-core/03_msbuild/MSBuildItemGroup.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Xml; + +public class MSBuildItemGroup +{ + XmlElement uo; + + public XmlElement UnderlyingObject { get { return uo; } } + + IEnumerable Items { get; } + + //ICanHaveItems parent; + + public MSBuildItemGroup(ICanHaveItems parent) + { + //this.parent = parent; + XmlDocument doc = parent.UnderlyingNode.OwnerDocument; + uo = (XmlElement)doc.CreateNode(XmlNodeType.Element, "UndefilnedItemName", doc.NamespaceURI); + } + + public MSBuildItem CreateItem() + { + MSBuildItem res = new MSBuildItem(this); + return res; + } + public void AppendItem(MSBuildItem item) + { + throw new NotImplementedException(); + } +} + diff --git a/mpt-core/03_msbuild/MSBuildProperty.cs b/mpt-core/03_msbuild/MSBuildProperty.cs new file mode 100644 index 0000000..4b6486c --- /dev/null +++ b/mpt-core/03_msbuild/MSBuildProperty.cs @@ -0,0 +1,41 @@ +using System; +using System.Xml; + +public class MSBuildProperty +{ + XmlElement uo; + + public XmlElement UnderlyingObject { get { return uo; } } + + public string Name { get { return uo.LocalName; } set { SetName(value); } } + public string Value { get { return uo.Value; } set { uo.Value = value; } } + + public MSBuildProperty(MSBuildPropertyGroup parent) + { + XmlDocument doc = parent.UnderlyingObject.OwnerDocument; + uo = (XmlElement)doc.CreateNode(XmlNodeType.Element, "UndefilnedPropertyName", doc.NamespaceURI); + } + + void SetName(string name) + { + // replace underlaying object to change it's name + XmlElement oldItem = uo; + XmlDocument doc = oldItem.OwnerDocument; + // replace name + uo = (XmlElement)doc.CreateNode(XmlNodeType.Element, name, doc.NamespaceURI); + uo.Value = oldItem.Value; + // copy attributes + foreach (XmlAttribute a in oldItem.Attributes) + { + uo.Attributes.Append((XmlAttribute)a.CloneNode(true)); + } + // copy childs + for (XmlNode child = oldItem.FirstChild; child != null; child = child.NextSibling) + { + uo.AppendChild(child.CloneNode(true)); + } + // what about node's text content ? + //uo.Value = oldItem.Value; + oldItem.ParentNode.ReplaceChild(uo, oldItem); + } +} diff --git a/mpt-core/03_msbuild/MSBuildPropertyGroup.cs b/mpt-core/03_msbuild/MSBuildPropertyGroup.cs new file mode 100644 index 0000000..6262e32 --- /dev/null +++ b/mpt-core/03_msbuild/MSBuildPropertyGroup.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections.Generic; +using System.Xml; + +public class MSBuildPropertyGroup : ICanBeConditional +{ + XmlElement uo; + List properties = new List(); + + public XmlElement UnderlyingObject { get { return uo; } } + public IEnumerable Properties { get { return properties; } } + + public string Condition { get { return GetCondition(); } set { SetCondition(value); } } + + public MSBuildPropertyGroup(ICanHaveProperties parent) + { + //this.parent = parent; + XmlDocument doc = parent.UnderlyingNode.OwnerDocument; + uo = (XmlElement)doc.CreateNode(XmlNodeType.Element, "PropertyGroup", doc.NamespaceURI); + } + + string GetCondition() + { + if (uo.HasAttribute("Condition") == false) return null; + return uo.Attributes["Condition"].Value; + } + + void SetCondition(string value) + { + uo.SetAttribute("Condition", value); + } + + public MSBuildProperty CreateProperty() + { + MSBuildProperty res = new MSBuildProperty(this); + return res; + } + + public void AppendProperty(MSBuildProperty item) + { + // insert on this level + this.properties.Add(item); + // insert on underlaying level + XmlNode tn = item.UnderlyingObject; + uo.AppendChild(tn); + } + + public void AddProperty(string name, string val) + { + MSBuildProperty prop = this.CreateProperty(); + prop.Name = name; + prop.Value = val; + this.AppendProperty(prop); + } +} diff --git a/mpt-core/03_msbuild/MSBuildTarget.cs b/mpt-core/03_msbuild/MSBuildTarget.cs new file mode 100644 index 0000000..2b50eea --- /dev/null +++ b/mpt-core/03_msbuild/MSBuildTarget.cs @@ -0,0 +1,70 @@ +using System; +using System.Collections.Generic; +using System.Xml; + +public class MSBuildTarget : ICanHaveProperties, ICanHaveItems +{ + MSBuildFile file; + XmlElement uo; + List propertyGroups = new List(); + List tasks = new List(); + List items = new List(); + + public string Name { get { return uo.Attributes["Name"].Value; } set { uo.Attributes["Name"].Value = value; } } + public IEnumerable Tasks { get { return tasks; } } + public XmlElement UnderlyingObject { get { return uo; } } + public XmlNode UnderlyingNode { get { return UnderlyingObject; } } + public IEnumerable PropertyGroups {get { return propertyGroups; } } + public IEnumerable Items { get { return items; } } + + public MSBuildTarget(MSBuildFile f) + { + this.file = f; + uo = (XmlElement)file.UnderlyingObject.CreateNode(XmlNodeType.Element, "Target", this.uo.NamespaceURI); + } + + public MSBuildTarget(MSBuildFile f, XmlElement el) + { + this.file = f; + uo = el; + } + + public MSBuildTask CreateTask() + { + MSBuildTask res = new MSBuildTask(this); + return res; + } + + public MSBuildPropertyGroup CreatePropertyGroup() + { + MSBuildPropertyGroup res = new MSBuildPropertyGroup(this); + return res; + } + + public void AppendTask(MSBuildTask task) + { + // insert on this level + this.tasks.Add(task); + // insert on underlaying level + XmlNode tn = task.UnderlyingObject; + uo.AppendChild(tn); + } + + public void AppendPropertyGroup(MSBuildPropertyGroup item) + { + // insert on this level + this.propertyGroups.Add(item); + // insert on underlaying level + XmlNode tn = item.UnderlyingObject; + uo.AppendChild(tn); + } + + public void AppendItem(MSBuildItem item) + { + // insert on this level + this.items.Add(item); + // insert on underlaying level + XmlNode tn = item.UnderlyingObject; + uo.AppendChild(tn); + } +} diff --git a/mpt-core/03_msbuild/MSBuildTask.cs b/mpt-core/03_msbuild/MSBuildTask.cs new file mode 100644 index 0000000..71146d0 --- /dev/null +++ b/mpt-core/03_msbuild/MSBuildTask.cs @@ -0,0 +1,118 @@ +using System; +using System.Collections.Generic; +using System.Xml; + +public class MSBuildTask : ICanBeConditional +{ + MSBuildTarget parent; + XmlElement uo; + List parameters = new List(); + List resultProperties = new List(); + List resultItems = new List(); + public XmlNode UnderlyingObject + { + get + { + return uo; + } + } + + public string Condition { get { return GetCondition(); } set { SetCondition(value); } } + + public string Name { get { return uo.LocalName; } set { SetName(value); } } + + public MSBuildTask(MSBuildTarget p) + { + string name = "NoXmlElementName"; + this.parent = p; + XmlDocument doc = parent.UnderlyingObject.OwnerDocument; + uo = (XmlElement)doc.CreateNode(XmlNodeType.Element, name, doc.NamespaceURI); + } + + void SetName(string name) + { + // replace underlaying object to change it's name + XmlElement oldItem = uo; + XmlDocument doc = oldItem.OwnerDocument; + // replace name + uo = (XmlElement)doc.CreateNode(XmlNodeType.Element, name, doc.NamespaceURI); + uo.Value = oldItem.Value; + // copy attributes + foreach (XmlAttribute a in oldItem.Attributes) + { + uo.Attributes.Append((XmlAttribute)a.CloneNode(true)); + } + // copy childs + for (XmlNode child = oldItem.FirstChild; child != null; child = child.NextSibling) + { + uo.AppendChild(child.CloneNode(true)); + } + // what about node's text content ? + //uo.Value = oldItem.Value; + oldItem.ParentNode.ReplaceChild(uo, oldItem); + } + + public MSBuildTaskParameter CreateParameter() + { + MSBuildTaskParameter res = new MSBuildTaskParameter(this); + return res; + } + + public MSBuildTaskResultProperty CreateResultProperty() + { + MSBuildTaskResultProperty res = new MSBuildTaskResultProperty(this); + return res; + } + + public MSBuildTaskResultItem CreateResultItem() + { + MSBuildTaskResultItem res = new MSBuildTaskResultItem(this); + return res; + } + + public void AppendParameter(MSBuildTaskParameter attribute) + { + // insert on this level + this.parameters.Add(attribute); + // insert on underlaying level + XmlAttribute tn = attribute.UnderlyingObject; + uo.SetAttributeNode(tn); + } + + public void AppendResultProperty(MSBuildTaskResultProperty subNode) + { + // insert on this level + this.resultProperties.Add(subNode); + // insert on underlaying level + XmlNode tn = subNode.UnderlyingObject; + uo.AppendChild(tn); + } + + public void AppendResultItem(MSBuildTaskResultItem subNode) + { + // insert on this level + this.resultItems.Add(subNode); + // insert on underlaying level + XmlNode tn = subNode.UnderlyingObject; + uo.AppendChild(tn); + } + + public void AddParameter(string name, string val) + { + MSBuildTaskParameter parameter = this.CreateParameter(); + parameter.Name = name; + parameter.Value = val; + this.AppendParameter(parameter); + } + + string GetCondition() + { + if (uo.HasAttribute("Condition") == false) return null; + return uo.Attributes["Condition"].Value; + } + + void SetCondition(string value) + { + uo.SetAttribute("Condition", value); + } +} diff --git a/mpt-core/03_msbuild/MSBuildTaskParameter.cs b/mpt-core/03_msbuild/MSBuildTaskParameter.cs new file mode 100644 index 0000000..bb88a73 --- /dev/null +++ b/mpt-core/03_msbuild/MSBuildTaskParameter.cs @@ -0,0 +1,38 @@ +using System; +using System.Xml; + +public class MSBuildTaskParameter +{ + // https://github.com/mono/mono/blob/master/mcs/class/referencesource/System.Xml/System/Xml/Dom/XmlAttribute.cs + XmlAttribute uo; + MSBuildTask parent; + + public XmlAttribute UnderlyingObject + { + get + { + return uo; + } + } + + public string Name { get { return uo.LocalName; } set { SetName(value); } } + public string Value { get { return uo.Value; } set { uo.Value = value; } } + + public MSBuildTaskParameter(MSBuildTask p) + { + string name = "NoAttributeNameGiven"; + this.parent = p; + XmlDocument doc = parent.UnderlyingObject.OwnerDocument; + uo = (XmlAttribute)doc.CreateNode(XmlNodeType.Attribute, name, doc.NamespaceURI); + } + + void SetName(string name) + { + // replace underlaying object to change it's name + XmlAttribute oldAttr = uo; + XmlDocument doc = oldAttr.OwnerDocument; + uo = (XmlAttribute)doc.CreateNode(XmlNodeType.Attribute, name, doc.NamespaceURI); + uo.Value = oldAttr.Value; + oldAttr.ParentNode.ReplaceChild(uo, oldAttr); + } +} diff --git a/mpt-core/03_msbuild/MSBuildTaskResultItem.cs b/mpt-core/03_msbuild/MSBuildTaskResultItem.cs new file mode 100644 index 0000000..fae1689 --- /dev/null +++ b/mpt-core/03_msbuild/MSBuildTaskResultItem.cs @@ -0,0 +1,50 @@ +using System; +using System.Xml; + +public class MSBuildTaskResultItem +{ + // https://github.com/mono/mono/blob/master/mcs/class/referencesource/System.Xml/System/Xml/Dom/XmlAttribute.cs + XmlElement uo; + MSBuildTask parent; + + public XmlElement UnderlyingObject + { + get + { + return uo; + } + } + + public string TaskParameter { get { return uo.Attributes["TaskParameter"].Value; } set { uo.Attributes["TaskParameter"].Value = value; } } + public string ItemName { get { return uo.Attributes["ItemName"].Value; } set { uo.Attributes["ItemName"].Value = value; } } + + public MSBuildTaskResultItem(MSBuildTask p) + { + this.parent = p; + XmlDocument doc = parent.UnderlyingObject.OwnerDocument; + uo = (XmlElement)doc.CreateNode(XmlNodeType.Element, "Output", doc.NamespaceURI); + } + + void SetName(string name) + { + // replace underlaying object to change it's name + XmlElement oldItem = uo; + XmlDocument doc = oldItem.OwnerDocument; + // replace name + uo = (XmlElement)doc.CreateNode(XmlNodeType.Element, name, doc.NamespaceURI); + uo.Value = oldItem.Value; + // copy attributes + foreach (XmlAttribute a in oldItem.Attributes) + { + uo.Attributes.Append((XmlAttribute)a.CloneNode(true)); + } + // copy childs + for (XmlNode child = oldItem.FirstChild; child != null; child = child.NextSibling) + { + uo.AppendChild(child.CloneNode(true)); + } + // what about node's text content ? + //uo.Value = oldItem.Value; + oldItem.ParentNode.ReplaceChild(uo, oldItem); + } +} diff --git a/mpt-core/03_msbuild/MSBuildTaskResultProperty.cs b/mpt-core/03_msbuild/MSBuildTaskResultProperty.cs new file mode 100644 index 0000000..ddc50bf --- /dev/null +++ b/mpt-core/03_msbuild/MSBuildTaskResultProperty.cs @@ -0,0 +1,50 @@ +using System; +using System.Xml; + +public class MSBuildTaskResultProperty +{ + // https://github.com/mono/mono/blob/master/mcs/class/referencesource/System.Xml/System/Xml/Dom/XmlAttribute.cs + XmlElement uo; + MSBuildTask parent; + + public XmlElement UnderlyingObject + { + get + { + return uo; + } + } + + public string TaskParameter { get { return uo.Attributes["TaskParameter"].Value; } set { uo.Attributes["TaskParameter"].Value = value; } } + public string Value { get { return uo.Value; } set { uo.Value = value; } } + + public MSBuildTaskResultProperty(MSBuildTask p) + { + this.parent = p; + XmlDocument doc = parent.UnderlyingObject.OwnerDocument; + uo = (XmlElement)doc.CreateNode(XmlNodeType.Element, "Output", doc.NamespaceURI); + } + + void SetName(string name) + { + // replace underlaying object to change it's name + XmlElement oldItem = uo; + XmlDocument doc = oldItem.OwnerDocument; + // replace name + uo = (XmlElement)doc.CreateNode(XmlNodeType.Element, name, doc.NamespaceURI); + uo.Value = oldItem.Value; + // copy attributes + foreach (XmlAttribute a in oldItem.Attributes) + { + uo.Attributes.Append((XmlAttribute)a.CloneNode(true)); + } + // copy childs + for (XmlNode child = oldItem.FirstChild; child != null; child = child.NextSibling) + { + uo.AppendChild(child.CloneNode(true)); + } + // what about node's text content ? + //uo.Value = oldItem.Value; + oldItem.ParentNode.ReplaceChild(uo, oldItem); + } +} diff --git a/mpt-core/04_CSProj/CSharpLibraryProject.cs b/mpt-core/04_CSProj/CSharpLibraryProject.cs new file mode 100644 index 0000000..8ee06fb --- /dev/null +++ b/mpt-core/04_CSProj/CSharpLibraryProject.cs @@ -0,0 +1,113 @@ +using System; + +public class CSharpLibraryProject : IDisposable +{ + MSBuildFile uo; + + ConfigurationHashList configurations = null; + public ConfigurationHashList Configurations { get { return configurations; } } + + public string FileName { get { return uo.FileName; } set { uo.FileName = value; } } + + public CSharpLibraryProject(string csproj_file) + { + configurations = new ConfigurationHashList(this); + uo = new MSBuildFile(csproj_file); + } + + public void Dispose() + { + uo.Dispose(); + } + + public void InjectProjectImport(string import_name) + { + // construct new import + MSBuildImport newImport = uo.CreateImport(); + newImport.Project = import_name; + // insert import + MSBuildImport existingImport = uo.FindImport("$(MSBuildBinPath)\\Microsoft.CSharp.targets"); + if (existingImport == null) + { + uo.InsertImport(newImport); + } + else + { + uo.InsertImportAfter(existingImport, newImport); + } + } + + public void InjectVersioning() + { + /* + + + + + + + */ + MSBuildTarget targ = uo.CreateTarget(); + targ.Name = "MyAssemblyVersion"; + { + MSBuildTask task = targ.CreateTask(); + task.Name = "MakeDir"; + task.AddParameter("Directories", "$(IntermediateOutputPath)"); + targ.AppendTask(task); + } + { + MSBuildTask task = targ.CreateTask(); + task.Name = "AssemblyInfo"; + task.AddParameter("CodeLanguage", "CS"); + + task.AddParameter("AssemblyVersion", "$(VersionNumber)"); // System.Reflection.AssemblyVersion + task.AddParameter("AssemblyFileVersion", "$(VersionNumber)"); // System.Reflection.AssemblyFileVersion + task.AddParameter("AssemblyInformationalVersion", "$(VersionNumber)"); // System.Reflection.AssemblyInformationalVersion + + task.AddParameter("OutputFile", "$(IntermediateOutputPath)AssemblyVersion.Generated.cs"); + { + MSBuildTaskResultItem resultItem = task.CreateResultItem(); + resultItem.TaskParameter = "OutputFile"; + resultItem.ItemName = "Compile"; + task.AppendResultItem(resultItem); + } + targ.AppendTask(task); + } + uo.InsertTarget(targ); + } + + // http://stackoverflow.com/questions/30943342/how-to-use-internalsvisibleto-attribute-with-strongly-named-assembly + public void InjectInternalsVisibleTo(string assemblyName, string assemblyPublicKey) + { + MSBuildTarget targ = uo.CreateTarget(); + targ.Name = "MyInsertInternalsTo"; + { + MSBuildPropertyGroup group = targ.CreatePropertyGroup(); + group.Condition = " '$(VersionNumber)' == '' "; + group.AddProperty("VersionNumber", "1.0.0.0"); + targ.AppendPropertyGroup(group); + } + { + MSBuildTask task = targ.CreateTask(); // '$(SignAssembly)' == 'true' + task.Name = "AssemblyInfo"; + task.Condition = "'$(SignAssembly)' == 'true'"; + task.AddParameter("InternalsVisibleTo", assemblyName + ", PublicKey=" + assemblyPublicKey); + task.AddParameter("OutputFile", "$(IntermediateOutputPath)" + assemblyName + ".IVT.Generated.cs"); + targ.AppendTask(task); + } + { + MSBuildTask task = targ.CreateTask(); // '$(SignAssembly)' == 'false' + task.Name = "AssemblyInfo"; + task.Condition = "'$(SignAssembly)' != 'true'"; + task.AddParameter("InternalsVisibleTo", assemblyName); + task.AddParameter("OutputFile", "$(IntermediateOutputPath)" + assemblyName + ".IVT.Generated.cs"); + targ.AppendTask(task); + } + uo.InsertTarget(targ); + } +} diff --git a/mpt-core/CSProj/Configuration.cs b/mpt-core/04_CSProj/Configuration.cs similarity index 100% rename from mpt-core/CSProj/Configuration.cs rename to mpt-core/04_CSProj/Configuration.cs diff --git a/mpt-core/sln/ProjectTools.cs b/mpt-core/04_CSProj/ProjectTools.cs similarity index 81% rename from mpt-core/sln/ProjectTools.cs rename to mpt-core/04_CSProj/ProjectTools.cs index 47bf5d4..eb73b98 100644 --- a/mpt-core/sln/ProjectTools.cs +++ b/mpt-core/04_CSProj/ProjectTools.cs @@ -8,7 +8,6 @@ public class ProjectTools { - private const string namespaceName = "http://schemas.microsoft.com/developer/msbuild/2003"; public static void DumpFiles(string projectFilename, string baseDirectory) { List files = new List(); @@ -16,7 +15,7 @@ public static void DumpFiles(string projectFilename, string baseDirectory) var stream = new MemoryStream(File.ReadAllBytes(projectFilename)); // cache file in memoty var document = XDocument.Load(stream); var xmlNamespaceManager = new XmlNamespaceManager(new NameTable()); - xmlNamespaceManager.AddNamespace("ns", namespaceName); + xmlNamespaceManager.AddNamespace("ns", MSBuildFile.NamespaceName); IEnumerable listOfSourceFiles = document.XPathSelectElements("/ns:Project/ns:ItemGroup/ns:Compile[@Include]", xmlNamespaceManager); foreach (var el in listOfSourceFiles) { @@ -61,7 +60,7 @@ public static void DumpRefs(string projectFilename, string baseDirectory) var stream = new MemoryStream(File.ReadAllBytes(projectFilename)); // cache file in memoty var document = XDocument.Load(stream); var xmlNamespaceManager = new XmlNamespaceManager(new NameTable()); - xmlNamespaceManager.AddNamespace("ns", namespaceName); + xmlNamespaceManager.AddNamespace("ns", MSBuildFile.NamespaceName); IEnumerable listOfSourceFiles = document.XPathSelectElements("/ns:Project/ns:ItemGroup/ns:Reference[@Include]", xmlNamespaceManager); foreach (var el in listOfSourceFiles) { @@ -77,7 +76,7 @@ public static void DumpProjRefs(string projectFilename, string baseDirectory) var stream = new MemoryStream(File.ReadAllBytes(projectFilename)); // cache file in memoty var document = XDocument.Load(stream); var xmlNamespaceManager = new XmlNamespaceManager(new NameTable()); - xmlNamespaceManager.AddNamespace("ns", namespaceName); + xmlNamespaceManager.AddNamespace("ns", MSBuildFile.NamespaceName); IEnumerable listOfSourceFiles = document.XPathSelectElements("/ns:Project/ns:ItemGroup/ns:ProjectReference[@Include]", xmlNamespaceManager); foreach (var el in listOfSourceFiles) { @@ -192,7 +191,7 @@ public static void RemoveSigning(string csproj_file, string as_unified_patch) var stream = new MemoryStream(File.ReadAllBytes(csproj_file)); // cache file in memoty var document = XDocument.Load(stream); var xmlNamespaceManager = new XmlNamespaceManager(new NameTable()); - xmlNamespaceManager.AddNamespace("ns", namespaceName); + xmlNamespaceManager.AddNamespace("ns", MSBuildFile.NamespaceName); // remove SignAssembly var itemsToRemove1 = new List(); @@ -263,7 +262,7 @@ public static void ReplaceReference(string csproj_file, string reference_name, b var stream = new MemoryStream(File.ReadAllBytes(csproj_file)); // cache file in memoty var document = XDocument.Load(stream); var xmlNamespaceManager = new XmlNamespaceManager(new NameTable()); - xmlNamespaceManager.AddNamespace("ns", namespaceName); + xmlNamespaceManager.AddNamespace("ns", MSBuildFile.NamespaceName); // remove ProjectReference var itemsToRemove2 = new List(); @@ -328,65 +327,4 @@ public static void ReplaceReference(string csproj_file, string reference_name, b document.Save(csproj_file); } } - - static bool IsAlreadyExists(string import_name, XmlNamespaceManager xmlNamespaceManager, XPathNavigator navigator) - { - var xpath1 = "/ns:Project/ns:Import[@Project='" + import_name + "']"; - XPathExpression expr1 = navigator.Compile(xpath1); - expr1.SetContext(xmlNamespaceManager); - var nodeIterator1 = navigator.Select(expr1); - if (nodeIterator1.Count > 0) - { - return true; - } - return false; - } - - public static void InjectProjectImport(string csproj_file, string import_name) - { - string element = ""; - - var stream = new MemoryStream(File.ReadAllBytes(csproj_file)); // cache file in memoty - var document = new XmlDocument(); - document.Load(stream); - - var xmlNamespaceManager = new XmlNamespaceManager(new NameTable()); - xmlNamespaceManager.AddNamespace("ns", namespaceName); - - // locate if there is import of Microsoft.CSharp.targets - var navigator = document.CreateNavigator(); - navigator.MoveToRoot(); - if (IsAlreadyExists(import_name, xmlNamespaceManager, navigator) == false) - { - - //var xpath1 = "/Project/Import[@Project='$(MSBuildToolsPath)\\Microsoft.CSharp.targets']"; - //var xpath2 = "/Project/Import[@Project='$(MSBuildBinPath)\\Microsoft.CSharp.targets']"; - var xpath = "/ns:Project/ns:Import[@Project='$(MSBuildBinPath)\\Microsoft.CSharp.targets']"; - XPathExpression expr = navigator.Compile(xpath); - expr.SetContext(xmlNamespaceManager); - var nodeIterator = navigator.Select(expr); - if (nodeIterator.Count == 0) - { - // Insert project import to end of file - var ce = navigator.CanEdit; - navigator.MoveToRoot(); - navigator.MoveToFirstChild(); - navigator.AppendChild(element); - } - else - { - nodeIterator.MoveNext(); - // remove comment, if it is present - XPathNavigator pn = nodeIterator.Current.CreateNavigator(); - pn.MoveToNext(); - var s = "To modify your build process, add your task inside one of the targets below and uncomment it."; - if (pn.Value.Contains(s)) - { - pn.DeleteSelf(); - } - nodeIterator.Current.InsertAfter(element); - } - document.Save(csproj_file); - } - } } diff --git a/mpt-core/CSProj/CSharpLibraryProject.cs b/mpt-core/CSProj/CSharpLibraryProject.cs deleted file mode 100644 index 476f751..0000000 --- a/mpt-core/CSProj/CSharpLibraryProject.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System; -using System.Collections.Generic; -using CWDev.SLNTools.Core; - -public class CSharpLibraryProject : Project -{ - ConfigurationHashList configurations = null; - public ConfigurationHashList Configurations - { - get - { - return configurations; - } - } - public CSharpLibraryProject(SolutionFile container, string projectGuid, string projectTypeGuid, string projectName, string relativePath, string parentFolderGuid, IEnumerable
projectSections, IEnumerable versionControlLines, IEnumerable projectConfigurationPlatformsLines) - : base(container, projectGuid, projectTypeGuid, projectName, relativePath, parentFolderGuid, projectSections, versionControlLines, projectConfigurationPlatformsLines) - { - configurations = new ConfigurationHashList(this); - } -} - diff --git a/mpt-core/mpt-core.csproj b/mpt-core/mpt-core.csproj index 5eedce7..35b7fad 100644 --- a/mpt-core/mpt-core.csproj +++ b/mpt-core/mpt-core.csproj @@ -53,16 +53,30 @@ - - - + + + + + + + + + + + + + + + - + + + diff --git a/mpt-core/sln/SolutionTools.cs b/mpt-core/sln/SolutionTools.cs index 2969564..9e6d4ae 100644 --- a/mpt-core/sln/SolutionTools.cs +++ b/mpt-core/sln/SolutionTools.cs @@ -30,14 +30,12 @@ public static void ProcessReferences(string solutionFullPath) var projList = sln.Projects; foreach (var p in projList) { - if (p is CSharpLibraryProject) + string fileNath = p.FullPath; + Console.WriteLine(fileNath); + var cslib = new CSharpLibraryProject(fileNath); + foreach (var configuration in cslib.Configurations) { - var cslib = (CSharpLibraryProject)p; - Console.WriteLine(cslib.FullPath); - foreach (var configuration in cslib.Configurations) - { - Console.WriteLine($"{configuration.Name} -> { configuration.GetAssemblyName()}"); - } + Console.WriteLine($"{configuration.Name} -> { configuration.GetAssemblyName()}"); } } } diff --git a/mpt-csproj/Program.cs b/mpt-csproj/Program.cs index 849650a..3ef105b 100644 --- a/mpt-csproj/Program.cs +++ b/mpt-csproj/Program.cs @@ -217,7 +217,13 @@ public static int Main (string[] args) Console.WriteLine($"Injecting import of project {import_name}"); foreach (var csproj_file in listOfCsproj) { - ProjectTools.InjectProjectImport(csproj_file, import_name); + using (CSharpLibraryProject file = new CSharpLibraryProject(csproj_file)) + { + file.InjectProjectImport(import_name); + file.InjectVersioning(); + // null is ok - http://stackoverflow.com/questions/637308/why-is-adding-null-to-a-string-legal + file.InjectInternalsVisibleTo(import_name, null); + } } } return (int)ExitCode.Success; diff --git a/mpt-csproj/mpt-csproj.csproj b/mpt-csproj/mpt-csproj.csproj index 882a08c..b02265c 100644 --- a/mpt-csproj/mpt-csproj.csproj +++ b/mpt-csproj/mpt-csproj.csproj @@ -45,6 +45,7 @@ mono-options-4.4.0.0 +