| package dockerfile // import "github.com/docker/docker/builder/dockerfile" | |
| import ( | |
| "fmt" | |
| "io" | |
| "github.com/docker/docker/runconfig/opts" | |
| ) | |
| // builtinAllowedBuildArgs is list of built-in allowed build args | |
| // these args are considered transparent and are excluded from the image history. | |
| // Filtering from history is implemented in dispatchers.go | |
| var builtinAllowedBuildArgs = map[string]bool{ | |
| "HTTP_PROXY": true, | |
| "http_proxy": true, | |
| "HTTPS_PROXY": true, | |
| "https_proxy": true, | |
| "FTP_PROXY": true, | |
| "ftp_proxy": true, | |
| "NO_PROXY": true, | |
| "no_proxy": true, | |
| "ALL_PROXY": true, | |
| "all_proxy": true, | |
| } | |
| // BuildArgs manages arguments used by the builder | |
| type BuildArgs struct { | |
| // args that are allowed for expansion/substitution and passing to commands in 'run'. | |
| allowedBuildArgs map[string]*string | |
| // args defined before the first `FROM` in a Dockerfile | |
| allowedMetaArgs map[string]*string | |
| // args referenced by the Dockerfile | |
| referencedArgs map[string]struct{} | |
| // args provided by the user on the command line | |
| argsFromOptions map[string]*string | |
| } | |
| // NewBuildArgs creates a new BuildArgs type | |
| func NewBuildArgs(argsFromOptions map[string]*string) *BuildArgs { | |
| return &BuildArgs{ | |
| allowedBuildArgs: make(map[string]*string), | |
| allowedMetaArgs: make(map[string]*string), | |
| referencedArgs: make(map[string]struct{}), | |
| argsFromOptions: argsFromOptions, | |
| } | |
| } | |
| // Clone returns a copy of the BuildArgs type | |
| func (b *BuildArgs) Clone() *BuildArgs { | |
| result := NewBuildArgs(b.argsFromOptions) | |
| for k, v := range b.allowedBuildArgs { | |
| result.allowedBuildArgs[k] = v | |
| } | |
| for k, v := range b.allowedMetaArgs { | |
| result.allowedMetaArgs[k] = v | |
| } | |
| for k := range b.referencedArgs { | |
| result.referencedArgs[k] = struct{}{} | |
| } | |
| return result | |
| } | |
| // MergeReferencedArgs merges referenced args from another BuildArgs | |
| // object into the current one | |
| func (b *BuildArgs) MergeReferencedArgs(other *BuildArgs) { | |
| for k := range other.referencedArgs { | |
| b.referencedArgs[k] = struct{}{} | |
| } | |
| } | |
| // WarnOnUnusedBuildArgs checks if there are any leftover build-args that were | |
| // passed but not consumed during build. Print a warning, if there are any. | |
| func (b *BuildArgs) WarnOnUnusedBuildArgs(out io.Writer) { | |
| var leftoverArgs []string | |
| for arg := range b.argsFromOptions { | |
| _, isReferenced := b.referencedArgs[arg] | |
| _, isBuiltin := builtinAllowedBuildArgs[arg] | |
| if !isBuiltin && !isReferenced { | |
| leftoverArgs = append(leftoverArgs, arg) | |
| } | |
| } | |
| if len(leftoverArgs) > 0 { | |
| fmt.Fprintf(out, "[Warning] One or more build-args %v were not consumed\n", leftoverArgs) | |
| } | |
| } | |
| // ResetAllowed clears the list of args that are allowed to be used by a | |
| // directive | |
| func (b *BuildArgs) ResetAllowed() { | |
| b.allowedBuildArgs = make(map[string]*string) | |
| } | |
| // AddMetaArg adds a new meta arg that can be used by FROM directives | |
| func (b *BuildArgs) AddMetaArg(key string, value *string) { | |
| b.allowedMetaArgs[key] = value | |
| } | |
| // AddArg adds a new arg that can be used by directives | |
| func (b *BuildArgs) AddArg(key string, value *string) { | |
| b.allowedBuildArgs[key] = value | |
| b.referencedArgs[key] = struct{}{} | |
| } | |
| // IsReferencedOrNotBuiltin checks if the key is a built-in arg, or if it has been | |
| // referenced by the Dockerfile. Returns true if the arg is not a builtin or | |
| // if the builtin has been referenced in the Dockerfile. | |
| func (b *BuildArgs) IsReferencedOrNotBuiltin(key string) bool { | |
| _, isBuiltin := builtinAllowedBuildArgs[key] | |
| _, isAllowed := b.allowedBuildArgs[key] | |
| return isAllowed || !isBuiltin | |
| } | |
| // GetAllAllowed returns a mapping with all the allowed args | |
| func (b *BuildArgs) GetAllAllowed() map[string]string { | |
| return b.getAllFromMapping(b.allowedBuildArgs) | |
| } | |
| // GetAllMeta returns a mapping with all the meta args | |
| func (b *BuildArgs) GetAllMeta() map[string]string { | |
| return b.getAllFromMapping(b.allowedMetaArgs) | |
| } | |
| func (b *BuildArgs) getAllFromMapping(source map[string]*string) map[string]string { | |
| m := make(map[string]string) | |
| keys := keysFromMaps(source, builtinAllowedBuildArgs) | |
| for _, key := range keys { | |
| v, ok := b.getBuildArg(key, source) | |
| if ok { | |
| m[key] = v | |
| } | |
| } | |
| return m | |
| } | |
| // FilterAllowed returns all allowed args without the filtered args | |
| func (b *BuildArgs) FilterAllowed(filter []string) []string { | |
| envs := []string{} | |
| configEnv := opts.ConvertKVStringsToMap(filter) | |
| for key, val := range b.GetAllAllowed() { | |
| if _, ok := configEnv[key]; !ok { | |
| envs = append(envs, fmt.Sprintf("%s=%s", key, val)) | |
| } | |
| } | |
| return envs | |
| } | |
| func (b *BuildArgs) getBuildArg(key string, mapping map[string]*string) (string, bool) { | |
| defaultValue, exists := mapping[key] | |
| // Return override from options if one is defined | |
| if v, ok := b.argsFromOptions[key]; ok && v != nil { | |
| return *v, ok | |
| } | |
| if defaultValue == nil { | |
| if v, ok := b.allowedMetaArgs[key]; ok && v != nil { | |
| return *v, ok | |
| } | |
| return "", false | |
| } | |
| return *defaultValue, exists | |
| } | |
| func keysFromMaps(source map[string]*string, builtin map[string]bool) []string { | |
| keys := []string{} | |
| for key := range source { | |
| keys = append(keys, key) | |
| } | |
| for key := range builtin { | |
| keys = append(keys, key) | |
| } | |
| return keys | |
| } |