| File: parent\Shared\TaskHostTaskComplete.cs | Web Access |
| Project: Microsoft.Build.csproj (Microsoft.Build) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.Collections.Generic; using System.Diagnostics; #if FEATURE_REPORTFILEACCESSES using Microsoft.Build.Experimental.FileAccess; #endif using Microsoft.Build.Shared; #nullable disable namespace Microsoft.Build.BackEnd { /// <summary> /// How the task completed -- successful, failed, or crashed /// </summary> internal enum TaskCompleteType { /// <summary> /// Task execution succeeded /// </summary> Success, /// <summary> /// Task execution failed /// </summary> Failure, /// <summary> /// Task crashed during initialization steps -- loading the task, /// validating or setting the parameters, etc. /// </summary> CrashedDuringInitialization, /// <summary> /// Task crashed while being executed /// </summary> CrashedDuringExecution, /// <summary> /// Task crashed after being executed /// -- Getting outputs, etc /// </summary> CrashedAfterExecution } /// <summary> /// TaskHostTaskComplete contains all the information the owning worker node /// needs from the task host on completion of task execution. /// </summary> internal class TaskHostTaskComplete : INodePacket { #if FEATURE_REPORTFILEACCESSES private List<FileAccessData> _fileAccessData; #endif /// <summary> /// Result of the task's execution. /// </summary> private TaskCompleteType _taskResult; /// <summary> /// If the task threw an exception during its initialization or execution, /// save it here. /// </summary> private Exception _taskException; /// <summary> /// If there's an additional message that should be attached to the error /// logged beyond "task X failed unexpectedly", save it here. May be null. /// </summary> private string _taskExceptionMessage; /// <summary> /// If the message saved in taskExceptionMessage requires arguments, save /// them here. May be null. /// </summary> private string[] _taskExceptionMessageArgs; /// <summary> /// The set of parameters / values from the task after it finishes execution. /// </summary> private Dictionary<string, TaskParameter> _taskOutputParameters = null; /// <summary> /// The process environment at the end of task execution. /// </summary> private Dictionary<string, string> _buildProcessEnvironment = null; /// <summary> /// How <see cref="_buildProcessEnvironment"/> is represented on the wire. Defaults to /// <see cref="InvariantPayloadTransferMode.Full"/> so older (legacy) code paths keep their existing behavior. /// </summary> private InvariantPayloadTransferMode _environmentMode = InvariantPayloadTransferMode.Full; #pragma warning disable CS1572 // XML comment has a param tag, but there is no parameter by that name. Justification: xmldoc doesn't seem to interact well with #ifdef of params. /// <summary> /// Initializes a new instance of the <see cref="TaskHostTaskComplete"/> class. /// </summary> /// <param name="result">The result of the task's execution.</param> /// <param name="fileAccessData">The file accesses reported by the task.</param> /// <param name="buildProcessEnvironment">The build process environment as it was at the end of the task's execution.</param> #pragma warning restore CS1572 // XML comment has a param tag, but there is no parameter by that name public TaskHostTaskComplete( OutOfProcTaskHostTaskResult result, #if FEATURE_REPORTFILEACCESSES List<FileAccessData> fileAccessData, #endif IDictionary<string, string> buildProcessEnvironment) { Assumed.NotNull(result); _taskResult = result.Result; _taskException = result.TaskException; _taskExceptionMessage = result.ExceptionMessage; _taskExceptionMessageArgs = result.ExceptionMessageArgs; #if FEATURE_REPORTFILEACCESSES _fileAccessData = fileAccessData; #endif if (result.FinalParameterValues != null) { _taskOutputParameters = new Dictionary<string, TaskParameter>(StringComparer.OrdinalIgnoreCase); foreach (KeyValuePair<string, object> parameter in result.FinalParameterValues) { _taskOutputParameters[parameter.Key] = new TaskParameter(parameter.Value); } } if (buildProcessEnvironment != null) { _buildProcessEnvironment = buildProcessEnvironment as Dictionary<string, string>; if (_buildProcessEnvironment == null) { _buildProcessEnvironment = new Dictionary<string, string>(buildProcessEnvironment); } } } /// <summary> /// For deserialization. /// </summary> private TaskHostTaskComplete() { } /// <summary> /// Result of the task's execution. /// </summary> public TaskCompleteType TaskResult { [DebuggerStepThrough] get { return _taskResult; } } /// <summary> /// If the task threw an exception during its initialization or execution, /// save it here. /// </summary> public Exception TaskException { [DebuggerStepThrough] get { return _taskException; } } /// <summary> /// If there's an additional message that should be attached to the error /// logged beyond "task X failed unexpectedly", put it here. May be null. /// </summary> public string TaskExceptionMessage { [DebuggerStepThrough] get { return _taskExceptionMessage; } } /// <summary> /// If there are arguments that need to be formatted into the message being /// sent, set them here. May be null. /// </summary> public string[] TaskExceptionMessageArgs { [DebuggerStepThrough] get { return _taskExceptionMessageArgs; } } /// <summary> /// Task parameters and their values after the task has finished. /// </summary> public Dictionary<string, TaskParameter> TaskOutputParameters { [DebuggerStepThrough] get { if (_taskOutputParameters == null) { _taskOutputParameters = new Dictionary<string, TaskParameter>(StringComparer.OrdinalIgnoreCase); } return _taskOutputParameters; } } /// <summary> /// The process environment. /// </summary> public Dictionary<string, string> BuildProcessEnvironment { [DebuggerStepThrough] get { return _buildProcessEnvironment; } } /// <summary> /// How the build process environment is transferred on the wire. See <see cref="InvariantPayloadTransferMode"/>. /// Set by the task host when the negotiated packet version supports environment delta transfer and the task /// did not change the environment. /// </summary> internal InvariantPayloadTransferMode EnvironmentMode { [DebuggerStepThrough] get { return _environmentMode; } [DebuggerStepThrough] set { _environmentMode = value; } } /// <summary> /// The type of this packet. /// </summary> public NodePacketType Type { get { return NodePacketType.TaskHostTaskComplete; } } #if FEATURE_REPORTFILEACCESSES /// <summary> /// Gets the file accesses reported by the task. /// </summary> public List<FileAccessData> FileAccessData { [DebuggerStepThrough] get => _fileAccessData; } #endif /// <summary> /// Translates the packet to/from binary form. /// </summary> /// <param name="translator">The translator to use.</param> public void Translate(ITranslator translator) { translator.TranslateEnum(ref _taskResult, (int)_taskResult); translator.TranslateException(ref _taskException); translator.Translate(ref _taskExceptionMessage); translator.Translate(ref _taskExceptionMessageArgs); translator.TranslateDictionary(ref _taskOutputParameters, StringComparer.OrdinalIgnoreCase, TaskParameter.FactoryForDeserialization); TranslateBuildProcessEnvironment(translator); #if FEATURE_REPORTFILEACCESSES translator.Translate(ref _fileAccessData, (ITranslator translator, ref FileAccessData data) => ((ITranslatable)data).Translate(translator)); #else bool hasFileAccessData = false; translator.Translate(ref hasFileAccessData); #endif } private void TranslateBuildProcessEnvironment(ITranslator translator) { if (translator.NegotiatedPacketVersion >= NodePacketTypeExtensions.EnvironmentDeltaMinVersion) { translator.TranslateEnum(ref _environmentMode, (int)_environmentMode); if (_environmentMode == InvariantPayloadTransferMode.Full) { translator.TranslateDictionary(ref _buildProcessEnvironment, StringComparer.OrdinalIgnoreCase); } } else { translator.TranslateDictionary(ref _buildProcessEnvironment, StringComparer.OrdinalIgnoreCase); } } /// <summary> /// Factory for deserialization. /// </summary> internal static INodePacket FactoryForDeserialization(ITranslator translator) { TaskHostTaskComplete taskComplete = new TaskHostTaskComplete(); taskComplete.Translate(translator); return taskComplete; } } }