using EpicGames.MCP.Automation; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Xml; using UnrealBuildTool; namespace AutomationTool.Tasks { /// /// Parameters for a task which splits a build into chunks /// public class ChunkTaskParameters { /// /// The application name /// [TaskParameter] public string AppName; /// /// The application id /// [TaskParameter(Optional = true)] public int AppID = 1; /// /// Platform we are staging for. /// [TaskParameter] public MCPPlatform Platform; /// /// BuildVersion of the App we are staging. /// [TaskParameter] public string BuildVersion; /// /// Directory that build data will be copied from. /// [TaskParameter] public string InputDir; /// /// Optional list of files that should be considered /// [TaskParameter(Optional = true)] public string Files; /// /// The executable to run to launch this application. /// [TaskParameter(Optional = true)] public string Launch; /// /// Parameters that the application should be launched with. /// [TaskParameter(Optional = true)] public string LaunchArgs; /// /// Full path to the CloudDir where chunks and manifests should be staged. /// [TaskParameter] public string CloudDir; /// /// Determines the version of BuildPatchTool to use, for example, to allow us to use a pre-release version. /// [TaskParameter(Optional = true)] public BuildPatchToolBase.ToolVersion ToolVersion = BuildPatchToolBase.ToolVersion.Live; /// /// Location of a file listing attributes to apply to chunked files. /// Should contain quoted InputDir relative files followed by optional attribute keywords readonly compressed executable, separated by \\r\\n line endings. /// [TaskParameter(Optional = true)] public string AttributesFileName; /// /// The prerequisites installer to launch on successful product install, must be relative to, and inside of InputDir. /// [TaskParameter(Optional = true)] public string PrereqPath; /// /// The commandline to send to prerequisites installer on launch. /// [TaskParameter(Optional = true)] public string PrereqArgs; } /// /// Implements a task which splits a build into chunks /// [TaskElement("Chunk", typeof(ChunkTaskParameters))] public class ChunkTask : CustomTask { /// /// Parameters for this task /// ChunkTaskParameters Parameters; /// /// Construct a new ChunkTask. /// /// Parameters for this task public ChunkTask(ChunkTaskParameters InParameters) { Parameters = InParameters; } /// /// Execute 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 /// True if the task succeeded public override bool Execute(JobContext Job, HashSet BuildProducts, Dictionary> TagNameToFileSet) { // Get the build directory DirectoryReference InputDir = ResolveDirectory(Parameters.InputDir); // If there's a set of files specified, generate a temporary ignore list. FileReference IgnoreList = null; if (Parameters.Files != null) { // Find the files which are to be included HashSet IncludeFiles = ResolveFilespec(InputDir, Parameters.Files, TagNameToFileSet); // Create a file to store the ignored file list IgnoreList = new FileReference(LogUtils.GetUniqueLogName(Path.Combine(CommandUtils.CmdEnv.LogFolder, Parameters.AppName + "-Ignore"))); using (StreamWriter Writer = new StreamWriter(IgnoreList.FullName)) { DirectoryInfo InputDirInfo = new DirectoryInfo(InputDir.FullName); foreach (FileInfo File in InputDirInfo.EnumerateFiles("*", SearchOption.AllDirectories)) { FileReference FileRef = new FileReference(File); if (!IncludeFiles.Contains(FileRef)) { string RelativePath = FileRef.MakeRelativeTo(InputDir); const string Iso8601DateTimeFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fffZ"; Writer.WriteLine("{0}\t{1}", (RelativePath.IndexOf(' ') == -1) ? RelativePath : "\"" + RelativePath + "\"", File.LastWriteTimeUtc.ToString(Iso8601DateTimeFormat)); } } } } // Create the staging info BuildPatchToolStagingInfo StagingInfo = new BuildPatchToolStagingInfo(Job.OwnerCommand, Parameters.AppName, Parameters.AppID, Parameters.BuildVersion, Parameters.Platform, Parameters.CloudDir); // Set the patch generation options BuildPatchToolBase.PatchGenerationOptions Options = new BuildPatchToolBase.PatchGenerationOptions(); Options.StagingInfo = StagingInfo; Options.BuildRoot = ResolveDirectory(Parameters.InputDir).FullName; Options.FileIgnoreList = (IgnoreList != null) ? IgnoreList.FullName : null; Options.FileAttributeList = Parameters.AttributesFileName ?? ""; Options.AppLaunchCmd = Parameters.Launch ?? ""; Options.AppLaunchCmdArgs = Parameters.LaunchArgs ?? ""; Options.AppChunkType = BuildPatchToolBase.ChunkType.Chunk; Options.Platform = Parameters.Platform; Options.PrereqPath = Parameters.PrereqPath ?? ""; Options.PrereqArgs = Parameters.PrereqArgs ?? ""; // Run the chunking BuildPatchToolBase.Get().Execute(Options, Parameters.ToolVersion); return true; } /// /// 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() { return FindTagNamesFromFilespec(Parameters.Files); } /// /// Find all the tags which are modified by this task /// /// The tag names which are modified by this task public override IEnumerable FindProducedTagNames() { yield break; } } }