147 lines
3.3 KiB
Go
147 lines
3.3 KiB
Go
package launcher
|
|
|
|
import (
|
|
"fmt"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
type Command string
|
|
|
|
const (
|
|
CommandRun Command = "run"
|
|
CommandStart Command = "start"
|
|
)
|
|
|
|
type Options struct {
|
|
Command Command
|
|
BackendPort int
|
|
Verbose bool
|
|
Debug bool
|
|
ShowVersion bool
|
|
Headless bool
|
|
ShowHelp bool
|
|
}
|
|
|
|
type ParseError struct {
|
|
Message string
|
|
}
|
|
|
|
func (e ParseError) Error() string {
|
|
return e.Message
|
|
}
|
|
|
|
func parseArgs(argv []string) (Options, error) {
|
|
opts := Options{Command: CommandRun}
|
|
for i := 0; i < len(argv); i++ {
|
|
next, err := parseArgAt(argv, i, &opts)
|
|
if err != nil {
|
|
return opts, err
|
|
}
|
|
i = next
|
|
}
|
|
return opts, nil
|
|
}
|
|
|
|
func parseArgAt(argv []string, i int, opts *Options) (int, error) {
|
|
arg := argv[i]
|
|
if parseSimpleArg(arg, opts) {
|
|
return i, nil
|
|
}
|
|
if isRuntimeVersionArg(arg) {
|
|
return i, ParseError{Message: "--runtime-version is not supported by the native launcher"}
|
|
}
|
|
if next, ok, err := parsePortArg(argv, i, opts); ok || err != nil {
|
|
return next, err
|
|
}
|
|
return i, ParseError{Message: fmt.Sprintf("unknown argument %q", arg)}
|
|
}
|
|
|
|
func parseSimpleArg(arg string, opts *Options) bool {
|
|
return parseCommandArg(arg, opts) || parseBooleanFlag(arg, opts)
|
|
}
|
|
|
|
func parseCommandArg(arg string, opts *Options) bool {
|
|
switch arg {
|
|
case "run":
|
|
opts.Command = CommandRun
|
|
case string(CommandStart):
|
|
opts.Command = CommandStart
|
|
default:
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
func parseBooleanFlag(arg string, opts *Options) bool {
|
|
switch arg {
|
|
case "--help", "-h", "help":
|
|
opts.ShowHelp = true
|
|
case "--version", "-V":
|
|
opts.ShowVersion = true
|
|
case "--verbose", "-v":
|
|
opts.Verbose = true
|
|
case "--debug":
|
|
opts.Debug = true
|
|
case "--headless", "--no-browser":
|
|
opts.Headless = true
|
|
default:
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
func isRuntimeVersionArg(arg string) bool {
|
|
return arg == "--runtime-version" || strings.HasPrefix(arg, "--runtime-version=")
|
|
}
|
|
|
|
func parsePortArg(argv []string, i int, opts *Options) (int, bool, error) {
|
|
arg := argv[i]
|
|
switch {
|
|
case arg == "--port" || arg == "--backend-port":
|
|
next, err := parseBackendPort(argv, i, opts)
|
|
return next, true, err
|
|
case strings.HasPrefix(arg, "--port="):
|
|
return i, true, parseBackendPortValue("--port", strings.TrimPrefix(arg, "--port="), opts)
|
|
case strings.HasPrefix(arg, "--backend-port="):
|
|
return i, true, parseBackendPortValue("--backend-port", strings.TrimPrefix(arg, "--backend-port="), opts)
|
|
default:
|
|
return i, false, nil
|
|
}
|
|
}
|
|
|
|
func parseBackendPort(argv []string, i int, opts *Options) (int, error) {
|
|
v, err := takeValue(argv, i, argv[i])
|
|
if err != nil {
|
|
return i, err
|
|
}
|
|
if err := parseBackendPortValue(argv[i], v, opts); err != nil {
|
|
return i, err
|
|
}
|
|
return i + 1, nil
|
|
}
|
|
|
|
func parseBackendPortValue(flag, value string, opts *Options) error {
|
|
port, err := parsePort(value, flag)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
opts.BackendPort = port
|
|
return nil
|
|
}
|
|
|
|
func takeValue(argv []string, i int, flag string) (string, error) {
|
|
if i+1 >= len(argv) || strings.HasPrefix(argv[i+1], "-") {
|
|
return "", ParseError{Message: fmt.Sprintf("%s requires a value", flag)}
|
|
}
|
|
return argv[i+1], nil
|
|
}
|
|
|
|
func parsePort(raw, flag string) (int, error) {
|
|
n, err := strconv.Atoi(raw)
|
|
if raw == "" || err != nil || n < 1 || n > 65535 {
|
|
return 0, ParseError{Message: fmt.Sprintf("%s value must be an integer between 1 and 65535, got %q", flag, raw)}
|
|
}
|
|
return n, nil
|
|
}
|