File: BackEnd\Components\RequestBuilder\IntrinsicTasks\CallTarget.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.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.Build.Framework;
 
// This CallTarget intrinsic task replaces the one on Microsoft.Build.Tasks, which is now deprecated.
 
#nullable disable
 
namespace Microsoft.Build.BackEnd
{
    /// <remarks>
    /// This class implements the "CallTarget" task, which invokes other targets within the same
    /// project file.  Marked RunInMTA because we do not want this task to ever be invoked explicitly
    /// on the STA if the RequestBuilder is running on another thread, as this will cause thread
    /// id validation checks to fail.
    /// </remarks>
    [RunInMTA]
    internal class CallTarget : ITask
    {
        /// <summary>
        /// The task logging helper
        /// </summary>
        private TaskLoggingHelper _logHelper;
 
        #region Properties
 
        // outputs of all built targets
        private readonly List<ITaskItem> _targetOutputs = new List<ITaskItem>();
 
        /// <summary>
        /// A list of targets to build.  This is a required parameter.  If you want to build the
        /// default targets, use the <see cref="MSBuild"/> task and pass in Projects=$(MSBuildProjectFile).
        /// </summary>
        /// <value>Array of target names.</value>
        public string[] Targets { get; set; } = null;
 
        /// <summary>
        /// Outputs of the targets built in each project.
        /// </summary>
        /// <value>Array of output items.</value>
        [Output]
        public ITaskItem[] TargetOutputs => _targetOutputs.ToArray();
 
        /// <summary>
        /// When this is true, instead of calling the engine once to build all the targets (for each project),
        /// we would call the engine once per target (for each project).  The benefit of this is that
        /// if one target fails, you can still continue with the remaining targets.
        /// </summary>
        public bool RunEachTargetSeparately { get; set; } = false;
 
        /// <summary>
        /// Deprecated. Does nothing.
        /// </summary>
        public bool UseResultsCache { get; set; } = false;
 
        #endregion
 
        #region ITask Members
 
        public IBuildEngine BuildEngine { get; set; }
 
        public IBuildEngine2 BuildEngine2 => (IBuildEngine2)BuildEngine;
 
        public IBuildEngine3 BuildEngine3 => (IBuildEngine3)BuildEngine;
 
        /// <summary>
        /// The host object, from ITask
        /// </summary>
        public ITaskHost HostObject { get; set; }
 
        public TaskLoggingHelper Log => _logHelper ?? (_logHelper = new TaskLoggingHelper(this));
 
        public bool Execute()
        {
            throw new NotImplementedException();
        }
 
        /// <summary>
        /// Instructs the MSBuild engine to build one or more targets in the current project.
        /// </summary>
        /// <returns>true if all targets built successfully; false if any target fails</returns>
        public Task<bool> ExecuteInternal()
        {
            // Make sure the list of targets was passed in.
            if ((Targets == null) || (Targets.Length == 0))
            {
                return Task.FromResult(true);
            }
 
            // This is a list of string[].  That is, each element in the list is a string[].  Each
            // string[] represents a set of target names to build.  Depending on the value
            // of the RunEachTargetSeparately parameter, we each just call the engine to run all
            // the targets together, or we call the engine separately for each target.
            List<string[]> targetLists = MSBuild.CreateTargetLists(Targets, RunEachTargetSeparately);
 
            var singleProject = new ITaskItem[1];
            singleProject[0] = null;
 
            // Build the specified targets in the current project.
            return MSBuild.ExecuteTargets(
                projects: singleProject,
                propertiesTable: null,
                undefineProperties: null,
                targetLists: targetLists,
                stopOnFirstFailure: false,
                rebaseOutputs: false,
                buildEngine: this.BuildEngine3,
                log: this.Log,
                targetOutputs: _targetOutputs,
                unloadProjectsOnCompletion: false,
                toolsVersion: null,
                skipNonexistentTargets: false);
        }
 
        #endregion
    }
}