poise 2.0.0 → 2.0.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ace7c3aba6dbd072ffe99718c8599290df36ff80
4
- data.tar.gz: 4822dff3762b4c319010e93102defab184a7dd2b
3
+ metadata.gz: 139be873d0ca15732ed1e63cda3c64fb5f66df07
4
+ data.tar.gz: 5c320b061767f73716e12d14cd4435d2ac454ade
5
5
  SHA512:
6
- metadata.gz: 71d3c8d0288dcad6916084eccbd21e8a25f5caae239269aecf838930ba96df15b069d08b97475930608d415eec6f38ba8991c18812c364d805d8be793ea04691
7
- data.tar.gz: 0455db8c92eb97d8760dce620865ae74497fb3ba645b12aeb9890238d8ec832cdf7d836508dbfe814c0b2da68ff5c4f9eac478a692c345891713ac1dd71d048d
6
+ metadata.gz: 3cad8094aa339ae2da67533a14be99ad2ad855f7f9e1896540db99a23a129c714e1cc906e89fa1c46be36a417bc5dfa4b24cf7882d51cfe73b881d1bfb98dabf
7
+ data.tar.gz: c924334c534a43fc017a2b2437479ff8b1e73460485df2559ebceb750178ec204219a6075185c2194a214b75cf061aeb7f9e714cee8845ee47a6e678fda28915
@@ -1,12 +1,12 @@
1
1
  sudo: false
2
2
  cache: bundler
3
3
  language: ruby
4
- rvm:
5
- - '2.2'
6
4
  addons:
7
5
  apt:
8
6
  packages:
9
7
  - libgecode-dev
8
+ rvm:
9
+ - '2.2'
10
10
  env:
11
11
  global:
12
12
  - USE_SYSTEM_GECODE=true
@@ -1,5 +1,25 @@
1
1
  # Changelog
2
2
 
3
+ ## v2.0.1
4
+
5
+ * Make the ChefspecHelpers helper a no-op if chefspec is not already loaded.
6
+ * Fix for finding the correct cookbook for a file when using vendored gems.
7
+ * New flag for the OptionCollector helper, `parser`:
8
+
9
+ ```ruby
10
+ class Resource < Chef::Resource
11
+ include Poise
12
+ attribute(:options, option_collector: true, parser: proc {|val| parse(val) })
13
+
14
+ def parse(val)
15
+ {name: val}
16
+ end
17
+ end
18
+ ```
19
+
20
+ * Fix for a possible infinite loop when using `ResourceProviderMixin` in a nested
21
+ module structure.
22
+
3
23
  ## v2.0.0
4
24
 
5
25
  Major overhaul! Poise is now a Halite gem/cookbook. New helpers:
data/Gemfile CHANGED
@@ -18,13 +18,10 @@ source 'https://rubygems.org/'
18
18
 
19
19
  gemspec path: File.expand_path('..', __FILE__)
20
20
 
21
- def dev_gem(name, path: File.join('..', name), github: "poise/#{name}")
22
- github = "#{github}/#{name}" unless github.include?('/')
21
+ def dev_gem(name, path: File.join('..', name))
23
22
  path = File.expand_path(File.join('..', path), __FILE__)
24
23
  if File.exist?(path)
25
24
  gem name, path: path
26
- else
27
- gem name, github: github
28
25
  end
29
26
  end
30
27
 
@@ -14,12 +14,8 @@
14
14
  # limitations under the License.
15
15
  #
16
16
 
17
- begin
18
- require 'chefspec'
19
- require 'rspec/expectations'
20
- rescue LoadError
21
- # Don't panic! We will no-op later on if these aren't available.
22
- end
17
+ # Not requiring chefspec or rspec/expectations since this code should only
18
+ # activate if they are already loaded.
23
19
 
24
20
  require 'poise/helpers/lwrp_polyfill'
25
21
  require 'poise/helpers/resource_name'
@@ -16,6 +16,8 @@
16
16
 
17
17
  require 'chef/mash'
18
18
 
19
+ require 'poise/error'
20
+
19
21
 
20
22
  module Poise
21
23
  module Helpers
@@ -80,8 +82,12 @@ module Poise
80
82
  # Define an option collector attribute. Normally used via {.attribute}.
81
83
  #
82
84
  # @param name [String, Symbol] Name of the attribute to define.
