bflag.go 4.1 KB

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