poise-python 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.
Files changed (51) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +11 -0
  3. data/.kitchen.travis.yml +9 -0
  4. data/.kitchen.yml +8 -0
  5. data/.travis.yml +21 -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 +399 -0
  11. data/Rakefile +17 -0
  12. data/chef/attributes/default.rb +24 -0
  13. data/chef/recipes/default.rb +20 -0
  14. data/lib/poise_python.rb +25 -0
  15. data/lib/poise_python/cheftie.rb +18 -0
  16. data/lib/poise_python/error.rb +23 -0
  17. data/lib/poise_python/python_command_mixin.rb +45 -0
  18. data/lib/poise_python/python_providers.rb +35 -0
  19. data/lib/poise_python/python_providers/base.rb +177 -0
  20. data/lib/poise_python/python_providers/portable_pypy.rb +96 -0
  21. data/lib/poise_python/python_providers/scl.rb +77 -0
  22. data/lib/poise_python/python_providers/system.rb +86 -0
  23. data/lib/poise_python/resources.rb +31 -0
  24. data/lib/poise_python/resources/pip_requirements.rb +102 -0
  25. data/lib/poise_python/resources/python_execute.rb +83 -0
  26. data/lib/poise_python/resources/python_package.rb +322 -0
  27. data/lib/poise_python/resources/python_runtime.rb +114 -0
  28. data/lib/poise_python/resources/python_runtime_pip.rb +167 -0
  29. data/lib/poise_python/resources/python_runtime_test.rb +185 -0
  30. data/lib/poise_python/resources/python_virtualenv.rb +164 -0
  31. data/lib/poise_python/utils.rb +63 -0
  32. data/lib/poise_python/utils/python_encoder.rb +73 -0
  33. data/lib/poise_python/version.rb +20 -0
  34. data/poise-python.gemspec +41 -0
  35. data/test/cookbooks/poise-python_test/metadata.rb +18 -0
  36. data/test/cookbooks/poise-python_test/recipes/default.rb +40 -0
  37. data/test/gemfiles/chef-12.gemfile +19 -0
  38. data/test/gemfiles/master.gemfile +23 -0
  39. data/test/integration/default/serverspec/default_spec.rb +102 -0
  40. data/test/spec/python_command_mixin_spec.rb +115 -0
  41. data/test/spec/python_providers/portable_pypy_spec.rb +68 -0
  42. data/test/spec/python_providers/scl_spec.rb +75 -0
  43. data/test/spec/python_providers/system_spec.rb +81 -0
  44. data/test/spec/resources/pip_requirements_spec.rb +69 -0
  45. data/test/spec/resources/python_package_spec.rb +65 -0
  46. data/test/spec/resources/python_runtime_pip_spec.rb +33 -0
  47. data/test/spec/resources/python_virtualenv_spec.rb +103 -0
  48. data/test/spec/spec_helper.rb +19 -0
  49. data/test/spec/utils/python_encoder_spec.rb +79 -0
  50. data/test/spec/utils_spec.rb +86 -0
  51. metadata +170 -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,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
