mirror of
https://github.com/caddyserver/caddy.git
synced 2024-12-27 06:03:48 +03:00
cmd: CLI improvements; add --validate to adapt command
This commit is contained in:
parent
5b36424cf0
commit
2c3657bb8a
2 changed files with 107 additions and 61 deletions
|
@ -351,10 +351,11 @@ func cmdAdaptConfig(fl Flags) (int, error) {
|
||||||
adaptCmdInputFlag := fl.String("config")
|
adaptCmdInputFlag := fl.String("config")
|
||||||
adaptCmdAdapterFlag := fl.String("adapter")
|
adaptCmdAdapterFlag := fl.String("adapter")
|
||||||
adaptCmdPrettyFlag := fl.Bool("pretty")
|
adaptCmdPrettyFlag := fl.Bool("pretty")
|
||||||
|
adaptCmdValidateFlag := fl.Bool("validate")
|
||||||
|
|
||||||
if adaptCmdAdapterFlag == "" || adaptCmdInputFlag == "" {
|
if adaptCmdAdapterFlag == "" || adaptCmdInputFlag == "" {
|
||||||
return caddy.ExitCodeFailedStartup,
|
return caddy.ExitCodeFailedStartup,
|
||||||
fmt.Errorf("usage: caddy adapt --adapter <name> --input <file>")
|
fmt.Errorf("--adapter and --config flags are required")
|
||||||
}
|
}
|
||||||
|
|
||||||
cfgAdapter := caddyconfig.GetAdapter(adaptCmdAdapterFlag)
|
cfgAdapter := caddyconfig.GetAdapter(adaptCmdAdapterFlag)
|
||||||
|
@ -391,6 +392,19 @@ func cmdAdaptConfig(fl Flags) (int, error) {
|
||||||
// print result to stdout
|
// print result to stdout
|
||||||
fmt.Println(string(adaptedConfig))
|
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
|
return caddy.ExitCodeSuccess, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -457,7 +471,8 @@ usage:
|
||||||
commands:
|
commands:
|
||||||
`
|
`
|
||||||
for _, cmd := range 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"
|
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])
|
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",
|
result := fmt.Sprintf("%s\n\nusage:\n caddy %s %s\n",
|
||||||
strings.TrimSpace(subcommand.Long),
|
helpText,
|
||||||
subcommand.Name,
|
subcommand.Name,
|
||||||
strings.TrimSpace(subcommand.Usage),
|
strings.TrimSpace(subcommand.Usage),
|
||||||
)
|
)
|
||||||
|
|
139
cmd/commands.go
139
cmd/commands.go
|
@ -19,29 +19,40 @@ import (
|
||||||
"regexp"
|
"regexp"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Command represents a subcommand. All fields
|
// Command represents a subcommand. Name, Func,
|
||||||
// are required to be set except for Flags if
|
// and Short are required.
|
||||||
// there are no flags and Usage if there are
|
|
||||||
// no flags or arguments.
|
|
||||||
type Command struct {
|
type Command struct {
|
||||||
|
// The name of the subcommand. Must conform to the
|
||||||
|
// format described by the RegisterCommand() godoc.
|
||||||
|
// Required.
|
||||||
Name string
|
Name string
|
||||||
|
|
||||||
// Run is a function that executes a subcommand.
|
// Run is a function that executes a subcommand using
|
||||||
// It returns an exit code and any associated error.
|
// the parsed flags. It returns an exit code and any
|
||||||
// Takes non-flag commandline arguments as args.
|
// associated error.
|
||||||
// Flag must be parsed before Run is executed.
|
// Required.
|
||||||
Func CommandFunc
|
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
|
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
|
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
|
Long string
|
||||||
|
|
||||||
// Flags is flagset for command.
|
// Flags is the flagset for command.
|
||||||
Flags *flag.FlagSet
|
Flags *flag.FlagSet
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,14 +65,15 @@ var commands = map[string]Command{
|
||||||
"start": {
|
"start": {
|
||||||
Name: "start",
|
Name: "start",
|
||||||
Func: cmdStart,
|
Func: cmdStart,
|
||||||
Usage: "[--config <path>] [--adapter <name>]",
|
Usage: "[--config <path> [[--adapter <name>]]",
|
||||||
Short: "Starts the Caddy process and returns after server has started.",
|
Short: "Starts the Caddy process in the background and then returns",
|
||||||
Long: `
|
Long: `
|
||||||
Starts the Caddy process, optionally bootstrapped with an initial
|
Starts the Caddy process, optionally bootstrapped with an initial config file.
|
||||||
config file. Blocks until server is successfully running (or fails to run),
|
This command unblocks after the server starts 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
|
On Windows, the spawned child process will remain attached to the terminal, so
|
||||||
details.`,
|
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 {
|
Flags: func() *flag.FlagSet {
|
||||||
fs := flag.NewFlagSet("start", flag.ExitOnError)
|
fs := flag.NewFlagSet("start", flag.ExitOnError)
|
||||||
fs.String("config", "", "Configuration file")
|
fs.String("config", "", "Configuration file")
|
||||||
|
@ -73,13 +85,12 @@ details.`,
|
||||||
"run": {
|
"run": {
|
||||||
Name: "run",
|
Name: "run",
|
||||||
Func: cmdRun,
|
Func: cmdRun,
|
||||||
Usage: "[--config <path>] [--adapter <name>] [--print-env]",
|
Usage: "[--config <path> [--adapter <name>]] [--environ]",
|
||||||
Short: `Starts the Caddy process and blocks indefinitely.`,
|
Short: `Starts the Caddy process and blocks indefinitely`,
|
||||||
Long: `
|
Long: `
|
||||||
Same as start, but blocks indefinitely; i.e. runs Caddy in "daemon" mode. On
|
Starts the Caddy process, optionally bootstrapped with an initial config file,
|
||||||
Windows, this is recommended over caddy start when running Caddy manually since
|
and blocks indefinitely until the server is stopped; i.e. runs Caddy in
|
||||||
it will be more obvious that Caddy is still running and bound to the terminal
|
"daemon" mode (foreground).
|
||||||
window.
|
|
||||||
|
|
||||||
If a config file is specified, it will be applied immediately after the process
|
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
|
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.
|
adaptation first, use the 'adapt' subcommand.
|
||||||
|
|
||||||
As a special case, if the current working directory has a file called
|
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
|
"Caddyfile" and the caddyfile config adapter is plugged in (default), then
|
||||||
file will be loaded and used to configure Caddy, even without any command line
|
that file will be loaded and used to configure Caddy, even without any command
|
||||||
flags.
|
line flags.
|
||||||
|
|
||||||
If --environ is specified, the environment as seen by the Caddy process will
|
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
|
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 {
|
Flags: func() *flag.FlagSet {
|
||||||
fs := flag.NewFlagSet("run", flag.ExitOnError)
|
fs := flag.NewFlagSet("run", flag.ExitOnError)
|
||||||
fs.String("config", "", "Configuration file")
|
fs.String("config", "", "Configuration file")
|
||||||
|
@ -111,26 +122,32 @@ not quit after printing.`,
|
||||||
Name: "stop",
|
Name: "stop",
|
||||||
Func: cmdStop,
|
Func: cmdStop,
|
||||||
Short: "Gracefully stops the running Caddy process",
|
Short: "Gracefully stops the running Caddy process",
|
||||||
Long: `Gracefully stops the running Caddy process. (Note: this will stop any process
|
Long: `
|
||||||
named the same as the executable.) On Windows, this stop is forceful and Caddy
|
Stops the running Caddy process as gracefully as possible.
|
||||||
will not have an opportunity to clean up any active locks; for a graceful
|
|
||||||
shutdown on Windows, use Ctrl+C or the /stop endpoint.`,
|
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": {
|
"reload": {
|
||||||
Name: "reload",
|
Name: "reload",
|
||||||
Func: cmdReload,
|
Func: cmdReload,
|
||||||
Usage: "--config <path> [--adapter <name>] [--address <interface>]",
|
Usage: "--config <path> [--adapter <name>] [--address <interface>]",
|
||||||
Short: "Gives the running Caddy instance a new configuration",
|
Short: "Changes the config of the running Caddy instance",
|
||||||
Long: `Gives the running Caddy instance a new configuration. This has the same effect
|
Long: `
|
||||||
as POSTing a document to the /load endpoint, but is convenient for simple
|
Gives the running Caddy instance a new configuration. This has the same effect
|
||||||
workflows revolving around config files. Since the admin endpoint is
|
as POSTing a document to the /load API endpoint, but is convenient for simple
|
||||||
configurable, the endpoint configuration is loaded from the --address flag if
|
workflows revolving around config files.
|
||||||
specified; otherwise it is loaded from the given config file; otherwise the
|
|
||||||
default is assumed.`,
|
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 {
|
Flags: func() *flag.FlagSet {
|
||||||
fs := flag.NewFlagSet("reload", flag.ExitOnError)
|
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("adapter", "", "Name of config adapter to apply")
|
||||||
fs.String("address", "", "Address of the administration listener, if different from config")
|
fs.String("address", "", "Address of the administration listener, if different from config")
|
||||||
return fs
|
return fs
|
||||||
|
@ -140,15 +157,14 @@ default is assumed.`,
|
||||||
"version": {
|
"version": {
|
||||||
Name: "version",
|
Name: "version",
|
||||||
Func: cmdVersion,
|
Func: cmdVersion,
|
||||||
Short: "Prints the version.",
|
Short: "Prints the version",
|
||||||
Long: `Prints the version.`,
|
|
||||||
},
|
},
|
||||||
|
|
||||||
"list-modules": {
|
"list-modules": {
|
||||||
Name: "list-modules",
|
Name: "list-modules",
|
||||||
Func: cmdListModules,
|
Func: cmdListModules,
|
||||||
Short: "List installed Caddy modules.",
|
Usage: "[--versions]",
|
||||||
Long: `List installed Caddy modules.`,
|
Short: "Lists the installed Caddy modules",
|
||||||
Flags: func() *flag.FlagSet {
|
Flags: func() *flag.FlagSet {
|
||||||
fs := flag.NewFlagSet("list-modules", flag.ExitOnError)
|
fs := flag.NewFlagSet("list-modules", flag.ExitOnError)
|
||||||
fs.Bool("versions", false, "Print version information")
|
fs.Bool("versions", false, "Print version information")
|
||||||
|
@ -159,24 +175,30 @@ default is assumed.`,
|
||||||
"environ": {
|
"environ": {
|
||||||
Name: "environ",
|
Name: "environ",
|
||||||
Func: cmdEnviron,
|
Func: cmdEnviron,
|
||||||
Short: "Prints the environment as seen by Caddy.",
|
Short: "Prints the environment",
|
||||||
Long: `Prints the environment as seen by Caddy.`,
|
|
||||||
},
|
},
|
||||||
|
|
||||||
"adapt": {
|
"adapt": {
|
||||||
Name: "adapt",
|
Name: "adapt",
|
||||||
Func: cmdAdaptConfig,
|
Func: cmdAdaptConfig,
|
||||||
Usage: "--config <path> --adapter <name> [--pretty]",
|
Usage: "--config <path> --adapter <name> [--pretty] [--validate]",
|
||||||
Short: "Adapts a configuration to Caddy's native JSON config structure",
|
Short: "Adapts a configuration to Caddy's native JSON",
|
||||||
Long: `
|
Long: `
|
||||||
Adapts a configuration to Caddy's native JSON config structure and writes the
|
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,
|
output to stdout, along with any warnings to stderr.
|
||||||
the output will be formatted with indentation for human readability.`,
|
|
||||||
|
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 {
|
Flags: func() *flag.FlagSet {
|
||||||
fs := flag.NewFlagSet("adapt", flag.ExitOnError)
|
fs := flag.NewFlagSet("adapt", flag.ExitOnError)
|
||||||
fs.String("config", "", "Configuration file to adapt")
|
fs.String("config", "", "Configuration file to adapt (required)")
|
||||||
fs.String("adapter", "", "Name of config adapter")
|
fs.String("adapter", "", "Name of config adapter (required)")
|
||||||
fs.Bool("pretty", false, "Format the output for human readability")
|
fs.Bool("pretty", false, "Format the output for human readability")
|
||||||
|
fs.Bool("validate", false, "Validate the output")
|
||||||
return fs
|
return fs
|
||||||
}(),
|
}(),
|
||||||
},
|
},
|
||||||
|
@ -185,10 +207,11 @@ the output will be formatted with indentation for human readability.`,
|
||||||
Name: "validate",
|
Name: "validate",
|
||||||
Func: cmdValidateConfig,
|
Func: cmdValidateConfig,
|
||||||
Usage: "--config <path> [--adapter <name>]",
|
Usage: "--config <path> [--adapter <name>]",
|
||||||
Short: "Tests whether a configuration file is valid.",
|
Short: "Tests whether a configuration file is valid",
|
||||||
Long: `
|
Long: `
|
||||||
Loads and provisions the provided config, but does not start
|
Loads and provisions the provided config, but does not start running it.
|
||||||
running it.`,
|
This reveals any errors with the configuration through the loading and
|
||||||
|
provisioning stages.`,
|
||||||
Flags: func() *flag.FlagSet {
|
Flags: func() *flag.FlagSet {
|
||||||
fs := flag.NewFlagSet("load", flag.ExitOnError)
|
fs := flag.NewFlagSet("load", flag.ExitOnError)
|
||||||
fs.String("config", "", "Input configuration file")
|
fs.String("config", "", "Input configuration file")
|
||||||
|
@ -208,7 +231,7 @@ func init() {
|
||||||
Name: "help",
|
Name: "help",
|
||||||
Func: cmdHelp,
|
Func: cmdHelp,
|
||||||
Usage: "<command>",
|
Usage: "<command>",
|
||||||
Short: "Shows help for a Caddy subcommand.",
|
Short: "Shows help for a Caddy subcommand",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue