poise-languages 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.
@@ -0,0 +1,202 @@
1
+ #
2
+ # Copyright 2015, Noah Kantrowitz
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ #
16
+
17
+ require 'chef/resource'
18
+ require 'chef/provider'
19
+ require 'poise'
20
+
21
+
22
+ module PoiseLanguages
23
+ module System
24
+ # A `poise_language_system` resource to manage installing a language from
25
+ # system packages. This is an internal implementation detail of
26
+ # poise-languages.
27
+ #
28
+ # @api private
29
+ # @since 1.0
30
+ # @provides poise_languages_system
31
+ # @action install
32
+ # @action upgrade
33
+ # @action uninstall
34
+ class Resource < Chef::Resource
35
+ include Poise
36
+ provides(:poise_languages_system)
37
+ actions(:install, :upgrade, :uninstall)
38
+
39
+ # @!attribute package_name
40
+ # Name of the main package for the language.
41
+ # @return [String]
42
+ attribute(:package_name, kind_of: String, name_attribute: true)
43
+ # @!attribute dev_package
44
+ # Name of the development headers package, or false to disable
45
+ # installing headers. By default computed from {package_name}.
46
+ # @return [String, false]
47
+ attribute(:dev_package, kind_of: [String, FalseClass], default: lazy { default_dev_package })
48
+ # @!attribute dev_package_overrides
49
+ # A hash of override names for dev packages that don't match the normal
50
+ # naming scheme.
51
+ # @return [Hash<String, String>]
52
+ attribute(:dev_package_overrides, kind_of: Hash, default: lazy { {} })
53
+ # @!attribute package_version
54
+ # Version of the package(s) to install. This is distinct from {version},
55
+ # and is the specific version package version, not the language version.
56
+ # By default this is unset meaning the latest version will be used.
57
+ # @return [String, nil]
58
+ attribute(:package_version, kind_of: [String, NilClass])
59
+ # @!attribute parent
60
+ # Resource for the language runtime. Used only for messages.
61
+ # @return [Chef::Resource]
62
+ attribute(:parent, kind_of: Chef::Resource, required: true)
63
+ # @!attributes version
64
+ # Language version prefix. This prefix determines which version of the
65
+ # language to install, following prefix matching rules.
66
+ # @return [String]
67
+ attribute(:version, kind_of: String, default: '')
68
+
69
+ # Compute the default package name for the development headers.
70
+ #
71
+ # @return [String]
72
+ def default_dev_package
73
+ # Check for an override.
74
+ return dev_package_overrides[package_name] if dev_package_overrides.include?(package_name)
75
+ suffix = node.value_for_platform_family(debian: '-dev', rhel: '-devel', fedora: '-devel')
76
+ # Platforms like Arch and Gentoo don't need this anyway. I've got no
77
+ # clue how Amazon Linux does this.
78
+ if suffix
79
+ package_name + suffix
80
+ else
81
+ nil
82
+ end
83
+ end
84
+ end
85
+
86
+ # The default provider for `poise_languages_system`.
87
+ #
88
+ # @api private
89
+ # @since 1.0
90
+ # @see Resource
91
+ # @provides poise_languages_system
92
+ class Provider < Chef::Provider
93
+ include Poise
94
+ provides(:poise_languages_system)
95
+
96
+ # The `install` action for the `poise_languages_system` resource.
97
+ #
98
+ # @return [void]
99
+ def action_install
100
+ run_package_action(:install)
101
+ end
102
+
103
+ # The `upgrade` action for the `poise_languages_system` resource.
104
+ #
105
+ # @return [void]
106
+ def action_upgrade
107
+ run_package_action(:upgrade)
108
+ end
109
+
110
+ # The `uninstall` action for the `poise_languages_system` resource.
111
+ #
112
+ # @return [void]
113
+ def action_uninstall
114
+ action = node.platform_family?('debian') ? :purge : :remove
115
+ package_resources(action).each do |resource|
116
+ resource.run_action(action)
117
+ new_resource.updated_by_last_action(true) if resource.updated_by_last_action?
118
+ end
119
+ end
120
+
121
+ private
122
+
123
+ # Create package resource objects for all needed packages. These are created
124
+ # directly and not added to the resource collection.
125
+ #
126
+ # @return [Array<Chef::Resource::Package>]
127
+ def package_resources(action)
128
+ packages = {new_resource.package_name => new_resource.package_version}
129
+ # If we are supposed to install the dev package, grab it using the same
130
+ # version as the main package.
131
+ if new_resource.dev_package
132
+ packages[new_resource.dev_package] = new_resource.package_version
133
+ end
134
+
135
+ Chef::Log.debug("[#{new_resource.parent}] Building package resource using #{packages.inspect}.")
136
+ @package_resource ||= if node.platform_family?('rhel', 'fedora', 'amazon')
137
+ # @todo Can't use multi-package mode with yum pending https://github.com/chef/chef/issues/3476.
138
+ packages.map do |name, version|
139
+ Chef::Resource::Package.new(name, run_context).tap do |r|
140
+ r.version(version)
141
+ r.action(action)
142
+ r.declared_type = :package
143
+ end
144
+ end
145
+ else
146
+ [Chef::Resource::Package.new(packages.keys, run_context).tap do |r|
147
+ r.version(packages.values)
148
+ r.action(action)
149
+ r.declared_type = :package
150
+ end]
151
+ end
152
+ end
153
+
154
+ # Run the requested action for all package resources. This exists because
155
+ # we inject our version check in to the provider directly and I want to
156
+ # only run the provider action once for performance. It is otherwise
157
+ # mostly a stripped down version of Chef::Resource#run_action.
158
+ #
159
+ # @param action [Symbol] Action to run on all package resources.
160
+ # @return [void]
161
+ def run_package_action(action)
162
+ package_resources(action).each do |resource|
163
+ # Reset it so we have a clean baseline.
164
+ resource.updated_by_last_action(false)
165
+ # Grab the provider.
166
+ provider = resource.provider_for_action(action)
167
+ provider.action = action
168
+ # Check the candidate version if needed
169
+ patch_load_current_resource!(provider, new_resource.version)
170
+ # Run our action.
171
+ Chef::Log.debug("[#{new_resource.parent}] Running #{provider} with #{action}")
172
+ provider.run_action(action)
173
+ # Check updated flag.
174
+ new_resource.updated_by_last_action(true) if resource.updated_by_last_action?
175
+ end
176
+ end
177
+
178
+ # Hack a provider object to run our verification code.
179
+ #
180
+ # @param provider [Chef::Provider] Provider object to patch.
181
+ # @param version [String] Language version prefix to check for.
182
+ # @return [void]
183
+ def patch_load_current_resource!(provider, version)
184
+ # Create a closure module and inject it.
185
+ provider.extend Module.new {
186
+ # Patch load_current_resource to run our verification logic after
187
+ # the normal code.
188
+ define_method(:load_current_resource) do
189
+ super().tap do |_|
190
+ each_package do |package_name, new_version, current_version, candidate_version|
191
+ unless candidate_version.start_with?(version)
192
+ raise PoiseLanguages::Error.new("Package #{package_name} would install #{candidate_version}, which does not match #{version.empty? ? version.inspect : version}. Please set the package_name or package_version provider options.")
193
+ end
194
+ end
195
+ end
196
+ end
197
+ }
198
+ end
199
+
200
+ end
201
+ end
202
+ end
@@ -0,0 +1,49 @@
1
+ #
2
+ # Copyright 2015, Noah Kantrowitz
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ #
16
+
17
+ require 'shellwords'
18
+
19
+ require 'poise_languages/utils/which'
20
+
21
+
22
+ module PoiseLanguages
23
+ module Utils
24
+ include Which
25
+ extend self
26
+
27
+ # Convert the executable in a string or array command to an absolute path.
28
+ #
29
+ # @param cmd [String, Array<String>] Command to fix up.
30
+ # @param path [String, nil] Replacement $PATH for executable lookup.
31
+ # @return [String, Array<String>]
32
+ def absolute_command(cmd, path: nil)
33
+ was_array = cmd.is_a?(Array)
34
+ cmd = if was_array
35
+ cmd.dup
36
+ else
37
+ Shellwords.split(cmd)
38
+ end
39
+ # Don't try to touch anything if the first value looks like a flag.
40
+ if cmd.first && !cmd.first.start_with?('-')
41
+ # If which returns false, just leave it I guess.
42
+ cmd[0] = which(cmd.first, path: path) || cmd.first
43
+ end
44
+ cmd = Shellwords.join(cmd) unless was_array
45
+ cmd
46
+ end
47
+
48
+ end
49
+ end
@@ -0,0 +1,49 @@
1
+ #
2
+ # Copyright 2015, Noah Kantrowitz
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ #
16
+
17
+
18
+ module PoiseLanguages
19
+ module Utils
20
+ # Replacement module for Chef::Mixin::Which with a slight improvement.
21
+ #
22
+ # @since 1.0.0
23
+ # @see Which#which
24
+ module Which
25
+ extend self
26
+
27
+ # A replacement for Chef::Mixin::Which#which that allows using something
28
+ # other than an environment variable if needed.
29
+ #
30
+ # @param cmd [String] Executable to search for.
31
+ # @param extra_path [Array<String>] Extra directories to always search.
32
+ # @param path [String, nil] Replacement $PATH value.
33
+ # @return [String, false]
34
+ def which(cmd, extra_path: %w{/bin /usr/bin /sbin /usr/sbin}, path: nil)
35
+ # Allow passing something other than the real env var.
36
+ path ||= ENV['PATH']
37
+ # Based on Chef::Mixin::Which#which
38
+ # Copyright 2010-2015, Chef Softare, Inc.
39
+ paths = path.split(File::PATH_SEPARATOR) + extra_path
40
+ paths.each do |candidate_path|
41
+ filename = ::File.join(candidate_path, cmd)
42
+ return filename if ::File.executable?(filename)
43
+ end
44
+ false
45
+ end
46
+
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,20 @@
1
+ #
2
+ # Copyright 2015, Noah Kantrowitz
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ #
16
+
17
+
18
+ module PoiseLanguages
19
+ VERSION = '1.0.0'
20
+ end
@@ -0,0 +1,40 @@
1
+ #
2
+ # Copyright 2015, Noah Kantrowitz
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ #
16
+
17
+ lib = File.expand_path('../lib', __FILE__)
18
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
19
+ require 'poise_languages/version'
20
+
21
+ Gem::Specification.new do |spec|
22
+ spec.name = 'poise-languages'
23
+ spec.version = PoiseLanguages::VERSION
24
+ spec.authors = ['Noah Kantrowitz']
25
+ spec.email = %w{noah@coderanger.net}
26
+ spec.description = "A Chef cookbook to help writing language cooobkoks."
27
+ spec.summary = spec.description
28
+ spec.homepage = 'https://github.com/poise/poise-languages'
29
+ spec.license = 'Apache 2.0'
30
+
31
+ spec.files = `git ls-files`.split($/)
32
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
33
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
34
+ spec.require_paths = %w{lib}
35
+
36
+ spec.add_dependency 'halite', '~> 1.0'
37
+ spec.add_dependency 'poise', '~> 2.3'
38
+
39
+ spec.add_development_dependency 'poise-boiler', '~> 1.0'
40
+ end
@@ -0,0 +1,19 @@
1
+ #
2
+ # Copyright 2015, Noah Kantrowitz
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ #
16
+
17
+ eval_gemfile File.expand_path('../../../Gemfile', __FILE__)
18
+
19
+ gem 'chef', '~> 12.0'
@@ -0,0 +1,22 @@
1
+ #
2
+ # Copyright 2015, Noah Kantrowitz
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ #
16
+
17
+ eval_gemfile File.expand_path('../../../Gemfile', __FILE__)
18
+
19
+ gem 'chef', github: 'chef/chef'
20
+ gem 'halite', github: 'poise/halite'
21
+ gem 'poise', github: 'poise/poise'
22
+ gem 'poise-boiler', github: 'poise/poise-boiler'
@@ -0,0 +1,328 @@
1
+ #
2
+ # Copyright 2015, Noah Kantrowitz
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ #
16
+
17
+ require 'spec_helper'
18
+
19
+ describe PoiseLanguages::Command::Mixin do
20
+ resource(:mylang_runtime) do
21
+ include Poise(container: true)
22
+ attribute(:mylang_binary, default: '/binary')
23
+ attribute(:mylang_environment, default: {'MYLANG_PATH' => '/thing'})
24
+ end
25
+ provider(:mylang_runtime)
26
+ let(:runtime) { chef_run.mylang_runtime('parent') }
27
+
28
+ describe PoiseLanguages::Command::Mixin::Resource do
29
+ resource(:poise_test) do
30
+ klass = described_class
31
+ include Module.new {
32
+ include klass
33
+ language_command_mixin(:mylang)
34
+ }
35
+ def which(name)
36
+ "/which/#{name}"
37
+ end
38
+ end
39
+ provider(:poise_test)
40
+
41
+ describe '#parent_$name' do
42
+ context 'with a parent' do
43
+ recipe do
44
+ mylang_runtime 'parent'
45
+ poise_test 'test'
46
+ end
47
+ it { is_expected.to run_poise_test('test').with(parent_mylang: chef_run.mylang_runtime('parent')) }
48
+ end # /context with a parent
49
+
50
+ context 'with no parent' do
51
+ recipe do
52
+ poise_test 'test'
53
+ end
54
+ it { is_expected.to run_poise_test('test').with(parent_mylang: nil) }
55
+ end # /context with no parent
56
+
57
+ context 'with two containers' do
58
+ recipe do
59
+ mylang_runtime 'parent'
60
+ poise_test 'test'
61
+ mylang_runtime 'other'
62
+ end
63
+
64
+ it { is_expected.to run_poise_test('test').with(parent_mylang: chef_run.mylang_runtime('parent')) }
65
+ end # /context with two containers
66
+ end # /describe #parent_$name
67
+
68
+ describe '#timeout' do
69
+ recipe do
70
+ poise_test 'test' do
71
+ # Be explicit because Kernel#timeout is part of the timeout.rb lib.
72
+ self.timeout(123)
73
+ end
74
+ end
75
+
76
+ context 'with timeout enabled' do
77
+ it { is_expected.to run_poise_test('test').with(timeout: 123) }
78
+ end # /context with timeout enabled
79
+
80
+ context 'with timeout disabled' do
81
+ resource(:poise_test) do
82
+ klass = described_class
83
+ include Module.new {
84
+ include klass
85
+ language_command_mixin(:poise, timeout: false)
86
+ }
87
+ end
88
+ it { expect { subject }.to raise_error NoMethodError }
89
+ end # /context with timeout disabled
90
+ end # /describe #timeout
91
+
92
+ describe '#$name' do
93
+ context 'with an implicit parent' do
94
+ recipe do
95
+ mylang_runtime 'parent'
96
+ poise_test 'test'
97
+ end
98
+
99
+ it { is_expected.to run_poise_test('test').with(parent_mylang: runtime, mylang: '/binary') }
100
+ end # /context with an implicit parent
101
+
102
+ context 'with a parent resource' do
103
+ recipe do
104
+ r = mylang_runtime 'parent'
105
+ poise_test 'test' do
106
+ mylang r
107
+ end
108
+ end
109
+
110
+ it { is_expected.to run_poise_test('test').with(parent_mylang: runtime, mylang: '/binary') }
111
+ end # /context with a parent resource
112
+
113
+ context 'with a parent resource name' do
114
+ recipe do
115
+ mylang_runtime 'parent'
116
+ poise_test 'test' do
117
+ mylang 'parent'
118
+ end
119
+ end
120
+
121
+ it { is_expected.to run_poise_test('test').with(parent_mylang: runtime, mylang: '/binary') }
122
+ end # /context with a parent resource name
123
+
124
+ context 'with a parent resource name that looks like a path' do
125
+ let(:runtime) { chef_run.mylang_runtime('/usr/bin/other') }
126
+ recipe do
127
+ mylang_runtime '/usr/bin/other' do
128
+ mylang_binary name
129
+ end
130
+ poise_test 'test' do
131
+ mylang '/usr/bin/other'
132
+ end
133
+ end
134
+
135
+ it { is_expected.to run_poise_test('test').with(parent_mylang: runtime, mylang: '/usr/bin/other') }
136
+ end # /context with a parent resource name that looks like a path
137
+
138
+ context 'with a path' do
139
+ recipe do
140
+ poise_test 'test' do
141
+ mylang '/usr/bin/other'
142
+ end
143
+ end
144
+
145
+ it { is_expected.to run_poise_test('test').with(parent_mylang: nil, mylang: '/usr/bin/other') }
146
+ end # /context with a path
147
+
148
+ context 'with a path and an implicit parent' do
149
+ recipe do
150
+ mylang_runtime 'parent'
151
+ poise_test 'test' do
152
+ mylang '/usr/bin/other'
153
+ end
154
+ end
155
+
156
+ it { is_expected.to run_poise_test('test').with(parent_mylang: runtime, mylang: '/usr/bin/other') }
157
+ end # /context with a path and an implicit parent
158
+
159
+ context 'with an invalid parent' do
160
+ recipe do
161
+ poise_test 'test' do
162
+ mylang 'test'
163
+ end
164
+ end
165
+
166
+ it { expect { subject }.to raise_error Chef::Exceptions::ResourceNotFound }
167
+ end # /context with an invalid parent
168
+
169
+ context 'with no parent' do
170
+ recipe do
171
+ poise_test 'test'
172
+ end
173
+
174
+ it { is_expected.to run_poise_test('test').with(parent_mylang: nil, mylang: '/which/mylang') }
175
+ end # /context with no parent
176
+ end # /describe #$name
177
+
178
+ describe '#$name_from_parent' do
179
+ context 'with a resource parent' do
180
+ recipe do
181
+ mylang_runtime 'parent'
182
+ r = poise_test 'first' do
183
+ mylang 'parent'
184
+ end
185
+ mylang_runtime 'other'
186
+ poise_test 'test' do
187
+ mylang_from_parent r
188
+ end
189
+ end
190
+
191
+ it { is_expected.to run_poise_test('test').with(parent_mylang: runtime, mylang: '/binary') }
192
+ end # /context with a resource parent
193
+
194
+ context 'with a path parent' do
195
+ recipe do
196
+ r = poise_test 'first' do
197
+ mylang '/other'
198
+ end
199
+ poise_test 'test' do
200
+ mylang_from_parent r
201
+ end
202
+ end
203
+
204
+ it { is_expected.to run_poise_test('test').with(parent_mylang: nil, mylang: '/other') }
205
+ end # /context with a path parent
206
+ end # /describe #$name_from_parent
207
+
208
+ context 'as a method' do
209
+ resource(:poise_test) do
210
+ include Module.new {
211
+ include PoiseLanguages::Command::Mixin::Resource(:mylang)
212
+ }
213
+ end
214
+ recipe do
215
+ mylang_runtime 'parent'
216
+ poise_test 'test'
217
+ end
218
+
219
+ it { is_expected.to run_poise_test('test').with(parent_mylang: runtime, mylang: '/binary') }
220
+ end # /context as a method
221
+ end # /describe PoiseLanguages::Command::Mixin::Resource
222
+
223
+ describe PoiseLanguages::Command::Mixin::Provider do
224
+ resource(:poise_test) do
225
+ include PoiseLanguages::Command::Mixin::Resource(:mylang)
226
+ include Poise::Helpers::LWRPPolyfill
227
+ attribute(:command)
228
+ attribute(:expect)
229
+ attribute(:options, default: [])
230
+ def which(name)
231
+ "/which/#{name}"
232
+ end
233
+ end
234
+
235
+ describe '#$name_shell_out' do
236
+ provider(:poise_test) do
237
+ klass = described_class
238
+ include Module.new {
239
+ include klass
240
+ language_command_mixin(:mylang)
241
+ }
242
+ def action_run
243
+ expect(self).to receive(:shell_out).with(*new_resource.expect)
244
+ mylang_shell_out(new_resource.command, *new_resource.options)
245
+ end
246
+ end
247
+
248
+ context 'with a parent' do
249
+ recipe do
250
+ mylang_runtime 'parent'
251
+ poise_test 'test' do
252
+ command 'foo'
253
+ expect ['/binary foo', {environment: {'MYLANG_PATH' => '/thing'}, timeout: 900}]
254
+ end
255
+ end
256
+ it { run_chef }
257
+ end # /context with a parent
258
+
259
+ context 'without a parent' do
260
+ recipe do
261
+ poise_test 'test' do
262
+ command 'foo'
263
+ expect ['/which/mylang foo', {timeout: 900}]
264
+ end
265
+ end
266
+ it { run_chef }
267
+ end # /context without a parent
268
+
269
+ context 'with a timeout' do
270
+ recipe do
271
+ mylang_runtime 'parent'
272
+ poise_test 'test' do
273
+ timeout 300
274
+ command 'foo'
275
+ expect ['/binary foo', {environment: {'MYLANG_PATH' => '/thing'}, timeout: 300}]
276
+ end
277
+ end
278
+ it { run_chef }
279
+ end # /context with a timeout
280
+
281
+ context 'with environment options' do
282
+ recipe do
283
+ mylang_runtime 'parent'
284
+ poise_test 'test' do
285
+ command 'foo'
286
+ options [{environment: {'OTHER' => 'foo'}}]
287
+ expect ['/binary foo', {environment: {'MYLANG_PATH' => '/thing', 'OTHER' => 'foo'}, timeout: 900}]
288
+ end
289
+ end
290
+ it { run_chef }
291
+ end # /context with environment options
292
+
293
+ context 'with an array command' do
294
+ recipe do
295
+ poise_test 'test' do
296
+ command ['foo']
297
+ expect [['/which/mylang', 'foo'], {timeout: 900}]
298
+ end
299
+ end
300
+ it { run_chef }
301
+ end # /context with an array command
302
+ end # /describe #$name_shell_out
303
+
304
+ describe '#$name_shell_out!' do
305
+ provider(:poise_test) do
306
+ klass = described_class
307
+ include Module.new {
308
+ include klass
309
+ language_command_mixin(:mylang)
310
+ }
311
+ def action_run
312
+ fake_output = double()
313
+ expect(fake_output).to receive(:error!)
314
+ expect(self).to receive(:mylang_shell_out).with(*new_resource.expect).and_return(fake_output)
315
+ mylang_shell_out!(new_resource.command, *new_resource.options)
316
+ end
317
+ end
318
+ recipe do
319
+ poise_test 'test' do
320
+ command 'foo'
321
+ expect ['foo']
322
+ end
323
+ end
324
+
325
+ it { run_chef }
326
+ end # /describe #$name_shell_out!
327
+ end # /describe PoiseLanguages::Command::Mixin::Provider
328
+ end