Beispiel #1
0
        internal static RootCommand CreateRootCommand()
        {
            var rootCommand = new RootCommand()
            {
                Description = "A multi-platform data driven 2D diagram editor."
            };

            var optionTheme = new Option(new[] { "--theme", "-t" }, "Set application theme")
            {
                Argument = new Argument <ThemeName?>()
            };

            rootCommand.AddOption(optionTheme);

            var optionScripts = new Option(new[] { "--scripts", "-s" }, "The relative or absolute path to the script files")
            {
                Argument = new Argument <FileInfo[]?>()
            };

            rootCommand.AddOption(optionScripts);

            var optionProject = new Option(new[] { "--project", "-p" }, "The relative or absolute path to the project file")
            {
                Argument = new Argument <FileInfo?>()
            };

            rootCommand.AddOption(optionProject);

            var optionRepl = new Option(new[] { "--repl" }, "Run scripting repl")
            {
                Argument = new Argument <bool>()
            };

            rootCommand.AddOption(optionRepl);

            var optionUseManagedSystemDialogs = new Option(new[] { "--useManagedSystemDialogs" }, "Use managed system dialogs")
            {
                Argument = new Argument <bool>()
            };

            rootCommand.AddOption(optionUseManagedSystemDialogs);

            var optionUseSkia = new Option(new[] { "--useSkia" }, "Use Skia renderer")
            {
                Argument = new Argument <bool>()
            };

            rootCommand.AddOption(optionUseSkia);

            var optionUseDirect2D1 = new Option(new[] { "--useDirect2D1" }, "Use Direct2D1 renderer")
            {
                Argument = new Argument <bool>()
            };

            rootCommand.AddOption(optionUseDirect2D1);

            var optionEnableMultiTouch = new Option(new[] { "--enableMultiTouch" }, "Enable multi-touch")
            {
                Argument = new Argument <bool>(getDefaultValue: () => true)
            };

            rootCommand.AddOption(optionEnableMultiTouch);

            var optionUseGpu = new Option(new[] { "--useGpu" }, "Use Gpu")
            {
                Argument = new Argument <bool>(getDefaultValue: () => true)
            };

            rootCommand.AddOption(optionUseGpu);

            var optionAllowEglInitialization = new Option(new[] { "--allowEglInitialization" }, "Allow EGL initialization")
            {
                Argument = new Argument <bool>(getDefaultValue: () => true)
            };

            rootCommand.AddOption(optionAllowEglInitialization);

            var optionUseDeferredRendering = new Option(new[] { "--useDeferredRendering" }, "Use deferred rendering")
            {
                Argument = new Argument <bool>(getDefaultValue: () => true)
            };

            rootCommand.AddOption(optionUseDeferredRendering);

            var optionUseDirectX11 = new Option(new[] { "--useDirectX11" }, "Use DirectX11 platform api")
            {
                Argument = new Argument <bool>()
            };

            rootCommand.AddOption(optionUseDirectX11);

            var optionUseHeadless = new Option(new[] { "--useHeadless" }, "Use headless")
            {
                Argument = new Argument <bool>()
            };

            rootCommand.AddOption(optionUseHeadless);

            var optionUseHeadlessDrawing = new Option(new[] { "--useHeadlessDrawing" }, "Use headless drawing")
            {
                Argument = new Argument <bool>()
            };

            rootCommand.AddOption(optionUseHeadlessDrawing);

            var optionUseHeadlessVnc = new Option(new[] { "--useHeadlessVnc" }, "Use headless vnc")
            {
                Argument = new Argument <bool>()
            };

            rootCommand.AddOption(optionUseHeadlessVnc);

            var optionCreateHeadlessScreenshots = new Option(new[] { "--createHeadlessScreenshots" }, "Create headless screenshots")
            {
                Argument = new Argument <bool>()
            };

            rootCommand.AddOption(optionCreateHeadlessScreenshots);

            var optionVncHost = new Option(new[] { "--vncHost" }, "Vnc host")
            {
                Argument = new Argument <string?>()
            };

            rootCommand.AddOption(optionVncHost);

            var optionVncPort = new Option(new[] { "--vncPort" }, "Vnc port")
            {
                Argument = new Argument <int>(getDefaultValue: () => 5901)
            };

            rootCommand.AddOption(optionVncPort);

            return(rootCommand);
        }
