private static void AddSourceFileOption(Command csharp)
        {
            var sourceFileArg = new Argument <RelativeFilePath>(
                result =>
            {
                var filename = result.Tokens.Select(t => t.Value).SingleOrDefault();

                if (filename == null)
                {
                    return(ArgumentResult.Success(null));
                }

                if (RelativeFilePath.TryParse(filename, out var relativeFilePath))
                {
                    return(ArgumentResult.Success(relativeFilePath));
                }

                return(ArgumentResult.Failure($"Error parsing the filename: {filename}"));
            })
            {
                Name  = "SourceFile",
                Arity = ArgumentArity.ZeroOrOne
            };

            var sourceFileOption = new Option("--source-file",
                                              argument: sourceFileArg);

            csharp.AddOption(sourceFileOption);
        }
        private static void AddProjectOption(
            Command csharp,
            IDirectoryAccessor directoryAccessor)
        {
            var projectOptionArgument = new Argument <FileInfo>(result =>
            {
                var projectPath = new RelativeFilePath(result.Tokens.Select(t => t.Value).Single());

                if (directoryAccessor.FileExists(projectPath))
                {
                    return(ArgumentResult.Success(directoryAccessor.GetFullyQualifiedPath(projectPath)));
                }

                return(ArgumentResult.Failure($"Project not found: {projectPath.Value}"));
            })
            {
                Name  = "project",
                Arity = ArgumentArity.ExactlyOne
            };

            projectOptionArgument.SetDefaultValue(() =>
            {
                var rootDirectory = directoryAccessor.GetFullyQualifiedPath(new RelativeDirectoryPath("."));
                var projectFiles  = directoryAccessor.GetAllFilesRecursively()
                                    .Where(file =>
                {
                    return(directoryAccessor.GetFullyQualifiedPath(file.Directory).FullName == rootDirectory.FullName && file.Extension == ".csproj");
                })
                                    .ToArray();

                if (projectFiles.Length == 1)
                {
                    return(directoryAccessor.GetFullyQualifiedPath(projectFiles.Single()));
                }

                return(null);
            });

            var projectOption = new Option("--project",
                                           argument: projectOptionArgument);

            csharp.Add(projectOption);
        }
