// Copyright Epic Games, Inc. All Rights Reserved. using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using System.Xml; using EpicGames.Core; using Microsoft.Extensions.Logging; using UnrealBuildBase; using UnrealBuildTool; 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 { get; set; } /// /// List of output files. PDBs will be extracted from this list. /// [TaskParameter] public string Files { get; set; } /// /// Output directory for the compressed symbols. /// [TaskParameter] public string StoreDir { get; set; } /// /// Name of the product for the symbol store records. /// [TaskParameter] public string Product { get; set; } /// /// 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 { get; set; } /// /// 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 { get; set; } /// /// 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 { get; set; } /// /// 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 { get; set; } = 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 { get; set; } } /// /// Task that strips symbols from a set of files. /// [TaskElement("SymStore", typeof(SymStoreTaskParameters))] public class SymStoreTask : BgTaskImpl { /// /// Parameters for this task /// readonly SymStoreTaskParameters _parameters; /// /// Construct a spawn task /// /// Parameters for the task public SymStoreTask(SymStoreTaskParameters 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) { // 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; } } }