Beispiel #2
0
    private static bool TryParseCli(string[] args, out Configuration config)
    {
        var cmd = new RootCommand();

        cmd.AddOption(new Option("-n", "Max number of requests to make concurrently.")
        {
            Argument = new Argument <int>("numWorkers", Environment.ProcessorCount)
        });
        cmd.AddOption(new Option("-serverUri", "Stress suite server uri.")
        {
            Argument = new Argument <Uri>("serverUri", new Uri("https://localhost:5001"))
        });
        cmd.AddOption(new Option("-runMode", "Stress suite execution mode. Defaults to Both.")
        {
            Argument = new Argument <RunMode>("runMode", RunMode.both)
        });
        cmd.AddOption(new Option("-maxContentLength", "Max content length for request and response bodies.")
        {
            Argument = new Argument <int>("numBytes", 1000)
        });
        cmd.AddOption(new Option("-maxRequestUriSize", "Max query string length support by the server.")
        {
            Argument = new Argument <int>("numChars", 5000)
        });
        cmd.AddOption(new Option("-maxRequestHeaderCount", "Maximum number of headers to place in request")
        {
            Argument = new Argument <int>("numHeaders", 90)
        });
        cmd.AddOption(new Option("-maxRequestHeaderTotalSize", "Max request header total size.")
        {
            Argument = new Argument <int>("numBytes", 1000)
        });
        cmd.AddOption(new Option("-http", "HTTP version (1.1 or 2.0)")
        {
            Argument = new Argument <Version>("version", HttpVersion.Version20)
        });
        cmd.AddOption(new Option("-connectionLifetime", "Max connection lifetime length (milliseconds).")
        {
            Argument = new Argument <int?>("connectionLifetime", null)
        });
        cmd.AddOption(new Option("-ops", "Indices of the operations to use")
        {
            Argument = new Argument <int[]>("space-delimited indices", null)
        });
        cmd.AddOption(new Option("-xops", "Indices of the operations to exclude")
        {
            Argument = new Argument <int[]>("space-delimited indices", null)
        });
        cmd.AddOption(new Option("-trace", "Enable Microsoft-System-Net-Http tracing.")
        {
            Argument = new Argument <string>("\"console\" or path")
        });
        cmd.AddOption(new Option("-aspnetlog", "Enable ASP.NET warning and error logging.")
        {
            Argument = new Argument <bool>("enable", false)
        });
        cmd.AddOption(new Option("-listOps", "List available options.")
        {
            Argument = new Argument <bool>("enable", false)
        });
        cmd.AddOption(new Option("-seed", "Seed for generating pseudo-random parameters for a given -n argument.")
        {
            Argument = new Argument <int?>("seed", null)
        });
        cmd.AddOption(new Option("-numParameters", "Max number of query parameters or form fields for a request.")
        {
            Argument = new Argument <int>("queryParameters", 1)
        });
        cmd.AddOption(new Option("-cancelRate", "Number between 0 and 1 indicating rate of client-side request cancellation attempts. Defaults to 0.1.")
        {
            Argument = new Argument <double>("probability", 0.1)
        });
        cmd.AddOption(new Option("-httpSys", "Use http.sys instead of Kestrel.")
        {
            Argument = new Argument <bool>("enable", false)
        });
        cmd.AddOption(new Option("-winHttp", "Use WinHttpHandler for the stress client.")
        {
            Argument = new Argument <bool>("enable", false)
        });
        cmd.AddOption(new Option("-displayInterval", "Client stats display interval in seconds. Defaults to 5 seconds.")
        {
            Argument = new Argument <int>("seconds", 5)
        });
        cmd.AddOption(new Option("-clientTimeout", "Default HttpClient timeout in seconds. Defaults to 10 seconds.")
        {
            Argument = new Argument <int>("seconds", 10)
        });

        ParseResult cmdline = cmd.Parse(args);

        if (cmdline.Errors.Count > 0)
        {
            foreach (ParseError error in cmdline.Errors)
            {
                Console.WriteLine(error);
            }
            Console.WriteLine();
            new HelpBuilder(new SystemConsole()).Write(cmd);
            config = null;
            return(false);
        }

        config = new Configuration()
        {
            RunMode        = cmdline.ValueForOption <RunMode>("-runMode"),
            ServerUri      = cmdline.ValueForOption <Uri>("-serverUri"),
            ListOperations = cmdline.ValueForOption <bool>("-listOps"),

            HttpVersion               = cmdline.ValueForOption <Version>("-http"),
            UseWinHttpHandler         = cmdline.ValueForOption <bool>("-winHttp"),
            ConcurrentRequests        = cmdline.ValueForOption <int>("-n"),
            RandomSeed                = cmdline.ValueForOption <int?>("-seed") ?? new Random().Next(),
            MaxContentLength          = cmdline.ValueForOption <int>("-maxContentLength"),
            MaxRequestUriSize         = cmdline.ValueForOption <int>("-maxRequestUriSize"),
            MaxRequestHeaderCount     = cmdline.ValueForOption <int>("-maxRequestHeaderCount"),
            MaxRequestHeaderTotalSize = cmdline.ValueForOption <int>("-maxRequestHeaderTotalSize"),
            OpIndices               = cmdline.ValueForOption <int[]>("-ops"),
            ExcludedOpIndices       = cmdline.ValueForOption <int[]>("-xops"),
            MaxParameters           = cmdline.ValueForOption <int>("-numParameters"),
            DisplayInterval         = TimeSpan.FromSeconds(cmdline.ValueForOption <int>("-displayInterval")),
            DefaultTimeout          = TimeSpan.FromSeconds(cmdline.ValueForOption <int>("-clientTimeout")),
            ConnectionLifetime      = cmdline.ValueForOption <double?>("-connectionLifetime").Select(TimeSpan.FromMilliseconds),
            CancellationProbability = Math.Max(0, Math.Min(1, cmdline.ValueForOption <double>("-cancelRate"))),

            UseHttpSys = cmdline.ValueForOption <bool>("-httpSys"),
            LogAspNet  = cmdline.ValueForOption <bool>("-aspnetlog"),
            LogPath    = cmdline.HasOption("-trace") ? cmdline.ValueForOption <string>("-trace") : null
        };

        return(true);
    }
        public static Parser Create(
            IServiceCollection services,
            StartServer startServer             = null,
            Jupyter jupyter                     = null,
            StartKernelServer startKernelServer = null,
            ITelemetry telemetry                = null,
            IFirstTimeUseNoticeSentinel firstTimeUseNoticeSentinel = null)
        {
            if (services == null)
            {
                throw new ArgumentNullException(nameof(services));
            }

            startServer ??= ((startupOptions, invocationContext) =>
                             Program.ConstructWebHost(startupOptions).Run());

            jupyter ??= JupyterCommand.Do;

            startKernelServer ??= (async(startupOptions, kernel, console) =>
            {
                var disposable = Program.StartToolLogging(startupOptions);
                if (kernel is KernelBase kernelBase)
                {
                    kernelBase.RegisterForDisposal(disposable);
                }
                var server = new StandardIOKernelServer(
                    kernel,
                    Console.In,
                    Console.Out);

                await server.Input.LastAsync();
            });

            // Setup first time use notice sentinel.
            firstTimeUseNoticeSentinel ??= new FirstTimeUseNoticeSentinel(VersionSensor.Version().AssemblyInformationalVersion);

            // Setup telemetry.
            telemetry ??= new Telemetry.Telemetry(
                VersionSensor.Version().AssemblyInformationalVersion,
                firstTimeUseNoticeSentinel);
            var filter = new TelemetryFilter(Sha256Hasher.HashWithNormalizedCasing);

            void Track(ParseResult o) => telemetry.SendFiltered(filter, o);

            var verboseOption = new Option <bool>(
                "--verbose",
                "Enable verbose logging to the console");

            var logPathOption = new Option <DirectoryInfo>(
                "--log-path",
                "Enable file logging to the specified directory");

            var defaultKernelOption = new Option <string>(
                "--default-kernel",
                description: "The default language for the kernel",
                getDefaultValue: () => "csharp");
            var rootCommand = DotnetInteractive();

            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();
                }

                await next(context);
            })
                   .Build());

            RootCommand DotnetInteractive()
            {
                var command = new RootCommand
                {
                    Name        = "dotnet-interactive",
                    Description = "Interactive programming for .NET."
                };

                command.AddOption(logPathOption);
                command.AddOption(verboseOption);

                return(command);
            }

            Command Jupyter()
            {
                var jupyterCommand = new Command("jupyter", "Starts dotnet-interactive as a Jupyter kernel")
                {
                    defaultKernelOption,
                    logPathOption,
                    verboseOption,
                    new Argument <FileInfo>
                    {
                        Name = "connection-file"
                    }.ExistingOnly()
                };

                jupyterCommand.Handler = CommandHandler.Create <StartupOptions, JupyterOptions, IConsole, InvocationContext>((startupOptions, options, console, context) =>
                {
                    Track(context.ParseResult);

                    var frontendEnvironment = new JupyterFrontendEnvironment();
                    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, frontendEnvironment))
                    .AddSingleton(c => new JupyterRequestContextHandler(c.GetRequiredService <IKernel>(), frontendEnvironment)
                                  .Trace())
                    .AddSingleton <IHostedService, Shell>()
                    .AddSingleton <IHostedService, Heartbeat>();

                    return(jupyter(startupOptions, console, startServer, context));
                });

                var installCommand = new Command("install", "Install the .NET kernel for Jupyter")
                {
                    logPathOption,
                    verboseOption
                };

                installCommand.Handler = CommandHandler.Create <IConsole, InvocationContext>((console, context) =>
                {
                    Track(context.ParseResult);
                    return(new JupyterInstallCommand(console, new JupyterKernelSpec()).InvokeAsync());
                });

                jupyterCommand.AddCommand(installCommand);

                return(jupyterCommand);
            }

            Command KernelServer()
            {
                var startKernelServerCommand = new Command("kernel-server", "Starts dotnet-interactive with kernel functionality exposed over standard I/O")
                {
                    defaultKernelOption,
                    logPathOption,
                };

                startKernelServerCommand.Handler = CommandHandler.Create <StartupOptions, KernelServerOptions, IConsole, InvocationContext>(
                    (startupOptions, options, console, context) =>
                {
                    Track(context.ParseResult);
                    return(startKernelServer(startupOptions, CreateKernel(options.DefaultKernel, new JupyterFrontendEnvironment()), console));
                });

                return(startKernelServerCommand);
            }
        }
