2022-10-20 19:59:46 +00:00
|
|
|
package main
|
2021-04-20 21:31:37 +00:00
|
|
|
|
|
|
|
import (
|
2022-10-26 22:37:03 +00:00
|
|
|
"context"
|
2021-04-20 21:31:37 +00:00
|
|
|
"fmt"
|
2024-07-06 12:26:06 +00:00
|
|
|
"isle/daemon"
|
2024-06-23 12:37:10 +00:00
|
|
|
"isle/daemon/jsonrpc2"
|
2021-04-20 21:31:37 +00:00
|
|
|
"os"
|
|
|
|
"strings"
|
|
|
|
|
2024-06-22 15:49:56 +00:00
|
|
|
"dev.mediocregopher.com/mediocre-go-lib.git/mlog"
|
2021-04-20 21:31:37 +00:00
|
|
|
"github.com/spf13/pflag"
|
|
|
|
)
|
|
|
|
|
2024-07-22 14:37:22 +00:00
|
|
|
type flagSet struct {
|
|
|
|
*pflag.FlagSet
|
|
|
|
}
|
|
|
|
|
|
|
|
func (fs flagSet) Parse(args []string) error {
|
|
|
|
fs.VisitAll(func(f *pflag.Flag) {
|
|
|
|
if f.Shorthand == "h" {
|
|
|
|
panic(fmt.Sprintf("flag %+v has reserved shorthand `-h`", f))
|
|
|
|
}
|
|
|
|
if f.Name == "help" {
|
|
|
|
panic(fmt.Sprintf("flag %+v has reserved name `--help`", f))
|
|
|
|
}
|
|
|
|
})
|
|
|
|
return fs.FlagSet.Parse(args)
|
|
|
|
}
|
|
|
|
|
2021-04-20 21:31:37 +00:00
|
|
|
// subCmdCtx contains all information available to a subCmd's do method.
|
|
|
|
type subCmdCtx struct {
|
2024-09-04 20:35:29 +00:00
|
|
|
context.Context
|
|
|
|
|
2021-04-20 21:31:37 +00:00
|
|
|
subCmd subCmd // the subCmd itself
|
|
|
|
args []string // command-line arguments, excluding the subCmd itself.
|
|
|
|
subCmdNames []string // names of subCmds so far, including this one
|
2022-10-26 22:37:03 +00:00
|
|
|
|
2024-09-04 19:24:45 +00:00
|
|
|
logger *mlog.Logger
|
|
|
|
daemonRPC daemon.RPC
|
2021-04-20 21:31:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type subCmd struct {
|
2024-07-12 14:13:44 +00:00
|
|
|
name string
|
|
|
|
descr string
|
|
|
|
do func(subCmdCtx) error
|
2024-07-22 13:52:51 +00:00
|
|
|
|
|
|
|
// If set then the name will be allowed to be suffixed with this string.
|
|
|
|
plural string
|
2021-04-20 21:31:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (ctx subCmdCtx) usagePrefix() string {
|
|
|
|
|
|
|
|
subCmdNamesStr := strings.Join(ctx.subCmdNames, " ")
|
|
|
|
if subCmdNamesStr != "" {
|
|
|
|
subCmdNamesStr += " "
|
|
|
|
}
|
|
|
|
|
|
|
|
return fmt.Sprintf("\nUSAGE: %s %s", os.Args[0], subCmdNamesStr)
|
|
|
|
}
|
|
|
|
|
2024-07-22 14:37:22 +00:00
|
|
|
func (ctx subCmdCtx) flagSet(withPassthrough bool) flagSet {
|
2021-04-20 21:31:37 +00:00
|
|
|
flags := pflag.NewFlagSet(ctx.subCmd.name, pflag.ExitOnError)
|
|
|
|
flags.Usage = func() {
|
|
|
|
|
|
|
|
var passthroughStr string
|
|
|
|
if withPassthrough {
|
|
|
|
passthroughStr = " [--] [args...]"
|
|
|
|
}
|
|
|
|
|
|
|
|
fmt.Fprintf(
|
|
|
|
os.Stderr, "%s[-h|--help] [%s flags...]%s\n\n",
|
|
|
|
ctx.usagePrefix(), ctx.subCmd.name, passthroughStr,
|
|
|
|
)
|
|
|
|
fmt.Fprintf(os.Stderr, "%s FLAGS:\n\n", strings.ToUpper(ctx.subCmd.name))
|
|
|
|
fmt.Fprintln(os.Stderr, flags.FlagUsages())
|
|
|
|
|
|
|
|
os.Stderr.Sync()
|
|
|
|
os.Exit(2)
|
|
|
|
}
|
2024-07-22 14:37:22 +00:00
|
|
|
return flagSet{flags}
|
2021-04-20 21:31:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (ctx subCmdCtx) doSubCmd(subCmds ...subCmd) error {
|
|
|
|
|
|
|
|
printUsageExit := func(subCmdName string) {
|
|
|
|
|
|
|
|
fmt.Fprintf(os.Stderr, "unknown sub-command %q\n", subCmdName)
|
|
|
|
|
|
|
|
fmt.Fprintf(
|
|
|
|
os.Stderr,
|
|
|
|
"%s<subCmd> [-h|--help] [sub-command flags...]\n",
|
|
|
|
ctx.usagePrefix(),
|
|
|
|
)
|
|
|
|
|
|
|
|
fmt.Fprintf(os.Stderr, "\nSUB-COMMANDS:\n\n")
|
|
|
|
|
|
|
|
for _, subCmd := range subCmds {
|
2024-07-22 13:52:51 +00:00
|
|
|
name := subCmd.name
|
|
|
|
if subCmd.plural != "" {
|
|
|
|
name += "(" + subCmd.plural + ")"
|
|
|
|
}
|
|
|
|
fmt.Fprintf(os.Stderr, " %s\t%s\n", name, subCmd.descr)
|
2021-04-20 21:31:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fmt.Fprintf(os.Stderr, "\n")
|
|
|
|
os.Stderr.Sync()
|
|
|
|
os.Exit(2)
|
|
|
|
}
|
|
|
|
|
|
|
|
args := ctx.args
|
|
|
|
|
|
|
|
if len(args) == 0 {
|
|
|
|
printUsageExit("")
|
|
|
|
}
|
|
|
|
|
|
|
|
subCmdsMap := map[string]subCmd{}
|
|
|
|
for _, subCmd := range subCmds {
|
|
|
|
subCmdsMap[subCmd.name] = subCmd
|
2024-07-22 13:52:51 +00:00
|
|
|
if subCmd.plural != "" {
|
|
|
|
subCmdsMap[subCmd.name+subCmd.plural] = subCmd
|
|
|
|
}
|
2021-04-20 21:31:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
subCmdName, args := args[0], args[1:]
|
|
|
|
subCmd, ok := subCmdsMap[subCmdName]
|
|
|
|
|
|
|
|
if !ok {
|
|
|
|
printUsageExit(subCmdName)
|
|
|
|
}
|
|
|
|
|
2024-09-04 19:24:45 +00:00
|
|
|
daemonRPC := daemon.RPCFromClient(
|
|
|
|
jsonrpc2.NewUnixHTTPClient(daemon.HTTPSocketPath(), daemonHTTPRPCPath),
|
2024-06-23 12:37:10 +00:00
|
|
|
)
|
|
|
|
|
2021-04-20 21:31:37 +00:00
|
|
|
err := subCmd.do(subCmdCtx{
|
2024-09-04 20:35:29 +00:00
|
|
|
Context: ctx.Context,
|
2024-09-04 19:24:45 +00:00
|
|
|
subCmd: subCmd,
|
|
|
|
args: args,
|
|
|
|
subCmdNames: append(ctx.subCmdNames, subCmdName),
|
|
|
|
logger: ctx.logger,
|
|
|
|
daemonRPC: daemonRPC,
|
2021-04-20 21:31:37 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|