poise-ruby 2.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.
Files changed (41) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +11 -0
  3. data/.kitchen.travis.yml +9 -0
  4. data/.kitchen.yml +9 -0
  5. data/.travis.yml +20 -0
  6. data/.yardopts +7 -0
  7. data/Berksfile +28 -0
  8. data/Gemfile +33 -0
  9. data/LICENSE +201 -0
  10. data/README.md +290 -0
  11. data/Rakefile +17 -0
  12. data/chef/attributes/default.rb +23 -0
  13. data/chef/recipes/default.rb +19 -0
  14. data/lib/poise_ruby.rb +24 -0
  15. data/lib/poise_ruby/cheftie.rb +18 -0
  16. data/lib/poise_ruby/error.rb +21 -0
  17. data/lib/poise_ruby/resources.rb +29 -0
  18. data/lib/poise_ruby/resources/bundle_install.rb +221 -0
  19. data/lib/poise_ruby/resources/ruby_execute.rb +91 -0
  20. data/lib/poise_ruby/resources/ruby_gem.rb +118 -0
  21. data/lib/poise_ruby/resources/ruby_runtime.rb +87 -0
  22. data/lib/poise_ruby/ruby_command_mixin.rb +59 -0
  23. data/lib/poise_ruby/ruby_providers.rb +32 -0
  24. data/lib/poise_ruby/ruby_providers/base.rb +116 -0
  25. data/lib/poise_ruby/ruby_providers/chef.rb +53 -0
  26. data/lib/poise_ruby/ruby_providers/scl.rb +77 -0
  27. data/lib/poise_ruby/ruby_providers/system.rb +115 -0
  28. data/lib/poise_ruby/version.rb +20 -0
  29. data/poise-ruby.gemspec +41 -0
  30. data/test/cookbooks/poise-ruby_test/metadata.rb +18 -0
  31. data/test/cookbooks/poise-ruby_test/recipes/bundle_install.rb +102 -0
  32. data/test/cookbooks/poise-ruby_test/recipes/default.rb +85 -0
  33. data/test/gemfiles/chef-12.gemfile +19 -0
  34. data/test/gemfiles/master.gemfile +23 -0
  35. data/test/integration/default/serverspec/bundle_install_spec.rb +73 -0
  36. data/test/integration/default/serverspec/default_spec.rb +46 -0
  37. data/test/spec/resources/bundle_install_spec.rb +306 -0
  38. data/test/spec/resources/ruby_execute_spec.rb +78 -0
  39. data/test/spec/ruby_command_mixin_spec.rb +34 -0
  40. data/test/spec/spec_helper.rb +18 -0
  41. metadata +155 -0
