summaryrefslogtreecommitdiff
path: root/cmd/main.go
diff options
context:
space:
mode:
authoraca <acadx0@gmail.com>2019-10-01 12:23:58 +0900
committerMatt Holt <mholt@users.noreply.github.com>2019-09-30 21:23:58 -0600
commit0006df60264e7fdc55fc1a0962109e8198fa9d71 (patch)
treec85dc2eead63987288285d1426c097f820088a73 /cmd/main.go
parentc95db3551d79112513196b71841de8d010a42b25 (diff)
cmd: Refactor subcommands, add help, make them pluggable
* cli: Change command structure, add help subcommand (#328) * cli: improve subcommand structure - make help command as normal subcommand - add flag usage message for each command * cmd: Refactor subcommands and command line help; make commands pluggable
Diffstat (limited to 'cmd/main.go')
-rw-r--r--cmd/main.go130
1 files changed, 101 insertions, 29 deletions
diff --git a/cmd/main.go b/cmd/main.go
index 5b97992..aea020f 100644
--- a/cmd/main.go
+++ b/cmd/main.go
@@ -23,6 +23,9 @@ import (
"log"
"net"
"os"
+ "strconv"
+ "strings"
+ "time"
"github.com/caddyserver/caddy/v2"
"github.com/caddyserver/caddy/v2/caddyconfig"
@@ -33,45 +36,43 @@ import (
func Main() {
caddy.TrapSignals()
- if len(os.Args) < 2 {
- fmt.Println(usageString())
- return
+ switch len(os.Args) {
+ case 0:
+ log.Printf("[FATAL] no arguments provided by OS; args[0] must be command")
+ os.Exit(caddy.ExitCodeFailedStartup)
+ case 1:
+ os.Args = append(os.Args, "help")
}
- subcommand, ok := commands[os.Args[1]]
+ subcommandName := os.Args[1]
+ subcommand, ok := commands[subcommandName]
if !ok {
- fmt.Printf("%q is not a valid command\n", os.Args[1])
+ if strings.HasPrefix(os.Args[1], "-") {
+ // user probably forgot to type the subcommand
+ log.Println("[ERROR] first argument must be a subcommand; see 'caddy help'")
+ } else {
+ log.Printf("[ERROR] '%s' is not a recognized subcommand; see 'caddy help'", os.Args[1])
+ }
os.Exit(caddy.ExitCodeFailedStartup)
}
- if exitCode, err := subcommand(); err != nil {
+ fs := subcommand.Flags
+ if fs == nil {
+ fs = flag.NewFlagSet(subcommand.Name, flag.ExitOnError)
+ }
+
+ err := fs.Parse(os.Args[2:])
+ if err != nil {
log.Println(err)
- os.Exit(exitCode)
+ os.Exit(caddy.ExitCodeFailedStartup)
}
-}
-// commandFunc is a function that executes
-// a subcommand. It returns an exit code and
-// any associated error.
-type commandFunc func() (int, error)
-
-var commands = map[string]commandFunc{
- "start": cmdStart,
- "run": cmdRun,
- "stop": cmdStop,
- "reload": cmdReload,
- "version": cmdVersion,
- "list-modules": cmdListModules,
- "environ": cmdEnviron,
- "adapt-config": cmdAdaptConfig,
-}
+ exitCode, err := subcommand.Func(Flags{fs})
+ if err != nil {
+ log.Printf("%s: %v", subcommand.Name, err)
+ }
-func usageString() string {
- buf := new(bytes.Buffer)
- buf.WriteString("usage: caddy <command> [<args>]")
- flag.CommandLine.SetOutput(buf)
- flag.CommandLine.PrintDefaults()
- return buf.String()
+ os.Exit(exitCode)
}
// handlePingbackConn reads from conn and ensures it matches
@@ -156,3 +157,74 @@ func loadConfig(configFile, adapterName string) ([]byte, error) {
return config, nil
}
+
+// Flags wraps a FlagSet so that typed values
+// from flags can be easily retrieved.
+type Flags struct {
+ *flag.FlagSet
+}
+
+// String returns the string representation of the
+// flag given by name. It panics if the flag is not
+// in the flag set.
+func (f Flags) String(name string) string {
+ return f.FlagSet.Lookup(name).Value.String()
+}
+
+// Bool returns the boolean representation of the
+// flag given by name. It returns false if the flag
+// is not a boolean type. It panics if the flag is
+// not in the flag set.
+func (f Flags) Bool(name string) bool {
+ val, _ := strconv.ParseBool(f.String(name))
+ return val
+}
+
+// Int returns the integer representation of the
+// flag given by name. It returns 0 if the flag
+// is not an integer type. It panics if the flag is
+// not in the flag set.
+func (f Flags) Int(name string) int {
+ val, _ := strconv.ParseInt(f.String(name), 0, strconv.IntSize)
+ return int(val)
+}
+
+// Float64 returns the float64 representation of the
+// flag given by name. It returns false if the flag
+// is not a float63 type. It panics if the flag is
+// not in the flag set.
+func (f Flags) Float64(name string) float64 {
+ val, _ := strconv.ParseFloat(f.String(name), 64)
+ return val
+}
+
+// Duration returns the duration representation of the
+// flag given by name. It returns false if the flag
+// is not a duration type. It panics if the flag is
+// not in the flag set.
+func (f Flags) Duration(name string) time.Duration {
+ val, _ := time.ParseDuration(f.String(name))
+ return val
+}
+
+// flagHelp returns the help text for fs.
+func flagHelp(fs *flag.FlagSet) string {
+ if fs == nil {
+ return ""
+ }
+
+ // temporarily redirect output
+ out := fs.Output()
+ defer fs.SetOutput(out)
+
+ buf := new(bytes.Buffer)
+ fs.SetOutput(buf)
+ fs.PrintDefaults()
+ return buf.String()
+}
+
+func printEnvironment() {
+ for _, v := range os.Environ() {
+ fmt.Println(v)
+ }
+}