poise-python 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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
+