poise 2.0.0 → 2.0.1

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