config is the main, high-level configuration setting function, processing config files and command-line arguments in the following order: - Apply any `default:` field tag default values. - Look for `--config`, `--cfg`, or `-c` arg, specifying a config file on the command line. - Fall back on default
(opts *Options, cfg T, cmds ...*Cmd[T])
| 127 | // for its command-line arguments. It returns the command, if any, that was passed in |
| 128 | // [os.Args], and any error that ocurred during the configuration process. |
| 129 | func config[T any](opts *Options, cfg T, cmds ...*Cmd[T]) (string, error) { |
| 130 | var errs []error |
| 131 | err := SetFromDefaults(cfg) |
| 132 | if err != nil { |
| 133 | errs = append(errs, err) |
| 134 | } |
| 135 | |
| 136 | args := os.Args[1:] |
| 137 | |
| 138 | // first, we do a pass to get the meta command flags |
| 139 | // (help and config), which we need to know before |
| 140 | // we can do other configuration. |
| 141 | mc := &metaConfig{} |
| 142 | // we ignore not found flags in meta config, because we only care about meta config and not anything else being passed to the command |
| 143 | cmd, err := SetFromArgs(mc, args, NoErrNotFound, metaCmds...) |
| 144 | if err != nil { |
| 145 | // if we can't do first set for meta flags, we return immediately (we only do AllErrors for more specific errors) |
| 146 | return cmd, fmt.Errorf("error doing meta configuration: %w", err) |
| 147 | } |
| 148 | logx.UserLevel = logx.LevelFromFlags(mc.VeryVerbose, mc.Verbose, mc.Quiet) |
| 149 | |
| 150 | // both flag and command trigger help |
| 151 | if mc.Help || cmd == "help" { |
| 152 | // string version of args slice has [] on the side, so need to get rid of them |
| 153 | mc.HelpCmd = strings.TrimPrefix(strings.TrimSuffix(mc.HelpCmd, "]"), "[") |
| 154 | // if flag and no posargs, will be nil |
| 155 | if mc.HelpCmd == "nil" { |
| 156 | mc.HelpCmd = "" |
| 157 | } |
| 158 | fmt.Println(usage(opts, cfg, mc.HelpCmd, cmds...)) |
| 159 | os.Exit(0) |
| 160 | } |
| 161 | |
| 162 | var cfgFiles []string |
| 163 | if mc.Config != "" { |
| 164 | cfgFiles = append(cfgFiles, mc.Config) |
| 165 | } |
| 166 | cfgFiles = append(cfgFiles, opts.DefaultFiles...) |
| 167 | |
| 168 | if opts.SearchUp { |
| 169 | wd, err := os.Getwd() |
| 170 | if err != nil { |
| 171 | return "", fmt.Errorf("error getting current directory: %w", err) |
| 172 | } |
| 173 | pwd := wd |
| 174 | for { |
| 175 | pwd = wd |
| 176 | wd = filepath.Dir(pwd) |
| 177 | if wd == pwd { // if there is no change, we have reached the root of the filesystem |
| 178 | break |
| 179 | } |
| 180 | opts.IncludePaths = append(opts.IncludePaths, wd) |
| 181 | } |
| 182 | } |
| 183 | |
| 184 | if opts.NeedConfigFile && len(cfgFiles) == 0 { |
| 185 | return "", errors.New("cli.Config: no config file or default files specified") |
| 186 | } |