Beispiel #4
0
        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)
        {
            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 ??
                     ((options, console, startupOptions) =>
                      VerifyCommand.Do(options,
                                       console,
                                       startupOptions));

            pack = pack ??
                   PackCommand.Do;

            install = install ??
                      InstallCommand.Do;

            startKernelServer = startKernelServer ??
                                KernelServerCommand.Do;

            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 (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")
                {
                    IsHidden = true
                };
                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 <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)));
                    })
                    .AddSingleton(c => CreateKernel(options.DefaultKernel))
                    .AddSingleton(c => new JupyterRequestContextHandler(c.GetRequiredService <IKernel>())
                                  .Trace())
                    .AddSingleton <IHostedService, Shell>()
                    .AddSingleton <IHostedService, Heartbeat>();

                    return(jupyter(console, startServer, context));
                });

                var installCommand = new Command("install", "Install the .NET kernel for Jupyter");

                installCommand.Handler = CommandHandler.Create <IConsole>((console) =>
                {
                    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")
                {
                    IsHidden = true
                };
                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 <KernelServerOptions, IConsole>((options, console) =>
                {
                    return(startKernelServer(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)
                    },
                    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);
            }
        }
Beispiel #5
0
        static async Task <int> Main(string[] args)
        {
            var rootCommand = new RootCommand()
            {
                Description = "Converts a svg file to a C# code."
            };

            var optionInputFile = new Option(new[] { "--inputFile", "-i" }, "The relative or absolute path to the input file")
            {
                IsRequired = false,
                Argument   = new Argument <System.IO.FileInfo?>(getDefaultValue: () => null)
            };

            rootCommand.AddOption(optionInputFile);

            var optionOutputFile = new Option(new[] { "--outputFile", "-o" }, "The relative or absolute path to the output file")
            {
                IsRequired = false,
                Argument   = new Argument <System.IO.FileInfo?>(getDefaultValue: () => null)
            };

            rootCommand.AddOption(optionOutputFile);

            var optionJsonFile = new Option(new[] { "--jsonFile", "-j" }, "The relative or absolute path to the json file")
            {
                IsRequired = false,
                Argument   = new Argument <System.IO.FileInfo?>(getDefaultValue: () => null)
            };

            rootCommand.AddOption(optionJsonFile);

            var optionNamespace = new Option(new[] { "--namespace", "-n" }, "The generated C# namespace name")
            {
                IsRequired = false,
                Argument   = new Argument <string>(getDefaultValue: () => "Svg")
            };

            rootCommand.AddOption(optionNamespace);

            var optionClass = new Option(new[] { "--class", "-c" }, "The generated C# class name")
            {
                IsRequired = false,
                Argument   = new Argument <string>(getDefaultValue: () => "Generated")
            };

            rootCommand.AddOption(optionClass);

            rootCommand.Handler = CommandHandler.Create((Settings settings) =>
            {
                try
                {
                    if (settings.JsonFile != null)
                    {
                        var json    = System.IO.File.ReadAllText(settings.JsonFile.FullName);
                        var options = new JsonSerializerOptions
                        {
                            ReadCommentHandling = JsonCommentHandling.Skip
                        };
                        var items = JsonSerializer.Deserialize <Item[]>(json, options);
                        if (items != null)
                        {
                            foreach (var item in items)
                            {
                                if (item.InputFile != null && item.OutputFile != null)
                                {
                                    Log($"Generating: {item.OutputFile}");
                                    Generate(item.InputFile, item.OutputFile, item.Namespace ?? settings.Namespace, item.Class ?? settings.Class);
                                }
                            }
                        }
                    }

                    if (settings.InputFile != null && settings.OutputFile != null)
                    {
                        Log($"Generating: {settings.OutputFile.FullName}");
                        Generate(settings.InputFile.FullName, settings.OutputFile.FullName, settings.Namespace, settings.Class);
                    }
                }
                catch (Exception ex)
                {
                    Error(ex);
                }
            });

            return(await rootCommand.InvokeAsync(args));
        }
Beispiel #6
0
    public static void Main(string[] args)
    {
        var cmd = new RootCommand();

        cmd.AddOption(new Option("-n", "Max number of requests to make concurrently.")
        {
            Argument = new Argument <int>("numWorkers", Environment.ProcessorCount)
        });
        cmd.AddOption(new Option("-serverUri", "Stress suite server uri.")
        {
            Argument = new Argument <Uri>("serverUri", new Uri("https://localhost:5001"))
        });
        cmd.AddOption(new Option("-runMode", "Stress suite execution mode. Defaults to Both.")
        {
            Argument = new Argument <RunMode>("runMode", RunMode.both)
        });
        cmd.AddOption(new Option("-maxContentLength", "Max content length for request and response bodies.")
        {
            Argument = new Argument <int>("numBytes", 1000)
        });
        cmd.AddOption(new Option("-maxRequestLineSize", "Max query string length support by the server.")
        {
            Argument = new Argument <int>("numChars", 8192)
        });
        cmd.AddOption(new Option("-http", "HTTP version (1.1 or 2.0)")
        {
            Argument = new Argument <Version>("version", HttpVersion.Version20)
        });
        cmd.AddOption(new Option("-connectionLifetime", "Max connection lifetime length (milliseconds).")
        {
            Argument = new Argument <int?>("connectionLifetime", null)
        });
        cmd.AddOption(new Option("-ops", "Indices of the operations to use")
        {
            Argument = new Argument <int[]>("space-delimited indices", null)
        });
        cmd.AddOption(new Option("-trace", "Enable Microsoft-System-Net-Http tracing.")
        {
            Argument = new Argument <string>("\"console\" or path")
        });
        cmd.AddOption(new Option("-aspnetlog", "Enable ASP.NET warning and error logging.")
        {
            Argument = new Argument <bool>("enable", false)
        });
        cmd.AddOption(new Option("-listOps", "List available options.")
        {
            Argument = new Argument <bool>("enable", false)
        });
        cmd.AddOption(new Option("-seed", "Seed for generating pseudo-random parameters for a given -n argument.")
        {
            Argument = new Argument <int?>("seed", null)
        });
        cmd.AddOption(new Option("-numParameters", "Max number of query parameters or form fields for a request.")
        {
            Argument = new Argument <int>("queryParameters", 1)
        });
        cmd.AddOption(new Option("-cancelRate", "Number between 0 and 1 indicating rate of client-side request cancellation attempts. Defaults to 0.1.")
        {
            Argument = new Argument <double>("probability", 0.1)
        });
        cmd.AddOption(new Option("-httpSys", "Use http.sys instead of Kestrel.")
        {
            Argument = new Argument <bool>("enable", false)
        });
        cmd.AddOption(new Option("-displayInterval", "Client stats display interval in seconds. Defaults to 1 second.")
        {
            Argument = new Argument <int>("displayInterval", 1)
        });

        ParseResult cmdline = cmd.Parse(args);

        if (cmdline.Errors.Count > 0)
        {
            foreach (ParseError error in cmdline.Errors)
            {
                Console.WriteLine(error);
            }
            Console.WriteLine();
            new HelpBuilder(new SystemConsole()).Write(cmd);
            return;
        }

        Run(
            runMode: cmdline.ValueForOption <RunMode>("-runMode"),
            serverUri: cmdline.ValueForOption <Uri>("-serverUri"),
            httpSys: cmdline.ValueForOption <bool>("-httpSys"),
            concurrentRequests: cmdline.ValueForOption <int>("-n"),
            maxContentLength: cmdline.ValueForOption <int>("-maxContentLength"),
            maxRequestLineSize: cmdline.ValueForOption <int>("-maxRequestLineSize"),
            httpVersion: cmdline.ValueForOption <Version>("-http"),
            connectionLifetime: cmdline.ValueForOption <int?>("-connectionLifetime"),
            opIndices: cmdline.ValueForOption <int[]>("-ops"),
            logPath: cmdline.HasOption("-trace") ? cmdline.ValueForOption <string>("-trace") : null,
            aspnetLog: cmdline.ValueForOption <bool>("-aspnetlog"),
            listOps: cmdline.ValueForOption <bool>("-listOps"),
            seed: cmdline.ValueForOption <int?>("-seed") ?? new Random().Next(),
            numParameters: cmdline.ValueForOption <int>("-numParameters"),
            cancellationProbability: Math.Max(0, Math.Min(1, cmdline.ValueForOption <double>("-cancelRate"))),
            displayIntervalSeconds: cmdline.ValueForOption <int>("-displayInterval"));
    }
Beispiel #7
0
        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);
        }
