Skip to content

Commit 4f7d030

Browse files
authored
Lazy initialize Spectre.Console in XPlat command registration (#7063)
1 parent 048ea45 commit 4f7d030

3 files changed

Lines changed: 31 additions & 16 deletions

File tree

src/NuGet.Core/NuGet.CommandLine.XPlat/Commands/Why/WhyCommand.cs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ internal static void Register(CommandLineApplication app)
2525
});
2626
}
2727

28-
internal static void Register(Command rootCommand, IAnsiConsole console)
28+
internal static void Register(Command rootCommand, Lazy<IAnsiConsole> console)
2929
{
3030
Register(rootCommand, console, WhyCommandRunner.ExecuteCommand);
3131
}
@@ -38,11 +38,13 @@ internal static void Register(Command rootCommand, IAnsiConsole console)
3838
public static void GetWhyCommand(Command rootCommand)
3939
{
4040
Register(rootCommand,
41-
Spectre.Console.AnsiConsole.Console,
41+
new Lazy<IAnsiConsole>(() => Spectre.Console.AnsiConsole.Console),
4242
WhyCommandRunner.ExecuteCommand);
4343
}
4444

45-
internal static void Register(Command rootCommand, IAnsiConsole console, Func<WhyCommandArgs, Task<int>> action)
45+
// console must be lazy, because Spectre.Console's AnsiConsole will send VT sequences to the output
46+
// as soon as it's created, which causes problems with the dotnet CLI's C++ output, like dotnet --info
47+
internal static void Register(Command rootCommand, Lazy<IAnsiConsole> console, Func<WhyCommandArgs, Task<int>> action)
4648
{
4749
var whyCommand = new DocumentedCommand("why", Strings.WhyCommand_Description, "https://aka.ms/dotnet/nuget/why");
4850

@@ -111,15 +113,15 @@ bool HasPathArgument(ArgumentResult ar)
111113
parseResult.GetValue(path)!,
112114
parseResult.GetValue(package)!,
113115
parseResult.GetValue(frameworks)!,
114-
console,
116+
console.Value,
115117
cancellationToken);
116118

117119
int exitCode = await action(whyCommandArgs);
118120
return exitCode;
119121
}
120122
catch (ArgumentException ex)
121123
{
122-
console.Markup($"[red]{ex.Message}[/]");
124+
console.Value.Markup($"[red]{ex.Message}[/]");
123125
return ExitCodes.InvalidArguments;
124126
}
125127
});

src/NuGet.Core/NuGet.CommandLine.XPlat/Program.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,10 +115,12 @@ public static int MainInternal(string[] args, CommandOutputLogger log, IEnvironm
115115
var nugetCommand = new Command("nuget");
116116
rootCommand.Subcommands.Add(nugetCommand);
117117

118+
var lazyConsole = new Lazy<Spectre.Console.IAnsiConsole>(() => Spectre.Console.AnsiConsole.Console);
119+
118120
ConfigCommand.Register(nugetCommand, getHidePrefixLogger);
119121
ConfigCommand.Register(rootCommand, getHidePrefixLogger);
120-
Commands.Why.WhyCommand.Register(nugetCommand, Spectre.Console.AnsiConsole.Console);
121-
Commands.Why.WhyCommand.Register(rootCommand, Spectre.Console.AnsiConsole.Console);
122+
Commands.Why.WhyCommand.Register(nugetCommand, lazyConsole);
123+
Commands.Why.WhyCommand.Register(rootCommand, lazyConsole);
122124
}
123125

124126
CancellationTokenSource tokenSource = new CancellationTokenSource();

test/NuGet.Core.Tests/NuGet.CommandLine.Xplat.Tests/Commands/Why/WhyCommandLineParsingTests.cs

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using FluentAssertions;
88
using NuGet.CommandLine.XPlat.Commands;
99
using NuGet.CommandLine.XPlat.Commands.Why;
10+
using Spectre.Console;
1011
using Spectre.Console.Testing;
1112
using Xunit;
1213

