chef-utils 0.0.1 → 15.5.9

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,118 @@
1
+ #
2
+ # Copyright:: Copyright 2018-2019, Chef Software Inc.
3
+ # License:: Apache License, Version 2.0
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ #
17
+
18
+ require_relative "../internal"
19
+
20
+ module ChefUtils
21
+ module DSL
22
+ module Which
23
+ include Internal
24
+
25
+ # Lookup an executable through the systems search PATH. Allows specifying an array
26
+ # of executables to look for. The first executable that is found, along any path entry,
27
+ # will be the preferred one and returned first. The extra_path will override any default
28
+ # extra_paths which are added (allwing the user to pass an empty array to remove them).
29
+ #
30
+ # When passed a block the block will be called with the full pathname of any executables
31
+ # which are found, and the block should return truthy or falsey values to further filter
32
+ # the executable based on arbitrary criteria.
33
+ #
34
+ # This is syntactic sugar for `where(...).first`
35
+ #
36
+ # This helper can be used in target mode in chef or with train using the appropriate
37
+ # wiring extenerally.
38
+ #
39
+ # @example Find the most appropriate python executable, searching through the system PATH
40
+ # plus additionally the "/usr/libexec" directory, which has the dnf libraries
41
+ # installed and available.
42
+ #
43
+ # cmd = which("platform-python", "python", "python3", "python2", "python2.7", extra_path: "/usr/libexec") do |f|
44
+ # shell_out("#{f} -c 'import dnf'").exitstatus == 0
45
+ # end
46
+ #
47
+ # @param [Array<String>] list of commands to search for
48
+ # @param [String,Array<String>] array of extra paths to search through
49
+ # @return [String] the first match
50
+ #
51
+ def which(*cmds, extra_path: nil, &block)
52
+ where(*cmds, extra_path: extra_path, &block).first || false
53
+ end
54
+
55
+ # Lookup all the instances of an an executable that can be found through the systems search PATH.
56
+ # Allows specifying an array of executables to look for. All the instances of the first executable
57
+ # that is found will be returned first. The extra_path will override any default extra_paths
58
+ # which are added (allwing the user to pass an empty array to remove them).
59
+ #
60
+ # When passed a block the block will be called with the full pathname of any executables
61
+ # which are found, and the block should return truthy or falsey values to further filter
62
+ # the executable based on arbitrary criteria.
63
+ #
64
+ # This helper can be used in target mode in chef or with train using the appropriate
65
+ # wiring extenerally.
66
+ #
67
+ # @example Find all the python executables, searching through the system PATH plus additionally
68
+ # the "/usr/libexec" directory, which have the dnf libraries installed and available.
69
+ #
70
+ # cmds = where("platform-python", "python", "python3", "python2", "python2.7", extra_path: "/usr/libexec") do |f|
71
+ # shell_out("#{f} -c 'import dnf'").exitstatus == 0
72
+ # end
73
+ #
74
+ # @param [Array<String>] list of commands to search for
75
+ # @param [String,Array<String>] array of extra paths to search through
76
+ # @return [String] the first match
77
+ #
78
+ def where(*cmds, extra_path: nil, &block)
79
+ extra_path ||= __extra_path
80
+ paths = __env_path.split(File::PATH_SEPARATOR) + Array(extra_path)
81
+ paths.uniq!
82
+ cmds.map do |cmd|
83
+ paths.map do |path|
84
+ filename = File.join(path, cmd)
85
+ filename if __valid_executable?(filename, &block)
86
+ end.compact
87
+ end.flatten
88
+ end
89
+
90
+ private
91
+
92
+ # This is for injecting common extra_paths into the search PATH. The chef-client codebase overrides this into its
93
+ # own custom mixin to ensure that /usr/sbin, /sbin, etc are in the search PATH for chef-client.
94
+ #
95
+ # @api private
96
+ def __extra_path
97
+ nil
98
+ end
99
+
100
+ # Windows compatible and train/target-mode-enhanced helper to determine if an executable is valid.
101
+ #
102
+ # @api private
103
+ def __valid_executable?(filename, &block)
104
+ is_executable =
105
+ if __transport_connection
106
+ __transport_connection.file(filename).stat[:mode] & 1 && !__transport_connection.file(filename).directory?
107
+ else
108
+ File.executable?(filename) && !File.directory?(filename)
109
+ end
110
+ return false unless is_executable
111
+
112
+ block ? yield(filename) : true
113
+ end
114
+
115
+ extend self
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,77 @@
1
+ #
2
+ # Copyright:: Copyright 2018-2019, Chef Software Inc.
3
+ # License:: Apache License, Version 2.0
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ #
17
+
18
+ module ChefUtils
19
+ #
20
+ # This is glue code to make the helpers work when called as ChefUtils.helper? from inside of chef-client.
21
+ #
22
+ # This also is glue code to make the helpers work when mixed into classes that have node/run_context methods that
23
+ # provide those objects.
24
+ #
25
+ # It should not be assumed that any of this code runs from within chef-client and that the
26
+ # Chef class or run_context, etc exists.
27
+ #
28
+ # This gem may be used by gems like mixlib-shellout which can be consumed by external non-Chef utilities,
29
+ # so including brittle code here which depends on the existence of the chef-client will cause broken
30
+ # behavior downstream. You must practice defensive coding, and not make assumptions about runnign within chef-client.
31
+ #
32
+ # Other consumers may mix in the helper classes and then override the methods here and provide their own custom
33
+ # wiring and override what is provided here. They are marked as private because no downstream user should ever touch
34
+ # them -- they are intended to be subclassable and overridable by Chef developers in other projects. Chef Software
35
+ # reserves the right to change the implementation details of this class in minor revs which is what "api private" means,
36
+ # so external persons should subclass and override only when necessary (submit PRs and issues upstream if this is a problem).
37
+ #
38
+ module Internal
39
+ extend self
40
+
41
+ private
42
+
43
+ # FIXME: include a `__config` method so we can wire up Chef::Config automatically or allow other consumers to
44
+ # inject a config hash without having to take a direct dep on the chef-config gem
45
+
46
+ # @api private
47
+ def __getnode(skip_global = false)
48
+ return node if respond_to?(:node) && node
49
+
50
+ return run_context&.node if respond_to?(:run_context) && run_context&.node
51
+
52
+ unless skip_global
53
+ return Chef.run_context&.node if defined?(Chef) && Chef.respond_to?(:run_context) && Chef.run_context&.node
54
+ end
55
+
56
+ nil
57
+ end
58
+
59
+ # @api private
60
+ def __env_path
61
+ if __transport_connection
62
+ __transport_connection.run_command("echo $PATH").stdout || ""
63
+ else
64
+ ENV["PATH"] || ""
65
+ end
66
+ end
67
+
68
+ # @api private
69
+ def __transport_connection
70
+ return Chef.run_context.transport_connection if defined?(Chef) && Chef.respond_to?(:run_context) && Chef&.run_context&.transport_connection
71
+
72
+ nil
73
+ end
74
+
75
+ extend self
76
+ end
77
+ end
@@ -0,0 +1,239 @@
1
+ # Copyright 2009-2016, Dan Kubb
2
+
3
+ # Permission is hereby granted, free of charge, to any person obtaining
4
+ # a copy of this software and associated documentation files (the
5
+ # "Software"), to deal in the Software without restriction, including
6
+ # without limitation the rights to use, copy, modify, merge, publish,
7
+ # distribute, sublicense, and/or sell copies of the Software, and to
8
+ # permit persons to whom the Software is furnished to do so, subject to
9
+ # the following conditions:
10
+
11
+ # The above copyright notice and this permission notice shall be
12
+ # included in all copies or substantial portions of the Software.
13
+
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ # ---
23
+ # ---
24
+
25
+ # Some portions of blank.rb and mash.rb are verbatim copies of software
26
+ # licensed under the MIT license. That license is included below:
27
+
28
+ # Copyright 2005-2016, David Heinemeier Hansson
29
+
30
+ # Permission is hereby granted, free of charge, to any person obtaining
31
+ # a copy of this software and associated documentation files (the
32
+ # "Software"), to deal in the Software without restriction, including
33
+ # without limitation the rights to use, copy, modify, merge, publish,
34
+ # distribute, sublicense, and/or sell copies of the Software, and to
35
+ # permit persons to whom the Software is furnished to do so, subject to
36
+ # the following conditions:
37
+
38
+ # The above copyright notice and this permission notice shall be
39
+ # included in all copies or substantial portions of the Software.
40
+
41
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
42
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
43
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
44
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
45
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
46
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
47
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
48
+
49
+ # This class has dubious semantics and we only have it so that people can write
50
+ # params[:key] instead of params['key'].
51
+ module ChefUtils
52
+ class Mash < Hash
53
+
54
+ # @param constructor<Object>
55
+ # The default value for the mash. Defaults to an empty hash.
56
+ #
57
+ # @details [Alternatives]
58
+ # If constructor is a Hash, a new mash will be created based on the keys of
59
+ # the hash and no default value will be set.
60
+ def initialize(constructor = {})
61
+ if constructor.is_a?(Hash)
62
+ super()
63
+ update(constructor)
64
+ else
65
+ super(constructor)
66
+ end
67
+ end
68
+
69
+ # @param orig<Object> Mash being copied
70
+ #
71
+ # @return [Object] A new copied Mash
72
+ def initialize_copy(orig)
73
+ super
74
+ # Handle nested values
75
+ each do |k, v|
76
+ if v.is_a?(Mash) || v.is_a?(Array)
77
+ self[k] = v.dup
78
+ end
79
+ end
80
+ self
81
+ end
82
+
83
+ # @param key<Object> The default value for the mash. Defaults to nil.
84
+ #
85
+ # @details [Alternatives]
86
+ # If key is a Symbol and it is a key in the mash, then the default value will
87
+ # be set to the value matching the key.
88
+ def default(key = nil)
89
+ if key.is_a?(Symbol) && include?(key = key.to_s)
90
+ self[key]
91
+ else
92
+ super
93
+ end
94
+ end
95
+
96
+ unless method_defined?(:regular_writer)
97
+ alias_method :regular_writer, :[]=
98
+ end
99
+
100
+ unless method_defined?(:regular_update)
101
+ alias_method :regular_update, :update
102
+ end
103
+
104
+ # @param key<Object> The key to set.
105
+ # @param value<Object>
106
+ # The value to set the key to.
107
+ #
108
+ # @see Mash#convert_key
109
+ # @see Mash#convert_value
110
+ def []=(key, value)
111
+ regular_writer(convert_key(key), convert_value(value))
112
+ end
113
+
114
+ # internal API for use by Chef's deep merge cache
115
+ # @api private
116
+ def internal_set(key, value)
117
+ regular_writer(key, convert_value(value))
118
+ end
119
+
120
+ # @param other_hash<Hash>
121
+ # A hash to update values in the mash with. The keys and the values will be
122
+ # converted to Mash format.
123
+ #
124
+ # @return [Mash] The updated mash.
125
+ def update(other_hash)
126
+ other_hash.each_pair { |key, value| regular_writer(convert_key(key), convert_value(value)) }
127
+ self
128
+ end
129
+
130
+ alias_method :merge!, :update
131
+
132
+ # @param key<Object> The key to check for. This will be run through convert_key.
133
+ #
134
+ # @return [Boolean] True if the key exists in the mash.
135
+ def key?(key)
136
+ super(convert_key(key))
137
+ end
138
+
139
+ # def include? def has_key? def member?
140
+ alias_method :include?, :key?
141
+ alias_method :has_key?, :key?
142
+ alias_method :member?, :key?
143
+
144
+ # @param key<Object> The key to fetch. This will be run through convert_key.
145
+ # @param *extras<Array> Default value.
146
+ #
147
+ # @return [Object] The value at key or the default value.
148
+ def fetch(key, *extras)
149
+ super(convert_key(key), *extras)
150
+ end
151
+
152
+ # @param *indices<Array>
153
+ # The keys to retrieve values for. These will be run through +convert_key+.
154
+ #
155
+ # @return [Array] The values at each of the provided keys
156
+ def values_at(*indices)
157
+ indices.collect { |key| self[convert_key(key)] }
158
+ end
159
+
160
+ # @param hash<Hash> The hash to merge with the mash.
161
+ #
162
+ # @return [Mash] A new mash with the hash values merged in.
163
+ def merge(hash)
164
+ dup.update(hash)
165
+ end
166
+
167
+ # @param key<Object>
168
+ # The key to delete from the mash.\
169
+ def delete(key)
170
+ super(convert_key(key))
171
+ end
172
+
173
+ # @param *rejected<Array[(String, Symbol)] The mash keys to exclude.
174
+ #
175
+ # @return [Mash] A new mash without the selected keys.
176
+ #
177
+ # @example
178
+ # { :one => 1, :two => 2, :three => 3 }.except(:one)
179
+ # #=> { "two" => 2, "three" => 3 }
180
+ def except(*keys)
181
+ super(*keys.map { |k| convert_key(k) })
182
+ end
183
+
184
+ # Used to provide the same interface as Hash.
185
+ #
186
+ # @return [Mash] This mash unchanged.
187
+ def stringify_keys!; self end
188
+
189
+ # @return [Hash] The mash as a Hash with symbolized keys.
190
+ def symbolize_keys
191
+ h = Hash.new(default)
192
+ each { |key, val| h[key.to_sym] = val }
193
+ h
194
+ end
195
+
196
+ # @return [Hash] The mash as a Hash with string keys.
197
+ def to_hash
198
+ Hash.new(default).merge(self)
199
+ end
200
+
201
+ # @return [Mash] Convert a Hash into a Mash
202
+ # The input Hash's default value is maintained
203
+ def self.from_hash(hash)
204
+ mash = Mash.new(hash)
205
+ mash.default = hash.default
206
+ mash
207
+ end
208
+
209
+ protected
210
+
211
+ # @param key<Object> The key to convert.
212
+ #
213
+ # @param [Object]
214
+ # The converted key. If the key was a symbol, it will be converted to a
215
+ # string.
216
+ #
217
+ # @api private
218
+ def convert_key(key)
219
+ key.is_a?(Symbol) ? key.to_s : key
220
+ end
221
+
222
+ # @param value<Object> The value to convert.
223
+ #
224
+ # @return [Object]
225
+ # The converted value. A Hash or an Array of hashes, will be converted to
226
+ # their Mash equivalents.
227
+ #
228
+ # @api private
229
+ def convert_value(value)
230
+ if value.class == Hash
231
+ Mash.from_hash(value)
232
+ elsif value.is_a?(Array)
233
+ value.collect { |e| convert_value(e) }
234
+ else
235
+ value
236
+ end
237
+ end
238
+ end
239
+ end
@@ -15,5 +15,5 @@
15
15
 
