chef-dk 2.3.4 → 2.4.17
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/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
|