chef-dk 2.3.4 → 2.4.17
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +22 -18
- data/Gemfile.lock +184 -254
- data/README.md +1 -1
- data/Rakefile +1 -1
- data/acceptance/Gemfile.lock +27 -32
- data/lib/chef-dk/chef_server_api_multi.rb +73 -0
- data/lib/chef-dk/command/update.rb +5 -12
- data/lib/chef-dk/configurable.rb +19 -0
- data/lib/chef-dk/cookbook_omnifetch.rb +1 -0
- data/lib/chef-dk/exceptions.rb +11 -0
- data/lib/chef-dk/generator.rb +1 -1
- data/lib/chef-dk/policyfile/attribute_merge_checker.rb +110 -0
- data/lib/chef-dk/policyfile/chef_server_cookbook_source.rb +5 -4
- data/lib/chef-dk/policyfile/chef_server_lock_fetcher.rb +164 -0
- data/lib/chef-dk/policyfile/cookbook_location_specification.rb +3 -3
- data/lib/chef-dk/policyfile/dsl.rb +16 -0
- data/lib/chef-dk/policyfile/included_policies_cookbook_source.rb +156 -0
- data/lib/chef-dk/policyfile/local_lock_fetcher.rb +122 -0
- data/lib/chef-dk/policyfile/lock_applier.rb +80 -0
- data/lib/chef-dk/policyfile/null_cookbook_source.rb +4 -0
- data/lib/chef-dk/policyfile/policyfile_location_specification.rb +122 -0
- data/lib/chef-dk/policyfile_compiler.rb +129 -16
- data/lib/chef-dk/policyfile_lock.rb +30 -0
- data/lib/chef-dk/policyfile_services/install.rb +7 -1
- data/lib/chef-dk/policyfile_services/update_attributes.rb +10 -2
- data/lib/chef-dk/skeletons/code_generator/templates/default/recipe_spec.rb.erb +14 -1
- data/lib/chef-dk/version.rb +1 -1
- data/omnibus_overrides.rb +6 -6
- data/spec/unit/chef_server_api_multi_spec.rb +120 -0
- data/spec/unit/command/update_spec.rb +3 -3
- data/spec/unit/configurable_spec.rb +27 -0
- data/spec/unit/policyfile/attribute_merge_checker_spec.rb +80 -0
- data/spec/unit/policyfile/chef_server_lock_fetcher_spec.rb +161 -0
- data/spec/unit/policyfile/cookbook_location_specification_spec.rb +48 -0
- data/spec/unit/policyfile/included_policies_cookbook_source_spec.rb +242 -0
- data/spec/unit/policyfile/local_lock_fetcher_spec.rb +161 -0
- data/spec/unit/policyfile/lock_applier_spec.rb +100 -0
- data/spec/unit/policyfile_demands_spec.rb +1 -1
- data/spec/unit/policyfile_includes_dsl_spec.rb +159 -0
- data/spec/unit/policyfile_includes_spec.rb +720 -0
- data/spec/unit/policyfile_install_with_includes_spec.rb +232 -0
- data/spec/unit/policyfile_lock_build_spec.rb +11 -2
- data/spec/unit/policyfile_services/update_attributes_spec.rb +13 -0
- metadata +28 -3
data/README.md
CHANGED
@@ -314,7 +314,7 @@ For information on contributing to this project see <https://github.com/chef/che
|
|
314
314
|
|
315
315
|
# For ChefDK Developers
|
316
316
|
|
317
|
-
See the [Development Guide](
|
317
|
+
See the [Development Guide](CONTRIBUTING.md) for how to get started with
|
318
318
|
development on the ChefDK itself, as well as details on how dependencies,
|
319
319
|
packaging, and building works.
|
320
320
|
|
data/Rakefile
CHANGED
@@ -63,7 +63,7 @@ namespace :style do
|
|
63
63
|
FoodCritic::Rake::LintTask.new(:foodcritic) do |t|
|
64
64
|
t.options = {
|
65
65
|
fail_tags: ["any"],
|
66
|
-
tags: ["~
|
66
|
+
tags: ["~FC071", "~supermarket"],
|
67
67
|
cookbook_paths: ["lib/chef-dk/skeletons/code_generator"],
|
68
68
|
progress: true,
|
69
69
|
}
|
data/acceptance/Gemfile.lock
CHANGED
@@ -12,13 +12,13 @@ GEM
|
|
12
12
|
addressable (2.5.2)
|
13
13
|
public_suffix (>= 2.0.2, < 4.0)
|
14
14
|
artifactory (2.8.2)
|
15
|
-
aws-sdk (2.10.
|
16
|
-
aws-sdk-resources (= 2.10.
|
17
|
-
aws-sdk-core (2.10.
|
15
|
+
aws-sdk (2.10.90)
|
16
|
+
aws-sdk-resources (= 2.10.90)
|
17
|
+
aws-sdk-core (2.10.90)
|
18
18
|
aws-sigv4 (~> 1.0)
|
19
19
|
jmespath (~> 1.0)
|
20
|
-
aws-sdk-resources (2.10.
|
21
|
-
aws-sdk-core (= 2.10.
|
20
|
+
aws-sdk-resources (2.10.90)
|
21
|
+
aws-sdk-core (= 2.10.90)
|
22
22
|
aws-sigv4 (1.0.2)
|
23
23
|
berkshelf (6.3.1)
|
24
24
|
buff-config (~> 2.0)
|
@@ -36,7 +36,6 @@ GEM
|
|
36
36
|
ridley (~> 5.0)
|
37
37
|
solve (~> 4.0)
|
38
38
|
thor (~> 0.19, < 0.19.2)
|
39
|
-
blankslate (2.1.2.4)
|
40
39
|
buff-config (2.0.0)
|
41
40
|
buff-extensions (~> 2.0)
|
42
41
|
varia_model (~> 0.6)
|
@@ -92,9 +91,9 @@ GEM
|
|
92
91
|
coderay (1.1.2)
|
93
92
|
concurrent-ruby (1.0.5)
|
94
93
|
diff-lcs (1.3)
|
95
|
-
docker-api (1.
|
96
|
-
excon (>= 0.
|
97
|
-
|
94
|
+
docker-api (1.34.0)
|
95
|
+
excon (>= 0.47.0)
|
96
|
+
multi_json
|
98
97
|
erubis (2.7.0)
|
99
98
|
excon (0.59.0)
|
100
99
|
faraday (0.13.1)
|
@@ -108,12 +107,12 @@ GEM
|
|
108
107
|
gyoku (1.3.1)
|
109
108
|
builder (>= 2.1.2)
|
110
109
|
hashie (3.5.6)
|
111
|
-
highline (1.7.
|
110
|
+
highline (1.7.10)
|
112
111
|
hitimes (1.2.6)
|
113
112
|
htmlentities (4.3.4)
|
114
113
|
httpclient (2.8.3)
|
115
114
|
iniparse (1.4.4)
|
116
|
-
inspec (1.
|
115
|
+
inspec (1.45.13)
|
117
116
|
addressable (~> 2.4)
|
118
117
|
faraday (>= 0.9.0)
|
119
118
|
hashie (~> 3.4)
|
@@ -131,8 +130,8 @@ GEM
|
|
131
130
|
semverse
|
132
131
|
sslshake (~> 1.2)
|
133
132
|
thor (~> 0.19)
|
134
|
-
|
135
|
-
train (~> 0.
|
133
|
+
tomlrb (~> 1.2)
|
134
|
+
train (~> 0.29, >= 0.29.2)
|
136
135
|
ipaddress (0.8.3)
|
137
136
|
jmespath (1.3.1)
|
138
137
|
json (2.1.0)
|
@@ -142,7 +141,7 @@ GEM
|
|
142
141
|
multi_json
|
143
142
|
retryable (~> 2.0)
|
144
143
|
test-kitchen (~> 1.4, >= 1.4.1)
|
145
|
-
kitchen-inspec (0.
|
144
|
+
kitchen-inspec (0.20.0)
|
146
145
|
hashie (~> 3.4)
|
147
146
|
inspec (>= 0.34.0, < 2.0.0)
|
148
147
|
test-kitchen (~> 1.6)
|
@@ -153,7 +152,7 @@ GEM
|
|
153
152
|
logging (2.2.2)
|
154
153
|
little-plugger (~> 1.1)
|
155
154
|
multi_json (~> 1.10)
|
156
|
-
method_source (0.
|
155
|
+
method_source (0.9.0)
|
157
156
|
minitar (0.6.1)
|
158
157
|
mixlib-archive (0.4.1)
|
159
158
|
mixlib-log
|
@@ -167,7 +166,7 @@ GEM
|
|
167
166
|
mixlib-log (1.7.1)
|
168
167
|
mixlib-shellout (2.3.2)
|
169
168
|
mixlib-versioning (1.2.2)
|
170
|
-
molinillo (0.6.
|
169
|
+
molinillo (0.6.4)
|
171
170
|
multi_json (1.12.2)
|
172
171
|
multipart-post (2.0.0)
|
173
172
|
net-scp (1.2.1)
|
@@ -185,7 +184,7 @@ GEM
|
|
185
184
|
nori (2.6.0)
|
186
185
|
octokit (4.7.0)
|
187
186
|
sawyer (~> 0.8.0, >= 0.5.3)
|
188
|
-
ohai (8.
|
187
|
+
ohai (8.25.1)
|
189
188
|
chef-config (>= 12.5.0.alpha.1, < 14)
|
190
189
|
ffi (~> 1.9)
|
191
190
|
ffi-yajl (~> 2.2)
|
@@ -198,15 +197,13 @@ GEM
|
|
198
197
|
systemu (~> 2.6.4)
|
199
198
|
wmi-lite (~> 1.0)
|
200
199
|
parallel (1.12.0)
|
201
|
-
parslet (1.
|
202
|
-
blankslate (~> 2.0)
|
200
|
+
parslet (1.8.1)
|
203
201
|
plist (3.3.0)
|
204
202
|
proxifier (1.0.3)
|
205
|
-
pry (0.
|
203
|
+
pry (0.11.3)
|
206
204
|
coderay (~> 1.1.0)
|
207
|
-
method_source (~> 0.
|
208
|
-
|
209
|
-
public_suffix (3.0.0)
|
205
|
+
method_source (~> 0.9.0)
|
206
|
+
public_suffix (3.0.1)
|
210
207
|
rack (1.6.8)
|
211
208
|
rainbow (2.1.0)
|
212
209
|
retryable (2.0.4)
|
@@ -254,17 +251,16 @@ GEM
|
|
254
251
|
addressable (>= 2.3.5, < 2.6)
|
255
252
|
faraday (~> 0.8, < 1.0)
|
256
253
|
semverse (2.0.0)
|
257
|
-
serverspec (2.
|
254
|
+
serverspec (2.41.3)
|
258
255
|
multi_json
|
259
256
|
rspec (~> 3.0)
|
260
257
|
rspec-its
|
261
|
-
specinfra (~> 2.
|
258
|
+
specinfra (~> 2.72)
|
262
259
|
sfl (2.3)
|
263
|
-
slop (3.6.0)
|
264
260
|
solve (4.0.0)
|
265
261
|
molinillo (~> 0.6)
|
266
262
|
semverse (>= 1.1, < 3.0)
|
267
|
-
specinfra (2.
|
263
|
+
specinfra (2.72.1)
|
268
264
|
net-scp
|
269
265
|
net-ssh (>= 2.7, < 5.0)
|
270
266
|
net-telnet
|
@@ -283,9 +279,8 @@ GEM
|
|
283
279
|
thor (0.19.1)
|
284
280
|
timers (4.0.4)
|
285
281
|
hitimes
|
286
|
-
|
287
|
-
|
288
|
-
train (0.26.2)
|
282
|
+
tomlrb (1.2.6)
|
283
|
+
train (0.29.2)
|
289
284
|
docker-api (~> 1.26)
|
290
285
|
json (>= 1.8, < 3.0)
|
291
286
|
mixlib-shellout (~> 2.0)
|
@@ -311,7 +306,7 @@ GEM
|
|
311
306
|
winrm-elevated (1.1.0)
|
312
307
|
winrm (~> 2.0)
|
313
308
|
winrm-fs (~> 1.0)
|
314
|
-
winrm-fs (1.
|
309
|
+
winrm-fs (1.1.1)
|
315
310
|
erubis (~> 2.7)
|
316
311
|
logging (>= 1.6.1, < 3.0)
|
317
312
|
rubyzip (~> 1.1)
|
@@ -336,4 +331,4 @@ DEPENDENCIES
|
|
336
331
|
winrm-fs
|
337
332
|
|
338
333
|
BUNDLED WITH
|
339
|
-
1.
|
334
|
+
1.16.0
|
@@ -0,0 +1,73 @@
|
|
1
|
+
#
|
2
|
+
# Copyright:: Copyright (c) 2017 Chef Software Inc.
|
3
|
+
# License:: Apache License, Version 2.0
|
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
|
+
|
18
|
+
require "chef/server_api"
|
19
|
+
|
20
|
+
module ChefDK
|
21
|
+
|
22
|
+
# A wrapper for `Chef::ServerAPI` that supports multi-threading by creating a
|
23
|
+
# `Chef::ServerAPI` object per-thread.
|
24
|
+
#
|
25
|
+
# This is intended to be used for downloading cookbooks from the Chef Server,
|
26
|
+
# where the API of the Chef Server requires each file to be downloaded
|
27
|
+
# individually.
|
28
|
+
#
|
29
|
+
# It also configures `Chef::ServerAPI` to enable keepalives by default. To
|
30
|
+
# disable them, `keepalives: false` must be set in the options to the
|
31
|
+
# constructor.
|
32
|
+
class ChefServerAPIMulti
|
33
|
+
|
34
|
+
KEEPALIVES_TRUE = { keepalives: true }.freeze
|
35
|
+
|
36
|
+
attr_reader :url
|
37
|
+
attr_reader :opts
|
38
|
+
|
39
|
+
def initialize(url, opts)
|
40
|
+
@url = url
|
41
|
+
@opts = KEEPALIVES_TRUE.merge(opts)
|
42
|
+
end
|
43
|
+
|
44
|
+
def head(*args)
|
45
|
+
client_for_thread.head(*args)
|
46
|
+
end
|
47
|
+
|
48
|
+
def get(*args)
|
49
|
+
client_for_thread.get(*args)
|
50
|
+
end
|
51
|
+
|
52
|
+
def put(*args)
|
53
|
+
client_for_thread.put(*args)
|
54
|
+
end
|
55
|
+
|
56
|
+
def post(*args)
|
57
|
+
client_for_thread.post(*args)
|
58
|
+
end
|
59
|
+
|
60
|
+
def delete(*args)
|
61
|
+
client_for_thread.delete(*args)
|
62
|
+
end
|
63
|
+
|
64
|
+
def streaming_request(*args, &block)
|
65
|
+
client_for_thread.streaming_request(*args, &block)
|
66
|
+
end
|
67
|
+
|
68
|
+
def client_for_thread
|
69
|
+
Thread.current[:chef_server_api_multi] ||= Chef::ServerAPI.new(@url, @opts)
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
end
|
@@ -29,16 +29,16 @@ module ChefDK
|
|
29
29
|
include Configurable
|
30
30
|
|
31
31
|
banner(<<-BANNER)
|
32
|
-
Usage: chef update [ POLICY_FILE ] [options]
|
32
|
+
Usage: chef update [ POLICY_FILE ] [options] [cookbook_1] [...]
|
33
33
|
|
34
34
|
`chef update` reads your `Policyfile.rb`, applies any changes, re-solves the
|
35
35
|
dependencies and emits an updated `Policyfile.lock.json`. The new locked policy
|
36
36
|
will reflect any changes to the `run_list` and pull in any cookbook updates
|
37
37
|
that are compatible with the version constraints stated in your `Policyfile.rb`.
|
38
38
|
|
39
|
-
|
40
|
-
|
41
|
-
|
39
|
+
Individual dependent cookbooks (and their dependencies) may be updated by
|
40
|
+
passing their names after the POLICY_FILE. The POLICY_FILE parameter is
|
41
|
+
mandatory if you want to update individual cookbooks.
|
42
42
|
|
43
43
|
See our detailed README for more information:
|
44
44
|
|
@@ -83,13 +83,6 @@ BANNER
|
|
83
83
|
|
84
84
|
def run(params = [])
|
85
85
|
return 1 unless apply_params!(params)
|
86
|
-
|
87
|
-
# Force config file to be loaded. We don't use the configuration
|
88
|
-
# directly, but the user may have SSL configuration options that they
|
89
|
-
# need to talk to a private supermarket (e.g., trusted_certs or
|
90
|
-
# ssl_verify_mode)
|
91
|
-
chef_config
|
92
|
-
|
93
86
|
attributes_updater.run
|
94
87
|
installer.run(@cookbooks_to_update) unless update_attributes_only?
|
95
88
|
0
|
@@ -104,7 +97,7 @@ BANNER
|
|
104
97
|
|
105
98
|
def attributes_updater
|
106
99
|
@attributes_updater ||=
|
107
|
-
PolicyfileServices::UpdateAttributes.new(policyfile: policyfile_relative_path, ui: ui, root_dir: Dir.pwd)
|
100
|
+
PolicyfileServices::UpdateAttributes.new(policyfile: policyfile_relative_path, ui: ui, root_dir: Dir.pwd, chef_config: chef_config)
|
108
101
|
end
|
109
102
|
|
110
103
|
def debug?
|
data/lib/chef-dk/configurable.rb
CHANGED
@@ -18,6 +18,9 @@
|
|
18
18
|
require "chef/config"
|
19
19
|
require "chef/workstation_config_loader"
|
20
20
|
|
21
|
+
require "chef-dk/cookbook_omnifetch"
|
22
|
+
require "chef-dk/chef_server_api_multi"
|
23
|
+
|
21
24
|
# Define a config context for ChefDK
|
22
25
|
class Chef::Config
|
23
26
|
|
@@ -48,6 +51,8 @@ module ChefDK
|
|
48
51
|
return @chef_config if @chef_config
|
49
52
|
config_loader.load
|
50
53
|
@chef_config = Chef::Config
|
54
|
+
CookbookOmnifetch.integration.default_chef_server_http_client = default_chef_server_http_client
|
55
|
+
@chef_config
|
51
56
|
end
|
52
57
|
|
53
58
|
def chefdk_config
|
@@ -65,5 +70,19 @@ module ChefDK
|
|
65
70
|
def knife_config
|
66
71
|
chef_config.knife
|
67
72
|
end
|
73
|
+
|
74
|
+
def reset_config!
|
75
|
+
@chef_config = nil
|
76
|
+
@config_loader = nil
|
77
|
+
end
|
78
|
+
|
79
|
+
def default_chef_server_http_client
|
80
|
+
lambda do
|
81
|
+
ChefServerAPIMulti.new(@chef_config.chef_server_url,
|
82
|
+
signing_key_filename: @chef_config.client_key,
|
83
|
+
client_name: @chef_config.node_name)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
68
87
|
end
|
69
88
|
end
|
@@ -28,4 +28,5 @@ CookbookOmnifetch.configure do |c|
|
|
28
28
|
c.storage_path = Pathname.new(File.expand_path(File.join(ChefDK::Helpers.chefdk_home, "cache", "cookbooks")))
|
29
29
|
c.shell_out_class = ChefDK::ShellOut
|
30
30
|
c.cached_cookbook_class = ChefDK::CookbookMetadata
|
31
|
+
c.chef_server_download_concurrency = 10
|
31
32
|
end
|
data/lib/chef-dk/exceptions.rb
CHANGED
@@ -96,6 +96,9 @@ module ChefDK
|
|
96
96
|
class BUG < RuntimeError
|
97
97
|
end
|
98
98
|
|
99
|
+
class IncludePolicyCookbookSourceConflict < StandardError
|
100
|
+
end
|
101
|
+
|
99
102
|
class CookbookSourceConflict < StandardError
|
100
103
|
|
101
104
|
attr_reader :conflicting_cookbooks
|
@@ -136,4 +139,12 @@ EXAMPLE
|
|
136
139
|
|
137
140
|
end
|
138
141
|
|
142
|
+
class PolicyfileLockDownloadError < StandardError
|
143
|
+
end
|
144
|
+
|
145
|
+
class LocalPolicyfileLockNotFound < StandardError
|
146
|
+
end
|
147
|
+
|
148
|
+
class InvalidPolicyfileLocation < StandardError
|
149
|
+
end
|
139
150
|
end
|
data/lib/chef-dk/generator.rb
CHANGED
@@ -0,0 +1,110 @@
|
|
1
|
+
#
|
2
|
+
# Copyright:: Copyright (c) 2017 Chef Software Inc.
|
3
|
+
# License:: Apache License, Version 2.0
|
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
|
+
|
18
|
+
require "chef/mash"
|
19
|
+
|
20
|
+
module ChefDK
|
21
|
+
module Policyfile
|
22
|
+
class AttributeMergeChecker
|
23
|
+
# A ConflictError is used to specify a conflict has occurred
|
24
|
+
class ConflictError < StandardError
|
25
|
+
attr_reader :attribute_path
|
26
|
+
attr_reader :provided_by
|
27
|
+
|
28
|
+
def initialize(attribute_path, provided_by)
|
29
|
+
@attribute_path = attribute_path
|
30
|
+
@provided_by = provided_by
|
31
|
+
super("Attribute '#{attribute_path}' provided conflicting values by the following sources #{provided_by}")
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# A Leaf is used to mark an individual attribute that has already
|
36
|
+
# been provided, along with its value and by who
|
37
|
+
#
|
38
|
+
# @api private
|
39
|
+
class Leaf
|
40
|
+
attr_reader :provided_by
|
41
|
+
attr_reader :val
|
42
|
+
|
43
|
+
def initialize(provided_by, val)
|
44
|
+
@provided_by = provided_by
|
45
|
+
@val = val
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# An AttributeHashInfo holds a set of attributes along with where they came from
|
50
|
+
class AttributeHashInfo
|
51
|
+
attr_reader :source_name
|
52
|
+
attr_reader :hash
|
53
|
+
def initialize(source_name, hash)
|
54
|
+
@source_name = source_name
|
55
|
+
@hash = hash
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# @return [Array<AttributeHashInfo>] A list of attributes and who they were provided by
|
60
|
+
attr_reader :attribute_hash_infos
|
61
|
+
|
62
|
+
def initialize
|
63
|
+
@attribute_hash_infos = []
|
64
|
+
end
|
65
|
+
|
66
|
+
# Add a hash of attributes to the set of attributes that will be compared
|
67
|
+
# for conflicts
|
68
|
+
#
|
69
|
+
# @param source_name [String] Where the attributes came from
|
70
|
+
# @param hash [Hash] attributes from source_name
|
71
|
+
def with_attributes(source_name, hash)
|
72
|
+
attribute_hash_infos << AttributeHashInfo.new(source_name, hash)
|
73
|
+
end
|
74
|
+
|
75
|
+
# Check all added attributes for conflicts. Different sources can provide
|
76
|
+
# the same attribute if they have the same value. Otherwise, it is considered
|
77
|
+
# a conflict
|
78
|
+
#
|
79
|
+
# @raise ConflictError if there are conflicting attributes
|
80
|
+
def check!
|
81
|
+
check_struct = Mash.new
|
82
|
+
attribute_hash_infos.each do |attr_hash_info|
|
83
|
+
fill!(check_struct, attr_hash_info.source_name, "", attr_hash_info.hash)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
private
|
88
|
+
|
89
|
+
def fill!(acc, source_name, path, hash)
|
90
|
+
hash.each do |(key, val)|
|
91
|
+
new_path = "#{path}[#{key}]"
|
92
|
+
if val.kind_of?(Hash)
|
93
|
+
acc[key] ||= Mash.new
|
94
|
+
fill!(acc[key], source_name, new_path, val)
|
95
|
+
else
|
96
|
+
if acc[key].nil?
|
97
|
+
acc[key] = Leaf.new(source_name, val)
|
98
|
+
else
|
99
|
+
leaf = acc[key]
|
100
|
+
if leaf.val != val
|
101
|
+
raise ConflictError.new(new_path, [leaf.provided_by, source_name])
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|