Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add new TargetBuiltReasons #10092

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
10 changes: 5 additions & 5 deletions src/Build.UnitTests/BackEnd/RequestBuilder_Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -356,16 +356,16 @@ internal void SetNewBuildRequests(FullyQualifiedBuildRequest[] requests)

#region ITargetBuilder Members

public Task<BuildResult> BuildTargets(ProjectLoggingContext loggingContext, BuildRequestEntry entry, IRequestBuilderCallback callback, string[] targets, Lookup baseLookup, CancellationToken cancellationToken)
public Task<BuildResult> BuildTargets(ProjectLoggingContext loggingContext, BuildRequestEntry entry, IRequestBuilderCallback callback, (string, TargetBuiltReason)[] targets, Lookup baseLookup, CancellationToken cancellationToken)
{
_requestBuilderCallback = callback;

if (cancellationToken.WaitHandle.WaitOne(1500))
{
BuildResult result = new BuildResult(entry.Request);
foreach (string target in targets)
foreach ((string, TargetBuiltReason) target in targets)
{
result.AddResultsForTarget(target, BuildResultUtilities.GetEmptyFailingTargetResult());
result.AddResultsForTarget(target.Item1, BuildResultUtilities.GetEmptyFailingTargetResult());
}
return Task<BuildResult>.FromResult(result);
}
Expand All @@ -388,9 +388,9 @@ public Task<BuildResult> BuildTargets(ProjectLoggingContext loggingContext, Buil
if (cancellationToken.WaitHandle.WaitOne(1500))
{
BuildResult result = new BuildResult(entry.Request);
foreach (string target in targets)
foreach ((string, TargetBuiltReason) target in targets)
{
result.AddResultsForTarget(target, BuildResultUtilities.GetEmptyFailingTargetResult());
result.AddResultsForTarget(target.Item1, BuildResultUtilities.GetEmptyFailingTargetResult());
}
return Task<BuildResult>.FromResult(result);
}
Expand Down
170 changes: 101 additions & 69 deletions src/Build.UnitTests/BackEnd/TargetBuilder_Tests.cs

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions src/Build/BackEnd/Components/Logging/NodeLoggingContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -90,16 +90,16 @@ internal void LogRequestHandledFromCache(BuildRequest request, BuildRequestConfi

// When pulling a request from the cache, we want to make sure we log a target skipped event for any targets which
// were used to build the request including default and initial targets.
foreach (string target in configuration.GetTargetsUsedToBuildRequest(request))
foreach ((string, TargetBuiltReason) target in configuration.GetTargetsUsedToBuildRequest(request))
{
var targetResult = result[target];
var targetResult = result[target.Item1];
bool isFailure = targetResult.ResultCode == TargetResultCode.Failure;

var skippedTargetEventArgs = new TargetSkippedEventArgs(message: null)
{
BuildEventContext = projectLoggingContext.BuildEventContext,
TargetName = target,
BuildReason = TargetBuiltReason.None,
TargetName = target.Item1,
BuildReason = target.Item2,
SkipReason = isFailure ? TargetSkipReason.PreviouslyBuiltUnsuccessfully : TargetSkipReason.PreviouslyBuiltSuccessfully,
OriginallySucceeded = !isFailure,
OriginalBuildEventContext = (targetResult as TargetResult)?.OriginalBuildEventContext
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Build.BackEnd.Logging;
using Microsoft.Build.Framework;
using BuildResult = Microsoft.Build.Execution.BuildResult;

#nullable disable
Expand All @@ -25,6 +26,6 @@ internal interface ITargetBuilder
/// <param name="baseLookup">The Lookup containing all current items and properties for this target.</param>
/// <param name="cancellationToken">The cancellation token used to cancel processing of targets.</param>
/// <returns>A Task representing the work to be done.</returns>
Task<BuildResult> BuildTargets(ProjectLoggingContext projectLoggingContext, BuildRequestEntry entry, IRequestBuilderCallback callback, string[] targets, Lookup baseLookup, CancellationToken cancellationToken);
Task<BuildResult> BuildTargets(ProjectLoggingContext projectLoggingContext, BuildRequestEntry entry, IRequestBuilderCallback callback, (string, TargetBuiltReason)[] targets, Lookup baseLookup, CancellationToken cancellationToken);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1177,7 +1177,7 @@ private async Task<BuildResult> BuildProject()
_requestEntry.Request.BuildEventContext = _projectLoggingContext.BuildEventContext;

// Determine the set of targets we need to build
string[] allTargets = _requestEntry.RequestConfiguration
(string, TargetBuiltReason)[] allTargets = _requestEntry.RequestConfiguration
.GetTargetsUsedToBuildRequest(_requestEntry.Request).ToArray();

ProjectErrorUtilities.VerifyThrowInvalidProject(allTargets.Length > 0,
Expand Down
26 changes: 14 additions & 12 deletions src/Build/BackEnd/Components/RequestBuilder/TargetBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ internal class TargetBuilder : ITargetBuilder, ITargetBuilderCallback, IBuildCom
/// <param name="baseLookup">The Lookup containing all current items and properties for this target.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to use when building the targets.</param>
/// <returns>The target's outputs and result codes</returns>
public async Task<BuildResult> BuildTargets(ProjectLoggingContext loggingContext, BuildRequestEntry entry, IRequestBuilderCallback callback, string[] targetNames, Lookup baseLookup, CancellationToken cancellationToken)
public async Task<BuildResult> BuildTargets(ProjectLoggingContext loggingContext, BuildRequestEntry entry, IRequestBuilderCallback callback, (string, TargetBuiltReason)[] targetNames, Lookup baseLookup, CancellationToken cancellationToken)
{
ErrorUtilities.VerifyThrowArgumentNull(loggingContext, "projectLoggingContext");
ErrorUtilities.VerifyThrowArgumentNull(entry, nameof(entry));
Expand Down Expand Up @@ -143,17 +143,17 @@ public async Task<BuildResult> BuildTargets(ProjectLoggingContext loggingContext

List<TargetSpecification> targets = new List<TargetSpecification>(targetNames.Length);

foreach (string targetName in targetNames)
foreach ((string, TargetBuiltReason) targetName in targetNames)
{
var targetExists = _projectInstance.Targets.TryGetValue(targetName, out ProjectTargetInstance targetInstance);
var targetExists = _projectInstance.Targets.TryGetValue(targetName.Item1, out ProjectTargetInstance targetInstance);
if (!targetExists && entry.Request.BuildRequestDataFlags.HasFlag(BuildRequestDataFlags.SkipNonexistentTargets))
{
_projectLoggingContext.LogComment(Framework.MessageImportance.Low,
"TargetSkippedWhenSkipNonexistentTargets", targetName);
"TargetSkippedWhenSkipNonexistentTargets", targetName.Item1);
}
else
{
targets.Add(new TargetSpecification(targetName, targetExists ? targetInstance.Location : _projectInstance.ProjectFileLocation));
targets.Add(new TargetSpecification(targetName.Item1, targetExists ? targetInstance.Location : _projectInstance.ProjectFileLocation, targetName.Item2));
}
}

Expand Down Expand Up @@ -185,7 +185,7 @@ public async Task<BuildResult> BuildTargets(ProjectLoggingContext loggingContext

// Gather up outputs for the requested targets and return those. All of our information should be in the base lookup now.
ComputeAfterTargetFailures(targetNames);
BuildResult resultsToReport = new BuildResult(_buildResult, targetNames);
BuildResult resultsToReport = new BuildResult(_buildResult, targetNames.Select(target => target.Item1).ToArray());

// Return after-build project state if requested.
if (_requestEntry.Request.BuildRequestDataFlags.HasFlag(BuildRequestDataFlags.ProvideProjectStateAfterBuild))
Expand Down Expand Up @@ -737,7 +737,9 @@ private async Task<bool> PushTargets(IList<TargetSpecification> targets, TargetE

// Add to the list of targets to push. We don't actually put it on the stack here because we could run into a circular dependency
// during this loop, in which case the target stack would be out of whack.
TargetEntry newEntry = new TargetEntry(_requestEntry, this as ITargetBuilderCallback, targetSpecification, baseLookup, parentTargetEntry, buildReason, _componentHost, _projectLoggingContext, stopProcessingOnCompletion);
TargetBuiltReason entryReason = buildReason == TargetBuiltReason.None ? targetSpecification._targetBuiltReason : buildReason;
TargetEntry newEntry = new TargetEntry(_requestEntry, this as ITargetBuilderCallback, targetSpecification, baseLookup, parentTargetEntry, entryReason, _componentHost, _projectLoggingContext, stopProcessingOnCompletion);

newEntry.ErrorTarget = addAsErrorTarget;
targetsToPush.Add(newEntry);
stopProcessingOnCompletion = false; // The first target on the stack (the last one to be run) always inherits the stopProcessing flag.
Expand Down Expand Up @@ -772,15 +774,15 @@ private async Task<bool> CompleteOutstandingActiveRequests(string targetName)
return false;
}

private void ComputeAfterTargetFailures(string[] targetNames)
private void ComputeAfterTargetFailures((string, TargetBuiltReason)[] targetNames)
{
foreach (string targetName in targetNames)
foreach ((string, TargetBuiltReason) targetName in targetNames)
{
if (_buildResult.ResultsByTarget.TryGetValue(targetName, out TargetResult targetBuildResult))
if (_buildResult.ResultsByTarget.TryGetValue(targetName.Item1, out TargetResult targetBuildResult))
{
// Queue of targets waiting to be processed, seeded with the specific target for which we're computing AfterTargetsHaveFailed.
var targetsToCheckForAfterTargets = new Queue<string>();
targetsToCheckForAfterTargets.Enqueue(targetName);
targetsToCheckForAfterTargets.Enqueue(targetName.Item1);

// Set of targets already processed, to break cycles of AfterTargets.
// Initialized lazily when needed below.
Expand All @@ -804,7 +806,7 @@ private void ComputeAfterTargetFailures(string[] targetNames)

targetsChecked ??= new HashSet<string>(MSBuildNameIgnoreCaseComparer.Default)
{
targetName
targetName.Item1
};

// If we haven't seen this target yet, add it to the list to check.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System.Diagnostics;
using Microsoft.Build.Framework;
using Microsoft.Build.Shared;
using ElementLocation = Microsoft.Build.Construction.ElementLocation;

Expand All @@ -18,18 +19,22 @@ internal class TargetSpecification : ITranslatable
private string _targetName;
private ElementLocation _referenceLocation;

internal TargetBuiltReason _targetBuiltReason;

/// <summary>
/// Construct a target specification.
/// </summary>
/// <param name="targetName">The name of the target</param>
/// <param name="referenceLocation">The location from which it was referred.</param>
internal TargetSpecification(string targetName, ElementLocation referenceLocation)
/// <param name="targetBuiltReason">Reason the target is being built</param>
internal TargetSpecification(string targetName, ElementLocation referenceLocation, TargetBuiltReason targetBuiltReason = TargetBuiltReason.None)
{
ErrorUtilities.VerifyThrowArgumentLength(targetName, nameof(targetName));
ErrorUtilities.VerifyThrowArgumentNull(referenceLocation, nameof(referenceLocation));

this._targetName = targetName;
this._referenceLocation = referenceLocation;
this._targetBuiltReason = targetBuiltReason;
}

private TargetSpecification()
Expand All @@ -41,6 +46,8 @@ private TargetSpecification()
/// </summary>
public string TargetName => _targetName;

public TargetBuiltReason TargetBuiltReason => _targetBuiltReason;

/// <summary>
/// Gets or sets the reference location
/// </summary>
Expand Down
10 changes: 6 additions & 4 deletions src/Build/BackEnd/Shared/BuildRequestConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -762,7 +762,7 @@ public void RetrieveFromCache()
/// </summary>
/// <param name="request">The request </param>
/// <returns>An array of t</returns>
public List<string> GetTargetsUsedToBuildRequest(BuildRequest request)
public List<(string, TargetBuiltReason)> GetTargetsUsedToBuildRequest(BuildRequest request)
{
ErrorUtilities.VerifyThrow(request.ConfigurationId == ConfigurationId, "Request does not match configuration.");
ErrorUtilities.VerifyThrow(_projectInitialTargets != null, "Initial targets have not been set.");
Expand All @@ -775,10 +775,12 @@ public List<string> GetTargetsUsedToBuildRequest(BuildRequest request)
"Targets must be same as proxy targets");
}

List<string> initialTargets = _projectInitialTargets;
List<string> nonInitialTargets = (request.Targets.Count == 0) ? _projectDefaultTargets : request.Targets;
List<(string, TargetBuiltReason)> initialTargets = _projectInitialTargets.ConvertAll(target => (target, TargetBuiltReason.InitialTargets));
List<(string, TargetBuiltReason)> nonInitialTargets = (request.Targets.Count == 0)
? _projectDefaultTargets.ConvertAll(target => (target, TargetBuiltReason.DefaultTargets))
: request.Targets.ConvertAll(target => (target, TargetBuiltReason.EntryTargets));

var allTargets = new List<string>(initialTargets.Count + nonInitialTargets.Count);
var allTargets = new List<(string, TargetBuiltReason)>(initialTargets.Count + nonInitialTargets.Count);

allTargets.AddRange(initialTargets);
allTargets.AddRange(nonInitialTargets);
Expand Down
17 changes: 16 additions & 1 deletion src/Framework/TargetBuiltReason.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,21 @@ public enum TargetBuiltReason
/// <summary>
/// The target was part of the parent's AfterTargets list.
/// </summary>
AfterTargets
AfterTargets,

/// <summary>
/// The target was defined as an initial target of the project.
/// </summary>
InitialTargets,

/// <summary>
/// The target was one of the default targets of the project.
/// </summary>
DefaultTargets,

/// <summary>
/// The target was one of the targets explicitly called to be built.
/// </summary>
EntryTargets
}
}