Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS
Mirrored from https://github.com/Slazee/caddy.git
Synced Nov 12, 09:30 UTC
cmd: Use a factory to create the caddy root command (#6533)
Co-authored-by: Francis Lavoie <lavofr@gmail.com>
a committed
Aug 21, 2024 at 22:29 UTC
8ccfedf2bb0a1759aa68d4989f05d9a52ba41a34
4 files changed
+97
-61
cmd/cobra.go
+15
-11
@@ -8,9 +8,10 @@ import (
8
"github.com/caddyserver/caddy/v2"
9
)
10
11
-var rootCmd = &cobra.Command{
12
- Use: "caddy",
13
- Long: `Caddy is an extensible server platform written in Go.
11
+var defaultFactory = newRootCommandFactory(func() *cobra.Command {
12
+ return &cobra.Command{
13
+ Use: "caddy",
14
+ Long: `Caddy is an extensible server platform written in Go.
15
16
At its core, Caddy merely manages configuration. Modules are plugged
17
in statically at compile-time to provide useful functionality. Caddy's
@@ -91,23 +92,26 @@ package installers: https://caddyserver.com/docs/install
92
Instructions for running Caddy in production are also available:
93
https://caddyserver.com/docs/running
94
`,
94
- Example: ` $ caddy run
95
+ Example: ` $ caddy run
96
$ caddy run --config caddy.json
97
$ caddy reload --config caddy.json
98
$ caddy stop`,
99
99
- // kind of annoying to have all the help text printed out if
100
- // caddy has an error provisioning its modules, for instance...
101
- SilenceUsage: true,
102
- Version: onlyVersionText(),
103
-}
100
+ // kind of annoying to have all the help text printed out if
101
+ // caddy has an error provisioning its modules, for instance...
102
+ SilenceUsage: true,
103
+ Version: onlyVersionText(),
104
+ }
105
+})
106
107
const fullDocsFooter = `Full documentation is available at:
108
https://caddyserver.com/docs/command-line`
109
110
func init() {
109
- rootCmd.SetVersionTemplate("{{.Version}}\n")
110
- rootCmd.SetHelpTemplate(rootCmd.HelpTemplate() + "\n" + fullDocsFooter + "\n")
111
+ defaultFactory.Use(func(rootCmd *cobra.Command) {
112
+ rootCmd.SetVersionTemplate("{{.Version}}\n")
113
+ rootCmd.SetHelpTemplate(rootCmd.HelpTemplate() + "\n" + fullDocsFooter + "\n")
114
+ })
115
}
116
117
func onlyVersionText() string {
cmd/commandfactory.go
new
+28
@@ -0,0 +1,28 @@
1
+package caddycmd
2
+
3
+import (
4
+ "github.com/spf13/cobra"
5
+)
6
+
7
+type rootCommandFactory struct {
8
+ constructor func() *cobra.Command
9
+ options []func(*cobra.Command)
10
+}
11
+
12
+func newRootCommandFactory(fn func() *cobra.Command) *rootCommandFactory {
13
+ return &rootCommandFactory{
14
+ constructor: fn,
15
+ }
16
+}
17
+
18
+func (f *rootCommandFactory) Use(fn func(cmd *cobra.Command)) {
19
+ f.options = append(f.options, fn)
20
+}
21
+
22
+func (f *rootCommandFactory) Build() *cobra.Command {
23
+ o := f.constructor()
24
+ for _, v := range f.options {
25
+ v(o)
26
+ }
27
+ return o
28
+}
cmd/commands.go
+53
-49
@@ -438,43 +438,44 @@ EXPERIMENTAL: May be changed or removed.
438
},
439
})
440
441
- RegisterCommand(Command{
442
- Name: "manpage",
443
- Usage: "--directory <path>",
444
- Short: "Generates the manual pages for Caddy commands",
445
- Long: `
441
+ defaultFactory.Use(func(rootCmd *cobra.Command) {
442
+ RegisterCommand(Command{
443
+ Name: "manpage",
444
+ Usage: "--directory <path>",
445
+ Short: "Generates the manual pages for Caddy commands",
446
+ Long: `
447
Generates the manual pages for Caddy commands into the designated directory
448
tagged into section 8 (System Administration).
449
450
The manual page files are generated into the directory specified by the
451
argument of --directory. If the directory does not exist, it will be created.
452
`,
452
- CobraFunc: func(cmd *cobra.Command) {
453
- cmd.Flags().StringP("directory", "o", "", "The output directory where the manpages are generated")
454
- cmd.RunE = WrapCommandFuncForCobra(func(fl Flags) (int, error) {
455
- dir := strings.TrimSpace(fl.String("directory"))
456
- if dir == "" {
457
- return caddy.ExitCodeFailedQuit, fmt.Errorf("designated output directory and specified section are required")
458
- }
459
- if err := os.MkdirAll(dir, 0o755); err != nil {
460
- return caddy.ExitCodeFailedQuit, err
461
- }
462
- if err := doc.GenManTree(rootCmd, &doc.GenManHeader{
463
- Title: "Caddy",
464
- Section: "8", // https://en.wikipedia.org/wiki/Man_page#Manual_sections
465
- }, dir); err != nil {
466
- return caddy.ExitCodeFailedQuit, err
467
- }
468
- return caddy.ExitCodeSuccess, nil
469
- })
470
- },
471
- })
472
-
473
- // source: https://github.com/spf13/cobra/blob/main/shell_completions.md
474
- rootCmd.AddCommand(&cobra.Command{
475
- Use: "completion [bash|zsh|fish|powershell]",
476
- Short: "Generate completion script",
477
- Long: fmt.Sprintf(`To load completions:
453
+ CobraFunc: func(cmd *cobra.Command) {
454
+ cmd.Flags().StringP("directory", "o", "", "The output directory where the manpages are generated")
455
+ cmd.RunE = WrapCommandFuncForCobra(func(fl Flags) (int, error) {
456
+ dir := strings.TrimSpace(fl.String("directory"))
457
+ if dir == "" {
458
+ return caddy.ExitCodeFailedQuit, fmt.Errorf("designated output directory and specified section are required")
459
+ }
460
+ if err := os.MkdirAll(dir, 0o755); err != nil {
461
+ return caddy.ExitCodeFailedQuit, err
462
+ }
463
+ if err := doc.GenManTree(rootCmd, &doc.GenManHeader{
464
+ Title: "Caddy",
465
+ Section: "8", // https://en.wikipedia.org/wiki/Man_page#Manual_sections
466
+ }, dir); err != nil {
467
+ return caddy.ExitCodeFailedQuit, err
468
+ }
469
+ return caddy.ExitCodeSuccess, nil
470
+ })
471
+ },
472
+ })
473
+
474
+ // source: https://github.com/spf13/cobra/blob/main/shell_completions.md
475
+ rootCmd.AddCommand(&cobra.Command{
476
+ Use: "completion [bash|zsh|fish|powershell]",
477
+ Short: "Generate completion script",
478
+ Long: fmt.Sprintf(`To load completions:
479
480
Bash:
481
@@ -513,23 +514,24 @@ argument of --directory. If the directory does not exist, it will be created.
514
PS> %[1]s completion powershell > %[1]s.ps1
515
# and source this file from your PowerShell profile.
516
`, rootCmd.Root().Name()),
516
- DisableFlagsInUseLine: true,
517
- ValidArgs: []string{"bash", "zsh", "fish", "powershell"},
518
- Args: cobra.MatchAll(cobra.ExactArgs(1), cobra.OnlyValidArgs),
519
- RunE: func(cmd *cobra.Command, args []string) error {
520
- switch args[0] {
521
- case "bash":
522
- return cmd.Root().GenBashCompletion(os.Stdout)
523
- case "zsh":
524
- return cmd.Root().GenZshCompletion(os.Stdout)
525
- case "fish":
526
- return cmd.Root().GenFishCompletion(os.Stdout, true)
527
- case "powershell":
528
- return cmd.Root().GenPowerShellCompletionWithDesc(os.Stdout)
529
- default:
530
- return fmt.Errorf("unrecognized shell: %s", args[0])
531
- }
532
- },
517
+ DisableFlagsInUseLine: true,
518
+ ValidArgs: []string{"bash", "zsh", "fish", "powershell"},
519
+ Args: cobra.MatchAll(cobra.ExactArgs(1), cobra.OnlyValidArgs),
520
+ RunE: func(cmd *cobra.Command, args []string) error {
521
+ switch args[0] {
522
+ case "bash":
523
+ return cmd.Root().GenBashCompletion(os.Stdout)
524
+ case "zsh":
525
+ return cmd.Root().GenZshCompletion(os.Stdout)
526
+ case "fish":
527
+ return cmd.Root().GenFishCompletion(os.Stdout, true)
528
+ case "powershell":
529
+ return cmd.Root().GenPowerShellCompletionWithDesc(os.Stdout)
530
+ default:
531
+ return fmt.Errorf("unrecognized shell: %s", args[0])
532
+ }
533
+ },
534
+ })
535
})
536
}
537
@@ -563,7 +565,9 @@ func RegisterCommand(cmd Command) {
565
if !commandNameRegex.MatchString(cmd.Name) {
566
panic("invalid command name")
567
}
566
- rootCmd.AddCommand(caddyCmdToCobra(cmd))
568
+ defaultFactory.Use(func(rootCmd *cobra.Command) {
569
+ rootCmd.AddCommand(caddyCmdToCobra(cmd))
570
+ })
571
}
572
573
var commandNameRegex = regexp.MustCompile(`^[a-z0-9]$|^([a-z0-9]+-?[a-z0-9]*)+[a-z0-9]$`)
cmd/main.go
+1
-1
@@ -72,7 +72,7 @@ func Main() {
72
caddy.Log().Warn("failed to set GOMAXPROCS", zap.Error(err))
73
}
74
75
- if err := rootCmd.Execute(); err != nil {
75
+ if err := defaultFactory.Build().Execute(); err != nil {
76
var exitError *exitError
77
if errors.As(err, &exitError) {
78
os.Exit(exitError.ExitCode)