Beispiel #8
0
        public static Parser Create(
            IServiceCollection services,
            StartServer startServer = null,
            Jupyter jupyter         = null,
            StartStdIO startStdIO   = null,
            StartHttp startHttp     = null,
            ITelemetry telemetry    = null,
            IFirstTimeUseNoticeSentinel firstTimeUseNoticeSentinel = null)
        {
            if (services == null)
            {
                throw new ArgumentNullException(nameof(services));
            }

            startServer ??= (startupOptions, invocationContext) =>
            Program.ConstructWebHost(startupOptions).Run();

            jupyter ??= JupyterCommand.Do;

            startStdIO ??= StdIOCommand.Do;

            startHttp ??= HttpCommand.Do;

            // Setup first time use notice sentinel.
            firstTimeUseNoticeSentinel ??= new FirstTimeUseNoticeSentinel(VersionSensor.Version().AssemblyInformationalVersion);

            // Setup telemetry.
            telemetry ??= new Telemetry.Telemetry(
                VersionSensor.Version().AssemblyInformationalVersion,
                firstTimeUseNoticeSentinel);
            var filter = new TelemetryFilter(Sha256Hasher.HashWithNormalizedCasing);

            var verboseOption = new Option <bool>(
                "--verbose",
                "Enable verbose logging to the console");

            var logPathOption = new Option <DirectoryInfo>(
                "--log-path",
                "Enable file logging to the specified directory");

            var pathOption = new Option <DirectoryInfo>(
                "--path",
                "Installs the kernelspecs to the specified directory")
                             .ExistingOnly();

            var defaultKernelOption = new Option <string>(
                "--default-kernel",
                description: "The default language for the kernel",
                getDefaultValue: () => "csharp");

            var rootCommand = DotnetInteractive();

            rootCommand.AddCommand(Jupyter());
            rootCommand.AddCommand(StdIO());
            rootCommand.AddCommand(HttpServer());

            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.Telemetry.SkipFirstTimeExperience)
                {
                    context.Console.Out.WriteLine();
                    context.Console.Out.WriteLine(Telemetry.Telemetry.WelcomeMessage);

                    firstTimeUseNoticeSentinel.CreateIfNotExists();
                }

                await next(context);
            })
                   .Build());

            RootCommand DotnetInteractive()
            {
                var command = new RootCommand
                {
                    Name        = "dotnet-interactive",
                    Description = "Interactive programming for .NET."
                };

                command.AddOption(logPathOption);
                command.AddOption(verboseOption);

                return(command);
            }

            Command Jupyter()
            {
                var httpPortRangeOption = new Option <HttpPortRange>(
                    "--http-port-range",
                    parseArgument: result => result.Tokens.Count == 0 ? HttpPortRange.Default : ParsePortRangeOption(result),
                    description: "Specifies the range of port to use to enable HTTP services",
                    isDefault: true);

                var command = new Command("jupyter", "Starts dotnet-interactive as a Jupyter kernel")
                {
                    defaultKernelOption,
                    logPathOption,
                    verboseOption,
                    httpPortRangeOption,
                    new Argument <FileInfo>
                    {
                        Name = "connection-file"
                    }.ExistingOnly()
                };

                command.Handler = CommandHandler.Create <StartupOptions, JupyterOptions, IConsole, InvocationContext>(JupyterHandler);

                var installCommand = new Command("install", "Install the .NET kernel for Jupyter")
                {
                    logPathOption,
                    verboseOption,
                    httpPortRangeOption,
                    pathOption
                };

                installCommand.Handler = CommandHandler.Create <IConsole, InvocationContext, HttpPortRange, DirectoryInfo>(InstallHandler);

                command.AddCommand(installCommand);

                return(command);

                Task <int> JupyterHandler(StartupOptions startupOptions, JupyterOptions options, IConsole console, InvocationContext context)
                {
                    services = RegisterKernelInServiceCollection(
                        services,
                        startupOptions,
                        options.DefaultKernel,
                        serviceCollection =>
                    {
                        serviceCollection.AddSingleton(_ => new HtmlNotebookFrontedEnvironment());
                        serviceCollection.AddSingleton <FrontendEnvironment>(c =>
                                                                             c.GetService <HtmlNotebookFrontedEnvironment>());
                    });

                    services.AddSingleton(c => ConnectionInformation.Load(options.ConnectionFile))
                    .AddSingleton(c =>
                    {
                        return(CommandScheduler.Create <JupyterRequestContext>(delivery => c.GetRequiredService <ICommandHandler <JupyterRequestContext> >()
                                                                               .Trace()
                                                                               .Handle(delivery)));
                    })
                    .AddSingleton(c => new JupyterRequestContextHandler(
                                      c.GetRequiredService <IKernel>())
                                  .Trace())
                    .AddSingleton <IHostedService, Shell>()
                    .AddSingleton <IHostedService, Heartbeat>();

                    return(jupyter(startupOptions, console, startServer, context));
                }

                Task <int> InstallHandler(IConsole console, InvocationContext context, HttpPortRange httpPortRange, DirectoryInfo path)
                {
                    var jupyterInstallCommand = new JupyterInstallCommand(console, new JupyterKernelSpecInstaller(console), httpPortRange, path);

                    return(jupyterInstallCommand.InvokeAsync());
                }
            }

            Command HttpServer()
            {
                var httpPortOption = new Option <HttpPort>(
                    "--http-port",
                    description: "Specifies the port on which to enable HTTP services",
                    parseArgument: result =>
                {
                    if (result.Tokens.Count == 0)
                    {
                        return(HttpPort.Auto);
                    }

                    var source = result.Tokens[0].Value;

                    if (source == "*")
                    {
                        return(HttpPort.Auto);
                    }

                    if (!int.TryParse(source, out var portNumber))
                    {
                        result.ErrorMessage = "Must specify a port number or *.";
                        return(null);
                    }

                    return(new HttpPort(portNumber));
                },
                    isDefault: true);


                var command = new Command("http", "Starts dotnet-interactive with kernel functionality exposed over http")
                {
                    defaultKernelOption,
                    httpPortOption,
                    logPathOption
                };

                command.Handler = CommandHandler.Create <StartupOptions, KernelHttpOptions, IConsole, InvocationContext>(
                    (startupOptions, options, console, context) =>
                {
                    RegisterKernelInServiceCollection(
                        services,
                        startupOptions,
                        options.DefaultKernel, serviceCollection =>
                    {
                        serviceCollection.AddSingleton(_ =>
                        {
                            var frontendEnvironment = new BrowserFrontendEnvironment();
                            return(frontendEnvironment);
                        });
                        serviceCollection.AddSingleton <FrontendEnvironment>(c => c.GetRequiredService <BrowserFrontendEnvironment>());
                    });
                    return(startHttp(startupOptions, console, startServer, context));
                });

                return(command);
            }

            Command StdIO()
            {
                var httpPortRangeOption = new Option <HttpPortRange>(
                    "--http-port-range",
                    parseArgument: result => result.Tokens.Count == 0 ? HttpPortRange.Default : ParsePortRangeOption(result),
                    description: "Specifies the range of port to use to enable HTTP services");

                var command = new Command(
                    "stdio",
                    "Starts dotnet-interactive with kernel functionality exposed over standard I/O")
                {
                    defaultKernelOption,
                    logPathOption,
                    httpPortRangeOption
                };

                command.Handler = CommandHandler.Create <StartupOptions, StdIOOptions, IConsole, InvocationContext>(
                    (startupOptions, options, console, context) =>
                {
                    if (startupOptions.EnableHttpApi)
                    {
                        RegisterKernelInServiceCollection(
                            services,
                            startupOptions,
                            options.DefaultKernel,
                            serviceCollection =>
                        {
                            serviceCollection.AddSingleton(_ => new HtmlNotebookFrontedEnvironment());
                            serviceCollection.AddSingleton <FrontendEnvironment>(c =>
                                                                                 c.GetService <HtmlNotebookFrontedEnvironment>());
                        }, kernel =>
                        {
                            StdIOCommand.CreateServer(kernel, console);
                        });

                        return(startHttp(startupOptions, console, startServer, context));
                    }
                    return(startStdIO(
                               startupOptions,
                               CreateKernel(options.DefaultKernel, new BrowserFrontendEnvironment(), startupOptions, null),
                               console));
                });

                return(command);
            }
