leap_cli 1.8.1 → 1.9
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/bin/leap +6 -12
- data/lib/leap_cli.rb +3 -23
- data/lib/leap_cli/bootstrap.rb +36 -12
- data/lib/leap_cli/commands/common.rb +88 -46
- data/lib/leap_cli/commands/new.rb +24 -17
- data/lib/leap_cli/commands/pre.rb +3 -1
- data/lib/leap_cli/core_ext/hash.rb +19 -0
- data/lib/leap_cli/leapfile.rb +47 -32
- data/lib/leap_cli/log.rb +196 -88
- data/lib/leap_cli/path.rb +5 -5
- data/lib/leap_cli/util.rb +28 -18
- data/lib/leap_cli/version.rb +8 -3
- data/vendor/acme-client/lib/acme-client.rb +1 -0
- data/vendor/acme-client/lib/acme/client.rb +122 -0
- data/vendor/acme-client/lib/acme/client/certificate.rb +30 -0
- data/vendor/acme-client/lib/acme/client/certificate_request.rb +111 -0
- data/vendor/acme-client/lib/acme/client/crypto.rb +98 -0
- data/vendor/acme-client/lib/acme/client/error.rb +16 -0
- data/vendor/acme-client/lib/acme/client/faraday_middleware.rb +123 -0
- data/vendor/acme-client/lib/acme/client/resources.rb +5 -0
- data/vendor/acme-client/lib/acme/client/resources/authorization.rb +44 -0
- data/vendor/acme-client/lib/acme/client/resources/challenges.rb +6 -0
- data/vendor/acme-client/lib/acme/client/resources/challenges/base.rb +43 -0
- data/vendor/acme-client/lib/acme/client/resources/challenges/dns01.rb +19 -0
- data/vendor/acme-client/lib/acme/client/resources/challenges/http01.rb +18 -0
- data/vendor/acme-client/lib/acme/client/resources/challenges/tls_sni01.rb +24 -0
- data/vendor/acme-client/lib/acme/client/resources/registration.rb +37 -0
- data/vendor/acme-client/lib/acme/client/self_sign_certificate.rb +60 -0
- data/vendor/acme-client/lib/acme/client/version.rb +7 -0
- data/vendor/base32/lib/base32.rb +67 -0
- data/vendor/certificate_authority/lib/certificate_authority.rb +2 -1
- data/vendor/certificate_authority/lib/certificate_authority/certificate.rb +4 -4
- data/vendor/certificate_authority/lib/certificate_authority/certificate_revocation_list.rb +7 -5
- data/vendor/certificate_authority/lib/certificate_authority/core_extensions.rb +46 -0
- data/vendor/certificate_authority/lib/certificate_authority/distinguished_name.rb +6 -2
- data/vendor/certificate_authority/lib/certificate_authority/extensions.rb +10 -3
- data/vendor/certificate_authority/lib/certificate_authority/key_material.rb +11 -9
- data/vendor/certificate_authority/lib/certificate_authority/ocsp_handler.rb +3 -3
- data/vendor/certificate_authority/lib/certificate_authority/pkcs11_key_material.rb +0 -2
- data/vendor/certificate_authority/lib/certificate_authority/serial_number.rb +8 -2
- data/vendor/certificate_authority/lib/certificate_authority/validations.rb +31 -0
- data/vendor/rsync_command/lib/rsync_command.rb +49 -12
- metadata +50 -91
- data/lib/leap/platform.rb +0 -90
- data/lib/leap_cli/config/environment.rb +0 -180
- data/lib/leap_cli/config/filter.rb +0 -178
- data/lib/leap_cli/config/manager.rb +0 -419
- data/lib/leap_cli/config/node.rb +0 -77
- data/lib/leap_cli/config/object.rb +0 -428
- data/lib/leap_cli/config/object_list.rb +0 -209
- data/lib/leap_cli/config/provider.rb +0 -22
- data/lib/leap_cli/config/secrets.rb +0 -87
- data/lib/leap_cli/config/sources.rb +0 -11
- data/lib/leap_cli/config/tag.rb +0 -25
- data/lib/leap_cli/lib_ext/capistrano_connections.rb +0 -16
- data/lib/leap_cli/logger.rb +0 -237
- data/lib/leap_cli/remote/leap_plugin.rb +0 -192
- data/lib/leap_cli/remote/puppet_plugin.rb +0 -26
- data/lib/leap_cli/remote/rsync_plugin.rb +0 -35
- data/lib/leap_cli/remote/tasks.rb +0 -51
- data/lib/leap_cli/ssh_key.rb +0 -195
- data/lib/leap_cli/util/remote_command.rb +0 -158
- data/lib/leap_cli/util/secret.rb +0 -55
- data/lib/leap_cli/util/x509.rb +0 -33
data/lib/leap_cli/config/node.rb
DELETED
@@ -1,77 +0,0 @@
|
|
1
|
-
#
|
2
|
-
# Configuration for a 'node' (a server in the provider's infrastructure)
|
3
|
-
#
|
4
|
-
|
5
|
-
require 'ipaddr'
|
6
|
-
|
7
|
-
module LeapCli; module Config
|
8
|
-
|
9
|
-
class Node < Object
|
10
|
-
attr_accessor :file_paths
|
11
|
-
|
12
|
-
def initialize(environment=nil)
|
13
|
-
super(environment)
|
14
|
-
@node = self
|
15
|
-
@file_paths = []
|
16
|
-
end
|
17
|
-
|
18
|
-
#
|
19
|
-
# returns true if this node has an ip address in the range of the vagrant network
|
20
|
-
#
|
21
|
-
def vagrant?
|
22
|
-
begin
|
23
|
-
vagrant_range = IPAddr.new LeapCli.leapfile.vagrant_network
|
24
|
-
rescue ArgumentError => exc
|
25
|
-
Util::bail! { Util::log :invalid, "ip address '#{@node.ip_address}' vagrant.network" }
|
26
|
-
end
|
27
|
-
|
28
|
-
begin
|
29
|
-
ip_address = IPAddr.new @node.get('ip_address')
|
30
|
-
rescue ArgumentError => exc
|
31
|
-
Util::log :warning, "invalid ip address '#{@node.get('ip_address')}' for node '#{@node.name}'"
|
32
|
-
end
|
33
|
-
return vagrant_range.include?(ip_address)
|
34
|
-
end
|
35
|
-
|
36
|
-
#
|
37
|
-
# Return a hash table representation of ourselves, with the key equal to the @node.name,
|
38
|
-
# and the value equal to the fields specified in *keys.
|
39
|
-
#
|
40
|
-
# Also, the result is flattened to a single hash, so a key of 'a.b' becomes 'a_b'
|
41
|
-
#
|
42
|
-
# compare to Object#pick(*keys). This method is the sames as Config::ObjectList#pick_fields,
|
43
|
-
# but works on a single node.
|
44
|
-
#
|
45
|
-
# Example:
|
46
|
-
#
|
47
|
-
# node.pick('domain.internal') =>
|
48
|
-
#
|
49
|
-
# {
|
50
|
-
# 'node1': {
|
51
|
-
# 'domain_internal': 'node1.example.i'
|
52
|
-
# }
|
53
|
-
# }
|
54
|
-
#
|
55
|
-
def pick_fields(*keys)
|
56
|
-
{@node.name => self.pick(*keys)}
|
57
|
-
end
|
58
|
-
|
59
|
-
#
|
60
|
-
# can be overridden by the platform.
|
61
|
-
# returns a list of node names that should be tested before this node
|
62
|
-
#
|
63
|
-
def test_dependencies
|
64
|
-
[]
|
65
|
-
end
|
66
|
-
|
67
|
-
# returns a string list of supported ssh host key algorithms for this node.
|
68
|
-
# or an empty string if it could not be determined
|
69
|
-
def supported_ssh_host_key_algorithms
|
70
|
-
@host_key_algo ||= SshKey.supported_host_key_algorithms(
|
71
|
-
Util.read_file([:node_ssh_pub_key, @node.name])
|
72
|
-
)
|
73
|
-
end
|
74
|
-
|
75
|
-
end
|
76
|
-
|
77
|
-
end; end
|
@@ -1,428 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
require 'erb'
|
4
|
-
require 'json/pure' # pure ruby implementation is required for our sorted trick to work.
|
5
|
-
|
6
|
-
if $ruby_version < [1,9]
|
7
|
-
$KCODE = 'UTF8'
|
8
|
-
end
|
9
|
-
require 'ya2yaml' # pure ruby yaml
|
10
|
-
|
11
|
-
module LeapCli
|
12
|
-
module Config
|
13
|
-
|
14
|
-
#
|
15
|
-
# This class represents the configuration for a single node, service, or tag.
|
16
|
-
# Also, all the nested hashes are also of this type.
|
17
|
-
#
|
18
|
-
# It is called 'object' because it corresponds to an Object in JSON.
|
19
|
-
#
|
20
|
-
class Object < Hash
|
21
|
-
|
22
|
-
attr_reader :env
|
23
|
-
attr_reader :node
|
24
|
-
|
25
|
-
def initialize(environment=nil, node=nil)
|
26
|
-
raise ArgumentError unless environment.nil? || environment.is_a?(Config::Environment)
|
27
|
-
@env = environment
|
28
|
-
# an object that is a node as @node equal to self, otherwise all the
|
29
|
-
# child objects point back to the top level node.
|
30
|
-
@node = node || self
|
31
|
-
end
|
32
|
-
|
33
|
-
def manager
|
34
|
-
@env.manager
|
35
|
-
end
|
36
|
-
|
37
|
-
#
|
38
|
-
# TODO: deprecate node.global()
|
39
|
-
#
|
40
|
-
def global
|
41
|
-
@env
|
42
|
-
end
|
43
|
-
|
44
|
-
def environment=(e)
|
45
|
-
self.store('environment', e)
|
46
|
-
end
|
47
|
-
|
48
|
-
def environment
|
49
|
-
self['environment']
|
50
|
-
end
|
51
|
-
|
52
|
-
def duplicate(env)
|
53
|
-
new_object = self.deep_dup
|
54
|
-
new_object.set_environment(env, new_object)
|
55
|
-
end
|
56
|
-
|
57
|
-
#
|
58
|
-
# export YAML
|
59
|
-
#
|
60
|
-
# We use pure ruby yaml exporter ya2yaml instead of SYCK or PSYCH because it
|
61
|
-
# allows us greater compatibility regardless of installed ruby version and
|
62
|
-
# greater control over how the yaml is exported (sorted keys, in particular).
|
63
|
-
#
|
64
|
-
def dump_yaml
|
65
|
-
evaluate(@node)
|
66
|
-
sorted_ya2yaml(:syck_compatible => true)
|
67
|
-
end
|
68
|
-
|
69
|
-
#
|
70
|
-
# export JSON
|
71
|
-
#
|
72
|
-
def dump_json(options={})
|
73
|
-
evaluate(@node)
|
74
|
-
if options[:format] == :compact
|
75
|
-
return self.to_json
|
76
|
-
else
|
77
|
-
excluded = {}
|
78
|
-
if options[:exclude]
|
79
|
-
options[:exclude].each do |key|
|
80
|
-
excluded[key] = self[key]
|
81
|
-
self.delete(key)
|
82
|
-
end
|
83
|
-
end
|
84
|
-
json_str = JSON.sorted_generate(self)
|
85
|
-
if excluded.any?
|
86
|
-
self.merge!(excluded)
|
87
|
-
end
|
88
|
-
return json_str
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
|
-
def evaluate(context=@node)
|
93
|
-
evaluate_everything(context)
|
94
|
-
late_evaluate_everything(context)
|
95
|
-
end
|
96
|
-
|
97
|
-
##
|
98
|
-
## FETCHING VALUES
|
99
|
-
##
|
100
|
-
|
101
|
-
def [](key)
|
102
|
-
get(key)
|
103
|
-
end
|
104
|
-
|
105
|
-
# Overrride some default methods in Hash that are likely to
|
106
|
-
# be used as attributes.
|
107
|
-
alias_method :hkey, :key
|
108
|
-
def key; get('key'); end
|
109
|
-
|
110
|
-
#
|
111
|
-
# make hash addressable like an object (e.g. obj['name'] available as obj.name)
|
112
|
-
#
|
113
|
-
def method_missing(method, *args, &block)
|
114
|
-
get!(method)
|
115
|
-
end
|
116
|
-
|
117
|
-
def get(key)
|
118
|
-
begin
|
119
|
-
get!(key)
|
120
|
-
rescue NoMethodError
|
121
|
-
nil
|
122
|
-
end
|
123
|
-
end
|
124
|
-
|
125
|
-
# override behavior of #default() from Hash
|
126
|
-
def default
|
127
|
-
get!('default')
|
128
|
-
end
|
129
|
-
|
130
|
-
#
|
131
|
-
# Like a normal Hash#[], except:
|
132
|
-
#
|
133
|
-
# (1) lazily eval dynamic values when we encounter them. (i.e. strings that start with "= ")
|
134
|
-
#
|
135
|
-
# (2) support for nested references in a single string (e.g. ['a.b'] is the same as ['a']['b'])
|
136
|
-
# the dot path is always absolute, starting at the top-most object.
|
137
|
-
#
|
138
|
-
def get!(key)
|
139
|
-
key = key.to_s
|
140
|
-
if self.has_key?(key)
|
141
|
-
fetch_value(key)
|
142
|
-
elsif key =~ /\./
|
143
|
-
# for keys with with '.' in them, we start from the root object (@node).
|
144
|
-
keys = key.split('.')
|
145
|
-
value = self.get!(keys.first)
|
146
|
-
if value.is_a? Config::Object
|
147
|
-
value.get!(keys[1..-1].join('.'))
|
148
|
-
else
|
149
|
-
value
|
150
|
-
end
|
151
|
-
else
|
152
|
-
raise NoMethodError.new(key, "No method '#{key}' for #{self.class}")
|
153
|
-
end
|
154
|
-
end
|
155
|
-
|
156
|
-
##
|
157
|
-
## COPYING
|
158
|
-
##
|
159
|
-
|
160
|
-
#
|
161
|
-
# A deep (recursive) merge with another Config::Object.
|
162
|
-
#
|
163
|
-
# If prefer_self is set to true, the value from self will be picked when there is a conflict
|
164
|
-
# that cannot be merged.
|
165
|
-
#
|
166
|
-
# Merging rules:
|
167
|
-
#
|
168
|
-
# - If a value is a hash, we recursively merge it.
|
169
|
-
# - If the value is simple, like a string, the new one overwrites the value.
|
170
|
-
# - If the value is an array:
|
171
|
-
# - If both old and new values are arrays, the new one replaces the old.
|
172
|
-
# - If one of the values is simple but the other is an array, the simple is added to the array.
|
173
|
-
#
|
174
|
-
def deep_merge!(object, prefer_self=false)
|
175
|
-
object.each do |key,new_value|
|
176
|
-
if self.has_key?('+'+key)
|
177
|
-
mode = :add
|
178
|
-
old_value = self.fetch '+'+key, nil
|
179
|
-
self.delete('+'+key)
|
180
|
-
elsif self.has_key?('-'+key)
|
181
|
-
mode = :subtract
|
182
|
-
old_value = self.fetch '-'+key, nil
|
183
|
-
self.delete('-'+key)
|
184
|
-
elsif self.has_key?('!'+key)
|
185
|
-
mode = :replace
|
186
|
-
old_value = self.fetch '!'+key, nil
|
187
|
-
self.delete('!'+key)
|
188
|
-
else
|
189
|
-
mode = :normal
|
190
|
-
old_value = self.fetch key, nil
|
191
|
-
end
|
192
|
-
|
193
|
-
# clean up boolean
|
194
|
-
new_value = true if new_value == "true"
|
195
|
-
new_value = false if new_value == "false"
|
196
|
-
old_value = true if old_value == "true"
|
197
|
-
old_value = false if old_value == "false"
|
198
|
-
|
199
|
-
# force replace?
|
200
|
-
if mode == :replace && prefer_self
|
201
|
-
value = old_value
|
202
|
-
|
203
|
-
# merge hashes
|
204
|
-
elsif old_value.is_a?(Hash) || new_value.is_a?(Hash)
|
205
|
-
value = Config::Object.new(@env, @node)
|
206
|
-
old_value.is_a?(Hash) ? value.deep_merge!(old_value) : (value[key] = old_value if !old_value.nil?)
|
207
|
-
new_value.is_a?(Hash) ? value.deep_merge!(new_value, prefer_self) : (value[key] = new_value if !new_value.nil?)
|
208
|
-
|
209
|
-
# merge nil
|
210
|
-
elsif new_value.nil?
|
211
|
-
value = old_value
|
212
|
-
elsif old_value.nil?
|
213
|
-
value = new_value
|
214
|
-
|
215
|
-
# merge arrays when one value is not an array
|
216
|
-
elsif old_value.is_a?(Array) && !new_value.is_a?(Array)
|
217
|
-
(value = (old_value.dup << new_value).compact.uniq).delete('REQUIRED')
|
218
|
-
elsif new_value.is_a?(Array) && !old_value.is_a?(Array)
|
219
|
-
(value = (new_value.dup << old_value).compact.uniq).delete('REQUIRED')
|
220
|
-
|
221
|
-
# merge two arrays
|
222
|
-
elsif old_value.is_a?(Array) && new_value.is_a?(Array)
|
223
|
-
if mode == :add
|
224
|
-
value = (old_value + new_value).sort.uniq
|
225
|
-
elsif mode == :subtract
|
226
|
-
value = new_value - old_value
|
227
|
-
elsif prefer_self
|
228
|
-
value = old_value
|
229
|
-
else
|
230
|
-
value = new_value
|
231
|
-
end
|
232
|
-
|
233
|
-
# catch errors
|
234
|
-
elsif type_mismatch?(old_value, new_value)
|
235
|
-
raise 'Type mismatch. Cannot merge %s (%s) with %s (%s). Key is "%s", name is "%s".' % [
|
236
|
-
old_value.inspect, old_value.class,
|
237
|
-
new_value.inspect, new_value.class,
|
238
|
-
key, self.class
|
239
|
-
]
|
240
|
-
|
241
|
-
# merge simple strings & numbers
|
242
|
-
else
|
243
|
-
if prefer_self
|
244
|
-
value = old_value
|
245
|
-
else
|
246
|
-
value = new_value
|
247
|
-
end
|
248
|
-
end
|
249
|
-
|
250
|
-
# save value
|
251
|
-
self[key] = value
|
252
|
-
end
|
253
|
-
self
|
254
|
-
end
|
255
|
-
|
256
|
-
def set_environment(env, node)
|
257
|
-
@env = env
|
258
|
-
@node = node
|
259
|
-
self.each do |key, value|
|
260
|
-
if value.is_a?(Config::Object)
|
261
|
-
value.set_environment(env, node)
|
262
|
-
end
|
263
|
-
end
|
264
|
-
end
|
265
|
-
|
266
|
-
#
|
267
|
-
# like a reverse deep merge
|
268
|
-
# (self takes precedence)
|
269
|
-
#
|
270
|
-
def inherit_from!(object)
|
271
|
-
self.deep_merge!(object, true)
|
272
|
-
end
|
273
|
-
|
274
|
-
#
|
275
|
-
# Make a copy of ourselves, except only including the specified keys.
|
276
|
-
#
|
277
|
-
# Also, the result is flattened to a single hash, so a key of 'a.b' becomes 'a_b'
|
278
|
-
#
|
279
|
-
def pick(*keys)
|
280
|
-
keys.map(&:to_s).inject(self.class.new(@manager)) do |hsh, key|
|
281
|
-
value = self.get(key)
|
282
|
-
if !value.nil?
|
283
|
-
hsh[key.gsub('.','_')] = value
|
284
|
-
end
|
285
|
-
hsh
|
286
|
-
end
|
287
|
-
end
|
288
|
-
|
289
|
-
def eval_file(filename)
|
290
|
-
evaluate_ruby(filename, File.read(filename))
|
291
|
-
end
|
292
|
-
|
293
|
-
protected
|
294
|
-
|
295
|
-
#
|
296
|
-
# walks the object tree, eval'ing all the attributes that are dynamic ruby (e.g. value starts with '= ')
|
297
|
-
#
|
298
|
-
def evaluate_everything(context)
|
299
|
-
keys.each do |key|
|
300
|
-
obj = fetch_value(key, context)
|
301
|
-
if is_required_value_not_set?(obj)
|
302
|
-
Util::log 0, :warning, "required property \"#{key}\" is not set in node \"#{node.name}\"."
|
303
|
-
elsif obj.is_a? Config::Object
|
304
|
-
obj.evaluate_everything(context)
|
305
|
-
end
|
306
|
-
end
|
307
|
-
end
|
308
|
-
|
309
|
-
#
|
310
|
-
# some keys need to be evaluated 'late', after all the other keys have been evaluated.
|
311
|
-
#
|
312
|
-
def late_evaluate_everything(context)
|
313
|
-
if @late_eval_list
|
314
|
-
@late_eval_list.each do |key, value|
|
315
|
-
self[key] = context.evaluate_ruby(key, value)
|
316
|
-
if is_required_value_not_set?(self[key])
|
317
|
-
Util::log 0, :warning, "required property \"#{key}\" is not set in node \"#{node.name}\"."
|
318
|
-
end
|
319
|
-
end
|
320
|
-
end
|
321
|
-
values.each do |obj|
|
322
|
-
if obj.is_a? Config::Object
|
323
|
-
obj.late_evaluate_everything(context)
|
324
|
-
end
|
325
|
-
end
|
326
|
-
end
|
327
|
-
|
328
|
-
#
|
329
|
-
# evaluates the string `value` as ruby in the context of self.
|
330
|
-
# (`key` is just passed for debugging purposes)
|
331
|
-
#
|
332
|
-
def evaluate_ruby(key, value)
|
333
|
-
self.instance_eval(value, key, 1)
|
334
|
-
rescue ConfigError => exc
|
335
|
-
raise exc # pass through
|
336
|
-
rescue SystemStackError => exc
|
337
|
-
Util::log 0, :error, "while evaluating node '#{self.name}'"
|
338
|
-
Util::log 0, "offending key: #{key}", :indent => 1
|
339
|
-
Util::log 0, "offending string: #{value}", :indent => 1
|
340
|
-
Util::log 0, "STACK OVERFLOW, BAILING OUT. There must be an eval loop of death (variables with circular dependencies).", :indent => 1
|
341
|
-
raise SystemExit.new(1)
|
342
|
-
rescue FileMissing => exc
|
343
|
-
Util::bail! do
|
344
|
-
if exc.options[:missing]
|
345
|
-
Util::log :missing, exc.options[:missing].gsub('$node', self.name).gsub('$file', exc.path)
|
346
|
-
else
|
347
|
-
Util::log :error, "while evaluating node '#{self.name}'"
|
348
|
-
Util::log "offending key: #{key}", :indent => 1
|
349
|
-
Util::log "offending string: #{value}", :indent => 1
|
350
|
-
Util::log "error message: no file '#{exc}'", :indent => 1
|
351
|
-
end
|
352
|
-
raise exc if DEBUG
|
353
|
-
end
|
354
|
-
rescue AssertionFailed => exc
|
355
|
-
Util.bail! do
|
356
|
-
Util::log :failed, "assertion while evaluating node '#{self.name}'"
|
357
|
-
Util::log 'assertion: %s' % exc.assertion, :indent => 1
|
358
|
-
Util::log "offending key: #{key}", :indent => 1
|
359
|
-
raise exc if DEBUG
|
360
|
-
end
|
361
|
-
rescue SyntaxError, StandardError => exc
|
362
|
-
Util::bail! do
|
363
|
-
Util::log :error, "while evaluating node '#{self.name}'"
|
364
|
-
Util::log "offending key: #{key}", :indent => 1
|
365
|
-
Util::log "offending string: #{value}", :indent => 1
|
366
|
-
Util::log "error message: #{exc.inspect}", :indent => 1
|
367
|
-
raise exc if DEBUG
|
368
|
-
end
|
369
|
-
end
|
370
|
-
|
371
|
-
private
|
372
|
-
|
373
|
-
#
|
374
|
-
# fetches the value for the key, evaluating the value as ruby if it begins with '='
|
375
|
-
#
|
376
|
-
def fetch_value(key, context=@node)
|
377
|
-
value = fetch(key, nil)
|
378
|
-
if value.is_a?(String) && value =~ /^=/
|
379
|
-
if value =~ /^=> (.*)$/
|
380
|
-
value = evaluate_later(key, $1)
|
381
|
-
elsif value =~ /^= (.*)$/
|
382
|
-
value = context.evaluate_ruby(key, $1)
|
383
|
-
end
|
384
|
-
self[key] = value
|
385
|
-
end
|
386
|
-
return value
|
387
|
-
end
|
388
|
-
|
389
|
-
def evaluate_later(key, value)
|
390
|
-
@late_eval_list ||= []
|
391
|
-
@late_eval_list << [key, value]
|
392
|
-
'<evaluate later>'
|
393
|
-
end
|
394
|
-
|
395
|
-
#
|
396
|
-
# when merging, we raise an error if this method returns true for the two values.
|
397
|
-
#
|
398
|
-
def type_mismatch?(old_value, new_value)
|
399
|
-
if old_value.is_a?(Boolean) && new_value.is_a?(Boolean)
|
400
|
-
# note: FalseClass and TrueClass are different classes
|
401
|
-
# so we can't do old_value.class == new_value.class
|
402
|
-
return false
|
403
|
-
elsif old_value.is_a?(String) && old_value =~ /^=/
|
404
|
-
# pass through macros, since we don't know what the type will eventually be.
|
405
|
-
return false
|
406
|
-
elsif new_value.is_a?(String) && new_value =~ /^=/
|
407
|
-
return false
|
408
|
-
elsif old_value.class == new_value.class
|
409
|
-
return false
|
410
|
-
else
|
411
|
-
return true
|
412
|
-
end
|
413
|
-
end
|
414
|
-
|
415
|
-
#
|
416
|
-
# returns true if the value has not been changed and the default is "REQUIRED"
|
417
|
-
#
|
418
|
-
def is_required_value_not_set?(value)
|
419
|
-
if value.is_a? Array
|
420
|
-
value == ["REQUIRED"]
|
421
|
-
else
|
422
|
-
value == "REQUIRED"
|
423
|
-
end
|
424
|
-
end
|
425
|
-
|
426
|
-
end # class
|
427
|
-
end # module
|
428
|
-
end # module
|