// Copyright Epic Games, Inc. All Rights Reserved. using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Xml; using EpicGames.Core; using UnrealBuildBase; using UnrealBuildTool; using Microsoft.Extensions.Logging; using static AutomationTool.CommandUtils; namespace AutomationTool.Tasks { /// /// Parameters for a task that uploads symbols to a symbol server /// public class SymStoreTaskParameters { /// /// The platform toolchain required to handle symbol files. /// [TaskParameter] public UnrealTargetPlatform Platform; /// /// List of output files. PDBs will be extracted from this list. /// [TaskParameter] public string Files; /// /// Output directory for the compressed symbols. /// [TaskParameter] public string StoreDir; /// /// Name of the product for the symbol store records. /// [TaskParameter] public string Product; /// /// Name of the Branch to base all the depot source files from. /// Used when IndexSources is true (may be used only on some platforms). /// [TaskParameter(Optional = true)] public string Branch; /// /// Changelist to which all the depot source files have been synced to. /// Used when IndexSources is true (may be used only on some platforms). /// [TaskParameter(Optional = true)] public int Change; /// /// BuildVersion associated with these symbols. Used for clean-up in AgeStore by matching this version against a directory name in a build share. /// [TaskParameter(Optional = true)] public string BuildVersion; /// /// Whether to include the source code index in the uploaded symbols. /// When enabled, the task will generate data required by a source server (only some platforms and source control servers are supported). /// The source server allows debuggers to automatically fetch the matching source code when debbugging builds or analyzing dumps. /// [TaskParameter(Optional = true)] public bool IndexSources = false; /// /// Filter for the depot source files that are to be indexed. /// It's a semicolon-separated list of perforce filter e.g. Engine/....cpp;Engine/....h. /// It may also be a name of a previously defined tag e.g. "#SourceFiles /// Used when IndexSources is true (may be used only on some platforms). /// [TaskParameter(Optional = true)] public string SourceFiles; } /// /// Task that strips symbols from a set of files. /// [TaskElement("SymStore", typeof(SymStoreTaskParameters))] public class SymStoreTask : BgTaskImpl { /// /// Parameters for this task /// SymStoreTaskParameters Parameters; /// /// Construct a spawn task /// /// Parameters for the task public SymStoreTask(SymStoreTaskParameters 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 Task ExecuteAsync(JobContext Job, HashSet BuildProducts, Dictionary> TagNameToFileSet) { // Find the matching files List Files = ResolveFilespec(Unreal.RootDirectory, Parameters.Files, TagNameToFileSet).ToList(); // Get the symbol store directory DirectoryReference StoreDir = ResolveDirectory(Parameters.StoreDir); // Take the lock before accessing the symbol server, if required by the platform Platform TargetPlatform = Platform.GetPlatform(Parameters.Platform); List SourceFiles = new List(); if (Parameters.IndexSources && TargetPlatform.SymbolServerSourceIndexingRequiresListOfSourceFiles) { Logger.LogInformation("Discovering source code files..."); SourceFiles = ResolveFilespec(Unreal.RootDirectory, Parameters.SourceFiles, TagNameToFileSet).ToList(); } CommandUtils.OptionallyTakeLock(TargetPlatform.SymbolServerRequiresLock, StoreDir, TimeSpan.FromMinutes(60), () => { if (!TargetPlatform.PublishSymbols(StoreDir, Files, Parameters.IndexSources, SourceFiles, Parameters.Product, Parameters.Branch, Parameters.Change, Parameters.BuildVersion)) { throw new AutomationException("Failure publishing symbol files."); } }); 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() { 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; } } }