// Copyright Epic Games, Inc. All Rights Reserved. using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Xml; using EpicGames.Core; using EpicGames.Perforce; 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 { get; set; } = "..."; /// /// The configuration to compile. /// [TaskParameter(Optional = true)] public int Change { get; set; } /// /// The configuration to compile. /// [TaskParameter(Optional = true)] public int MinChange { get; set; } /// /// The configuration to compile. /// [TaskParameter(Optional = true)] public int MaxChange { get; set; } /// /// The file to write to /// [TaskParameter(Optional = true)] public FileReference Output { get; set; } } /// /// Compiles C# project files, and their dependencies. /// [TaskElement("FindModifiedFiles", typeof(FindModifiedFilesTaskParameters))] public class FindModifiedFilesTask : BgTaskImpl { /// /// Parameters for the task /// readonly FindModifiedFilesTaskParameters _parameters; /// /// Constructor. /// /// Parameters for this task public FindModifiedFilesTask(FindModifiedFilesTaskParameters 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 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; }*/ } } }