bflag.go 3.9 KB

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