// Copyright Epic Games, Inc. All Rights Reserved. using EpicGames.BuildGraph; using EpicGames.Perforce; using Microsoft.Extensions.Logging.Abstractions; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Xml; using EpicGames.Core; using UnrealBuildBase; using UnrealBuildTool; using Microsoft.Extensions.Logging; namespace AutomationTool.Tasks { /// /// Parameters for a task that compiles a C# project /// public class FindModifiedFilesTaskParameters { /// /// List of file specifications separated by semicolon (default is ...) /// [TaskParameter(Optional=true, ValidationType = TaskParameterValidationType.FileSpec)] public string Path = "..."; /// /// The configuration to compile. /// [TaskParameter(Optional = true)] public int Change; /// /// The configuration to compile. /// [TaskParameter(Optional = true)] public int MinChange; /// /// The configuration to compile. /// [TaskParameter(Optional = true)] public int MaxChange; /// /// The file to write to /// [TaskParameter(Optional = true)] public FileReference Output; } /// /// Compiles C# project files, and their dependencies. /// [TaskElement("FindModifiedFiles", typeof(FindModifiedFilesTaskParameters))] public class FindModifiedFilesTask : BgTaskImpl { /// /// Parameters for the task /// FindModifiedFilesTaskParameters Parameters; /// /// Constructor. /// /// Parameters for this task public FindModifiedFilesTask(FindModifiedFilesTaskParameters 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 public override async Task ExecuteAsync(JobContext Job, HashSet BuildProducts, Dictionary> TagNameToFileSet) { using IPerforceConnection Connection = await PerforceConnection.CreateAsync(CommandUtils.P4Settings, Log.Logger); SortedSet AllLocalFiles = new SortedSet(); foreach (string Path in Parameters.Path.Split(";")) { StringBuilder Filter = new StringBuilder($"//{Connection.Settings.ClientName}/{Path}"); if (Parameters.Change > 0) { Filter.Append($"@={Parameters.Change}"); } else if (Parameters.MinChange > 0) { if (Parameters.MaxChange > 0) { Filter.Append($"@{Parameters.MinChange},{Parameters.MaxChange}"); } else { Filter.Append($"@>={Parameters.MinChange}"); } } else { throw new AutomationException("Change or MinChange must be specified to FindModifiedFiles task"); } StreamRecord StreamRecord = await Connection.GetStreamAsync(CommandUtils.P4Env.Branch, true); PerforceViewMap ViewMap = PerforceViewMap.Parse(StreamRecord.View); HashSet LocalFiles = new HashSet(); List Files = await Connection.FilesAsync(FilesOptions.None, Filter.ToString()); foreach (FilesRecord File in Files) { string LocalFile; if (ViewMap.TryMapFile(File.DepotFile, StringComparison.OrdinalIgnoreCase, out LocalFile)) { LocalFiles.Add(LocalFile); } else { Logger.LogInformation("Unable to map {DepotFile} to workspace; skipping.", File.DepotFile); } } Logger.LogInformation("Found {NumFiles} modified files matching {Filter}", LocalFiles.Count, Filter.ToString()); foreach (string LocalFile in LocalFiles) { Logger.LogInformation(" {LocalFile}", LocalFile); } AllLocalFiles.UnionWith(LocalFiles); } Logger.LogInformation("Found {NumFiles} total modified files", AllLocalFiles.Count); if (Parameters.Output != null) { await FileReference.WriteAllLinesAsync(Parameters.Output, AllLocalFiles); Logger.LogInformation("Written {OutputFile}", Parameters.Output); } } /// /// 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.Project); return Enumerable.Empty(); } /// /// Find all the tags which are modified by this task /// /// The tag names which are modified by this task public override IEnumerable FindProducedTagNames() { return Enumerable.Empty(); /* foreach (string TagName in FindTagNamesFromList(Parameters.Tag)) { yield return TagName; } foreach (string TagName in FindTagNamesFromList(Parameters.TagReferences)) { yield return TagName; }*/ } } }