public static void Main(string[] args) { RootCommand root = new RootCommand("Convert between different file formats supported by RDFSharp."); root.AddArgument(new Argument <RDFModelEnums.RDFFormats>("formatSource")); root.AddArgument(new Argument <FileInfo>("fileSource").ExistingOnly()); root.AddArgument(new Argument <RDFModelEnums.RDFFormats>("formatDestination")); root.AddArgument(new Argument <FileInfo>("fileDestination").LegalFilePathsOnly()); root.Handler = CommandHandler.Create <RDFModelEnums.RDFFormats, FileInfo, RDFModelEnums.RDFFormats, FileInfo>(Convert); root.Invoke(args); }
private static async Task <int> Main(string[] args) { // Directly output characters up to and including 255 as bytes, without modifying them. // This allows UTF-8 encoded text to be output one byte at a time. Console.OutputEncoding = Encoding.GetEncoding("iso-8859-1"); var bytes = Enumerable.Range(0, 256).Select(x => (byte)x).ToArray(); var encodedBytes = Console.OutputEncoding .GetBytes(bytes.Select(x => (char)x).ToArray()); if (!bytes.SequenceEqual(encodedBytes)) { throw new InvalidOperationException("Encoding error."); } var rootCommand = new RootCommand { new Option <int>( new[] { "-g", "--generate" }, "Generate a hexagon with the given size."), new Option <bool>( new[] { "-d", "--debug" }, "Output debug information to STDERR for instructions preceded by \"`\"."), new Option <bool>( new[] { "-D", "--debug-all" }, "Output debug information to STDERR after every tick."), }; rootCommand.AddArgument(new Argument { Name = "File", ArgumentType = typeof(FileInfo), Arity = ArgumentArity.ZeroOrOne, Description = "Path to code file. Use \"-\" for STDIN.", }); rootCommand.AddArgument(new Argument { Name = "Arguments", ArgumentType = typeof(string), Arity = ArgumentArity.ZeroOrMore, Description = "Optional arguments for program that will be joined with null characters. Otherwise, if STDIN is not used for the code file, it will be used for input.", }); rootCommand.Description = "Hexagony interpreter"; // Note that the parameters of the handler method are matched according to the names of the options. rootCommand.Handler = CommandHandler.Create <CommandLineOptions>(MainTask); return(await rootCommand.InvokeAsync(args)); }
static CommandLineBuilder BuildCommandLine() { var root = new RootCommand(); root.AddArgument(new Argument <System.IO.DirectoryInfo>("source")); root.AddArgument(new Argument <System.IO.DirectoryInfo>("destination")); root.AddOption(new Option <bool>(new[] { "-m", "--move" }, "Moves the files")); root.AddOption(new Option <bool>(new[] { "-r", "--recursive" }, "Recursively searches <SOURCE>")); root.AddOption(new Option <bool>(new[] { "-n", "--dry-run" }, "Don’t actually move/copy any file(s). Instead, just show if they exist and would otherwise be moved/copied by the command.")); root.AddOption(new Option <bool>(new[] { "-i", "--inplace" }, "Renames the files in place, rather than to <DESTINATION>.")); root.Handler = CommandHandler.Create <IHost, System.IO.DirectoryInfo, System.IO.DirectoryInfo, bool, bool, bool, bool>(Process); return(new CommandLineBuilder(root)); }
public RootCommand Build() { // Check attribute exists if (_att is null) { throw new ArgumentNullException("Object doesn't implement RootCommandAttribute"); } // Create root command var root = new RootCommand(_att.Description ?? ""); // Search in properties for arguments and options foreach (var p in _t.GetProperties()) { var arg = new ArgumentFactory(p); if (arg.IsValid) { root.AddArgument(arg.Build()); continue; } var opt = new OptionFactory(p); if (opt.IsValid) { root.AddOption(opt.Build()); } } return(root); }
private static RootCommand BuildCommand() { var root = new RootCommand { new Option <FileInfo>( new string[] { "--output", "-o" }, description: "Output file path"), new Option <string>( new string[] { "--target", "-t" }, description: "Translation target language"), new Option <string>( new string[] { "--model", "-m" }, description: "Data model source (connection string or JSON file path)"), new Option <string>( new string[] { "--namespace-mapping", "-n" }, description: "Namespace mapping json file path"), new Option <string>( new string[] { "--default-namespace", "-d" }, description: "Default data model namespace"), new Option( new string[] { "--verbose", "-v" }, description: "Logs debug information"), new Option( new string[] { "--console", "-c" }, description: "Print logs to console output") }; root.AddArgument(new Argument <FileInfo>("input")); root.Description = "VTL translator command line interface"; root.Handler = CommandHandler.Create <TranslateOptions>(Run); return(root); }
/// <summary> /// The BuildCommandLine. /// </summary> /// <returns>The <see cref="CommandLineBuilder"/>.</returns> private static CommandLineBuilder BuildCommandLine() { var root = new RootCommand(@"$ dotnet run 'MUM_120'") { }; root.AddArgument(new Argument <string>("number", "number of av")); root.AddOption(new Option <bool>(new string[] { "--table", "-t" }, () => false, "set table view")); root.AddOption(new Option <bool>(new string[] { "--search", "-s" }, () => false, "enable search")); root.Handler = CommandHandler.Create <string, List <string>, bool, bool, IHost>(Run); return(new CommandLineBuilder(root)); }
public void Command_argument_is_bound_to_longest_constructor() { var rootCommand = new RootCommand(); rootCommand.AddArgument(new Argument <int> { Name = nameof(ClassWithMultipleCtor.IntProperty) }); var parser = new Parser(rootCommand); var bindingContext = new BindingContext(parser.Parse("42")); var binder = new ModelBinder <ClassWithMultipleCtor>(); var instance = binder.CreateInstance(bindingContext) as ClassWithMultipleCtor; instance.Should().NotBeNull(); instance.IntProperty.Should().Be(42); }
private static int Main(string[] args) { RootCommand rootCommand = new RootCommand( description: "Parses Kindle highlight files into useful formats."); rootCommand.AddOption(new Option <string>(new string[] { "--format", "--f" }, () => "", "Select the output format. Default: pages and nopages. Also available: json. For multiple formats, separate them by comma.")); rootCommand.AddArgument(new Argument <FileInfo>("highlightsFile", () => new FileInfo("My Clippings.txt"), "The path to the highlights file.")); rootCommand.Handler = CommandHandler.Create <FileInfo, string>(ParseAndOutput); return(rootCommand.Invoke(args)); }
private void BuildCommand() { var fileArgument = new Argument <FileInfo>() { Name = "Model", Description = "3MF file to open", Arity = ArgumentArity.ZeroOrOne }.ExistingOnly(); RootCommand.AddArgument(fileArgument); RootCommand.Add(_createCommand.Command); RootCommand.Add(_addCommand.Command); RootCommand.Add(_listCommand.Command); RootCommand.Add(_setCommand.Command); RootCommand.Add(_removeCommand.Command); RootCommand.Add(_packCommand.Command); RootCommand.Add(_extractCommand.Command); RootCommand.Handler = CommandHandler.Create <FileInfo>((model) => new PrintProjectWebview().Run(model)); }
static void Main(string[] args) { var rootCommand = new RootCommand(description: "Converts a specfic colour (chroma key) in images and makes them transparent") { new Option(new string[] { "--color", "--colour", "-c" }, "The named colour to be changed") { Argument = new Argument <Color>() }, new Option(new string[] { "--outdir" }, "The custom directory to output the changed image.") { Argument = new Argument <DirectoryInfo>() }, }; rootCommand.AddArgument(new Argument <FileInfo[]>("files")); rootCommand.Handler = CommandHandler.Create <Color?, DirectoryInfo, FileInfo[]>(ProcessImages); rootCommand.InvokeAsync(args).Wait(); }
private static RootCommand CreateCommandLineInterface() { var rootCommand = new RootCommand(); rootCommand.Handler = CommandHandler.Create <IHost>(Run); rootCommand.AddArgument(new Argument <FileInfo>("path") { Description = "Path of the script file to execute.", Arity = ArgumentArity.ExactlyOne }); rootCommand.AddOption(new Option <string>("--plugin-path")); //rootCommand.AddOption(new Option<int>(new string[] { "--int-option", "/int-option" }, getDefaultValue: () => 42, description: "An option whose argument is parsed to an int")); //rootCommand.AddOption(new Option<string>("--string-option", getDefaultValue: () => "NONE", description: "An option for string value")); //rootCommand.AddOption(new Option("--that-option", "An option that's there or not")); //rootCommand.Description = "Sample App using System.CommandLine"; return(rootCommand); }
private async Task <(int ExitCode, IConsole Console)> RunCommand(string filename, bool allowNewFile = false) { var file = new FileArgument("file"); file.AllowNewFile = allowNewFile; var command = new RootCommand(); command.AddArgument(file); var console = new TestConsole(); command.SetHandler((string file) => { console.Out.Write("Success " + file); }, file); var exitCode = await command.InvokeAsync(filename, console); return(exitCode, console); }
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 <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); }
/// <summary> /// Main entry for the program. /// https://dotnetdevaddict.co.za/2020/09/25/getting-started-with-system-commandline/ Tutorial for System.CommandLine /// https://github.com/dotnet/command-line-api System.CommandLine Git repository and its document. /// </summary> /// <param name="args">Command line arguments.</param> static int Main(string[] args) { var rootCommand = new RootCommand("The PHP switcher command line that will work on these tasks for you."); var phpversion = new Argument <string>( name: "phpversion", description: "The PHP version to switch to." ); rootCommand.AddArgument(phpversion); var configjson = new Option <FileInfo>( name: "--config-json", description: "The path to phpswitch.json configuration file." ); rootCommand.AddOption(configjson); var verbose = new Option <bool>( name: "--verbose", description: "Show verbose output" ); verbose.AddAlias("-v"); rootCommand.Add(verbose); rootCommand.Description = "The PHP switcher command line that will work on these tasks for you." + "\n" + " Switch PHP version for CLI.\n" + " Rewrite Apache configuration to use selected PHP version. (Optional)\n" + " Start and stop web server service(s). (Optional)\n" + " Copy files depend on PHP version in JSON config file. (Optional)"; rootCommand.SetHandler((phpversion, configJson, verbose) => { var app = new App(); app.Run(phpversion, configJson, verbose); }, phpversion, configjson, verbose); // Parse the incoming args and invoke the handler return(rootCommand.InvokeAsync(args).Result); }
static async Task <int> Main(string[] args) { Func <string, bool, bool, string, string, int, Task <int> > action = Run; var rootCommand = new RootCommand(description: "A test runner for running standalone bash-based or xunit tests"); rootCommand.Handler = CommandHandler.Create(action); var testRootArgument = new Argument <string>(); testRootArgument.Name = "testRoot"; testRootArgument.Description = "Root directory for searching for tests"; testRootArgument.Arity = ArgumentArity.ZeroOrOne; rootCommand.AddArgument(testRootArgument); rootCommand.AddOption(compatibleOption); rootCommand.AddOption(verboseOption); rootCommand.AddOption(logDirectoryOption); rootCommand.AddOption(additionalFeedOption); rootCommand.AddOption(timeoutOption); return(await rootCommand.InvokeAsync(args)); }
static async Task <int> Main(string[] args) { CultureInfo.CurrentCulture = CultureInfo.InvariantCulture; CultureInfo.CurrentUICulture = CultureInfo.InvariantCulture; var cmd = new RootCommand { new Option <int>(new [] { "--scan-radius", "-r" }, 50, "Scan radius in ly (default: 50)"), new Option <bool>(new [] { "--plot-journey", "-p" }, false, "Plot journey (default: false)"), new Option <bool>(new [] { "--include-bodies", "-b" }, false, "Include bodies in systems.txt (default: false)"), new Option <TimeSpan>(new [] { "--cache-duration" }, TimeSpan.FromMinutes(30), "Duration on how long system details are cached (default: 00:30:00)"), new Option <string[]>(new [] { "--filter-body", "-fb" }, Array.Empty <string>, $"Body filter(s) written in form on LINQ expression like: \"{nameof(SystemBody.IsScoopable)}==true\". When applied, only the systems with at least one matching body will be returned."), new Option <string[]>(new [] { "--filter-system", "-fs" }, Array.Empty <string>, $"System filter(s) written in form on LINQ expression like: \"{nameof(SystemDetails.DiscoveredStars)} > 1\".") }; cmd.Description = "Edsm Scanner"; cmd.AddArgument(new Argument <string>("origin-system") { Description = "Origin system name" }); cmd.Handler = CommandHandler.Create <string, int, bool, bool, TimeSpan, string[], string[]>(Scan); var helpCmd = new Command("help", "Displays help"); helpCmd.AddCommand(new Command("usage", "Displays usage") { Handler = CommandHandler.Create(HelpUsage) }); helpCmd.AddCommand(new Command("filters", "Displays filters usage") { Handler = CommandHandler.Create(FiltersUsage) }); cmd.AddCommand(helpCmd); return(await cmd.InvokeAsync(args)); }
public Program() { Option optionServerConfigName = new Option("--server", "defines a name of server configuration which will be used"); Argument <string> argumentServerConfigName = new Argument <string> { Arity = ArgumentArity.ExactlyOne }; Argument <string> argumentServerFingerPrint = new Argument <string> ("server-finger-print") { Arity = ArgumentArity.ExactlyOne }; optionServerConfigName.AddAlias("-s"); optionServerConfigName.Argument = argumentServerConfigName; rootCommand.AddOption(optionServerConfigName); rootCommand.AddArgument(argumentServerFingerPrint); var commandUpload = new Command("upload", "uploads file to the specified or the default server"); commandUpload.AddAlias("u"); var argumentLocalPathFileName = new Argument <string> ("local-path-file-name") { Arity = ArgumentArity.ExactlyOne }; commandUpload.AddArgument(argumentLocalPathFileName); var argumentRemotePathFileName = new Argument <string> ("remote-path-file-name") { Arity = ArgumentArity.ExactlyOne }; commandUpload.AddArgument(argumentRemotePathFileName); commandUpload.Handler = CommandHandler.Create <string, string, string, string> (Upload); rootCommand.AddCommand(commandUpload); }
public static Parser Create( IServiceCollection services, StartServer startServer = null, Demo demo = null, TryGitHub tryGithub = null, Pack pack = null, Install install = null, Verify verify = null, Jupyter jupyter = null, StartKernelServer startKernelServer = null, ITelemetry telemetry = null, IFirstTimeUseNoticeSentinel firstTimeUseNoticeSentinel = null) { if (services == null) { throw new ArgumentNullException(nameof(services)); } startServer = startServer ?? ((startupOptions, invocationContext) => Program.ConstructWebHost(startupOptions).Run()); jupyter = jupyter ?? ((startupOptions, console, server, context) => JupyterCommand.Do(startupOptions, console, server, context)); demo = demo ?? DemoCommand.Do; tryGithub = tryGithub ?? ((repo, console) => GitHubHandler.Handler(repo, console, new GitHubRepoLocator())); verify = verify ?? ((options, console, startupOptions) => VerifyCommand.Do(options, console, startupOptions)); pack = pack ?? PackCommand.Do; install = install ?? InstallCommand.Do; startKernelServer = startKernelServer ?? ((startupOptions, kernel, console) => KernelServerCommand.Do(startupOptions, kernel, console)); // Setup first time use notice sentinel. firstTimeUseNoticeSentinel = firstTimeUseNoticeSentinel ?? new FirstTimeUseNoticeSentinel(); // Setup telemetry. telemetry = telemetry ?? new Telemetry.Telemetry(firstTimeUseNoticeSentinel); var filter = new TelemetryFilter(Sha256Hasher.HashWithNormalizedCasing); Action <ParseResult> track = o => telemetry.SendFiltered(filter, o); var dirArgument = new Argument <FileSystemDirectoryAccessor>(() => new FileSystemDirectoryAccessor(Directory.GetCurrentDirectory())) { Name = nameof(StartupOptions.RootDirectory), Arity = ArgumentArity.ZeroOrOne, Description = "Specify the path to the root directory for your documentation", }; dirArgument.AddValidator(symbolResult => { var directory = symbolResult.Tokens .Select(t => t.Value) .FirstOrDefault(); if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory)) { return($"Directory does not exist: {directory}"); } return(null); }); var rootCommand = StartInTryMode(); rootCommand.AddCommand(StartInHostedMode()); rootCommand.AddCommand(Demo()); rootCommand.AddCommand(GitHub()); rootCommand.AddCommand(Pack()); rootCommand.AddCommand(Install()); rootCommand.AddCommand(Verify()); rootCommand.AddCommand(Jupyter()); rootCommand.AddCommand(KernelServer()); return(new CommandLineBuilder(rootCommand) .UseDefaults() .UseMiddleware(async(context, next) => { // If sentinel does not exist, print the welcome message showing the telemetry notification. if (!firstTimeUseNoticeSentinel.Exists() && !Telemetry.Telemetry.SkipFirstTimeExperience) { context.Console.Out.WriteLine(); context.Console.Out.WriteLine(Telemetry.Telemetry.WelcomeMessage); firstTimeUseNoticeSentinel.CreateIfNotExists(); } if (context.ParseResult.Directives.Contains("debug") && !(Clock.Current is VirtualClock)) { VirtualClock.Start(); } await next(context); }) .Build()); RootCommand StartInTryMode() { var command = new RootCommand { Name = "dotnet-try", Description = "Interactive documentation in your browser" }; command.AddArgument(dirArgument); command.AddOption(new Option( "--add-package-source", "Specify an additional NuGet package source") { Argument = new Argument <PackageSource>(() => new PackageSource(Directory.GetCurrentDirectory())) { Name = "NuGet source" } }); command.AddOption(new Option( "--package", "Specify a Try .NET package or path to a .csproj to run code samples with") { Argument = new Argument <string> { Name = "name or .csproj" } }); command.AddOption(new Option( "--package-version", "Specify a Try .NET package version to use with the --package option") { Argument = new Argument <string> { Name = "version" } }); command.AddOption(new Option( "--uri", "Specify a URL or a relative path to a Markdown file") { Argument = new Argument <Uri>() }); command.AddOption(new Option( "--enable-preview-features", "Enable preview features") { Argument = new Argument <bool>() }); command.AddOption(new Option( "--log-path", "Enable file logging to the specified directory") { Argument = new Argument <DirectoryInfo> { Name = "dir" } }); command.AddOption(new Option( "--verbose", "Enable verbose logging to the console") { Argument = new Argument <bool>() }); var portArgument = new Argument <ushort>(); portArgument.AddValidator(symbolResult => { if (symbolResult.Tokens .Select(t => t.Value) .Count(value => !ushort.TryParse(value, out _)) > 0) { return("Invalid argument for --port option"); } return(null); }); command.AddOption(new Option( "--port", "Specify the port for dotnet try to listen on") { Argument = portArgument }); command.Handler = CommandHandler.Create <InvocationContext, StartupOptions>((context, options) => { services.AddSingleton(_ => PackageRegistry.CreateForTryMode( options.RootDirectory, options.AddPackageSource)); startServer(options, context); }); return(command); } Command StartInHostedMode() { var command = new Command("hosted") { new Option( "--id", "A unique id for the agent instance (e.g. its development environment id).") { Argument = new Argument <string>(defaultValue: () => Environment.MachineName) }, new Option( "--production", "Specifies whether the agent is being run using production resources") { Argument = new Argument <bool>() }, new Option( "--language-service", "Specifies whether the agent is being run in language service-only mode") { Argument = new Argument <bool>() }, new Option( new[] { "-k", "--key" }, "The encryption key") { Argument = new Argument <string>() }, new Option( new[] { "--ai-key", "--application-insights-key" }, "Application Insights key.") { Argument = new Argument <string>() }, new Option( "--region-id", "A unique id for the agent region") { Argument = new Argument <string>() }, new Option( "--log-to-file", "Writes a log file") { Argument = new Argument <bool>() } }; command.Description = "Starts the Try .NET agent"; command.IsHidden = true; command.Handler = CommandHandler.Create <InvocationContext, StartupOptions>((context, options) => { services.AddSingleton(_ => PackageRegistry.CreateForHostedMode()); services.AddSingleton(c => new MarkdownProject(c.GetRequiredService <PackageRegistry>())); services.AddSingleton <IHostedService, Warmup>(); startServer(options, context); }); return(command); } Command Demo() { var demoCommand = new Command( "demo", "Learn how to create Try .NET content with an interactive demo") { new Option("--output", "Where should the demo project be written to?") { Argument = new Argument <DirectoryInfo>( defaultValue: () => new DirectoryInfo(Directory.GetCurrentDirectory())) } }; demoCommand.Handler = CommandHandler.Create <DemoOptions, InvocationContext>((options, context) => { demo(options, context.Console, startServer, context); }); return(demoCommand); } Command GitHub() { var argument = new Argument <string> { // System.CommandLine parameter binding does lookup by name, // so name the argument after the github command's string param Name = nameof(TryGitHubOptions.Repo) }; var github = new Command("github", "Try a GitHub repo") { argument }; github.IsHidden = true; github.Handler = CommandHandler.Create <TryGitHubOptions, IConsole>((repo, console) => tryGithub(repo, console)); return(github); } Command Jupyter() { var jupyterCommand = new Command("jupyter", "Starts dotnet try as a Jupyter kernel"); var defaultKernelOption = new Option("--default-kernel", "The default .NET kernel language for the notebook.") { Argument = new Argument <string>(defaultValue: () => "csharp") }; jupyterCommand.AddOption(defaultKernelOption); var connectionFileArgument = new Argument <FileInfo> { Name = "ConnectionFile", Arity = ArgumentArity.ZeroOrOne //should be removed once the commandlineapi allows subcommands to not have arguments from the main command }.ExistingOnly(); jupyterCommand.AddArgument(connectionFileArgument); jupyterCommand.Handler = CommandHandler.Create <StartupOptions, JupyterOptions, IConsole, InvocationContext>((startupOptions, options, console, context) => { track(context.ParseResult); services .AddSingleton(c => ConnectionInformation.Load(options.ConnectionFile)) .AddSingleton( c => { return(CommandScheduler .Create <JupyterRequestContext>(delivery => c.GetRequiredService <ICommandHandler <JupyterRequestContext> >() .Trace() .Handle(delivery))); }) .AddSingleton(c => CreateKernel(options.DefaultKernel)) .AddSingleton(c => new JupyterRequestContextHandler(c.GetRequiredService <IKernel>()) .Trace()) .AddSingleton <IHostedService, Shell>() .AddSingleton <IHostedService, Heartbeat>(); return(jupyter(startupOptions, console, startServer, context)); }); var installCommand = new Command("install", "Install the .NET kernel for Jupyter"); installCommand.Handler = CommandHandler.Create <IConsole, InvocationContext>((console, context) => { track(context.ParseResult); return(new JupyterCommandLine(console, new FileSystemJupyterKernelSpec()).InvokeAsync()); }); jupyterCommand.AddCommand(installCommand); return(jupyterCommand); } Command KernelServer() { var startKernelServerCommand = new Command("kernel-server", "Starts dotnet-try with kernel functionality exposed over standard I/O"); var defaultKernelOption = new Option("--default-kernel", "The default .NET kernel language for the notebook.") { Argument = new Argument <string>(defaultValue: () => "csharp") }; startKernelServerCommand.AddOption(defaultKernelOption); startKernelServerCommand.Handler = CommandHandler.Create <StartupOptions, KernelServerOptions, IConsole, InvocationContext>( (startupOptions, options, console, context) => { track(context.ParseResult); return(startKernelServer(startupOptions, CreateKernel(options.DefaultKernel), console)); }); return(startKernelServerCommand); } Command Pack() { var packCommand = new Command("pack", "Create a Try .NET package") { new Argument <DirectoryInfo> { Name = nameof(PackOptions.PackTarget) }, new Option("--version", "The version of the Try .NET package") { Argument = new Argument <string>() }, new Option("--enable-wasm", "Enables web assembly code execution") }; packCommand.IsHidden = true; packCommand.Handler = CommandHandler.Create <PackOptions, IConsole>( (options, console) => { return(pack(options, console)); }); return(packCommand); } Command Install() { var installCommand = new Command("install", "Install a Try .NET package") { new Argument <string> { Name = nameof(InstallOptions.PackageName), Arity = ArgumentArity.ExactlyOne }, new Option("--add-source") { Argument = new Argument <PackageSource>() } }; installCommand.IsHidden = true; installCommand.Handler = CommandHandler.Create <InstallOptions, IConsole>((options, console) => install(options, console)); return(installCommand); } Command Verify() { var verifyCommand = new Command("verify", "Verify Markdown files in the target directory and its children.") { dirArgument }; verifyCommand.Handler = CommandHandler.Create <VerifyOptions, IConsole, StartupOptions>( (options, console, startupOptions) => { return(verify(options, console, startupOptions)); }); return(verifyCommand); } }
static CommandLineConfigs() { UninstallRootCommand.AddArgument(new Argument <IEnumerable <string> > { Name = LocalizableStrings.UninstallNoOptionArgumentName, Description = LocalizableStrings.UninstallNoOptionArgumentDescription }); UninstallRootCommand.AddCommand(ListCommand); var supportedBundleTypeNames = SupportedBundleTypeConfigs.GetSupportedBundleTypes().Select(type => type.OptionName); var supportedUninstallBundleTypeOptions = new Option[] { UninstallSdkOption, UninstallRuntimeOption, UninstallAspNetRuntimeOption, UninstallHostingBundleOption } .Where(option => supportedBundleTypeNames.Contains(option.Name)); var supportedListBundleTypeOptions = new Option[] { ListSdkOption, ListRuntimeOption, ListAspNetRuntimeOption, ListHostingBundleOption } .Where(option => supportedBundleTypeNames.Contains(option.Name)); UninstallAuxOptions = supportedUninstallBundleTypeOptions .Append(VerbosityOption) .Append(UninstallX64Option) .Append(UninstallX86Option) .Append(VersionOption) .Append(DryRunOption) .Append(YesOption); ListAuxOptions = supportedListBundleTypeOptions .Append(VerbosityOption) .Append(ListX64Option) .Append(ListX86Option); foreach (var option in UninstallMainOptions .Concat(UninstallAuxOptions) .OrderBy(option => option.Name)) { UninstallRootCommand.AddOption(option); } foreach (var option in ListAuxOptions .OrderBy(option => option.Name)) { ListCommand.AddOption(option); } ListCommand.Handler = CommandHandler.Create(ExceptionHandler.HandleException(() => ListCommandExec.Execute())); UninstallRootCommand.Handler = CommandHandler.Create(ExceptionHandler.HandleException(() => UninstallCommandExec.Execute())); CommandLineParseResult = UninstallRootCommand.Parse(Environment.GetCommandLineArgs()); }
public static Parser Create( IServiceCollection services, StartServer startServer = null, Demo demo = null, TryGitHub tryGithub = null, Pack pack = null, Install install = null, Verify verify = null, Jupyter jupyter = null) { if (services == null) { throw new ArgumentNullException(nameof(services)); } startServer = startServer ?? ((options, invocationContext) => Program.ConstructWebHost(options).Run()); jupyter = jupyter ?? JupyterCommand.Do; demo = demo ?? DemoCommand.Do; tryGithub = tryGithub ?? ((repo, console) => GitHubHandler.Handler(repo, console, new GitHubRepoLocator())); verify = verify ?? ((verifyOptions, console, startupOptions) => VerifyCommand.Do(verifyOptions, console, () => new FileSystemDirectoryAccessor(verifyOptions.Dir), PackageRegistry.CreateForTryMode(verifyOptions.Dir), startupOptions)); pack = pack ?? PackCommand.Do; install = install ?? InstallCommand.Do; var dirArgument = new Argument <DirectoryInfo> { Arity = ArgumentArity.ZeroOrOne, Name = nameof(StartupOptions.Dir).ToLower(), Description = "Specify the path to the root directory for your documentation" }.ExistingOnly(); var rootCommand = StartInTryMode(); rootCommand.AddCommand(StartInHostedMode()); rootCommand.AddCommand(Demo()); rootCommand.AddCommand(GitHub()); rootCommand.AddCommand(Pack()); rootCommand.AddCommand(Install()); rootCommand.AddCommand(Verify()); rootCommand.AddCommand(Jupyter()); return(new CommandLineBuilder(rootCommand) .UseDefaults() .UseMiddleware(async(context, next) => { if (context.ParseResult.Directives.Contains("debug") && !(Clock.Current is VirtualClock)) { VirtualClock.Start(); } await next(context); }) .Build()); RootCommand StartInTryMode() { var command = new RootCommand { Name = "dotnet-try", Description = "Interactive documentation in your browser" }; command.AddArgument(dirArgument); command.AddOption(new Option( "--add-package-source", "Specify an additional NuGet package source") { Argument = new Argument <PackageSource>(() => new PackageSource(Directory.GetCurrentDirectory())) { Name = "NuGet source" } }); command.AddOption(new Option( "--package", "Specify a Try .NET package or path to a .csproj to run code samples with") { Argument = new Argument <string> { Name = "name or .csproj" } }); command.AddOption(new Option( "--package-version", "Specify a Try .NET package version to use with the --package option") { Argument = new Argument <string> { Name = "version" } }); command.AddOption(new Option( "--uri", "Specify a URL or a relative path to a Markdown file") { Argument = new Argument <Uri>() }); command.AddOption(new Option( "--enable-preview-features", "Enable preview features") { Argument = new Argument <bool>() }); command.AddOption(new Option( "--log-path", "Enable file logging to the specified directory") { Argument = new Argument <DirectoryInfo> { Name = "dir" } }); command.AddOption(new Option( "--verbose", "Enable verbose logging to the console") { Argument = new Argument <bool>() }); var portArgument = new Argument <ushort>(); portArgument.AddValidator(symbolResult => { if (symbolResult.Tokens .Select(t => t.Value) .Count(value => !ushort.TryParse(value, out _)) > 0) { return("Invalid argument for --port option"); } return(null); }); command.AddOption(new Option( "--port", "Specify the port for dotnet try to listen on") { Argument = portArgument }); command.Handler = CommandHandler.Create <InvocationContext, StartupOptions>((context, options) => { services.AddSingleton(_ => PackageRegistry.CreateForTryMode( options.Dir, options.AddPackageSource)); startServer(options, context); }); return(command); } Command StartInHostedMode() { var command = new Command("hosted") { new Option( "--id", "A unique id for the agent instance (e.g. its development environment id).") { Argument = new Argument <string>(defaultValue: () => Environment.MachineName) }, new Option( "--production", "Specifies whether the agent is being run using production resources") { Argument = new Argument <bool>() }, new Option( "--language-service", "Specifies whether the agent is being run in language service-only mode") { Argument = new Argument <bool>() }, new Option( new[] { "-k", "--key" }, "The encryption key") { Argument = new Argument <string>() }, new Option( new[] { "--ai-key", "--application-insights-key" }, "Application Insights key.") { Argument = new Argument <string>() }, new Option( "--region-id", "A unique id for the agent region") { Argument = new Argument <string>() }, new Option( "--log-to-file", "Writes a log file") { Argument = new Argument <bool>() } }; command.Description = "Starts the Try .NET agent"; command.IsHidden = true; command.Handler = CommandHandler.Create <InvocationContext, StartupOptions>((context, options) => { services.AddSingleton(_ => PackageRegistry.CreateForHostedMode()); services.AddSingleton(c => new MarkdownProject(c.GetRequiredService <PackageRegistry>())); services.AddSingleton <IHostedService, Warmup>(); startServer(options, context); }); return(command); } Command Demo() { var demoCommand = new Command( "demo", "Learn how to create Try .NET content with an interactive demo") { new Option("--output", "Where should the demo project be written to?") { Argument = new Argument <DirectoryInfo>( defaultValue: () => new DirectoryInfo(Directory.GetCurrentDirectory())) } }; demoCommand.Handler = CommandHandler.Create <DemoOptions, InvocationContext>((options, context) => { demo(options, context.Console, startServer, context); }); return(demoCommand); } Command GitHub() { var argument = new Argument <string> { // System.CommandLine parameter binding does lookup by name, // so name the argument after the github command's string param Name = nameof(TryGitHubOptions.Repo) }; var github = new Command("github", "Try a GitHub repo") { argument }; github.IsHidden = true; github.Handler = CommandHandler.Create <TryGitHubOptions, IConsole>((repo, console) => tryGithub(repo, console)); return(github); } Command Jupyter() { var jupyterCommand = new Command("jupyter", "Starts dotnet try as a Jupyter kernel") { IsHidden = true }; var connectionFileArgument = new Argument <FileInfo> { Name = "ConnectionFile" }.ExistingOnly(); jupyterCommand.AddArgument(connectionFileArgument); jupyterCommand.Handler = CommandHandler.Create <JupyterOptions, IConsole, InvocationContext>((options, console, context) => { services .AddSingleton(c => ConnectionInformation.Load(options.ConnectionFile)) .AddSingleton( c => { return(CommandScheduler .Create <JupyterRequestContext>(delivery => c.GetRequiredService <ICommandHandler <JupyterRequestContext> >() .Trace() .Handle(delivery))); }) .AddTransient <IKernel>(c => new CompositeKernel { new CSharpKernel().UseNugetDirective() }) .AddSingleton(c => new JupyterRequestContextHandler( c.GetRequiredService <PackageRegistry>(), c.GetRequiredService <IKernel>()) .Trace()) .AddSingleton <IHostedService, Shell>() .AddSingleton <IHostedService, Heartbeat>(); return(jupyter(options, console, startServer, context)); }); return(jupyterCommand); } Command Pack() { var packCommand = new Command("pack", "Create a Try .NET package") { new Argument <DirectoryInfo> { Name = nameof(PackOptions.PackTarget) }, new Option("--version", "The version of the Try .NET package") { Argument = new Argument <string>() }, new Option("--enable-wasm", "Enables web assembly code execution") }; packCommand.IsHidden = true; packCommand.Handler = CommandHandler.Create <PackOptions, IConsole>( (options, console) => { return(pack(options, console)); }); return(packCommand); } Command Install() { var installCommand = new Command("install", "Install a Try .NET package") { new Argument <string> { Name = nameof(InstallOptions.PackageName) }, new Option("--add-source") { Argument = new Argument <PackageSource>() } }; installCommand.IsHidden = true; installCommand.Handler = CommandHandler.Create <InstallOptions, IConsole>((options, console) => install(options, console)); return(installCommand); } Command Verify() { var verifyCommand = new Command("verify", "Verify Markdown files in the target directory and its children.") { dirArgument }; verifyCommand.Handler = CommandHandler.Create <VerifyOptions, IConsole, StartupOptions>( (options, console, startupOptions) => { return(verify(options, console, startupOptions)); }); return(verifyCommand); } }
/// <summary> /// Entry point for `perlang`, with the possibility to override the console streams (stdin, stdout, stderr). /// </summary> /// <param name="args">The command line arguments.</param> /// <param name="console">A custom `IConsole` implementation to use. May be null, in which case the standard /// streams of the calling process will be used.</param> /// <returns>Zero if the program executed successfully; non-zero otherwise.</returns> public static int MainWithCustomConsole(string[] args, IConsole console) { var versionOption = new Option(new[] { "--version", "-v" }, "Show version information"); var detailedVersionOption = new Option("-V", "Show detailed version information"); var evalOption = new Option <string>("-e", "Executes a single-line script") { AllowMultipleArgumentsPerToken = false, ArgumentHelpName = "script" }; var printOption = new Option <string>("-p", "Parse a single-line script and output a human-readable version of the AST") { ArgumentHelpName = "script" }; var noWarnAsErrorOption = new Option <string>("-Wno-error", "Treats specified warning as a warning instead of an error.") { ArgumentHelpName = "error" }; var disabledWarningsAsErrorsList = new List <WarningType>(); noWarnAsErrorOption.AddValidator(result => { string warningName = result.GetValueOrDefault <string>(); if (!WarningType.KnownWarning(warningName)) { return($"Unknown warning: {warningName}"); } disabledWarningsAsErrorsList.Add(WarningType.Get(warningName)); return(null); }); // Note: options must be present in this list to be valid for the RootCommand. var options = new[] { versionOption, detailedVersionOption, evalOption, printOption, noWarnAsErrorOption }; var scriptNameArgument = new Argument <string> { Name = "script-name", Arity = ArgumentArity.ZeroOrOne, }; scriptNameArgument.AddValidator(result => { var tokens = result.Parent !.Tokens; if (tokens.Any(t => t.Type == System.CommandLine.Parsing.TokenType.Option && t.Value == evalOption.Name)) { return("<script-name> positional argument cannot be used together with the -e option"); } return(null); }); var rootCommand = new RootCommand { Description = "The Perlang Interpreter", Handler = CommandHandler.Create((ParseResult parseResult, IConsole console) => { if (parseResult.HasOption(versionOption)) { console.Out.WriteLine(CommonConstants.InformationalVersion); return(Task.FromResult(0)); } if (parseResult.HasOption(detailedVersionOption)) { console.Out.WriteLine($"Perlang {CommonConstants.InformationalVersion} (built from git commit {CommonConstants.GitCommit}) on .NET {Environment.Version}"); console.Out.WriteLine(); console.Out.WriteLine($" Number of detected (v)CPUs: {Environment.ProcessorCount}"); console.Out.WriteLine($" Running in 64-bit mode: {Environment.Is64BitProcess}"); console.Out.WriteLine($" Operating system info: {Environment.OSVersion.VersionString}"); console.Out.WriteLine(); return(Task.FromResult(0)); } if (parseResult.HasOption(evalOption)) { // TODO: Workaround until we have a command-line-api package with https://github.com/dotnet/command-line-api/pull/1271 included. OptionResult optionResult = parseResult.FindResultFor(evalOption); string source = optionResult.Children .Where(c => c.Symbol.Name == evalOption.ArgumentHelpName) .Cast <ArgumentResult>() .First() .GetValueOrDefault <string>(); var program = new Program( replMode: true, standardOutputHandler: console.Out.WriteLine, disabledWarningsAsErrors: disabledWarningsAsErrorsList ); int result = program.Run(source, program.CompilerWarning); return(Task.FromResult(result)); } else if (parseResult.HasOption(printOption)) { // TODO: Workaround until we have a command-line-api package with https://github.com/dotnet/command-line-api/pull/1271 included. OptionResult optionResult = parseResult.FindResultFor(printOption); string source = optionResult.Children .Where(c => c.Symbol.Name == evalOption.ArgumentHelpName) .Cast <ArgumentResult>() .First() .GetValueOrDefault <string>(); new Program( replMode: true, standardOutputHandler: console.Out.WriteLine, disabledWarningsAsErrors: disabledWarningsAsErrorsList ).ParseAndPrint(source); return(Task.FromResult(0)); } else if (parseResult.Tokens.Count == 0) { new Program( replMode: true, standardOutputHandler: console.Out.WriteLine, disabledWarningsAsErrors: disabledWarningsAsErrorsList ).RunPrompt(); return(Task.FromResult(0)); } else { string scriptName = parseResult.ValueForArgument(scriptNameArgument); int result; if (parseResult.Tokens.Count == 1) { var program = new Program( replMode: false, standardOutputHandler: console.Out.WriteLine, disabledWarningsAsErrors: disabledWarningsAsErrorsList ); result = program.RunFile(scriptName); } else { // The first token available in RootCommandResult.Tokens at this point is the script name. // All remaining arguments are passed to the program, which can use methods on the ARGV // object to retrieve them. var remainingArguments = parseResult.RootCommandResult.Tokens.Skip(1) .Take(parseResult.Tokens.Count - 1) .Select(r => r.Value); var program = new Program( replMode: false, arguments: remainingArguments, standardOutputHandler: console.Out.WriteLine, disabledWarningsAsErrors: disabledWarningsAsErrorsList ); result = program.RunFile(scriptName); } return(Task.FromResult(result)); } }) }; rootCommand.AddArgument(scriptNameArgument); rootCommand.AddValidator(result => { if (result.HasOption(evalOption) && result.HasOption(printOption)) { return("Error: the -e and -p options are mutually exclusive"); } if (result.HasOption(evalOption) && result.HasArgument(scriptNameArgument)) { return("Error: the -e option cannot be combined with the <script-name> argument"); } return(null); }); var scriptArguments = new Argument <string> { Name = "args", Arity = ArgumentArity.ZeroOrMore }; rootCommand.AddArgument(scriptArguments); foreach (Option option in options) { rootCommand.AddOption(option); } return(new CommandLineBuilder(rootCommand) .UseDefaults() .Build() .Invoke(args, console)); }
static void Main(string[] args) { var rootCommand = new RootCommand() { Name = "AndroidBackupUnpacker", Description = "Tool for converting and unpacking android backups - Luka Kusulja", }; var backupFileNameArgument = new Argument <string>("backup"); rootCommand.AddArgument(backupFileNameArgument); var convertCommand = new Command("--convert", "Convert backtup to TAR archive") { new Argument <string>("tar") }; rootCommand.AddCommand(convertCommand); var unpackCommand = new Command("--unpack", "Extract content to folder") { new Argument <string>("folder") }; rootCommand.AddCommand(unpackCommand); var exitCodesCommand = new Command("--exitcodes", "Print exit code list"); rootCommand.AddCommand(exitCodesCommand); rootCommand.AddGlobalOption(new Option("--password", "Password if the backup is encrypted") { Argument = new Argument <string>("password") }); convertCommand.Handler = CommandHandler.Create <string, string, string>( (backup, tar, password) => { UnpackBackup(backup, tar, false, password); }); unpackCommand.Handler = CommandHandler.Create <string, string, string>( (backup, folder, password) => { UnpackBackup(backup, folder, true, password); }); exitCodesCommand.Handler = CommandHandler.Create( () => { PrintExitCodes(); }); rootCommand.Handler = CommandHandler.Create( () => { Console.Error.WriteLine("Missing command"); Environment.Exit((int)ExitCode.MissingCommand); }); rootCommand.Invoke(args); }
public void Binding_is_correct_for_Func_overload_having_arity_(int arity) { var command = new RootCommand(); var commandLine = ""; for (var i = 1; i <= arity; i++) { command.AddArgument(new Argument <int>($"i{i}")); commandLine += $" {i}"; } var receivedValues = new List <int>(); Delegate handlerFunc = arity switch { 1 => new Func <int, Task>( i1 => Received(i1)), 2 => new Func <int, int, Task>( (i1, i2) => Received(i1, i2)), 3 => new Func <int, int, int, Task>( (i1, i2, i3) => Received(i1, i2, i3)), 4 => new Func <int, int, int, int, Task>( (i1, i2, i3, i4) => Received(i1, i2, i3, i4)), 5 => new Func <int, int, int, int, int, Task>( (i1, i2, i3, i4, i5) => Received(i1, i2, i3, i4, i5)), 6 => new Func <int, int, int, int, int, int, Task>( (i1, i2, i3, i4, i5, i6) => Received(i1, i2, i3, i4, i5, i6)), 7 => new Func <int, int, int, int, int, int, int, Task>( (i1, i2, i3, i4, i5, i6, i7) => Received(i1, i2, i3, i4, i5, i6, i7)), 8 => new Func <int, int, int, int, int, int, int, int, Task>( (i1, i2, i3, i4, i5, i6, i7, i8) => Received(i1, i2, i3, i4, i5, i6, i7, i8)), 9 => new Func <int, int, int, int, int, int, int, int, int, Task>( (i1, i2, i3, i4, i5, i6, i7, i8, i9) => Received(i1, i2, i3, i4, i5, i6, i7, i8, i9)), 10 => new Func <int, int, int, int, int, int, int, int, int, int, Task>( (i1, i2, i3, i4, i5, i6, i7, i8, i9, i10) => Received(i1, i2, i3, i4, i5, i6, i7, i8, i9, i10)), 11 => new Func <int, int, int, int, int, int, int, int, int, int, int, Task>( (i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11) => Received(i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11)), 12 => new Func <int, int, int, int, int, int, int, int, int, int, int, int, Task>( (i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12) => Received(i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12)), 13 => new Func <int, int, int, int, int, int, int, int, int, int, int, int, int, Task>( (i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13) => Received(i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13)), 14 => new Func <int, int, int, int, int, int, int, int, int, int, int, int, int, int, Task>( (i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14) => Received(i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14)), 15 => new Func <int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, Task>( (i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15) => Received(i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15)), 16 => new Func <int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, Task>( (i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16) => Received(i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16)), _ => throw new ArgumentOutOfRangeException() }; // build up the method invocation var genericMethodDef = typeof(Handler) .GetMethods() .Where(m => m.Name == nameof(Handler.SetHandler)) .Where(m => m.IsGenericMethod /* symbols + handler Func */) .Where(m => m.GetParameters().ElementAt(1).ParameterType.Name.StartsWith("Func")) .Single(m => m.GetGenericArguments().Length == arity); var genericParameterTypes = Enumerable.Range(1, arity) .Select(_ => typeof(int)) .ToArray(); var setHandler = genericMethodDef.MakeGenericMethod(genericParameterTypes); var parameters = new List <object> { command, handlerFunc, command.Arguments.ToArray() }; setHandler.Invoke(null, parameters.ToArray()); var exitCode = command.Invoke(commandLine); receivedValues.Should().BeEquivalentTo( Enumerable.Range(1, arity), config => config.WithStrictOrdering()); exitCode.Should().Be(123); Task Received(params int[] values) { receivedValues.AddRange(values); return(Task.FromResult(123)); } }
public static Parser Create( IServiceCollection services, StartServer startServer = null, Install install = null, Demo demo = null, TryGitHub tryGithub = null, Pack pack = null, Verify verify = null, Publish publish = null, ITelemetry telemetry = null, IFirstTimeUseNoticeSentinel firstTimeUseNoticeSentinel = null) { if (services == null) { throw new ArgumentNullException(nameof(services)); } startServer ??= (startupOptions, invocationContext) => Program.ConstructWebHost(startupOptions).Run(); demo ??= DemoCommand.Do; tryGithub ??= (repo, console) => GitHubHandler.Handler(repo, console, new GitHubRepoLocator()); verify ??= VerifyCommand.Do; publish ??= (options, console, startupOptions) => PublishCommand.Do(options, console, startupOptions); pack ??= PackCommand.Do; // Setup first time use notice sentinel. firstTimeUseNoticeSentinel ??= new FirstTimeUseNoticeSentinel(VersionSensor.Version().AssemblyInformationalVersion); // Setup telemetry. telemetry ??= new Telemetry( VersionSensor.Version().AssemblyInformationalVersion, firstTimeUseNoticeSentinel); var filter = new TelemetryFilter(Sha256Hasher.HashWithNormalizedCasing); Action <ParseResult> track = o => telemetry.SendFiltered(filter, o); var dirArgument = new Argument <FileSystemDirectoryAccessor>(result => { var directory = result.Tokens .Select(t => t.Value) .FirstOrDefault(); if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory)) { result.ErrorMessage = $"Directory does not exist: {directory}"; return(null); } return(new FileSystemDirectoryAccessor( directory ?? Directory.GetCurrentDirectory())); }, isDefault: true) { Name = "root-directory", Arity = ArgumentArity.ZeroOrOne, Description = "The root directory for your documentation" }; var rootCommand = StartInTryMode(); rootCommand.AddCommand(StartInHostedMode()); rootCommand.AddCommand(Demo()); rootCommand.AddCommand(GitHub()); rootCommand.AddCommand(Install()); rootCommand.AddCommand(Pack()); rootCommand.AddCommand(Verify()); rootCommand.AddCommand(Publish()); return(new CommandLineBuilder(rootCommand) .UseDefaults() .UseMiddleware(async(context, next) => { if (context.ParseResult.Errors.Count == 0) { telemetry.SendFiltered(filter, context.ParseResult); } // If sentinel does not exist, print the welcome message showing the telemetry notification. if (!firstTimeUseNoticeSentinel.Exists() && !Telemetry.SkipFirstTimeExperience) { context.Console.Out.WriteLine(); context.Console.Out.WriteLine(Telemetry.WelcomeMessage); firstTimeUseNoticeSentinel.CreateIfNotExists(); } if (context.ParseResult.Directives.Contains("debug") && !(Clock.Current is VirtualClock)) { VirtualClock.Start(); } await next(context); }) .Build()); RootCommand StartInTryMode() { var command = new RootCommand { Name = "dotnet-try", Description = "Interactive documentation in your browser" }; command.AddArgument(dirArgument); command.AddOption(new Option( "--add-package-source", "Specify an additional NuGet package source") { Argument = new Argument <PackageSource>(() => new PackageSource(Directory.GetCurrentDirectory())) { Name = "NuGet source" } }); command.AddOption(new Option( "--package", "Specify a Try .NET package or path to a .csproj to run code samples with") { Argument = new Argument <string> { Name = "name or .csproj" } }); command.AddOption(new Option( "--package-version", "Specify a Try .NET package version to use with the --package option") { Argument = new Argument <string> { Name = "version" } }); command.AddOption(new Option <Uri>( "--uri", "Specify a URL or a relative path to a Markdown file")); command.AddOption(new Option <bool>( "--enable-preview-features", "Enable preview features")); command.AddOption(new Option( "--log-path", "Enable file logging to the specified directory") { Argument = new Argument <DirectoryInfo> { Name = "dir" } }); command.AddOption(new Option <bool>( "--verbose", "Enable verbose logging to the console")); var portArgument = new Argument <ushort>(); portArgument.AddValidator(symbolResult => { if (symbolResult.Tokens .Select(t => t.Value) .Count(value => !ushort.TryParse(value, out _)) > 0) { return("Invalid argument for --port option"); } return(null); }); command.AddOption(new Option( "--port", "Specify the port for dotnet try to listen on") { Argument = portArgument }); command.Handler = CommandHandler.Create <InvocationContext, StartupOptions>((context, options) => { services.AddSingleton(_ => PackageRegistry.CreateForTryMode( options.RootDirectory, options.AddPackageSource)); startServer(options, context); }); return(command); } Command StartInHostedMode() { var command = new Command("hosted") { new Option <string>( "--id", description: "A unique id for the agent instance (e.g. its development environment id).", getDefaultValue: () => Environment.MachineName), new Option <bool>( "--production", "Specifies whether the agent is being run using production resources"), new Option <bool>( "--language-service", "Specifies whether the agent is being run in language service-only mode"), new Option <string>( new[] { "-k", "--key" }, "The encryption key"), new Option <string>( new[] { "--ai-key", "--application-insights-key" }, "Application Insights key."), new Option <string>( "--region-id", "A unique id for the agent region"), new Option <bool>( "--log-to-file", "Writes a log file") }; command.Description = "Starts the Try .NET agent"; command.IsHidden = true; command.Handler = CommandHandler.Create <InvocationContext, StartupOptions>((context, options) => { services.AddSingleton(_ => PackageRegistry.CreateForHostedMode()); services.AddSingleton(c => new MarkdownProject(c.GetRequiredService <PackageRegistry>())); startServer(options, context); }); return(command); } Command Demo() { var demoCommand = new Command( "demo", "Learn how to create Try .NET content with an interactive demo") { new Option <DirectoryInfo>( "--output", description: "Where should the demo project be written to?", getDefaultValue: () => new DirectoryInfo(Directory.GetCurrentDirectory())) }; demoCommand.Handler = CommandHandler.Create <DemoOptions, InvocationContext>((options, context) => { demo(options, context.Console, startServer, context); }); return(demoCommand); } Command GitHub() { var argument = new Argument <string> { // System.CommandLine parameter binding does lookup by name, // so name the argument after the github command's string param Name = nameof(TryGitHubOptions.Repo) }; var github = new Command("github", "Try a GitHub repo") { argument }; github.IsHidden = true; github.Handler = CommandHandler.Create <TryGitHubOptions, IConsole>((repo, console) => tryGithub(repo, console)); return(github); } Command Install() { var installCommand = new Command("install", "Install a Try .NET package") { new Argument <string> { Name = nameof(InstallOptions.PackageName), Arity = ArgumentArity.ExactlyOne }, new Option <PackageSource>("--add-source") }; installCommand.IsHidden = true; installCommand.Handler = CommandHandler.Create <InstallOptions, IConsole>((options, console) => install(options, console)); return(installCommand); } Command Pack() { var packCommand = new Command("pack", "Create a Try .NET package") { new Argument <DirectoryInfo> { Name = nameof(PackOptions.PackTarget) }, new Option <string>("--version", "The version of the Try .NET package"), new Option <bool>("--enable-wasm", "Enables web assembly code execution") }; packCommand.IsHidden = true; packCommand.Handler = CommandHandler.Create <PackOptions, IConsole>( (options, console) => { return(pack(options, console)); }); return(packCommand); } Command Verify() { var verifyCommand = new Command("verify", "Verify Markdown files found under the root directory.") { dirArgument }; verifyCommand.Handler = CommandHandler.Create <VerifyOptions, IConsole, StartupOptions>( (options, console, startupOptions) => { return(verify(options, console, startupOptions)); }); return(verifyCommand); } Command Publish() { var publishCommand = new Command("publish", "Publish code from sample projects found under the root directory into Markdown files in the target directory") { new Option <PublishFormat>( "--format", description: "Format of the files to publish", getDefaultValue: () => PublishFormat.Markdown), new Option <IDirectoryAccessor>( "--target-directory", description: "The path where the output files should go. This can be the same as the root directory, which will overwrite files in place.", parseArgument: result => { var directory = result.Tokens .Select(t => t.Value) .Single(); return(new FileSystemDirectoryAccessor(directory)); } ), dirArgument }; publishCommand.Handler = CommandHandler.Create <PublishOptions, IConsole, StartupOptions>( (options, console, startupOptions) => publish(options, console, startupOptions)); return(publishCommand); } }
public static Task <int> Main(string[] args) { var mimeOption = new Option("--mime") { Name = "mime", Description = "MIME type indicating the type of data", Argument = new Argument <MediaTypeHeaderValue> { Name = "MIME", Description = "RFC 2616 compliant Media-Type header value, like text/plain", Arity = ArgumentArity.ZeroOrOne } }; mimeOption.AddAlias("-m"); mimeOption.Argument.AddValidator(symbol => symbol.Tokens.Select(t => t.Value) .Select(m => { try { _ = MediaTypeHeaderValue.Parse(m); return(null); } catch (FormatException) { return($"Invalid MIME format: '{m}'"); } }) .FirstOrDefault(msg => msg is string) ); var charsetOption = new Option("--charset") { Name = "charset", Description = "Add charset to mime-type", Argument = new Argument { Name = "ENCODING", Description = "Text encoding web name", Arity = ArgumentArity.ZeroOrOne } }; charsetOption.AddAlias("-c"); charsetOption.Argument.AddSuggestions(Encoding .GetEncodings() .Select(i => i.Name) .ToList()); var fileArgument = new Argument <FileInfo> { Name = "FILE", Description = "Path to file. Omit or use '-' for STDIN", Arity = ArgumentArity.ZeroOrOne }; fileArgument.AddValidator(symbol => symbol.Tokens .Select(t => t.Value) .Where(p => p != "-" && !File.Exists(p)) .Select(ValidationMessages.Instance.FileDoesNotExist) .FirstOrDefault() ); var rootCommand = new RootCommand(typeof(Program).Assembly.GetCustomAttribute <AssemblyDescriptionAttribute>()?.Description) { Handler = CommandHandler.Create <ParseResult, CancellationToken>(RunAsync) }; rootCommand.AddArgument(fileArgument); var parser = new CommandLineBuilder(rootCommand) .AddOption(mimeOption) .AddOption(charsetOption) .UseDefaults() .Build(); return(parser.InvokeAsync(args)); async Task RunAsync(ParseResult parseResult, CancellationToken cancelToken) { var mimeValue = parseResult.FindResultFor(mimeOption)? .GetValueOrDefault <MediaTypeHeaderValue>(); var charsetValue = parseResult.FindResultFor(charsetOption)? .GetValueOrDefault <string>(); if (charsetValue is string) { if (mimeValue is null) { mimeValue = new MediaTypeHeaderValue("text/plain"); } if (string.IsNullOrEmpty(mimeValue.CharSet)) { mimeValue.CharSet = charsetValue; } } var mimeString = mimeValue?.ToString(); var fileResult = parseResult.FindResultFor(fileArgument); Stream fileStream; if (fileResult is null || fileResult.Tokens.Single().Value == "-") { fileStream = Console.OpenStandardInput(); }
private static int MiddlewarePipeline(params string[] args) { // Create some options and a parser var optionThatTakesInt = new Option <int[]>( name: "--int-option", description: "An option whose argument is parsed as an int[]", getDefaultValue: () => new int[] { 1, 2, 3 }) { Arity = ArgumentArity.OneOrMore, IsHidden = false }; optionThatTakesInt.AddAlias("-i"); // optionThatTakesInt. var optionThatTakesBool = new Option <bool>( name: "--bool-option", description: "An option whose argument is parsed as a bool") { Arity = ArgumentArity.ZeroOrOne, }; optionThatTakesBool.AddAlias("-b"); var optionThatTakesFileInfo = new Option <FileInfo>( name: "--file-option", description: "An option whose argument is parsed as a FileInfo") { Arity = ArgumentArity.ExactlyOne }; // Add them to the root command // var rootCommand = new RootCommand(); var rootCommand = new RootCommand("My sample app"); rootCommand.AddAlias("pgapp"); // rootCommand.AddOption(optionThatTakesInt); // rootCommand.AddOption(optionThatTakesBool); // rootCommand.AddOption(optionThatTakesFileInfo); // ※ Argument顺序重要 Argument argument = new Argument() { Name = "playground", ValueType = typeof(string), Description = "默认参数" }; // Suggest信息会显示在help中,并且会覆盖argument.name argument.AddCompletions(new string[] { "Suggest1", "Suggest2", "substring suggest" }); // rootCommand.AddArgument(argument); Argument <string> argument1 = new Argument <string>("arg1") { Description = "string参数" }; argument1.Completions.Add(new SimpleSuggestSource()); // rootCommand.AddArgument(argument1); Argument <int> argument2 = new Argument <int>("arg2"); argument2.AddCompletions(c => { // Console.WriteLine($"textToMatch:\u001b[31m{textToMatch}\u001b[0m"); return(new string[] { "world" }); }); // rootCommand.AddArgument(argument2); // ※ handler中可以乱序 rootCommand.Handler = CommandHandler.Create <InvocationContext, string, int, string, int[], bool, FileInfo>((context, playground, arg2, arg1, intOption, boolOption, fileOption) => { Console.WriteLine("Arguments:"); Console.WriteLine($"\tplayground:{playground}"); Console.WriteLine($"\targ1:{arg1}"); Console.WriteLine($"\targ2:{arg2}"); Console.WriteLine("Options:"); foreach (var item in intOption) { Console.WriteLine($"\tThe value for --int-option is: {item}"); } Console.WriteLine($"\tThe value for --bool-option is: {boolOption}"); Console.WriteLine($"\tThe value for --file-option is: {fileOption?.FullName ?? "null"}"); }); // rootCommand.Handler = CommandHandler.Create((IConsole console, CancellationToken token) => // { // return 0; // }); // return rootCommand.InvokeAsync(new string[] { "-b" }).GetAwaiter().GetResult(); // return rootCommand.InvokeAsync(new string[] { "-i:1", "-i:2", "-b" }).GetAwaiter().GetResult(); // Console.WriteLine("inited"); rootCommand.AddCommand(BuildSubcommand()); rootCommand.AddCommand(BuildErrorSubcommand()); rootCommand.AddGlobalOption(new Option("--global", "global option sample"));// 全局选项,适用到所有子命令 rootCommand.AddOption(optionThatTakesInt); rootCommand.AddOption(optionThatTakesBool); rootCommand.AddOption(optionThatTakesFileInfo); rootCommand.AddArgument(argument); rootCommand.AddArgument(argument1); rootCommand.AddArgument(argument2); var builder = new CommandLineBuilder(rootCommand) // .EnablePositionalOptions(value: true)/* 无用 */ .EnablePosixBundling(value: true) /* 对无值option生效,-b */ // .ParseResponseFileAs(responseFileHandling: ResponseFileHandling.ParseArgsAsLineSeparated) /* 添加@起始参数,从文件读取命令 */ .ParseResponseFileAs(responseFileHandling: ResponseFileHandling.ParseArgsAsSpaceSeparated) // .UseDefaults() ////.UseVersionOption() .UseHelp() ////.UseEnvironmentVariableDirective() ////.UseParseDirective() ////.UseDebugDirective() ////.UseSuggestDirective() ////.RegisterWithDotnetSuggest() ////.UseTypoCorrections() ////.UseParseErrorReporting() ////.UseExceptionHandler() ////.CancelOnProcessTermination() // /* 自定义帮助信息输出类 */ // .UseHelpBuilder(context => // { // return new HelpBuilder(new LocalizationResources()); // }) .UseVersionOption() // 版本号选项,--version .CancelOnProcessTermination() // 控制台ctrl+c取消事件 // 设置console .ConfigureConsole(context => { return(context.Console); }) .RegisterWithDotnetSuggest() // 需要安装dotnet-suggest .UseDebugDirective() // 使用[debug]指令 // 命令异常处理 .UseExceptionHandler((ex, context) => { context.Console.Error.WriteLine($"ExceptionHandler<{ex.GetType()}>:\u001b[31m{ex.Message}\u001b[0m"); }) // | lv | value | MiddlewareOrderInternal | MiddlewareOrder | // | --- | ----- | ---------------------------- | ---------------- | // | 1 | -4000 | Startup | | // | 2 | -3000 | ExceptionHandler | | // | 3 | -2600 | EnvironmentVariableDirective | | // | 4 | -2500 | ConfigureConsole | | // | 5 | -2400 | RegisterWithDotnetSuggest | | // | 6 | -2300 | DebugDirective | | // | 7 | -2200 | ParseDirective | | // | 8 | -2000 | SuggestDirective | ExceptionHandler | // | 9 | -1900 | TypoCorrection | | // | 10 | -1200 | VersionOption | | // | 11 | -1100 | HelpOption | | // | 12 | -1000 | | Configuration | // | 13 | 0 | | Default | // | 14 | 1000 | ParseErrorReporting | ErrorReporting | // .UseHelp()/* help中间件优先级为11级 */ // .UseHelpBuilder(context => new HelpBuilder(context.Console)) // 普通中间件优先级为13级 .AddMiddleware(context => { // 默认执行后续中间件 if (context.ParseResult.Directives.TryGetValues("command", out IReadOnlyList <string> value)) { Console.WriteLine(string.Join(',', value.ToArray())); } }) .AddMiddleware(async(context, next) => { // 选择执行后续中间件 if (context.ParseResult.Directives.Contains("just-say-hi")) { context.Console.Out.WriteLine("Hi!"); if (context.ParseResult.Directives.Contains("just-say-hi2")) { context.Console.Out.WriteLine("Hi2!"); } } else { await next(context); } }) .AddMiddleware(async(context, next) => { if (context.ParseResult.Directives.Contains("Simple")) { context.InvocationResult = new SimpleResult(); } await next(context); }) .UseParseDirective() // 当解析失败直接返回,不会执行设置的中间件 .UseParseErrorReporting() // 拼写错误提示 // 0.3.0-alpha.19317.1 bug command有参数时异常 https://github.com/dotnet/command-line-api/issues/578 .UseTypoCorrections() // 显示argument添加的suggest,并通过指令参数搜索 // 指令参数表示搜索的字符串索引处单个单词 // 指令参数缺省为0 .UseSuggestDirective() .Build(); // Console.WriteLine("created"); return(builder.InvokeAsync(args).Result); }