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

Use repository root for output path calculation when the output isn't a child of the working directory #9805

Open
wants to merge 14 commits into
base: main
Choose a base branch
from
Open
5 changes: 5 additions & 0 deletions src/MSBuild/TerminalLogger/Project.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ public Project(string? targetFramework, StopwatchAbstraction? stopwatch)
/// </summary>
public ReadOnlyMemory<char>? OutputPath { get; set; }

/// <summary>
/// Full path to the 'root' of this project's source control repository, if known.
/// </summary>
public ReadOnlyMemory<char>? SourceRoot { get; set; }
baronfel marked this conversation as resolved.
Show resolved Hide resolved

/// <summary>
/// The target framework of the project or null if not multi-targeting.
/// </summary>
Expand Down
71 changes: 64 additions & 7 deletions src/MSBuild/TerminalLogger/TerminalLogger.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Licensed to the .NET Foundation under one or more agreements.
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
Expand All @@ -9,6 +9,10 @@
using Microsoft.Build.Shared;
using System.Text.RegularExpressions;
using System.Diagnostics;
using Microsoft.Build.Execution;
using Microsoft.Build.Utilities;



#if NET7_0_OR_GREATER
using System.Diagnostics.CodeAnalysis;
Expand Down Expand Up @@ -245,6 +249,11 @@ public void Initialize(IEventSource eventSource)
eventSource.WarningRaised += WarningRaised;
eventSource.ErrorRaised += ErrorRaised;

if (eventSource is IEventSource3 eventSource3)
{
eventSource3.IncludeTaskInputs();
}

if (eventSource is IEventSource4 eventSource4)
{
eventSource4.IncludeEvaluationPropertiesAndItems();
Expand Down Expand Up @@ -520,19 +529,31 @@ private void ProjectFinished(object sender, ProjectFinishedEventArgs e)
urlString = uri.AbsoluteUri;
}

var outputPathString = outputPathSpan.ToString();
var relativeDisplayPath = outputPathString;
var workingDirectory = _initialWorkingDirectory;

// If the output path is under the initial working directory, make the console output relative to that to save space.
if (outputPathSpan.StartsWith(_initialWorkingDirectory.AsSpan(), FileUtilities.PathComparison))
if (outputPathString.StartsWith(workingDirectory, FileUtilities.PathComparison))
{
relativeDisplayPath = Path.GetRelativePath(workingDirectory, outputPathString);
}

// if the output path isn't under the working directory, but is under the source root, make the output relative to that to save space
else if (project.SourceRoot is ReadOnlyMemory<char> sourceRoot)
{
if (outputPathSpan.Length > _initialWorkingDirectory.Length
&& (outputPathSpan[_initialWorkingDirectory.Length] == Path.DirectorySeparatorChar
|| outputPathSpan[_initialWorkingDirectory.Length] == Path.AltDirectorySeparatorChar))
var sourceRootString = sourceRoot.Span.ToString();
if (outputPathString.StartsWith(sourceRootString, FileUtilities.PathComparison))
baronfel marked this conversation as resolved.
Show resolved Hide resolved
{
outputPathSpan = outputPathSpan.Slice(_initialWorkingDirectory.Length + 1);
var relativePathFromOutputToRoot = Path.GetRelativePath(sourceRootString, outputPathString);
// we have the portion from sourceRoot to outputPath, now we need to get the portion from workingDirectory to sourceRoot
var relativePathFromWorkingDirToSourceRoot = Path.GetRelativePath(workingDirectory, sourceRootString);
relativeDisplayPath = Path.Join(relativePathFromWorkingDirToSourceRoot, relativePathFromOutputToRoot);
}
}

Terminal.WriteLine(ResourceUtilities.FormatResourceStringIgnoreCodeAndKeyword("ProjectFinished_OutputPath",
$"{AnsiCodes.LinkPrefix}{urlString}{AnsiCodes.LinkInfix}{outputPathSpan.ToString()}{AnsiCodes.LinkSuffix}"));
$"{AnsiCodes.LinkPrefix}{urlString}{AnsiCodes.LinkInfix}{relativeDisplayPath}{AnsiCodes.LinkSuffix}"));
}
else
{
Expand Down Expand Up @@ -609,6 +630,32 @@ private void TargetFinished(object sender, TargetFinishedEventArgs e)
{
}

private void TryReadSourceControlInformationForProject(BuildEventContext? context, IEnumerable<ITaskItem>? sourceRoots)
{
if (context is null || sourceRoots is null)
{
return;
}

var projectContext = new ProjectContext(context);
if (_projects.TryGetValue(projectContext, out Project? project))
{
if (project.SourceRoot is not null)
{
return;
}
var sourceControlSourceRoot = sourceRoots.FirstOrDefault(root => !string.IsNullOrEmpty(root.GetMetadata("SourceControl")));
if (sourceControlSourceRoot is not null)
{
// This takes the first root from source control the first time it's added to the build.
// This seems to be the Target InitializeSourceControlInformationFromSourceControlManager.
// So far this has been acceptable, but if a SourceRoot would be modified by a task later on
// (e.g. TranslateGitHubUrlsInSourceControlInformation) we would lose that modification.
baronfel marked this conversation as resolved.
Show resolved Hide resolved
project.SourceRoot = sourceControlSourceRoot.ItemSpec.AsMemory();
}
}
}

/// <summary>
/// The <see cref="IEventSource.TaskStarted"/> callback.
/// </summary>
Expand Down Expand Up @@ -639,6 +686,16 @@ private void MessageRaised(object sender, BuildMessageEventArgs e)
}

string? message = e.Message;
if (e is TaskParameterEventArgs taskArgs)
{
if (taskArgs.Kind == TaskParameterMessageKind.AddItem)
{
if (taskArgs.ItemType.Equals("SourceRoot", StringComparison.OrdinalIgnoreCase))
{
TryReadSourceControlInformationForProject(taskArgs.BuildEventContext, taskArgs.Items as IList<ProjectItemInstance>);
}
}
}
if (message is not null && e.Importance == MessageImportance.High)
{
var hasProject = _projects.TryGetValue(new ProjectContext(buildEventContext), out Project? project);
Expand Down