83
- # @param default [Object] Default value for the options.
84
- def option_collector_attribute(name, default: {})
85
+ # @param default [Hash] Default value for the options.
86
+ # @param parser [Proc, Symbol] Optional parser method. If a symbol it is
87
+ # called as a method on self. Takes a non-hash value and returns a
88
+ # hash of its parsed representation.
89
+ def option_collector_attribute(name, default: {}, parser: nil)
90
+ raise Poise::Error.new("Parser must be a Proc or Symbol: #{parser.inspect}") if parser && !(parser.is_a?(Proc) || parser.is_a?(Symbol))
85
91
  # Unlike LWRPBase.attribute, I don't care about Ruby 1.8. Worlds tiniest violin.
86
92
  define_method(name.to_sym) do |arg=nil, &block|
87
93
  iv_sym = :"@#{name}"
@@ -91,7 +97,15 @@ module Poise
91
97
  Mash.new(default) # Wrap in a mash because fuck str vs sym.
92
98
  end
93
99
  if arg
94
- raise Exceptions::ValidationFailed, "Option #{name} must be a Hash" if arg && !arg.is_a?(Hash)
100
+ if !arg.is_a?(Hash) && parser
101
+ arg = case parser
102
+ when Proc
103
+ instance_exec(arg, &parser)
104
+ when Symbol
105
+ send(parser, arg)
106
+ end
107
+ end
108
+ raise Exceptions::ValidationFailed, "Option #{name} must be a Hash" if !arg.is_a?(Hash)
95
109
  # Should this and the update below be a deep merge?
96
110
  value.update(arg)
97
111
  end
@@ -36,25 +36,35 @@ module Poise
36
36
  # # ...
37
37
  # end
38
38
  def find_cookbook_name(run_context, filename)
39
+ possibles = {}
40
+ Chef::Log.debug("[Poise] Checking cookbook for #{filename.inspect}")
39
41
  run_context.cookbook_collection.each do |name, ver|
40
42
  # This special method is added by Halite::Gem#as_cookbook_version.
41
43
  if ver.respond_to?(:halite_root)
42
44
  # The join is there because ../poise-ruby/lib starts with ../poise so
43
45
  # we want a trailing /.
46
+ Chef::Log.debug("")
44
47
  if filename.start_with?(File.join(ver.halite_root, ''))
45
- return name
48
+ Chef::Log.debug("[Poise] Found matching halite_root in #{name}: #{ver.halite_root.inspect}")
49
+ possibles[ver.halite_root] = name
46
50
  end
47
51
  else
48
52
  Chef::CookbookVersion::COOKBOOK_SEGMENTS.each do |seg|
49
53
  ver.segment_filenames(seg).each do |file|
54
+ # Put this behind an environment variable because it is verbose
55
+ # even for normal debugging-level output.
56
+ Chef::Log.debug("[Poise] Checking #{seg} in #{name}: #{file.inspect}") if ENV['POISE_DEBUG']
50
57
  if file == filename
51
- return name
58
+ Chef::Log.debug("[Poise] Found matching #{seg} in #{name}: #{file.inspect}")
59
+ possibles[file] = name
52
60
  end
53
61
  end
54
62
  end
55
63
  end
56
64
  end
57
- raise Poise::Error.new("Unable to find cookbook for file #{filename.inspect}")
65
+ raise Poise::Error.new("Unable to find cookbook for file #{filename.inspect}") if possibles.empty?
66
+ # Sort the items by matching path length, pick the name attached to the longest.
67
+ possibles.sort_by{|key, value| key.length }.last[1]
58
68
  end
59
69
  end
60
70
  end
@@ -34,20 +34,32 @@ module Poise
34
34
  # end
35
35
  # end
36
36
  module ResourceProviderMixin
37
- # @!classmethods
38
- module ClassMethods
39
- def included(klass)
40
- super
41
- klass.extend(ClassMethods)
42
- if klass < Chef::Resource
43
- klass.class_exec { include self::Resource }
44
- elsif klass < Chef::Provider
45
- klass.class_exec { include self::Provider }
37
+ def self.included(klass)
38
+ # Warning here be dragons.
39
+ # Create a new anonymous module, klass will be the module that
40
+ # actually included ResourceProviderMixin. We want to keep a reference
41
+ # to that locked down so that we can close over it and use it in the
42
+ # "real" .included defined below to find the original relative consts.
43
+ mod = Module.new do
44
+ # Use define_method instead of def so we can close over klass and mod.
45
+ define_method(:included) do |inner_klass|
46
+ # Has to be explicit because super inside define_method.
47
+ super(inner_klass)
48
+ # Cargo this .included to things which include us.
49
+ inner_klass.extend(mod)
50
+ # Dispatch to submodules, inner_klass is the most recent includer.
51
+ if inner_klass < Chef::Resource
52
+ # Use klass::Resource to look up relative to the original module.
53
+ inner_klass.class_exec { include klass::Resource }
54
+ elsif inner_klass < Chef::Provider
55
+ # As above, klass::Provider.
56
+ inner_klass.class_exec { include klass::Provider }
57
+ end
46
58
  end
