@marcel91200 / caddy Mirror · read-only / commits / 5b36424c
Fork 0

Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS

Mirrored from https://github.com/Slazee/caddy.git

Synced Nov 14, 05:15 UTC

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.

Matthew Holt committed Sep 30, 2019 at 23:43 UTC 5b36424cf056cc2063c708f0b68ba7cd68d23ac8
2 files changed +154 -24
cmd/commandfuncs.go
+112 -10
@@ -26,6 +26,8 @@ import (
26 "net/http"
27 "os"
28 "os/exec"
29 + "reflect"
30 + "runtime/debug"
31 "strings"
32
33 "github.com/caddyserver/caddy/v2"
@@ -36,7 +38,7 @@ import (
38
39 func cmdStart(fl Flags) (int, error) {
40 startCmdConfigFlag := fl.String("config")
39 - startCmdConfigAdapterFlag := fl.String("config-adapter")
41 + startCmdConfigAdapterFlag := fl.String("adapter")
42
43 // open a listener to which the child process will connect when
44 // it is ready to confirm that it has successfully started
@@ -61,7 +63,7 @@ func cmdStart(fl Flags) (int, error) {
63 cmd.Args = append(cmd.Args, "--config", startCmdConfigFlag)
64 }
65 if startCmdConfigAdapterFlag != "" {
64 - cmd.Args = append(cmd.Args, "--config-adapter", startCmdConfigAdapterFlag)
66 + cmd.Args = append(cmd.Args, "--adapter", startCmdConfigAdapterFlag)
67 }
68 stdinpipe, err := cmd.StdinPipe()
69 if err != nil {
@@ -137,8 +139,8 @@ func cmdStart(fl Flags) (int, error) {
139
140 func cmdRun(fl Flags) (int, error) {
141 runCmdConfigFlag := fl.String("config")
140 - runCmdConfigAdapterFlag := fl.String("config-adapter")
141 - runCmdPrintEnvFlag := fl.Bool("print-env")
142 + runCmdConfigAdapterFlag := fl.String("adapter")
143 + runCmdPrintEnvFlag := fl.Bool("environ")
144 runCmdPingbackFlag := fl.String("pingback")
145
146 // if we are supposed to print the environment, do that first
@@ -216,7 +218,7 @@ func cmdStop(_ Flags) (int, error) {
218
219 func cmdReload(fl Flags) (int, error) {
220 reloadCmdConfigFlag := fl.String("config")
219 - reloadCmdConfigAdapterFlag := fl.String("config-adapter")
221 + reloadCmdConfigAdapterFlag := fl.String("adapter")
222 reloadCmdAddrFlag := fl.String("address")
223
224 // a configuration is required
@@ -282,10 +284,61 @@ func cmdVersion(_ Flags) (int, error) {
284 return caddy.ExitCodeSuccess, nil
285 }
286
285 -func cmdListModules(_ Flags) (int, error) {
286 - for _, m := range caddy.Modules() {
287 - fmt.Println(m)
287 +func cmdListModules(fl Flags) (int, error) {
288 + versions := fl.Bool("versions")
289 +
290 + bi, ok := debug.ReadBuildInfo()
291 + if !ok || !versions {
292 + // if there's no build information,
293 + // just print out the modules
294 + for _, m := range caddy.Modules() {
295 + fmt.Println(m)
296 + }
297 + return caddy.ExitCodeSuccess, nil
298 + }
299 +
300 + for _, modName := range caddy.Modules() {
301 + modInfo, err := caddy.GetModule(modName)
302 + if err != nil {
303 + // that's weird
304 + fmt.Println(modName)
305 + continue
306 + }
307 +
308 + // to get the Caddy plugin's version info, we need to know
309 + // the package that the Caddy module's value comes from; we
310 + // can use reflection but we need a non-pointer value (I'm
311 + // not sure why), and since New() should return a pointer
312 + // value, we need to dereference it first
313 + iface := interface{}(modInfo.New())
314 + if rv := reflect.ValueOf(iface); rv.Kind() == reflect.Ptr {
315 + iface = reflect.New(reflect.TypeOf(iface).Elem()).Elem().Interface()
316 + }
317 + modPkgPath := reflect.TypeOf(iface).PkgPath()
318 +
319 + // now we find the Go module that the Caddy module's package
320 + // belongs to; we assume the Caddy module package path will
321 + // be prefixed by its Go module path, and we will choose the
322 + // longest matching prefix in case there are nested modules
323 + var matched *debug.Module
324 + for _, dep := range bi.Deps {
325 + if strings.HasPrefix(modPkgPath, dep.Path) {
326 + if matched == nil || len(dep.Path) > len(matched.Path) {
327 + matched = dep
328 + }
329 + }
330 + }
331 +
332 + // if we could find no matching module, just print out
333 + // the module name instead
334 + if matched == nil {
335 + fmt.Println(modName)
336 + continue
337 + }
338 +
339 + fmt.Printf("%s %s\n", modName, matched.Version)
340 }
341 +
342 return caddy.ExitCodeSuccess, nil
343 }
344
@@ -295,13 +348,13 @@ func cmdEnviron(_ Flags) (int, error) {
348 }
349
350 func cmdAdaptConfig(fl Flags) (int, error) {
351 + adaptCmdInputFlag := fl.String("config")
352 adaptCmdAdapterFlag := fl.String("adapter")
299 - adaptCmdInputFlag := fl.String("input")
353 adaptCmdPrettyFlag := fl.Bool("pretty")
354
355 if adaptCmdAdapterFlag == "" || adaptCmdInputFlag == "" {
356 return caddy.ExitCodeFailedStartup,
304 - fmt.Errorf("usage: caddy adapt-config --adapter <name> --input <file>")
357 + fmt.Errorf("usage: caddy adapt --adapter <name> --input <file>")
358 }
359
360 cfgAdapter := caddyconfig.GetAdapter(adaptCmdAdapterFlag)
@@ -341,6 +394,55 @@ func cmdAdaptConfig(fl Flags) (int, error) {
394 return caddy.ExitCodeSuccess, nil
395 }
396
397 +func cmdValidateConfig(fl Flags) (int, error) {
398 + validateCmdConfigFlag := fl.String("config")
399 + validateCmdAdapterFlag := fl.String("adapter")
400 +
401 + input, err := ioutil.ReadFile(validateCmdConfigFlag)
402 + if err != nil {
403 + return caddy.ExitCodeFailedStartup,
404 + fmt.Errorf("reading input file: %v", err)
405 + }
406 +
407 + if validateCmdAdapterFlag != "" {
408 + cfgAdapter := caddyconfig.GetAdapter(validateCmdAdapterFlag)
409 + if cfgAdapter == nil {
410 + return caddy.ExitCodeFailedStartup,
411 + fmt.Errorf("unrecognized config adapter: %s", validateCmdAdapterFlag)
412 + }
413 +
414 + adaptedConfig, warnings, err := cfgAdapter.Adapt(input, nil)
415 + if err != nil {
416 + return caddy.ExitCodeFailedStartup, err
417 + }
418 + // print warnings to stderr
419 + for _, warn := range warnings {
420 + msg := warn.Message
421 + if warn.Directive != "" {
422 + msg = fmt.Sprintf("%s: %s", warn.Directive, warn.Message)
423 + }
424 + log.Printf("[WARNING][%s] %s:%d: %s", validateCmdAdapterFlag, warn.File, warn.Line, msg)
425 + }
426 +
427 + input = adaptedConfig
428 + }
429 +
430 + var cfg *caddy.Config
431 + err = json.Unmarshal(input, &cfg)
432 + if err != nil {
433 + return caddy.ExitCodeFailedStartup, fmt.Errorf("decoding config: %v", err)
434 + }
435 +
436 + err = caddy.Validate(cfg)
437 + if err != nil {
438 + return caddy.ExitCodeFailedStartup, err
439 + }
440 +
441 + fmt.Println("Valid configuration")
442 +
443 + return caddy.ExitCodeSuccess, nil
444 +}
445 +
446 func cmdHelp(fl Flags) (int, error) {
447 const fullDocs = `Full documentation is available at:
448 https://github.com/caddyserver/caddy/wiki/v2:-Documentation`
cmd/commands.go
+42 -14
@@ -54,7 +54,7 @@ var commands = map[string]Command{
54 "start": {
55 Name: "start",
56 Func: cmdStart,
57 - Usage: "[--config <path>] [--config-adapter <name>]",
57 + Usage: "[--config <path>] [--adapter <name>]",
58 Short: "Starts the Caddy process and returns after server has started.",
59 Long: `
60 Starts the Caddy process, optionally bootstrapped with an initial
@@ -65,7 +65,7 @@ details.`,
65 Flags: func() *flag.FlagSet {
66 fs := flag.NewFlagSet("start", flag.ExitOnError)
67 fs.String("config", "", "Configuration file")
68 - fs.String("config-adapter", "", "Name of config adapter to apply")
68 + fs.String("adapter", "", "Name of config adapter to apply")
69 return fs
70 }(),
71 },
@@ -73,7 +73,7 @@ details.`,
73 "run": {
74 Name: "run",
75 Func: cmdRun,
76 - Usage: "[--config <path>] [--config-adapter <name>] [--print-env]",
76 + Usage: "[--config <path>] [--adapter <name>] [--print-env]",
77 Short: `Starts the Caddy process and blocks indefinitely.`,
78 Long: `
79 Same as start, but blocks indefinitely; i.e. runs Caddy in "daemon" mode. On
@@ -83,25 +83,25 @@ window.
83
84 If a config file is specified, it will be applied immediately after the process
85 is running. If the config file is not in Caddy's native JSON format, you can
86 -specify an adapter with --config-adapter to adapt the given config file to
86 +specify an adapter with --adapter to adapt the given config file to
87 Caddy's native format. The config adapter must be a registered module. Any
88 warnings will be printed to the log, but beware that any adaptation without
89 errors will immediately be used. If you want to review the results of the
90 -adaptation first, use adapt-config.
90 +adaptation first, use the 'adapt' subcommand.
91
92 As a special case, if the current working directory has a file called
93 "Caddyfile" and the caddyfile config adapter is plugged in (default), then that
94 file will be loaded and used to configure Caddy, even without any command line
95 flags.
96
97 -If --print-env is specified, the environment as seen by the Caddy process will
97 +If --environ is specified, the environment as seen by the Caddy process will
98 be printed before starting. This is the same as the environ command but does
99 not quit after printing.`,
100 Flags: func() *flag.FlagSet {
101 fs := flag.NewFlagSet("run", flag.ExitOnError)
102 fs.String("config", "", "Configuration file")
103 - fs.String("config-adapter", "", "Name of config adapter to apply")
104 - fs.Bool("print-env", false, "Print environment")
103 + fs.String("adapter", "", "Name of config adapter to apply")
104 + fs.Bool("environ", false, "Print environment")
105 fs.String("pingback", "", "Echo confirmation bytes to this address on success")
106 return fs
107 }(),
@@ -120,7 +120,7 @@ shutdown on Windows, use Ctrl+C or the /stop endpoint.`,
120 "reload": {
121 Name: "reload",
122 Func: cmdReload,
123 - Usage: "--config <path> [--config-adapter <name>] [--address <interface>]",
123 + Usage: "--config <path> [--adapter <name>] [--address <interface>]",
124 Short: "Gives the running Caddy instance a new configuration",
125 Long: `Gives the running Caddy instance a new configuration. This has the same effect
126 as POSTing a document to the /load endpoint, but is convenient for simple
@@ -129,9 +129,9 @@ configurable, the endpoint configuration is loaded from the --address flag if
129 specified; otherwise it is loaded from the given config file; otherwise the
130 default is assumed.`,
131 Flags: func() *flag.FlagSet {
132 - fs := flag.NewFlagSet("load", flag.ExitOnError)
132 + fs := flag.NewFlagSet("reload", flag.ExitOnError)
133 fs.String("config", "", "Configuration file")
134 - fs.String("config-adapter", "", "Name of config adapter to apply")
134 + fs.String("adapter", "", "Name of config adapter to apply")
135 fs.String("address", "", "Address of the administration listener, if different from config")
136 return fs
137 }(),
@@ -149,6 +149,11 @@ default is assumed.`,
149 Func: cmdListModules,
150 Short: "List installed Caddy modules.",
151 Long: `List installed Caddy modules.`,
152 + Flags: func() *flag.FlagSet {
153 + fs := flag.NewFlagSet("list-modules", flag.ExitOnError)
154 + fs.Bool("versions", false, "Print version information")
155 + return fs
156 + }(),
157 },
158
159 "environ": {
@@ -158,15 +163,38 @@ default is assumed.`,
163 Long: `Prints the environment as seen by Caddy.`,
164 },
165
161 - "adapt-config": {
162 - Name: "adapt-config",
166 + "adapt": {
167 + Name: "adapt",
168 Func: cmdAdaptConfig,
164 - Usage: "--input <path> --adapter <name> [--pretty]",
169 + Usage: "--config <path> --adapter <name> [--pretty]",
170 Short: "Adapts a configuration to Caddy's native JSON config structure",
171 Long: `
172 Adapts a configuration to Caddy's native JSON config structure and writes the
173 output to stdout, along with any warnings to stderr. If --pretty is specified,
174 the output will be formatted with indentation for human readability.`,
175 + Flags: func() *flag.FlagSet {
176 + fs := flag.NewFlagSet("adapt", flag.ExitOnError)
177 + fs.String("config", "", "Configuration file to adapt")
178 + fs.String("adapter", "", "Name of config adapter")
179 + fs.Bool("pretty", false, "Format the output for human readability")
180 + return fs
181 + }(),
182 + },
183 +
184 + "validate": {
185 + Name: "validate",
186 + Func: cmdValidateConfig,
187 + Usage: "--config <path> [--adapter <name>]",
188 + Short: "Tests whether a configuration file is valid.",
189 + Long: `
190 +Loads and provisions the provided config, but does not start
191 +running it.`,
192 + Flags: func() *flag.FlagSet {
193 + fs := flag.NewFlagSet("load", flag.ExitOnError)
194 + fs.String("config", "", "Input configuration file")
195 + fs.String("adapter", "", "Name of config adapter")
196 + return fs
197 + }(),
198 },
199 }
200