Beispiel #9
0
        /// <summary>
        /// Build the RootCommand for parsing
        /// </summary>
        /// <returns>RootCommand</returns>
        public static RootCommand BuildRootCommand()
        {
            RootCommand root = new RootCommand
            {
                Name        = "LodeRunner",
                Description = "Validate API responses",
                TreatUnmatchedTokensAsErrors = true,
            };

            root.AddOption(new Option <List <string> >(new string[] { "-s", "--server" }, Parsers.ParseStringList, true, "Server(s) to test"));
            root.AddOption(new Option <List <string> >(new string[] { "-f", "--files" }, Parsers.ParseStringList, true, "List of files to test"));
            root.AddOption(new Option <string>(new string[] { "--zone" }, Parsers.ParseString, true, "Zone for logging"));
            root.AddOption(new Option <string>(new string[] { "--region" }, Parsers.ParseString, true, "Region for logging"));
            root.AddOption(new Option <bool>(new string[] { "-p", "--prometheus" }, Parsers.ParseBool, true, "Send metrics to Prometheus"));
            root.AddOption(new Option <string>(new string[] { "--tag" }, Parsers.ParseString, true, "Tag for logging"));
            root.AddOption(new Option <int>(new string[] { "-l", "--sleep" }, Parsers.ParseIntGTZero, true, "Sleep (ms) between each request"));
            root.AddOption(new Option <bool>(new string[] { "-j", "--strict-json" }, Parsers.ParseBool, true, "Use strict json when parsing"));
            root.AddOption(new Option <string>(new string[] { "-u", "--base-url" }, Parsers.ParseString, true, "Base url for files"));
            root.AddOption(new Option <bool>(new string[] { "-v", "--verbose" }, Parsers.ParseBool, true, "Display verbose results"));
            root.AddOption(new Option <bool>(new string[] { "-r", "--run-loop" }, Parsers.ParseBool, true, "Run test in an infinite loop"));
            root.AddOption(new Option <bool>(new string[] { "--verbose-errors" }, Parsers.ParseBool, true, "Log verbose error messages"));
            root.AddOption(new Option <bool>(new string[] { "--random" }, Parsers.ParseBool, true, "Run requests randomly (requires --run-loop)"));
            root.AddOption(new Option <int>(new string[] { "--duration" }, Parsers.ParseIntGTZero, true, "Test duration (seconds)  (requires --run-loop)"));
            root.AddOption(new Option <int>(new string[] { "--summary-minutes" }, Parsers.ParseIntGTZero, true, "Display summary results (minutes)  (requires --run-loop)"));
            root.AddOption(new Option <int>(new string[] { "-t", "--timeout" }, Parsers.ParseIntGTZero, true, "Request timeout (seconds)"));
            root.AddOption(new Option <int>(new string[] { "--max-concurrent" }, Parsers.ParseIntGTZero, true, "Max concurrent requests"));
            root.AddOption(new Option <int>(new string[] { "--max-errors" }, Parsers.ParseIntGTZero, true, "Max validation errors"));
            root.AddOption(new Option <int>(new string[] { "--delay-start" }, Parsers.ParseIntGTZero, true, "Delay test start (seconds)"));
            root.AddOption(new Option <bool>(new string[] { "-d", "--dry-run" }, "Validates configuration"));

            // these require access to --run-loop so are added at the root level
            root.AddValidator(ValidateRunLoopDependencies);

            return(root);
        }
