@@ -4,13 +4,10 @@ import (
4
4
"bufio"
5
5
"bytes"
6
6
"fmt"
7
- "path"
8
7
"strings"
9
8
10
- "github.com/Sirupsen/logrus"
11
9
yaml "github.com/cloudfoundry-incubator/candiedyaml"
12
10
"github.com/docker/docker/pkg/urlutil"
13
- "github.com/docker/libcompose/utils"
14
11
)
15
12
16
13
var (
@@ -20,56 +17,44 @@ var (
20
17
}
21
18
)
22
19
23
- // MergeServices merges a compose file into an existing set of service configs
24
- func MergeServices (existingServices * Configs , environmentLookup EnvironmentLookup , resourceLookup ResourceLookup , file string , bytes []byte ) (map [string ]* ServiceConfig , error ) {
25
- configs := make (map [string ]* ServiceConfig )
26
-
27
- datas := make (RawServiceMap )
28
- if err := yaml .Unmarshal (bytes , & datas ); err != nil {
29
- return nil , err
30
- }
31
-
32
- if err := Interpolate (environmentLookup , & datas ); err != nil {
33
- return nil , err
20
+ // Merge merges a compose file into an existing set of service configs
21
+ func Merge (existingServices * ServiceConfigs , environmentLookup EnvironmentLookup , resourceLookup ResourceLookup , file string , bytes []byte ) (map [string ]* ServiceConfig , map [string ]* VolumeConfig , map [string ]* NetworkConfig , error ) {
22
+ var config Config
23
+ if err := yaml .Unmarshal (bytes , & config ); err != nil {
24
+ return nil , nil , nil , err
34
25
}
35
26
36
- if err := validate ( datas ); err != nil {
37
- return nil , err
38
- }
39
-
40
- for name , data := range datas {
41
- data , err := parse ( resourceLookup , environmentLookup , file , data , datas )
27
+ var serviceConfigs map [ string ] * ServiceConfig
28
+ var volumeConfigs map [ string ] * VolumeConfig
29
+ var networkConfigs map [ string ] * NetworkConfig
30
+ if config . Version == "2" {
31
+ var err error
32
+ serviceConfigs , err = MergeServicesV2 ( existingServices , environmentLookup , resourceLookup , file , bytes )
42
33
if err != nil {
43
- logrus .Errorf ("Failed to parse service %s: %v" , name , err )
44
- return nil , err
34
+ return nil , nil , nil , err
45
35
}
46
-
47
- if serviceConfig , ok := existingServices .Get (name ); ok {
48
- var rawExistingService RawService
49
- if err := utils .Convert (serviceConfig , & rawExistingService ); err != nil {
50
- return nil , err
51
- }
52
-
53
- data = mergeConfig (rawExistingService , data )
36
+ volumeConfigs , err = ParseVolumes (environmentLookup , resourceLookup , file , bytes )
37
+ if err != nil {
38
+ return nil , nil , nil , err
54
39
}
55
-
56
- datas [name ] = data
57
- }
58
-
59
- for name , data := range datas {
60
- err := validateServiceConstraints (data , name )
40
+ networkConfigs , err = ParseNetworks (environmentLookup , resourceLookup , file , bytes )
61
41
if err != nil {
62
- return nil , err
42
+ return nil , nil , nil , err
43
+ }
44
+ } else {
45
+ serviceConfigsV1 , err := MergeServicesV1 (existingServices , environmentLookup , resourceLookup , file , bytes )
46
+ if err != nil {
47
+ return nil , nil , nil , err
48
+ }
49
+ serviceConfigs , err = ConvertV1toV2 (serviceConfigsV1 , environmentLookup , resourceLookup )
50
+ if err != nil {
51
+ return nil , nil , nil , err
63
52
}
64
53
}
65
54
66
- if err := utils .Convert (datas , & configs ); err != nil {
67
- return nil , err
68
- }
69
-
70
- adjustValues (configs )
55
+ adjustValues (serviceConfigs )
71
56
72
- return configs , nil
57
+ return serviceConfigs , volumeConfigs , networkConfigs , nil
73
58
}
74
59
75
60
func adjustValues (configs map [string ]* ServiceConfig ) {
@@ -82,24 +67,25 @@ func adjustValues(configs map[string]*ServiceConfig) {
82
67
}
83
68
84
69
func readEnvFile (resourceLookup ResourceLookup , inFile string , serviceData RawService ) (RawService , error ) {
85
- var config ServiceConfig
86
-
87
- if err := utils .Convert (serviceData , & config ); err != nil {
88
- return nil , err
70
+ if _ , ok := serviceData ["env_file" ]; ! ok {
71
+ return serviceData , nil
89
72
}
90
-
91
- if len (config . EnvFile ) == 0 {
73
+ envFiles := serviceData [ "env_file" ].([] interface {})
74
+ if len (envFiles ) == 0 {
92
75
return serviceData , nil
93
76
}
94
77
95
78
if resourceLookup == nil {
96
79
return nil , fmt .Errorf ("Can not use env_file in file %s no mechanism provided to load files" , inFile )
97
80
}
98
81
99
- vars := config .Environment
82
+ var vars []interface {}
83
+ if _ , ok := serviceData ["environment" ]; ok {
84
+ vars = serviceData ["environment" ].([]interface {})
85
+ }
100
86
101
- for i := len (config . EnvFile ) - 1 ; i >= 0 ; i -- {
102
- envFile := config . EnvFile [i ]
87
+ for i := len (envFiles ) - 1 ; i >= 0 ; i -- {
88
+ envFile := envFiles [i ].( string )
103
89
content , _ , err := resourceLookup .Lookup (envFile , inFile )
104
90
if err != nil {
105
91
return nil , err
@@ -116,7 +102,7 @@ func readEnvFile(resourceLookup ResourceLookup, inFile string, serviceData RawSe
116
102
117
103
found := false
118
104
for _ , v := range vars {
119
- if strings .HasPrefix (v , key ) {
105
+ if strings .HasPrefix (v .( string ) , key ) {
120
106
found = true
121
107
break
122
108
}
@@ -139,124 +125,6 @@ func readEnvFile(resourceLookup ResourceLookup, inFile string, serviceData RawSe
139
125
return serviceData , nil
140
126
}
141
127
142
- func resolveBuild (inFile string , serviceData RawService ) (RawService , error ) {
143
-
144
- build := asString (serviceData ["build" ])
145
- if build == "" {
146
- return serviceData , nil
147
- }
148
-
149
- if IsValidRemote (build ) {
150
- return serviceData , nil
151
- }
152
-
153
- current := path .Dir (inFile )
154
-
155
- if build == "." {
156
- build = current
157
- } else {
158
- current = path .Join (current , build )
159
- }
160
-
161
- serviceData ["build" ] = current
162
-
163
- return serviceData , nil
164
- }
165
-
166
- func parse (resourceLookup ResourceLookup , environmentLookup EnvironmentLookup , inFile string , serviceData RawService , datas RawServiceMap ) (RawService , error ) {
167
- serviceData , err := readEnvFile (resourceLookup , inFile , serviceData )
168
- if err != nil {
169
- return nil , err
170
- }
171
-
172
- serviceData , err = resolveBuild (inFile , serviceData )
173
- if err != nil {
174
- return nil , err
175
- }
176
-
177
- value , ok := serviceData ["extends" ]
178
- if ! ok {
179
- return serviceData , nil
180
- }
181
-
182
- mapValue , ok := value .(map [interface {}]interface {})
183
- if ! ok {
184
- return serviceData , nil
185
- }
186
-
187
- if resourceLookup == nil {
188
- return nil , fmt .Errorf ("Can not use extends in file %s no mechanism provided to files" , inFile )
189
- }
190
-
191
- file := asString (mapValue ["file" ])
192
- service := asString (mapValue ["service" ])
193
-
194
- if service == "" {
195
- return serviceData , nil
196
- }
197
-
198
- var baseService RawService
199
-
200
- if file == "" {
201
- if serviceData , ok := datas [service ]; ok {
202
- baseService , err = parse (resourceLookup , environmentLookup , inFile , serviceData , datas )
203
- } else {
204
- return nil , fmt .Errorf ("Failed to find service %s to extend" , service )
205
- }
206
- } else {
207
- bytes , resolved , err := resourceLookup .Lookup (file , inFile )
208
- if err != nil {
209
- logrus .Errorf ("Failed to lookup file %s: %v" , file , err )
210
- return nil , err
211
- }
212
-
213
- var baseRawServices RawServiceMap
214
- if err := yaml .Unmarshal (bytes , & baseRawServices ); err != nil {
215
- return nil , err
216
- }
217
-
218
- err = Interpolate (environmentLookup , & baseRawServices )
219
- if err != nil {
220
- return nil , err
221
- }
222
-
223
- if err := validate (baseRawServices ); err != nil {
224
- return nil , err
225
- }
226
-
227
- baseService , ok = baseRawServices [service ]
228
- if ! ok {
229
- return nil , fmt .Errorf ("Failed to find service %s in file %s" , service , file )
230
- }
231
-
232
- baseService , err = parse (resourceLookup , environmentLookup , resolved , baseService , baseRawServices )
233
- }
234
-
235
- if err != nil {
236
- return nil , err
237
- }
238
-
239
- baseService = clone (baseService )
240
-
241
- logrus .Debugf ("Merging %#v, %#v" , baseService , serviceData )
242
-
243
- for _ , k := range noMerge {
244
- if _ , ok := baseService [k ]; ok {
245
- source := file
246
- if source == "" {
247
- source = inFile
248
- }
249
- return nil , fmt .Errorf ("Cannot extend service '%s' in %s: services with '%s' cannot be extended" , service , source , k )
250
- }
251
- }
252
-
253
- baseService = mergeConfig (baseService , serviceData )
254
-
255
- logrus .Debugf ("Merged result %#v" , baseService )
256
-
257
- return baseService , nil
258
- }
259
-
260
128
func mergeConfig (baseService , serviceData RawService ) RawService {
261
129
for k , v := range serviceData {
262
130
// Image and build are mutually exclusive in merge
@@ -276,47 +144,6 @@ func mergeConfig(baseService, serviceData RawService) RawService {
276
144
return baseService
277
145
}
278
146
279
- func merge (existing , value interface {}) interface {} {
280
- // append strings
281
- if left , lok := existing .([]interface {}); lok {
282
- if right , rok := value .([]interface {}); rok {
283
- return append (left , right ... )
284
- }
285
- }
286
-
287
- //merge maps
288
- if left , lok := existing .(map [interface {}]interface {}); lok {
289
- if right , rok := value .(map [interface {}]interface {}); rok {
290
- newLeft := make (map [interface {}]interface {})
291
- for k , v := range left {
292
- newLeft [k ] = v
293
- }
294
- for k , v := range right {
295
- newLeft [k ] = v
296
- }
297
- return newLeft
298
- }
299
- }
300
-
301
- return value
302
- }
303
-
304
- func clone (in RawService ) RawService {
305
- result := RawService {}
306
- for k , v := range in {
307
- result [k ] = v
308
- }
309
-
310
- return result
311
- }
312
-
313
- func asString (obj interface {}) string {
314
- if v , ok := obj .(string ); ok {
315
- return v
316
- }
317
- return ""
318
- }
319
-
320
147
// IsValidRemote checks if the specified string is a valid remote (for builds)
321
148
func IsValidRemote (remote string ) bool {
322
149
return urlutil .IsGitURL (remote ) || urlutil .IsURL (remote )
0 commit comments