From 5b36424cf056cc2063c708f0b68ba7cd68d23ac8 Mon Sep 17 00:00:00 2001 From: Matthew Holt Date: Mon, 30 Sep 2019 23:43:39 -0600 Subject: cmd: Add validate subcommand; list-modules --versions; some renaming Renames --config-adapter flag to --adapter, adapt-config command to adapt, --print-env flag to --environ, and --input flag to --config. --- cmd/commandfuncs.go | 122 +++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 112 insertions(+), 10 deletions(-) (limited to 'cmd/commandfuncs.go') diff --git a/cmd/commandfuncs.go b/cmd/commandfuncs.go index be9da93..715f064 100644 --- a/cmd/commandfuncs.go +++ b/cmd/commandfuncs.go @@ -26,6 +26,8 @@ import ( "net/http" "os" "os/exec" + "reflect" + "runtime/debug" "strings" "github.com/caddyserver/caddy/v2" @@ -36,7 +38,7 @@ import ( func cmdStart(fl Flags) (int, error) { startCmdConfigFlag := fl.String("config") - startCmdConfigAdapterFlag := fl.String("config-adapter") + startCmdConfigAdapterFlag := fl.String("adapter") // open a listener to which the child process will connect when // it is ready to confirm that it has successfully started @@ -61,7 +63,7 @@ func cmdStart(fl Flags) (int, error) { cmd.Args = append(cmd.Args, "--config", startCmdConfigFlag) } if startCmdConfigAdapterFlag != "" { - cmd.Args = append(cmd.Args, "--config-adapter", startCmdConfigAdapterFlag) + cmd.Args = append(cmd.Args, "--adapter", startCmdConfigAdapterFlag) } stdinpipe, err := cmd.StdinPipe() if err != nil { @@ -137,8 +139,8 @@ func cmdStart(fl Flags) (int, error) { func cmdRun(fl Flags) (int, error) { runCmdConfigFlag := fl.String("config") - runCmdConfigAdapterFlag := fl.String("config-adapter") - runCmdPrintEnvFlag := fl.Bool("print-env") + runCmdConfigAdapterFlag := fl.String("adapter") + runCmdPrintEnvFlag := fl.Bool("environ") runCmdPingbackFlag := fl.String("pingback") // if we are supposed to print the environment, do that first @@ -216,7 +218,7 @@ func cmdStop(_ Flags) (int, error) { func cmdReload(fl Flags) (int, error) { reloadCmdConfigFlag := fl.String("config") - reloadCmdConfigAdapterFlag := fl.String("config-adapter") + reloadCmdConfigAdapterFlag := fl.String("adapter") reloadCmdAddrFlag := fl.String("address") // a configuration is required @@ -282,10 +284,61 @@ func cmdVersion(_ Flags) (int, error) { return caddy.ExitCodeSuccess, nil } -func cmdListModules(_ Flags) (int, error) { - for _, m := range caddy.Modules() { - fmt.Println(m) +func cmdListModules(fl Flags) (int, error) { + versions := fl.Bool("versions") + + bi, ok := debug.ReadBuildInfo() + if !ok || !versions { + // if there's no build information, + // just print out the modules + for _, m := range caddy.Modules() { + fmt.Println(m) + } + return caddy.ExitCodeSuccess, nil + } + + for _, modName := range caddy.Modules() { + modInfo, err := caddy.GetModule(modName) + if err != nil { + // that's weird + fmt.Println(modName) + continue + } + + // to get the Caddy plugin's version info, we need to know + // the package that the Caddy module's value comes from; we + // can use reflection but we need a non-pointer value (I'm + // not sure why), and since New() should return a pointer + // value, we need to dereference it first + iface := interface{}(modInfo.New()) + if rv := reflect.ValueOf(iface); rv.Kind() == reflect.Ptr { + iface = reflect.New(reflect.TypeOf(iface).Elem()).Elem().Interface() + } + modPkgPath := reflect.TypeOf(iface).PkgPath() + + // now we find the Go module that the Caddy module's package + // belongs to; we assume the Caddy module package path will + // be prefixed by its Go module path, and we will choose the + // longest matching prefix in case there are nested modules + var matched *debug.Module + for _, dep := range bi.Deps { + if strings.HasPrefix(modPkgPath, dep.Path) { + if matched == nil || len(dep.Path) > len(matched.Path) { + matched = dep + } + } + } + + // if we could find no matching module, just print out + // the module name instead + if matched == nil { + fmt.Println(modName) + continue + } + + fmt.Printf("%s %s\n", modName, matched.Version) } + return caddy.ExitCodeSuccess, nil } @@ -295,13 +348,13 @@ func cmdEnviron(_ Flags) (int, error) { } func cmdAdaptConfig(fl Flags) (int, error) { + adaptCmdInputFlag := fl.String("config") adaptCmdAdapterFlag := fl.String("adapter") - adaptCmdInputFlag := fl.String("input") adaptCmdPrettyFlag := fl.Bool("pretty") if adaptCmdAdapterFlag == "" || adaptCmdInputFlag == "" { return caddy.ExitCodeFailedStartup, - fmt.Errorf("usage: caddy adapt-config --adapter --input ") + fmt.Errorf("usage: caddy adapt --adapter --input ") } cfgAdapter := caddyconfig.GetAdapter(adaptCmdAdapterFlag) @@ -341,6 +394,55 @@ func cmdAdaptConfig(fl Flags) (int, error) { return caddy.ExitCodeSuccess, nil } +func cmdValidateConfig(fl Flags) (int, error) { + validateCmdConfigFlag := fl.String("config") + validateCmdAdapterFlag := fl.String("adapter") + + input, err := ioutil.ReadFile(validateCmdConfigFlag) + if err != nil { + return caddy.ExitCodeFailedStartup, + fmt.Errorf("reading input file: %v", err) + } + + if validateCmdAdapterFlag != "" { + cfgAdapter := caddyconfig.GetAdapter(validateCmdAdapterFlag) + if cfgAdapter == nil { + return caddy.ExitCodeFailedStartup, + fmt.Errorf("unrecognized config adapter: %s", validateCmdAdapterFlag) + } + + adaptedConfig, warnings, err := cfgAdapter.Adapt(input, nil) + if err != nil { + return caddy.ExitCodeFailedStartup, err + } + // print warnings to stderr + for _, warn := range warnings { + msg := warn.Message + if warn.Directive != "" { + msg = fmt.Sprintf("%s: %s", warn.Directive, warn.Message) + } + log.Printf("[WARNING][%s] %s:%d: %s", validateCmdAdapterFlag, warn.File, warn.Line, msg) + } + + input = adaptedConfig + } + + var cfg *caddy.Config + err = json.Unmarshal(input, &cfg) + if err != nil { + return caddy.ExitCodeFailedStartup, fmt.Errorf("decoding config: %v", err) + } + + err = caddy.Validate(cfg) + if err != nil { + return caddy.ExitCodeFailedStartup, err + } + + fmt.Println("Valid configuration") + + return caddy.ExitCodeSuccess, nil +} + func cmdHelp(fl Flags) (int, error) { const fullDocs = `Full documentation is available at: https://github.com/caddyserver/caddy/wiki/v2:-Documentation` -- cgit v1.2.3