Beispiel #10
0
        public static Parser Create(
            IServiceCollection services,
            StartServer startServer             = null,
            Jupyter jupyter                     = null,
            StartKernelServer startKernelServer = null,
            ITelemetry telemetry                = null,
            IFirstTimeUseNoticeSentinel firstTimeUseNoticeSentinel = null)
        {
            if (services == null)
            {
                throw new ArgumentNullException(nameof(services));
            }

            startServer ??= (startupOptions, invocationContext) =>
            Program.ConstructWebHost(startupOptions).Run();

            jupyter ??= JupyterCommand.Do;

            startKernelServer ??= async(startupOptions, kernel, console) =>
            {
                var disposable = Program.StartToolLogging(startupOptions);

                if (kernel is KernelBase kernelBase)
                {
                    kernelBase.RegisterForDisposal(disposable);
                }

                var server = new StandardIOKernelServer(
                    kernel,
                    Console.In,
                    Console.Out);

                await server.Input.LastAsync();
            };

            // Setup first time use notice sentinel.
            firstTimeUseNoticeSentinel ??= new FirstTimeUseNoticeSentinel(VersionSensor.Version().AssemblyInformationalVersion);

            // Setup telemetry.
            telemetry ??= new Telemetry.Telemetry(
                VersionSensor.Version().AssemblyInformationalVersion,
                firstTimeUseNoticeSentinel);
            var filter = new TelemetryFilter(Sha256Hasher.HashWithNormalizedCasing);

            var verboseOption = new Option <bool>(
                "--verbose",
                "Enable verbose logging to the console");

            var httpPortOption = new Option <int>(
                "--http-port",
                "Specifies the port on which to enable HTTP services");

            var httpPortRangeOption = new Option <PortRange>(
                "--http-port-range",
                parseArgument: result =>
            {
                if (result.Parent.Parent.Children.FirstOrDefault(c => c.Symbol == httpPortOption) is OptionResult conflictingOption)
                {
                    var parsed          = result.Parent as OptionResult;
                    result.ErrorMessage = $"Cannot specify both {conflictingOption.Token.Value} and {parsed.Token.Value} together";
                    return(null);
                }

                var source = result.Tokens[0].Value;

                if (string.IsNullOrWhiteSpace(source))
                {
                    result.ErrorMessage = "Must specify a port range";
                    return(null);
                }

                var parts = source.Split(new[] { "-" }, StringSplitOptions.RemoveEmptyEntries);

                if (parts.Length != 2)
                {
                    result.ErrorMessage = "Must specify a port range";
                    return(null);
                }

                if (!int.TryParse(parts[0], out var start) || !int.TryParse(parts[1], out var end))
                {
                    result.ErrorMessage = "Must specify a port range as StartPort-EndPort";

                    return(null);
                }

                if (start > end)
                {
                    result.ErrorMessage = "Start port must be lower then end port";
                    return(null);
                }

                var pr = new PortRange(start, end);

                return(pr);
            },
                description: "Specifies the range of port to use to enable HTTP services");

            var logPathOption = new Option <DirectoryInfo>(
                "--log-path",
                "Enable file logging to the specified directory");

            var defaultKernelOption = new Option <string>(
                "--default-kernel",
                description: "The default language for the kernel",
                getDefaultValue: () => "csharp");

            var rootCommand = DotnetInteractive();

            rootCommand.AddCommand(Jupyter());
            rootCommand.AddCommand(KernelServer());
            rootCommand.AddCommand(HttpServer());

            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.Telemetry.SkipFirstTimeExperience)
                {
                    context.Console.Out.WriteLine();
                    context.Console.Out.WriteLine(Telemetry.Telemetry.WelcomeMessage);

                    firstTimeUseNoticeSentinel.CreateIfNotExists();
                }

                await next(context);
            })
                   .Build());

            RootCommand DotnetInteractive()
            {
                var command = new RootCommand
                {
                    Name        = "dotnet-interactive",
                    Description = "Interactive programming for .NET."
                };

                command.AddOption(logPathOption);
                command.AddOption(verboseOption);
                command.AddOption(httpPortOption);

                return(command);
            }

            Command Jupyter()
            {
                var jupyterCommand = new Command("jupyter", "Starts dotnet-interactive as a Jupyter kernel")
                {
                    defaultKernelOption,
                    logPathOption,
                    verboseOption,
                    httpPortOption,
                    httpPortRangeOption,
                    new Argument <FileInfo>
                    {
                        Name = "connection-file"
                    }.ExistingOnly()
                };

                jupyterCommand.Handler = CommandHandler.Create <StartupOptions, JupyterOptions, IConsole, InvocationContext>(JupyterHandler);

                var installCommand = new Command("install", "Install the .NET kernel for Jupyter")
                {
                    logPathOption,
                    verboseOption,
                    httpPortRangeOption
                };

                installCommand.Handler = CommandHandler.Create <IConsole, InvocationContext, PortRange>(InstallHandler);

                jupyterCommand.AddCommand(installCommand);

                return(jupyterCommand);

                Task <int> JupyterHandler(StartupOptions startupOptions, JupyterOptions options, IConsole console, InvocationContext context)
                {
                    services.AddSingleton(c => ConnectionInformation.Load(options.ConnectionFile))
                    .AddSingleton(_ =>
                    {
                        var frontendEnvironment = new BrowserFrontendEnvironment
                        {
                            ApiUri = new Uri($"http://localhost:{startupOptions.HttpPort}")
                        };
                        return(frontendEnvironment);
                    })
                    .AddSingleton <FrontendEnvironment>(c => c.GetService <BrowserFrontendEnvironment>())
                    .AddSingleton(c =>
                    {
                        return(CommandScheduler.Create <JupyterRequestContext>(delivery => c.GetRequiredService <ICommandHandler <JupyterRequestContext> >()
                                                                               .Trace()
                                                                               .Handle(delivery)));
                    })
                    .AddSingleton(c =>
                    {
                        var frontendEnvironment = c.GetRequiredService <BrowserFrontendEnvironment>();

                        var kernel = CreateKernel(options.DefaultKernel,
                                                  frontendEnvironment,
                                                  startupOptions,
                                                  c.GetRequiredService <HttpProbingSettings>());
                        return(kernel);
                    })
                    .AddSingleton(c => new JupyterRequestContextHandler(
                                      c.GetRequiredService <IKernel>())
                                  .Trace())
                    .AddSingleton <IHostedService, Shell>()
                    .AddSingleton <IHostedService, Heartbeat>()
                    ;

                    return(jupyter(startupOptions, console, startServer, context));
                }

                Task <int> InstallHandler(IConsole console, InvocationContext context, PortRange httpPortRange) =>
                new JupyterInstallCommand(console, new JupyterKernelSpec(), httpPortRange).InvokeAsync();
            }

            Command HttpServer()
            {
                var startKernelHttpCommand = new Command("http", "Starts dotnet-interactive with kernel functionality exposed over http")
                {
                    defaultKernelOption,
                    httpPortOption,
                    logPathOption,
                    httpPortRangeOption
                };

                startKernelHttpCommand.Handler = CommandHandler.Create <StartupOptions, KernelHttpOptions, IConsole, InvocationContext>(
                    (startupOptions, options, console, context) =>
                {
                    var frontendEnvironment = new BrowserFrontendEnvironment();
                    services
                    .AddSingleton(_ => frontendEnvironment)
                    .AddSingleton(c => CreateKernel(options.DefaultKernel, frontendEnvironment, startupOptions, null));

                    return(jupyter(startupOptions, console, startServer, context));
                });

                return(startKernelHttpCommand);
            }

            Command KernelServer()
            {
                var startKernelServerCommand = new Command(
                    "stdio",
                    "Starts dotnet-interactive with kernel functionality exposed over standard I/O")
                {
                    defaultKernelOption,
                    logPathOption,
                };

                startKernelServerCommand.Handler = CommandHandler.Create <StartupOptions, KernelServerOptions, IConsole, InvocationContext>(
                    (startupOptions, options, console, context) => startKernelServer(
                        startupOptions,
                        CreateKernel(options.DefaultKernel,
                                     new BrowserFrontendEnvironment(), startupOptions, null), console));

                return(startKernelServerCommand);
            }
        }
        /// <summary>
        /// Leverages the System.CommandLine package to parse and validate arguments and build a command.
        /// </summary>
        static RootCommand CreateRouteTableCommand()
        {
            var command = new RootCommand();

            var regionOption = new Option(
                new string[] { "-r", "--region" },
                "Azure Region abbreviation.");

            regionOption.Argument = new Argument <string>();
            regionOption.Required = false;
            command.AddOption(regionOption);

            var tableOption = new Option(
                new string[] { "-t", "--table" },
                "Route Table resource name.");

            tableOption.Argument = new Argument <string>();
            tableOption.Required = false;
            command.AddOption(tableOption);

            var firewallOption = new Option(
                new string[] { "-f", "--firewall" },
                "IP Address of the Firewall.");

            firewallOption.Argument = new Argument <string>();
            firewallOption.Required = true;
            command.AddOption(firewallOption);

            var groupOption = new Option(
                new string[] { "-g", "--group" },
                "Azure Resource Group to create Route Table.");

            groupOption.Argument = new Argument <string>();
            groupOption.Required = true;
            command.AddOption(groupOption);

            var subscriptionOption = new Option(
                new string[] { "-s", "--subscription" },
                "Azure Subscription ID.");

            subscriptionOption.Argument = new Argument <string>();
            subscriptionOption.Required = false;
            command.AddOption(subscriptionOption);

            var vnetOption = new Option(
                new string[] { "-v", "--vnet" },
                "Azure vnet name");

            vnetOption.Argument = new Argument <string>();
            vnetOption.Required = true;
            command.AddOption(vnetOption);

            var subnetsOption = new Option(
                new string[] { "-n", "--subnets" },
                "1 or more Azure subnet names, separated by spaces.");

            subnetsOption.Argument = new Argument <string[]>();
            subnetsOption.Required = false;
            command.AddOption(subnetsOption);

            command.Handler =
                CommandHandler.Create <string, string, string, string, string, string, string[]>(CreateOrUpdateRouteTableAsync);

            return(command);
        }
