| File: Commands\Why\WhyCommand.cs | Web Access |
| Project: src\nuget-client\src\NuGet.Core\NuGet.CommandLine.XPlat\NuGet.CommandLine.XPlat.csproj (NuGet.CommandLine.XPlat) |
// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. #nullable enable using System; using System.Collections.Generic; using System.CommandLine; using System.CommandLine.Parsing; using System.IO; using System.Threading.Tasks; using NuGet.Common; using Spectre.Console; namespace NuGet.CommandLine.XPlat.Commands.Why { public static class WhyCommand { internal static void Register(Command rootCommand, Lazy<IAnsiConsole> console, IVirtualProjectBuilder? virtualProjectBuilder = null) { Register(rootCommand, console, () => new WhyCommandRunner(new MSBuildAPIUtility(NullLogger.Instance, virtualProjectBuilder))); } /// <summary> /// This is a temporary API until NuGet migrates all our commands to System.CommandLine, at which time I suspect we'll have a NuGetParser.GetNuGetCommand for all the `dotnet nuget *` commands. /// For now, this allows the dotnet CLI to invoke why directly, instead of running NuGet.CommandLine.XPlat as a child process. /// </summary> /// <param name="rootCommand">The <c>dotnet nuget</c> command handler, to add <c>why</c> to.</param> /// <param name="virtualProjectBuilder">For handling file-based apps.</param> public static void GetWhyCommand(Command rootCommand, IVirtualProjectBuilder? virtualProjectBuilder = null) { Register(rootCommand, new Lazy<IAnsiConsole>(() => Spectre.Console.AnsiConsole.Console), virtualProjectBuilder); } // For binary backcompat. To delete once the SDK starts using the other overload. public static void GetWhyCommand(Command rootCommand) { GetWhyCommand(rootCommand, virtualProjectBuilder: null); } internal static void Register(Command rootCommand, Lazy<IAnsiConsole> console, Func<WhyCommandRunner> getCommandRunner) { Register(rootCommand, console, action: (args) => getCommandRunner().ExecuteCommand(args)); } // console must be lazy, because Spectre.Console's AnsiConsole will send VT sequences to the output // as soon as it's created, which causes problems with the dotnet CLI's C++ output, like dotnet --info internal static void Register(Command rootCommand, Lazy<IAnsiConsole> console, Func<WhyCommandArgs, Task<int>> action) { var whyCommand = new DocumentedCommand("why", Strings.WhyCommand_Description, "https://aka.ms/dotnet/nuget/why"); Argument<string> path = new Argument<string>("PROJECT|SOLUTION|FILE") { Description = Strings.WhyCommand_PathArgument_Description, // We really want this to be zero or one, however, because this is the first argument, it doesn't work. // Instead, we need to use a CustomParser to choose if the argument is the path, or the package. // In order for the parser to tell us there's more than 1 argument available, we need to tell Argument // that it supports more than one, but then in the custom parser we'll make sure we only take at most 1. Arity = ArgumentArity.ZeroOrMore, CustomParser = ar => { if (HasPathArgument(ar)) { var value = ar.Tokens[0]; ar.OnlyTake(1); return value.Value; } ar.OnlyTake(0); var currentDirectory = Directory.GetCurrentDirectory(); return currentDirectory; bool HasPathArgument(ArgumentResult ar) { // If there's only one argument, it could be the path, or the package. if (ar.Tokens.Count == 1) { var value = ar.Tokens[0].Value; return File.Exists(value) || Directory.Exists(value); } return ar.Tokens.Count > 1; } } }; Argument<string> package = new Argument<string>("PACKAGE") { Description = Strings.WhyCommand_PackageArgument_Description, Arity = ArgumentArity.ExactlyOne }; Option<List<string>> frameworks = new Option<List<string>>("--framework", "-f") { Description = Strings.WhyCommand_FrameworksOption_Description, Arity = ArgumentArity.OneOrMore }; whyCommand.Arguments.Add(path); whyCommand.Arguments.Add(package); whyCommand.Options.Add(frameworks); whyCommand.SetAction(async (parseResult, cancellationToken) => { try { var whyCommandArgs = new WhyCommandArgs { Path = parseResult.GetValue(path)!, Package = parseResult.GetValue(package)!, Frameworks = parseResult.GetValue(frameworks)!, Logger = console.Value, CancellationToken = cancellationToken, DotnetVersionChecker = DotnetVersionChecker.Instance, }; int exitCode = await action(whyCommandArgs); return exitCode; } catch (ArgumentException ex) { console.Value.Markup($"[red]{ex.Message}[/]"); return ExitCodes.InvalidArguments; } }); rootCommand.Subcommands.Add(whyCommand); } } }