// Copyright Epic Games, Inc. All Rights Reserved. using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using System.Xml; using EpicGames.Core; using OpenTracing; using OpenTracing.Util; namespace AutomationTool.Tasks { /// /// Parameters for a task that runs the cooker /// public class CookTaskParameters { /// /// Project file to be cooked. /// [TaskParameter] public string Project { get; set; } /// /// The cook platform to target (for example, Windows). /// [TaskParameter] public string Platform { get; set; } /// /// List of maps to be cooked, separated by '+' characters. /// [TaskParameter(Optional = true)] public string Maps { get; set; } /// /// Additional arguments to be passed to the cooker. /// [TaskParameter(Optional = true)] public bool Versioned { get; set; } = false; /// /// Additional arguments to be passed to the cooker. /// [TaskParameter(Optional = true)] public string Arguments { get; set; } = ""; /// /// Optional path to what editor executable to run for cooking. /// [TaskParameter(Optional = true)] public string EditorExe { get; set; } = ""; /// /// Whether to tag the output from the cook. Since cooks produce a lot of files, it can be detrimental to spend time tagging them if we don't need them in a dependent node. /// [TaskParameter(Optional = true)] public bool TagOutput { get; set; } = true; /// /// Tag to be applied to build products of this task. /// [TaskParameter(Optional = true, ValidationType = TaskParameterValidationType.TagList)] public string Tag { get; set; } } /// /// Cook a selection of maps for a certain platform /// [TaskElement("Cook", typeof(CookTaskParameters))] public class CookTask : BgTaskImpl { /// /// Parameters for the task /// readonly CookTaskParameters _parameters; /// /// Constructor. /// /// Parameters for this task public CookTask(CookTaskParameters parameters) { _parameters = parameters; } /// /// ExecuteAsync the task. /// /// Information about the current job /// Set of build products produced by this node. /// Mapping from tag names to the set of files they include public override Task ExecuteAsync(JobContext job, HashSet buildProducts, Dictionary> tagNameToFileSet) { // Figure out the project that this target belongs to FileReference projectFile = null; if (_parameters.Project != null) { projectFile = new FileReference(_parameters.Project); if (!FileReference.Exists(projectFile)) { throw new AutomationException("Missing project file - {0}", projectFile.FullName); } } // ExecuteAsync the cooker using (IScope scope = GlobalTracer.Instance.BuildSpan("Cook").StartActive()) { scope.Span.SetTag("project", projectFile == null ? "UE4" : projectFile.GetFileNameWithoutExtension()); scope.Span.SetTag("platform", _parameters.Platform); string[] maps = (_parameters.Maps == null) ? null : _parameters.Maps.Split(new char[] { '+' }); string arguments = (_parameters.Versioned ? "" : "-Unversioned ") + _parameters.Arguments; string editorExe = (System.String.IsNullOrWhiteSpace(_parameters.EditorExe) ? ProjectUtils.GetEditorForProject(projectFile).FullName : _parameters.EditorExe); CommandUtils.CookCommandlet(projectFile, editorExe, maps, null, null, null, _parameters.Platform, arguments); } // Find all the cooked files List cookedFiles = new List(); if (_parameters.TagOutput) { foreach (string platform in _parameters.Platform.Split('+')) { DirectoryReference platformCookedDirectory = DirectoryReference.Combine(projectFile.Directory, "Saved", "Cooked", platform); if (!DirectoryReference.Exists(platformCookedDirectory)) { throw new AutomationException("Cook output directory not found ({0})", platformCookedDirectory.FullName); } List platformCookedFiles = DirectoryReference.EnumerateFiles(platformCookedDirectory, "*", System.IO.SearchOption.AllDirectories).ToList(); if (platformCookedFiles.Count == 0) { throw new AutomationException("Cooking did not produce any files in {0}", platformCookedDirectory.FullName); } cookedFiles.AddRange(platformCookedFiles); } } // Apply the optional tag to the build products foreach (string tagName in FindTagNamesFromList(_parameters.Tag)) { FindOrAddTagSet(tagNameToFileSet, tagName).UnionWith(cookedFiles); } // Add them to the set of build products buildProducts.UnionWith(cookedFiles); return Task.CompletedTask; } /// /// Output this task out to an XML writer. /// public override void Write(XmlWriter writer) { Write(writer, _parameters); } /// /// Find all the tags which are used as inputs to this task /// /// The tag names which are read by this task public override IEnumerable FindConsumedTagNames() { yield break; } /// /// Find all the tags which are modified by this task /// /// The tag names which are modified by this task public override IEnumerable FindProducedTagNames() { return FindTagNamesFromList(_parameters.Tag); } } }