Beispiel #12
0
        // Entrypoint.
        public static int Main(string[] args)
        {
            // *** PRELAUNCH CHECKS
            // Check that we are, in fact, running on Linux/WSL.
            if (!RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
            {
                Console.WriteLine("genie: not executing on the Linux platform - how did we get here?");
                return(EBADF);
            }

            if (geteuid() != 0)
            {
                Console.WriteLine("genie: must execute as root - has the setuid bit gone astray?");
                return(EPERM);
            }

            // *** PARSE COMMAND-LINE
            // Create options.
            Option optVerbose = new Option("--verbose",
                                           "Display verbose progress messages",
                                           new Argument <bool>(defaultValue: false));

            optVerbose.AddAlias("-v");

            // Add them to the root command.
            var rootCommand = new RootCommand();

            rootCommand.Description = "Handles transitions to the \"bottle\" namespace for systemd under WSL.";
            rootCommand.AddOption(optVerbose);
            rootCommand.Handler = CommandHandler.Create <bool>((Func <bool, int>)RootHandler);

            var cmdInitialize = new Command("--initialize");

            cmdInitialize.AddAlias("-i");
            cmdInitialize.Description = "Initialize the bottle (if necessary) only.";
            cmdInitialize.Handler     = CommandHandler.Create <bool>((Func <bool, int>)InitializeHandler);

            rootCommand.Add(cmdInitialize);

            var cmdShell = new Command("--shell");

            cmdShell.AddAlias("-s");
            cmdShell.Description = "Initialize the bottle (if necessary), and run a shell in it.";
            cmdShell.Handler     = CommandHandler.Create <bool>((Func <bool, int>)ShellHandler);

            rootCommand.Add(cmdShell);

            var argCmdLine = new Argument <string> ();

            argCmdLine.Description = "The command to execute within the bottle.";
            argCmdLine.Arity       = ArgumentArity.OneOrMore;

            var cmdExec = new Command("--command");

            cmdExec.AddAlias("-c");
            cmdExec.Argument    = argCmdLine;
            cmdExec.Description = "Initialize the bottle (if necessary), and run the specified command in it.";
            cmdExec.Handler     = CommandHandler.Create <bool, List <string> >((Func <bool, List <string>, int>)ExecHandler);

            rootCommand.Add(cmdExec);

            // Parse the arguments and invoke the handler.
            return(rootCommand.InvokeAsync(args).Result);
        }
Beispiel #13
0
    public static void Main(string[] args)
    {
        var cmd = new RootCommand();

        cmd.AddOption(new Option("-n", "Max number of requests to make concurrently.")
        {
            Argument = new Argument <int>("numWorkers", 1)
        });
        cmd.AddOption(new Option("-maxContentLength", "Max content length for request and response bodies.")
        {
            Argument = new Argument <int>("numBytes", 1000)
        });
        cmd.AddOption(new Option("-http", "HTTP version (1.1 or 2.0)")
        {
            Argument = new Argument <Version[]>("version", new[] { HttpVersion.Version20 })
        });
        cmd.AddOption(new Option("-connectionLifetime", "Max connection lifetime length (milliseconds).")
        {
            Argument = new Argument <int?>("connectionLifetime", null)
        });
        cmd.AddOption(new Option("-ops", "Indices of the operations to use")
        {
            Argument = new Argument <int[]>("space-delimited indices", null)
        });
        cmd.AddOption(new Option("-trace", "Enable Microsoft-System-Net-Http tracing.")
        {
            Argument = new Argument <string>("\"console\" or path")
        });
        cmd.AddOption(new Option("-aspnetlog", "Enable ASP.NET warning and error logging.")
        {
            Argument = new Argument <bool>("enable", false)
        });
        cmd.AddOption(new Option("-listOps", "List available options.")
        {
            Argument = new Argument <bool>("enable", false)
        });
        cmd.AddOption(new Option("-seed", "Seed for generating pseudo-random parameters for a given -n argument.")
        {
            Argument = new Argument <int?>("seed", null)
        });

        ParseResult cmdline = cmd.Parse(args);

        if (cmdline.Errors.Count > 0)
        {
            foreach (ParseError error in cmdline.Errors)
            {
                Console.WriteLine(error);
            }
            Console.WriteLine();
            new HelpBuilder(new SystemConsole()).Write(cmd);
            return;
        }

        Run(concurrentRequests: cmdline.ValueForOption <int>("-n"),
            maxContentLength: cmdline.ValueForOption <int>("-maxContentLength"),
            httpVersions: cmdline.ValueForOption <Version[]>("-http"),
            connectionLifetime: cmdline.ValueForOption <int?>("-connectionLifetime"),
            opIndices: cmdline.ValueForOption <int[]>("-ops"),
            logPath: cmdline.HasOption("-trace") ? cmdline.ValueForOption <string>("-trace") : null,
            aspnetLog: cmdline.ValueForOption <bool>("-aspnetlog"),
            listOps: cmdline.ValueForOption <bool>("-listOps"),
            seed: cmdline.ValueForOption <int?>("-seed") ?? new Random().Next());
    }
Beispiel #14
0
        public static async Task <int> Main(string[] args)
        {
            var rootCommand = new RootCommand();

            rootCommand.AddOption(new Option <string>(new string[] { "--client_type", nameof(ClientOptions.ClientType) }, () => "httpclient"));
            rootCommand.AddOption(new Option <string>(new string[] { "--server_host", nameof(ClientOptions.ServerHost) })
            {
                Required = true
            });
            rootCommand.AddOption(new Option <string>(new string[] { "--server_host_override", nameof(ClientOptions.ServerHostOverride) }));
            rootCommand.AddOption(new Option <int>(new string[] { "--server_port", nameof(ClientOptions.ServerPort) })
            {
                Required = true
            });
            rootCommand.AddOption(new Option <string>(new string[] { "--test_case", nameof(ClientOptions.TestCase) })
            {
                Required = true
            });
            rootCommand.AddOption(new Option <bool>(new string[] { "--use_tls", nameof(ClientOptions.UseTls) }));
            rootCommand.AddOption(new Option <bool>(new string[] { "--use_test_ca", nameof(ClientOptions.UseTestCa) }));
            rootCommand.AddOption(new Option <string>(new string[] { "--default_service_account", nameof(ClientOptions.DefaultServiceAccount) }));
            rootCommand.AddOption(new Option <string>(new string[] { "--oauth_scope", nameof(ClientOptions.OAuthScope) }));
            rootCommand.AddOption(new Option <string>(new string[] { "--service_account_key_file", nameof(ClientOptions.ServiceAccountKeyFile) }));
            rootCommand.AddOption(new Option <string>(new string[] { "--grpc_web_mode", nameof(ClientOptions.GrpcWebMode) }));

            rootCommand.Handler = CommandHandler.Create <ClientOptions>(async(options) =>
            {
                Console.WriteLine("Use TLS: " + options.UseTls);
                Console.WriteLine("Use Test CA: " + options.UseTestCa);
                Console.WriteLine("Client type: " + options.ClientType);
                Console.WriteLine("Server host: " + options.ServerHost);
                Console.WriteLine("Server port: " + options.ServerPort);

                var services = new ServiceCollection();
                services.AddLogging(configure =>
                {
                    configure.SetMinimumLevel(LogLevel.Trace);
                    configure.AddConsole(loggerOptions => loggerOptions.IncludeScopes = true);
                });

                using var serviceProvider = services.BuildServiceProvider();

                var interopClient = new InteropClient(options, serviceProvider.GetRequiredService <ILoggerFactory>());
                await interopClient.Run();
            });

            return(await rootCommand.InvokeAsync(args));
        }
        public static RootCommand RootCommand()
        {
            RootCommand command = new RootCommand();

            command.AddOption(new Option(new[] { "--in", "-i" }, "Input file(s) to dump. Expects them to by ReadyToRun images", new Argument <FileInfo[]>()));
            command.AddOption(new Option(new[] { "--out", "-o" }, "Output file path. Dumps everything to the specified file except for help message and exception messages", new Argument <FileInfo>()));
            command.AddOption(new Option(new[] { "--raw" }, "Dump the raw bytes of each section or runtime function", new Argument <bool>()));
            command.AddOption(new Option(new[] { "--header" }, "Dump R2R header", new Argument <bool>()));
            command.AddOption(new Option(new[] { "--disasm", "-d" }, "Show disassembly of methods or runtime functions", new Argument <bool>()));
            command.AddOption(new Option(new[] { "--naked" }, "Naked dump suppresses most compilation details like placement addresses", new Argument <bool>()));
            command.AddOption(new Option(new[] { "--hide-offsets", "--ho" }, "Hide offsets in naked disassembly", new Argument <bool>()));
            command.AddOption(new Option(new[] { "--query", "-q" }, "Query method by exact name, signature, row ID or token", new Argument <string[]>()));
            command.AddOption(new Option(new[] { "--keyword", "-k" }, "Search method by keyword", new Argument <string[]>()));
            command.AddOption(new Option(new[] { "--runtimefunction", "-f" }, "Get one runtime function by id or relative virtual address", new Argument <string[]>()));
            command.AddOption(new Option(new[] { "--section", "-s" }, "Get section by keyword", new Argument <string[]>()));
            command.AddOption(new Option(new[] { "--unwind" }, "Dump unwindInfo", new Argument <bool>()));
            command.AddOption(new Option(new[] { "--gc" }, "Dump gcInfo and slot table", new Argument <bool>()));
            command.AddOption(new Option(new[] { "--sectionContents", "--sc" }, "Dump section contents", new Argument <bool>()));
            command.AddOption(new Option(new[] { "--entrypoints", "-e" }, "Dump list of method / instance entrypoints in the R2R file", new Argument <bool>()));
            command.AddOption(new Option(new[] { "--normalize", "-n" }, "Normalize dump by sorting the various tables and methods (default = unsorted i.e. file order)", new Argument <bool>()));
            command.AddOption(new Option(new[] { "--hide-transitions", "--ht" }, "Don't include GC transitions in disassembly output", new Argument <bool>()));
            command.AddOption(new Option(new[] { "--verbose", "-v" }, "Dump disassembly, unwindInfo, gcInfo and sectionContents", new Argument <bool>()));
            command.AddOption(new Option(new[] { "--diff" }, "Compare two R2R images", new Argument <bool>()));
            command.AddOption(new Option(new[] { "--diff-hide-same-disasm" }, "In matching method diff dump, hide functions with identical disassembly", new Argument <bool>()));
            command.AddOption(new Option(new[] { "--reference", "-r" }, "Explicit reference assembly files", new Argument <FileInfo[]>()));
            command.AddOption(new Option(new[] { "--referencePath", "--rp" }, "Search paths for reference assemblies", new Argument <DirectoryInfo[]>()));
            command.AddOption(new Option(new[] { "--inlineSignatureBinary", "--isb" }, "Embed binary signature into its textual representation", new Argument <bool>()));
            command.AddOption(new Option(new[] { "--signatureBinary", "--sb" }, "Append signature binary to its textual representation", new Argument <bool>()));
            return(command);
        }
        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());
        }
