@@ -3,36 +3,43 @@ package build
3
3
import (
4
4
"fmt"
5
5
"path"
6
+ "path/filepath"
7
+ "strings"
8
+
9
+ "github.com/docker/app/render"
6
10
7
11
"github.com/docker/app/types"
8
12
"github.com/docker/buildx/build"
9
- "github.com/docker/cli/cli/compose/loader"
10
13
compose "github.com/docker/cli/cli/compose/types"
11
14
)
12
15
13
16
// parseCompose do parse app compose file and extract buildx Options
14
17
// We don't rely on bake's ReadTargets + TargetsToBuildOpt here as we have to skip environment variable interpolation
15
- func parseCompose (app * types.App , contextPath string , options buildOptions ) (map [string ]build.Options , []ServiceConfig , error ) {
16
- parsed , err := loader . ParseYAML (app . Composes ()[ 0 ] )
18
+ func parseCompose (app * types.App , contextPath string , options buildOptions ) (map [string ]build.Options , []compose. ServiceConfig , error ) {
19
+ comp , err := render . Render (app , nil , nil )
17
20
if err != nil {
18
21
return nil , nil , err
19
22
}
20
23
21
- services , err := load (parsed , options .args )
22
- if err != nil {
23
- return nil , nil , fmt .Errorf ("Failed to parse compose file: %s" , err )
24
- }
24
+ buildArgs := buildArgsToMap (options .args )
25
25
26
- pulledServices := []ServiceConfig {}
26
+ pulledServices := []compose. ServiceConfig {}
27
27
opts := map [string ]build.Options {}
28
- for _ , service := range services {
29
- if service .Build == nil {
28
+ for _ , service := range comp .Services {
29
+ // Sanity check
30
+ for _ , vol := range service .Volumes {
31
+ if vol .Type == "bind" && ! filepath .IsAbs (vol .Source ) {
32
+ return nil , nil , fmt .Errorf ("invalid service %q: can't use relative path as volume source" , service .Name )
33
+ }
34
+ }
35
+
36
+ if service .Build .Context == "" {
30
37
pulledServices = append (pulledServices , service )
31
38
continue
32
39
}
33
40
var tags []string
34
- if service .Image != nil {
35
- tags = append (tags , * service .Image )
41
+ if service .Image != "" {
42
+ tags = append (tags , service .Image )
36
43
}
37
44
38
45
if service .Build .Dockerfile == "" {
@@ -43,7 +50,7 @@ func parseCompose(app *types.App, contextPath string, options buildOptions) (map
43
50
ContextPath : path .Join (contextPath , service .Build .Context ),
44
51
DockerfilePath : path .Join (contextPath , service .Build .Context , service .Build .Dockerfile ),
45
52
},
46
- BuildArgs : flatten (service .Build .Args ),
53
+ BuildArgs : flatten (mergeArgs ( service .Build .Args , buildArgs ) ),
47
54
NoCache : options .noCache ,
48
55
Pull : options .pull ,
49
56
Tags : tags ,
@@ -52,6 +59,33 @@ func parseCompose(app *types.App, contextPath string, options buildOptions) (map
52
59
return opts , pulledServices , nil
53
60
}
54
61
62
+ func buildArgsToMap (array []string ) map [string ]string {
63
+ result := make (map [string ]string )
64
+ for _ , value := range array {
65
+ parts := strings .SplitN (value , "=" , 2 )
66
+ key := parts [0 ]
67
+ if len (parts ) == 1 {
68
+ result [key ] = ""
69
+ } else {
70
+ result [key ] = parts [1 ]
71
+ }
72
+ }
73
+ return result
74
+ }
75
+
76
+ func mergeArgs (src compose.MappingWithEquals , values map [string ]string ) compose.MappingWithEquals {
77
+ for key := range src {
78
+ if val , ok := values [key ]; ok {
79
+ if val == "" {
80
+ src [key ] = nil
81
+ } else {
82
+ src [key ] = & val
83
+ }
84
+ }
85
+ }
86
+ return src
87
+ }
88
+
55
89
func flatten (in compose.MappingWithEquals ) map [string ]string {
56
90
if len (in ) == 0 {
57
91
return nil
0 commit comments