@marcel91200 / caddy Mirror · read-only / commits / 2c3657bb
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: CLI improvements; add --validate to adapt command

Matthew Holt committed Oct 1, 2019 at 11:02 UTC 2c3657bb8a37ce9c644dc1889223e37ca9988148
2 files changed +107 -61
cmd/commandfuncs.go
+26 -3
@@ -351,10 +351,11 @@ func cmdAdaptConfig(fl Flags) (int, error) {
351 adaptCmdInputFlag := fl.String("config")
352 adaptCmdAdapterFlag := fl.String("adapter")
353 adaptCmdPrettyFlag := fl.Bool("pretty")
354 + adaptCmdValidateFlag := fl.Bool("validate")
355
356 if adaptCmdAdapterFlag == "" || adaptCmdInputFlag == "" {
357 return caddy.ExitCodeFailedStartup,
357 - fmt.Errorf("usage: caddy adapt --adapter <name> --input <file>")
358 + fmt.Errorf("--adapter and --config flags are required")
359 }
360
361 cfgAdapter := caddyconfig.GetAdapter(adaptCmdAdapterFlag)
@@ -391,6 +392,19 @@ func cmdAdaptConfig(fl Flags) (int, error) {
392 // print result to stdout
393 fmt.Println(string(adaptedConfig))
394
395 + // validate output if requested
396 + if adaptCmdValidateFlag {
397 + var cfg *caddy.Config
398 + err = json.Unmarshal(adaptedConfig, &cfg)
399 + if err != nil {
400 + return caddy.ExitCodeFailedStartup, fmt.Errorf("decoding config: %v", err)
401 + }
402 + err = caddy.Validate(cfg)
403 + if err != nil {
404 + return caddy.ExitCodeFailedStartup, fmt.Errorf("validation: %v", err)
405 + }
406 + }
407 +
408 return caddy.ExitCodeSuccess, nil
409 }
410
@@ -457,7 +471,8 @@ usage:
471 commands:
472 `
473 for _, cmd := range commands {
460 - s += fmt.Sprintf(" %-15s %s\n", cmd.Name, cmd.Short)
474 + short := strings.TrimSuffix(cmd.Short, ".")
475 + s += fmt.Sprintf(" %-15s %s\n", cmd.Name, short)
476 }
477
478 s += "\nUse 'caddy help <command>' for more information about a command.\n"
@@ -475,8 +490,16 @@ commands:
490 return caddy.ExitCodeFailedStartup, fmt.Errorf("unknown command: %s", args[0])
491 }
492
493 + helpText := strings.TrimSpace(subcommand.Long)
494 + if helpText == "" {
495 + helpText = subcommand.Short
496 + if !strings.HasSuffix(helpText, ".") {
497 + helpText += "."
498 + }
499 + }
500 +
501 result := fmt.Sprintf("%s\n\nusage:\n caddy %s %s\n",
479 - strings.TrimSpace(subcommand.Long),
502 + helpText,
503 subcommand.Name,
504 strings.TrimSpace(subcommand.Usage),
505 )
cmd/commands.go
+81 -58
@@ -19,29 +19,40 @@ import (
19 "regexp"
20 )
21
22 -// Command represents a subcommand. All fields
23 -// are required to be set except for Flags if
24 -// there are no flags and Usage if there are
25 -// no flags or arguments.
22 +// Command represents a subcommand. Name, Func,
23 +// and Short are required.
24 type Command struct {
25 + // The name of the subcommand. Must conform to the
26 + // format described by the RegisterCommand() godoc.
27 + // Required.
28 Name string
29
29 - // Run is a function that executes a subcommand.
30 - // It returns an exit code and any associated error.
31 - // Takes non-flag commandline arguments as args.
32 - // Flag must be parsed before Run is executed.
30 + // Run is a function that executes a subcommand using
31 + // the parsed flags. It returns an exit code and any
32 + // associated error.
33 + // Required.
34 Func CommandFunc
35
35 - // Usage is the one-line message explaining args, flags.
36 + // Usage is a brief message describing the syntax of
37 + // the subcommand's flags and args. Use [] to indicate
38 + // optional parameters and <> to enclose literal values
39 + // intended to be replaced by the user. Do not prefix
40 + // the string with "caddy" or the name of the command
41 + // since these will be prepended for you; only include
42 + // the actual parameters for this command.
43 Usage string
44
38 - // Short is the short description for command.
45 + // Short is a one-line message explaining what the
46 + // command does. Should not end with punctuation.
47 + // Required.
48 Short string
49
41 - // Long is the message for 'caddy help <command>'
50 + // Long is the full help text shown to the user.
51 + // Will be trimmed of whitespace on both ends before
52 + // being printed.
53 Long string
54
44 - // Flags is flagset for command.
55 + // Flags is the flagset for command.
56 Flags *flag.FlagSet
57 }
58
@@ -54,14 +65,15 @@ var commands = map[string]Command{
65 "start": {
66 Name: "start",
67 Func: cmdStart,
57 - Usage: "[--config <path>] [--adapter <name>]",
58 - Short: "Starts the Caddy process and returns after server has started.",
68 + Usage: "[--config <path> [[--adapter <name>]]",
69 + Short: "Starts the Caddy process in the background and then returns",
70 Long: `
60 -Starts the Caddy process, optionally bootstrapped with an initial
61 -config file. Blocks until server is successfully running (or fails to run),
62 -then returns. On Windows, the child process will remain attached to the
63 -terminal, so closing the window will forcefully stop Caddy. See run for more
64 -details.`,
71 +Starts the Caddy process, optionally bootstrapped with an initial config file.
72 +This command unblocks after the server starts running or fails to run.
73 +
74 +On Windows, the spawned child process will remain attached to the terminal, so
75 +closing the window will forcefully stop Caddy; to avoid forgetting this, try
76 +using 'caddy run' instead to keep it in the foreground.`,
77 Flags: func() *flag.FlagSet {
78 fs := flag.NewFlagSet("start", flag.ExitOnError)
79 fs.String("config", "", "Configuration file")
@@ -73,13 +85,12 @@ details.`,
85 "run": {
86 Name: "run",
87 Func: cmdRun,
76 - Usage: "[--config <path>] [--adapter <name>] [--print-env]",
77 - Short: `Starts the Caddy process and blocks indefinitely.`,
88 + Usage: "[--config <path> [--adapter <name>]] [--environ]",
89 + Short: `Starts the Caddy process and blocks indefinitely`,
90 Long: `
79 -Same as start, but blocks indefinitely; i.e. runs Caddy in "daemon" mode. On
80 -Windows, this is recommended over caddy start when running Caddy manually since
81 -it will be more obvious that Caddy is still running and bound to the terminal
82 -window.
91 +Starts the Caddy process, optionally bootstrapped with an initial config file,
92 +and blocks indefinitely until the server is stopped; i.e. runs Caddy in
93 +"daemon" mode (foreground).
94
95 If a config file is specified, it will be applied immediately after the process
96 is running. If the config file is not in Caddy's native JSON format, you can
@@ -90,13 +101,13 @@ errors will immediately be used. If you want to review the results of the
101 adaptation first, use the 'adapt' subcommand.
102
103 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.
104 +"Caddyfile" and the caddyfile config adapter is plugged in (default), then
105 +that file will be loaded and used to configure Caddy, even without any command
106 +line flags.
107
108 If --environ is specified, the environment as seen by the Caddy process will
109 be printed before starting. This is the same as the environ command but does
99 -not quit after printing.`,
110 +not quit after printing, and can be useful for troubleshooting.`,
111 Flags: func() *flag.FlagSet {
112 fs := flag.NewFlagSet("run", flag.ExitOnError)
113 fs.String("config", "", "Configuration file")
@@ -111,26 +122,32 @@ not quit after printing.`,
122 Name: "stop",
123 Func: cmdStop,
124 Short: "Gracefully stops the running Caddy process",
114 - Long: `Gracefully stops the running Caddy process. (Note: this will stop any process
115 -named the same as the executable.) On Windows, this stop is forceful and Caddy
116 -will not have an opportunity to clean up any active locks; for a graceful
117 -shutdown on Windows, use Ctrl+C or the /stop endpoint.`,
125 + Long: `
126 +Stops the running Caddy process as gracefully as possible.
127 +
128 +On Windows, this stop is forceful and Caddy will not have an opportunity to
129 +clean up any active locks; for a graceful shutdown on Windows, use Ctrl+C
130 +or the /stop API endpoint.
131 +
132 +Note: this will stop any process named the same as the executable (os.Args[0]).`,
133 },
134
135 "reload": {
136 Name: "reload",
137 Func: cmdReload,
138 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
127 -workflows revolving around config files. Since the admin endpoint is
128 -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.`,
139 + Short: "Changes the config of the running Caddy instance",
140 + Long: `
141 +Gives the running Caddy instance a new configuration. This has the same effect
142 +as POSTing a document to the /load API endpoint, but is convenient for simple
143 +workflows revolving around config files.
144 +
145 +Since the admin endpoint is configurable, the endpoint configuration is loaded
146 +from the --address flag if specified; otherwise it is loaded from the given
147 +config file; otherwise the default is assumed.`,
148 Flags: func() *flag.FlagSet {
149 fs := flag.NewFlagSet("reload", flag.ExitOnError)
133 - fs.String("config", "", "Configuration file")
150 + fs.String("config", "", "Configuration file (required)")
151 fs.String("adapter", "", "Name of config adapter to apply")
152 fs.String("address", "", "Address of the administration listener, if different from config")
153 return fs
@@ -140,15 +157,14 @@ default is assumed.`,
157 "version": {
158 Name: "version",
159 Func: cmdVersion,
143 - Short: "Prints the version.",
144 - Long: `Prints the version.`,
160 + Short: "Prints the version",
161 },
162
163 "list-modules": {
164 Name: "list-modules",
165 Func: cmdListModules,
150 - Short: "List installed Caddy modules.",
151 - Long: `List installed Caddy modules.`,
166 + Usage: "[--versions]",
167 + Short: "Lists the installed Caddy modules",
168 Flags: func() *flag.FlagSet {
169 fs := flag.NewFlagSet("list-modules", flag.ExitOnError)
170 fs.Bool("versions", false, "Print version information")
@@ -159,24 +175,30 @@ default is assumed.`,
175 "environ": {
176 Name: "environ",
177 Func: cmdEnviron,
162 - Short: "Prints the environment as seen by Caddy.",
163 - Long: `Prints the environment as seen by Caddy.`,
178 + Short: "Prints the environment",
179 },
180
181 "adapt": {
182 Name: "adapt",
183 Func: cmdAdaptConfig,
169 - Usage: "--config <path> --adapter <name> [--pretty]",
170 - Short: "Adapts a configuration to Caddy's native JSON config structure",
184 + Usage: "--config <path> --adapter <name> [--pretty] [--validate]",
185 + Short: "Adapts a configuration to Caddy's native JSON",
186 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.`,
187 +Adapts a configuration to Caddy's native JSON format and writes the
188 +output to stdout, along with any warnings to stderr.
189 +
190 +If --pretty is specified, the output will be formatted with indentation
191 +for human readability.
192 +
193 +If --validate is used, the adapted config will be checked for validity.
194 +If the config is invalid, an error will be printed to stderr and a non-
195 +zero exit status will be returned.`,
196 Flags: func() *flag.FlagSet {
197 fs := flag.NewFlagSet("adapt", flag.ExitOnError)
177 - fs.String("config", "", "Configuration file to adapt")
178 - fs.String("adapter", "", "Name of config adapter")
198 + fs.String("config", "", "Configuration file to adapt (required)")
199 + fs.String("adapter", "", "Name of config adapter (required)")
200 fs.Bool("pretty", false, "Format the output for human readability")
201 + fs.Bool("validate", false, "Validate the output")
202 return fs
203 }(),
204 },
@@ -185,10 +207,11 @@ the output will be formatted with indentation for human readability.`,
207 Name: "validate",
208 Func: cmdValidateConfig,
209 Usage: "--config <path> [--adapter <name>]",
188 - Short: "Tests whether a configuration file is valid.",
210 + Short: "Tests whether a configuration file is valid",
211 Long: `
190 -Loads and provisions the provided config, but does not start
191 -running it.`,
212 +Loads and provisions the provided config, but does not start running it.
213 +This reveals any errors with the configuration through the loading and
214 +provisioning stages.`,
215 Flags: func() *flag.FlagSet {
216 fs := flag.NewFlagSet("load", flag.ExitOnError)
217 fs.String("config", "", "Input configuration file")
@@ -208,7 +231,7 @@ func init() {
231 Name: "help",
232 Func: cmdHelp,
233 Usage: "<command>",
211 - Short: "Shows help for a Caddy subcommand.",
234 + Short: "Shows help for a Caddy subcommand",
235 }
236 }
237