Beispiel #17
0
        // Entrypoint.
        public static int Main(string[] args)
        {
            // *** PRELAUNCH CHECKS
            // Check that we are, in fact, running on Linux/WSL.
            if (!PlatformChecks.IsLinux)
            {
                Console.WriteLine("genie: not executing on the Linux platform - how did we get here?");
                return(EBADF);
            }

            if (PlatformChecks.IsWsl1)
            {
                Console.WriteLine("genie: systemd is not supported under WSL 1.");
                return(EPERM);
            }

            if (!PlatformChecks.IsWsl2)
            {
                Console.WriteLine("genie: not executing under WSL 2 - how did we get here?");
                return(EBADF);
            }

            if (!UidChecks.IsEffectivelyRoot)
            {
                Console.WriteLine("genie: must execute as root - has the setuid bit gone astray?");
                return(EPERM);
            }

            // Set up secure path, saving original if specified.

            if (Config.ClonePath)
            {
                originalPath = Environment.GetEnvironmentVariable("PATH");
            }
            else
            {
                // TODO: Should reference system drive by letter
                originalPath = @"/mnt/c/Windows/System32";
            }

            Environment.SetEnvironmentVariable("PATH", Config.SecurePath);

            // Stash original environment (specified variables only).
            clonedVariables = GenieConfig.DefaultVariables
                              .Union(from DictionaryEntry de in Environment.GetEnvironmentVariables()
                                     where Config.CloneEnv.Contains(de.Key)
                                     select $"{de.Key}={de.Value}")
                              .ToArray();

            // Store the name of the real user.
            // TODO: replace this with something less hilariously insecure
            realUserName = Environment.GetEnvironmentVariable("LOGNAME");

            // *** PARSE COMMAND-LINE
            // Create options.
            Option optVerbose = new Option <bool> ("--verbose",
                                                   getDefaultValue: () => false,
                                                   description: "Display verbose progress messages");

            optVerbose.AddAlias("-v");

            // Add them to the root command.
            var rootCommand = new RootCommand();

            rootCommand.Description = "Handles transitions to the \"bottle\" namespace for systemd under WSL.";
            rootCommand.AddOption(optVerbose);
            rootCommand.Handler = CommandHandler.Create <bool>((Func <bool, int>)RootHandler);

            var cmdInitialize = new Command("--initialize");

            cmdInitialize.AddAlias("-i");
            cmdInitialize.Description = "Initialize the bottle (if necessary) only.";
            cmdInitialize.Handler     = CommandHandler.Create <bool>((Func <bool, int>)InitializeHandler);

            rootCommand.Add(cmdInitialize);

            var cmdShell = new Command("--shell");

            cmdShell.AddAlias("-s");
            cmdShell.Description = "Initialize the bottle (if necessary), and run a shell in it.";
            cmdShell.Handler     = CommandHandler.Create <bool>((Func <bool, int>)ShellHandler);

            rootCommand.Add(cmdShell);

            var cmdLogin = new Command("--login");

            cmdLogin.AddAlias("-l");
            cmdLogin.Description = "Initialize the bottle (if necessary), and open a logon prompt in it.";
            cmdLogin.Handler     = CommandHandler.Create <bool>((Func <bool, int>)LoginHandler);

            rootCommand.Add(cmdLogin);

            var argCmdLine = new Argument <IEnumerable <string> > ("command");

            argCmdLine.Description = "The command to execute within the bottle.";
            argCmdLine.Arity       = ArgumentArity.OneOrMore;

            var cmdExec = new Command("--command");

            cmdExec.AddAlias("-c");
            cmdExec.AddArgument(argCmdLine);
            cmdExec.Description = "Initialize the bottle (if necessary), and run the specified command in it.";
            cmdExec.Handler     = CommandHandler.Create <bool, IEnumerable <string> >((Func <bool, IEnumerable <string>, int>)ExecHandler);

            rootCommand.Add(cmdExec);

            var cmdShutdown = new Command("--shutdown");

            cmdShutdown.AddAlias("-u");
            cmdShutdown.Description = "Shut down systemd and exit the bottle.";
            cmdShutdown.Handler     = CommandHandler.Create <bool>((Func <bool, int>)ShutdownHandler);

            rootCommand.Add(cmdShutdown);

            var cmdIsRunning = new Command("--is-running");

            cmdIsRunning.AddAlias("-r");
            cmdIsRunning.Description = "Check whether systemd is running in genie, or not.";
            cmdIsRunning.Handler     = CommandHandler.Create <bool>((Func <bool, int>)IsRunningHandler);

            rootCommand.Add(cmdIsRunning);

            var cmdIsInside = new Command("--is-in-bottle");

            cmdIsInside.AddAlias("-b");
            cmdIsInside.Description = "Check whether currently executing within the genie bottle, or not.";
            cmdIsInside.Handler     = CommandHandler.Create <bool>((Func <bool, int>)IsInsideHandler);

            rootCommand.Add(cmdIsInside);

            // Parse the arguments and invoke the handler.
            return(rootCommand.InvokeAsync(args).Result);
        }
Beispiel #18
0
        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);
        }