| File: BackEnd\Shared\WorkUnitResult.cs | Web Access |
| Project: src\msbuild\src\Build\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; #nullable disable namespace Microsoft.Build.BackEnd { /// <summary> /// The result of executing the task or target. /// </summary> internal enum WorkUnitResultCode { /// <summary> /// The work unit was skipped. /// </summary> Skipped, /// <summary> /// The work unit succeeded. /// </summary> Success, /// <summary> /// The work unit failed. /// </summary> Failed, /// <summary> /// The work unit was cancelled. /// </summary> Canceled, } /// <summary> /// Indicates whether further work should be done. /// </summary> internal enum WorkUnitActionCode { /// <summary> /// Work should proceed with the next work unit. /// </summary> Continue, /// <summary> /// No further work units should be executed. /// </summary> Stop, } /// <summary> /// A result of executing a target or task. /// </summary> internal readonly struct WorkUnitResult : ITranslatable { /// <summary> /// The result. /// </summary> private readonly WorkUnitResultCode _resultCode; /// <summary> /// The next action to take. /// </summary> private readonly WorkUnitActionCode _actionCode; /// <summary> /// The exception from the failure, if any. /// </summary> private readonly Exception _exception; /// <summary> /// Creates a new work result ready for aggregation during batches. /// </summary> public WorkUnitResult() { _resultCode = WorkUnitResultCode.Skipped; _actionCode = WorkUnitActionCode.Continue; _exception = null; } /// <summary> /// Creates a work result with the specified result codes. /// </summary> internal WorkUnitResult(WorkUnitResultCode resultCode, WorkUnitActionCode actionCode, Exception e) { _resultCode = resultCode; _actionCode = actionCode; _exception = e; } /// <summary> /// Translator constructor /// </summary> private WorkUnitResult(ITranslator translator) { translator.TranslateEnum(ref _resultCode, (int)_resultCode); translator.TranslateEnum(ref _actionCode, (int)_actionCode); translator.TranslateException(ref _exception); } /// <summary> /// Get the result code. /// </summary> internal WorkUnitResultCode ResultCode => _resultCode; /// <summary> /// Get the action code. /// </summary> internal WorkUnitActionCode ActionCode => _actionCode; /// <summary> /// Get the exception /// </summary> internal Exception Exception => _exception; #region INodePacketTranslatable Members /// <summary> /// Translator. /// </summary> public void Translate(ITranslator translator) { if (translator.Mode == TranslationDirection.ReadFromStream) { throw new InvalidOperationException("Readonly struct - use the factory method for deserialization."); } WorkUnitResultCode resultCode = _resultCode; WorkUnitActionCode actionCode = _actionCode; Exception exception = _exception; translator.TranslateEnum(ref resultCode, (int)_resultCode); translator.TranslateEnum(ref actionCode, (int)_actionCode); translator.TranslateException(ref exception); } #endregion /// <summary> /// Factory for serialization. /// </summary> internal static WorkUnitResult FactoryForDeserialization(ITranslator translator) { return new WorkUnitResult(translator); } /// <summary> /// Aggregates the specified result with this result and returns the aggregation. /// </summary> /// <remarks> /// The rules are: /// 1. Errors take precedence over success. /// 2. Success takes precedence over skipped. /// 3. Stop takes precedence over continue. /// 4. The first exception in the result wins. /// </remarks> internal WorkUnitResult AggregateResult(WorkUnitResult result) { WorkUnitResultCode aggregateResult = _resultCode; WorkUnitActionCode aggregateAction = _actionCode; Exception aggregateException = _exception; if (result._resultCode == WorkUnitResultCode.Canceled || result.ResultCode == WorkUnitResultCode.Failed) { // Failed and canceled take priority aggregateResult = result._resultCode; } else if (result._resultCode == WorkUnitResultCode.Success && aggregateResult == WorkUnitResultCode.Skipped) { // Success only counts if we were previously in the skipped category. aggregateResult = result._resultCode; } if (result._actionCode == WorkUnitActionCode.Stop) { aggregateAction = result.ActionCode; } if (aggregateException == null) { aggregateException = result._exception; } return new WorkUnitResult(aggregateResult, aggregateAction, aggregateException); } } }