compote 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,371 @@
1
+ module Compote
2
+
3
+ module Schema
4
+
5
+ resolve_relative_path = {
6
+
7
+ String => proc { | value, config |
8
+
9
+ value = config.get_path value if value.start_with? '.'
10
+
11
+ value
12
+
13
+ },
14
+
15
+ }
16
+
17
+ wrap_string_in_array = {
18
+
19
+ String => proc { | value |
20
+
21
+ [ value ]
22
+
23
+ },
24
+
25
+ }
26
+
27
+ options_array_to_hash = {
28
+
29
+ Array => proc { | value |
30
+
31
+ value.map do | value |
32
+
33
+ [ value, {} ]
34
+
35
+ end.to_h
36
+
37
+ },
38
+
39
+ }
40
+
41
+ variables_array_to_hash = {
42
+
43
+ Array => proc { | value |
44
+
45
+ value.map do | value |
46
+
47
+ result = value.split '=', 2
48
+
49
+ result += [ nil ] if result.size == 1
50
+
51
+ result
52
+
53
+ end.to_h
54
+
55
+ },
56
+
57
+ }
58
+
59
+ labels_array_to_hash = {
60
+
61
+ Array => proc { | value |
62
+
63
+ value.map do | value |
64
+
65
+ result = value.split '=', 2
66
+
67
+ result += [ '' ] if result.size == 1
68
+
69
+ result
70
+
71
+ end.to_h
72
+
73
+ },
74
+
75
+ }
76
+
77
+ compote_extends_to_hash = {
78
+
79
+ String => proc { | value | { value => {} } },
80
+
81
+ Array => options_array_to_hash[ Array ],
82
+
83
+ Hash => proc { | value | value.map { | key, value | [ key, value || {} ] }.to_h },
84
+
85
+ '*' => {
86
+
87
+ 'only' => wrap_string_in_array,
88
+
89
+ 'except' => wrap_string_in_array,
90
+
91
+ },
92
+
93
+ }
94
+
95
+ env_files_mapping = {
96
+
97
+ String => wrap_string_in_array[ String ],
98
+
99
+ '*' => resolve_relative_path,
100
+
101
+ },
102
+
103
+
104
+ MAPPINGS = {
105
+
106
+ 'compote' => {
107
+
108
+ 'extends' => compote_extends_to_hash,
109
+
110
+ 'env_file' => env_files_mapping,
111
+
112
+ 'environment' => variables_array_to_hash,
113
+
114
+ },
115
+
116
+ 'volumes' => {
117
+
118
+ '*' => {
119
+
120
+ 'labels' => labels_array_to_hash,
121
+
122
+ },
123
+
124
+ },
125
+
126
+ 'networks' => {
127
+
128
+ '*' => {
129
+
130
+ 'labels' => labels_array_to_hash,
131
+
132
+ },
133
+
134
+ },
135
+
136
+ 'services' => {
137
+
138
+ '*' => {
139
+
140
+ 'build' => {
141
+
142
+ String => proc { | value | { 'context' => value } },
143
+
144
+ 'args' => variables_array_to_hash,
145
+
146
+ },
147
+
148
+ 'depends_on' => options_array_to_hash,
149
+
150
+ 'dns' => wrap_string_in_array,
151
+
152
+ 'dns_search' => wrap_string_in_array,
153
+
154
+ 'tmpfs' => wrap_string_in_array,
155
+
156
+ 'env_file' => env_files_mapping,
157
+
158
+ 'environment' => variables_array_to_hash,
159
+
160
+ 'labels' => labels_array_to_hash,
161
+
162
+ 'sysctls' => variables_array_to_hash,
163
+
164
+ 'volumes' => {
165
+
166
+ '*' => {
167
+
168
+ String => proc { | value, config |
169
+
170
+ if value.start_with? '.'
171
+
172
+ values = value.split ':'
173
+
174
+ values[ 0 ] = config.get_path values[ 0 ]
175
+
176
+ value = values.join ':'
177
+
178
+ end
179
+
180
+ value
181
+
182
+ },
183
+
184
+ },
185
+
186
+ },
187
+
188
+ 'compote' => {
189
+
190
+ 'extends' => compote_extends_to_hash,
191
+
192
+ 'volumes' => {
193
+
194
+ '*' => {
195
+
196
+ 'labels' => labels_array_to_hash,
197
+
198
+ },
199
+
200
+ },
201
+
202
+ 'networks' => {
203
+
204
+ '*' => {
205
+
206
+ 'labels' => labels_array_to_hash,
207
+
208
+ },
209
+
210
+ },
211
+
212
+ },
213
+
214
+ },
215
+
216
+ },
217
+
218
+ }
219
+
220
+
221
+ def self.validate! ( data )
222
+
223
+ scheme = Pathname.new( __FILE__ ).join( '../schema.json' ).to_path
224
+
225
+ JSON::Validator.validate! scheme, data
226
+
227
+ rescue JSON::Schema::ValidationError => error
228
+
229
+ raise ConfigFormatError.new error: error, data: data
230
+
231
+ end
232
+
233
+ def self.normalize ( config, value, mappings = MAPPINGS )
234
+
235
+ validate! value if mappings == MAPPINGS
236
+
237
+
238
+ value = value.clone
239
+
240
+
241
+ class_mappings = mappings.select { | key, value | key.is_a? Class }
242
+
243
+ unless class_mappings.empty?
244
+
245
+ class_mapping = class_mappings[ value.class ]
246
+
247
+ value = class_mapping.call value, config if class_mapping
248
+
249
+ end
250
+
251
+
252
+ paths_mappings = mappings.select { | key, value | key.is_a? String }
253
+
254
+ unless paths_mappings.empty? || ! value.is_a?( Enumerable ) || value.empty?
255
+
256
+ if paths_mappings.keys == [ '*' ]
257
+
258
+ path_mappings = paths_mappings[ '*' ]
259
+
260
+ if value.is_a? Hash
261
+
262
+ value = value.map do | key, value |
263
+
264
+ [ key, normalize( config, value, path_mappings ) ]
265
+
266
+ end.to_h
267
+
268
+ end
269
+
270
+ if value.is_a? Array
271
+
272
+ value = value.map do | value |
273
+
274
+ normalize config, value, path_mappings
275
+
276
+ end
277
+
278
+ end
279
+
280
+ elsif value.is_a? Hash
281
+
282
+ value = value.map do | key, value |
283
+
284
+ path_mappings = paths_mappings[ key ]
285
+
286
+ if path_mappings
287
+
288
+ [ key, normalize( config, value, path_mappings ) ]
289
+
290
+ else
291
+
292
+ [ key, value ]
293
+
294
+ end
295
+
296
+ end.to_h
297
+
298
+ end
299
+
300
+ end
301
+
302
+
303
+ value
304
+
305
+ end
306
+
307
+ def self.apply_extends ( initial_data, &get_data )
308
+
309
+ extends = initial_data.dig 'compote', 'extends'
310
+
311
+ return initial_data.clone unless extends
312
+
313
+ extending_datas = extends.map do | key, options |
314
+
315
+ data = get_data.call key
316
+
317
+ data = data.select { | key, value | options[ 'only' ].include? key } if options[ 'only' ]
318
+
319
+ data = data.reject { | key, value | options[ 'except' ].include? key } if options[ 'except' ]
320
+
321
+ data
322
+
323
+ end
324
+
325
+ extending_datas += [ initial_data ]
326
+
327
+ resulted_data = merge extending_datas
328
+
329
+ resulted_data
330
+
331
+ end
332
+
333
+ def self.merge ( datas )
334
+
335
+ result = {}
336
+
337
+ datas.each do | data |
338
+
339
+ data.keys.each do | key |
340
+
341
+ values = [ result[ key ], data[ key ] ]
342
+
343
+ result[ key ] = begin
344
+
345
+ if values.all? { | value | value.is_a? Hash }
346
+
347
+ merge values
348
+
349
+ elsif values.all? { | value | value.is_a? Array } && ! %w( command entrypoint ).include?( key )
350
+
351
+ values.first + values.last
352
+
353
+ else
354
+
355
+ values.last.clone
356
+
357
+ end
358
+
359
+ end
360
+
361
+ end
362
+
363
+ end
364
+
365
+ result
366
+
367
+ end
368
+
369
+ end
370
+
371
+ end
@@ -0,0 +1,81 @@
1
+ module Compote
2
+
3
+ class ServiceConfig
4
+
5
+ def initialize ( config, name, data )
6
+
7
+ @config = config
8
+
9
+ @name = name
10
+
11
+ @data = apply_extends data
12
+
13
+
14
+ @compote_settings = @data.fetch 'compote', {}
15
+
16
+ @service_settings = @data.reject { | key, value | key == 'compote' }
17
+
18
+ end
19
+
20
+ def commands
21
+
22
+ @compote_settings.fetch 'commands', {}
23
+
24
+ end
25
+
26
+ def compose_config
27
+
28
+ compose_config = {}
29
+
30
+ compose_config[ 'version' ] = @config.compose_version
31
+
32
+ compose_config[ 'services' ] = @service_settings.empty? ? {} : { @name => @service_settings }
33
+
34
+ compose_config[ 'volumes' ] = @compote_settings.fetch 'volumes', {}
35
+
36
+ compose_config[ 'networks' ] = @compote_settings.fetch 'networks', {}
37
+
38
+ compose_config
39
+
40
+ end
41
+
42
+
43
+ protected
44
+
45
+ def data
46
+
47
+ @data
48
+
49
+ end
50
+
51
+ def apply_extends ( initial_data )
52
+
53
+ Schema.apply_extends initial_data do | key |
54
+
55
+ key_info = key.split ':'
56
+
57
+ key_info = [ '.', key_info[ 0 ] ] if key_info.size == 1
58
+
59
+ config_path, service_name = key_info
60
+
61
+ config = @config.load_config config_path
62
+
63
+ service_config = config.get_service_config service_name
64
+
65
+ data = service_config.data
66
+
67
+ data
68
+
69
+ end
70
+
71
+ rescue ServiceNotFoundError => error
72
+
73
+ error.message += "\n" + "If the service exists, check that its definition is higher than of service \"#{ @name }\"" if error.config == @config
74
+
75
+ raise error
76
+
77
+ end
78
+
79
+ end
80
+
81
+ end