// Copyright Epic Games, Inc. All Rights Reserved.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml;
using EpicGames.BuildGraph;
using EpicGames.Core;
#nullable enable
namespace AutomationTool
{
///
/// Implementation of XmlDocument which preserves line numbers for its elements
///
public static class BgScriptWriter
{
///
/// Writes a preprocessed build graph to a script file
///
/// Graph to output
/// The file to load
/// Schema file for validation
public static void Write(this BgGraphDef graph, FileReference file, FileReference? schemaFile)
{
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
settings.IndentChars = "\t";
using (XmlWriter writer = XmlWriter.Create(file.FullName, settings))
{
writer.WriteStartElement("BuildGraph", "http://www.epicgames.com/BuildGraph");
if (schemaFile != null)
{
writer.WriteAttributeString("schemaLocation", "http://www.w3.org/2001/XMLSchema-instance", "http://www.epicgames.com/BuildGraph " + schemaFile.MakeRelativeTo(file.Directory));
}
foreach (BgAgentDef agent in graph.Agents)
{
agent.Write(writer);
}
foreach (BgAggregateDef aggregate in graph.NameToAggregate.Values)
{
// If the aggregate has no required elements, skip it.
if (aggregate.RequiredNodes.Count == 0)
{
continue;
}
writer.WriteStartElement("Aggregate");
writer.WriteAttributeString("Name", aggregate.Name);
writer.WriteAttributeString("Requires", String.Join(";", aggregate.RequiredNodes.Select(x => x.Name)));
writer.WriteEndElement();
}
foreach (BgLabelDef label in graph.Labels)
{
writer.WriteStartElement("Label");
if (label.DashboardCategory != null)
{
writer.WriteAttributeString("Category", label.DashboardCategory);
}
writer.WriteAttributeString("Name", label.DashboardName);
writer.WriteAttributeString("Requires", String.Join(";", label.RequiredNodes.Select(x => x.Name)));
HashSet includedNodes = new HashSet(label.IncludedNodes);
includedNodes.ExceptWith(label.IncludedNodes.SelectMany(x => x.InputDependencies));
includedNodes.ExceptWith(label.RequiredNodes);
if (includedNodes.Count > 0)
{
writer.WriteAttributeString("Include", String.Join(";", includedNodes.Select(x => x.Name)));
}
HashSet excludedNodes = new HashSet(label.IncludedNodes);
excludedNodes.UnionWith(label.IncludedNodes.SelectMany(x => x.InputDependencies));
excludedNodes.ExceptWith(label.IncludedNodes);
excludedNodes.ExceptWith(excludedNodes.ToArray().SelectMany(x => x.InputDependencies));
if (excludedNodes.Count > 0)
{
writer.WriteAttributeString("Exclude", String.Join(";", excludedNodes.Select(x => x.Name)));
}
writer.WriteEndElement();
}
foreach (BgReport report in graph.NameToReport.Values)
{
writer.WriteStartElement("Report");
writer.WriteAttributeString("Name", report.Name);
writer.WriteAttributeString("Requires", String.Join(";", report.Nodes.Select(x => x.Name)));
writer.WriteEndElement();
}
foreach (BgBadgeDef badge in graph.Badges)
{
writer.WriteStartElement("Badge");
writer.WriteAttributeString("Name", badge.Name);
if (badge.Project != null)
{
writer.WriteAttributeString("Project", badge.Project);
}
if (badge.Change != 0)
{
writer.WriteAttributeString("Change", badge.Change.ToString());
}
writer.WriteAttributeString("Requires", String.Join(";", badge.Nodes.Select(x => x.Name)));
writer.WriteEndElement();
}
writer.WriteEndElement();
}
}
///
/// Writes this agent group out to a file, filtering nodes by a controlling trigger
///
/// Agent to output
/// The XML writer to output to
public static void Write(this BgAgentDef agent, XmlWriter writer)
{
writer.WriteStartElement("Agent");
writer.WriteAttributeString("Name", agent.Name);
writer.WriteAttributeString("Type", String.Join(";", agent.PossibleTypes));
foreach (BgNodeDef node in agent.Nodes)
{
node.Write(writer);
}
writer.WriteEndElement();
}
///
/// Write this node to an XML writer
///
/// Node to output
/// The writer to output the node to
public static void Write(this BgNodeDef node, XmlWriter writer)
{
writer.WriteStartElement("Node");
writer.WriteAttributeString("Name", node.Name);
string[] requireNames = node.Inputs.Select(x => x.TagName).ToArray();
if (requireNames.Length > 0)
{
writer.WriteAttributeString("Requires", String.Join(";", requireNames));
}
string[] producesNames = node.Outputs.Where(x => x != node.DefaultOutput).Select(x => x.TagName).ToArray();
if (producesNames.Length > 0)
{
writer.WriteAttributeString("Produces", String.Join(";", producesNames));
}
string[] afterNames = node.GetDirectOrderDependencies().Except(node.InputDependencies).Select(x => x.Name).ToArray();
if (afterNames.Length > 0)
{
writer.WriteAttributeString("After", String.Join(";", afterNames));
}
if (!node.NotifyOnWarnings)
{
writer.WriteAttributeString("NotifyOnWarnings", node.NotifyOnWarnings.ToString());
}
if (node.RunEarly)
{
writer.WriteAttributeString("RunEarly", node.RunEarly.ToString());
}
if (node.IgnoreModified.Count > 0)
{
writer.WriteAttributeString("IgnoreModified", String.Join(";", node.IgnoreModified));
}
BgScriptNode scriptNode = (BgScriptNode)node;
foreach (BgTask task in scriptNode.Tasks)
{
task.Write(writer);
}
writer.WriteEndElement();
}
}
}