isle/go/cmd/entrypoint/sub_cmd.go

127 lines
2.7 KiB
Go

package main
import (
"context"
"fmt"
"isle/daemon"
"isle/daemon/jsonrpc2"
"os"
"strings"
"dev.mediocregopher.com/mediocre-go-lib.git/mlog"
"github.com/spf13/pflag"
)
// subCmdCtx contains all information available to a subCmd's do method.
type subCmdCtx struct {
subCmd subCmd // the subCmd itself
args []string // command-line arguments, excluding the subCmd itself.
subCmdNames []string // names of subCmds so far, including this one
ctx context.Context
logger *mlog.Logger
daemonRCPClient jsonrpc2.Client
}
type subCmd struct {
name string
descr string
do func(subCmdCtx) error
}
func (ctx subCmdCtx) usagePrefix() string {
subCmdNamesStr := strings.Join(ctx.subCmdNames, " ")
if subCmdNamesStr != "" {
subCmdNamesStr += " "
}
return fmt.Sprintf("\nUSAGE: %s %s", os.Args[0], subCmdNamesStr)
}
func (ctx subCmdCtx) flagSet(withPassthrough bool) *pflag.FlagSet {
flags := pflag.NewFlagSet(ctx.subCmd.name, pflag.ExitOnError)
flags.Usage = func() {
var passthroughStr string
if withPassthrough {
passthroughStr = " [--] [args...]"
}
// TODO don't allow -h/--help flag to be set by sub-commands (or better,
// somehow check that a flag hasn't been set twice).
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)
}
return flags
}
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 {
fmt.Fprintf(os.Stderr, " %s\t%s\n", subCmd.name, subCmd.descr)
}
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 {
// TODO allow subCmd(s) in some cases
subCmdsMap[subCmd.name] = subCmd
}
subCmdName, args := args[0], args[1:]
subCmd, ok := subCmdsMap[subCmdName]
if !ok {
printUsageExit(subCmdName)
}
daemonRCPClient := jsonrpc2.NewUnixHTTPClient(
daemon.HTTPSocketPath(), daemonHTTPRPCPath,
)
err := subCmd.do(subCmdCtx{
subCmd: subCmd,
args: args,
subCmdNames: append(ctx.subCmdNames, subCmdName),
ctx: ctx.ctx,
logger: ctx.logger,
daemonRCPClient: daemonRCPClient,
})
if err != nil {
return err
}
return nil
}