+ # Default inversion options.
18
+ default['poise-python']['provider'] = 'auto'
19
+ default['poise-python']['options'] = {}
20
+
21
+ # Used for the default recipe.
22
+ default['poise-python']['install_python2'] = true
23
+ default['poise-python']['install_python3'] = false
24
+ default['poise-python']['install_pypy'] = false
@@ -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
+ # Default runtimes, last one will be the default.
18
+ python_runtime 'pypy' if node['poise-python']['install_pypy']
19
+ python_runtime '3' if node['poise-python']['install_python3']
20
+ python_runtime '2' if node['poise-python']['install_python2']
@@ -0,0 +1,25 @@
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 PoisePython
19
+ autoload :Error, 'poise_python/error'
20
+ autoload :Resources, 'poise_python/resources'
21
+ autoload :PythonCommandMixin, 'poise_python/python_command_mixin'
22
+ autoload :PythonProviders, 'poise_python/python_providers'
23
+ autoload :Utils, 'poise_python/utils'
24
+ autoload :VERSION, 'poise_python/version'
25
+ 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_python/resources'
18
+ require 'poise_python/python_providers'
@@ -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
+ require 'poise_languages'
18
+
19
+
20
+ module PoisePython
21
+ class Error < PoiseLanguages::Error
22
+ end
23
+ end
@@ -0,0 +1,45 @@
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/utils'
18
+ require 'poise_languages'
19
+
20
+
21
+ module PoisePython
22
+ # Mixin for resources and providers which run Python commands.
23
+ #
24
+ # @since 1.0.0
25
+ module PythonCommandMixin
26
+ include Poise::Utils::ResourceProviderMixin
27
+
28
+ # Mixin for resources which run Python commands.
29
+ module Resource
30
+ include PoiseLanguages::Command::Mixin::Resource(:python)
31
+
32
+ # Wrapper for setting the parent to be a virtualenv.
33
+ #
34
+ # @param name [String] Name of the virtualenv resource.
35
+ # @return [void]
36
+ def virtualenv(name)
37
+ parent_python("python_virtualenv[#{name}]")
38
+ end
39
+ end
40
+
41
+ module Provider
42
+ include PoiseLanguages::Command::Mixin::Provider(:python)
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,35 @@
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_python/python_providers/portable_pypy'
18
+ require 'poise_python/python_providers/scl'
19
+ require 'poise_python/python_providers/system'
20
+
21
+
22
+ module PoisePython
23
+ # Inversion providers for the python_runtime resource.
24
+ #
25
+ # @since 1.0.0
26
+ module PythonProviders
27
+ autoload :Base, 'poise_python/python_providers/base'
28
+
29
+ Chef::Platform::ProviderPriorityMap.instance.priority(:python_runtime, [
30
+ PoisePython::PythonProviders::PortablePyPy,
31
+ PoisePython::PythonProviders::Scl,
32
+ PoisePython::PythonProviders::System,
33
+ ])
34
+ end
35
+ end
@@ -0,0 +1,177 @@
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/provider'
18
+ require 'poise'
19
+
20
+
21
+ module PoisePython
22
+ module PythonProviders
23
+ class Base < Chef::Provider
24
+ include Poise(inversion: :python_runtime)
25
+
26
+ # Set default inversion options.
27
+ #
28
+ # @api private
29
+ def self.default_inversion_options(node, new_resource)
30
+ super.merge({
31
+ pip_version: new_resource.pip_version,
32
+ setuptools_version: new_resource.setuptools_version,
33
+ version: new_resource.version,
34
+ virtualenv_version: new_resource.virtualenv_version,
35
+ wheel_version: new_resource.wheel_version,
36
+ })
37
+ end
38
+
39
+ # The `install` action for the `python_runtime` resource.
40
+ #
41
+ # @return [void]
42
+ def action_install
43
+ # First inner converge for the Python install.
44
+ notifying_block do
45
+ install_python
46
+ end
47
+ # Second inner converge for the support tools. This is needed because
48
+ # we run a python command to check if venv is available.
49
+ notifying_block do
50
+ install_pip
51
+ install_setuptools
52
+ install_wheel
53
+ install_virtualenv
54
+ end
55
+ end
56
+
57
+ # The `uninstall` action for the `python_runtime` resource.
58
+ #
59
+ # @abstract
60
+ # @return [void]
61
+ def action_uninstall
62
+ notifying_block do
63
+ uninstall_python
64
+ end
65
+ end
66
+
67
+ # The path to the `python` binary. This is an output property.
68
+ #
69
+ # @abstract
70
+ # @return [String]
71
+ def python_binary
72
+ raise NotImplementedError
73
+ end
74
+
75
+ # The environment variables for this Python. This is an output property.
76
+ #
77
+ # @return [Hash<String, String>]
78
+ def python_environment
79
+ {}
80
+ end
81
+
82
+ private
83
+
84
+ # Install the Python runtime. Must be implemented by subclass.
85
+ #
86
+ # @abstract
87
+ # @return [void]
88
+ def install_python
89
+ raise NotImplementedError
90
+ end
91
+
92
+ # Uninstall the Python runtime. Must be implemented by subclass.
93
+ #
94
+ # @abstract
95
+ # @return [void]
96
+ def uninstall_python
97
+ raise NotImplementedError
98
+ end
99
+
100
+ # Install pip in to the Python runtime.
101
+ #
102
+ # @return [void]
103
+ def install_pip
104
+ pip_version_or_url = options[:pip_version]
105
+ return unless pip_version_or_url
106
+ # If there is a : in the version, use it as a URL.
107
+ if pip_version_or_url.is_a?(String) && pip_version_or_url.include?(':')
108
+ pip_version = nil
109
+ pip_url = pip_version_or_url
110
+ else
111
+ pip_version = pip_version_or_url
112
+ pip_url = nil
113
+ end
114
+ Chef::Log.debug("[#{new_resource}] Installing pip #{pip_version || 'latest'}")
115
+ # Install or bootstrap pip.
116
+ python_runtime_pip new_resource.name do
117
+ parent new_resource
118
+ # If the version is `true`, don't pass it at all.
119
+ version pip_version if pip_version.is_a?(String)
120
+ get_pip_url pip_url if pip_url
121
+ end
122
+ end
123
+
124
+ # Install setuptools in to the Python runtime. This is very similar to the
125
+ # {#install_wheel} and {#install_virtualenv} methods but they are kept
126
+ # separate for the benefit of subclasses being able to override them
127
+ # individually.
128
+ #
129
+ # @return [void]
130
+ def install_setuptools
131
+ # Captured because #options conflicts with Chef::Resource::Package#options.
132
+ setuptools_version = options[:setuptools_version]
133
+ return unless setuptools_version
134
+ Chef::Log.debug("[#{new_resource}] Installing setuptools #{setuptools_version == true ? 'latest' : setuptools_version}")
135
+ # Install setuptools via pip.
136
+ python_package 'setuptools' do
137
+ parent_python new_resource
138
+ version setuptools_version if setuptools_version.is_a?(String)
139
+ end
140
+ end
141
+
142
+ # Install wheel in to the Python runtime.
143
+ #
144
+ # @return [void]
145
+ def install_wheel
146
+ # Captured because #options conflicts with Chef::Resource::Package#options.
147
+ wheel_version = options[:wheel_version]
148
+ return unless wheel_version
149
+ Chef::Log.debug("[#{new_resource}] Installing setuptools #{wheel_version == true ? 'latest' : wheel_version}")
150
+ # Install wheel via pip.
151
+ python_package 'wheel' do
152
+ parent_python new_resource
153
+ version wheel_version if wheel_version.is_a?(String)
154
+ end
155
+ end
156
+
157
+ # Install virtualenv in to the Python runtime.
158
+ #
159
+ # @return [void]
160
+ def install_virtualenv
161
+ # Captured because #options conflicts with Chef::Resource::Package#options.
162
+ virtualenv_version = options[:virtualenv_version]
163
+ return unless virtualenv_version
164
+ # Check if the venv module exists.
165
+ cmd = shell_out([python_binary, '-m', 'venv', '-h'], environment: python_environment)
166
+ return unless cmd.error?
167
+ Chef::Log.debug("[#{new_resource}] Installing virtualenv #{virtualenv_version == true ? 'latest' : virtualenv_version}")
168
+ # Install virtualenv via pip.
169
+ python_package 'virtualenv' do
170
+ parent_python new_resource
171
+ version virtualenv_version if virtualenv_version.is_a?(String)
172
+ end
173
+ end
174
+
175
+ end
176
+ end
177
+ end
@@ -0,0 +1,96 @@
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
+
19
+ require 'poise_python/error'
20
+ require 'poise_python/python_providers/base'
21
+
22
+
23
+ module PoisePython
24
+ module PythonProviders
25
+ class PortablePyPy < Base
26
+ provides(:portable_pypy)
27
+
28
+ PYPY_PACKAGES = {
29
+ 'pypy' => %w{2.6 2.5.1 2.5 2.4 2.3.1 2.3 2.2.1 2.2 2.1 2.0.2},
30
+ 'pypy3' => %w{2.4 2.3.1},
31
+ }
32
+
33
+ # Only use this to install pypy.
34
+ #
35
+ # @api private
36
+ def self.provides_auto?(node, resource)
37
+ super || (resource.version.start_with?('pypy') && node['kernel']['name'].downcase == 'linux')
38
+ end
39
+
40
+ def python_binary
41
+ ::File.join(pypy_folder, 'bin', 'pypy')
42
+ end
43
+
44
+ private
45
+
46
+ def install_python
47
+ path = ::File.join(Chef::Config[:file_cache_path], "#{pypy_package}.tar.bz2")
48
+ folder = pypy_folder
49
+ url = pypy_package_url
50
+
51
+ package %w{tar bzip2}
52
+
53
+ unpack = execute 'unpack pypy' do
54
+ action :nothing
55
+ command ['tar', 'xjvf', path]
56
+ cwd ::File.dirname(folder)
57
+ end
58
+
59
+ remote_file path do
60
+ source url
61
+ owner 'root'
62
+ group 'root'
63
+ mode '644'
64
+ notifies :run, unpack, :immediately
65
+ end
66
+ end
67
+
68
+ def uninstall_python
69
+ directory pypy_folder do
70
+ action :delete
71
+ recursive true
72
+ end
73
+ end
74
+
75
+ def pypy_package
76
+ @pypy_package ||= begin
77
+ match = options['version'].match(/^(pypy(?:|3))(?:-(.*))?$/)
78
+ package_type = match ? match[1] : 'pypy'
79
+ version_prefix = (match && match[2]).to_s
80
+ version = PYPY_PACKAGES[package_type].find {|v| v.start_with?(version_prefix) }
81
+ "#{package_type}-#{version}-#{node['kernel']['name'].downcase}_#{node['kernel']['machine']}-portable"
82
+ end
83
+ end
84
+
85
+ def pypy_folder
86
+ options['folder'] || ::File.join('', 'opt', pypy_package)
87
+ end
88
+
89
+ def pypy_package_url
90
+ options['url'] || "https://bitbucket.org/squeaky/portable-pypy/downloads/#{pypy_package}.tar.bz2"
91
+ end
92
+
93
+ end
94
+ end
95
+ end
96
+