github.com/sijibomii/docker@v0.0.0-20231230191044-5cf6ca554647/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 return 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  }