diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index f9bfe0e6c5..a7c2f759e9 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -25,18 +25,18 @@ https://github.com/dotnet/symreader 27e584661980ee6d82c419a2a471ae505b7d122e - + https://github.com/dotnet/command-line-api - 8374d5fca634a93458c84414b1604c12f765d1ab + 02fe27cd6a9b001c8feb7938e6ef4b3799745759 - + https://github.com/dotnet/command-line-api - 8374d5fca634a93458c84414b1604c12f765d1ab + 02fe27cd6a9b001c8feb7938e6ef4b3799745759 - + https://github.com/dotnet/command-line-api - 8374d5fca634a93458c84414b1604c12f765d1ab + 02fe27cd6a9b001c8feb7938e6ef4b3799745759 diff --git a/eng/Versions.props b/eng/Versions.props index a0fbac4322..d53cabee7b 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -17,8 +17,8 @@ - 2.0.0-beta4.22564.1 - 0.4.0-alpha.22564.1 + 2.0.0-beta4.23307.1 + 0.4.0-alpha.23307.1 10.3.0 diff --git a/src/CommandLineExtensions.cs b/src/CommandLineExtensions.cs deleted file mode 100644 index 9cd803c685..0000000000 --- a/src/CommandLineExtensions.cs +++ /dev/null @@ -1,102 +0,0 @@ -// Copyright (c) Microsoft. All Rights Reserved. Licensed under the MIT license. See License.txt in the project root for license information. - -using System; -using System.Collections.Generic; -using System.CommandLine; -using System.CommandLine.Parsing; -using System.Diagnostics.CodeAnalysis; -using System.Linq; - -namespace Microsoft.CodeAnalysis.Tools -{ - internal static class CommandLineExtensions - { - internal static OptionResult? GetOptionResult(this ParseResult result, string alias) - { - return GetOptionResult(result.CommandResult, alias); - } - - internal static ArgumentResult? GetArgumentResult(this ParseResult result, string alias) - { - return GetArgumentResult(result.CommandResult, alias); - } - - internal static OptionResult? GetOptionResult(this CommandResult result, string alias) - { - return result.Children.GetByAlias(alias) as OptionResult; - } - - internal static ArgumentResult? GetArgumentResult(this CommandResult result, string alias) - { - return result.Children.GetByAlias(alias) as ArgumentResult; - } - - internal static SymbolResult? GetByAlias(this IReadOnlyList results, string alias) - { - return results.SingleOrDefault(result => result.Symbol.Name.Equals(alias) || result.Symbol is IdentifierSymbol id && id.HasAlias(alias)); - } - - [return: MaybeNull] - internal static T GetValueForArgument(this ParseResult result, string alias) - { - return GetValueForArgument(result.CommandResult, alias); - } - - [return: MaybeNull] - internal static T GetValueForArgument(this ParseResult result, Argument argument) - { - return GetValueForArgument(result.CommandResult, argument); - } - - [return: MaybeNull] - internal static T GetValueForOption(this ParseResult result, string alias) - { - return GetValueForOption(result.CommandResult, alias); - } - - [return: MaybeNull] - internal static T GetValueForArgument(this CommandResult result, Argument argumentDefinition) - { - var arguments = result.Children.Where(x => x.Symbol.Name == argumentDefinition.Name).ToArray(); - if (arguments.Length == 1 && - arguments.SingleOrDefault() is ArgumentResult argument && - argument.GetValueOrDefault() is T t) - { - return t; - } - - return default; - } - - [return: MaybeNull] - internal static T GetValueForArgument(this CommandResult result, string alias) - { - if (result.GetArgumentResult(alias) is ArgumentResult argument && - argument.GetValueOrDefault() is { } t) - { - return t; - } - - return default; - } - - [return: MaybeNull] - internal static T GetValueForOption(this CommandResult result, string alias) - { - if (result.GetOptionResult(alias) is OptionResult option && - option.GetValueOrDefault() is { } t) - { - return t; - } - - return default; - } - - internal static bool WasOptionUsed(this ParseResult result, params string[] aliases) - { - return result.Tokens - .Where(token => token.Type == TokenType.Option) - .Any(token => aliases.Contains(token.Value)); - } - } -} diff --git a/src/Commands/FormatAnalyzersCommand.cs b/src/Commands/FormatAnalyzersCommand.cs index 994a73735d..4ecbb180c3 100644 --- a/src/Commands/FormatAnalyzersCommand.cs +++ b/src/Commands/FormatAnalyzersCommand.cs @@ -2,8 +2,8 @@ using System.Collections.Immutable; using System.CommandLine; -using System.CommandLine.Invocation; -using System.CommandLine.Parsing; +using System.CommandLine.IO; +using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Logging; using static Microsoft.CodeAnalysis.Tools.FormatCommandCommon; @@ -14,44 +14,43 @@ internal static class FormatAnalyzersCommand { private static readonly FormatAnalyzersHandler s_analyzerHandler = new(); - internal static Command GetCommand() + internal static CliCommand GetCommand() { - var command = new Command("analyzers", Resources.Run_3rd_party_analyzers__and_apply_fixes) + var command = new CliCommand("analyzers", Resources.Run_3rd_party_analyzers__and_apply_fixes) { DiagnosticsOption, ExcludeDiagnosticsOption, SeverityOption, }; command.AddCommonOptions(); - command.Handler = s_analyzerHandler; + command.Action = s_analyzerHandler; return command; } - private class FormatAnalyzersHandler : ICommandHandler + private class FormatAnalyzersHandler : CliAction { - public int Invoke(InvocationContext context) => InvokeAsync(context).GetAwaiter().GetResult(); + public override int Invoke(ParseResult parseResult) => InvokeAsync(parseResult, CancellationToken.None).GetAwaiter().GetResult(); - public async Task InvokeAsync(InvocationContext context) + public override async Task InvokeAsync(ParseResult parseResult, CancellationToken cancellationToken) { - var parseResult = context.ParseResult; var formatOptions = parseResult.ParseVerbosityOption(FormatOptions.Instance); - var logger = context.Console.SetupLogging(minimalLogLevel: formatOptions.LogLevel, minimalErrorLevel: LogLevel.Warning); + var logger = new SystemConsole().SetupLogging(minimalLogLevel: formatOptions.LogLevel, minimalErrorLevel: LogLevel.Warning); formatOptions = parseResult.ParseCommonOptions(formatOptions, logger); formatOptions = parseResult.ParseWorkspaceOptions(formatOptions); - if (parseResult.HasOption(SeverityOption) && + if (parseResult.GetResult(SeverityOption) is not null && parseResult.GetValue(SeverityOption) is string { Length: > 0 } analyzerSeverity) { formatOptions = formatOptions with { AnalyzerSeverity = GetSeverity(analyzerSeverity) }; } - if (parseResult.HasOption(DiagnosticsOption) && + if (parseResult.GetResult(DiagnosticsOption) is not null && parseResult.GetValue(DiagnosticsOption) is string[] { Length: > 0 } diagnostics) { formatOptions = formatOptions with { Diagnostics = diagnostics.ToImmutableHashSet() }; } - if (parseResult.HasOption(ExcludeDiagnosticsOption) && + if (parseResult.GetResult(ExcludeDiagnosticsOption) is not null && parseResult.GetValue(ExcludeDiagnosticsOption) is string[] { Length: > 0 } excludeDiagnostics) { formatOptions = formatOptions with { ExcludeDiagnostics = excludeDiagnostics.ToImmutableHashSet() }; @@ -59,7 +58,7 @@ public async Task InvokeAsync(InvocationContext context) formatOptions = formatOptions with { FixCategory = FixCategory.Analyzers }; - return await FormatAsync(formatOptions, logger, context.GetCancellationToken()).ConfigureAwait(false); + return await FormatAsync(formatOptions, logger, cancellationToken).ConfigureAwait(false); } } } diff --git a/src/Commands/FormatCommandCommon.cs b/src/Commands/FormatCommandCommon.cs index 5cccf1bbde..d2ed8fad0c 100644 --- a/src/Commands/FormatCommandCommon.cs +++ b/src/Commands/FormatCommandCommon.cs @@ -2,7 +2,6 @@ using System; using System.CommandLine; -using System.CommandLine.Parsing; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; @@ -27,44 +26,80 @@ internal static class FormatCommandCommon private static string[] VerbosityLevels => new[] { "q", "quiet", "m", "minimal", "n", "normal", "d", "detailed", "diag", "diagnostic" }; private static string[] SeverityLevels => new[] { "info", "warn", "error" }; - public static readonly Argument SlnOrProjectArgument = new Argument(Resources.SolutionOrProjectArgumentName) + public static readonly CliArgument SlnOrProjectArgument = new CliArgument(Resources.SolutionOrProjectArgumentName) { Description = Resources.SolutionOrProjectArgumentDescription, Arity = ArgumentArity.ZeroOrOne }.DefaultToCurrentDirectory(); - internal static readonly Option FolderOption = new(new[] { "--folder" }, Resources.Whether_to_treat_the_workspace_argument_as_a_simple_folder_of_files); - internal static readonly Option NoRestoreOption = new(new[] { "--no-restore" }, Resources.Doesnt_execute_an_implicit_restore_before_formatting); - internal static readonly Option VerifyNoChanges = new(new[] { "--verify-no-changes" }, Resources.Verify_no_formatting_changes_would_be_performed_Terminates_with_a_non_zero_exit_code_if_any_files_would_have_been_formatted); - internal static readonly Option DiagnosticsOption = new(new[] { "--diagnostics" }, () => Array.Empty(), Resources.A_space_separated_list_of_diagnostic_ids_to_use_as_a_filter_when_fixing_code_style_or_3rd_party_issues) + internal static readonly CliOption FolderOption = new("--folder") { - AllowMultipleArgumentsPerToken = true + Description = Resources.Whether_to_treat_the_workspace_argument_as_a_simple_folder_of_files, }; - internal static readonly Option ExcludeDiagnosticsOption = new(new[] { "--exclude-diagnostics" }, () => Array.Empty(), Resources.A_space_separated_list_of_diagnostic_ids_to_ignore_when_fixing_code_style_or_3rd_party_issues) + internal static readonly CliOption NoRestoreOption = new("--no-restore") { - AllowMultipleArgumentsPerToken = true + Description = Resources.Doesnt_execute_an_implicit_restore_before_formatting, }; - internal static readonly Option SeverityOption = new Option("--severity", Resources.The_severity_of_diagnostics_to_fix_Allowed_values_are_info_warn_and_error).AcceptOnlyFromAmong(SeverityLevels); - internal static readonly Option IncludeOption = new(new[] { "--include" }, () => Array.Empty(), Resources.A_list_of_relative_file_or_folder_paths_to_include_in_formatting_All_files_are_formatted_if_empty) + internal static readonly CliOption VerifyNoChanges = new("--verify-no-changes") { - AllowMultipleArgumentsPerToken = true + Description = Resources.Verify_no_formatting_changes_would_be_performed_Terminates_with_a_non_zero_exit_code_if_any_files_would_have_been_formatted, }; - internal static readonly Option ExcludeOption = new(new[] { "--exclude" }, () => Array.Empty(), Resources.A_list_of_relative_file_or_folder_paths_to_exclude_from_formatting) + internal static readonly CliOption DiagnosticsOption = new("--diagnostics") { - AllowMultipleArgumentsPerToken = true + AllowMultipleArgumentsPerToken = true, + DefaultValueFactory = _ => Array.Empty(), + Description = Resources.A_space_separated_list_of_diagnostic_ids_to_use_as_a_filter_when_fixing_code_style_or_3rd_party_issues, }; - internal static readonly Option IncludeGeneratedOption = new(new[] { "--include-generated" }, Resources.Format_files_generated_by_the_SDK); - internal static readonly Option VerbosityOption = new Option(new[] { "--verbosity", "-v" }, Resources.Set_the_verbosity_level_Allowed_values_are_quiet_minimal_normal_detailed_and_diagnostic).AcceptOnlyFromAmong(VerbosityLevels); - internal static readonly Option BinarylogOption = new Option(new[] { "--binarylog" }, Resources.Log_all_project_or_solution_load_information_to_a_binary_log_file) + internal static readonly CliOption ExcludeDiagnosticsOption = new("--exclude-diagnostics") { - ArgumentHelpName = "binary-log-path", - Arity = ArgumentArity.ZeroOrOne - }.AcceptLegalFilePathsOnly(); - internal static readonly Option ReportOption = new Option(new[] { "--report" }, Resources.Accepts_a_file_path_which_if_provided_will_produce_a_json_report_in_the_given_directory) + AllowMultipleArgumentsPerToken = true, + DefaultValueFactory = _ => Array.Empty(), + Description = Resources.A_space_separated_list_of_diagnostic_ids_to_ignore_when_fixing_code_style_or_3rd_party_issues, + }; + internal static readonly CliOption SeverityOption = new CliOption("--severity") { - ArgumentHelpName = "report-path", - Arity = ArgumentArity.ZeroOrOne - }.AcceptLegalFilePathsOnly(); + Description = Resources.The_severity_of_diagnostics_to_fix_Allowed_values_are_info_warn_and_error, + }; + internal static readonly CliOption IncludeOption = new("--include") + { + AllowMultipleArgumentsPerToken = true, + DefaultValueFactory = _ => Array.Empty(), + Description = Resources.A_list_of_relative_file_or_folder_paths_to_include_in_formatting_All_files_are_formatted_if_empty, + }; + internal static readonly CliOption ExcludeOption = new("--exclude") + { + AllowMultipleArgumentsPerToken = true, + DefaultValueFactory = _ => Array.Empty(), + Description = Resources.A_list_of_relative_file_or_folder_paths_to_exclude_from_formatting, + }; + internal static readonly CliOption IncludeGeneratedOption = new("--include-generated") + { + Description = Resources.Format_files_generated_by_the_SDK, + }; + internal static readonly CliOption VerbosityOption = new CliOption("--verbosity", "-v") + { + Description = Resources.Set_the_verbosity_level_Allowed_values_are_quiet_minimal_normal_detailed_and_diagnostic, + }; + internal static readonly CliOption BinarylogOption = new CliOption("--binarylog") + { + HelpName = "binary-log-path", + Arity = ArgumentArity.ZeroOrOne, + Description = Resources.Log_all_project_or_solution_load_information_to_a_binary_log_file, + }; + internal static readonly CliOption ReportOption = new CliOption("--report") + { + HelpName = "report-path", + Arity = ArgumentArity.ZeroOrOne, + Description = Resources.Accepts_a_file_path_which_if_provided_will_produce_a_json_report_in_the_given_directory, + }; + + static FormatCommandCommon() + { + SeverityOption.AcceptOnlyFromAmong(SeverityLevels); + VerbosityOption.AcceptOnlyFromAmong(VerbosityLevels); + BinarylogOption.AcceptLegalFilePathsOnly(); + ReportOption.AcceptLegalFilePathsOnly(); + } internal static async Task FormatAsync(FormatOptions formatOptions, ILogger logger, CancellationToken cancellationToken) { @@ -98,22 +133,22 @@ internal static async Task FormatAsync(FormatOptions formatOptions, ILogger return formatResult.GetExitCode(formatOptions.ChangesAreErrors); } - public static void AddCommonOptions(this Command command) + public static void AddCommonOptions(this CliCommand command) { - command.AddArgument(SlnOrProjectArgument); - command.AddOption(NoRestoreOption); - command.AddOption(VerifyNoChanges); - command.AddOption(IncludeOption); - command.AddOption(ExcludeOption); - command.AddOption(IncludeGeneratedOption); - command.AddOption(VerbosityOption); - command.AddOption(BinarylogOption); - command.AddOption(ReportOption); + command.Arguments.Add(SlnOrProjectArgument); + command.Options.Add(NoRestoreOption); + command.Options.Add(VerifyNoChanges); + command.Options.Add(IncludeOption); + command.Options.Add(ExcludeOption); + command.Options.Add(IncludeGeneratedOption); + command.Options.Add(VerbosityOption); + command.Options.Add(BinarylogOption); + command.Options.Add(ReportOption); } - public static Argument DefaultToCurrentDirectory(this Argument arg) + public static CliArgument DefaultToCurrentDirectory(this CliArgument arg) { - arg.SetDefaultValue(EnsureTrailingSlash(Directory.GetCurrentDirectory())); + arg.DefaultValueFactory = _ => EnsureTrailingSlash(Directory.GetCurrentDirectory()); return arg; } @@ -137,7 +172,7 @@ public static int GetExitCode(this WorkspaceFormatResult formatResult, bool chec public static FormatOptions ParseVerbosityOption(this ParseResult parseResult, FormatOptions formatOptions) { - if (parseResult.HasOption(VerbosityOption) && + if (parseResult.GetResult(VerbosityOption) is not null && parseResult.GetValue(VerbosityOption) is string { Length: > 0 } verbosity) { formatOptions = formatOptions with { LogLevel = GetLogLevel(verbosity) }; @@ -152,23 +187,23 @@ public static FormatOptions ParseVerbosityOption(this ParseResult parseResult, F public static FormatOptions ParseCommonOptions(this ParseResult parseResult, FormatOptions formatOptions, ILogger logger) { - if (parseResult.HasOption(NoRestoreOption)) + if (parseResult.GetResult(NoRestoreOption) is not null) { formatOptions = formatOptions with { NoRestore = true }; } - if (parseResult.HasOption(VerifyNoChanges)) + if (parseResult.GetResult(VerifyNoChanges) is not null) { formatOptions = formatOptions with { ChangesAreErrors = true }; formatOptions = formatOptions with { SaveFormattedFiles = false }; } - if (parseResult.HasOption(IncludeGeneratedOption)) + if (parseResult.GetResult(IncludeGeneratedOption) is not null) { formatOptions = formatOptions with { IncludeGeneratedFiles = true }; } - if (parseResult.HasOption(IncludeOption) || parseResult.HasOption(ExcludeOption)) + if (parseResult.GetResult(IncludeOption) is not null || parseResult.GetResult(ExcludeOption) is not null) { var fileToInclude = parseResult.GetValue(IncludeOption) ?? Array.Empty(); var fileToExclude = parseResult.GetValue(ExcludeOption) ?? Array.Empty(); @@ -176,7 +211,7 @@ public static FormatOptions ParseCommonOptions(this ParseResult parseResult, For formatOptions = formatOptions with { FileMatcher = SourceFileMatcher.CreateMatcher(fileToInclude, fileToExclude) }; } - if (parseResult.HasOption(ReportOption)) + if (parseResult.GetResult(ReportOption) is not null) { formatOptions = formatOptions with { ReportPath = string.Empty }; @@ -186,7 +221,7 @@ public static FormatOptions ParseCommonOptions(this ParseResult parseResult, For } } - if (parseResult.HasOption(BinarylogOption)) + if (parseResult.GetResult(BinarylogOption) is not null) { formatOptions = formatOptions with { BinaryLogPath = "format.binlog" }; @@ -288,7 +323,7 @@ public static FormatOptions ParseWorkspaceOptions(this ParseResult parseResult, if (parseResult.GetValue(SlnOrProjectArgument) is string { Length: > 0 } slnOrProject) { - if (parseResult.HasOption(FolderOption)) + if (parseResult.GetResult(FolderOption) is not null) { formatOptions = formatOptions with { WorkspaceFilePath = slnOrProject }; formatOptions = formatOptions with { WorkspaceType = WorkspaceType.Folder }; diff --git a/src/Commands/FormatStyleCommand.cs b/src/Commands/FormatStyleCommand.cs index e915e9936b..cddf23cad7 100644 --- a/src/Commands/FormatStyleCommand.cs +++ b/src/Commands/FormatStyleCommand.cs @@ -2,8 +2,8 @@ using System.Collections.Immutable; using System.CommandLine; -using System.CommandLine.Invocation; -using System.CommandLine.Parsing; +using System.CommandLine.IO; +using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Logging; using static Microsoft.CodeAnalysis.Tools.FormatCommandCommon; @@ -14,44 +14,43 @@ internal static class FormatStyleCommand { private static readonly FormatStyleHandler s_styleHandler = new(); - internal static Command GetCommand() + internal static CliCommand GetCommand() { - var command = new Command("style", Resources.Run_code_style_analyzers_and_apply_fixes) + var command = new CliCommand("style", Resources.Run_code_style_analyzers_and_apply_fixes) { DiagnosticsOption, ExcludeDiagnosticsOption, SeverityOption, }; command.AddCommonOptions(); - command.Handler = s_styleHandler; + command.Action = s_styleHandler; return command; } - private class FormatStyleHandler : ICommandHandler + private class FormatStyleHandler : CliAction { - public int Invoke(InvocationContext context) => InvokeAsync(context).GetAwaiter().GetResult(); + public override int Invoke(ParseResult parseResult) => InvokeAsync(parseResult, CancellationToken.None).GetAwaiter().GetResult(); - public async Task InvokeAsync(InvocationContext context) + public override async Task InvokeAsync(ParseResult parseResult, CancellationToken cancellationToken) { - var parseResult = context.ParseResult; var formatOptions = parseResult.ParseVerbosityOption(FormatOptions.Instance); - var logger = context.Console.SetupLogging(minimalLogLevel: formatOptions.LogLevel, minimalErrorLevel: LogLevel.Warning); + var logger = new SystemConsole().SetupLogging(minimalLogLevel: formatOptions.LogLevel, minimalErrorLevel: LogLevel.Warning); formatOptions = parseResult.ParseCommonOptions(formatOptions, logger); formatOptions = parseResult.ParseWorkspaceOptions(formatOptions); - if (parseResult.HasOption(SeverityOption) && + if (parseResult.GetResult(SeverityOption) is not null && parseResult.GetValue(SeverityOption) is string { Length: > 0 } styleSeverity) { formatOptions = formatOptions with { CodeStyleSeverity = GetSeverity(styleSeverity) }; } - if (parseResult.HasOption(DiagnosticsOption) && + if (parseResult.GetResult(DiagnosticsOption) is not null && parseResult.GetValue(DiagnosticsOption) is string[] { Length: > 0 } diagnostics) { formatOptions = formatOptions with { Diagnostics = diagnostics.ToImmutableHashSet() }; } - if (parseResult.HasOption(ExcludeDiagnosticsOption) && + if (parseResult.GetResult(ExcludeDiagnosticsOption) is not null && parseResult.GetValue(ExcludeDiagnosticsOption) is string[] { Length: > 0 } excludeDiagnostics) { formatOptions = formatOptions with { ExcludeDiagnostics = excludeDiagnostics.ToImmutableHashSet() }; @@ -59,7 +58,7 @@ public async Task InvokeAsync(InvocationContext context) formatOptions = formatOptions with { FixCategory = FixCategory.CodeStyle }; - return await FormatAsync(formatOptions, logger, context.GetCancellationToken()).ConfigureAwait(false); + return await FormatAsync(formatOptions, logger, cancellationToken).ConfigureAwait(false); } } } diff --git a/src/Commands/FormatWhitespaceCommand.cs b/src/Commands/FormatWhitespaceCommand.cs index 953f4c018f..de62c51cd3 100644 --- a/src/Commands/FormatWhitespaceCommand.cs +++ b/src/Commands/FormatWhitespaceCommand.cs @@ -1,8 +1,9 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the MIT license. See License.txt in the project root for license information. using System.CommandLine; -using System.CommandLine.Invocation; +using System.CommandLine.IO; using System.CommandLine.Parsing; +using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Logging; using static Microsoft.CodeAnalysis.Tools.FormatCommandCommon; @@ -28,52 +29,53 @@ internal delegate Task Handler( private static readonly FormatWhitespaceHandler s_formattingHandler = new(); - internal static Command GetCommand() + internal static CliCommand GetCommand() { - var command = new Command("whitespace", Resources.Run_whitespace_formatting) + var command = new CliCommand("whitespace", Resources.Run_whitespace_formatting) { FolderOption }; command.AddCommonOptions(); - command.AddValidator(EnsureFolderNotSpecifiedWithNoRestore); - command.AddValidator(EnsureFolderNotSpecifiedWhenLoggingBinlog); - command.Handler = s_formattingHandler; + command.Validators.Add(EnsureFolderNotSpecifiedWithNoRestore); + command.Validators.Add(EnsureFolderNotSpecifiedWhenLoggingBinlog); + command.Action = s_formattingHandler; return command; } internal static void EnsureFolderNotSpecifiedWithNoRestore(CommandResult symbolResult) { - var folder = symbolResult.GetValueForOption("--folder"); - var noRestore = symbolResult.GetOptionResult("--no-restore"); - symbolResult.ErrorMessage = folder && noRestore != null - ? Resources.Cannot_specify_the_folder_option_with_no_restore - : null; + var folder = symbolResult.GetValue(FolderOption); + var noRestore = symbolResult.GetResult(NoRestoreOption); + if (folder && noRestore != null) + { + symbolResult.AddError(Resources.Cannot_specify_the_folder_option_with_no_restore); + } } internal static void EnsureFolderNotSpecifiedWhenLoggingBinlog(CommandResult symbolResult) { - var folder = symbolResult.GetValueForOption("--folder"); - var binarylog = symbolResult.GetOptionResult("--binarylog"); - symbolResult.ErrorMessage = folder && binarylog is not null && !binarylog.IsImplicit - ? Resources.Cannot_specify_the_folder_option_when_writing_a_binary_log - : null; + var folder = symbolResult.GetValue(FolderOption); + var binarylog = symbolResult.GetResult(BinarylogOption); + if (folder && binarylog is not null && !binarylog.Implicit) + { + symbolResult.AddError(Resources.Cannot_specify_the_folder_option_when_writing_a_binary_log); + } } - private class FormatWhitespaceHandler : ICommandHandler + private class FormatWhitespaceHandler : CliAction { - public int Invoke(InvocationContext context) => InvokeAsync(context).GetAwaiter().GetResult(); + public override int Invoke(ParseResult parseResult) => InvokeAsync(parseResult, CancellationToken.None).GetAwaiter().GetResult(); - public async Task InvokeAsync(InvocationContext context) + public override async Task InvokeAsync(ParseResult parseResult, CancellationToken cancellationToken) { - var parseResult = context.ParseResult; var formatOptions = parseResult.ParseVerbosityOption(FormatOptions.Instance); - var logger = context.Console.SetupLogging(minimalLogLevel: formatOptions.LogLevel, minimalErrorLevel: LogLevel.Warning); + var logger = new SystemConsole().SetupLogging(minimalLogLevel: formatOptions.LogLevel, minimalErrorLevel: LogLevel.Warning); formatOptions = parseResult.ParseCommonOptions(formatOptions, logger); formatOptions = parseResult.ParseWorkspaceOptions(formatOptions); formatOptions = formatOptions with { FixCategory = FixCategory.Whitespace }; - return await FormatAsync(formatOptions, logger, context.GetCancellationToken()).ConfigureAwait(false); + return await FormatAsync(formatOptions, logger, cancellationToken).ConfigureAwait(false); } } } diff --git a/src/Commands/RootFormatCommand.cs b/src/Commands/RootFormatCommand.cs index 7f04ecfa79..79faa8edb1 100644 --- a/src/Commands/RootFormatCommand.cs +++ b/src/Commands/RootFormatCommand.cs @@ -2,8 +2,8 @@ using System.Collections.Immutable; using System.CommandLine; -using System.CommandLine.Invocation; -using System.CommandLine.Parsing; +using System.CommandLine.IO; +using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Logging; using static Microsoft.CodeAnalysis.Tools.FormatCommandCommon; @@ -14,9 +14,9 @@ internal static class RootFormatCommand { private static readonly FormatCommandDefaultHandler s_formatCommandHandler = new(); - public static RootCommand GetCommand() + public static CliRootCommand GetCommand() { - var formatCommand = new RootCommand(Resources.Formats_code_to_match_editorconfig_settings) + var formatCommand = new CliRootCommand(Resources.Formats_code_to_match_editorconfig_settings) { FormatWhitespaceCommand.GetCommand(), FormatStyleCommand.GetCommand(), @@ -26,36 +26,35 @@ public static RootCommand GetCommand() SeverityOption, }; formatCommand.AddCommonOptions(); - formatCommand.Handler = s_formatCommandHandler; + formatCommand.Action = s_formatCommandHandler; return formatCommand; } - private class FormatCommandDefaultHandler : ICommandHandler + private class FormatCommandDefaultHandler : CliAction { - public int Invoke(InvocationContext context) => InvokeAsync(context).GetAwaiter().GetResult(); + public override int Invoke(ParseResult parseResult) => InvokeAsync(parseResult, CancellationToken.None).GetAwaiter().GetResult(); - public async Task InvokeAsync(InvocationContext context) + public override async Task InvokeAsync(ParseResult parseResult, CancellationToken cancellationToken) { - var parseResult = context.ParseResult; var formatOptions = parseResult.ParseVerbosityOption(FormatOptions.Instance); - var logger = context.Console.SetupLogging(minimalLogLevel: formatOptions.LogLevel, minimalErrorLevel: LogLevel.Warning); + var logger = new SystemConsole().SetupLogging(minimalLogLevel: formatOptions.LogLevel, minimalErrorLevel: LogLevel.Warning); formatOptions = parseResult.ParseCommonOptions(formatOptions, logger); formatOptions = parseResult.ParseWorkspaceOptions(formatOptions); - if (parseResult.HasOption(SeverityOption) && + if (parseResult.GetResult(SeverityOption) is not null && parseResult.GetValue(SeverityOption) is string { Length: > 0 } defaultSeverity) { formatOptions = formatOptions with { AnalyzerSeverity = GetSeverity(defaultSeverity) }; formatOptions = formatOptions with { CodeStyleSeverity = GetSeverity(defaultSeverity) }; } - if (parseResult.HasOption(DiagnosticsOption) && + if (parseResult.GetResult(DiagnosticsOption) is not null && parseResult.GetValue(DiagnosticsOption) is string[] { Length: > 0 } diagnostics) { formatOptions = formatOptions with { Diagnostics = diagnostics.ToImmutableHashSet() }; } - if (parseResult.HasOption(ExcludeDiagnosticsOption) && + if (parseResult.GetResult(ExcludeDiagnosticsOption) is not null && parseResult.GetValue(ExcludeDiagnosticsOption) is string[] { Length: > 0 } excludeDiagnostics) { formatOptions = formatOptions with { ExcludeDiagnostics = excludeDiagnostics.ToImmutableHashSet() }; @@ -63,7 +62,7 @@ public async Task InvokeAsync(InvocationContext context) formatOptions = formatOptions with { FixCategory = FixCategory.Whitespace | FixCategory.CodeStyle | FixCategory.Analyzers }; - return await FormatAsync(formatOptions, logger, context.GetCancellationToken()).ConfigureAwait(false); + return await FormatAsync(formatOptions, logger, cancellationToken).ConfigureAwait(false); } } } diff --git a/src/Program.cs b/src/Program.cs index 5ffb0f8dbf..91ec85b660 100644 --- a/src/Program.cs +++ b/src/Program.cs @@ -1,7 +1,6 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the MIT license. See License.txt in the project root for license information. -using System.CommandLine; -using System.CommandLine.Parsing; +using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Tools.Commands; @@ -12,7 +11,7 @@ internal class Program private static async Task Main(string[] args) { var rootCommand = RootFormatCommand.GetCommand(); - return await rootCommand.InvokeAsync(args); + return await rootCommand.Parse(args).InvokeAsync(CancellationToken.None); } } } diff --git a/tests/ProgramTests.cs b/tests/ProgramTests.cs index 488f4955d7..7c51810252 100644 --- a/tests/ProgramTests.cs +++ b/tests/ProgramTests.cs @@ -1,8 +1,5 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the MIT license. See License.txt in the project root for license information. -using System.Collections.Generic; -using System.CommandLine; -using System.CommandLine.Parsing; using Microsoft.CodeAnalysis.Tools.Commands; using Xunit; @@ -58,18 +55,18 @@ public void CommandLine_OptionsAreParsedCorrectly() Assert.Equal(0, result.Errors.Count); Assert.Equal(0, result.UnmatchedTokens.Count); Assert.Equal(0, result.UnmatchedTokens.Count); - result.GetValueForOption("--no-restore"); - Assert.Collection(result.GetValueForOption>("--include"), + result.GetValue(FormatCommandCommon.NoRestoreOption); + Assert.Collection(result.GetValue(FormatCommandCommon.IncludeOption), i0 => Assert.Equal("include1", i0), i1 => Assert.Equal("include2", i1)); - Assert.Collection(result.GetValueForOption>("--exclude"), + Assert.Collection(result.GetValue(FormatCommandCommon.ExcludeOption), i0 => Assert.Equal("exclude1", i0), i1 => Assert.Equal("exclude2", i1)); - Assert.True(result.GetValueForOption("--verify-no-changes")); - Assert.Equal("binary-log-path", result.GetValueForOption("--binarylog")); - Assert.Equal("report", result.GetValueForOption("--report")); - Assert.Equal("detailed", result.GetValueForOption("--verbosity")); - Assert.True(result.GetValueForOption("--include-generated")); + Assert.True(result.GetValue(FormatCommandCommon.VerifyNoChanges)); + Assert.Equal("binary-log-path", result.GetValue(FormatCommandCommon.BinarylogOption)); + Assert.Equal("report", result.GetValue(FormatCommandCommon.ReportOption)); + Assert.Equal("detailed", result.GetValue(FormatCommandCommon.VerbosityOption)); + Assert.True(result.GetValue(FormatCommandCommon.IncludeGeneratedOption)); } [Fact] @@ -83,7 +80,7 @@ public void CommandLine_ProjectArgument_Simple() // Assert Assert.Equal(0, result.Errors.Count); - Assert.Equal("workspaceValue", result.GetValueForArgument(FormatCommandCommon.SlnOrProjectArgument)); + Assert.Equal("workspaceValue", result.GetValue(FormatCommandCommon.SlnOrProjectArgument)); } [Fact] @@ -97,8 +94,8 @@ public void CommandLine_ProjectArgument_WithOption_AfterArgument() // Assert Assert.Equal(0, result.Errors.Count); - Assert.Equal("workspaceValue", result.GetValueForArgument(FormatCommandCommon.SlnOrProjectArgument)); - Assert.Equal("detailed", result.GetValueForOption("--verbosity")); + Assert.Equal("workspaceValue", result.GetValue(FormatCommandCommon.SlnOrProjectArgument)); + Assert.Equal("detailed", result.GetValue(FormatCommandCommon.VerbosityOption)); } [Fact] @@ -112,8 +109,8 @@ public void CommandLine_ProjectArgument_WithOption_BeforeArgument() // Assert Assert.Equal(0, result.Errors.Count); - Assert.Equal("workspaceValue", result.GetValueForArgument(FormatCommandCommon.SlnOrProjectArgument)); - Assert.Equal("detailed", result.GetValueForOption("--verbosity")); + Assert.Equal("workspaceValue", result.GetValue(FormatCommandCommon.SlnOrProjectArgument)); + Assert.Equal("detailed", result.GetValue(FormatCommandCommon.VerbosityOption)); } [Fact] @@ -179,7 +176,7 @@ public void CommandLine_BinaryLog_DoesNotFailIfPathNotSpecified() // Assert Assert.Equal(0, result.Errors.Count); - Assert.True(result.WasOptionUsed("--binarylog")); + Assert.NotNull(result.GetResult(FormatCommandCommon.BinarylogOption)); } [Fact] @@ -193,7 +190,7 @@ public void CommandLine_BinaryLog_DoesNotFailIfPathIsSpecified() // Assert Assert.Equal(0, result.Errors.Count); - Assert.True(result.WasOptionUsed("--binarylog")); + Assert.NotNull(result.GetResult(FormatCommandCommon.BinarylogOption)); } [Fact]