From a8da27b784e90d3654fea712bc75e463e251c259 Mon Sep 17 00:00:00 2001 From: Atif Aziz Date: Sun, 2 Apr 2023 18:08:57 +0200 Subject: [PATCH 1/2] Use docopt.net to parse extensions generator args --- .../MoreLinq.ExtensionsGenerator.csproj | 1 + bld/ExtensionsGenerator/Program.cs | 95 ++++++++----------- 2 files changed, 39 insertions(+), 57 deletions(-) diff --git a/bld/ExtensionsGenerator/MoreLinq.ExtensionsGenerator.csproj b/bld/ExtensionsGenerator/MoreLinq.ExtensionsGenerator.csproj index faf971cfd..9e19b8bfb 100644 --- a/bld/ExtensionsGenerator/MoreLinq.ExtensionsGenerator.csproj +++ b/bld/ExtensionsGenerator/MoreLinq.ExtensionsGenerator.csproj @@ -5,6 +5,7 @@ false + diff --git a/bld/ExtensionsGenerator/Program.cs b/bld/ExtensionsGenerator/Program.cs index d275c3272..29a7e5664 100644 --- a/bld/ExtensionsGenerator/Program.cs +++ b/bld/ExtensionsGenerator/Program.cs @@ -24,6 +24,7 @@ using System.Linq; using System.Reflection; using System.Text.RegularExpressions; +using DocoptNet; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; @@ -35,8 +36,20 @@ try #pragma warning restore CA1852 // Seal internal types { - Run(args); - return 0; + var exitCode = + ProgramArguments.CreateParser() + .Parse(args) + .Match(args => { Run(args); return 0; }, _ => 1); + + if (exitCode != 0) + { + Console.Error.WriteLine("Invalid argument or usage!"); + Console.Error.WriteLine(); + var usage = ProgramArguments.Help.Replace("#BIN#", Path.GetFileName(Environment.ProcessPath), StringComparison.Ordinal); + Console.Error.WriteLine(usage); + } + + return exitCode; } #pragma warning disable CA1031 // Do not catch general exception types catch (Exception e) @@ -46,54 +59,9 @@ return 0xbad; } -static void Run(IEnumerable args) +static void Run(ProgramArguments args) { - var dir = Directory.GetCurrentDirectory(); - - string? includePattern = null; - string? excludePattern = null; - var debug = false; - var usings = new List(); - var noClassLead = false; - - using (var arg = args.GetEnumerator()) - { - while (arg.MoveNext()) - { - switch (arg.Current) - { - case "-i": - case "--include": - includePattern = Read(arg, MissingArgValue); - break; - case "-x": - case "--exclude": - excludePattern = Read(arg, MissingArgValue); - break; - case "-u": - case "--using": - usings.Add(Read(arg, MissingArgValue)); - break; - case "--no-class-lead": - noClassLead = true; - break; - case "-d": - case "--debug": - debug = true; - break; - case "": - continue; - default: - dir = arg.Current[0] != '-' - ? arg.Current - : throw new Exception("Invalid argument: " + arg.Current); - break; - } - } - - static Exception MissingArgValue() => - new InvalidOperationException("Missing argument value."); - } + var dir = args.ArgDir ?? Directory.GetCurrentDirectory(); static Func PredicateFromPattern(string? pattern, bool @default) => @@ -101,8 +69,8 @@ static Func ? delegate { return @default; } : new Func(new Regex(pattern).IsMatch); - var includePredicate = PredicateFromPattern(includePattern, true); - var excludePredicate = PredicateFromPattern(excludePattern, false); + var includePredicate = PredicateFromPattern(args.OptInclude, true); + var excludePredicate = PredicateFromPattern(args.OptExclude, false); var thisAssemblyName = typeof(TypeKey).GetTypeInfo().Assembly.GetName(); @@ -198,7 +166,7 @@ from e in ms.Select((m, i) => (SourceOrder: i + 1, Method: m)) q = q.ToArray(); - if (debug) + if (args.OptDebug) { var ms = // @@ -252,7 +220,7 @@ into e }; var imports = - from ns in baseImports.Concat(usings) + from ns in baseImports.Concat(args.OptUsing) select indent + $"using {ns};"; var classes = @@ -290,7 +258,7 @@ select Argument(IdentifierName(p.Identifier)), .WithSemicolonToken(ParseToken(";").WithTrailingTrivia(LineFeed)) } into m - let classLead = !noClassLead + let classLead = !args.OptNoClassLead ? $$""" /// {{m.Name}} extension. @@ -373,9 +341,6 @@ select Walk(te.Type))), }; } -static T Read(IEnumerator e, Func errorFactory) => - e.MoveNext() ? e.Current : throw errorFactory(); - // // Logical type nodes designed to be structurally sortable based on: // @@ -478,3 +443,19 @@ protected override int CompareParameters(TypeKey other) return base.CompareParameters(other); } } + +[DocoptArguments] +sealed partial class ProgramArguments +{ + public const string Help = """ + Usage: + #BIN# [options] [-u NAMESPACE]... [DIR] + + Options: + -i, --include REGEX Include files matching pattern. + -x, --exclude REGEX Exclude files matching pattern. + -u, --using NAMESPACE Additional using imports to add. + --no-class-lead Skip generating class lead. + -d, --debug Produce output for debugging. + """; +} From 9083bda161ccf7ac755b3962c68d0b07f3b15c05 Mon Sep 17 00:00:00 2001 From: Atif Aziz Date: Mon, 3 Apr 2023 00:34:43 +0200 Subject: [PATCH 2/2] Encapsulate help bin token replacement --- bld/ExtensionsGenerator/Program.cs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/bld/ExtensionsGenerator/Program.cs b/bld/ExtensionsGenerator/Program.cs index 29a7e5664..f9cc083c2 100644 --- a/bld/ExtensionsGenerator/Program.cs +++ b/bld/ExtensionsGenerator/Program.cs @@ -45,8 +45,7 @@ { Console.Error.WriteLine("Invalid argument or usage!"); Console.Error.WriteLine(); - var usage = ProgramArguments.Help.Replace("#BIN#", Path.GetFileName(Environment.ProcessPath), StringComparison.Ordinal); - Console.Error.WriteLine(usage); + Console.Error.WriteLine(ProgramArguments.Help); } return exitCode; @@ -444,10 +443,10 @@ protected override int CompareParameters(TypeKey other) } } -[DocoptArguments] +[DocoptArguments(HelpConstName = nameof(HelpText))] sealed partial class ProgramArguments { - public const string Help = """ + const string HelpText = """ Usage: #BIN# [options] [-u NAMESPACE]... [DIR] @@ -458,4 +457,7 @@ sealed partial class ProgramArguments --no-class-lead Skip generating class lead. -d, --debug Produce output for debugging. """; + + public static string Help => + HelpText.Replace("#BIN#", Path.GetFileName(Environment.ProcessPath), StringComparison.Ordinal); }