This commit is contained in:
a 2024-06-18 21:57:46 -05:00
parent edf4168c8e
commit 7bc7e1680e
No known key found for this signature in database
GPG key ID: 374BC539FE795AF0
4 changed files with 76 additions and 46 deletions

View file

@ -8,7 +8,8 @@ import (
"github.com/caddyserver/caddy/v2" "github.com/caddyserver/caddy/v2"
) )
var rootCmd = &cobra.Command{ var defaultFactory = NewRootCommandFactory(func() *cobra.Command {
return &cobra.Command{
Use: "caddy", Use: "caddy",
Long: `Caddy is an extensible server platform written in Go. Long: `Caddy is an extensible server platform written in Go.
@ -101,13 +102,16 @@ https://caddyserver.com/docs/running
SilenceUsage: true, SilenceUsage: true,
Version: onlyVersionText(), Version: onlyVersionText(),
} }
})
const fullDocsFooter = `Full documentation is available at: const fullDocsFooter = `Full documentation is available at:
https://caddyserver.com/docs/command-line` https://caddyserver.com/docs/command-line`
func init() { func init() {
rootCmd.SetVersionTemplate("{{.Version}}\n") defaultFactory.Use(func(cmd *cobra.Command) {
rootCmd.SetHelpTemplate(rootCmd.HelpTemplate() + "\n" + fullDocsFooter + "\n") cmd.SetVersionTemplate("{{.Version}}\n")
cmd.SetHelpTemplate(cmd.HelpTemplate() + "\n" + fullDocsFooter + "\n")
})
} }
func onlyVersionText() string { func onlyVersionText() string {

28
cmd/commandfactory.go Normal file
View file

@ -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
}

View file

@ -459,7 +459,8 @@ argument of --directory. If the directory does not exist, it will be created.
if err := os.MkdirAll(dir, 0o755); err != nil { if err := os.MkdirAll(dir, 0o755); err != nil {
return caddy.ExitCodeFailedQuit, err return caddy.ExitCodeFailedQuit, err
} }
if err := doc.GenManTree(rootCmd, &doc.GenManHeader{ ccmd := defaultFactory.Build()
if err := doc.GenManTree(ccmd, &doc.GenManHeader{
Title: "Caddy", Title: "Caddy",
Section: "8", // https://en.wikipedia.org/wiki/Man_page#Manual_sections Section: "8", // https://en.wikipedia.org/wiki/Man_page#Manual_sections
}, dir); err != nil { }, dir); err != nil {
@ -471,7 +472,8 @@ argument of --directory. If the directory does not exist, it will be created.
}) })
// source: https://github.com/spf13/cobra/blob/main/shell_completions.md // source: https://github.com/spf13/cobra/blob/main/shell_completions.md
rootCmd.AddCommand(&cobra.Command{ defaultFactory.Use(func(ccmd *cobra.Command) {
ccmd.AddCommand(&cobra.Command{
Use: "completion [bash|zsh|fish|powershell]", Use: "completion [bash|zsh|fish|powershell]",
Short: "Generate completion script", Short: "Generate completion script",
Long: fmt.Sprintf(`To load completions: Long: fmt.Sprintf(`To load completions:
@ -512,7 +514,7 @@ argument of --directory. If the directory does not exist, it will be created.
# To load completions for every new session, run: # To load completions for every new session, run:
PS> %[1]s completion powershell > %[1]s.ps1 PS> %[1]s completion powershell > %[1]s.ps1
# and source this file from your PowerShell profile. # and source this file from your PowerShell profile.
`, rootCmd.Root().Name()), `, defaultFactory.constructor().Name()),
DisableFlagsInUseLine: true, DisableFlagsInUseLine: true,
ValidArgs: []string{"bash", "zsh", "fish", "powershell"}, ValidArgs: []string{"bash", "zsh", "fish", "powershell"},
Args: cobra.MatchAll(cobra.ExactArgs(1), cobra.OnlyValidArgs), Args: cobra.MatchAll(cobra.ExactArgs(1), cobra.OnlyValidArgs),
@ -531,6 +533,7 @@ argument of --directory. If the directory does not exist, it will be created.
} }
}, },
}) })
})
} }
// RegisterCommand registers the command cmd. // RegisterCommand registers the command cmd.
@ -563,7 +566,9 @@ func RegisterCommand(cmd Command) {
if !commandNameRegex.MatchString(cmd.Name) { if !commandNameRegex.MatchString(cmd.Name) {
panic("invalid command name") panic("invalid command name")
} }
rootCmd.AddCommand(caddyCmdToCobra(cmd)) defaultFactory.Use(func(ccmd *cobra.Command) {
ccmd.AddCommand(caddyCmdToCobra(cmd))
})
} }
var commandNameRegex = regexp.MustCompile(`^[a-z0-9]$|^([a-z0-9]+-?[a-z0-9]*)+[a-z0-9]$`) var commandNameRegex = regexp.MustCompile(`^[a-z0-9]$|^([a-z0-9]+-?[a-z0-9]*)+[a-z0-9]$`)

View file

@ -34,7 +34,6 @@ import (
"time" "time"
"github.com/caddyserver/certmagic" "github.com/caddyserver/certmagic"
"github.com/spf13/cobra"
"github.com/spf13/pflag" "github.com/spf13/pflag"
"go.uber.org/automaxprocs/maxprocs" "go.uber.org/automaxprocs/maxprocs"
"go.uber.org/zap" "go.uber.org/zap"
@ -72,7 +71,7 @@ func Main() {
if err != nil { if err != nil {
caddy.Log().Warn("failed to set GOMAXPROCS", zap.Error(err)) caddy.Log().Warn("failed to set GOMAXPROCS", zap.Error(err))
} }
rootCmd := defaultFactory.Build()
if err := rootCmd.Execute(); err != nil { if err := rootCmd.Execute(); err != nil {
var exitError *exitError var exitError *exitError
if errors.As(err, &exitError) { if errors.As(err, &exitError) {
@ -86,15 +85,9 @@ func Main() {
func MainForTesting(args ...string) error { func MainForTesting(args ...string) error {
// create a root command for testing which will not pollute the global namespace, and does not // create a root command for testing which will not pollute the global namespace, and does not
// call os.Exit(). // call os.Exit().
tmpRootCmp := cobra.Command{ rootCmd := defaultFactory.Build()
Use: rootCmd.Use, rootCmd.SetArgs(args)
Long: rootCmd.Long, if err := rootCmd.Execute(); err != nil {
Example: rootCmd.Example,
SilenceUsage: rootCmd.SilenceUsage,
Version: rootCmd.Version,
}
tmpRootCmp.SetArgs(args)
if err := tmpRootCmp.Execute(); err != nil {
return err return err
} }
return nil return nil