aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authora <[email protected]>2024-08-21 22:29:42 -0500
committerGitHub <[email protected]>2024-08-22 03:29:42 +0000
commit8ccfedf2bb0a1759aa68d4989f05d9a52ba41a34 (patch)
tree52fce9ed7d21964da859ed70e436115690044eab
parent2bb2ecc5498c99d535f5b8f56fb8a4732e818ad3 (diff)
downloadcaddy-8ccfedf2bb0a1759aa68d4989f05d9a52ba41a34.tar.gz
caddy-8ccfedf2bb0a1759aa68d4989f05d9a52ba41a34.zip
cmd: Use a factory to create the caddy root command (#6533)
Co-authored-by: Francis Lavoie <[email protected]>
-rw-r--r--cmd/cobra.go26
-rw-r--r--cmd/commandfactory.go28
-rw-r--r--cmd/commands.go102
-rw-r--r--cmd/main.go2
4 files changed, 97 insertions, 61 deletions
diff --git a/cmd/cobra.go b/cmd/cobra.go
index 1a2509206..9ecb389e2 100644
--- a/cmd/cobra.go
+++ b/cmd/cobra.go
@@ -8,9 +8,10 @@ import (
"github.com/caddyserver/caddy/v2"
)
-var rootCmd = &cobra.Command{
- Use: "caddy",
- Long: `Caddy is an extensible server platform written in Go.
+var defaultFactory = newRootCommandFactory(func() *cobra.Command {
+ return &cobra.Command{
+ Use: "caddy",
+ Long: `Caddy is an extensible server platform written in Go.
At its core, Caddy merely manages configuration. Modules are plugged
in statically at compile-time to provide useful functionality. Caddy's
@@ -91,23 +92,26 @@ package installers: https://caddyserver.com/docs/install
Instructions for running Caddy in production are also available:
https://caddyserver.com/docs/running
`,
- Example: ` $ caddy run
+ Example: ` $ caddy run
$ caddy run --config caddy.json
$ caddy reload --config caddy.json
$ caddy stop`,
- // kind of annoying to have all the help text printed out if
- // caddy has an error provisioning its modules, for instance...
- SilenceUsage: true,
- Version: onlyVersionText(),
-}
+ // kind of annoying to have all the help text printed out if
+ // caddy has an error provisioning its modules, for instance...
+ SilenceUsage: true,
+ Version: onlyVersionText(),
+ }
+})
const fullDocsFooter = `Full documentation is available at:
https://caddyserver.com/docs/command-line`
func init() {
- rootCmd.SetVersionTemplate("{{.Version}}\n")
- rootCmd.SetHelpTemplate(rootCmd.HelpTemplate() + "\n" + fullDocsFooter + "\n")
+ defaultFactory.Use(func(rootCmd *cobra.Command) {
+ rootCmd.SetVersionTemplate("{{.Version}}\n")
+ rootCmd.SetHelpTemplate(rootCmd.HelpTemplate() + "\n" + fullDocsFooter + "\n")
+ })
}
func onlyVersionText() string {
diff --git a/cmd/commandfactory.go b/cmd/commandfactory.go
new file mode 100644
index 000000000..ac571a21a
--- /dev/null
+++ b/cmd/commandfactory.go
@@ -0,0 +1,28 @@
+package caddycmd
+
+import (
+ "github.com/spf13/cobra"
+)
+
+type rootCommandFactory struct {
+ constructor func() *cobra.Command
+ options []func(*cobra.Command)
+}
+
+func newRootCommandFactory(fn func() *cobra.Command) *rootCommandFactory {
+ return &rootCommandFactory{
+ constructor: fn,
+ }
+}
+
+func (f *rootCommandFactory) Use(fn func(cmd *cobra.Command)) {
+ f.options = append(f.options, fn)
+}
+
+func (f *rootCommandFactory) Build() *cobra.Command {
+ o := f.constructor()
+ for _, v := range f.options {
+ v(o)
+ }
+ return o
+}
diff --git a/cmd/commands.go b/cmd/commands.go
index e5e1265e4..0853ebf83 100644
--- a/cmd/commands.go
+++ b/cmd/commands.go
@@ -438,43 +438,44 @@ EXPERIMENTAL: May be changed or removed.
},
})
- RegisterCommand(Command{
- Name: "manpage",
- Usage: "--directory <path>",
- Short: "Generates the manual pages for Caddy commands",
- Long: `
+ defaultFactory.Use(func(rootCmd *cobra.Command) {
+ RegisterCommand(Command{
+ Name: "manpage",
+ Usage: "--directory <path>",
+ Short: "Generates the manual pages for Caddy commands",
+ Long: `
Generates the manual pages for Caddy commands into the designated directory
tagged into section 8 (System Administration).
The manual page files are generated into the directory specified by the
argument of --directory. If the directory does not exist, it will be created.
`,
- CobraFunc: func(cmd *cobra.Command) {
- cmd.Flags().StringP("directory", "o", "", "The output directory where the manpages are generated")
- cmd.RunE = WrapCommandFuncForCobra(func(fl Flags) (int, error) {
- dir := strings.TrimSpace(fl.String("directory"))
- if dir == "" {
- return caddy.ExitCodeFailedQuit, fmt.Errorf("designated output directory and specified section are required")
- }
- if err := os.MkdirAll(dir, 0o755); err != nil {
- return caddy.ExitCodeFailedQuit, err
- }
- if err := doc.GenManTree(rootCmd, &doc.GenManHeader{
- Title: "Caddy",
- Section: "8", // https://en.wikipedia.org/wiki/Man_page#Manual_sections
- }, dir); err != nil {
- return caddy.ExitCodeFailedQuit, err
- }
- return caddy.ExitCodeSuccess, nil
- })
- },
- })
-
- // source: https://github.com/spf13/cobra/blob/main/shell_completions.md
- rootCmd.AddCommand(&cobra.Command{
- Use: "completion [bash|zsh|fish|powershell]",
- Short: "Generate completion script",
- Long: fmt.Sprintf(`To load completions:
+ CobraFunc: func(cmd *cobra.Command) {
+ cmd.Flags().StringP("directory", "o", "", "The output directory where the manpages are generated")
+ cmd.RunE = WrapCommandFuncForCobra(func(fl Flags) (int, error) {
+ dir := strings.TrimSpace(fl.String("directory"))
+ if dir == "" {
+ return caddy.ExitCodeFailedQuit, fmt.Errorf("designated output directory and specified section are required")
+ }
+ if err := os.MkdirAll(dir, 0o755); err != nil {
+ return caddy.ExitCodeFailedQuit, err
+ }
+ if err := doc.GenManTree(rootCmd, &doc.GenManHeader{
+ Title: "Caddy",
+ Section: "8", // https://en.wikipedia.org/wiki/Man_page#Manual_sections
+ }, dir); err != nil {
+ return caddy.ExitCodeFailedQuit, err
+ }
+ return caddy.ExitCodeSuccess, nil
+ })
+ },
+ })
+
+ // source: https://github.com/spf13/cobra/blob/main/shell_completions.md
+ rootCmd.AddCommand(&cobra.Command{
+ Use: "completion [bash|zsh|fish|powershell]",
+ Short: "Generate completion script",
+ Long: fmt.Sprintf(`To load completions:
Bash:
@@ -513,23 +514,24 @@ argument of --directory. If the directory does not exist, it will be created.
PS> %[1]s completion powershell > %[1]s.ps1
# and source this file from your PowerShell profile.
`, rootCmd.Root().Name()),
- DisableFlagsInUseLine: true,
- ValidArgs: []string{"bash", "zsh", "fish", "powershell"},
- Args: cobra.MatchAll(cobra.ExactArgs(1), cobra.OnlyValidArgs),
- RunE: func(cmd *cobra.Command, args []string) error {
- switch args[0] {
- case "bash":
- return cmd.Root().GenBashCompletion(os.Stdout)
- case "zsh":
- return cmd.Root().GenZshCompletion(os.Stdout)
- case "fish":
- return cmd.Root().GenFishCompletion(os.Stdout, true)
- case "powershell":
- return cmd.Root().GenPowerShellCompletionWithDesc(os.Stdout)
- default:
- return fmt.Errorf("unrecognized shell: %s", args[0])
- }
- },
+ DisableFlagsInUseLine: true,
+ ValidArgs: []string{"bash", "zsh", "fish", "powershell"},
+ Args: cobra.MatchAll(cobra.ExactArgs(1), cobra.OnlyValidArgs),
+ RunE: func(cmd *cobra.Command, args []string) error {
+ switch args[0] {
+ case "bash":
+ return cmd.Root().GenBashCompletion(os.Stdout)
+ case "zsh":
+ return cmd.Root().GenZshCompletion(os.Stdout)
+ case "fish":
+ return cmd.Root().GenFishCompletion(os.Stdout, true)
+ case "powershell":
+ return cmd.Root().GenPowerShellCompletionWithDesc(os.Stdout)
+ default:
+ return fmt.Errorf("unrecognized shell: %s", args[0])
+ }
+ },
+ })
})
}
@@ -563,7 +565,9 @@ func RegisterCommand(cmd Command) {
if !commandNameRegex.MatchString(cmd.Name) {
panic("invalid command name")
}
- rootCmd.AddCommand(caddyCmdToCobra(cmd))
+ defaultFactory.Use(func(rootCmd *cobra.Command) {
+ rootCmd.AddCommand(caddyCmdToCobra(cmd))
+ })
}
var commandNameRegex = regexp.MustCompile(`^[a-z0-9]$|^([a-z0-9]+-?[a-z0-9]*)+[a-z0-9]$`)
diff --git a/cmd/main.go b/cmd/main.go
index 3c3ae6270..655c0084b 100644
--- a/cmd/main.go
+++ b/cmd/main.go
@@ -72,7 +72,7 @@ func Main() {
caddy.Log().Warn("failed to set GOMAXPROCS", zap.Error(err))
}
- if err := rootCmd.Execute(); err != nil {
+ if err := defaultFactory.Build().Execute(); err != nil {
var exitError *exitError
if errors.As(err, &exitError) {
os.Exit(exitError.ExitCode)