buildargs.go 5.0 KB

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