github.com/sohaha/zlsgo@v1.7.13-0.20240501141223-10dd1a906f76/zcli/parse.go (about) 1 package zcli 2 3 import ( 4 "flag" 5 "fmt" 6 "os" 7 "strings" 8 "sync" 9 10 "github.com/sohaha/zlsgo/zarray" 11 "github.com/sohaha/zlsgo/ztype" 12 ) 13 14 var runCmd = []string{os.Args[0]} 15 16 func parse(outHelp bool) { 17 parseCommand(outHelp) 18 parseSubcommand(flag.Args()) 19 } 20 21 func parseRequiredFlags(fs *flag.FlagSet, requiredFlags []string) (err error) { 22 requiredFlagsLen := len(requiredFlags) 23 if requiredFlagsLen > 0 { 24 flagMap := zarray.NewArray(requiredFlagsLen) 25 for _, flagName := range requiredFlags { 26 flagMap.Push(flagName) 27 } 28 fs.Visit(func(f *flag.Flag) { 29 Log.Error(f.Name) 30 31 _, _ = flagMap.RemoveValue(f.Name) 32 }) 33 flagMapLen := flagMap.Length() 34 if flagMapLen > 0 && !*flagHelp { 35 arr := make([]string, flagMapLen) 36 for i := 0; i < flagMapLen; i++ { 37 value, _ := flagMap.Get(i) 38 arr[i] = "-" + ztype.ToString(value) 39 } 40 err = fmt.Errorf("required flags: %s", strings.Join(arr, ", ")) 41 } 42 } 43 return 44 } 45 46 var parseDone sync.Once 47 48 // Parse Parse command line arguments 49 func Parse(arg ...[]string) (hasflag bool) { 50 parseDone.Do(func() { 51 if Version != "" { 52 flagVersion = SetVar("version", GetLangText("version")).short("V").Bool() 53 } 54 if EnableDetach { 55 flagDetach = SetVar("detach", GetLangText("detach")).Bool() 56 } 57 }) 58 59 var argsData []string 60 if len(arg) == 1 { 61 argsData = arg[0] 62 } else { 63 argsData = os.Args[1:] 64 } 65 for k := range argsData { 66 s := argsData[k] 67 if !isDetach(s) { 68 runCmd = append(runCmd, s) 69 } 70 if len(s) < 2 || s[0] != '-' { 71 continue 72 } 73 prefix := "-" 74 if s[1] == '-' { 75 s = s[2:] 76 prefix = "--" 77 } else { 78 s = s[1:] 79 } 80 for key := range varsKey { 81 if key == s { 82 argsData[k] = prefix + cliPrefix + s 83 } 84 } 85 } 86 87 hasflag = len(argsData) > 0 88 89 if hasflag && argsData[0][0] != '-' { 90 parseSubcommand(argsData) 91 if matchingCmd != nil { 92 matchingCmd.command.Run(args) 93 } 94 osExit(0) 95 } 96 97 _ = flag.CommandLine.Parse(argsData) 98 v, ok := ShortValues["V"].(*bool) 99 if ok && *v { 100 *flagVersion = *v 101 } 102 if d, ok := ShortValues["D"].(*bool); ok && *d { 103 *flagDetach = *d 104 } 105 if *flagVersion { 106 showVersionNum(*v) 107 osExit(0) 108 return 109 } 110 return 111 } 112 113 func parseCommand(outHelp bool) { 114 Parse() 115 if len(cmds) < 1 { 116 return 117 } 118 flag.Usage = usage 119 requiredErr := parseRequiredFlags(flag.CommandLine, requiredFlags) 120 if requiredErr != nil { 121 if len(flag.Args()) > 0 { 122 Error(requiredErr.Error()) 123 } else if outHelp { 124 Help() 125 } 126 } 127 128 if flag.NArg() < 1 { 129 if outHelp { 130 Help() 131 } 132 return 133 } 134 } 135 136 func parseSubcommand(Args []string) { 137 var name = "" 138 if len(Args) > 0 { 139 name = Args[0] 140 } 141 if cont, ok := cmds[name]; ok { 142 matchingCmd = cont 143 FirstParameter += " " + name 144 fsArgs := Args[1:] 145 fs := flag.NewFlagSet(name, flag.ExitOnError) 146 flag.CommandLine.VisitAll(func(f *flag.Flag) { 147 fs.Var(f.Value, f.Name, f.Usage) 148 }) 149 flag.CommandLine = fs 150 subcommand := &Subcommand{ 151 Name: cont.name, 152 Desc: cont.desc, 153 Supplement: cont.Supplement, 154 Parameter: FirstParameter, 155 CommandLine: fs, 156 } 157 cont.command.Flags(subcommand) 158 fs.SetOutput(&errWrite{}) 159 fs.Usage = func() { 160 Log.Printf("%s\n\n", subcommand.Desc) 161 if subcommand.Supplement != "" { 162 Log.Printf("%s\n\n", subcommand.Supplement) 163 } 164 Log.Printf("\nusage of %s\n\n", subcommand.Parameter) 165 showFlags(fs) 166 showRequired(fs, cont.requiredFlags) 167 } 168 _ = fs.Parse(fsArgs) 169 args = fs.Args() 170 argsIsHelp(args) 171 flagMap := zarray.NewArray(len(cont.requiredFlags)) 172 for _, flagName := range cont.requiredFlags { 173 flagMap.Push(flagName) 174 } 175 fs.Visit(func(f *flag.Flag) { 176 _, _ = flagMap.RemoveValue(f.Name) 177 }) 178 flagMapLen := flagMap.Length() 179 if flagMapLen > 0 && !*flagHelp { 180 arr := make([]string, flagMapLen) 181 for i := 0; i < flagMapLen; i++ { 182 value, _ := flagMap.Get(i) 183 arr[i] = "-" + ztype.ToString(value) 184 } 185 Error("required flags: %s", strings.Join(arr, ", ")) 186 } 187 } else if name != "" { 188 unknownCommandFn(name) 189 osExit(1) 190 } 191 }