github.com/sandwich-go/boost@v1.3.29/xcmd/cmd.go (about) 1 package xcmd 2 3 import ( 4 "flag" 5 "fmt" 6 "os" 7 "regexp" 8 "strings" 9 ) 10 11 var ( 12 flagPrefix = "xcmd_" 13 parsedOptions = make(map[string]string) 14 argumentRegex = regexp.MustCompile(`^\-{1,2}([\w\?\.\-]+)(=){0,1}(.*)$`) 15 formal = make(map[string]string) 16 invalidChars = ".-/\\" 17 ) 18 19 const ( 20 FlagPrefix = "sandwich_" 21 DefaultStringFalse = "false" 22 DefaultStringTrue = "true" 23 DefaultStringEmpty = "" 24 cmdEnvSandwichBuildInfo = "sandwich_build_info" 25 DefaultTopologyRender = "true" 26 ) 27 28 // SetFlagPrefix 设置 flag 的前缀 29 func SetFlagPrefix(prefix string) { flagPrefix = prefix } 30 31 // GetFlagPrefix 获取 flag 的前缀 32 func GetFlagPrefix() string { return flagPrefix } 33 34 func addFlagIfNotExists(fs *flag.FlagSet, name string, value string) { 35 if fs.Lookup(name) == nil { 36 usage := fmt.Sprintf("%sbase_command flag:%s default:%s", flagPrefix, name, value) 37 _ = fs.String(name, value, usage) 38 } 39 } 40 41 // DeclareInto 将 command 预留的 flag 定义添加到指定的 FlagSet 中 42 func DeclareInto(fs *flag.FlagSet) { 43 for name, val := range formal { 44 addFlagIfNotExists(fs, name, val) 45 } 46 } 47 48 // AddFlag 添加框架内默认的 flag 数据 49 // name 必须有 flagPrefix 前缀,不能包含.-/\字符 50 func AddFlag(name, defaultVal string) error { 51 if !strings.HasPrefix(name, flagPrefix) { 52 return fmt.Errorf("command flag must has prefix: %s", flagPrefix) 53 } 54 if strings.ContainsAny(name, invalidChars) { 55 return fmt.Errorf("command flag should only use _ as world separator, format must be:%s<package name>_<variable name>", flagPrefix) 56 } 57 _, alreadyThere := formal[name] 58 if alreadyThere { 59 return fmt.Errorf("flag redefined: %s", name) 60 } 61 formal[name] = defaultVal 62 addFlagIfNotExists(flag.CommandLine, name, defaultVal) 63 return nil 64 } 65 66 // MustAddFlag 添加框架内默认的 flag 数据,若失败,则panic 67 // name 必须有 flagPrefix 前缀,不能包含特殊的字符 68 func MustAddFlag(name, defaultVal string) { 69 err := AddFlag(name, defaultVal) 70 if err != nil { 71 panic(err) 72 } 73 } 74 75 // Init 根据给定的参数初始化预留的参数,如果args为空,则会使用os.Args初始化 76 func Init(args ...string) { 77 if len(args) == 0 { 78 if len(parsedOptions) != 0 { // 已经初始化过数据 79 return 80 } 81 args = os.Args 82 } 83 84 if len(parsedOptions) == 0 { 85 parsedOptions = make(map[string]string) 86 } 87 for i := 0; i < len(args); { 88 match := argumentRegex.FindStringSubmatch(args[i]) 89 if len(match) > 2 { 90 if match[2] == "=" { 91 // -xcmd_debug=1 92 // array 4 [-xcmd_debug=1 xcmd_debug = 1] 93 parsedOptions[match[1]] = match[3] 94 } else if i < len(args)-1 { 95 if len(args[i+1]) > 0 && args[i+1][0] == '-' { 96 parsedOptions[match[1]] = match[3] 97 } else { 98 parsedOptions[match[1]] = args[i+1] 99 i += 2 100 continue 101 } 102 } else { 103 parsedOptions[match[1]] = match[3] 104 } 105 } 106 i++ 107 } 108 } 109 110 // GetOptWithEnv 返回命令定义的行参数或Env中的参数 111 // 1. 命令行参数,小写,单词之间以_分割,$FlagPrefix_<package name>_<variable name> 112 // 2. 环境变量参数,小写(历史遗留),且单词之间以_分割,$FlagPrefix_<package name>_<variable name> 113 func GetOptWithEnv(key string, def ...string) string { 114 Init() 115 if v, ok := parsedOptions[key]; ok { 116 return v 117 } 118 if r, ok := os.LookupEnv(key); ok { 119 return r 120 } 121 if len(def) > 0 { 122 return def[0] 123 } 124 if v, ok := formal[key]; ok { 125 return v 126 } 127 return "" 128 } 129 130 // ContainsOpt checks whether option named `name` exist in the arguments. 131 func ContainsOpt(name string) bool { 132 Init() 133 _, ok := parsedOptions[name] 134 return ok 135 }