Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Improve MSBuild argument parsing and tracking, and use that to set RestoreProperties that optimize Restore for large projects #49526

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 28 commits into from
Jul 2, 2025

Conversation

baronfel
Copy link
Member

@baronfel baronfel commented Jun 22, 2025

The premise of this PR is that we would like to set some properties during Restore-time only that disable certain kinds of default globbing behaviors - those for Compile, EmbeddedResource, and None items. #49415 has the details of why we would want to do this.

MSBuild has a facility for passing properties that only apply during a Restore: --restoreproperty. The caveat to this is that as soon as a single --restoreproperty is passed, the engine no longer uses any of the --property values passed to that same invocation. This means that we need a way to:

  1. track any user-provided --restoreproperty values
  2. track any user-provided --property values
  3. determine if an implicit restore is requested
  4. when performing an implicit restore, mirror any --property values into --restoreproperty values as well, so that the Restore has a similar execution/evaluation environment as its associated build.

To do this, we

  • define a S.CL Option for the --restoreproperty structure.
  • Create a new structure to track all MSBuild-forwarded arguments
  • Force all MSBuild-forwarding pathways to work in terms of this new structure
  • At the last point we know that an implicit restore is requested or not, we mirror the existing properties (if any) into restoreproperties
  • The MSbuildForwardingAppWithoutLogging transforms the new MSbuild args structure into the string array of arguments to forward to MSBuild.

With this new structure in place, we can set the three restoreproperties that control the three item types in question, and we can do so in a way that respects any user-provided properties/restoreproperties that may override our defaults as well.

Every other change in this PR is a result of this approach. Over time, we can model more parts of the MSBuild CLI (targets, binlogs, logger arguments, etc) and expand the scope of the structured MSBuild arguments object, to provide more confidence/control.

I did model properties and targets in this new approach as well - so we have most of the common use cases accurately modeled and understood now.

@baronfel baronfel force-pushed the handle-restore-properties branch 3 times, most recently from a3c3554 to 1f8c0ac Compare June 27, 2025 12:38
@baronfel baronfel marked this pull request as ready for review June 27, 2025 15:23
@Copilot Copilot AI review requested due to automatic review settings June 27, 2025 15:23
Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR implements a new mechanism for handling restore properties by introducing a structured MSBuild arguments object (MSBuildArgs) and converting all MSBuild property–forwarding from the legacy dash-prefix (‑property:) style to the new double‐dash (“--property:”) convention. Key changes include refactoring command-line parsing and forwarding logic across multiple commands, updating tests to match the new syntax, and adding support for restore‐only properties that disable default item globbing.

Reviewed Changes

Copilot reviewed 46 out of 47 changed files in this pull request and generated 2 comments.

