Skip to content

Support binlog in build/restore of file-based programs #49009

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

Merged
merged 2 commits into from
Jun 10, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions src/Cli/dotnet/Commands/Build/BuildCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@ public static CommandBase FromParseResult(ParseResult parseResult, string msbuil
parseResult.GetResult(BuildCommandParser.SelfContainedOption) is not null,
parseResult.GetResult(BuildCommandParser.NoSelfContainedOption) is not null);

string[] fileArgument = parseResult.GetValue(BuildCommandParser.SlnOrProjectOrFileArgument) ?? [];
string[] args = parseResult.GetValue(BuildCommandParser.SlnOrProjectOrFileArgument) ?? [];

LoggerUtility.SeparateBinLogArguments(args, out var binLogArgs, out var nonBinLogArgs);

string[] forwardedOptions = parseResult.OptionValuesToBeForwarded(BuildCommandParser.GetCommand()).ToArray();

Expand All @@ -39,11 +41,11 @@ public static CommandBase FromParseResult(ParseResult parseResult, string msbuil

CommandBase command;

if (fileArgument is [{ } arg] && VirtualProjectBuildingCommand.IsValidEntryPointPath(arg))
if (nonBinLogArgs is [{ } arg] && VirtualProjectBuildingCommand.IsValidEntryPointPath(arg))
{
command = new VirtualProjectBuildingCommand(
entryPointFileFullPath: Path.GetFullPath(arg),
msbuildArgs: forwardedOptions,
msbuildArgs: [.. forwardedOptions, .. binLogArgs],
verbosity: parseResult.GetValue(CommonOptions.VerbosityOption),
interactive: parseResult.GetValue(CommonOptions.InteractiveMsBuildForwardOption))
{
Expand All @@ -65,7 +67,7 @@ public static CommandBase FromParseResult(ParseResult parseResult, string msbuil

msbuildArgs.AddRange(forwardedOptions);

msbuildArgs.AddRange(fileArgument);
msbuildArgs.AddRange(args);

command = new RestoringCommand(
msbuildArgs: msbuildArgs,
Expand Down
10 changes: 6 additions & 4 deletions src/Cli/dotnet/Commands/Restore/RestoreCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,17 @@ public static CommandBase FromParseResult(ParseResult result, string? msbuildPat

result.ShowHelpOrErrorIfAppropriate();

string[] fileArgument = result.GetValue(RestoreCommandParser.SlnOrProjectOrFileArgument) ?? [];
string[] args = result.GetValue(RestoreCommandParser.SlnOrProjectOrFileArgument) ?? [];

LoggerUtility.SeparateBinLogArguments(args, out var binLogArgs, out var nonBinLogArgs);

string[] forwardedOptions = result.OptionValuesToBeForwarded(RestoreCommandParser.GetCommand()).ToArray();

if (fileArgument is [{ } arg] && VirtualProjectBuildingCommand.IsValidEntryPointPath(arg))
if (nonBinLogArgs is [{ } arg] && VirtualProjectBuildingCommand.IsValidEntryPointPath(arg))
{
return new VirtualProjectBuildingCommand(
entryPointFileFullPath: Path.GetFullPath(arg),
msbuildArgs: forwardedOptions,
msbuildArgs: [.. forwardedOptions, ..binLogArgs],
verbosity: result.GetValue(CommonOptions.VerbosityOption),
interactive: result.GetValue(CommonOptions.InteractiveMsBuildForwardOption))
{
Expand All @@ -41,7 +43,7 @@ public static CommandBase FromParseResult(ParseResult result, string? msbuildPat
};
}

return CreateForwarding(["-target:Restore", .. forwardedOptions, .. fileArgument], msbuildPath);
return CreateForwarding(["-target:Restore", .. forwardedOptions, .. args], msbuildPath);
}

public static MSBuildForwardingApp CreateForwarding(IEnumerable<string> msbuildArgs, string? msbuildPath = null)
Expand Down
18 changes: 3 additions & 15 deletions src/Cli/dotnet/Commands/Run/RunCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -515,24 +515,12 @@ public static RunCommand FromParseResult(ParseResult parseResult)
// bl information to synchronize the restore and build logger configurations
var applicationArguments = parseResult.GetValue(RunCommandParser.ApplicationArguments)?.ToList();

var binlogArgs = new List<string>();
var nonBinLogArgs = new List<string>();
foreach (var arg in applicationArguments ?? [])
{
if (LoggerUtility.IsBinLogArgument(arg))
{
binlogArgs.Add(arg);
}
else
{
nonBinLogArgs.Add(arg);
}
}
LoggerUtility.SeparateBinLogArguments(applicationArguments, out var binLogArgs, out var nonBinLogArgs);

var restoreArgs = parseResult.OptionValuesToBeForwarded(RunCommandParser.GetCommand()).ToList();
if (binlogArgs.Count > 0)
if (binLogArgs.Count > 0)
{
restoreArgs.AddRange(binlogArgs);
restoreArgs.AddRange(binLogArgs);
}

var command = new RunCommand(
Expand Down
15 changes: 1 addition & 14 deletions src/Cli/dotnet/Commands/Test/MSBuildUtility.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,20 +61,7 @@ public static (IEnumerable<ParallelizableTestModuleGroupWithSequentialInnerModul

public static BuildOptions GetBuildOptions(ParseResult parseResult, int degreeOfParallelism)
{
var binLogArgs = new List<string>();
var otherArgs = new List<string>();

foreach (var arg in parseResult.UnmatchedTokens)
{
if (LoggerUtility.IsBinLogArgument(arg))
{
binLogArgs.Add(arg);
}
else
{
otherArgs.Add(arg);
}
}
LoggerUtility.SeparateBinLogArguments(parseResult.UnmatchedTokens, out var binLogArgs, out var otherArgs);

var msbuildArgs = parseResult.OptionValuesToBeForwarded(TestCommandParser.GetCommand())
.Concat(binLogArgs);
Expand Down
17 changes: 17 additions & 0 deletions src/Cli/dotnet/LoggerUtility.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,23 @@ private static FacadeLogger ConfigureDispatcher(List<BinaryLogger> binaryLoggers
return new FacadeLogger(dispatcher);
}

internal static void SeparateBinLogArguments(IEnumerable<string>? args, out List<string> binLogArgs, out List<string> nonBinLogArgs)
Copy link
Preview

Copilot AI May 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] Consider adding XML documentation comments for the SeparateBinLogArguments method to explain its behavior, especially the treatment of null inputs and the criteria used to separate binlog arguments.

Copilot uses AI. Check for mistakes.

{
binLogArgs = new List<string>();
nonBinLogArgs = new List<string>();
foreach (var arg in args ?? [])
{
if (IsBinLogArgument(arg))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will return true for -bl which causes the switch -bl to be put into binLogArgs but not the value. Is that intended?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, -bl doesn't have a value, that would have to be written as -bl:value.

{
binLogArgs.Add(arg);
}
else
{
nonBinLogArgs.Add(arg);
}
}
}

internal static bool IsBinLogArgument(string arg)
{
const StringComparison comp = StringComparison.OrdinalIgnoreCase;
Expand Down
21 changes: 21 additions & 0 deletions test/dotnet.Tests/CommandTests/Run/RunFileTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -573,6 +573,27 @@ public void BinaryLog(bool beforeFile)
.Should().BeEquivalentTo(["msbuild.binlog", "msbuild-dotnet-run.binlog"]);
}

[Theory, CombinatorialData]
public void BinaryLog_Build([CombinatorialValues("restore", "build")] string command, bool beforeFile)
{
var testInstance = _testAssetsManager.CreateTestDirectory();
File.WriteAllText(Path.Join(testInstance.Path, "Program.cs"), s_program);

string[] args = beforeFile
? [command, "-bl", "Program.cs"]
: [command, "Program.cs", "-bl"];

new DotnetCommand(Log, args)
.WithWorkingDirectory(testInstance.Path)
.Execute()
.Should().Pass();

new DirectoryInfo(testInstance.Path)
.EnumerateFiles("*.binlog", SearchOption.TopDirectoryOnly)
.Select(f => f.Name)
.Should().BeEquivalentTo(["msbuild.binlog"]);
}

[Theory]
[InlineData("-bl")]
[InlineData("-BL")]
Expand Down
Loading