@@ -0,0 +1,17 @@
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 'poise_boiler/rakefile'
@@ -0,0 +1,23 @@
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
+ # Default inversion options.
18
+ default['poise-ruby']['provider'] = 'auto'
19
+ default['poise-ruby']['options'] = {}
20
+
21
+ # Used for the default recipe.
22
+ default['poise-ruby']['install_ruby'] = true
23
+ default['poise-ruby']['install_chef_ruby'] = true
@@ -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
+ # Default runtimes, last one will be the default.
18
+ ruby_runtime('chef') { provider :chef } if node['poise-ruby']['install_chef_ruby']
19
+ ruby_runtime 'ruby' if node['poise-ruby']['install_ruby']
@@ -0,0 +1,24 @@
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 PoiseRuby
19
+ autoload :Error, 'poise_ruby/error'
20
+ autoload :Resources, 'poise_ruby/resources'
21
+ autoload :RubyCommandMixin, 'poise_ruby/ruby_command_mixin'
22
+ autoload :RubyProviders, 'poise_ruby/ruby_providers'
23
+ autoload :VERSION, 'poise_ruby/version'
24
+ end
@@ -0,0 +1,18 @@
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 'poise_ruby/resources'
18
+ require 'poise_ruby/ruby_providers'
@@ -0,0 +1,21 @@
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 PoiseRuby
19
+ class Error < ::Exception
20
+ end
21
+ end
@@ -0,0 +1,29 @@
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 'poise_ruby/resources/bundle_install'
18
+ require 'poise_ruby/resources/ruby_execute'
19
+ require 'poise_ruby/resources/ruby_gem'
20
+ require 'poise_ruby/resources/ruby_runtime'
21
+
22
+
23
+ module PoiseRuby
24
+ # Chef resources and providers for poise-ruby.
25
+ #
26
+ # @since 2.0.0
27
+ module Resources
28
+ end
29
+ end
@@ -0,0 +1,221 @@
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/mixin/shell_out'
18
+ require 'chef/mixin/which'
19
+ require 'chef/provider'
20
+ require 'chef/resource'
21
+ require 'poise'
22
+
23
+ require 'poise_ruby/error'
24
+ require 'poise_ruby/ruby_command_mixin'
25
+
26
+
27
+ module PoiseRuby
28
+ module Resources
29
+ # (see BundleInstall::Resource)
30
+ # @since 2.0.0
31
+ module BundleInstall
32
+ # A `bundle_install` resource to install a [Bundler](http://bundler.io/)
33
+ # Gemfile.
34
+ #
35
+ # @provides bundle_install
36
+ # @action install
37
+ # @action update
38
+ # @note
39
+ # This resource is not idempotent itself, it will always run `bundle
40
+ # install`.
41
+ # @example
42
+ # bundle_install '/opt/my_app' do
43
+ # gem_path '/usr/local/bin/gem'
44
+ # end
45
+ class Resource < Chef::Resource
46
+ include Poise
47
+ provides(:bundle_install)
48
+ actions(:install, :update)
49
+ include PoiseRuby::RubyCommandMixin
50
+
51
+ # @!attribute path
52
+ # Path to the Gemfile or to a directory that contains a Gemfile.
53
+ # @return [String]
54
+ attribute(:path, kind_of: String, name_attribute: true)
55
+ # @!attribute binstubs
56
+ # Enable binstubs. If set to a string it is the path to generate
57
+ # stubs in.
58
+ # @return [Boolean, String]
59
+ attribute(:binstubs, kind_of: [TrueClass, String])
60
+ # @!attribute deployment
61
+ # Enable deployment mode.
62
+ # @return [Boolean]
63
+ attribute(:deployment, equal_to: [true, false], default: false)
64
+ # @!attribute jobs
65
+ # Number of parallel installations to run.
66
+ # @return [String, Integer]
67
+ attribute(:jobs, kind_of: [String, Integer])
68
+ # @!attribute retry
69
+ # Number of times to retry failed installations.
70
+ # @return [String, Integer]
71
+ attribute(:retry, kind_of: [String, Integer])
72
+ # @!attribute user
73
+ # User to run bundler as.
74
+ # @return [String, Integery, nil]
75
+ attribute(:user, kind_of: [String, Integer, NilClass])
76
+ # @!attribute vendor
77
+ # Enable local vendoring. This maps to the `--path` option in bundler,
78
+ # but that attribute name is already used.
79
+ # @return [Boolean, String]
80
+ attribute(:vendor, kind_of: [TrueClass, String])
81
+ # @!attribute without
82
+ # Group or groups to not install.
83
+ # @return [String, Array<String>]
84
+ attribute(:without, kind_of: [Array, String])
85
+
86
+ # The path to the `bundle` binary for this installation. This is an
87
+ # output property.
88
+ #
89
+ # @return [String]
90
+ # @example
91
+ # execute "#{resources('bundle_install[/opt/myapp]').bundler_binary} vendor"
92
+ def bundler_binary
93
+ @bundler_binary ||= provider_for_action(:bundler_binary).bundler_binary
94
+ end
95
+
96
+ # The path to the Gemfile for this installation. This is an output
97
+ # property.
98
+ #
99
+ # @return [String]
100
+ # @example
101
+ # file resources('bundle_install[/opt/myapp]').gemfile_path do
102
+ # owner 'root'
103
+ # end
104
+ def gemfile_path
105
+ @gemfile_path ||= provider_for_action(:gemfile_path).gemfile_path
106
+ end
107
+ end
108
+
109
+ # The default provider for the `bundle_install` resource.
110
+ #
111
+ # @see Resource
112
+ class Provider < Chef::Provider
113
+ include Poise
114
+ provides(:bundle_install)
115
+ include PoiseRuby::RubyCommandMixin
116
+
117
+ # Install bundler and the gems in the Gemfile.
118
+ def action_install
119
+ run_bundler('install')
120
+ end
121
+
122
+ # Install bundler and update the gems in the Gemfile.
123
+ def action_update
124
+ run_bundler('update')
125
+ end
126
+
127
+ # Return the absolute path to the correct bundle binary to run.
128
+ #
129
+ # @return [String]
130
+ def bundler_binary
131
+ @bundler_binary ||= ::File.join(gem_bindir, 'bundle')
132
+ end
133
+
134
+ # Find the absolute path to the Gemfile. This mirrors bundler's internal
135
+ # search logic by scanning up to parent folder as needed.
136
+ #
137
+ # @return [String]
138
+ def gemfile_path
139
+ @gemfile_path ||= begin
140
+ path = ::File.expand_path(new_resource.path)
141
+ if ::File.file?(path)
142
+ # We got a path to a real file, use that.
143
+ path
144
+ else
145
+ # Walk back until path==dirname(path) meaning we are at the root
146
+ while path != (next_path = ::File.dirname(path))
147
+ possible_path = ::File.join(path, 'Gemfile')
148
+ return possible_path if ::File.file?(possible_path)
149
+ path = next_path
150
+ end
151
+ end
152
+ end
153
+ end
154
+
155
+ private
156
+
157
+ # Install the gems in the Gemfile.
158
+ def run_bundler(command)
159
+ return converge_by "Run bundle #{command}" if whyrun_mode?
160
+ cmd = ruby_shell_out!(bundler_command(command), environment: {'BUNDLE_GEMFILE' => gemfile_path}, user: new_resource.user)
161
+ # Look for a line like 'Installing $gemname $version' to know if we did anything.
162
+ if cmd.stdout.include?('Installing')
163
+ new_resource.updated_by_last_action(true)
164
+ end
165
+ end
166
+
167
+ # Parse out the value for Gem.bindir. This is so complicated to minimize
168
+ # the required configuration on the resource combined with gem having
169
+ # terrible output formats.
170
+ #
171
+ # @return [String]
172
+ def gem_bindir
173
+ cmd = ruby_shell_out!(new_resource.gem_binary, 'environment')
174
+ # Parse a line like:
175
+ # - EXECUTABLE DIRECTORY: /usr/local/bin
176
+ matches = cmd.stdout.scan(/EXECUTABLE DIRECTORY: (.*)$/).first
177
+ if matches
178
+ matches.first
179
+ else
180
+ raise PoiseRuby::Error.new("Cannot find EXECUTABLE DIRECTORY: #{cmd.stdout}")
181
+ end
182
+ end
183
+
184
+ # Command line options for the bundle install.
185
+ #
186
+ # @return [Array<String>]
187
+ def bundler_options
188
+ [].tap do |opts|
189
+ if new_resource.binstubs
190
+ opts << "--binstubs" + (new_resource.binstubs.is_a?(String) ? "=#{new_resource.binstubs}" : '')
191
+ end
192
+ if new_resource.vendor
193
+ opts << "--path=" + (new_resource.vendor.is_a?(String) ? new_resource.vendor : 'vendor/bundle')
194
+ end
195
+ if new_resource.deployment
196
+ opts << '--deployment'
197
+ end
198
+ if new_resource.jobs
199
+ opts << "--jobs=#{new_resource.jobs}"
200
+ end
201
+ if new_resource.retry
202
+ opts << "--retry=#{new_resource.retry}"
203
+ end
204
+ if new_resource.without
205
+ opts << '--without'
206
+ opts.insert(-1, *new_resource.without)
207
+ end
208
+ end
209
+ end
210
+
211
+ # Command array to run when installing the Gemfile.
212
+ #
213
+ # @return [Array<String>]
214
+ def bundler_command(command)
215
+ [bundler_binary, command] + bundler_options
216
+ end
217
+
218
+ end
219
+ end
220
+ end
221
+ end
@@ -0,0 +1,91 @@
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 'chef/mash'
20
+ require 'chef/provider/execute'
21
+ require 'chef/resource/execute'
22
+ require 'poise'
23
+
24
+ require 'poise_ruby/ruby_command_mixin'
25
+
26
+
27
+ module PoiseRuby
28
+ module Resources
29
+ # (see RubyExecute::Resource)
30
+ # @since 2.0.0
31
+ module RubyExecute
32
+ # A `ruby_execute` resource to run Ruby scripts and commands.
33
+ #
34
+ # @provides ruby_execute
35
+ # @action run
36
+ # @example
37
+ # ruby_execute 'myapp.rb' do
38
+ # user 'myuser'
39
+ # end
40
+ class Resource < Chef::Resource::Execute
41
+ include Poise
42
+ provides(:ruby_execute)
43
+ actions(:run)
44
+ include PoiseRuby::RubyCommandMixin
45
+
46
+ # @!attribute parent_bundle
47
+ # Optional bundle_install resource to run `bundle exec` against.
48
+ # @return [PoiseRuby::Resources::BundleInstall::Resource]
49
+ parent_attribute(:bundle, type: :bundle_install, optional: true, auto: false)
50
+ end
51
+
52
+ # The default provider for `ruby_execute`.
53
+ #
54
+ # @see Resource
55
+ # @provides ruby_execute
56
+ class Provider < Chef::Provider::Execute
57
+ provides(:ruby_execute)
58
+
59
+ private
60
+
61
+ # Command to pass to shell_out.
62
+ #
63
+ # @return [String, Array<String>]
64
+ def command
65
+ prefix = [new_resource.ruby]
66
+ if new_resource.parent_bundle
67
+ prefix << new_resource.parent_bundle.bundler_binary
68
+ prefix << 'exec'
69
+ end
70
+ if new_resource.command.is_a?(Array)
71
+ prefix + new_resource.command
72
+ else
73
+ "#{Shellwords.join(prefix)} #{new_resource.command}"
74
+ end
75
+ end
76
+
77
+ # Environment variables to pass to shell_out.
78
+ #
79
+ # @return [Hash]
80
+ def environment
81
+ Mash.new.tap do |environment|
82
+ environment.update(new_resource.parent_ruby.ruby_environment) if new_resource.parent_ruby
83
+ environment['BUNDLE_GEMFILE'] = new_resource.parent_bundle.gemfile_path if new_resource.parent_bundle
84
+ environment.update(new_resource.environment) if new_resource.environment
85
+ end
86
+ end
87
+
88
+ end
89
+ end
90
+ end
91
+ end