File Description
test/dotnet.Tests/CommandTests/* Updated tests to assert ApplicationArgs and revised MSBuild property syntax
src/Cli/dotnet/* and src/Cli/Microsoft.DotNet.Cli.Utils/* Refactored MSBuild forwarding and option parsing to use the new MSBuildArgs structure and “--property:” style
src/Cli/Microsoft.DotNet.Cli.Utils/MSBuildArgs.cs Introduced a structured model for accumulating MSBuild arguments with proper merging of global and restore properties
Comments suppressed due to low confidence (1)

src/Cli/Microsoft.DotNet.Cli.Utils/MSBuildArgs.cs:115

  • It would be beneficial to add a comment clarifying that duplicate keys from additional restore properties will overwrite existing ones, to aid future maintainability and user understanding.
    public void ApplyPropertiesToRestore()

@baronfel baronfel requested review from a team and removed request for a team June 27, 2025 23:10
@baronfel baronfel requested review from tmat, arunchndr and a team as code owners June 28, 2025 01:39
@baronfel
Copy link
Member Author

There's only one interesting failing test - Microsoft.DotNet.Tests.PackagedCommandTests.CanInvokeToolWhosePackageNameIsDifferentFromDllName. This test is intended to show that we can invoke tools that are pulled in via the mostly-deprecated DotNetCliToolReference mechanism. The tool that's brought in is targeting netcoreapp2.2, which apparently we no longer provision on the build hosts?

I'm inclined to remove this test.

@baronfel baronfel force-pushed the handle-restore-properties branch from 7372306 to f12508f Compare June 28, 2025 16:32
@baronfel baronfel changed the title Handle restore properties and set 3 that disable default items Improve MSBuild argument parsing and tracking, and use that to set RestoreProperties that optimize Restore for large projects Jun 29, 2025
@baronfel baronfel force-pushed the handle-restore-properties branch from b03968d to 02712c5 Compare July 1, 2025 13:33
Copy link
Member

@MiYanni MiYanni left a comment

Choose a reason for hiding this comment

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

Since this PR is so large, I've ignored most of my super minor nits I'd normally point out (extra/missing spaces, extra newlines, comments starting with lowercase letters, odd formatting, use of !, etc.). The core changes seem solid.

Comment on lines +14 to +20
System.CommandLine.Command command,
Argument<string[]> catchAllUserInputArgument,
Func<MSBuildArgs, string, VirtualProjectBuildingCommand> configureVirtualCommand,
Func<MSBuildArgs, string?, CommandBase> createPhysicalCommand,
IEnumerable<Option> optionsToUseWhenParsingMSBuildFlags,
ParseResult parseResult,
string? msbuildPath = null)
Copy link
Member

Choose a reason for hiding this comment

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

This is a little funky. Maybe a class/record to hold this stuff just as a DTO to send to this command?

@@ -95,4 +95,15 @@
<Using Include="System.Collections.Generic.Dictionary%3CMicrosoft.NET.Sdk.WorkloadManifestReader.WorkloadId, Microsoft.NET.Sdk.WorkloadManifestReader.WorkloadDefinition%3E" Alias="WorkloadCollection" />
</ItemGroup>

<!-- NOTE: only works for fast-path code changes -->
<Target Name="CopyToRedistFastPath" AfterTargets="AfterBuild">
Copy link
Member

Choose a reason for hiding this comment

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

This is curious. Does this fix the issue where rebuilding the CLI I wasn't always getting new updates? I'd end up needing to do a full new build to get certain things to work that I've changed.

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! But only for the subset of things that are actually contained in the dotnet.dll. This is totally a hack. If you change Targets, or something in the Cli.Utils.dll, etc - no benefit. Even so it's massively sped up my cycle times.

Copy link
Member

Choose a reason for hiding this comment

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

Nice, I've long wanted to add something like this. I've been running manually this command every time I built dotnet CLI :)

cp .\artifacts\bin\dotnet\Debug\net10.0\dotnet.dll .\artifacts\bin\redist\Debug\dotnet\sdk\10.0.100-dev\

@@ -9,32 +9,6 @@ public GivenParserDirectives(ITestOutputHelper log) : base(log)
{
}

[Fact]
public void ItCanInvokeDiagramDirective()
Copy link
Member

Choose a reason for hiding this comment

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

Are these tests just no longer valid or...?

Copy link
Member Author

Choose a reason for hiding this comment

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

The diagram directive is a S.CL builtin - and it's not user-facing. It's not a relevant thing to test IMO.

@baronfel
Copy link
Member Author

baronfel commented Jul 2, 2025

@jjonescz do you have a sec to take a look at Microsoft.DotNet.Cli.Run.Tests.RunFileTests.NoRestore_01 and see if I messed something up on this branch? When I debug this test it seems to work, but when I run the test it fails. It feels like a timing issue?

The output logs for the test are:

Executing 'dotnet run --no-restore Program.cs':
》__________________________________________________
》Project "E:\Code\dotnet-sdk\artifacts\tmp\Debug\NoRestore_01\Program.csproj" (Build target(s)):
》
》E:\Code\dotnet-sdk\artifacts\bin\redist\Debug\dotnet\sdk\10.0.100-dev\Sdks\Microsoft.NET.Sdk\targets\Microsoft.PackageDependencyResolution.targets(266,5): error NETSDK1004: Assets file 'C:\Users\chusk\AppData\Local\Temp\dotnet\runfile\Program-44d8093e140b3ceefcb5c0b5d4e6b101fc1ef03cc861347d6b511999f0a8ff6c\obj\project.assets.json' not found. Run a NuGet package restore to generate this file.
》Done building project "Program.csproj" -- FAILED.
❌
❌The build failed. Fix the build errors and run again.
Command 'dotnet run --no-restore Program.cs' exited with exit code 1.
Executing 'dotnet restore Program.cs':
》__________________________________________________
》Project "E:\Code\dotnet-sdk\artifacts\tmp\Debug\NoRestore_01\Program.csproj" (Restore target(s)):
》
》Restored E:\Code\dotnet-sdk\artifacts\tmp\Debug\NoRestore_01\Program.csproj (in 349 ms).
Command 'dotnet restore Program.cs' exited with exit code 0.
Executing 'dotnet run --no-restore Program.cs /bl:{}':
》Warning: Binary log option was specified but build will be skipped because output is up to date, specify '--no-cache' to force build.
❌Unhandled exception: An error occurred trying to start process 'C:\Users\chusk\AppData\Local\Temp\dotnet\runfile\Program-44d8093e140b3ceefcb5c0b5d4e6b101fc1ef03cc861347d6b511999f0a8ff6c\bin\debug\Program.exe' with working directory 'E:\Code\dotnet-sdk\artifacts\tmp\Debug\NoRestore_01'. The system cannot find the file specified.
Command 'dotnet run --no-restore Program.cs /bl:{}' exited with exit code 1.

and what it seems like is that somehow a 'completed' build is tracked without the actual build occurring - which leads to the invocation of the supposedly-built binary failing.

baronfel added 22 commits July 1, 2025 20:43
… for .NET Framework the same way we do for other projects that consume it.
It's important that per-command default behaviors come first in the list of args to
parse so that user-provided values can override them.
@baronfel baronfel force-pushed the handle-restore-properties branch from c257d1e to 2a5ce81 Compare July 2, 2025 01:43
@baronfel baronfel merged commit 480b58f into dotnet:main Jul 2, 2025
26 checks passed
@baronfel baronfel deleted the handle-restore-properties branch July 2, 2025 13:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants