isle/go/cmd/entrypoint/sub_cmd.go

124 lines
2.4 KiB
Go

package main
import (
"context"
"fmt"
"os"
"strings"
"github.com/mediocregopher/mediocre-go-lib/v2/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
}
type subCmd struct {
name string
descr string
checkLock bool
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...]"
}
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 {
subCmdsMap[subCmd.name] = subCmd
}
subCmdName, args := args[0], args[1:]
subCmd, ok := subCmdsMap[subCmdName]
if !ok {
printUsageExit(subCmdName)
}
if subCmd.checkLock {
if err := assertLock(); err != nil {
return fmt.Errorf("checking lock file: %w", err)
}
}
err := subCmd.do(subCmdCtx{
subCmd: subCmd,
args: args,
subCmdNames: append(ctx.subCmdNames, subCmdName),
ctx: ctx.ctx,
logger: ctx.logger,
})
if err != nil {
return err
}
return nil
}