|
// 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 Microsoft.Build.Collections;
using Microsoft.Build.Evaluation;
using Microsoft.Build.Shared;
#nullable disable
namespace Microsoft.Build.Execution
{
/// <summary>
/// Flags providing additional control over the build request
/// </summary>
[Flags]
public enum BuildRequestDataFlags
{
/// <summary>
/// No flags.
/// </summary>
None = 0,
/// <summary>
/// When this flag is present, the existing ProjectInstance in the build will be replaced by this one.
/// </summary>
ReplaceExistingProjectInstance = 1 << 0,
/// <summary>
/// When this flag is present, the <see cref="BuildResult"/> issued in response to this request will
/// include <see cref="BuildResult.ProjectStateAfterBuild"/>.
/// </summary>
ProvideProjectStateAfterBuild = 1 << 1,
/// <summary>
/// When this flag is present and the project has previously been built on a node whose affinity is
/// incompatible with the affinity this request requires, we will ignore the project state (but not
/// target results) that were previously generated.
/// </summary>
/// <remarks>
/// This usually is not desired behavior. It is only provided for those cases where the client
/// knows that the new build request does not depend on project state generated by a previous request. Setting
/// this flag can provide a performance boost in the case of incompatible node affinities, as MSBuild would
/// otherwise have to serialize the project state from one node to another, which may be
/// expensive depending on how much data the project previously generated.
///
/// This flag has no effect on target results, so if a previous request already built a target, the new
/// request will not re-build that target (nor will any of the project state mutations which previously
/// occurred as a consequence of building that target be re-applied.)
/// </remarks>
IgnoreExistingProjectState = 1 << 2,
/// <summary>
/// When this flag is present, caches including the <see cref="ProjectRootElementCacheBase"/> will be cleared
/// after the build request completes. This is used when the build request is known to modify a lot of
/// state such as restoring packages or generating parts of the import graph.
/// </summary>
ClearCachesAfterBuild = 1 << 3,
/// <summary>
/// When this flag is present, the top level target(s) in the build request will be skipped if those targets
/// are not defined in the Project to build. This only applies to this build request (if another target calls
/// the "missing target" at any other point this will still result in an error).
/// </summary>
SkipNonexistentTargets = 1 << 4,
/// <summary>
/// When this flag is present, the <see cref="BuildResult"/> issued in response to this request will
/// include a <see cref="BuildResult.ProjectStateAfterBuild"/> that includes ONLY the
/// explicitly-requested properties, items, and metadata.
/// </summary>
ProvideSubsetOfStateAfterBuild = 1 << 5,
/// <summary>
/// When this flag is present, projects loaded during build will ignore missing imports (<see cref="ProjectLoadSettings.IgnoreMissingImports"/> and <see cref="ProjectLoadSettings.IgnoreInvalidImports"/>).
/// This is especially useful during a restore since some imports might come from packages that haven't been restored yet.
/// </summary>
IgnoreMissingEmptyAndInvalidImports = 1 << 6,
/// <summary>
/// When this flag is present, an unresolved MSBuild project SDK will fail the build. This flag is used to
/// change the <see cref="IgnoreMissingEmptyAndInvalidImports" /> behavior to still fail when an SDK is missing
/// because those are more fatal.
/// </summary>
FailOnUnresolvedSdk = 1 << 7,
}
/// <summary>
/// BuildRequestData encapsulates all of the data needed to submit a build request.
/// </summary>
public class BuildRequestData
{
/// <summary>
/// Constructs a BuildRequestData for build requests based on project instances.
/// </summary>
/// <param name="projectInstance">The instance to build.</param>
/// <param name="targetsToBuild">The targets to build.</param>
public BuildRequestData(ProjectInstance projectInstance, string[] targetsToBuild)
: this(projectInstance, targetsToBuild, null, BuildRequestDataFlags.None)
{
}
/// <summary>
/// Constructs a BuildRequestData for build requests based on project instances.
/// </summary>
/// <param name="projectInstance">The instance to build.</param>
/// <param name="targetsToBuild">The targets to build.</param>
/// <param name="hostServices">The host services to use, if any. May be null.</param>
public BuildRequestData(ProjectInstance projectInstance, string[] targetsToBuild, HostServices hostServices)
: this(projectInstance, targetsToBuild, hostServices, BuildRequestDataFlags.None)
{
}
/// <summary>
/// Constructs a BuildRequestData for build requests based on project instances.
/// </summary>
/// <param name="projectInstance">The instance to build.</param>
/// <param name="targetsToBuild">The targets to build.</param>
/// <param name="hostServices">The host services to use, if any. May be null.</param>
/// <param name="flags">Flags controlling this build request.</param>
public BuildRequestData(ProjectInstance projectInstance, string[] targetsToBuild, HostServices hostServices, BuildRequestDataFlags flags)
: this(projectInstance, targetsToBuild, hostServices, flags, null)
{
}
/// <summary>
/// Constructs a BuildRequestData for build requests based on project instances.
/// </summary>
/// <param name="projectInstance">The instance to build.</param>
/// <param name="targetsToBuild">The targets to build.</param>
/// <param name="hostServices">The host services to use, if any. May be null.</param>
/// <param name="flags">Flags controlling this build request.</param>
/// <param name="propertiesToTransfer">The list of properties whose values should be transferred from the project to any out-of-proc node.</param>
public BuildRequestData(ProjectInstance projectInstance, string[] targetsToBuild, HostServices hostServices, BuildRequestDataFlags flags, IEnumerable<string> propertiesToTransfer)
: this(targetsToBuild, hostServices, flags)
{
ErrorUtilities.VerifyThrowArgumentNull(projectInstance, nameof(projectInstance));
foreach (string targetName in targetsToBuild)
{
ErrorUtilities.VerifyThrowArgumentNull(targetName, "target");
}
ProjectInstance = projectInstance;
ProjectFullPath = projectInstance.FullPath;
GlobalPropertiesDictionary = projectInstance.GlobalPropertiesDictionary;
ExplicitlySpecifiedToolsVersion = projectInstance.ExplicitToolsVersion;
if (propertiesToTransfer != null)
{
PropertiesToTransfer = new List<string>(propertiesToTransfer);
}
}
/// <summary>
/// Constructs a BuildRequestData for build requests based on project instances.
/// </summary>
/// <param name="projectInstance">The instance to build.</param>
/// <param name="targetsToBuild">The targets to build.</param>
/// <param name="hostServices">The host services to use, if any. May be null.</param>
/// <param name="flags">Flags controlling this build request.</param>
/// <param name="propertiesToTransfer">The list of properties whose values should be transferred from the project to any out-of-proc node.</param>
/// <param name="requestedProjectState">A <see cref="Execution.RequestedProjectState"/> describing properties, items, and metadata that should be returned. Requires setting <see cref="BuildRequestDataFlags.ProvideSubsetOfStateAfterBuild"/>.</param>
public BuildRequestData(ProjectInstance projectInstance, string[] targetsToBuild, HostServices hostServices, BuildRequestDataFlags flags, IEnumerable<string> propertiesToTransfer, RequestedProjectState requestedProjectState)
: this(projectInstance, targetsToBuild, hostServices, flags, propertiesToTransfer)
{
ErrorUtilities.VerifyThrowArgumentNull(requestedProjectState, nameof(requestedProjectState));
RequestedProjectState = requestedProjectState;
}
/// <summary>
/// Constructs a BuildRequestData for build requests based on project files.
/// </summary>
/// <param name="projectFullPath">The full path to the project file.</param>
/// <param name="globalProperties">The global properties which should be used during evaluation of the project. Cannot be null.</param>
/// <param name="toolsVersion">The tools version to use for the build. May be null.</param>
/// <param name="targetsToBuild">The targets to build.</param>
/// <param name="hostServices">The host services to use. May be null.</param>
public BuildRequestData(string projectFullPath, IDictionary<string, string> globalProperties, string toolsVersion, string[] targetsToBuild, HostServices hostServices)
: this(projectFullPath, globalProperties, toolsVersion, targetsToBuild, hostServices, BuildRequestDataFlags.None)
{
}
/// <summary>
/// Constructs a BuildRequestData for build requests based on project files.
/// </summary>
/// <param name="projectFullPath">The full path to the project file.</param>
/// <param name="globalProperties">The global properties which should be used during evaluation of the project. Cannot be null.</param>
/// <param name="toolsVersion">The tools version to use for the build. May be null.</param>
/// <param name="targetsToBuild">The targets to build.</param>
/// <param name="hostServices">The host services to use. May be null.</param>
/// <param name="flags">The <see cref="BuildRequestDataFlags"/> to use.</param>
/// <param name="requestedProjectState">A <see cref="Execution.RequestedProjectState"/> describing properties, items, and metadata that should be returned. Requires setting <see cref="BuildRequestDataFlags.ProvideSubsetOfStateAfterBuild"/>.</param>
public BuildRequestData(string projectFullPath, IDictionary<string, string> globalProperties,
string toolsVersion, string[] targetsToBuild, HostServices hostServices, BuildRequestDataFlags flags,
RequestedProjectState requestedProjectState)
: this(projectFullPath, globalProperties, toolsVersion, targetsToBuild, hostServices, flags)
{
ErrorUtilities.VerifyThrowArgumentNull(requestedProjectState, nameof(requestedProjectState));
RequestedProjectState = requestedProjectState;
}
/// <summary>
/// Constructs a BuildRequestData for build requests based on project files.
/// </summary>
/// <param name="projectFullPath">The full path to the project file.</param>
/// <param name="globalProperties">The global properties which should be used during evaluation of the project. Cannot be null.</param>
/// <param name="toolsVersion">The tools version to use for the build. May be null.</param>
/// <param name="targetsToBuild">The targets to build.</param>
/// <param name="hostServices">The host services to use. May be null.</param>
/// <param name="flags">The <see cref="BuildRequestDataFlags"/> to use.</param>
public BuildRequestData(string projectFullPath, IDictionary<string, string> globalProperties, string toolsVersion, string[] targetsToBuild, HostServices hostServices, BuildRequestDataFlags flags)
: this(targetsToBuild, hostServices, flags)
{
ErrorUtilities.VerifyThrowArgumentLength(projectFullPath, nameof(projectFullPath));
ErrorUtilities.VerifyThrowArgumentNull(globalProperties, nameof(globalProperties));
ProjectFullPath = FileUtilities.NormalizePath(projectFullPath);
GlobalPropertiesDictionary = new PropertyDictionary<ProjectPropertyInstance>(globalProperties.Count);
foreach (KeyValuePair<string, string> propertyPair in globalProperties)
{
GlobalPropertiesDictionary.Set(ProjectPropertyInstance.Create(propertyPair.Key, propertyPair.Value));
}
ExplicitlySpecifiedToolsVersion = toolsVersion;
}
/// <summary>
/// Common constructor.
/// </summary>
private BuildRequestData(string[] targetsToBuild, HostServices hostServices, BuildRequestDataFlags flags)
{
ErrorUtilities.VerifyThrowArgumentNull(targetsToBuild, nameof(targetsToBuild));
HostServices = hostServices;
TargetNames = new List<string>(targetsToBuild);
Flags = flags;
}
/// <summary>
/// The actual project, in the case where the project doesn't come from disk.
/// May be null.
/// </summary>
/// <value>The project instance.</value>
public ProjectInstance ProjectInstance
{
get;
}
/// <summary>The project file.</summary>
/// <value>The project file to be built.</value>
public string ProjectFullPath { get; internal set; }
/// <summary>
/// The name of the targets to build.
/// </summary>
/// <value>An array of targets in the project to be built.</value>
public ICollection<string> TargetNames { get; }
/// <summary>
/// Extra flags for this BuildRequest.
/// </summary>
public BuildRequestDataFlags Flags { get; }
/// <summary>
/// The global properties to use.
/// </summary>
/// <value>The set of global properties to be used to build this request.</value>
public ICollection<ProjectPropertyInstance> GlobalProperties => (GlobalPropertiesDictionary == null) ?
(ICollection<ProjectPropertyInstance>)ReadOnlyEmptyCollection<ProjectPropertyInstance>.Instance :
new ReadOnlyCollection<ProjectPropertyInstance>(GlobalPropertiesDictionary);
/// <summary>
/// The explicitly requested tools version to use.
/// </summary>
public string ExplicitlySpecifiedToolsVersion { get; }
/// <summary>
/// Gets the HostServices object for this request.
/// </summary>
public HostServices HostServices { get; }
/// <summary>
/// Returns a list of properties to transfer out of proc for the build.
/// </summary>
public IEnumerable<string> PropertiesToTransfer { get; }
/// <summary>
/// Returns the properties, items, and metadata that will be returned
/// by this build.
/// </summary>
public RequestedProjectState RequestedProjectState { get; }
/// <summary>
/// Whether the tools version used originated from an explicit specification,
/// for example from an MSBuild task or /tv switch.
/// </summary>
internal bool ExplicitToolsVersionSpecified => ExplicitlySpecifiedToolsVersion != null;
/// <summary>
/// Returns the global properties as a dictionary.
/// </summary>
internal PropertyDictionary<ProjectPropertyInstance> GlobalPropertiesDictionary { get; }
}
}
|