github.com/docker/docker@v299999999.0.0-20200612211812-aaf470eca7b5+incompatible/builder/dockerfile/buildargs.go (about)

     1  package dockerfile // import "github.com/docker/docker/builder/dockerfile"
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  
     7  	"github.com/docker/docker/runconfig/opts"
     8  )
     9  
    10  // builtinAllowedBuildArgs is list of built-in allowed build args
    11  // these args are considered transparent and are excluded from the image history.
    12  // Filtering from history is implemented in dispatchers.go
    13  var builtinAllowedBuildArgs = map[string]bool{
    14  	"HTTP_PROXY":  true,
    15  	"http_proxy":  true,
    16  	"HTTPS_PROXY": true,
    17  	"https_proxy": true,
    18  	"FTP_PROXY":   true,
    19  	"ftp_proxy":   true,
    20  	"NO_PROXY":    true,
    21  	"no_proxy":    true,
    22  }
    23  
    24  // BuildArgs manages arguments used by the builder
    25  type BuildArgs struct {
    26  	// args that are allowed for expansion/substitution and passing to commands in 'run'.
    27  	allowedBuildArgs map[string]*string
    28  	// args defined before the first `FROM` in a Dockerfile
    29  	allowedMetaArgs map[string]*string
    30  	// args referenced by the Dockerfile
    31  	referencedArgs map[string]struct{}
    32  	// args provided by the user on the command line
    33  	argsFromOptions map[string]*string
    34  }
    35  
    36  // NewBuildArgs creates a new BuildArgs type
    37  func NewBuildArgs(argsFromOptions map[string]*string) *BuildArgs {
    38  	return &BuildArgs{
    39  		allowedBuildArgs: make(map[string]*string),
    40  		allowedMetaArgs:  make(map[string]*string),
    41  		referencedArgs:   make(map[string]struct{}),
    42  		argsFromOptions:  argsFromOptions,
    43  	}
    44  }
    45  
    46  // Clone returns a copy of the BuildArgs type
    47  func (b *BuildArgs) Clone() *BuildArgs {
    48  	result := NewBuildArgs(b.argsFromOptions)
    49  	for k, v := range b.allowedBuildArgs {
    50  		result.allowedBuildArgs[k] = v
    51  	}
    52  	for k, v := range b.allowedMetaArgs {
    53  		result.allowedMetaArgs[k] = v
    54  	}
    55  	for k := range b.referencedArgs {
    56  		result.referencedArgs[k] = struct{}{}
    57  	}
    58  	return result
    59  }
    60  
    61  // MergeReferencedArgs merges referenced args from another BuildArgs
    62  // object into the current one
    63  func (b *BuildArgs) MergeReferencedArgs(other *BuildArgs) {
    64  	for k := range other.referencedArgs {
    65  		b.referencedArgs[k] = struct{}{}
    66  	}
    67  }
    68  
    69  // WarnOnUnusedBuildArgs checks if there are any leftover build-args that were
    70  // passed but not consumed during build. Print a warning, if there are any.
    71  func (b *BuildArgs) WarnOnUnusedBuildArgs(out io.Writer) {
    72  	var leftoverArgs []string
    73  	for arg := range b.argsFromOptions {
    74  		_, isReferenced := b.referencedArgs[arg]
    75  		_, isBuiltin := builtinAllowedBuildArgs[arg]
    76  		if !isBuiltin && !isReferenced {
    77  			leftoverArgs = append(leftoverArgs, arg)
    78  		}
    79  	}
    80  	if len(leftoverArgs) > 0 {
    81  		fmt.Fprintf(out, "[Warning] One or more build-args %v were not consumed\n", leftoverArgs)
    82  	}
    83  }
    84  
    85  // ResetAllowed clears the list of args that are allowed to be used by a
    86  // directive
    87  func (b *BuildArgs) ResetAllowed() {
    88  	b.allowedBuildArgs = make(map[string]*string)
    89  }
    90  
    91  // AddMetaArg adds a new meta arg that can be used by FROM directives
    92  func (b *BuildArgs) AddMetaArg(key string, value *string) {
    93  	b.allowedMetaArgs[key] = value
    94  }
    95  
    96  // AddArg adds a new arg that can be used by directives
    97  func (b *BuildArgs) AddArg(key string, value *string) {
    98  	b.allowedBuildArgs[key] = value
    99  	b.referencedArgs[key] = struct{}{}
   100  }
   101  
   102  // IsReferencedOrNotBuiltin checks if the key is a built-in arg, or if it has been
   103  // referenced by the Dockerfile. Returns true if the arg is not a builtin or
   104  // if the builtin has been referenced in the Dockerfile.
   105  func (b *BuildArgs) IsReferencedOrNotBuiltin(key string) bool {
   106  	_, isBuiltin := builtinAllowedBuildArgs[key]
   107  	_, isAllowed := b.allowedBuildArgs[key]
   108  	return isAllowed || !isBuiltin
   109  }
   110  
   111  // GetAllAllowed returns a mapping with all the allowed args
   112  func (b *BuildArgs) GetAllAllowed() map[string]string {
   113  	return b.getAllFromMapping(b.allowedBuildArgs)
   114  }
   115  
   116  // GetAllMeta returns a mapping with all the meta args
   117  func (b *BuildArgs) GetAllMeta() map[string]string {
   118  	return b.getAllFromMapping(b.allowedMetaArgs)
   119  }
   120  
   121  func (b *BuildArgs) getAllFromMapping(source map[string]*string) map[string]string {
   122  	m := make(map[string]string)
   123  
   124  	keys := keysFromMaps(source, builtinAllowedBuildArgs)
   125  	for _, key := range keys {
   126  		v, ok := b.getBuildArg(key, source)
   127  		if ok {
   128  			m[key] = v
   129  		}
   130  	}
   131  	return m
   132  }
   133  
   134  // FilterAllowed returns all allowed args without the filtered args
   135  func (b *BuildArgs) FilterAllowed(filter []string) []string {
   136  	envs := []string{}
   137  	configEnv := opts.ConvertKVStringsToMap(filter)
   138  
   139  	for key, val := range b.GetAllAllowed() {
   140  		if _, ok := configEnv[key]; !ok {
   141  			envs = append(envs, fmt.Sprintf("%s=%s", key, val))
   142  		}
   143  	}
   144  	return envs
   145  }
   146  
   147  func (b *BuildArgs) getBuildArg(key string, mapping map[string]*string) (string, bool) {
   148  	defaultValue, exists := mapping[key]
   149  	// Return override from options if one is defined
   150  	if v, ok := b.argsFromOptions[key]; ok && v != nil {
   151  		return *v, ok
   152  	}
   153  
   154  	if defaultValue == nil {
   155  		if v, ok := b.allowedMetaArgs[key]; ok && v != nil {
   156  			return *v, ok
   157  		}
   158  		return "", false
   159  	}
   160  	return *defaultValue, exists
   161  }
   162  
   163  func keysFromMaps(source map[string]*string, builtin map[string]bool) []string {
   164  	keys := []string{}
   165  	for key := range source {
   166  		keys = append(keys, key)
   167  	}
   168  	for key := range builtin {
   169  		keys = append(keys, key)
   170  	}
   171  	return keys
   172  }