lorj 0.2.0 → 1.0.0
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.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.rubocop.yml +46 -0
- data/Gemfile +15 -15
- data/README.md +22 -17
- data/Rakefile +12 -2
- data/bin/cloud_test.rb +13 -65
- data/example/students_1/process/students.rb +39 -0
- data/example/students_1/students.rb +22 -5
- data/example/students_2/process/students.rb +48 -0
- data/example/students_2/students.rb +39 -16
- data/example/students_3/controller/yaml_students.rb +50 -43
- data/example/students_3/controller/yaml_students_controller.rb +100 -87
- data/example/students_3/process/students.rb +161 -97
- data/example/students_3/students.rb +85 -56
- data/example/yaml_students/students.rb +40 -40
- data/example/yaml_students/yaml_students.rb +103 -90
- data/lib/core/core.rb +356 -696
- data/lib/core/core_controller.rb +227 -0
- data/lib/core/core_internal.rb +339 -0
- data/lib/core/core_model.rb +328 -0
- data/lib/core/core_object_data.rb +330 -0
- data/lib/core/core_object_params.rb +230 -0
- data/lib/core/core_process.rb +391 -0
- data/lib/core/core_process_setup.rb +353 -0
- data/lib/core/core_setup_ask.rb +241 -0
- data/lib/core/core_setup_encrypt.rb +146 -0
- data/lib/core/core_setup_init.rb +229 -0
- data/lib/core/core_setup_list.rb +160 -0
- data/lib/core/definition.rb +647 -469
- data/lib/core/definition_internal.rb +264 -308
- data/lib/core/lorj_basecontroller.rb +95 -0
- data/lib/core/lorj_basedefinition.rb +307 -0
- data/lib/core/lorj_baseprocess.rb +265 -0
- data/lib/core/lorj_data.rb +583 -0
- data/lib/core/lorj_keypath.rb +119 -0
- data/lib/core_process/cloud/process/common.rb +63 -0
- data/lib/core_process/cloud/process/connection.rb +93 -0
- data/lib/core_process/cloud/process/external_network.rb +94 -0
- data/lib/core_process/cloud/process/flavor.rb +99 -0
- data/lib/core_process/cloud/process/images.rb +87 -0
- data/lib/core_process/cloud/process/internet_network.rb +34 -0
- data/lib/core_process/cloud/process/internet_server.rb +30 -0
- data/lib/core_process/cloud/process/keypairs.rb +276 -0
- data/lib/core_process/cloud/process/network.rb +108 -0
- data/lib/core_process/cloud/process/public_ip.rb +100 -0
- data/lib/core_process/cloud/process/router.rb +260 -0
- data/lib/core_process/cloud/process/rules.rb +120 -0
- data/lib/core_process/cloud/process/security_groups.rb +121 -0
- data/lib/core_process/cloud/process/server.rb +127 -0
- data/lib/core_process/cloud/process/server_log.rb +35 -0
- data/lib/core_process/cloud/process/subnetwork.rb +108 -0
- data/lib/core_process/cloud_process.rb +30 -0
- data/lib/logging.rb +298 -0
- data/lib/lorj/version.rb +18 -1
- data/lib/lorj.rb +58 -18
- data/lib/lorj_account.rb +556 -0
- data/lib/lorj_config.rb +468 -0
- data/lib/lorj_defaults.rb +278 -0
- data/lib/prc.rb +136 -104
- data/lib/prc_base_config.rb +285 -0
- data/lib/prc_core_config.rb +878 -0
- data/lib/prc_section_config.rb +57 -0
- data/lib/providers/hpcloud/compute.rb +81 -93
- data/lib/providers/hpcloud/hpcloud.rb +462 -0
- data/lib/providers/hpcloud/network.rb +96 -98
- data/lib/providers/hpcloud/security_groups.rb +41 -40
- data/lib/providers/mock/mock.rb +144 -0
- data/lib/providers/openstack/openstack.rb +45 -0
- data/lib/providers/templates/compute.rb +21 -23
- data/lib/providers/templates/mycloud.rb +72 -0
- data/lib/providers/templates/network.rb +11 -12
- data/lib/rh.rb +339 -0
- data/lorj-spec/defaults.yaml +4 -0
- data/lorj.gemspec +6 -0
- data/spec/00_lorj_log_spec.rb +53 -0
- data/spec/01_hash_rh_spec.rb +243 -0
- data/spec/02_prc_base_config_spec.rb +216 -0
- data/spec/04_prc_core_config_spec.rb +83 -0
- data/spec/11_lorj_config_spec.rb +263 -0
- data/spec/12_lorj_account_spec.rb +181 -0
- metadata +76 -28
- data/Gemfile.lock +0 -37
- data/example/students_1/process/Students.rb +0 -20
- data/example/students_2/process/Students.rb +0 -27
- data/example/students_4/controller/yaml_students.rb +0 -82
- data/example/students_4/controller/yaml_students_controller.rb +0 -141
- data/example/students_4/process/students.rb +0 -112
- data/example/students_4/students.rb +0 -103
- data/lib/core/lorj-basecontroller.rb +0 -90
- data/lib/core/lorj-basedefinition.rb +0 -1139
- data/lib/core/lorj-baseprocess.rb +0 -236
- data/lib/core/lorj-data.rb +0 -567
- data/lib/core/lorj-keypath.rb +0 -115
- data/lib/core_process/CloudProcess.rb +0 -337
- data/lib/core_process/global_process.rb +0 -502
- data/lib/core_process/network_process.rb +0 -605
- data/lib/prc-account.rb +0 -339
- data/lib/prc-config.rb +0 -1030
- data/lib/prc-logging.rb +0 -261
- data/lib/providers/hpcloud/Hpcloud.rb +0 -426
- data/lib/providers/mock/Mock.rb +0 -141
- data/lib/providers/openstack/Openstack.rb +0 -47
- data/lib/providers/templates/core.rb +0 -61
- data/spec/forj-account_spec.rb +0 -75
- data/spec/forj-config_spec.rb +0 -196
|
@@ -0,0 +1,878 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
|
|
3
|
+
# (c) Copyright 2014 Hewlett-Packard Development Company, L.P.
|
|
4
|
+
#
|
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
# you may not use this file except in compliance with the License.
|
|
7
|
+
# You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
# See the License for the specific language governing permissions and
|
|
15
|
+
# limitations under the License.
|
|
16
|
+
|
|
17
|
+
require 'yaml'
|
|
18
|
+
|
|
19
|
+
module PRC
|
|
20
|
+
# This class implement The CoreConfig system of lorj.
|
|
21
|
+
#
|
|
22
|
+
# * You can use it directly. See PRC::CoreConfig.initialize.
|
|
23
|
+
# * you can enhance it with class heritage feature.
|
|
24
|
+
# See Class child discussion later in this class documentation.
|
|
25
|
+
#
|
|
26
|
+
# It implements several layer of CoreConfig object type
|
|
27
|
+
# to provide several source of data in layers priorities.
|
|
28
|
+
# Ex: RunTime => LocalConfig => AppDefault
|
|
29
|
+
#
|
|
30
|
+
# It implements config features:
|
|
31
|
+
# * [] - To get a value for a key or tree of keys
|
|
32
|
+
# * []= - To set a Config value in the highest config.
|
|
33
|
+
# * del - To delete key or simply nil the value in highest config.
|
|
34
|
+
# * exist? - To check the existence of a value in config levels.
|
|
35
|
+
# * where? - To get the name of the level where the value was found.
|
|
36
|
+
# * file - To get or set a filename to a config layer.
|
|
37
|
+
# * save - To save one config data level in a yaml file.
|
|
38
|
+
# * load - To load data from a yaml file to a config data layer.
|
|
39
|
+
#
|
|
40
|
+
# It implements Config Layer settings at init time.
|
|
41
|
+
# See initialize(config_layers)
|
|
42
|
+
#
|
|
43
|
+
# For details about Config data management, See BaseConfig.
|
|
44
|
+
#
|
|
45
|
+
# Child Class:
|
|
46
|
+
# ------------
|
|
47
|
+
#
|
|
48
|
+
# This class can be enhanced with any kind of additional functionality.
|
|
49
|
+
#
|
|
50
|
+
# You can redefine following functions:
|
|
51
|
+
# exist?, [], []=, file, save, load, del.
|
|
52
|
+
#
|
|
53
|
+
# * Your child class can limit or re-organize config layers to query.
|
|
54
|
+
# Use :indexes or :names options to select which layer you want to query
|
|
55
|
+
# and call the core function.
|
|
56
|
+
#
|
|
57
|
+
# Ex: If you have 4 config levels and want to limit to 2 top ones
|
|
58
|
+
#
|
|
59
|
+
# def [](*keys)
|
|
60
|
+
# options = { keys: keys}
|
|
61
|
+
# options[:indexes] = [0, 1]
|
|
62
|
+
# _get(options)
|
|
63
|
+
# end
|
|
64
|
+
#
|
|
65
|
+
# Ex: If you have 4 config levels and want to limit to 2 names.
|
|
66
|
+
#
|
|
67
|
+
# def [](*keys)
|
|
68
|
+
# options = { keys: keys}
|
|
69
|
+
# options[:names] = ['local', 'default_app']
|
|
70
|
+
# _get(options)
|
|
71
|
+
# end
|
|
72
|
+
#
|
|
73
|
+
# * Your child class can force some levels options.
|
|
74
|
+
# Use :data_options to define each of them
|
|
75
|
+
#
|
|
76
|
+
# Ex: If your class has 4 levels. /:name is not updatable for level 1.
|
|
77
|
+
#
|
|
78
|
+
# def [](*keys)
|
|
79
|
+
# options = { keys: keys }
|
|
80
|
+
# # The following defines data_readonly for the config level 1
|
|
81
|
+
# if keys[0] == :name
|
|
82
|
+
# options[:data_options] = [nil, {data_readonly: true}]
|
|
83
|
+
# end
|
|
84
|
+
# _get(options)
|
|
85
|
+
# end
|
|
86
|
+
#
|
|
87
|
+
#
|
|
88
|
+
#
|
|
89
|
+
#
|
|
90
|
+
#
|
|
91
|
+
class CoreConfig
|
|
92
|
+
# exist?
|
|
93
|
+
#
|
|
94
|
+
# * *Args*
|
|
95
|
+
# - +keys+ : Array of key path to found
|
|
96
|
+
#
|
|
97
|
+
# * *Returns*
|
|
98
|
+
# - boolean : true if the key path was found
|
|
99
|
+
#
|
|
100
|
+
# Class child:
|
|
101
|
+
# A class child can redefine this function to increase default
|
|
102
|
+
# features.
|
|
103
|
+
#
|
|
104
|
+
def exist?(*keys)
|
|
105
|
+
_exist?(:keys => keys)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# where?
|
|
109
|
+
#
|
|
110
|
+
# * *Args*
|
|
111
|
+
# - +keys+ : Array of key path to found
|
|
112
|
+
#
|
|
113
|
+
# * *Returns*
|
|
114
|
+
# - boolean : true if the key path was found
|
|
115
|
+
#
|
|
116
|
+
def where?(*keys)
|
|
117
|
+
_where?(:keys => keys)
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# Get function
|
|
121
|
+
#
|
|
122
|
+
# * *Args*
|
|
123
|
+
# - +keys+ : Array of key path to found
|
|
124
|
+
#
|
|
125
|
+
# * *Returns*
|
|
126
|
+
# value found or nil.
|
|
127
|
+
#
|
|
128
|
+
def [](*keys)
|
|
129
|
+
_get(:keys => keys)
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
# Set function
|
|
133
|
+
#
|
|
134
|
+
# * *Args*
|
|
135
|
+
# - +keys+ : Array of key path to found
|
|
136
|
+
# * *Returns*
|
|
137
|
+
# - The value set or nil
|
|
138
|
+
#
|
|
139
|
+
# ex:
|
|
140
|
+
# value = CoreConfig.New
|
|
141
|
+
#
|
|
142
|
+
# value[:level1, :level2] = 'value'
|
|
143
|
+
# # => {:level1 => {:level2 => 'value'}}
|
|
144
|
+
def []=(*keys, value)
|
|
145
|
+
_set(:keys => keys, :value => value)
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
# Del function
|
|
149
|
+
#
|
|
150
|
+
# * *Args*
|
|
151
|
+
# - +keys+ : Array of key path to found and delete the last element.
|
|
152
|
+
# * *Returns*
|
|
153
|
+
# - The Hash updated.
|
|
154
|
+
#
|
|
155
|
+
# ex:
|
|
156
|
+
# value = CoreConfig.New
|
|
157
|
+
#
|
|
158
|
+
# value[:level1, :level2] = 'value'
|
|
159
|
+
# # => {:level1 => {:level2 => 'value'}}
|
|
160
|
+
# {:level1 => {:level2 => 'value'}}.del(:level1, :level2)
|
|
161
|
+
# # => {:level1 => {}}
|
|
162
|
+
def del(*keys)
|
|
163
|
+
_del(:keys => keys)
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
# Load from a file to the highest layer or a specific layer.
|
|
167
|
+
#
|
|
168
|
+
# * *Args* :
|
|
169
|
+
# - +options+ : Supported options for load
|
|
170
|
+
# - +:name+ : layer to get data.
|
|
171
|
+
# - +:index+: layer index to get data.
|
|
172
|
+
# If neither :name or :index is set, set will use the highest
|
|
173
|
+
# layer
|
|
174
|
+
#
|
|
175
|
+
# * *Returns* :
|
|
176
|
+
# -
|
|
177
|
+
# * *Raises* :
|
|
178
|
+
# - ++ ->
|
|
179
|
+
def load(options = {})
|
|
180
|
+
_load(options)
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
# Save to a file
|
|
184
|
+
#
|
|
185
|
+
# * *Args* :
|
|
186
|
+
# - +options+ : Supported options for save
|
|
187
|
+
# - +:name+ : layer to get data.
|
|
188
|
+
# - +:index+: layer index to get data.
|
|
189
|
+
# If neither :name or :index is set, set will use the highest
|
|
190
|
+
# layer
|
|
191
|
+
#
|
|
192
|
+
# * *Returns* :
|
|
193
|
+
# -
|
|
194
|
+
def save(options = {})
|
|
195
|
+
_save(options)
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
# Get/Set the file name.
|
|
199
|
+
#
|
|
200
|
+
# * *Args*
|
|
201
|
+
# - +:file+ : file name for the layer identified.
|
|
202
|
+
# - +options+ : Supported options for save
|
|
203
|
+
# - +:index+: layer index to get data.
|
|
204
|
+
# - +:name+ : layer to get data.
|
|
205
|
+
# If neither :name or :index is set, nil is returned.
|
|
206
|
+
#
|
|
207
|
+
# * *Returns*
|
|
208
|
+
# - The file name.
|
|
209
|
+
def file(filename = nil, options = {})
|
|
210
|
+
_file(filename, options)
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
def layers
|
|
214
|
+
result = []
|
|
215
|
+
@config_layers.each { | layer | result << layer[:name] }
|
|
216
|
+
result
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
def to_s
|
|
220
|
+
data = "Configs list ordered:\n"
|
|
221
|
+
@config_layers.each do | layer |
|
|
222
|
+
data += format("---- Config : %s ----\noptions: ", layer[:name])
|
|
223
|
+
|
|
224
|
+
if layer[:set]
|
|
225
|
+
data += 'data RW '
|
|
226
|
+
else
|
|
227
|
+
data += 'data RO '
|
|
228
|
+
end
|
|
229
|
+
data += format(", %s\n", to_s_file_opts(layer))
|
|
230
|
+
|
|
231
|
+
data += format("%s\n", layer[:config].to_s)
|
|
232
|
+
end
|
|
233
|
+
data
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
private
|
|
237
|
+
|
|
238
|
+
def to_s_file_opts(layer)
|
|
239
|
+
data = 'File '
|
|
240
|
+
if layer[:load] &&
|
|
241
|
+
if layer[:save]
|
|
242
|
+
data += 'RW'
|
|
243
|
+
else
|
|
244
|
+
data += 'RO'
|
|
245
|
+
end
|
|
246
|
+
data += ', filename updatable' if layer[:file_set]
|
|
247
|
+
else
|
|
248
|
+
data += 'None'
|
|
249
|
+
end
|
|
250
|
+
data
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
def _file_common_options_get(options)
|
|
254
|
+
options = {} if options.nil?
|
|
255
|
+
options[:names] = [options[:name]] if options.key?(:name)
|
|
256
|
+
options[:indexes] = [options[:index]] if options.key?(:index)
|
|
257
|
+
|
|
258
|
+
_common_options_get(options)
|
|
259
|
+
end
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
# Internal core functions
|
|
263
|
+
class CoreConfig
|
|
264
|
+
# *****************************************************
|
|
265
|
+
|
|
266
|
+
private
|
|
267
|
+
|
|
268
|
+
# *****************************************************
|
|
269
|
+
|
|
270
|
+
# _file? Core file function called by default by file.
|
|
271
|
+
#
|
|
272
|
+
# This function can be used by child class to set one layer file name
|
|
273
|
+
#
|
|
274
|
+
# * *Args*
|
|
275
|
+
# - +options+ : Hash parameters
|
|
276
|
+
# - +:name+ : layer to get data.
|
|
277
|
+
# - +:index+ : Array layer indexes to get data.
|
|
278
|
+
# If neither :name or :index is set, level 0 is used.
|
|
279
|
+
#
|
|
280
|
+
# * *Returns*
|
|
281
|
+
# - filename : if updated.
|
|
282
|
+
# OR
|
|
283
|
+
# - false : if not updated.
|
|
284
|
+
# OR
|
|
285
|
+
# - nil : If something went wrong.
|
|
286
|
+
#
|
|
287
|
+
# ex:
|
|
288
|
+
# { :test => {:titi => 'found'}}
|
|
289
|
+
def _file(filename = nil, options = {})
|
|
290
|
+
parameters = _file_common_options_get(options)
|
|
291
|
+
|
|
292
|
+
return nil if parameters.nil?
|
|
293
|
+
|
|
294
|
+
config_layers = parameters[0][0]
|
|
295
|
+
|
|
296
|
+
layer = config_layers[0]
|
|
297
|
+
|
|
298
|
+
return layer[:config].filename unless filename.is_a?(String)
|
|
299
|
+
|
|
300
|
+
return false if _filename_unsetable(layer)
|
|
301
|
+
|
|
302
|
+
layer[:config].filename = filename
|
|
303
|
+
filename
|
|
304
|
+
end
|
|
305
|
+
|
|
306
|
+
def _filename_unsetable(layer)
|
|
307
|
+
return true if !layer[:load] && !layer[:save]
|
|
308
|
+
|
|
309
|
+
!layer[:config].filename.nil? && !layer[:file_set]
|
|
310
|
+
end
|
|
311
|
+
|
|
312
|
+
# _exist? Core exist function called by default by exist?.
|
|
313
|
+
#
|
|
314
|
+
# * *Args*
|
|
315
|
+
# - +options+ : Hash parameters
|
|
316
|
+
# - +:keys+ : key tree to check existence in config layers
|
|
317
|
+
# - +:names+ : layer to get data.
|
|
318
|
+
# - +:indexes+ : Array layer indexes to get data.
|
|
319
|
+
# If neither :name or :index is set, get will search data
|
|
320
|
+
# per layers priority.
|
|
321
|
+
# - +:data_opts+ : Array or Hash. Define data options per layer.
|
|
322
|
+
#
|
|
323
|
+
# * *Returns*
|
|
324
|
+
# - boolean : true if the key path was found
|
|
325
|
+
#
|
|
326
|
+
# ex:
|
|
327
|
+
# { :test => {:titi => 'found'}}
|
|
328
|
+
def _exist?(options)
|
|
329
|
+
parameters = _common_options_get(options, [:keys])
|
|
330
|
+
return nil if parameters.nil?
|
|
331
|
+
|
|
332
|
+
config_layers, data_opts, keys = parameters[0]
|
|
333
|
+
|
|
334
|
+
return nil if keys.length == 0 || keys[0].nil? || config_layers[0].nil?
|
|
335
|
+
|
|
336
|
+
config_layers.each_index do | index |
|
|
337
|
+
config = @config_layers[index][:config]
|
|
338
|
+
|
|
339
|
+
data_options = options.clone
|
|
340
|
+
data_options.delete_if do |key|
|
|
341
|
+
[:keys, :names, :indexes, :name, :index].include?(key)
|
|
342
|
+
end
|
|
343
|
+
data_options.merge!(data_opts[index])
|
|
344
|
+
|
|
345
|
+
config.data_options(data_options)
|
|
346
|
+
return true if config.exist?(*keys)
|
|
347
|
+
end
|
|
348
|
+
false
|
|
349
|
+
end
|
|
350
|
+
|
|
351
|
+
# _where? called by default by where
|
|
352
|
+
#
|
|
353
|
+
# - +options+ : Hash parameters
|
|
354
|
+
# - +:keys+ : key tree to check existence in config layers
|
|
355
|
+
# - +:names+ : layer to get data.
|
|
356
|
+
# - +:indexes+ : Array layer indexes to get data.
|
|
357
|
+
# If neither :name or :index is set, get will search data
|
|
358
|
+
# per layers priority.
|
|
359
|
+
# - +:data_opts+ : Array or Hash. Define data options per layer.
|
|
360
|
+
#
|
|
361
|
+
# * *Returns*
|
|
362
|
+
# - array of config name : list of first layers where the key was found.
|
|
363
|
+
# OR
|
|
364
|
+
# - nil can be returned for several reasons:
|
|
365
|
+
# - keys is not an array
|
|
366
|
+
# - keys array is empty.
|
|
367
|
+
|
|
368
|
+
#
|
|
369
|
+
# ex:
|
|
370
|
+
# { :test => {:titi => 'found'}}
|
|
371
|
+
def _where?(options)
|
|
372
|
+
parameters = _common_options_get(options, [:keys])
|
|
373
|
+
return nil if parameters.nil?
|
|
374
|
+
|
|
375
|
+
config_layers, data_opts, keys = parameters[0]
|
|
376
|
+
|
|
377
|
+
return nil if keys.length == 0 || keys[0].nil? || config_layers[0].nil?
|
|
378
|
+
|
|
379
|
+
_do_where?(config_layers, keys, options, data_opts)
|
|
380
|
+
end
|
|
381
|
+
|
|
382
|
+
def _do_where?(config_layers, keys, options, data_opts)
|
|
383
|
+
layer_indexes = []
|
|
384
|
+
config_layers.each_index do | index |
|
|
385
|
+
config = @config_layers[index][:config]
|
|
386
|
+
|
|
387
|
+
data_options = options.clone
|
|
388
|
+
data_options.delete_if do |key|
|
|
389
|
+
[:keys, :names, :indexes, :name, :index].include?(key)
|
|
390
|
+
end
|
|
391
|
+
data_options.merge!(data_opts[index]) if data_opts[index].is_a?(Hash)
|
|
392
|
+
|
|
393
|
+
config.data_options(data_options)
|
|
394
|
+
layer_indexes << @config_layers[index][:name] if config.exist?(keys)
|
|
395
|
+
end
|
|
396
|
+
return layer_indexes if layer_indexes.length > 0
|
|
397
|
+
false
|
|
398
|
+
end
|
|
399
|
+
# Get function called by default by []
|
|
400
|
+
#
|
|
401
|
+
# * *Args*
|
|
402
|
+
# - +options+ : Hash of how to get the data
|
|
403
|
+
# - +:keys+ : Array of key path to found
|
|
404
|
+
# - +:names+ : layer to get data.
|
|
405
|
+
# - +:indexes+ : Array layer indexes to get data.
|
|
406
|
+
# If neither :name or :index is set, get will search data
|
|
407
|
+
# per layers priority.
|
|
408
|
+
# - +:data_opts+ : Array or Hash. Define data options per layer.
|
|
409
|
+
#
|
|
410
|
+
# * *Returns*
|
|
411
|
+
# value found or nil.
|
|
412
|
+
# nil can be returned for several reasons:
|
|
413
|
+
# - keys is not an array
|
|
414
|
+
# - keys array is empty.
|
|
415
|
+
#
|
|
416
|
+
def _get(options)
|
|
417
|
+
parameters = _common_options_get(options, [:keys])
|
|
418
|
+
return nil if parameters.nil?
|
|
419
|
+
|
|
420
|
+
config_layers, data_opts, keys = parameters[0]
|
|
421
|
+
|
|
422
|
+
return nil if keys.length == 0 || keys[0].nil? || config_layers[0].nil?
|
|
423
|
+
|
|
424
|
+
config_layers.each_index do | layer_index |
|
|
425
|
+
layer = config_layers[layer_index]
|
|
426
|
+
|
|
427
|
+
data_options = options.clone
|
|
428
|
+
data_options.delete_if do |key|
|
|
429
|
+
[:keys, :names, :indexes, :name, :index].include?(key)
|
|
430
|
+
end
|
|
431
|
+
data_options = data_options.merge!(data_opts[layer_index])
|
|
432
|
+
|
|
433
|
+
layer[:config].data_options(data_options)
|
|
434
|
+
return layer[:config][*keys] if layer[:config].exist?(*keys)
|
|
435
|
+
end
|
|
436
|
+
nil
|
|
437
|
+
end
|
|
438
|
+
|
|
439
|
+
# Set function called by default by []=
|
|
440
|
+
#
|
|
441
|
+
# * *Args*
|
|
442
|
+
# - +options+ : Hash of how to get the data
|
|
443
|
+
# - +:value+: Value to set
|
|
444
|
+
# - +:keys+ : Array of key path to found
|
|
445
|
+
# - +:name+ : layer to get data.
|
|
446
|
+
# - +:index+: layer index to get data.
|
|
447
|
+
# If neither :name or :index is set, set will use the highest
|
|
448
|
+
# layer
|
|
449
|
+
# - +:data_opts+ : Array or Hash. Define data options per layer.
|
|
450
|
+
#
|
|
451
|
+
# * *Returns*
|
|
452
|
+
# - The value set.
|
|
453
|
+
# OR
|
|
454
|
+
# - nil can be returned for several reasons:
|
|
455
|
+
# - layer options :set is false
|
|
456
|
+
# - options defines a :data_readonly to true.
|
|
457
|
+
# - value is nil
|
|
458
|
+
# - keys is not an array
|
|
459
|
+
# - keys array is empty.
|
|
460
|
+
#
|
|
461
|
+
# ex:
|
|
462
|
+
# value = CoreConfig.New
|
|
463
|
+
#
|
|
464
|
+
# value[:level1, :level2] = 'value'
|
|
465
|
+
# # => {:level1 => {:level2 => 'value'}}
|
|
466
|
+
def _set(options)
|
|
467
|
+
parameters = _common_options_get(options, [:keys, :value])
|
|
468
|
+
return nil if parameters.nil?
|
|
469
|
+
|
|
470
|
+
config_layers, data_opts, keys, value = parameters[0]
|
|
471
|
+
|
|
472
|
+
# get data options for level 0
|
|
473
|
+
data_options = options.clone.merge!(data_opts[0])
|
|
474
|
+
|
|
475
|
+
return nil if keys.length == 0 || keys[0].nil? || config_layers[0].nil?
|
|
476
|
+
|
|
477
|
+
data_options.delete_if do |key|
|
|
478
|
+
[:keys, :names, :indexes, :name, :index, :value].include?(key)
|
|
479
|
+
end
|
|
480
|
+
|
|
481
|
+
return nil unless @config_layers[0][:set]
|
|
482
|
+
|
|
483
|
+
config_layer = config_layers[0][:config]
|
|
484
|
+
config_layer.data_options(data_options)
|
|
485
|
+
config_layer[keys] = value
|
|
486
|
+
end
|
|
487
|
+
|
|
488
|
+
# Del function called by default by del
|
|
489
|
+
#
|
|
490
|
+
# * *Args*
|
|
491
|
+
# - +options+ : Hash of how to get the data
|
|
492
|
+
# - +:keys+ : Array of key path to found
|
|
493
|
+
# - +:name+ : layer to get data.
|
|
494
|
+
# - +:index+ : layer index to get data.
|
|
495
|
+
# If neither :name or :index is set, set will use the
|
|
496
|
+
# highest layer
|
|
497
|
+
# - +:data_opts+ : Array or Hash. Define data options per layer.
|
|
498
|
+
#
|
|
499
|
+
# * *Returns*
|
|
500
|
+
# - The value attached to the key deleted.
|
|
501
|
+
# OR
|
|
502
|
+
# - nil can be returned for several reasons:
|
|
503
|
+
# - value is nil
|
|
504
|
+
# - keys is not an array
|
|
505
|
+
# - keys array is empty.
|
|
506
|
+
#
|
|
507
|
+
# ex:
|
|
508
|
+
# value = CoreConfig.New
|
|
509
|
+
#
|
|
510
|
+
# value[:level1, :level2] = 'value'
|
|
511
|
+
# # => {:level1 => {:level2 => 'value'}}
|
|
512
|
+
#
|
|
513
|
+
# value.del(:keys => [:level1, :level2])
|
|
514
|
+
# # => {:level1 => {}}
|
|
515
|
+
def _del(options)
|
|
516
|
+
parameters = _common_options_get(options, [:keys])
|
|
517
|
+
return nil if parameters.nil?
|
|
518
|
+
|
|
519
|
+
config_layers, data_opts, keys = parameters[0]
|
|
520
|
+
|
|
521
|
+
# get data options for level 0
|
|
522
|
+
data_options = options.clone.merge!(data_opts[0])
|
|
523
|
+
|
|
524
|
+
return nil if keys.length == 0
|
|
525
|
+
|
|
526
|
+
data_options.delete_if do |key|
|
|
527
|
+
[:keys, :names, :indexes, :name, :index].include?(key)
|
|
528
|
+
end
|
|
529
|
+
|
|
530
|
+
return nil unless @config_layers[0][:set]
|
|
531
|
+
|
|
532
|
+
config_layers[0][:config].data_options(data_options)
|
|
533
|
+
config_layers[0][:config].del(keys)
|
|
534
|
+
end
|
|
535
|
+
|
|
536
|
+
# Load from a file called by default by load.
|
|
537
|
+
#
|
|
538
|
+
# * *Args* :
|
|
539
|
+
# - +options+ : Supported options for load
|
|
540
|
+
# - +:name+ : layer name to get data.
|
|
541
|
+
# - +:index+ : layer index to get data.
|
|
542
|
+
# If neither :name or :index is set, set will use the highest
|
|
543
|
+
# layer.
|
|
544
|
+
#
|
|
545
|
+
# * *Returns* :
|
|
546
|
+
# - true : loaded
|
|
547
|
+
# - false: not loaded. There are several possible reasons:
|
|
548
|
+
# - input/output issue (normally raised)
|
|
549
|
+
# - layer option :load is false.
|
|
550
|
+
def _load(options = {})
|
|
551
|
+
options = {} if options.nil?
|
|
552
|
+
options[:names] = [options[:name]] if options.key?(:name)
|
|
553
|
+
options[:indexes] = [options[:index]] if options.key?(:index)
|
|
554
|
+
|
|
555
|
+
parameters = _file_common_options_get(options)
|
|
556
|
+
return nil if parameters.nil?
|
|
557
|
+
|
|
558
|
+
config_layers = parameters[0][0]
|
|
559
|
+
|
|
560
|
+
return nil unless config_layers[0][:load]
|
|
561
|
+
|
|
562
|
+
config_layers[0][:config].load
|
|
563
|
+
end
|
|
564
|
+
|
|
565
|
+
# Save to a file called by default by save
|
|
566
|
+
#
|
|
567
|
+
# * *Args* :
|
|
568
|
+
# - +options+ : Supported options for save
|
|
569
|
+
# - +:name+ : layer to get data.
|
|
570
|
+
# - +:index+: layer index to get data.
|
|
571
|
+
# If neither :name or :index is set, set will use the highest
|
|
572
|
+
# layer
|
|
573
|
+
#
|
|
574
|
+
# * *Returns* :
|
|
575
|
+
# - true : saved
|
|
576
|
+
# - false: not saved. There are several possible reasons:
|
|
577
|
+
# - options defines a :file_readonly to true.
|
|
578
|
+
# - input/output issue (normally raised)
|
|
579
|
+
# - layer option :save is false.
|
|
580
|
+
def _save(options = {})
|
|
581
|
+
options[:names] = [options[:name]] if options.key?(:name)
|
|
582
|
+
options[:indexes] = [options[:index]] if options.key?(:index)
|
|
583
|
+
|
|
584
|
+
parameters = _file_common_options_get(options)
|
|
585
|
+
return nil if parameters.nil?
|
|
586
|
+
|
|
587
|
+
config_layers = parameters[0][0]
|
|
588
|
+
|
|
589
|
+
return nil unless config_layers[0][:save]
|
|
590
|
+
|
|
591
|
+
config_layers[0][:config].save
|
|
592
|
+
end
|
|
593
|
+
end
|
|
594
|
+
|
|
595
|
+
# Internal functions
|
|
596
|
+
class CoreConfig
|
|
597
|
+
# initialize CoreConfig
|
|
598
|
+
#
|
|
599
|
+
# * *Args*
|
|
600
|
+
# - +config_layers+ : Array config layers configuration.
|
|
601
|
+
# Each layer options have those options:
|
|
602
|
+
# - :config : optional. See `Defining Config layer instance` for details
|
|
603
|
+
# - :name : required. String. Name of the config layer.
|
|
604
|
+
# Warning! unique name on layers is no tested.
|
|
605
|
+
# - :set : boolean. True if authorized. Default is True.
|
|
606
|
+
# - :load : boolean. True if authorized. Default is False.
|
|
607
|
+
# - :save : boolean. True if authorized. Default is False.
|
|
608
|
+
# - :file_set : boolean. True if authorized to update a filename.
|
|
609
|
+
# Default is False.
|
|
610
|
+
#
|
|
611
|
+
# each layers can defines some options for the layer to behave differently
|
|
612
|
+
# CoreConfig call a layer data_options to set some options, before
|
|
613
|
+
# exist?, get or [], set or []=, save and load functions.
|
|
614
|
+
# See BaseConfig::data_options for predefined options.
|
|
615
|
+
#
|
|
616
|
+
# Core config provides some private additionnal functions for
|
|
617
|
+
# child class functions:
|
|
618
|
+
# - _set_data_options(layers, options) - To set data_options on one or
|
|
619
|
+
# more config layers
|
|
620
|
+
# - _get(options) - core get function
|
|
621
|
+
# - _set(options) - core set function
|
|
622
|
+
# - _save(options) - core save function
|
|
623
|
+
# - _load(options) - core load function
|
|
624
|
+
#
|
|
625
|
+
# if +config_layers+ is not provided, CoreConfig will instanciate a runtime
|
|
626
|
+
# like system:
|
|
627
|
+
# config = CoreConfig.New
|
|
628
|
+
# # is equivalent as :
|
|
629
|
+
# config_layers = [{name: 'runtime',
|
|
630
|
+
# config: PRC::BaseConfig.new, set: true}]
|
|
631
|
+
# config = CoreConfig.New(config_layers)
|
|
632
|
+
#
|
|
633
|
+
# Defining Config layer instance:
|
|
634
|
+
# -------------------------------
|
|
635
|
+
#
|
|
636
|
+
# :config value requires it to be of type 'BaseConfig'
|
|
637
|
+
# By default, it uses `:config => PRC::BaseConfig.new`
|
|
638
|
+
# Instead, you can set:
|
|
639
|
+
# * directly BaseConfig. `:config => PRC::BaseConfig.new`
|
|
640
|
+
# * a child based on BaseConfig. `:config => MyConfig.new`
|
|
641
|
+
# * some predefined enhanced BaseConfig:
|
|
642
|
+
# * PRC::SectionConfig. See prc_section_config.rb.
|
|
643
|
+
# `:config => PRC::SectionConfig.new`
|
|
644
|
+
#
|
|
645
|
+
def initialize(config_layers = nil)
|
|
646
|
+
if config_layers.nil?
|
|
647
|
+
config_layers = []
|
|
648
|
+
config_layers << CoreConfig.define_layer
|
|
649
|
+
end
|
|
650
|
+
initialize_layers(config_layers)
|
|
651
|
+
end
|
|
652
|
+
|
|
653
|
+
def self.define_layer(options = {})
|
|
654
|
+
attributes = [:name, :config, :set, :load, :save, :file_set]
|
|
655
|
+
|
|
656
|
+
layer = {}
|
|
657
|
+
|
|
658
|
+
attributes.each do | attribute |
|
|
659
|
+
if options.key?(attribute)
|
|
660
|
+
layer[attribute] = options[attribute]
|
|
661
|
+
else
|
|
662
|
+
layer[attribute] = case attribute
|
|
663
|
+
when :name
|
|
664
|
+
'runtime'
|
|
665
|
+
when :config
|
|
666
|
+
PRC::BaseConfig.new
|
|
667
|
+
when :set
|
|
668
|
+
true
|
|
669
|
+
else
|
|
670
|
+
false
|
|
671
|
+
end
|
|
672
|
+
end
|
|
673
|
+
end
|
|
674
|
+
layer
|
|
675
|
+
end
|
|
676
|
+
|
|
677
|
+
# Function to initialize Config layers.
|
|
678
|
+
#
|
|
679
|
+
# *Args*
|
|
680
|
+
# - +config_layers+ : Array of config layers.
|
|
681
|
+
# First layer is the deepest config object.
|
|
682
|
+
# last layer is the first config object queried.
|
|
683
|
+
#
|
|
684
|
+
# Ex: If we define 2 config layer:
|
|
685
|
+
# local = PRC::BaseConfig.new(:test => :found_local)
|
|
686
|
+
# runtime = PRC::BaseConfig.new(:test => :found_runtime)
|
|
687
|
+
# layers = []
|
|
688
|
+
# layers << CoreConfig.define_layer(name: 'local', config: local )
|
|
689
|
+
# layers << CoreConfig.define_layer(name: 'runtime', config: runtime )
|
|
690
|
+
# config = PRC::CoreConfig.new
|
|
691
|
+
# config.initialize_layers(layers)
|
|
692
|
+
#
|
|
693
|
+
# p config[:test] # => :found_runtime
|
|
694
|
+
#
|
|
695
|
+
# config[:test] = "where?"
|
|
696
|
+
# p config.where?(:test) # => ["runtime", "local"]
|
|
697
|
+
#
|
|
698
|
+
# config.del(:test)
|
|
699
|
+
# p config.where?(:test) # => ["local"]
|
|
700
|
+
# p config[:test] # => :found_local
|
|
701
|
+
#
|
|
702
|
+
# config[:test] = "and now?"
|
|
703
|
+
# p config.where?(:test) # => ["runtime", "local"]
|
|
704
|
+
#
|
|
705
|
+
def initialize_layers(config_layers = nil)
|
|
706
|
+
@config_layers = []
|
|
707
|
+
|
|
708
|
+
config_layers.each do | layer |
|
|
709
|
+
next unless layer.is_a?(Hash) && layer.key?(:config) &&
|
|
710
|
+
layer[:config].is_a?(BaseConfig)
|
|
711
|
+
next unless layer[:name].is_a?(String)
|
|
712
|
+
@config_layers << initialize_layer(layer)
|
|
713
|
+
end
|
|
714
|
+
@config_layers.reverse!
|
|
715
|
+
end
|
|
716
|
+
|
|
717
|
+
def initialize_layer(layer)
|
|
718
|
+
newlayer = { :config => layer[:config], :name => layer[:name] }
|
|
719
|
+
newlayer[:set] = layer[:set].boolean? ? layer[:set] : true
|
|
720
|
+
newlayer[:load] = layer[:load].boolean? ? layer[:load] : false
|
|
721
|
+
newlayer[:save] = layer[:save].boolean? ? layer[:save] : false
|
|
722
|
+
newlayer[:file_set] = layer[:file_set].boolean? ? layer[:file_set] : false
|
|
723
|
+
newlayer
|
|
724
|
+
end
|
|
725
|
+
|
|
726
|
+
# layer_indexes function
|
|
727
|
+
#
|
|
728
|
+
# * *Args*
|
|
729
|
+
# - +:name+ : layer to identify.
|
|
730
|
+
#
|
|
731
|
+
# * *Returns*
|
|
732
|
+
# first index found or nil.
|
|
733
|
+
#
|
|
734
|
+
def _layer_indexes(names)
|
|
735
|
+
names = [names] if names.is_a?(String)
|
|
736
|
+
return nil unless names.is_a?(Array)
|
|
737
|
+
|
|
738
|
+
layers = []
|
|
739
|
+
|
|
740
|
+
names.each do | name |
|
|
741
|
+
index = layer_index(name)
|
|
742
|
+
layers << index unless index.nil?
|
|
743
|
+
end
|
|
744
|
+
return layers if layers.length > 0
|
|
745
|
+
nil
|
|
746
|
+
end
|
|
747
|
+
|
|
748
|
+
# layer_index function
|
|
749
|
+
#
|
|
750
|
+
# * *Args*
|
|
751
|
+
# - +:name+ : layer to identify.
|
|
752
|
+
#
|
|
753
|
+
# * *Returns*
|
|
754
|
+
# first index found or nil.
|
|
755
|
+
#
|
|
756
|
+
def layer_index(name)
|
|
757
|
+
return nil unless name.is_a?(String)
|
|
758
|
+
return nil if @config_layers.nil?
|
|
759
|
+
|
|
760
|
+
@config_layers.each_index do | index |
|
|
761
|
+
return index if @config_layers[index][:name] == name
|
|
762
|
+
end
|
|
763
|
+
nil
|
|
764
|
+
end
|
|
765
|
+
|
|
766
|
+
# Check and returns values of options required and optionnal.
|
|
767
|
+
#
|
|
768
|
+
# * *Args*
|
|
769
|
+
# - +options+ : options to extract information.
|
|
770
|
+
# - +required+ : Array of required option keys.
|
|
771
|
+
# - +optionnal+ : Array of optionnal option keys.
|
|
772
|
+
#
|
|
773
|
+
# * *Returns*
|
|
774
|
+
# - nil if at least one required keys doesn't exist
|
|
775
|
+
# - Array of combined required and optionnql values.
|
|
776
|
+
#
|
|
777
|
+
def _valid_options(options, required, optionnal = [])
|
|
778
|
+
return nil unless options.is_a?(Hash)
|
|
779
|
+
return nil unless required.is_a?(Array)
|
|
780
|
+
optionnal = [] unless optionnal.is_a?(Array)
|
|
781
|
+
|
|
782
|
+
result = [[], []]
|
|
783
|
+
|
|
784
|
+
required.each do | key |
|
|
785
|
+
return nil unless options.key?(key)
|
|
786
|
+
result[0] << options[key]
|
|
787
|
+
end
|
|
788
|
+
|
|
789
|
+
optionnal.each { | key | result[1] << options[key] }
|
|
790
|
+
|
|
791
|
+
result
|
|
792
|
+
end
|
|
793
|
+
|
|
794
|
+
# Take care of keys, indexes and names.
|
|
795
|
+
# if names if found, it will replace indexes.
|
|
796
|
+
def _common_options_get(options, required = [], optionnal = [])
|
|
797
|
+
return nil unless options.is_a?(Hash)
|
|
798
|
+
required = [] unless required.is_a?(Array)
|
|
799
|
+
optionnal = [] unless optionnal.is_a?(Array)
|
|
800
|
+
|
|
801
|
+
result = _valid_options(options, required,
|
|
802
|
+
[:indexes, :names,
|
|
803
|
+
:data_options].concat(optionnal))
|
|
804
|
+
# result Array is structured as:
|
|
805
|
+
# required [0] => [...]
|
|
806
|
+
# optional [1] => [indexes, names, data_options, ...]
|
|
807
|
+
|
|
808
|
+
# Following eliminates the optional :names (1) element
|
|
809
|
+
_set_indexes result
|
|
810
|
+
# required [0] => [...]
|
|
811
|
+
# optional [1] => [indexes, data_options, ...]
|
|
812
|
+
return nil if _keys_data_missing(options, required, result)
|
|
813
|
+
|
|
814
|
+
# Following eliminates the optional :indexes (0) element
|
|
815
|
+
# But add it as required in the Array, at pos 0
|
|
816
|
+
_build_layers(result)
|
|
817
|
+
# required [0] => [layers, ...]
|
|
818
|
+
# optional [1] => [data_options, ...]
|
|
819
|
+
|
|
820
|
+
# following eliminates the optional :data_options (0) element
|
|
821
|
+
# But data_options is added in required Array, at pos 1.
|
|
822
|
+
_set_data_opts(result)
|
|
823
|
+
# required [0] => [layers, data_options, ...]
|
|
824
|
+
# optional [1] => [...]
|
|
825
|
+
|
|
826
|
+
result
|
|
827
|
+
end
|
|
828
|
+
|
|
829
|
+
def _keys_data_missing(options, required, result)
|
|
830
|
+
return false unless required[0] == :keys
|
|
831
|
+
|
|
832
|
+
return true unless options.key?(:keys)
|
|
833
|
+
return true unless result[0][0].is_a?(Array)
|
|
834
|
+
return true if result[0][0].length == 0
|
|
835
|
+
false
|
|
836
|
+
end
|
|
837
|
+
|
|
838
|
+
# Setting indexes from names or indexes.
|
|
839
|
+
def _set_indexes(result)
|
|
840
|
+
names_indexes = _layer_indexes(result[1][1])
|
|
841
|
+
# replaced indexes by names indexes if exists.
|
|
842
|
+
result[1][0] = names_indexes if names_indexes
|
|
843
|
+
result[1].delete_at(1)
|
|
844
|
+
end
|
|
845
|
+
|
|
846
|
+
def _set_data_opts(result)
|
|
847
|
+
data_opts = []
|
|
848
|
+
|
|
849
|
+
result[0][0].each_index do | layer_index |
|
|
850
|
+
data_options = result[1][0][layer_index] if result[1][0].is_a?(Array)
|
|
851
|
+
data_options = {} unless data_options.is_a?(Hash)
|
|
852
|
+
data_opts << data_options
|
|
853
|
+
end
|
|
854
|
+
result[0].insert(1, data_opts)
|
|
855
|
+
|
|
856
|
+
# And removing the optionnal :data_options
|
|
857
|
+
result[1].delete_at(0)
|
|
858
|
+
end
|
|
859
|
+
|
|
860
|
+
def _build_layers(result)
|
|
861
|
+
# Setting layers at required [0]
|
|
862
|
+
if result[1][0].nil? || result[1][0].length == 0
|
|
863
|
+
config_layers = @config_layers
|
|
864
|
+
else
|
|
865
|
+
config_layers = []
|
|
866
|
+
result[1][0].each do | index |
|
|
867
|
+
config_layers << @config_layers[index] if index.is_a?(Fixnum)
|
|
868
|
+
end
|
|
869
|
+
config_layers = @config_layers if config_layers.length == 0
|
|
870
|
+
end
|
|
871
|
+
result[0].insert(0, config_layers)
|
|
872
|
+
|
|
873
|
+
# And removing the optionnal indexes
|
|
874
|
+
result[1].delete_at(0)
|
|
875
|
+
result
|
|
876
|
+
end
|
|
877
|
+
end
|
|
878
|
+
end
|