package main import ( "flag" "fmt" "os" ) // GlobalOptions 全局公共参数,所有子命令共享 type GlobalOptions struct { Verbose bool // 详细日志模式 Config string // 全局配置文件 } // SubCommand 通用子命令抽象结构体 type SubCommand struct { Name string Description string Flags *flag.FlagSet Run func([]string, GlobalOptions) error } // 提前声明变量,避免初始化循环引用 var commands map[string]*SubCommand // init 初始化子命令,将 FlagSet 的绑定与执行逻辑分离 func init() { // --- 初始化 build 命令 --- buildCmd := &SubCommand{ Name: "build", Description: "编译构建项目", Flags: flag.NewFlagSet("build", flag.ContinueOnError), } var buildOutput string // 在外部绑定参数,而不是在 Run 里面重新创建 FlagSet buildCmd.Flags.StringVar(&buildOutput, "output", "./dist", "项目构建输出目录") buildCmd.Run = func(args []string, global GlobalOptions) error { if err := buildCmd.Flags.Parse(args); err != nil { return err } fmt.Printf("[构建成功] 输出目录:%s,全局详细日志:%t,全局配置:%s\n", buildOutput, global.Verbose, global.Config) return nil } // --- 初始化 deploy 命令 --- deployCmd := &SubCommand{ Name: "deploy", Description: "部署项目到环境", Flags: flag.NewFlagSet("deploy", flag.ContinueOnError), } var deployEnv string deployCmd.Flags.StringVar(&deployEnv, "env", "dev", "部署环境 dev/test/prod") deployCmd.Run = func(args []string, global GlobalOptions) error { if err := deployCmd.Flags.Parse(args); err != nil { return err } fmt.Printf("[部署成功] 目标环境:%s,全局配置文件:%s\n", deployEnv, global.Config) return nil } // 注册子命令 commands = map[string]*SubCommand{ "build": buildCmd, "deploy": deployCmd, } } func main() { // 1. 初始化全局参数 FlagSet(独立隔离) var global GlobalOptions globalFlags := flag.NewFlagSet("global", flag.ContinueOnError) globalFlags.BoolVar(&global.Verbose, "verbose", false, "启用详细日志输出") globalFlags.StringVar(&global.Config, "config", "./config.yaml", "全局配置文件路径") // 2. 解析全局参数 // 注意:flag 库遇到第一个非 Flag 参数(即子命令名称)就会停止解析 if err := globalFlags.Parse(os.Args[1:]); err != nil { if err == flag.ErrHelp { printHelp(globalFlags) return } fmt.Println("全局参数解析失败:", err) os.Exit(1) } // 3. 获取剩余参数(子命令 + 子命令参数) remainingArgs := globalFlags.Args() if len(remainingArgs) == 0 { printHelp(globalFlags) os.Exit(1) } // 4. 路由分发执行子命令 cmdName := remainingArgs[0] if cmd, exists := commands[cmdName]; exists { if err := cmd.Run(remainingArgs[1:], global); err != nil { if err == flag.ErrHelp { // 当子命令触发 -h 时,打印该子命令专属的帮助信息 fmt.Printf("\n===== 子命令 [%s] 帮助信息 =====\n", cmd.Name) fmt.Printf("说明:%s\n\n用法:%s [选项]\n\n选项:\n", cmd.Description, cmd.Name) cmd.Flags.PrintDefaults() return } fmt.Printf("子命令执行失败:%v\n", err) os.Exit(1) } } else { fmt.Printf("❌ 未知子命令:%s\n", cmdName) printHelp(globalFlags) os.Exit(1) } } // printHelp 统一打印全局帮助信息 func printHelp(globalFlags *flag.FlagSet) { fmt.Println("===== 项目工程化 CLI 工具 =====") fmt.Println("用法:tool [全局选项] <子命令> [子命令选项]") fmt.Println("\n全局选项:") globalFlags.PrintDefaults() fmt.Println("\n可用子命令:") for _, cmd := range commands { fmt.Printf(" %-10s %s\n", cmd.Name, cmd.Description) } fmt.Println("\n提示:使用 'tool <子命令> -h' 查看子命令详细帮助") }