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.
- checksums.yaml +7 -0
- data/.gitignore +11 -0
- data/.kitchen.travis.yml +9 -0
- data/.kitchen.yml +8 -0
- data/.travis.yml +21 -0
- data/.yardopts +7 -0
- data/Berksfile +28 -0
- data/Gemfile +33 -0
- data/LICENSE +201 -0
- data/README.md +399 -0
- data/Rakefile +17 -0
- data/chef/attributes/default.rb +24 -0
- data/chef/recipes/default.rb +20 -0
- data/lib/poise_python.rb +25 -0
- data/lib/poise_python/cheftie.rb +18 -0
- data/lib/poise_python/error.rb +23 -0
- data/lib/poise_python/python_command_mixin.rb +45 -0
- data/lib/poise_python/python_providers.rb +35 -0
- data/lib/poise_python/python_providers/base.rb +177 -0
- data/lib/poise_python/python_providers/portable_pypy.rb +96 -0
- data/lib/poise_python/python_providers/scl.rb +77 -0
- data/lib/poise_python/python_providers/system.rb +86 -0
- data/lib/poise_python/resources.rb +31 -0
- data/lib/poise_python/resources/pip_requirements.rb +102 -0
- data/lib/poise_python/resources/python_execute.rb +83 -0
- data/lib/poise_python/resources/python_package.rb +322 -0
- data/lib/poise_python/resources/python_runtime.rb +114 -0
- data/lib/poise_python/resources/python_runtime_pip.rb +167 -0
- data/lib/poise_python/resources/python_runtime_test.rb +185 -0
- data/lib/poise_python/resources/python_virtualenv.rb +164 -0
- data/lib/poise_python/utils.rb +63 -0
- data/lib/poise_python/utils/python_encoder.rb +73 -0
- data/lib/poise_python/version.rb +20 -0
- data/poise-python.gemspec +41 -0
- data/test/cookbooks/poise-python_test/metadata.rb +18 -0
- data/test/cookbooks/poise-python_test/recipes/default.rb +40 -0
- data/test/gemfiles/chef-12.gemfile +19 -0
- data/test/gemfiles/master.gemfile +23 -0
- data/test/integration/default/serverspec/default_spec.rb +102 -0
- data/test/spec/python_command_mixin_spec.rb +115 -0
- data/test/spec/python_providers/portable_pypy_spec.rb +68 -0
- data/test/spec/python_providers/scl_spec.rb +75 -0
- data/test/spec/python_providers/system_spec.rb +81 -0
- data/test/spec/resources/pip_requirements_spec.rb +69 -0
- data/test/spec/resources/python_package_spec.rb +65 -0
- data/test/spec/resources/python_runtime_pip_spec.rb +33 -0
- data/test/spec/resources/python_virtualenv_spec.rb +103 -0
- data/test/spec/spec_helper.rb +19 -0
- data/test/spec/utils/python_encoder_spec.rb +79 -0
- data/test/spec/utils_spec.rb +86 -0
- metadata +170 -0
@@ -0,0 +1,164 @@
|
|
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'
|
18
|
+
|
19
|
+
# Break a require loop by letting autoload work its magic.
|
20
|
+
require 'poise_python'
|
21
|
+
|
22
|
+
|
23
|
+
module PoisePython
|
24
|
+
module Resources
|
25
|
+
# (see PythonVirtualenv::Resource)
|
26
|
+
# @since 1.0.0
|
27
|
+
module PythonVirtualenv
|
28
|
+
# A `python_virtualenv` resource to manage Python virtual environments.
|
29
|
+
#
|
30
|
+
# @provides python_virtualenv
|
31
|
+
# @action create
|
32
|
+
# @action delete
|
33
|
+
# @example
|
34
|
+
# python_virtualenv '/opt/myapp'
|
35
|
+
class Resource < PoisePython::Resources::PythonRuntime::Resource
|
36
|
+
include PoisePython::PythonCommandMixin
|
37
|
+
provides(:python_virtualenv)
|
38
|
+
# Add create and delete actions as more semantically relevant aliases.
|
39
|
+
default_action(:create)
|
40
|
+
actions(:create, :delete)
|
41
|
+
|
42
|
+
# @!attribute path
|
43
|
+
# Path to create the environment at.
|
44
|
+
# @return [String]
|
45
|
+
attribute(:path, kind_of: String, name_attribute: true)
|
46
|
+
# @!attribute group
|
47
|
+
# System group to create the virtualenv.
|
48
|
+
# @return [String, Integer, nil]
|
49
|
+
attribute(:group, kind_of: [String, Integer, NilClass])
|
50
|
+
# @!attribute system_site_packages
|
51
|
+
# Enable or disable visibilty of system packages in the environment.
|
52
|
+
# @return [Boolean]
|
53
|
+
attribute(:system_site_packages, equal_to: [true, false], default: false)
|
54
|
+
# @!attribute user
|
55
|
+
# System user to create the virtualenv.
|
56
|
+
# @return [String, Integer, nil]
|
57
|
+
attribute(:user, kind_of: [String, Integer, NilClass])
|
58
|
+
|
59
|
+
# Lock the default provider.
|
60
|
+
#
|
61
|
+
# @api private
|
62
|
+
def initialize(*args)
|
63
|
+
super
|
64
|
+
# Sidestep all the normal provider lookup stuffs. This is kind of
|
65
|
+
# gross but it will do for now. The hard part is that the base classes
|
66
|
+
# for the resource and provider are using Poise::Inversion, which we
|
67
|
+
# don't want to use for python_virtualenv.
|
68
|
+
@provider = Provider
|
69
|
+
end
|
70
|
+
|
71
|
+
# Upstream attribute we don't support. Sets are an error and gets always
|
72
|
+
# return nil.
|
73
|
+
#
|
74
|
+
# @api private
|
75
|
+
# @param arg [Object] Ignored
|
76
|
+
# @return [nil]
|
77
|
+
def version(arg=nil)
|
78
|
+
raise NoMethodError if arg
|
79
|
+
end
|
80
|
+
|
81
|
+
# (see #version)
|
82
|
+
def virtualenv_version(arg=nil)
|
83
|
+
raise NoMethodError if arg
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
# The default provider for `python_virtualenv`.
|
88
|
+
#
|
89
|
+
# @see Resource
|
90
|
+
# @provides python_virtualenv
|
91
|
+
class Provider < PoisePython::PythonProviders::Base
|
92
|
+
include PoisePython::PythonCommandMixin
|
93
|
+
provides(:python_virtualenv)
|
94
|
+
|
95
|
+
# Alias our actions. Slightly annoying that they will show in
|
96
|
+
# tracebacks with the original names, but oh well.
|
97
|
+
alias_method :action_create, :action_install
|
98
|
+
alias_method :action_delete, :action_uninstall
|
99
|
+
|
100
|
+
def python_binary
|
101
|
+
::File.join(new_resource.path, 'bin', 'python')
|
102
|
+
end
|
103
|
+
|
104
|
+
def python_environment
|
105
|
+
if new_resource.parent_python
|
106
|
+
new_resource.parent_python.python_environment
|
107
|
+
else
|
108
|
+
{}
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
private
|
113
|
+
|
114
|
+
def install_python
|
115
|
+
return if ::File.exist?(new_resource.path)
|
116
|
+
|
117
|
+
cmd = python_shell_out(%w{-m venv -h})
|
118
|
+
if cmd.error?
|
119
|
+
converge_by("Creating virtualenv at #{new_resource.path}") do
|
120
|
+
create_virtualenv(%w{virtualenv})
|
121
|
+
end
|
122
|
+
else
|
123
|
+
converge_by("Creating venv at #{new_resource.path}") do
|
124
|
+
create_virtualenv(%w{venv --without-pip})
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def uninstall_python
|
130
|
+
directory new_resource.path do
|
131
|
+
action :delete
|
132
|
+
recursive true
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
# Don't install virtualenv inside virtualenv.
|
137
|
+
#
|
138
|
+
# @api private
|
139
|
+
# @return [void]
|
140
|
+
def install_virtualenv
|
141
|
+
# This space left intentionally blank.
|
142
|
+
end
|
143
|
+
|
144
|
+
# Create a virtualenv using virtualenv or venv.
|
145
|
+
#
|
146
|
+
# @param driver [Array<String>] Command snippet to actually make it.
|
147
|
+
# @return [void]
|
148
|
+
def create_virtualenv(driver)
|
149
|
+
cmd = %w{-m} + driver
|
150
|
+
cmd << '--system-site-packages' if new_resource.system_site_packages
|
151
|
+
cmd << new_resource.path
|
152
|
+
python_shell_out!(cmd, environment: {
|
153
|
+
# Use the environment variables to cope with older virtualenv not
|
154
|
+
# supporting --no-wheel. The env var will be ignored if unsupported.
|
155
|
+
'VIRTUALENV_NO_PIP' => '1',
|
156
|
+
'VIRTUALENV_NO_SETUPTOOLS' => '1',
|
157
|
+
'VIRTUALENV_NO_WHEEL' => '1',
|
158
|
+
}, group: new_resource.group, user: new_resource.user)
|
159
|
+
end
|
160
|
+
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
@@ -0,0 +1,63 @@
|
|
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/error'
|
18
|
+
|
19
|
+
|
20
|
+
module PoisePython
|
21
|
+
# Helper methods for Python-related things.
|
22
|
+
#
|
23
|
+
# @since 1.0.0
|
24
|
+
module Utils
|
25
|
+
autoload :PythonEncoder, 'poise_python/utils/python_encoder'
|
26
|
+
extend self
|
27
|
+
|
28
|
+
# Convert an object to a Python literal.
|
29
|
+
#
|
30
|
+
# @param obj [Object] Ovject to convert.
|
31
|
+
# @return [String]
|
32
|
+
def to_python(obj)
|
33
|
+
PythonEncoder.new(obj).encode
|
34
|
+
end
|
35
|
+
|
36
|
+
# Convert path to a Python dotted module name.
|
37
|
+
#
|
38
|
+
# @param path [String] Path to the file. If base is not given, this must be
|
39
|
+
# a relative path.
|
40
|
+
# @param base [String] Optional base path to treat the file as relative to.
|
41
|
+
# @return [String]
|
42
|
+
def path_to_module(path, base=nil)
|
43
|
+
if base
|
44
|
+
path = ::File.expand_path(path, base)
|
45
|
+
raise PoisePython::Error.new("Path #{path} is not inside base path #{base}") unless path.start_with?(base)
|
46
|
+
path = path[base.length+1..-1]
|
47
|
+
end
|
48
|
+
path = path[0..-4] if path.end_with?('.py')
|
49
|
+
path.gsub(/#{::File::SEPARATOR}/, '.')
|
50
|
+
end
|
51
|
+
|
52
|
+
# Convert a Python dotted module name to a path.
|
53
|
+
#
|
54
|
+
# @param mod [String] Dotted module name.
|
55
|
+
# @param base [String] Optional base path to treat the file as relative to.
|
56
|
+
# @return [String]
|
57
|
+
def module_to_path(mod, base=nil)
|
58
|
+
path = mod.gsub(/\./, ::File::SEPARATOR) + '.py'
|
59
|
+
path = ::File.join(base, path) if base
|
60
|
+
path
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,73 @@
|
|
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 'json'
|
18
|
+
|
19
|
+
|
20
|
+
module PoisePython
|
21
|
+
module Utils
|
22
|
+
# Convert Ruby data structures to a Python literal. Overall similar to JSON
|
23
|
+
# but just different enough that I need to write this. Thanks Obama.
|
24
|
+
#
|
25
|
+
# @since 1.0.0
|
26
|
+
# @api private
|
27
|
+
class PythonEncoder
|
28
|
+
def initialize(root, depth_limit: 100)
|
29
|
+
@root = root
|
30
|
+
@depth_limit = depth_limit
|
31
|
+
end
|
32
|
+
|
33
|
+
def encode
|
34
|
+
encode_obj(@root, 0)
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def encode_obj(obj, depth)
|
40
|
+
raise ArgumentError.new("Depth limit exceeded") if depth > @depth_limit
|
41
|
+
case obj
|
42
|
+
when Hash
|
43
|
+
encode_hash(obj, depth)
|
44
|
+
when Array
|
45
|
+
encode_array(obj, depth)
|
46
|
+
when true
|
47
|
+
'True'
|
48
|
+
when false
|
49
|
+
'False'
|
50
|
+
when nil
|
51
|
+
'None'
|
52
|
+
else
|
53
|
+
obj.to_json
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def encode_hash(obj, depth)
|
58
|
+
middle = obj.map do |key, value|
|
59
|
+
"#{encode_obj(key, depth+1)}:#{encode_obj(value, depth+1)}"
|
60
|
+
end
|
61
|
+
"{#{middle.join(',')}}"
|
62
|
+
end
|
63
|
+
|
64
|
+
def encode_array(obj, depth)
|
65
|
+
middle = obj.map do |value|
|
66
|
+
encode_obj(value, depth+1)
|
67
|
+
end
|
68
|
+
"[#{middle.join(',')}]"
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
end
|
73
|
+
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 PoisePython
|
19
|
+
VERSION = '1.0.0'
|
20
|
+
end
|
@@ -0,0 +1,41 @@
|
|
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_python/version'
|
20
|
+
|
21
|
+
Gem::Specification.new do |spec|
|
22
|
+
spec.name = 'poise-python'
|
23
|
+
spec.version = PoisePython::VERSION
|
24
|
+
spec.authors = ['Noah Kantrowitz']
|
25
|
+
spec.email = %w{noah@coderanger.net}
|
26
|
+
spec.description = "A Chef cookbook for managing Python installations."
|
27
|
+
spec.summary = spec.description
|
28
|
+
spec.homepage = 'https://github.com/poise/python'
|
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.0'
|
38
|
+
spec.add_dependency 'poise-languages', '~> 1.0.dev'
|
39
|
+
|
40
|
+
spec.add_development_dependency 'poise-boiler', '~> 1.0'
|
41
|
+
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
|
+
name 'poise-python_test'
|
18
|
+
depends 'poise-python'
|
@@ -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
|
+
require 'poise_python/resources/python_runtime_test'
|
18
|
+
|
19
|
+
# Install lsb-release because Debian 6 doesn't by default and serverspec requires it
|
20
|
+
package 'lsb-release' if platform?('debian') && node['platform_version'].start_with?('6')
|
21
|
+
|
22
|
+
python_runtime_test '2'
|
23
|
+
|
24
|
+
python_runtime_test '3'
|
25
|
+
|
26
|
+
python_runtime_test 'pypy'
|
27
|
+
|
28
|
+
python_runtime_test 'system' do
|
29
|
+
version ''
|
30
|
+
runtime_provider :system
|
31
|
+
end
|
32
|
+
|
33
|
+
if platform_family?('rhel')
|
34
|
+
python_runtime_test 'scl' do
|
35
|
+
version ''
|
36
|
+
runtime_provider :scl
|
37
|
+
end
|
38
|
+
else
|
39
|
+
file '/no_scl'
|
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'
|