Add AOT support for dotnet sln list, migrate, and remove#54384
Add AOT support for dotnet sln list, migrate, and remove#54384NikolaMilosavljevic wants to merge 9 commits into
Conversation
Enable 'sln list' and 'sln migrate' commands in the AOT-compiled CLI (dotnet-aot). These commands are self-contained — they parse solution files using Microsoft.VisualStudio.SolutionPersistence without any MSBuild or NuGet dependencies. Changes: - Parser.cs: Add sln command with list/migrate subcommands under #if CLI_AOT, with inline action handlers that avoid CommandBase and its ParseResultExtensions dependency chain - dotnet-aot.csproj: Link SlnFileFactory.cs and SlnfFileHelper.cs, add CliStrings.resx as embedded resource, add Microsoft.VisualStudio.SolutionPersistence package reference Design decisions: - SLN_FILE argument is on each subcommand (not parent) so that unsupported commands like 'sln add/remove' produce parse errors and correctly fall back to the managed CLI - Hardcoded English strings for AOT-specific messages (matching the existing --info AOT pattern) to avoid CliCommandStrings.resx dep - GracefulException handling wraps all action handlers Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Implement sln remove subcommand in the CLI_AOT parser section, including project removal from both .sln and .slnf files, empty solution folder cleanup, and directory-to-project resolution. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… validation
- sln migrate: Use same error/success messages as managed implementation
('Only .sln files can be migrated' and '.slnx file {0} generated.')
- sln remove: Add validation to detect misplaced .sln/.slnx files in
project arguments with 'Did you mean' suggestion
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Move SLN_FILE argument from individual subcommands to the parent sln command, matching the managed CLI structure. This fixes a parsing ambiguity where 'dotnet sln remove proj1.csproj proj2.csproj' could misinterpret the first project as the solution file. Also: - Remove parent sln action handler so bare 'dotnet sln' falls back to managed CLI (which shows complete help including 'add') - Use .GetAwaiter().GetResult() instead of .Wait() in migrate Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
@NikolaMilosavljevic as we start lighting up these commands, a before/after comparison of time spent would be very useful data to have! |
There was a problem hiding this comment.
Pull request overview
Adds Native AOT support for dotnet sln list, sln migrate, and sln remove by wiring inline handlers into the CLI_AOT Parser, linking the SlnFileFactory/SlnfFileHelper source files into the AOT project, and providing a hand-written CliStrings shim with the subset of strings these flows need. Unknown sln subcommands and bare dotnet sln deliberately fail to parse so NativeEntryPoint falls back to the managed CLI.
Changes:
- Add
sln list/migrate/removehandlers inParser.csunder#if CLI_AOT, including misplaced-sln-file detection, directory-to-project resolution, and empty-solution-folder cleanup. - Link
SlnFileFactory.cs/SlnfFileHelper.csand add theMicrosoft.VisualStudio.SolutionPersistencepackage reference to the AOT csproj. - Introduce
src/Cli/dotnet-aot/CliStrings.csas a string shim with hard-coded English values for the resources used by the linked sources.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| src/Cli/dotnet/Parser.cs | New ConfigureSolutionCommand, inline list/migrate/remove handlers, and helpers (GetProjectFileFromDirectory, RemoveProjectsFromSolution, RemoveProjectsFromSolutionFilter) duplicated from the managed CLI with hard-coded English strings. |
| src/Cli/dotnet-aot/dotnet-aot.csproj | Links SlnFileFactory.cs/SlnfFileHelper.cs, adds Microsoft.VisualStudio.SolutionPersistence package, includes the new CliStrings.cs shim. |
| src/Cli/dotnet-aot/CliStrings.cs | New shim providing the subset of CliStrings properties (matching the values in CliStrings.resx) consumed by the linked AOT sources. |
Replace duplicated inline command definitions and action handlers with shared code from Microsoft.DotNet.Cli.Definitions project: - Use SolutionCommandDefinition from Definitions project instead of creating ad-hoc Command instances in Parser.cs AOT section - Use SolutionCommandParser to wire actions for list/migrate/remove - Link command implementation files (SolutionListCommand, SolutionMigrateCommand, SolutionRemoveCommand) from managed project - Link CommandBase, CommandParsingException, SolutionArgumentValidator, and MsbuildProject with #if CLI_AOT guards - Replace hand-written CliStrings.cs shim with proper .resx inclusion (CliStrings.resx + CliCommandStrings.resx with GenerateSource) - Add Definitions project reference to dotnet-aot.csproj - Add #if CLI_AOT guards in CommandBase.cs (skip ShowHelpOrErrorIfAppropriate) - Add #if CLI_AOT guards in MsbuildProject.cs (inline file-I/O methods, exclude MSBuild-dependent code) - Add #if CLI_AOT guards in SolutionCommandParser.cs (skip add command and parent action wiring) - Remove AddCommand from AOT parser to trigger managed fallback - Add localized strings for project directory lookup errors Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Refactoring summary (commit 908be28)This commit addresses the review feedback by refactoring the AOT sln commands to share definitions and implementations with the managed CLI instead of duplicating them: Key changes:
Net effect on Parser.cs AOT section:
All 157 sln tests pass (list: 54, migrate: 2, remove: 101). |
baronfel
left a comment
There was a problem hiding this comment.
Love the new approach - it makes a lot of sense to me!
|
One additional note on the refactoring commit: the |
Address review feedback: replace the sketchy Data dictionary check with a direct catch of GracefulException, which is the specific exception type used to signal user-displayable errors. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ption Instead of removing AddCommand from the definition tree in Parser.cs, wire it (and the parent sln command) to throw a dedicated exception in AOT mode. NativeEntryPoint catches CommandNotAvailableInAotException and falls back to managed CLI. This keeps AOT customization local to SolutionCommandParser.cs and the definition tree intact. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Summary
Add Native AOT support for three
dotnet slnsubcommands:list,migrate, andremove. These commands operate on solution files using pure file I/O and theMicrosoft.VisualStudio.SolutionPersistencepackage — no MSBuild or NuGet dependencies required.Changes
New file:
src/Cli/dotnet-aot/CliStrings.csString shim providing the subset of
CliStringsproperties needed by linked source files (SlnFileFactory.cs,Parser.cs) in the AOT project context, where the full.resxauto-generation doesn't work for linked resources.Modified:
src/Cli/dotnet-aot/dotnet-aot.csprojSlnFileFactory.csandSlnfFileHelper.csfrom the main dotnet projectMicrosoft.VisualStudio.SolutionPersistencepackage referenceCliStrings.csshimModified:
src/Cli/dotnet/Parser.cs(#if CLI_AOTsection)slncommand withlist,migrate, andremovesubcommandsSLN_FILEargument on parentslncommand (matching managed CLI structure)sln remove: includes project removal from.slnand.slnffiles, empty folder cleanup, directory-to-project resolution, and misplaced-argument validationdotnet sln(no subcommand) falls back to managed CLI for complete helpDesign decisions
SLN_FILEis on the parentslncommand, not subcommands, matching managed CLI. This prevents parsing ambiguity withsln removewhere an optional first arg + required variadic arg could misparse.sln add) produce parse errors, causingNativeEntryPoint.csto fall back to manageddotnet.dll. Baredotnet slnalso falls back for complete help.--versionand--info.GetProjectFileFromDirectory: The managed version delegates throughMsbuildProjecttoProjectLocator, but the actual logic is pure file I/O (dir.GetFiles("*proj")). Inlined to avoid pulling inMsbuildProjectdependencies.Testing
dotnet-aotand maindotnetprojects build with 0 warnings, 0 errorsbuild.cmdcompletes (only pre-existing ApiCompat file-locking errors unrelated to this change)