isle/go-workspace/src/cmd/entrypoint/sub_cmd.go
Brian Picciano 936ca8d48f Factor out garage-apply-layout-diff
The new code runs the equivalent functionality within the daemon go
code. It was required to make Env be immutable in order to prevent race
conditions (this really should have been done from the beginning
anyway).
2022-10-19 16:20:26 +02:00

122 lines
2.4 KiB
Go

package entrypoint
import (
crypticnet "cryptic-net"
"fmt"
"os"
"strings"
"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
env crypticnet.Env
}
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 {
err := crypticnet.NewProcLock(ctx.env.RuntimeDirPath).AssertLock()
if err != nil {
return fmt.Errorf("checking lock file: %w", err)
}
}
err := subCmd.do(subCmdCtx{
subCmd: subCmd,
args: args,
subCmdNames: append(ctx.subCmdNames, subCmdName),
env: ctx.env,
})
if err != nil {
return err
}
return nil
}