Skip to content

Commit

Permalink
Update to latest System.CommandLine package (#66929)
Browse files Browse the repository at this point in the history
  • Loading branch information
jkotas authored Mar 21, 2022
1 parent ca1b840 commit ca82541
Show file tree
Hide file tree
Showing 8 changed files with 679 additions and 484 deletions.
4 changes: 4 additions & 0 deletions eng/Version.Details.xml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@
<Uri>https://github.com/dotnet/llvm-project</Uri>
<Sha>f17917e8d6a2e3ba069cddeab873554706d502a5</Sha>
</Dependency>
<Dependency Name="System.CommandLine" Version="2.0.0-beta3.22151.2">
<Uri>https://github.com/dotnet/command-line-api</Uri>
<Sha>021ec68a4cb510c2cc125c6ebb78b9cfd4e3847a</Sha>
</Dependency>
</ProductDependencies>
<ToolsetDependencies>
<Dependency Name="Microsoft.DotNet.Arcade.Sdk" Version="7.0.0-beta.22166.1">
Expand Down
3 changes: 1 addition & 2 deletions eng/Versions.props
Original file line number Diff line number Diff line change
Expand Up @@ -138,9 +138,8 @@
<optimizationPGOCoreCLRVersion>1.0.0-prerelease.22121.2</optimizationPGOCoreCLRVersion>
<!-- Not auto-updated. -->
<MicrosoftDiaSymReaderNativeVersion>16.9.0-beta1.21055.5</MicrosoftDiaSymReaderNativeVersion>
<SystemCommandLineVersion>2.0.0-beta1.20253.1</SystemCommandLineVersion>
<SystemCommandLineVersion>2.0.0-beta3.22114.1</SystemCommandLineVersion>
<TraceEventVersion>2.0.65</TraceEventVersion>
<CommandLineParserVersion>2.2.0</CommandLineParserVersion>
<NETStandardLibraryRefVersion>2.1.0</NETStandardLibraryRefVersion>
<NetStandardLibraryVersion>2.0.3</NetStandardLibraryVersion>
<MicrosoftDiagnosticsToolsRuntimeClientVersion>1.0.4-preview6.19326.1</MicrosoftDiagnosticsToolsRuntimeClientVersion>
Expand Down
161 changes: 108 additions & 53 deletions src/coreclr/tools/ILVerify/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
using System;
using System.Collections.Generic;
using System.CommandLine;
using System.CommandLine.Builder;
using System.CommandLine.Invocation;
using System.CommandLine.Parsing;
using System.IO;
using System.Linq;
using System.Reflection;
Expand Down Expand Up @@ -43,42 +45,6 @@ public static IReadOnlyList<Regex> StringPatternsToRegexList(IReadOnlyList<strin
return patternList;
}

public class Options
{
public string[] InputFilePath { get; set; }
public string[] Reference { get; set; }
public string SystemModule { get; set; }
public bool SanityChecks { get; set; }
public string[] Include { get; set; }
public FileInfo IncludeFile { get; set; }
public string[] Exclude { get; set; }
public FileInfo ExcludeFile { get; set; }
public string[] IgnoreError { get; set; }
public FileInfo IgnoreErrorFile { get; set; }
public bool Statistics { get; set; }
public bool Verbose { get; set; }
public bool Tokens { get; set; }
}

public static RootCommand RootCommand()
{
RootCommand command = new RootCommand();
command.AddArgument(new Argument<string[]>("input-file-path", "Input file(s)") { Arity = new ArgumentArity(1, Int32.MaxValue) });
command.AddOption(new Option<string[]>(new[] { "--reference", "-r" }, "Reference metadata from the specified assembly"));
command.AddOption(new Option<string>(new[] { "--system-module", "-s" }, "System module name (default: mscorlib)"));
command.AddOption(new Option<bool>(new[] { "--sanity-checks", "-c" }, "Check for valid constructs that are likely mistakes"));
command.AddOption(new Option<string[]>(new[] { "--include", "-i" }, "Use only methods/types/namespaces, which match the given regular expression(s)"));
command.AddOption(new Option<FileInfo>(new[] { "--include-file" }, "Same as --include, but the regular expression(s) are declared line by line in the specified file.").ExistingOnly());
command.AddOption(new Option<string[]>(new[] { "--exclude", "-e" }, "Skip methods/types/namespaces, which match the given regular expression(s)"));
command.AddOption(new Option<FileInfo>(new[] { "--exclude-file" }, "Same as --exclude, but the regular expression(s) are declared line by line in the specified file.").ExistingOnly());
command.AddOption(new Option<string[]>(new[] { "--ignore-error", "-g" }, "Ignore errors, which match the given regular expression(s)"));
command.AddOption(new Option<FileInfo>(new[] { "--ignore-error-file" }, "Same as --ignore-error, but the regular expression(s) are declared line by line in the specified file.").ExistingOnly());
command.AddOption(new Option<bool>(new[] { "--statistics" }, "Print verification statistics"));
command.AddOption(new Option<bool>(new[] { "--verbose", "-v" }, "Verbose output"));
command.AddOption(new Option<bool>(new[] { "--tokens", "-t" }, "Include metadata tokens in error messages"));
return command;
}

private Program(Options options)
{
_options = options;
Expand Down Expand Up @@ -489,29 +455,118 @@ public PEReader Resolve(string simpleName)
return null;
}

private static int Run(Options options)
//
// Command line parsing
//

private class ILVerifyRootCommand : RootCommand
{
try
{
return new Program(options).Run();
}
catch (CommandLineException e)
{
Console.WriteLine("Error: " + e.Message);
return 1;
}
catch (Exception e)
public Argument<string[]> InputFilePath { get; } =
new("input-file-path", "Input file(s)") { Arity = ArgumentArity.OneOrMore };
public Option<string[]> Reference { get; } =
new(new[] { "--reference", "-r" }, "Reference metadata from the specified assembly");
public Option<string> SystemModule { get; } =
new(new[] { "--system-module", "-s" }, "System module name (default: mscorlib)");
public Option<bool> SanityChecks { get; } =
new(new[] { "--sanity-checks", "-c" }, "Check for valid constructs that are likely mistakes");
public Option<string[]> Include { get; } =
new(new[] { "--include", "-i" }, "Use only methods/types/namespaces, which match the given regular expression(s)");
public Option<FileInfo> IncludeFile { get; } =
new Option<FileInfo>(new[] { "--include-file" }, "Same as --include, but the regular expression(s) are declared line by line in the specified file.").ExistingOnly();
public Option<string[]> Exclude { get; } =
new(new[] { "--exclude", "-e" }, "Skip methods/types/namespaces, which match the given regular expression(s)");
public Option<FileInfo> ExcludeFile { get; } =
new Option<FileInfo>(new[] { "--exclude-file" }, "Same as --exclude, but the regular expression(s) are declared line by line in the specified file.").ExistingOnly();
public Option<string[]> IgnoreError { get; } =
new(new[] { "--ignore-error", "-g" }, "Ignore errors, which match the given regular expression(s)");
public Option<FileInfo> IgnoreErrorFile { get; } =
new Option<FileInfo>(new[] { "--ignore-error-file" }, "Same as --ignore-error, but the regular expression(s) are declared line by line in the specified file.").ExistingOnly();
public Option<bool> Statistics { get; } =
new(new[] { "--statistics" }, "Print verification statistics");
public Option<bool> Verbose { get; } =
new(new[] { "--verbose", "-v" }, "Verbose output");
public Option<bool> Tokens { get; } =
new(new[] { "--tokens", "-t" }, "Include metadata tokens in error messages");

public ILVerifyRootCommand()
: base("Tool for verifying MSIL code based on ECMA-335.")
{
Console.WriteLine("Error: " + e.ToString());
return 1;
AddArgument(InputFilePath);
AddOption(Reference);
AddOption(SystemModule);
AddOption(SanityChecks);
AddOption(Include);
AddOption(IncludeFile);
AddOption(Exclude);
AddOption(ExcludeFile);
AddOption(IgnoreError);
AddOption(IgnoreErrorFile);
AddOption(Statistics);
AddOption(Verbose);
AddOption(Tokens);

this.SetHandler<InvocationContext>((InvocationContext context) =>
{
try
{
context.ExitCode = new Program(new Options(this, context.ParseResult)).Run();
}
catch (Exception e)
{
Console.ResetColor();
Console.ForegroundColor = ConsoleColor.Red;

// Omit the stacktrace from the error (different from the default System.CommandLine exception handler)
Console.Error.WriteLine("Error: " + e.Message);

Console.ResetColor();

context.ExitCode = 1;
}
});
}
}

private static async Task<int> Main(string[] args)
private class Options
{
var command = RootCommand();
command.Handler = CommandHandler.Create<Options>(Run);
return await command.InvokeAsync(args);
public Options(ILVerifyRootCommand cmd, ParseResult res)
{
InputFilePath = res.GetValueForArgument(cmd.InputFilePath);
Reference = res.GetValueForOption(cmd.Reference);
SystemModule = res.GetValueForOption(cmd.SystemModule);
SanityChecks = res.GetValueForOption(cmd.SanityChecks);
Include = res.GetValueForOption(cmd.Include);
IncludeFile = res.GetValueForOption(cmd.IncludeFile);
Exclude = res.GetValueForOption(cmd.Exclude);
ExcludeFile = res.GetValueForOption(cmd.ExcludeFile);
IgnoreError = res.GetValueForOption(cmd.IgnoreError);
IgnoreErrorFile = res.GetValueForOption(cmd.IgnoreErrorFile);
Statistics = res.GetValueForOption(cmd.Statistics);
Verbose = res.GetValueForOption(cmd.Verbose);
Tokens = res.GetValueForOption(cmd.Tokens);
}

public string[] InputFilePath { get; }
public string[] Reference { get; }
public string SystemModule { get; }
public bool SanityChecks { get; }
public string[] Include { get; }
public FileInfo IncludeFile { get; }
public string[] Exclude { get; }
public FileInfo ExcludeFile { get; }
public string[] IgnoreError { get; }
public FileInfo IgnoreErrorFile { get; }
public bool Statistics { get; }
public bool Verbose { get; }
public bool Tokens { get; }
}

private static int Main(string[] args) =>
new CommandLineBuilder(new ILVerifyRootCommand())
.UseVersionOption()
.UseHelp()
.UseParseErrorReporting()
.Build()
.Invoke(args);
}
}
Loading

0 comments on commit ca82541

Please sign in to comment.