mirror of
				https://github.com/caddyserver/caddy.git
				synced 2025-10-31 10:37:24 -04:00 
			
		
		
		
	cmd: Use a factory to create the caddy root command (#6533)
Co-authored-by: Francis Lavoie <lavofr@gmail.com>
This commit is contained in:
		
							parent
							
								
									2bb2ecc549
								
							
						
					
					
						commit
						8ccfedf2bb
					
				
							
								
								
									
										26
									
								
								cmd/cobra.go
									
									
									
									
									
								
							
							
						
						
									
										26
									
								
								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 { | ||||
|  | ||||
							
								
								
									
										28
									
								
								cmd/commandfactory.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								cmd/commandfactory.go
									
									
									
									
									
										Normal 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 | ||||
| } | ||||
							
								
								
									
										100
									
								
								cmd/commands.go
									
									
									
									
									
								
							
							
						
						
									
										100
									
								
								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 | ||||
| 			}) | ||||
| 		}, | ||||
| 	}) | ||||
| 			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: | ||||
| 		// 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]$`) | ||||
|  | ||||
| @ -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) | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user