File: Graph\GraphBuildSubmission.cs
Web Access
Project: ..\..\..\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;
using System.Globalization;
using System.Threading;
using Microsoft.Build.BackEnd;
using Microsoft.Build.Execution;
using Microsoft.Build.Shared;
 
namespace Microsoft.Build.Graph
{
    /// <summary>
    /// A callback used to receive notification that a build has completed.
    /// </summary>
    /// <remarks>
    /// When this delegate is invoked, the WaitHandle on the BuildSubmission will have been be signalled and the OverallBuildResult will be valid.
    /// </remarks>
    public delegate void GraphBuildSubmissionCompleteCallback(GraphBuildSubmission submission);
 
    /// <summary>
    /// A GraphBuildSubmission represents a graph build request which has been submitted to the BuildManager for processing.  It may be used to
    /// execute synchronous or asynchronous graph build requests and provides access to the results upon completion.
    /// </summary>
    /// <remarks>
    /// This class is thread-safe.
    /// </remarks>
    public class GraphBuildSubmission : BuildSubmissionBase<GraphBuildRequestData, GraphBuildResult>
    {
        internal GraphBuildSubmission(BuildManager buildManager, int submissionId, GraphBuildRequestData requestData) :
            base(buildManager, submissionId, requestData)
        {
            CompleteLogging();
        }
 
        /// <summary>
        /// Starts the request asynchronously and immediately returns control to the caller.
        /// </summary>
        /// <exception cref="InvalidOperationException">The request has already been started or is already complete.</exception>
        public void ExecuteAsync(GraphBuildSubmissionCompleteCallback? callback, object? context)
        {
            void Clb(BuildSubmissionBase<GraphBuildRequestData, GraphBuildResult> submission)
            {
                callback?.Invoke((GraphBuildSubmission)submission);
            }
 
            ExecuteAsync(Clb, context, allowMainThreadBuild: false);
        }
 
        /// <summary>
        /// Starts the request and blocks until results are available.
        /// </summary>
        /// <exception cref="System.InvalidOperationException">The request has already been started or is already complete.</exception>
        public override GraphBuildResult Execute()
        {
            ExecuteAsync(null, null);
            WaitHandle.WaitOne();
 
            ErrorUtilities.VerifyThrow(BuildResult != null,
                "BuildResult is not populated after Execute is done.");
 
            return BuildResult!;
        }
 
        protected internal override void CheckResultValidForCompletion(GraphBuildResult result)
        {
            ErrorUtilities.VerifyThrow(result.SubmissionId == SubmissionId,
                "GraphBuildResult's submission id doesn't match GraphBuildSubmission's");
        }
 
        protected internal override GraphBuildResult CreateFailedResult(Exception exception)
            => new(SubmissionId, exception);
 
        /// <summary>
        /// Whether the build has started.
        /// </summary>
        internal override bool IsStarted { get; set; }
 
        // WARNING!: Do not remove the below proxy properties.
        //  They are required to make the OM forward compatible
        //  (code built against this OM should run against binaries with previous version of OM).
 
        /// <inheritdoc cref="BuildSubmissionBase{GraphBuildRequestData, GraphBuildResult}.BuildResult"/>
        public new GraphBuildResult? BuildResult => base.BuildResult;
 
        /// <inheritdoc cref="BuildSubmissionBase.BuildManager"/>
        public new BuildManager BuildManager => base.BuildManager;
 
        /// <inheritdoc cref="BuildSubmissionBase.SubmissionId"/>
        public new int SubmissionId => base.SubmissionId;
 
        /// <inheritdoc cref="BuildSubmissionBase.AsyncContext"/>
        public new object? AsyncContext => base.AsyncContext;
 
        /// <inheritdoc cref="BuildSubmissionBase.WaitHandle"/>
        public new WaitHandle WaitHandle => base.WaitHandle;
 
        /// <inheritdoc cref="BuildSubmissionBase.IsCompleted"/>
        public new bool IsCompleted => base.IsCompleted;
    }
}