47
59
  end
60
+ # Add our .included to the original includer.
61
+ klass.extend(mod)
48
62
  end
49
-
50
- extend ClassMethods
51
63
  end
52
64
  end
53
65
  end
@@ -16,5 +16,5 @@
16
16
 
17
17
 
18
18
  module Poise
19
- VERSION = '2.0.0'
19
+ VERSION = '2.0.1'
20
20
  end
@@ -15,4 +15,5 @@
15
15
  #
16
16
 
17
17
  eval_gemfile File.expand_path('../../../Gemfile', __FILE__)
18
+
18
19
  gem 'chef', '~> 12.0.0'
@@ -15,4 +15,5 @@
15
15
  #
16
16
 
17
17
  eval_gemfile File.expand_path('../../../Gemfile', __FILE__)
18
+
18
19
  gem 'chef', '~> 12.1.0'
@@ -15,4 +15,5 @@
15
15
  #
16
16
 
17
17
  eval_gemfile File.expand_path('../../../Gemfile', __FILE__)
18
+
18
19
  gem 'chef', '~> 12.2.0'
@@ -15,4 +15,5 @@
15
15
  #
16
16
 
17
17
  eval_gemfile File.expand_path('../../../Gemfile', __FILE__)
18
+
18
19
  gem 'chef', '~> 12.0'
@@ -15,6 +15,7 @@
15
15
  #
16
16
 
17
17
  eval_gemfile File.expand_path('../../../Gemfile', __FILE__)
18
+
18
19
  gem 'chef', github: 'chef/chef'
19
- # gem 'halite', github: 'poise/halite'
20
- # gem 'poise-boiler', github: 'poise/poise-boiler'
20
+ gem 'halite', github: 'poise/halite'
21
+ gem 'poise-boiler', github: 'poise/poise-boiler'
@@ -78,5 +78,49 @@ describe Poise::Helpers::OptionCollector do
78
78
  it { is_expected.to run_poise_test('test').with(options: {'one' => '1'}, value: 2) }
79
79
  end # /context with a normal attribute too
80
80
 
81
+ context 'with a parser Proc' do
82
+ resource(:poise_test) do
83
+ include Poise::Helpers::LWRPPolyfill
84
+ include described_class
85
+ attribute(:options, option_collector: true, parser: proc {|val| parse(val) })
86
+ def parse(val)
87
+ {name: val}
88
+ end
89
+ end
90
+ recipe do
91
+ poise_test 'test' do
92
+ options '1'
93
+ end
94
+ end
95
+
96
+ it { is_expected.to run_poise_test('test').with(options: {'name' => '1'}) }
97
+ end # /context with a parser Proc
98
+
99
+ context 'with a parser Symbol' do
100
+ resource(:poise_test) do
101
+ include Poise::Helpers::LWRPPolyfill
102
+ include described_class
103
+ attribute(:options, option_collector: true, parser: :parse)
104
+ def parse(val)
105
+ {name: val}
106
+ end
107
+ end
108
+ recipe do
109
+ poise_test 'test' do
110
+ options '1'
111
+ end
112
+ end
113
+
114
+ it { is_expected.to run_poise_test('test').with(options: {'name' => '1'}) }
115
+ end # /context with a parser Symbol
116
+
117
+ context 'with an invalid parse' do
118
+ it do
119
+ expect do
120
+ resource(:poise_test).send(:attribute, :options, option_collector: true, parser: 'invalid')
121
+ end.to raise_error(Poise::Error)
122
+ end
123
+ end # /context with an invalid parser
124
+
81
125
  # TODO: Write tests for mixed symbol/string data
82
126
  end
@@ -116,7 +116,7 @@ describe Poise::Helpers::Subresources::Container do
116
116
  it { is_expected.to run_inner('inner') }
117
117
  end # /context with a no namespace
118
118
 
119
- context 'with a no namespace and no inner name' do
119
+ context 'with a no namespace and an empty inner name' do
120
120
  resource(:poise_test) do