@@ -19,9 +20,10 @@ public void WhyCommand_HasHelpUrl()
1920
{
2021
// Arrange
2122
Command rootCommand = new("nuget");
23+
var console = new Lazy<IAnsiConsole>(() => new TestConsole());
2224

2325
// Act
24-
WhyCommand.Register(rootCommand, new TestConsole());
26+
WhyCommand.Register(rootCommand, console);
2527

2628
// Assert
2729
rootCommand.Subcommands[0].Should().BeAssignableTo<DocumentedCommand>();
@@ -33,8 +35,10 @@ public void WithTwoArguments_PathAndPackageAreSet()
3335
{
3436
// Arrange
3537
Command rootCommand = new("nuget");
38+
var console = new Lazy<IAnsiConsole>(() => new TestConsole());
3639

37-
WhyCommand.Register(rootCommand, new TestConsole(), whyCommandArgs =>
40+
41+
WhyCommand.Register(rootCommand, console, whyCommandArgs =>
3842
{
3943
// Assert
4044
whyCommandArgs.Path.Should().Be(@"path\to\my.proj");
@@ -54,8 +58,9 @@ public void WithOneArguments_PackageIsSet()
5458
{
5559
// Arrange
5660
Command rootCommand = new("nuget");
61+
var console = new Lazy<IAnsiConsole>(() => new TestConsole());
5762

58-
WhyCommand.Register(rootCommand, new TestConsole(), whyCommandArgs =>
63+
WhyCommand.Register(rootCommand, console, whyCommandArgs =>
5964
{
6065
// Assert
6166
whyCommandArgs.Path.Should().NotBeNull();
@@ -75,8 +80,9 @@ public void WithZeroArguments_HasParseError()
7580
{
7681
// Arrange
7782
Command rootCommand = new("nuget");
83+
var console = new Lazy<IAnsiConsole>(() => new TestConsole());
7884

79-
WhyCommand.Register(rootCommand, new TestConsole(), whyCommandArgs =>
85+
WhyCommand.Register(rootCommand, console, whyCommandArgs =>
8086
{
8187
// Assert
8288
throw new Exception("Should not get here");
@@ -92,8 +98,9 @@ public void WithThreeArguments_HasParseError()
9298
{
9399
// Arrange
94100
Command rootCommand = new("nuget");
101+
var console = new Lazy<IAnsiConsole>(() => new TestConsole());
95102

96-
WhyCommand.Register(rootCommand, new TestConsole(), whyCommandArgs =>
103+
WhyCommand.Register(rootCommand, console, whyCommandArgs =>
97104
{
98105
// Assert
99106
throw new Exception("Should not get here");
@@ -112,8 +119,9 @@ public void FrameworkOption_CanBeAtAnyPosition(string args)
112119
{
113120
// Arrange
114121
Command rootCommand = new("nuget");
122+
var console = new Lazy<IAnsiConsole>(() => new TestConsole());
115123

116-
WhyCommand.Register(rootCommand, new TestConsole(), whyCommandArgs =>
124+
WhyCommand.Register(rootCommand, console, whyCommandArgs =>
117125
{
118126
// Assert
119127
whyCommandArgs.Path.Should().Be("my.proj");
@@ -135,8 +143,9 @@ public void FrameworkOption_CanBeLongOrShortForm(string arg)
135143
{
136144
// Arrange
137145
Command rootCommand = new("nuget");
146+
var console = new Lazy<IAnsiConsole>(() => new TestConsole());
138147

139-
WhyCommand.Register(rootCommand, new TestConsole(), whyCommandArgs =>
148+
WhyCommand.Register(rootCommand, console, whyCommandArgs =>
140149
{
141150
// Assert
142151
whyCommandArgs.Path.Should().Be("my.proj");
@@ -156,8 +165,9 @@ public void FrameworkOption_AcceptsMultipleValues()
156165
{
157166
// Arrange
158167
Command rootCommand = new("nuget");
168+
var console = new Lazy<IAnsiConsole>(() => new TestConsole());
159169

160-
WhyCommand.Register(rootCommand, new TestConsole(), whyCommandArgs =>
170+
WhyCommand.Register(rootCommand, console, whyCommandArgs =>
161171
{
162172
// Assert
163173
whyCommandArgs.Path.Should().Be("my.proj");
@@ -177,8 +187,9 @@ public void HelpOption_ShowsHelp()
177187
{
178188
// Arrange
179189
Command rootCommand = new("nuget");
190+
var console = new Lazy<IAnsiConsole>(() => new TestConsole());
180191

181-
WhyCommand.Register(rootCommand, new TestConsole(), whyCommandArgs =>
192+
WhyCommand.Register(rootCommand, console, whyCommandArgs =>
182193
{
183194
// Assert
184195
whyCommandArgs.Path.Should().Be("my.proj");

0 commit comments

Comments
 (0)