poise-languages 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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 PoiseLanguages
19
+ class Error < ::Exception
20
+ end
21
+ end
@@ -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 PoiseLanguages
19
+ module Scl
20
+ autoload :Mixin, 'poise_languages/scl/mixin'
21
+ autoload :Resource, 'poise_languages/scl/resource'
22
+ autoload :Provider, 'poise_languages/scl/resource'
23
+ end
24
+ end
@@ -0,0 +1,110 @@
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/scl/resource'
18
+
19
+
20
+ module PoiseLanguages
21
+ module Scl
22
+ module Mixin
23
+ private
24
+
25
+ def install_scl_package
26
+ pkg = scl_package
27
+ poise_languages_scl pkg[:name] do
28
+ parent new_resource
29
+ url pkg[:url]
30
+ end
31
+ end
32
+
33
+ def uninstall_scl_package
34
+ install_scl_package.tap do |r|
35
+ r.action(:uninstall)
36
+ end
37
+ end
38
+
39
+ def scl_package
40
+ @scl_package ||= self.class.find_scl_package(node, options['version']).tap do |p|
41
+ raise PoiseLanguages::Error.new("No SCL repoistory package for #{node['platform']} #{node['platform_version']}") unless p
42
+ end
43
+ end
44
+
45
+ def scl_folder
46
+ ::File.join('', 'opt', 'rh', scl_package[:name])
47
+ end
48
+
49
+ def scl_environment
50
+ parse_enable_file(::File.join(scl_folder, 'enable'))
51
+ end
52
+
53
+ # Parse an SCL enable file to extract the environment variables set in it.
54
+ #
55
+ # @param path [String] Path to the enable file.
56
+ # @return [Hash<String, String>]
57
+ def parse_enable_file(path)
58
+ # Doesn't exist yet, so running Python will fail anyway. Just make sure
59
+ # it fails in the expected way.
60
+ return {} unless File.exist?(path)
61
+ # Yes, this is a bash parser in regex. Feel free to be mad at me.
62
+ IO.readlines(path).inject({}) do |memo, line|
63
+ if match = line.match(/^export (\w+)=(.*)$/)
64
+ memo[match[1]] = match[2].gsub(/\$\{(\w+)(:\+:\$\{\w+\})?\}/) do
65
+ if $2
66
+ ENV[$1] ? ":#{ENV[$1]}" : ''
67
+ else
68
+ ENV[$1].to_s
69
+ end
70
+ end
71
+ end
72
+ memo
73
+ end
74
+ end
75
+
76
+ module ClassMethods
77
+ def provides_auto?(node, resource)
78
+ version = inversion_options(node, resource)['version']
79
+ !!find_scl_package(node, version)
80
+ end
81
+
82
+ def find_scl_package(node, version)
83
+ pkg = scl_packages.find {|p| p[:version].start_with?(version) }
84
+ return unless pkg
85
+ pkg[:url] = node.value_for_platform(pkg[:urls])
86
+ return unless pkg[:url]
87
+ pkg
88
+ end
89
+
90
+ private
91
+
92
+ def scl_packages
93
+ @scl_packages ||= []
94
+ end
95
+
96
+ def scl_package(version, name, urls)
97
+ scl_packages << {version: version, name: name, urls: urls}
98
+ end
99
+
100
+ def included(klass)
101
+ super
102
+ klass.extend(ClassMethods)
103
+ end
104
+ end
105
+
106
+ extend ClassMethods
107
+
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,124 @@
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 Scl
24
+ # A `poise_language_scl` resource to manage installing a language from
25
+ # SCL packages. This is an internal implementation detail of
26
+ # poise-languages.
27
+ #
28
+ # @api private
29
+ # @since 1.0
30
+ # @provides poise_languages_scl
31
+ # @action install
32
+ # @action uninstall
33
+ class Resource < Chef::Resource
34
+ include Poise
35
+ provides(:poise_languages_scl)
36
+ actions(:install, :uninstall)
37
+
38
+ # @!attribute package_name
39
+ # Name of the SCL package for the language.
40
+ # @return [String]
41
+ attribute(:package_name, kind_of: String, name_attribute: true)
42
+ # @!attribute url
43
+ # URL to the SCL repository package for the language.
44
+ # @return [String]
45
+ attribute(:url, kind_of: String, required: true)
46
+ # @!attribute parent
47
+ # Resource for the language runtime. Used only for messages.
48
+ # @return [Chef::Resource]
49
+ attribute(:parent, kind_of: Chef::Resource, required: true)
50
+ end
51
+
52
+ # The default provider for `poise_languages_scl`.
53
+ #
54
+ # @api private
55
+ # @since 1.0
56
+ # @see Resource
57
+ # @provides poise_languages_scl
58
+ class Provider < Chef::Provider
59
+ include Poise
60
+ provides(:poise_languages_scl)
61
+
62
+ # The `install` action for the `poise_languages_scl` resource.
63
+ #
64
+ # @return [void]
65
+ def action_install
66
+ notifying_block do
67
+ install_scl_utils
68
+ install_scl_repo_package
69
+ install_scl_package
70
+ end
71
+ end
72
+
73
+ # The `uninstall` action for the `poise_languages_scl` resource.
74
+ #
75
+ # @return [void]
76
+ def action_uninstall
77
+ notifying_block do
78
+ uninstall_scl_utils
79
+ uninstall_scl_repo_package
80
+ uninstall_scl_package
81
+ end
82
+ end
83
+
84
+ private
85
+
86
+ def install_scl_utils
87
+ package 'scl-utils' do
88
+ action :upgrade # This shouldn't be a problem. Famous last words.
89
+ end
90
+ end
91
+
92
+ def install_scl_repo_package
93
+ rpm_package 'rhscl-' + new_resource.package_name do
94
+ source new_resource.url
95
+ end
96
+ end
97
+
98
+ def install_scl_package
99
+ yum_package new_resource.package_name do
100
+ flush_cache before: true
101
+ end
102
+ end
103
+
104
+ def uninstall_scl_utils
105
+ install_scl_utils.tap do |r|
106
+ r.action(:remove)
107
+ end
108
+ end
109
+
110
+ def uninstall_scl_repo_package
111
+ install_scl_repo_package.tap do |r|
112
+ r.action(:remove)
113
+ end
114
+ end
115
+
116
+ def uninstall_scl_package
117
+ install_scl_package.tap do |r|
118
+ r.action(:remove)
119
+ end
120
+ end
121
+
122
+ end
123
+ end
124
+ end
@@ -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 PoiseLanguages
19
+ module System
20
+ autoload :Mixin, 'poise_languages/system/mixin'
21
+ autoload :Resource, 'poise_languages/system/resource'
22
+ autoload :Provider, 'poise_languages/system/resource'
23
+ end
24
+ end
@@ -0,0 +1,165 @@
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/system/resource'
18
+
19
+
20
+ module PoiseLanguages
21
+ module System
22
+ module Mixin
23
+
24
+ private
25
+
26
+ # Install a language using system packages.
27
+ #
28
+ # @api public
29
+ # @return [PoiseLanguages::System::Resource]
30
+ def install_system_packages
31
+ dev_package_overrides = system_dev_package_overrides
32
+ poise_languages_system options['package_name'] || system_package_name do
33
+ # Otherwise use the default install action.
34
+ action(:upgrade) if options['package_upgrade']
35
+ parent new_resource
36
+ # Don't pass true because we want the default computed behavior for that.
37
+ dev_package options['dev_package'] unless options['dev_package'] == true
38
+ dev_package_overrides dev_package_overrides
39
+ package_version options['package_version'] if options['package_version']
40
+ version options['version']
41
+ end
42
+ end
43
+
44
+ # Uninstall a language using system packages.
45
+ #
46
+ # @api public
47
+ # @return [PoiseLanguages::System::Resource]
48
+ def uninstall_system_packages
49
+ install_system_packages.tap do |r|
50
+ r.action(:uninstall)
51
+ end
52
+ end
53
+
54
+ # Compute all possible package names for a given language version. Must be
55
+ # implemented by mixin users. Versions are expressed as prefixes so ''
56
+ # matches all versions, '2' matches 2.x.
57
+ #
58
+ # @abstract
59
+ # @api public
60
+ # @param version [String] Language version prefix.
61
+ # @return [Array<String>]
62
+ def system_package_candidates(version)
63
+ raise NotImplementedError
64
+ end
65
+
66
+ # Compute the default package name for the base package for this language.
67
+ #
68
+ # @api public
69
+ # @return [String]
70
+ def system_package_name
71
+ # Look up all packages for this language on this platform.
72
+ system_packages = node.value_for_platform(self.class.packages)
73
+ if !system_packages && self.class.default_package
74
+ Chef::Log.debug("[#{new_resource}] No known packages for #{node['platform']} #{node['platform_version']}, defaulting to '#{self.class.default_package}'.")
75
+ system_packages = Array(self.class.default_package)
76
+ end
77
+
78
+ # Find the first value on system_package_candidates that is in system_packages.
79
+ system_package_candidates(options['version'].to_s).each do |name|
80
+ return name if system_packages.include?(name)
81
+ end
82
+ # No valid candidate. Sad trombone.
83
+ raise PoiseLanguages::Error.new("Unable to find a candidate package for version #{options['version'].to_s.inspect}. Please set package_name provider option for #{new_resource}.")
84
+ end
85
+
86
+ # A hash mapping package names to their override dev package name.
87
+ #
88
+ # @api public
89
+ # @return [Hash<String, String>]
90
+ def system_dev_package_overrides
91
+ {}
92
+ end
93
+
94
+ module ClassMethods
95
+ # Install this as a default provider for platforms we are relatively
96
+ # certain work.
97
+ #
98
+ # @api private
99
+ def provides_auto?(node, resource)
100
+ super || node.platform_family?('debian', 'rhel', 'amazon', 'fedora')
101
+ end
102
+
103
+ # Set some default inversion provider options. Package name can't get
104
+ # a default value here because that would complicate the handling of
105
+ # {system_package_candidates}.
106
+ #
107
+ # @api private
108
+ def default_inversion_options(node, resource)
109
+ super.merge({
110
+ # Install dev headers?
111
+ dev_package: true,
112
+ # Manual overrides for package name and/or version.
113
+ package_name: nil,
114
+ package_version: nil,
115
+ # Set to true to use action :upgrade on system packages.
116
+ package_upgrade: false,
117
+ })
118
+ end
119
+
120
+ # @overload packages()
121
+ # Return a hash formatted for value_for_platform returning an Array
122
+ # of package names.
123
+ # @return [Hash]
124
+ # @overload packages(default_package, packages)
125
+ # Define what system packages are available for this language on each
126
+ # platform.
127
+ # @param default_package [String] Default package name for platforms
128
+ # not otherwise defined.
129
+ # @param [Hash] Hash formatted for value_for_platform returning an
130
+ # Array of package names.
131
+ # @return [Hash]
132
+ def packages(default_package=nil, packages=nil)
133
+ self.default_package(default_package) if default_package
134
+ if packages
135
+ @packages = packages
136
+ end
137
+ @packages
138
+ end
139
+
140
+ # @overload default_package()
141
+ # Return the default package name for platforms not otherwise defined.
142
+ # @return [String]
143
+ # @overload default_package(name)
144
+ # Set the default package name for platforms not defined in {packages}.
145
+ # @param name [String] Package name.
146
+ # @return [String]
147
+ def default_package(name=nil)
148
+ if name
149
+ @default_package = name
150
+ end
151
+ @default_package
152
+ end
153
+
154
+ # @api private
155
+ def included(klass)
156
+ super
157
+ klass.extend(ClassMethods)
158
+ end
159
+ end
160
+
161
+ extend ClassMethods
162
+
163
+ end
164
+ end
165
+ end