121
121
  include described_class
122
122
  container_namespace(false)
@@ -127,6 +127,21 @@ describe Poise::Helpers::Subresources::Container do
127
127
  end
128
128
  end
129
129
 
130
+ it { is_expected.to run_poise_test('container') }
131
+ it { is_expected.to run_inner('container') }
132
+ end # /context with a no namespace and an empty inner name
133
+
134
+ context 'with a no namespace and no inner name' do
135
+ resource(:poise_test) do
136
+ include described_class
137
+ container_namespace(false)
138
+ end
139
+ recipe do
140
+ poise_test 'container' do
141
+ inner
142
+ end
143
+ end
144
+
130
145
  it { is_expected.to run_poise_test('container') }
131
146
  it { is_expected.to run_inner('container') }
132
147
  end # /context with a no namespace and no inner name
@@ -37,6 +37,28 @@ module ResourceProviderMixinTest
37
37
  class Provider < Chef::Provider
38
38
  include Test
39
39
  end
40
+
41
+ module Test2
42
+ include Poise::Utils::ResourceProviderMixin
43
+
44
+ module Resource
45
+ include Test
46
+ end
47
+
48
+ module Provider
49
+ include Test
50
+ end
51
+ end
52
+
53
+ class Resource2 < Chef::Resource
54
+ include Test
55
+ include Test2
56
+ end
57
+
58
+ class Provider2 < Chef::Provider
59
+ include Test
60
+ include Test2
61
+ end
40
62
  end
41
63
 
42
64
  describe Poise::Utils::ResourceProviderMixin do
@@ -49,4 +71,18 @@ describe Poise::Utils::ResourceProviderMixin do
49
71
  subject { ResourceProviderMixinTest::Provider }
50
72
  it { is_expected.to be < ResourceProviderMixinTest::Test::Provider }
51
73
  end
74
+
75
+ context 'with nested usage' do
76
+ context 'in a resource' do
77
+ subject { ResourceProviderMixinTest::Resource2 }
78
+ it { is_expected.to be < ResourceProviderMixinTest::Test::Resource }
79
+ it { is_expected.to be < ResourceProviderMixinTest::Test2::Resource }
80
+ end
81
+
82
+ context 'in a provider' do
83
+ subject { ResourceProviderMixinTest::Provider2 }
84
+ it { is_expected.to be < ResourceProviderMixinTest::Test::Provider }
85
+ it { is_expected.to be < ResourceProviderMixinTest::Test2::Provider }
86
+ end
87
+ end # /context with nested usage
52
88
  end
@@ -106,5 +106,29 @@ describe Poise::Utils do
106
106
  end
107
107
  it { is_expected.to eq 'halite_cookbook_other' }
108
108
  end # /context with a Halite cookbook on a shared prefix
109
+
110
+ context 'with a Halite cookbook on a nested prefix' do
111
+ let(:filename) { '/source/halite_cookbook/vendor/other/lib/something.rb' }
112
+ before do
113
+ cookbooks << Chef::CookbookVersion.new('other_cookbook', '/test/other_cookbook').tap do |ver|
114
+ ver.library_filenames << '/test/other_cookbook/libraries/default.rb'
115
+ ver.recipe_filenames << '/test/other_cookbook/recipe/default.rb'
116
+ end
117
+ cookbooks << Chef::CookbookVersion.new('halite_cookbook', '/test/halite_cookbook').tap do |ver|
118
+ def ver.halite_root
119
+ '/source/halite_cookbook'
120
+ end
121
+ end
122
+ cookbooks << Chef::CookbookVersion.new('halite_cookbook_other', '/test/halite_cookbook/vendor/other').tap do |ver|
123
+ def ver.halite_root
124
+ '/source/halite_cookbook/vendor/other'
125
+ end
126
+ end
127
+ cookbooks << Chef::CookbookVersion.new('my_cookbook', '/test/my_cookbook').tap do |ver|
128
+ ver.recipe_filenames << '/test/my_cookbook/recipe/default.rb'
129
+ end
130
+ end
131
+ it { is_expected.to eq 'halite_cookbook_other' }
132
+ end # /context with a Halite cookbook on a nested prefix
109
133
  end # /describe .find_cookbook_name
110
134
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: poise
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0
4
+ version: 2.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Noah Kantrowitz
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-05-20 00:00:00.000000000 Z
11
+ date: 2015-05-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: halite