Exemplo n.º 3
0
        public static Task <int> Main(string[] args)
        {
#if !NOCODEPAGES
            Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
#endif // !NOCODEPAGES

            var cliParser = new CommandLineBuilder(RootCommand())
                            .UseDefaults()
                            .UseMiddleware(async(invokeCtx, next) =>
            {
                var cts = new CancellationTokenSource();
                var onCancelKeyPress = new ConsoleCancelEventHandler((object senter, ConsoleCancelEventArgs e) =>
                {
                    // If cancellation already has been requested,
                    // do not cancel process termination signal.
                    e.Cancel = !cts.IsCancellationRequested;

                    cts.Cancel(throwOnFirstException: true);
                });
                Console.CancelKeyPress += onCancelKeyPress;

                invokeCtx.BindingContext.AddService(typeof(CancellationTokenSource), () => cts);
                invokeCtx.BindingContext.AddService(typeof(CancellationToken), () => cts.Token);

                try { await next(invokeCtx).ConfigureAwait(false); }
                catch (OperationCanceledException) { }
                finally
                {
                    Console.CancelKeyPress -= onCancelKeyPress;
                }
            })
                            .Build();
            return(cliParser.InvokeAsync(args ?? Array.Empty <string>()));

            RootCommand RootCommand()
            {
                var root = new RootCommand(description);

                root.AddOption(new Option(
                                   new string[] { "-d", "--decode" },
                                   "decode data (encodes by default)",
                                   new Argument <bool>()
                                   ));
                root.AddOption(new Option(
                                   new string[] { "-i", "--ignore-garbage" },
                                   "when decoding, ignore non-alphabet characters",
                                   new Argument <bool>()
                                   ));
                root.AddOption(new Option(
                                   new string[] { "-w", "--wrap" },
                                   "wrap encoded lines after COLS characters (default 76). Use 0 to disable line wrapping",
                                   WrapArgument()
                                   ));
                root.AddOption(new Option(
                                   new string[] { "-f", "--file" },
                                   "Encode or decode contents of FILE ('-' for STDIN)",
                                   FileArgument()
                                   ));
                root.AddOption(new Option(
                                   new string[] { "-c", "--charset" },
                                   $"use CHARSET when decoding data from a file (Default: {Encoding.UTF8.WebName}).",
                                   CharsetArgument()
                                   ));
                root.AddOption(new Option(
                                   new string[] { "-b", "--buffer" },
                                   "use SIZE as the read-buffer size. (Default: 4096)",
                                   new Argument <int>(4096)
                {
                    Name = "SIZE", Description = "Size to use for intermediate read buffer"
                }
                                   ));
                root.Handler = CommandHandler.Create(typeof(Program).GetMethod(nameof(InvokeAsync)));

                return(root);

                Argument <int?> WrapArgument()
                {
                    var arg = new Argument <int?>(symbol =>
                    {
                        if (symbol.Arguments.FirstOrDefault().TryNotNull(out string value))
                        {
                            try
                            {
                                int number = int.Parse(value, NumberStyles.Integer, CultureInfo.CurrentCulture);
                                return(ArgumentResult.Success <int?>(number));
                            }
                            catch (OverflowException overflowExcept)
                            { return(ArgumentResult.Failure(overflowExcept.Message)); }
                            catch (FormatException formatExcept)
                            { return(ArgumentResult.Failure(formatExcept.Message)); }
                        }
                        return(ArgumentResult.Success <int?>(76));
                    })
                    {
                        Name        = "COLS",
                        Description = $"Number of characters per line (default {76})",
                        Arity       = ArgumentArity.ZeroOrOne
                    };

                    arg.SetDefaultValue(null);

                    arg.AddValidator(symbol => symbol.Arguments.Select(s =>
                    {
                        if (int.TryParse(s, NumberStyles.Any, CultureInfo.CurrentCulture, out int v) && v >= 0)
                        {
                            return(null);
                        }
                        return($"Argument '{s}' for option '{symbol.Token}' is invalid. Expected a non-negative integer value.");
                    }).Where(msg => !string.IsNullOrWhiteSpace(msg)).FirstOrDefault());

                    return(arg);
                }

                Argument <FileInfo> FileArgument()
                {
                    var argument = new Argument <FileInfo>
                    {
                        Name        = "FILE",
                        Description = "Path to read from or write to",
                        Arity       = ArgumentArity.ExactlyOne
                    };

                    argument.AddValidator(symbol =>
                    {
                        IEnumerable <string> source = from filePath in symbol.Arguments
                                                      where !filePath.Equals("-", StringComparison.Ordinal)
                                                      where !File.Exists(filePath)
                                                      select filePath;
                        ValidationMessages validationMessages = symbol.ValidationMessages;
                        return(source.Select(validationMessages.FileDoesNotExist).FirstOrDefault());
                    });
                    return(argument);
                }

                Argument <Encoding> CharsetArgument()
                {
                    var arg = new Argument <Encoding>(ConvertToEncoding)
                    {
                        Arity       = ArgumentArity.ZeroOrOne,
                        Name        = "CHARSET",
                        Description = $"IANA charset name (default: {Encoding.UTF8})"
                    };

                    arg.AddSuggestions(Encoding.GetEncodings().Select(enc => enc.Name).ToArray());
                    arg.SetDefaultValue(Encoding.UTF8);
                    return(arg);

                    ArgumentResult ConvertToEncoding(SymbolResult symbol)
                    {
                        if (symbol.Arguments.FirstOrDefault().TryNotNullOrWhiteSpace(out string charset))
                        {
                            try
                            {
                                var encoding = Encoding.GetEncoding(charset);
                                return(ArgumentResult.Success(encoding));
                            }
                            catch (ArgumentException)
                            {
                                return(ArgumentResult.Failure($"Argument '{charset}' for option '{symbol.Token}' is invalid. '{charset}' is not a supported encoding name."));
                            }
                        }
                        return(ArgumentResult.Success(Encoding.UTF8));
                    }
                }
            }
        }