github.com/zhuohuang-hust/src-cbuild@v0.0.0-20230105071821-c7aab3e7c840/builder/dockerfile/bflag.go (about) 1 package dockerfile 2 3 import ( 4 "fmt" 5 "strings" 6 ) 7 8 // FlagType is the type of the build flag 9 type FlagType int 10 11 const ( 12 boolType FlagType = iota 13 stringType 14 ) 15 16 // BFlags contains all flags information for the builder 17 type BFlags struct { 18 Args []string // actual flags/args from cmd line 19 flags map[string]*Flag 20 used map[string]*Flag 21 Err error 22 } 23 24 // Flag contains all information for a flag 25 type Flag struct { 26 bf *BFlags 27 name string 28 flagType FlagType 29 Value string 30 } 31 32 // NewBFlags returns the new BFlags struct 33 func NewBFlags() *BFlags { 34 return &BFlags{ 35 flags: make(map[string]*Flag), 36 used: make(map[string]*Flag), 37 } 38 } 39 40 // AddBool adds a bool flag to BFlags 41 // Note, any error will be generated when Parse() is called (see Parse). 42 func (bf *BFlags) AddBool(name string, def bool) *Flag { 43 flag := bf.addFlag(name, boolType) 44 if flag == nil { 45 return nil 46 } 47 if def { 48 flag.Value = "true" 49 } else { 50 flag.Value = "false" 51 } 52 return flag 53 } 54 55 // AddString adds a string flag to BFlags 56 // Note, any error will be generated when Parse() is called (see Parse). 57 func (bf *BFlags) AddString(name string, def string) *Flag { 58 flag := bf.addFlag(name, stringType) 59 if flag == nil { 60 return nil 61 } 62 flag.Value = def 63 return flag 64 } 65 66 // addFlag is a generic func used by the other AddXXX() func 67 // to add a new flag to the BFlags struct. 68 // Note, any error will be generated when Parse() is called (see Parse). 69 func (bf *BFlags) addFlag(name string, flagType FlagType) *Flag { 70 if _, ok := bf.flags[name]; ok { 71 bf.Err = fmt.Errorf("Duplicate flag defined: %s", name) 72 return nil 73 } 74 75 newFlag := &Flag{ 76 bf: bf, 77 name: name, 78 flagType: flagType, 79 } 80 bf.flags[name] = newFlag 81 82 return newFlag 83 } 84 85 // IsUsed checks if the flag is used 86 func (fl *Flag) IsUsed() bool { 87 if _, ok := fl.bf.used[fl.name]; ok { 88 return true 89 } 90 return false 91 } 92 93 // IsTrue checks if a bool flag is true 94 func (fl *Flag) IsTrue() bool { 95 if fl.flagType != boolType { 96 // Should never get here 97 panic(fmt.Errorf("Trying to use IsTrue on a non-boolean: %s", fl.name)) 98 } 99 return fl.Value == "true" 100 } 101 102 // Parse parses and checks if the BFlags is valid. 103 // Any error noticed during the AddXXX() funcs will be generated/returned 104 // here. We do this because an error during AddXXX() is more like a 105 // compile time error so it doesn't matter too much when we stop our 106 // processing as long as we do stop it, so this allows the code 107 // around AddXXX() to be just: 108 // defFlag := AddString("description", "") 109 // w/o needing to add an if-statement around each one. 110 func (bf *BFlags) Parse() error { 111 // If there was an error while defining the possible flags 112 // go ahead and bubble it back up here since we didn't do it 113 // earlier in the processing 114 if bf.Err != nil { 115 return fmt.Errorf("Error setting up flags: %s", bf.Err) 116 } 117 118 for _, arg := range bf.Args { 119 if !strings.HasPrefix(arg, "--") { 120 return fmt.Errorf("Arg should start with -- : %s", arg) 121 } 122 123 if arg == "--" { 124 return nil 125 } 126 127 arg = arg[2:] 128 value := "" 129 130 index := strings.Index(arg, "=") 131 if index >= 0 { 132 value = arg[index+1:] 133 arg = arg[:index] 134 } 135 136 flag, ok := bf.flags[arg] 137 if !ok { 138 return fmt.Errorf("Unknown flag: %s", arg) 139 } 140 141 if _, ok = bf.used[arg]; ok { 142 return fmt.Errorf("Duplicate flag specified: %s", arg) 143 } 144 145 bf.used[arg] = flag 146 147 switch flag.flagType { 148 case boolType: 149 // value == "" is only ok if no "=" was specified 150 if index >= 0 && value == "" { 151 return fmt.Errorf("Missing a value on flag: %s", arg) 152 } 153 154 lower := strings.ToLower(value) 155 if lower == "" { 156 flag.Value = "true" 157 } else if lower == "true" || lower == "false" { 158 flag.Value = lower 159 } else { 160 return fmt.Errorf("Expecting boolean value for flag %s, not: %s", arg, value) 161 } 162 163 case stringType: 164 if index < 0 { 165 return fmt.Errorf("Missing a value on flag: %s", arg) 166 } 167 flag.Value = value 168 169 default: 170 panic(fmt.Errorf("No idea what kind of flag we have! Should never get here!")) 171 } 172 173 } 174 175 return nil 176 }