github.com/rclone/rclone@v1.66.1-0.20240517100346-7b89735ae726/fs/config/flags/flags.go (about) 1 // Package flags contains enhanced versions of spf13/pflag flag 2 // routines which will read from the environment also. 3 package flags 4 5 import ( 6 "log" 7 "os" 8 "regexp" 9 "strings" 10 "time" 11 12 "github.com/rclone/rclone/fs" 13 "github.com/spf13/pflag" 14 ) 15 16 // Groups of Flags 17 type Groups struct { 18 // Groups of flags 19 Groups []*Group 20 21 // GroupsMaps maps a group name to a Group 22 ByName map[string]*Group 23 } 24 25 // Group related flags together for documentation purposes 26 type Group struct { 27 Groups *Groups 28 Name string 29 Help string 30 Flags *pflag.FlagSet 31 } 32 33 // NewGroups constructs a collection of Groups 34 func NewGroups() *Groups { 35 return &Groups{ 36 ByName: make(map[string]*Group), 37 } 38 } 39 40 // NewGroup to create Group 41 func (gs *Groups) NewGroup(name, help string) *Group { 42 group := &Group{ 43 Name: name, 44 Help: help, 45 Flags: pflag.NewFlagSet(name, pflag.ExitOnError), 46 } 47 gs.ByName[group.Name] = group 48 gs.Groups = append(gs.Groups, group) 49 return group 50 } 51 52 // Filter makes a copy of groups filtered by flagsRe 53 func (gs *Groups) Filter(flagsRe *regexp.Regexp) *Groups { 54 newGs := NewGroups() 55 for _, g := range gs.Groups { 56 newG := newGs.NewGroup(g.Name, g.Help) 57 g.Flags.VisitAll(func(f *pflag.Flag) { 58 matched := flagsRe == nil || flagsRe.MatchString(f.Name) || flagsRe.MatchString(f.Usage) 59 if matched { 60 newG.Flags.AddFlag(f) 61 } 62 }) 63 } 64 return newGs 65 } 66 67 // Include makes a copy of groups only including the ones in the filter string 68 func (gs *Groups) Include(groupsString string) *Groups { 69 if groupsString == "" { 70 return gs 71 } 72 want := map[string]bool{} 73 for _, groupName := range strings.Split(groupsString, ",") { 74 _, ok := All.ByName[groupName] 75 if !ok { 76 log.Fatalf("Couldn't find group %q in command annotation", groupName) 77 } 78 want[groupName] = true 79 } 80 newGs := NewGroups() 81 for _, g := range gs.Groups { 82 if !want[g.Name] { 83 continue 84 } 85 newG := newGs.NewGroup(g.Name, g.Help) 86 newG.Flags = g.Flags 87 } 88 return newGs 89 } 90 91 // Add a new flag to the Group 92 func (g *Group) Add(flag *pflag.Flag) { 93 g.Flags.AddFlag(flag) 94 } 95 96 // AllRegistered returns all flags in a group 97 func (gs *Groups) AllRegistered() map[*pflag.Flag]struct{} { 98 out := make(map[*pflag.Flag]struct{}) 99 for _, g := range gs.Groups { 100 g.Flags.VisitAll(func(f *pflag.Flag) { 101 out[f] = struct{}{} 102 }) 103 } 104 return out 105 } 106 107 // All is the global stats Groups 108 var All *Groups 109 110 // Groups of flags for documentation purposes 111 func init() { 112 All = NewGroups() 113 All.NewGroup("Copy", "Flags for anything which can Copy a file.") 114 All.NewGroup("Sync", "Flags just used for `rclone sync`.") 115 All.NewGroup("Important", "Important flags useful for most commands.") 116 All.NewGroup("Check", "Flags used for `rclone check`.") 117 All.NewGroup("Networking", "General networking and HTTP stuff.") 118 All.NewGroup("Performance", "Flags helpful for increasing performance.") 119 All.NewGroup("Config", "General configuration of rclone.") 120 All.NewGroup("Debugging", "Flags for developers.") 121 All.NewGroup("Filter", "Flags for filtering directory listings.") 122 All.NewGroup("Listing", "Flags for listing directories.") 123 All.NewGroup("Logging", "Logging and statistics.") 124 All.NewGroup("Metadata", "Flags to control metadata.") 125 All.NewGroup("RC", "Flags to control the Remote Control API.") 126 } 127 128 // installFlag constructs a name from the flag passed in and 129 // sets the value and default from the environment if possible 130 // the value may be overridden when the command line is parsed 131 // 132 // Used to create non-backend flags like --stats. 133 // 134 // It also adds the flag to the groups passed in. 135 func installFlag(flags *pflag.FlagSet, name string, groupsString string) { 136 // Find flag 137 flag := flags.Lookup(name) 138 if flag == nil { 139 log.Fatalf("Couldn't find flag --%q", name) 140 } 141 142 // Read default from environment if possible 143 envKey := fs.OptionToEnv(name) 144 if envValue, envFound := os.LookupEnv(envKey); envFound { 145 err := flags.Set(name, envValue) 146 if err != nil { 147 log.Fatalf("Invalid value when setting --%s from environment variable %s=%q: %v", name, envKey, envValue, err) 148 } 149 fs.Debugf(nil, "Setting --%s %q from environment variable %s=%q", name, flag.Value, envKey, envValue) 150 flag.DefValue = envValue 151 } 152 153 // Add flag to Group if it is a global flag 154 if flags == pflag.CommandLine { 155 for _, groupName := range strings.Split(groupsString, ",") { 156 if groupName == "rc-" { 157 groupName = "RC" 158 } 159 group, ok := All.ByName[groupName] 160 if !ok { 161 log.Fatalf("Couldn't find group %q for flag --%s", groupName, name) 162 } 163 group.Add(flag) 164 } 165 } 166 } 167 168 // SetDefaultFromEnv constructs a name from the flag passed in and 169 // sets the default from the environment if possible 170 // 171 // Used to create backend flags like --skip-links 172 func SetDefaultFromEnv(flags *pflag.FlagSet, name string) { 173 envKey := fs.OptionToEnv(name) 174 envValue, found := os.LookupEnv(envKey) 175 if found { 176 flag := flags.Lookup(name) 177 if flag == nil { 178 log.Fatalf("Couldn't find flag --%q", name) 179 } 180 fs.Debugf(nil, "Setting default for %s=%q from environment variable %s", name, envValue, envKey) 181 //err = tempValue.Set() 182 flag.DefValue = envValue 183 } 184 } 185 186 // StringP defines a flag which can be set by an environment variable 187 // 188 // It is a thin wrapper around pflag.StringP 189 func StringP(name, shorthand string, value string, usage string, groups string) (out *string) { 190 out = pflag.StringP(name, shorthand, value, usage) 191 installFlag(pflag.CommandLine, name, groups) 192 return out 193 } 194 195 // StringVarP defines a flag which can be set by an environment variable 196 // 197 // It is a thin wrapper around pflag.StringVarP 198 func StringVarP(flags *pflag.FlagSet, p *string, name, shorthand string, value string, usage string, groups string) { 199 flags.StringVarP(p, name, shorthand, value, usage) 200 installFlag(flags, name, groups) 201 } 202 203 // BoolP defines a flag which can be set by an environment variable 204 // 205 // It is a thin wrapper around pflag.BoolP 206 func BoolP(name, shorthand string, value bool, usage string, groups string) (out *bool) { 207 out = pflag.BoolP(name, shorthand, value, usage) 208 installFlag(pflag.CommandLine, name, groups) 209 return out 210 } 211 212 // BoolVarP defines a flag which can be set by an environment variable 213 // 214 // It is a thin wrapper around pflag.BoolVarP 215 func BoolVarP(flags *pflag.FlagSet, p *bool, name, shorthand string, value bool, usage string, groups string) { 216 flags.BoolVarP(p, name, shorthand, value, usage) 217 installFlag(flags, name, groups) 218 } 219 220 // IntP defines a flag which can be set by an environment variable 221 // 222 // It is a thin wrapper around pflag.IntP 223 func IntP(name, shorthand string, value int, usage string, groups string) (out *int) { 224 out = pflag.IntP(name, shorthand, value, usage) 225 installFlag(pflag.CommandLine, name, groups) 226 return out 227 } 228 229 // Int64P defines a flag which can be set by an environment variable 230 // 231 // It is a thin wrapper around pflag.IntP 232 func Int64P(name, shorthand string, value int64, usage string, groups string) (out *int64) { 233 out = pflag.Int64P(name, shorthand, value, usage) 234 installFlag(pflag.CommandLine, name, groups) 235 return out 236 } 237 238 // Int64VarP defines a flag which can be set by an environment variable 239 // 240 // It is a thin wrapper around pflag.Int64VarP 241 func Int64VarP(flags *pflag.FlagSet, p *int64, name, shorthand string, value int64, usage string, groups string) { 242 flags.Int64VarP(p, name, shorthand, value, usage) 243 installFlag(flags, name, groups) 244 } 245 246 // IntVarP defines a flag which can be set by an environment variable 247 // 248 // It is a thin wrapper around pflag.IntVarP 249 func IntVarP(flags *pflag.FlagSet, p *int, name, shorthand string, value int, usage string, groups string) { 250 flags.IntVarP(p, name, shorthand, value, usage) 251 installFlag(flags, name, groups) 252 } 253 254 // Uint32VarP defines a flag which can be set by an environment variable 255 // 256 // It is a thin wrapper around pflag.Uint32VarP 257 func Uint32VarP(flags *pflag.FlagSet, p *uint32, name, shorthand string, value uint32, usage string, groups string) { 258 flags.Uint32VarP(p, name, shorthand, value, usage) 259 installFlag(flags, name, groups) 260 } 261 262 // Float64P defines a flag which can be set by an environment variable 263 // 264 // It is a thin wrapper around pflag.Float64P 265 func Float64P(name, shorthand string, value float64, usage string, groups string) (out *float64) { 266 out = pflag.Float64P(name, shorthand, value, usage) 267 installFlag(pflag.CommandLine, name, groups) 268 return out 269 } 270 271 // Float64VarP defines a flag which can be set by an environment variable 272 // 273 // It is a thin wrapper around pflag.Float64VarP 274 func Float64VarP(flags *pflag.FlagSet, p *float64, name, shorthand string, value float64, usage string, groups string) { 275 flags.Float64VarP(p, name, shorthand, value, usage) 276 installFlag(flags, name, groups) 277 } 278 279 // DurationP defines a flag which can be set by an environment variable 280 // 281 // It wraps the duration in an fs.Duration for extra suffixes and 282 // passes it to pflag.VarP 283 func DurationP(name, shorthand string, value time.Duration, usage string, groups string) (out *time.Duration) { 284 out = new(time.Duration) 285 *out = value 286 pflag.VarP((*fs.Duration)(out), name, shorthand, usage) 287 installFlag(pflag.CommandLine, name, groups) 288 return out 289 } 290 291 // DurationVarP defines a flag which can be set by an environment variable 292 // 293 // It wraps the duration in an fs.Duration for extra suffixes and 294 // passes it to pflag.VarP 295 func DurationVarP(flags *pflag.FlagSet, p *time.Duration, name, shorthand string, value time.Duration, usage string, groups string) { 296 flags.VarP((*fs.Duration)(p), name, shorthand, usage) 297 installFlag(flags, name, groups) 298 } 299 300 // VarP defines a flag which can be set by an environment variable 301 // 302 // It is a thin wrapper around pflag.VarP 303 func VarP(value pflag.Value, name, shorthand, usage string, groups string) { 304 pflag.VarP(value, name, shorthand, usage) 305 installFlag(pflag.CommandLine, name, groups) 306 } 307 308 // FVarP defines a flag which can be set by an environment variable 309 // 310 // It is a thin wrapper around pflag.VarP 311 func FVarP(flags *pflag.FlagSet, value pflag.Value, name, shorthand, usage string, groups string) { 312 flags.VarP(value, name, shorthand, usage) 313 installFlag(flags, name, groups) 314 } 315 316 // StringArrayP defines a flag which can be set by an environment variable 317 // 318 // It sets one value only - command line flags can be used to set more. 319 // 320 // It is a thin wrapper around pflag.StringArrayP 321 func StringArrayP(name, shorthand string, value []string, usage string, groups string) (out *[]string) { 322 out = pflag.StringArrayP(name, shorthand, value, usage) 323 installFlag(pflag.CommandLine, name, groups) 324 return out 325 } 326 327 // StringArrayVarP defines a flag which can be set by an environment variable 328 // 329 // It sets one value only - command line flags can be used to set more. 330 // 331 // It is a thin wrapper around pflag.StringArrayVarP 332 func StringArrayVarP(flags *pflag.FlagSet, p *[]string, name, shorthand string, value []string, usage string, groups string) { 333 flags.StringArrayVarP(p, name, shorthand, value, usage) 334 installFlag(flags, name, groups) 335 } 336 337 // CountP defines a flag which can be set by an environment variable 338 // 339 // It is a thin wrapper around pflag.CountP 340 func CountP(name, shorthand string, usage string, groups string) (out *int) { 341 out = pflag.CountP(name, shorthand, usage) 342 installFlag(pflag.CommandLine, name, groups) 343 return out 344 } 345 346 // CountVarP defines a flag which can be set by an environment variable 347 // 348 // It is a thin wrapper around pflag.CountVarP 349 func CountVarP(flags *pflag.FlagSet, p *int, name, shorthand string, usage string, groups string) { 350 flags.CountVarP(p, name, shorthand, usage) 351 installFlag(flags, name, groups) 352 }