16
16
  module ChefUtils
17
17
  CHEFUTILS_ROOT = File.expand_path("../..", __FILE__)
18
- VERSION = "0.0.1".freeze
18
+ VERSION = "15.5.9".freeze
19
19
  end
@@ -0,0 +1,93 @@
1
+ require "chef-utils"
2
+
3
+ # FIXME: dynamically generate this for accuracy
4
+ HELPER_MODULES = [
5
+ ChefUtils::DSL::Architecture,
6
+ ChefUtils::DSL::Introspection,
7
+ ChefUtils::DSL::OS,
8
+ ChefUtils::DSL::PathSanity,
9
+ ChefUtils::DSL::Platform,
10
+ ChefUtils::DSL::PlatformFamily,
11
+ ChefUtils::DSL::Service,
12
+ ChefUtils::DSL::Which,
13
+ ].freeze
14
+
15
+ ARCH_HELPERS = (ChefUtils::DSL::Architecture.methods - Module.methods).freeze
16
+ OS_HELPERS = (ChefUtils::DSL::OS.methods - Module.methods).freeze
17
+ PLATFORM_HELPERS = (ChefUtils::DSL::Platform.methods - Module.methods).freeze
18
+ PLATFORM_FAMILY_HELPERS = (ChefUtils::DSL::PlatformFamily.methods - Module.methods).freeze
19
+ INTROSPECTION_HELPERS = (ChefUtils::DSL::Introspection.methods - Module.methods).freeze
20
+
21
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
22
+ RSpec.configure do |config|
23
+ # rspec-expectations config goes here. You can use an alternate
24
+ # assertion/expectation library such as wrong or the stdlib/minitest
25
+ # assertions if you prefer.
26
+ config.expect_with :rspec do |expectations|
27
+ # This option will default to `true` in RSpec 4. It makes the `description`
28
+ # and `failure_message` of custom matchers include text for helper methods
29
+ # defined using `chain`, e.g.:
30
+ # be_bigger_than(2).and_smaller_than(4).description
31
+ # # => "be bigger than 2 and smaller than 4"
32
+ # ...rather than:
33
+ # # => "be bigger than 2"
34
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
35
+ end
36
+
37
+ # rspec-mocks config goes here. You can use an alternate test double
38
+ # library (such as bogus or mocha) by changing the `mock_with` option here.
39
+ config.mock_with :rspec do |mocks|
40
+ # Prevents you from mocking or stubbing a method that does not exist on
41
+ # a real object. This is generally recommended, and will default to
42
+ # `true` in RSpec 4.
43
+ mocks.verify_partial_doubles = true
44
+ end
45
+
46
+ # These two settings work together to allow you to limit a spec run
47
+ # to individual examples or groups you care about by tagging them with
48
+ # `:focus` metadata. When nothing is tagged with `:focus`, all examples
49
+ # get run.
50
+ config.filter_run :focus
51
+ config.run_all_when_everything_filtered = true
52
+
53
+ config.filter_run_excluding windows_only: true unless ChefUtils.windows?
54
+ config.filter_run_excluding unix_only: true if ChefUtils.windows?
55
+
56
+ # Limits the available syntax to the non-monkey patched syntax that is
57
+ # recommended. For more details, see:
58
+ # - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
59
+ # - http://teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
60
+ # - http://myronmars.to/n/dev-blog/2014/05/notable-changes-in-rspec-3#new__config_option_to_disable_rspeccore_monkey_patching
61
+ config.disable_monkey_patching!
62
+
63
+ # This setting enables warnings. It's recommended, but in some cases may
64
+ # be too noisy due to issues in dependencies.
65
+ config.warnings = true
66
+
67
+ # Many RSpec users commonly either run the entire suite or an individual
68
+ # file, and it's useful to allow more verbose output when running an
69
+ # individual spec file.
70
+ if config.files_to_run.one?
71
+ # Use the documentation formatter for detailed output,
72
+ # unless a formatter has already been configured
73
+ # (e.g. via a command-line flag).
74
+ config.default_formatter = "doc"
75
+ end
76
+
77
+ # Print the 10 slowest examples and example groups at the
78
+ # end of the spec run, to help surface which specs are running
79
+ # particularly slow.
80
+ # config.profile_examples = 10
81
+
82
+ # Run specs in random order to surface order dependencies. If you find an
83
+ # order dependency and want to debug it, you can fix the order by providing
84
+ # the seed, which is printed after each run.
85
+ # --seed 1234
86
+ config.order = :random
87
+
88
+ # Seed global randomization in this process using the `--seed` CLI option.
89
+ # Setting this allows you to use `--seed` to deterministically reproduce
90
+ # test failures related to randomization by passing the same `--seed` value
91
+ # as the one that triggered the failure.
92
+ Kernel.srand config.seed
93
+ end