[xharness] Append to MtouchExtraArgs/MonoBundlingExtraArgs instead of just setting the value. (#18200)

When generating/cloning test projects and modifying
MtouchExtraArgs/MonoBundlingExtraArgs, we always want to add to any existing
properties instead of overwriting them, so do exactly that.

With this change we now find the latest top-level PropertyGroup in the project
file with no Condition, and add a MtouchExtraArgs/MonoBundlingArgs that adds
to any existing property.
This commit is contained in:
Rolf Bjarne Kvinge 2023-05-04 17:09:50 +02:00 коммит произвёл GitHub
Родитель 791b98cac2
Коммит 066ab68bc6
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
2 изменённых файлов: 92 добавлений и 4 удалений

Просмотреть файл

@ -225,11 +225,13 @@ namespace Xharness.Jenkins {
var canSymlink = task.Platform.CanSymlink ();
if (!string.IsNullOrEmpty (mtouch_extra_args))
clone.Xml.AddExtraMtouchArgs (mtouch_extra_args, task.ProjectPlatform, configuration);
clone.Xml.AppendExtraMtouchArgs (mtouch_extra_args);
if (!string.IsNullOrEmpty (bundling_extra_args))
clone.Xml.AddMonoBundlingExtraArgs (bundling_extra_args, task.ProjectPlatform, configuration);
if (!string.IsNullOrEmpty (link_mode))
clone.Xml.SetNode (isMac ? "LinkMode" : "MtouchLink", link_mode, task.ProjectPlatform, configuration);
clone.Xml.AppendMonoBundlingExtraArgs (bundling_extra_args);
if (!string.IsNullOrEmpty (link_mode)) {
clone.Xml.SetProperty ("LinkMode", link_mode);
clone.Xml.SetProperty ("MtouchLink", link_mode);
}
if (!string.IsNullOrEmpty (defines)) {
clone.Xml.AddAdditionalDefines (defines, task.ProjectPlatform, configuration);
if (clone.ProjectReferences != null) {

Просмотреть файл

@ -17,6 +17,92 @@ using Xamarin.Utils;
namespace Xharness {
public static class EvolvedProjectFileExtensions {
public static void SetProperty (this XmlDocument csproj, string key, string value)
{
// Set all existing properties
var xmlNodeList = csproj.SelectNodes ("/*[local-name() = 'Project']/*[local-name() = 'PropertyGroup']/*[local-name() = '" + key + "']").Cast<XmlNode> ();
foreach (var item in xmlNodeList)
item.InnerText = value;
// Create a new one as well, in case any of the other ones are for a different configuration.
var propertyGroup = GetLastPropertyGroup (csproj);
var mea = csproj.CreateElement (key, csproj.GetNamespace ());
mea.InnerText = value;
propertyGroup.AppendChild (mea);
propertyGroup.InsertBefore (csproj.CreateComment ($" This property was created by xharness "), mea);
}
public static void AppendToProperty (this XmlDocument csproj, string node, string value, string separator)
{
var propertyGroup = GetLastPropertyGroup (csproj);
var newNode = csproj.CreateElement (node, csproj.GetNamespace ());
newNode.InnerText = $"$({node}){separator}{value}";
propertyGroup.AppendChild (newNode);
propertyGroup.InsertBefore (csproj.CreateComment ($" This property was created by xharness "), newNode);
}
public static void AppendExtraMtouchArgs (this XmlDocument csproj, string value)
{
csproj.AppendToProperty ("MtouchExtraArgs", value, " ");
}
public static void AppendMonoBundlingExtraArgs (this XmlDocument csproj, string value)
{
csproj.AppendToProperty ("MonoBundlingExtraArgs", value, " ");
}
static int IndexOf (this XmlNodeList @this, XmlNode node)
{
for (var i = 0; i < @this.Count; i++) {
if ((object) node == (object) @this [i])
return i;
}
return -1;
}
static XmlElement GetLastPropertyGroup (this XmlDocument csproj)
{
// Is the last property group Condition-less? If so, return it.
// Definition of last: the last PropertyGroup before an Import node (or last in file if there are no Import nodes)
var propertyGroups = csproj.SelectNodes ("/*[local-name() = 'Project']/*[local-name() = 'PropertyGroup']").Cast<XmlElement> ();
var imports = csproj.SelectNodes ("/*[local-name() = 'Project']/*[local-name() = 'Import']").Cast<XmlElement> ();
if (propertyGroups.Any ()) {
XmlElement? last = null;
if (imports.Any ()) {
var firstImport = imports.First ();
var firstImportIndex = firstImport.ParentNode.ChildNodes.IndexOf (firstImport);
foreach (var pg in propertyGroups) {
var pgIndex = pg.ParentNode.ChildNodes.IndexOf (pg);
if (pgIndex < firstImportIndex) {
last = pg;
} else {
break;
}
}
} else {
last = propertyGroups.Last ();
}
if (last?.HasAttribute ("Condition") == false)
return last;
}
// Create a new PropertyGroup, and add it either:
// * Just before the first Import node
// * If no Import node, then after the last PropertyGroup.
var projectNode = csproj.SelectSingleNode ("//*[local-name() = 'Project']");
var newPropertyGroup = csproj.CreateElement ("PropertyGroup", csproj.GetNamespace ());
if (imports.Any ()) {
projectNode.InsertBefore (newPropertyGroup, imports.First ());
} else {
var lastPropertyGroup = csproj.SelectNodes ("/*[local-name() = 'Project']/*[local-name() = 'PropertyGroup']").Cast<XmlNode> ().Last ();
projectNode.InsertAfter (newPropertyGroup, lastPropertyGroup);
}
projectNode.InsertBefore (csproj.CreateComment ($" This property group was created by xharness "), newPropertyGroup);
return newPropertyGroup;
}
// Evaluates a text and replaces '$(Variable)' with the property value specified in the 'properties' dictionary.
// Contrary to what MSBuild does, if the variable can't be found in the dictionary, it's not replaced with
// an empty string, instead the variable reference stays as-is.