summaryrefslogtreecommitdiff
path: root/cmd
diff options
context:
space:
mode:
authorMatthew Holt <mholt@users.noreply.github.com>2019-10-01 11:02:13 -0600
committerMatthew Holt <mholt@users.noreply.github.com>2019-10-01 11:02:13 -0600
commit2c3657bb8a37ce9c644dc1889223e37ca9988148 (patch)
treec3b749791a4c928c230d540803741e38fbee0b23 /cmd
parent5b36424cf056cc2063c708f0b68ba7cd68d23ac8 (diff)
cmd: CLI improvements; add --validate to adapt command
Diffstat (limited to 'cmd')
-rw-r--r--cmd/commandfuncs.go29
-rw-r--r--cmd/commands.go139
2 files changed, 107 insertions, 61 deletions
diff --git a/cmd/commandfuncs.go b/cmd/commandfuncs.go
index 715f064..5fba368 100644
--- a/cmd/commandfuncs.go
+++ b/cmd/commandfuncs.go
@@ -351,10 +351,11 @@ func cmdAdaptConfig(fl Flags) (int, error) {
adaptCmdInputFlag := fl.String("config")
adaptCmdAdapterFlag := fl.String("adapter")
adaptCmdPrettyFlag := fl.Bool("pretty")
+ adaptCmdValidateFlag := fl.Bool("validate")
if adaptCmdAdapterFlag == "" || adaptCmdInputFlag == "" {
return caddy.ExitCodeFailedStartup,
- fmt.Errorf("usage: caddy adapt --adapter <name> --input <file>")
+ fmt.Errorf("--adapter and --config flags are required")
}
cfgAdapter := caddyconfig.GetAdapter(adaptCmdAdapterFlag)
@@ -391,6 +392,19 @@ func cmdAdaptConfig(fl Flags) (int, error) {
// print result to stdout
fmt.Println(string(adaptedConfig))
+ // validate output if requested
+ if adaptCmdValidateFlag {
+ var cfg *caddy.Config
+ err = json.Unmarshal(adaptedConfig, &cfg)
+ if err != nil {
+ return caddy.ExitCodeFailedStartup, fmt.Errorf("decoding config: %v", err)
+ }
+ err = caddy.Validate(cfg)
+ if err != nil {
+ return caddy.ExitCodeFailedStartup, fmt.Errorf("validation: %v", err)
+ }
+ }
+
return caddy.ExitCodeSuccess, nil
}
@@ -457,7 +471,8 @@ usage:
commands:
`
for _, cmd := range commands {
- s += fmt.Sprintf(" %-15s %s\n", cmd.Name, cmd.Short)
+ short := strings.TrimSuffix(cmd.Short, ".")
+ s += fmt.Sprintf(" %-15s %s\n", cmd.Name, short)
}
s += "\nUse 'caddy help <command>' for more information about a command.\n"
@@ -475,8 +490,16 @@ commands:
return caddy.ExitCodeFailedStartup, fmt.Errorf("unknown command: %s", args[0])
}
+ helpText := strings.TrimSpace(subcommand.Long)
+ if helpText == "" {
+ helpText = subcommand.Short
+ if !strings.HasSuffix(helpText, ".") {
+ helpText += "."
+ }
+ }
+
result := fmt.Sprintf("%s\n\nusage:\n caddy %s %s\n",
- strings.TrimSpace(subcommand.Long),
+ helpText,
subcommand.Name,
strings.TrimSpace(subcommand.Usage),
)
diff --git a/cmd/commands.go b/cmd/commands.go
index 731e813..7473053 100644
--- a/cmd/commands.go
+++ b/cmd/commands.go
@@ -19,29 +19,40 @@ import (
"regexp"
)
-// Command represents a subcommand. All fields
-// are required to be set except for Flags if
-// there are no flags and Usage if there are
-// no flags or arguments.
+// Command represents a subcommand. Name, Func,
+// and Short are required.
type Command struct {
+ // The name of the subcommand. Must conform to the
+ // format described by the RegisterCommand() godoc.
+ // Required.
Name string
- // Run is a function that executes a subcommand.
- // It returns an exit code and any associated error.
- // Takes non-flag commandline arguments as args.
- // Flag must be parsed before Run is executed.
+ // Run is a function that executes a subcommand using
+ // the parsed flags. It returns an exit code and any
+ // associated error.
+ // Required.
Func CommandFunc
- // Usage is the one-line message explaining args, flags.
+ // Usage is a brief message describing the syntax of
+ // the subcommand's flags and args. Use [] to indicate
+ // optional parameters and <> to enclose literal values
+ // intended to be replaced by the user. Do not prefix
+ // the string with "caddy" or the name of the command
+ // since these will be prepended for you; only include
+ // the actual parameters for this command.
Usage string
- // Short is the short description for command.
+ // Short is a one-line message explaining what the
+ // command does. Should not end with punctuation.
+ // Required.
Short string
- // Long is the message for 'caddy help <command>'
+ // Long is the full help text shown to the user.
+ // Will be trimmed of whitespace on both ends before
+ // being printed.
Long string
- // Flags is flagset for command.
+ // Flags is the flagset for command.
Flags *flag.FlagSet
}
@@ -54,14 +65,15 @@ var commands = map[string]Command{
"start": {
Name: "start",
Func: cmdStart,
- Usage: "[--config <path>] [--adapter <name>]",
- Short: "Starts the Caddy process and returns after server has started.",
+ Usage: "[--config <path> [[--adapter <name>]]",
+ Short: "Starts the Caddy process in the background and then returns",
Long: `
-Starts the Caddy process, optionally bootstrapped with an initial
-config file. Blocks until server is successfully running (or fails to run),
-then returns. On Windows, the child process will remain attached to the
-terminal, so closing the window will forcefully stop Caddy. See run for more
-details.`,
+Starts the Caddy process, optionally bootstrapped with an initial config file.
+This command unblocks after the server starts running or fails to run.
+
+On Windows, the spawned child process will remain attached to the terminal, so
+closing the window will forcefully stop Caddy; to avoid forgetting this, try
+using 'caddy run' instead to keep it in the foreground.`,
Flags: func() *flag.FlagSet {
fs := flag.NewFlagSet("start", flag.ExitOnError)
fs.String("config", "", "Configuration file")
@@ -73,13 +85,12 @@ details.`,
"run": {
Name: "run",
Func: cmdRun,
- Usage: "[--config <path>] [--adapter <name>] [--print-env]",
- Short: `Starts the Caddy process and blocks indefinitely.`,
+ Usage: "[--config <path> [--adapter <name>]] [--environ]",
+ Short: `Starts the Caddy process and blocks indefinitely`,
Long: `
-Same as start, but blocks indefinitely; i.e. runs Caddy in "daemon" mode. On
-Windows, this is recommended over caddy start when running Caddy manually since
-it will be more obvious that Caddy is still running and bound to the terminal
-window.
+Starts the Caddy process, optionally bootstrapped with an initial config file,
+and blocks indefinitely until the server is stopped; i.e. runs Caddy in
+"daemon" mode (foreground).
If a config file is specified, it will be applied immediately after the process
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
adaptation first, use the 'adapt' subcommand.
As a special case, if the current working directory has a file called
-"Caddyfile" and the caddyfile config adapter is plugged in (default), then that
-file will be loaded and used to configure Caddy, even without any command line
-flags.
+"Caddyfile" and the caddyfile config adapter is plugged in (default), then
+that file will be loaded and used to configure Caddy, even without any command
+line flags.
If --environ is specified, the environment as seen by the Caddy process will
be printed before starting. This is the same as the environ command but does
-not quit after printing.`,
+not quit after printing, and can be useful for troubleshooting.`,
Flags: func() *flag.FlagSet {
fs := flag.NewFlagSet("run", flag.ExitOnError)
fs.String("config", "", "Configuration file")
@@ -111,26 +122,32 @@ not quit after printing.`,
Name: "stop",
Func: cmdStop,
Short: "Gracefully stops the running Caddy process",
- Long: `Gracefully stops the running Caddy process. (Note: this will stop any process
-named the same as the executable.) On Windows, this stop is forceful and Caddy
-will not have an opportunity to clean up any active locks; for a graceful
-shutdown on Windows, use Ctrl+C or the /stop endpoint.`,
+ Long: `
+Stops the running Caddy process as gracefully as possible.
+
+On Windows, this stop is forceful and Caddy will not have an opportunity to
+clean up any active locks; for a graceful shutdown on Windows, use Ctrl+C
+or the /stop API endpoint.
+
+Note: this will stop any process named the same as the executable (os.Args[0]).`,
},
"reload": {
Name: "reload",
Func: cmdReload,
Usage: "--config <path> [--adapter <name>] [--address <interface>]",
- Short: "Gives the running Caddy instance a new configuration",
- Long: `Gives the running Caddy instance a new configuration. This has the same effect
-as POSTing a document to the /load endpoint, but is convenient for simple
-workflows revolving around config files. Since the admin endpoint is
-configurable, the endpoint configuration is loaded from the --address flag if
-specified; otherwise it is loaded from the given config file; otherwise the
-default is assumed.`,
+ Short: "Changes the config of the running Caddy instance",
+ Long: `
+Gives the running Caddy instance a new configuration. This has the same effect
+as POSTing a document to the /load API endpoint, but is convenient for simple
+workflows revolving around config files.
+
+Since the admin endpoint is configurable, the endpoint configuration is loaded
+from the --address flag if specified; otherwise it is loaded from the given
+config file; otherwise the default is assumed.`,
Flags: func() *flag.FlagSet {
fs := flag.NewFlagSet("reload", flag.ExitOnError)
- fs.String("config", "", "Configuration file")
+ fs.String("config", "", "Configuration file (required)")
fs.String("adapter", "", "Name of config adapter to apply")
fs.String("address", "", "Address of the administration listener, if different from config")
return fs
@@ -140,15 +157,14 @@ default is assumed.`,
"version": {
Name: "version",
Func: cmdVersion,
- Short: "Prints the version.",
- Long: `Prints the version.`,
+ Short: "Prints the version",
},
"list-modules": {
Name: "list-modules",
Func: cmdListModules,
- Short: "List installed Caddy modules.",
- Long: `List installed Caddy modules.`,
+ Usage: "[--versions]",
+ Short: "Lists the installed Caddy modules",
Flags: func() *flag.FlagSet {
fs := flag.NewFlagSet("list-modules", flag.ExitOnError)
fs.Bool("versions", false, "Print version information")
@@ -159,24 +175,30 @@ default is assumed.`,
"environ": {
Name: "environ",
Func: cmdEnviron,
- Short: "Prints the environment as seen by Caddy.",
- Long: `Prints the environment as seen by Caddy.`,
+ Short: "Prints the environment",
},
"adapt": {
Name: "adapt",
Func: cmdAdaptConfig,
- Usage: "--config <path> --adapter <name> [--pretty]",
- Short: "Adapts a configuration to Caddy's native JSON config structure",
+ Usage: "--config <path> --adapter <name> [--pretty] [--validate]",
+ Short: "Adapts a configuration to Caddy's native JSON",
Long: `
-Adapts a configuration to Caddy's native JSON config structure and writes the
-output to stdout, along with any warnings to stderr. If --pretty is specified,
-the output will be formatted with indentation for human readability.`,
+Adapts a configuration to Caddy's native JSON format and writes the
+output to stdout, along with any warnings to stderr.
+
+If --pretty is specified, the output will be formatted with indentation
+for human readability.
+
+If --validate is used, the adapted config will be checked for validity.
+If the config is invalid, an error will be printed to stderr and a non-
+zero exit status will be returned.`,
Flags: func() *flag.FlagSet {
fs := flag.NewFlagSet("adapt", flag.ExitOnError)
- fs.String("config", "", "Configuration file to adapt")
- fs.String("adapter", "", "Name of config adapter")
+ fs.String("config", "", "Configuration file to adapt (required)")
+ fs.String("adapter", "", "Name of config adapter (required)")
fs.Bool("pretty", false, "Format the output for human readability")
+ fs.Bool("validate", false, "Validate the output")
return fs
}(),
},
@@ -185,10 +207,11 @@ the output will be formatted with indentation for human readability.`,
Name: "validate",
Func: cmdValidateConfig,
Usage: "--config <path> [--adapter <name>]",
- Short: "Tests whether a configuration file is valid.",
+ Short: "Tests whether a configuration file is valid",
Long: `
-Loads and provisions the provided config, but does not start
-running it.`,
+Loads and provisions the provided config, but does not start running it.
+This reveals any errors with the configuration through the loading and
+provisioning stages.`,
Flags: func() *flag.FlagSet {
fs := flag.NewFlagSet("load", flag.ExitOnError)
fs.String("config", "", "Input configuration file")
@@ -208,7 +231,7 @@ func init() {
Name: "help",
Func: cmdHelp,
Usage: "<command>",
- Short: "Shows help for a Caddy subcommand.",
+ Short: "Shows help for a Caddy subcommand",
}
}