poise 2.6.1 → 2.7.0

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: e47e162a7a11083aa3e77caaae22aaf1c4e99016
4
- data.tar.gz: 134c96de6e304855267955a405f8c25715b68a54
3
+ metadata.gz: 5c259866db8dc6ff155c572e3a1d5a237dd23e71
4
+ data.tar.gz: 64515ad046ac31f3c454ced2d852cafe27b029c7
5
5
  SHA512:
6
- metadata.gz: 2d8c33eba4b57fe71ad2c9a1e00f8b30ec0e619ef76520efc4b21c4e0df56daad869ca6458b801f9f9cdfed313e7639380252714c3a907ff381194c03fadc364
7
- data.tar.gz: f15d7623d0efcf762f728339f7d8a9403ba1a238151c7c5cdd67d55600d8610b3ad49e7ff3eebf213c684d90dc907423b424664ce937b980fd73b388b8771f58
6
+ metadata.gz: 89c9554bce8f2712bc0830fe8d6f1a69b7d1fd2de80e6c6d10ab51ff5cbb71234e2c50ba871657a6325a7e067efc7813d32bb4722d90b691a3f6413c0f7d3c79
7
+ data.tar.gz: 9c8b7865f4f36cccdb1dfc2e7db08ad99488c32e9a6eebdde4f3d7c5bb5a795652a3301ea89ac3249a0fc0edaf6ec92a05e6e4de0a14db6b2edb21cbeeeb84eb
@@ -1,3 +1,6 @@
1
1
  ---
2
2
  #<% require 'poise_boiler' %>
3
- <%= PoiseBoiler.kitchen(platforms: 'ubuntu-14.04') %>
3
+ <%= PoiseBoiler.kitchen(platforms: ENV['CI'] ? 'ubuntu-14.04' : %w{ubuntu-14.04 windows}) %>
4
+
5
+ verifier:
6
+ name: inspec
@@ -1,5 +1,14 @@
1
1
  # Changelog
2
2
 
3
+ ## v2.7.0
4
+
5
+ * More compatibility improvements for Chef 12.9.
6
+ * New helper: `Poise::Helpers::Win32User` to automatically convert `'root'`
7
+ defaults for user and group properties to more platform-appropriate values.
8
+ * Enhanced `poise_shell_out` to better cope with Windows command parsing. Use
9
+ Bash-style commands and it will automatically convert.
10
+ * Overall compatibility fixes for Windows.
11
+
3
12
  ## v2.6.1
4
13
 
5
14
  * Compatibility with Chef master to fix issues with `defined_in!` not ignoring
data/Gemfile CHANGED
@@ -30,3 +30,6 @@ end
30
30
  dev_gem 'halite'
31
31
  dev_gem 'poise-boiler'
32
32
  dev_gem 'poise-profiler'
33
+
34
+ # Pending https://github.com/customink/fauxhai/commit/d89f1e2de609478046e7a387f2b8d97729a68983
35
+ gem 'fauxhai', github: 'customink/fauxhai'
@@ -31,5 +31,6 @@ module Poise
31
31
  autoload :ResourceSubclass, 'poise/helpers/resource_subclass'
32
32
  autoload :Subresources, 'poise/helpers/subresources'
33
33
  autoload :TemplateContent, 'poise/helpers/template_content'
34
+ autoload :Win32User, 'poise/helpers/win32_user'
34
35
  end
35
36
  end
@@ -38,11 +38,18 @@ module Poise
38
38
  module DefinedIn
39
39
  # Path to the root of Poise's code.
40
40
  # @see #poise_defined!
41
+ # @api private
41
42
  POISE_LIB_ROOT = ::File.expand_path('../..', __FILE__)
42
43
 
43
44
  # Path to the root of Chef's code.
44
45
  # @see #poise_defined!
45
- CHEF_LIB_ROOT = ::Gem::Specification.find_by_name('chef').gem_dir
46
+ # @api private
47
+ CHEF_LIB_ROOT = ::File.join(::Gem::Specification.find_by_name('chef').gem_dir, 'lib')
48
+
49
+ # A regex used to parse Ruby's `caller` string syntax.
50
+ # @see #poise_defined!
51
+ # @api private
52
+ CALLER_REGEXP = /^(.+):\d+:in `.+'/
46
53
 
47
54
  # Wrapper for {.poise_defined_in_cookbook} to pass the run context for you.
48
55
  #
@@ -88,11 +95,15 @@ module Poise
88
95
  # Only try to set this once.
89
96
  return if @poise_defined_in
90
97
  # Parse out just the filenames.
91
- caller_array = caller_array.map {|line| line.split(/:/, 2).first }
98
+ caller_paths = caller_array.map {|line| line[CALLER_REGEXP, 1] }
92
99
  # Find the first non-poise, non-chef line. This assumes Halite
93
100
  # transformation which I'm not thrilled about.
94
- caller_path = caller_array.find do |line|
95
- !line.start_with?(POISE_LIB_ROOT) && !line.start_with?(CHEF_LIB_ROOT)
101
+ caller_path = caller_paths.find do |line|
102
+ line && !line.start_with?(POISE_LIB_ROOT) && !line.start_with?(CHEF_LIB_ROOT)
103
+ end
104
+ raise Poise::Error.new("Unable to find a caller path for: #{caller_array.inspect}") unless caller_path
105
+ if ::File::ALT_SEPARATOR
106
+ caller_path.gsub!(::File::ALT_SEPARATOR, ::File::SEPARATOR)
96
107
  end
97
108
  Chef::Log.debug("[#{self.name}] Recording poise_defined_in as #{caller_path}")
98
109
  @poise_defined_in = caller_path
@@ -30,7 +30,7 @@ module Poise
30
30
  def include_recipe(*recipes)
31
31
  loaded_recipes = []
32
32
  subcontext = subcontext_block do
33
- recipes.each do |recipe|
33
+ recipes.flatten.each do |recipe|
34
34
  case recipe
35
35
  when String
36
36
  # Process normally
@@ -0,0 +1,64 @@
1
+ #
2
+ # Copyright 2013-2016, 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/utils/win32'
18
+
19
+
20
+ module Poise
21
+ module Helpers
22
+ # A resource mixin to intercept properties named `user`, `group`, or `owner`,
23
+ # if their default value is `'root'` and make it work on Windows (and
24
+ # FreeBSD, AIX).
25
+ #
26
+ # @since 2.7.0
27
+ # @example
28
+ # class MyResource < Chef::Resource
29
+ # include Poise::Helpers::Win32User
30
+ # attribute(:user, default: 'root')
31
+ # attribute(:group, default: 'root')
32
+ # end
33
+ # @example Avoiding automatic translation
34
+ # class MyResource < Chef::Resource
35
+ # include Poise::Helpers::Win32User
36
+ # attribute(:user, default: lazy { 'root' })
37
+ # attribute(:group, default: lazy { 'root' })
38
+ # end
39
+ module Win32User
40
+ # User-ish property names.
41
+ # @api private
42
+ USER_PROPERTIES = ['user', :user, 'owner', :owner]
43
+
44
+ # Group-ish property names.
45
+ # @api private
46
+ GROUP_PROPERTIES = ['group', :group]
47
+
48
+ # Intercept property access to swap out the default value.
49
+ # @api private
50
+ def set_or_return(symbol, arg, options={})
51
+ if options && options[:default] == 'root'
52
+ if USER_PROPERTIES.include?(symbol) && node.platform_family?('windows')
53
+ options = options.dup
54
+ options[:default] = Poise::Utils::Win32.admin_user
55
+ elsif GROUP_PROPERTIES.include?(symbol)
56
+ options = options.dup
57
+ options[:default] = node['root_group']
58
+ end
59
+ end
60
+ super(symbol, arg, options)
61
+ end
62
+ end
63
+ end
64
+ end
@@ -33,8 +33,10 @@ module Poise
33
33
  # end
34
34
  module Provider
35
35
  include Poise::Helpers::DefinedIn
36
- include Poise::Helpers::IncludeRecipe
37
36
  include Poise::Helpers::LWRPPolyfill
37
+ # IncludeRecipe must come after LWRPPolyfill because that pulls in the
38
+ # recipe DSL which has its own #include_recipe.
39
+ include Poise::Helpers::IncludeRecipe
38
40
  include Poise::Helpers::NotifyingBlock
39
41
  include Poise::Utils::ShellOut
40
42
 
@@ -42,6 +42,7 @@ module Poise
42
42
  include Poise::Helpers::ResourceName
43
43
  include Poise::Helpers::ResourceSubclass
44
44
  include Poise::Helpers::TemplateContent
45
+ include Poise::Helpers::Win32User # Must be after LazyDefault.
45
46
  include Poise::Utils::ShellOut
46
47
 
47
48
  # @!classmethods
@@ -36,15 +36,20 @@ module Poise
36
36
  # ever fire because the superclass re-raises if there is an error.
37
37
  return super if error
38
38
  delayed_actions.each do |notification|
39
- notifications = run_context.parent_run_context.delayed_notifications(@resource)
40
- if notifications.any? { |existing_notification| existing_notification.duplicates?(notification) }
41
- Chef::Log.info( "#{@resource} not queuing delayed action #{notification.action} on #{notification.resource}"\
42
- " (delayed), as it's already been queued")
39
+ if @resource.run_context.respond_to?(:add_delayed_action)
40
+ @resource.run_context.add_delayed_action(notification)
43
41
  else
44
- notifications << notification
42
+ notifications = run_context.parent_run_context.delayed_notifications(@resource)
43
+ if notifications.any? { |existing_notification| existing_notification.duplicates?(notification) }
44
+ Chef::Log.info( "#{@resource} not queuing delayed action #{notification.action} on #{notification.resource}"\
45
+ " (delayed), as it's already been queued")
46
+ else
47
+ notifications << notification
48
+ end
45
49
  end
46
50
  end
47
51
  end
52
+
48
53
  end
49
54
  end
50
55
  end
@@ -21,6 +21,7 @@ module Poise
21
21
  module Utils
22
22
  autoload :ResourceProviderMixin, 'poise/utils/resource_provider_mixin'
23
23
  autoload :ShellOut, 'poise/utils/shell_out'
24
+ autoload :Win32, 'poise/utils/win32'
24
25
 
25
26
  extend self
26
27
 
@@ -51,6 +52,9 @@ module Poise
51
52
  else
52
53
  Chef::CookbookVersion::COOKBOOK_SEGMENTS.each do |seg|
53
54
  ver.segment_filenames(seg).each do |file|
55
+ if ::File::ALT_SEPARATOR
56
+ file = file.gsub(::File::ALT_SEPARATOR, ::File::SEPARATOR)
57
+ end
54
58
  # Put this behind an environment variable because it is verbose
55
59
  # even for normal debugging-level output.
56
60
  Poise.debug("[Poise] Checking #{seg} in #{name}: #{file.inspect}")
@@ -69,6 +69,11 @@ module Poise
69
69
  end
70
70
  # Set the default group on Unix.
71
71
  options[:group] ||= ent.gid if ent
72
+ # Mixlib-ShellOut doesn't support array commands on Windows and has
73
+ # super wonky escaping for cmd.exe.
74
+ if respond_to?(:node) && node.platform_family?('windows')
75
+ command_args = [Poise::Utils::Win32.reparse_command(*command_args)]
76
+ end
72
77
  # Call Chef's shell_out wrapper.
73
78
  shell_out(*command_args, **options)
74
79
  end
@@ -0,0 +1,121 @@
1
+ #
2
+ # Copyright 2016, 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 'shellwords'
18
+
19
+
20
+ module Poise
21
+ module Utils
22
+ # Utilities for working with Windows.
23
+ #
24
+ # @since 2.7.0
25
+ module Win32
26
+ extend self
27
+
28
+ # Code borrowed from https://github.com/chef-cookbooks/chef-client/blob/master/libraries/helpers.rb
29
+ # Used under the terms of the Apache v2 license.
30
+ # Copyright 2012-2016, John Dewey
31
+
32
+ # Run a WMI query and extracts a property. This assumes Chef has already
33
+ # loaded the win32 libraries.
34
+ #
35
+ # @api private
36
+ # @param wmi_property [Symbol] Property to extract.
37
+ # @param wmi_query [String] Query to run.
38
+ # @return [String]
39
+ def wmi_property_from_query(wmi_property, wmi_query)
40
+ @wmi = ::WIN32OLE.connect('winmgmts://')
41
+ result = @wmi.ExecQuery(wmi_query)
42
+ return nil unless result.each.count > 0
43
+ result.each.next.send(wmi_property)
44
+ end
45
+
46
+ # Find the name of the Administrator user, give or take localization.
47
+ #
48
+ # @return [String]
49
+ def admin_user
50
+ wmi_property_from_query(:name, "select * from Win32_UserAccount where sid like 'S-1-5-21-%-500' and LocalAccount=True")
51
+ end
52
+
53
+ # Escaping that is compatible with CommandLineToArgvW. Based on
54
+ # https://blogs.msdn.microsoft.com/twistylittlepassagesallalike/2011/04/23/everyone-quotes-command-line-arguments-the-wrong-way/
55
+ #
56
+ # @api private
57
+ # @param string [String] String to escape.
58
+ # @return [String]
59
+ def argv_quote(string, force_quote: false)
60
+ if !force_quote && !string.empty? && string !~ /[ \t\n\v"]/
61
+ # Nothing fancy, no escaping needed.
62
+ string
63
+ else
64
+ command_line = '"'
65
+ i = 0
66
+ while true
67
+ number_backslashes = 0
68
+
69
+ while i != string.size && string[i] == '\\'
70
+ i += 1
71
+ number_backslashes += 1
72
+ end
73
+
74
+ if i == string.size
75
+ # Escape all backslashes, but let the terminating
76
+ # double quotation mark we add below be interpreted
77
+ # as a metacharacter.
78
+ command_line << '\\' * (number_backslashes * 2)
79
+ break
80
+ elsif string[i] == '"'
81
+ # Escape all backslashes and the following
82
+ # double quotation mark.
83
+ command_line << '\\' * ((number_backslashes * 2) + 1)
84
+ command_line << '"'
85
+ else
86
+ # Backslashes aren't special here.
87
+ command_line << '\\' * number_backslashes
88
+ command_line << string[i]
89
+ end
90
+ i += 1
91
+ end
92
+ command_line << '"'
93
+ command_line
94
+ end
95
+ end
96
+
97
+ # Take a string or array command in the format used by shell_out et al and
98
+ # create something we can use on Windows.
99
+ #
100
+ # @
101
+ def reparse_command(*args)
102
+ array_mode = !(args.length == 1 && args.first.is_a?(String))
103
+ # At some point when mixlib-shellout groks array commands on Windows,
104
+ # we should support that here.
105
+ parsed_args = array_mode ? args.flatten : Shellwords.split(args.first)
106
+ cmd = parsed_args.map {|s| argv_quote(s) }.join(' ')
107
+ if array_mode
108
+ # This fails on non-Windows because of win32/process.
109
+ require 'mixlib/shellout/windows'
110
+ if Mixlib::ShellOut::Windows::Utils.should_run_under_cmd?(cmd)
111
+ # If we are in array mode, try to make cmd.exe keep its grubby paws
112
+ # off our metacharacters.
113
+ cmd = cmd.each_char.map {|c| '^'+c }.join('')
114
+ end
115
+ end
116
+ cmd
117
+ end
118
+
119
+ end
120
+ end
121
+ end
@@ -16,5 +16,5 @@
16
16
 
17
17
 
18
18
  module Poise
19
- VERSION = '2.6.1'
19
+ VERSION = '2.7.0'
20
20
  end
@@ -34,5 +34,7 @@ Gem::Specification.new do |spec|
34
34
  spec.require_paths = %w{lib}
35
35
 
36
36
  spec.add_dependency 'halite', '~> 1.0'
37
- spec.add_development_dependency 'poise-boiler', '~> 1.0'
37
+
38
+ spec.add_development_dependency 'kitchen-inspec', '~> 0.12'
39
+ spec.add_development_dependency 'poise-boiler', '~> 1.8'
38
40
  end
@@ -20,7 +20,8 @@ require 'poise'
20
20
  class Chef
21
21
  class Resource::App < Resource
22
22
  include Poise(container: true)
23
- default_action(:install)
23
+ provides(:app)
24
+ actions(:install)
24
25
 
25
26
  attribute(:path, kind_of: String, name_attribute: true)
26
27
  attribute(:user, kind_of: String, default: 'root')
@@ -19,7 +19,8 @@ require_relative 'app'
19
19
  class Chef
20
20
  class Resource::AppConfig < Resource
21
21
  include Poise(App)
22
- default_action(:create)
22
+ provides(:app_config)
23
+ actions(:create)
23
24
 
24
25
  attribute('', template: true, required: true)
25
26
  attribute(:config_name, kind_of: String, default: lazy { name.split('::').last })
@@ -14,7 +14,7 @@
14
14
  # limitations under the License.
15
15
  #
16
16
 
17
- app '/srv/app' do
17
+ app '/app' do
18
18
  app_config 'defaults' do
19
19
  content 'some defaults'
20
20
  end
@@ -14,22 +14,23 @@
14
14
  # limitations under the License.
15
15
  #
16
16
 
17
- require 'serverspec'
18
- set :backend, :exec
17
+ is_windows = os.windows?
19
18
 
20
- describe file('/srv/app') do
19
+ describe file('/app') do
21
20
  it { is_expected.to be_a_directory }
22
- it { is_expected.to be_owned_by 'root' }
21
+ it { is_expected.to be_owned_by 'root' } unless is_windows
23
22
  end
24
23
 
25
- describe file('/srv/app/defaults.conf') do
24
+ describe file('/app/defaults.conf') do
26
25
  it { is_expected.to be_a_file }
27
- it { is_expected.to be_owned_by 'root' }
28
- its(:content) { is_expected.to eq 'some defaults' }
26
+ it { is_expected.to be_owned_by 'root' } unless is_windows
27
+ # Pending https://github.com/chef/train/issues/81.
28
+ its(:content) { is_expected.to match /^some defaults\s*$/ }
29
29
  end
30
30
 
31
- describe file('/srv/app/user.conf') do
31
+ describe file('/app/user.conf') do
32
32
  it { is_expected.to be_a_file }
33
- it { is_expected.to be_owned_by 'root' }
34
- its(:content) { is_expected.to eq 'user config' }
33
+ it { is_expected.to be_owned_by 'root' } unless is_windows
34
+ # Pending https://github.com/chef/train/issues/81.
35
+ its(:content) { is_expected.to match /^user config\s*$/ }
35
36
  end
@@ -14,30 +14,31 @@
14
14
  # limitations under the License.
15
15
  #
16
16
 
17
- require 'serverspec'
18
- set :backend, :exec
19
-
20
17
  describe file('/inversion/a') do
21
18
  it { is_expected.to be_a_file }
22
19
  end
23
20
 
24
21
  describe file('/inversion/b') do
25
22
  it { is_expected.to be_a_file }
26
- its(:content) { is_expected.to eq 'one' }
23
+ # Pending https://github.com/chef/train/issues/81.
24
+ its(:content) { is_expected.to match /^one\s*$/ }
27
25
  end
28
26
 
29
27
  describe file('/inversion/c') do
30
28
  it { is_expected.to be_a_file }
31
- its(:content) { is_expected.to eq 'two' }
29
+ # Pending https://github.com/chef/train/issues/81.
30
+ its(:content) { is_expected.to match /^two\s*$/ }
32
31
  end
33
32
 
34
33
  describe file('/inversion/d') do
35
34
  it { is_expected.to be_a_file }
36
- its(:content) { is_expected.to eq 'd-three' }
35
+ # Pending https://github.com/chef/train/issues/81.
36
+ its(:content) { is_expected.to match /^d-three\s*$/ }
37
37
  end
38
38
 
39
39
  describe file('/inversion/e') do
40
40
  it { is_expected.to be_a_file }
41
- its(:content) { is_expected.to eq 'e-three' }
41
+ # Pending https://github.com/chef/train/issues/81.
42
+ its(:content) { is_expected.to match /^e-three\s*$/ }
42
43
  end
43
44
 
@@ -18,17 +18,85 @@ require 'spec_helper'
18
18
 
19
19
  describe Poise::Helpers::IncludeRecipe do
20
20
  resource(:poise_test)
21
- provider(:poise_test) do
22
- include described_class
23
-
24
- def action_run
25
- expect_any_instance_of(Chef::RunContext).to receive(:include_recipe).with('other').and_return(['other::default'])
26
- include_recipe 'other'
27
- end
28
- end
29
21
  recipe do
30
22
  poise_test 'test'
31
23
  end
32
24
 
33
- it { run_chef }
25
+ context 'with a string' do
26
+ provider(:poise_test) do
27
+ include described_class
28
+
29
+ def action_run
30
+ include_recipe 'other'
31
+ end
32
+ end
33
+
34
+ it do
35
+ expect_any_instance_of(Chef::RunContext).to receive(:include_recipe).with('other').and_return(['other::default'])
36
+ run_chef
37
+ end
38
+ end # /context with a string
39
+
40
+ context 'with a proc' do
41
+ provider(:poise_test) do
42
+ include described_class
43
+
44
+ def action_run
45
+ include_recipe proc { node.run_state['proc1'] = true }
46
+ end
47
+ end
48
+
49
+ it do
50
+ run_chef
51
+ expect(chef_run.node.run_state['proc1']).to be true
52
+ end
53
+ end # /context with a proc
54
+
55
+ context 'with an multiple arguments' do
56
+ provider(:poise_test) do
57
+ include described_class
58
+
59
+ def action_run
60
+ include_recipe('other', proc { node.run_state['proc2'] = true })
61
+ end
62
+ end
63
+
64
+ it do
65
+ expect_any_instance_of(Chef::RunContext).to receive(:include_recipe).with('other').and_return(['other::default'])
66
+ run_chef
67
+ expect(chef_run.node.run_state['proc2']).to be true
68
+ end
69
+ end # /context with an multiple arguments
70
+
71
+ context 'with an array' do
72
+ provider(:poise_test) do
73
+ include described_class
74
+
75
+ def action_run
76
+ include_recipe ['other', proc { node.run_state['proc3'] = true }]
77
+ end
78
+ end
79
+
80
+ it do
81
+ expect_any_instance_of(Chef::RunContext).to receive(:include_recipe).with('other').and_return(['other::default'])
82
+ run_chef
83
+ expect(chef_run.node.run_state['proc3']).to be true
84
+ end
85
+ end # /context with an array
86
+
87
+ context 'via include Poise' do
88
+ provider(:poise_test) do
89
+ include Poise
90
+
91
+ def action_run
92
+ include_recipe ['other', proc { node.run_state['proc4'] = true }]
93
+ end
94
+ end
95
+
96
+ it do
97
+ expect_any_instance_of(Chef::RunContext).to receive(:include_recipe).with('other').and_return(['other::default'])
98
+ run_chef
99
+ expect(chef_run.node.run_state['proc4']).to be true
100
+ end
101
+ end # /context via include Poise
34
102
  end
@@ -0,0 +1,177 @@
1
+ #
2
+ # Copyright 2016, 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 'spec_helper'
18
+
19
+ describe Poise::Helpers::Win32User do
20
+ let(:chefspec_options) { {platform: 'ubuntu', version: '14.04'} }
21
+ provider(:poise_test)
22
+ before do
23
+ allow(Poise::Utils::Win32).to receive(:admin_user).and_return('Administrator')
24
+ end
25
+
26
+ context 'user property' do
27
+ resource(:poise_test) do
28
+ include Poise::Helpers::LWRPPolyfill
29
+ include described_class
30
+ attribute(:user, default: 'root')
31
+ end
32
+
33
+ context 'with a default' do
34
+ recipe do
35
+ poise_test 'test'
36
+ end
37
+
38
+ context 'on Linux' do
39
+ it { is_expected.to run_poise_test('test').with(user: 'root') }
40
+ end # /context on Linux
41
+
42
+ context 'on Windows' do
43
+ let(:chefspec_options) { {platform: 'windows', version: '2012R2'} }
44
+ it { is_expected.to run_poise_test('test').with(user: 'Administrator') }
45
+ end # /context on Windows
46
+ end # /context with a default
47
+
48
+ context 'with a value' do
49
+ recipe do
50
+ poise_test 'test' do
51
+ user 'other'
52
+ end
53
+ end
54
+
55
+ context 'on Linux' do
56
+ it { is_expected.to run_poise_test('test').with(user: 'other') }
57
+ end # /context on Linux
58
+
59
+ context 'on Windows' do
60
+ let(:chefspec_options) { {platform: 'windows', version: '2012R2'} }
61
+ it { is_expected.to run_poise_test('test').with(user: 'other') }
62
+ end # /context on Windows
63
+ end # /context with a value
64
+ end # /context user property
65
+
66
+ context 'owner property' do
67
+ resource(:poise_test) do
68
+ include Poise::Helpers::LWRPPolyfill
69
+ include described_class
70
+ attribute(:owner, default: 'root')
71
+ end
72
+
73
+ context 'with a default' do
74
+ recipe do
75
+ poise_test 'test'
76
+ end
77
+
78
+ context 'on Linux' do
79
+ it { is_expected.to run_poise_test('test').with(owner: 'root') }
80
+ end # /context on Linux
81
+
82
+ context 'on Windows' do
83
+ let(:chefspec_options) { {platform: 'windows', version: '2012R2'} }
84
+ it { is_expected.to run_poise_test('test').with(owner: 'Administrator') }
85
+ end # /context on Windows
86
+ end # /context with a default
87
+
88
+ context 'with a value' do
89
+ recipe do
90
+ poise_test 'test' do
91
+ owner 'other'
92
+ end
93
+ end
94
+
95
+ context 'on Linux' do
96
+ it { is_expected.to run_poise_test('test').with(owner: 'other') }
97
+ end # /context on Linux
98
+
99
+ context 'on Windows' do
100
+ let(:chefspec_options) { {platform: 'windows', version: '2012R2'} }
101
+ it { is_expected.to run_poise_test('test').with(owner: 'other') }
102
+ end # /context on Windows
103
+ end # /context with a value
104
+ end # /context owner property
105
+
106
+ context 'group property' do
107
+ resource(:poise_test) do
108
+ include Poise::Helpers::LWRPPolyfill
109
+ include described_class
110
+ attribute(:group, default: 'root')
111
+ end
112
+
113
+ context 'with a default' do
114
+ recipe do
115
+ poise_test 'test'
116
+ end
117
+
118
+ context 'on Linux' do
119
+ it { is_expected.to run_poise_test('test').with(group: 'root') }
120
+ end # /context on Linux
121
+
122
+ context 'on Windows' do
123
+ let(:chefspec_options) { {platform: 'windows', version: '2012R2'} }
124
+ # This test is written to be silly because Fauxhai doesn't have
125
+ # root_group data for Windows.
126
+ it { is_expected.to run_poise_test('test').with(group: chef_run.node['root_group']) }
127
+ end # /context on Windows
128
+
129
+ context 'on AIX' do
130
+ let(:chefspec_options) { {platform: 'aix', version: '6.1'} }
131
+ it { is_expected.to run_poise_test('test').with(group: 'system') }
132
+ end # /context on AIX
133
+ end # /context with a default
134
+
135
+ context 'with a value' do
136
+ recipe do
137
+ poise_test 'test' do
138
+ group 'other'
139
+ end
140
+ end
141
+
142
+ context 'on Linux' do
143
+ it { is_expected.to run_poise_test('test').with(group: 'other') }
144
+ end # /context on Linux
145
+
146
+ context 'on Windows' do
147
+ let(:chefspec_options) { {platform: 'windows', version: '2012R2'} }
148
+ it { is_expected.to run_poise_test('test').with(group: 'other') }
149
+ end # /context on Windows
150
+ end # /context with a value
151
+ end # /context group property
152
+
153
+ describe 'interaction with lazy defaults' do
154
+ let(:chefspec_options) { {platform: 'windows', version: '2012R2'} }
155
+ recipe do
156
+ poise_test 'test'
157
+ end
158
+
159
+ context 'with a non-lazy default' do
160
+ resource(:poise_test) do
161
+ include Poise::Resource
162
+ attribute(:user, default: 'root')
163
+ end
164
+
165
+ it { is_expected.to run_poise_test('test').with(user: 'Administrator') }
166
+ end # /context with a non-lazy default
167
+
168
+ context 'with a lazy default' do
169
+ resource(:poise_test) do
170
+ include Poise::Resource
171
+ attribute(:user, default: lazy { 'root' })
172
+ end
173
+
174
+ it { is_expected.to run_poise_test('test').with(user: 'root') }
175
+ end # /context with a lazy default
176
+ end # /describe interaction with lazy defaults
177
+ end
@@ -15,4 +15,10 @@
15
15
  #
16
16
 
17
17
  require 'poise_boiler/spec_helper'
18
+
19
+ # If we aren't on Windows, inject our fake win32/process module.
20
+ unless RbConfig::CONFIG['host_os'] =~ /mswin|mingw|cygwin/
21
+ $LOAD_PATH.insert(0, File.expand_path('../utils/win32_helper', __FILE__))
22
+ end
23
+
18
24
  require 'poise'
@@ -0,0 +1,19 @@
1
+ #
2
+ # Copyright 2016, 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
+ # A fake module to use for mixlib/shellout/windows/core_ext on non-windows systems so the code can
19
+ # work for testing.
@@ -0,0 +1,30 @@
1
+ #
2
+ # Copyright 2016, 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
+ # A fake module to use for win32/process on non-windows systems so the code can
19
+ # work for testing.
20
+ #
21
+ # @api private
22
+ module Process
23
+ module Functions
24
+ def self.method_missing(*args)
25
+ end
26
+ end
27
+
28
+ module Constants
29
+ end
30
+ end
@@ -0,0 +1,25 @@
1
+ #
2
+ # Copyright 2016, 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
+ # A fake module to use for windows/handle on non-windows systems so the code can
19
+ # work for testing.
20
+ #
21
+ # @api private
22
+ module Windows
23
+ module Handle
24
+ end
25
+ end
@@ -0,0 +1,25 @@
1
+ #
2
+ # Copyright 2016, 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
+ # A fake module to use for windows/process on non-windows systems so the code can
19
+ # work for testing.
20
+ #
21
+ # @api private
22
+ module Windows
23
+ module Process
24
+ end
25
+ end
@@ -0,0 +1,25 @@
1
+ #
2
+ # Copyright 2016, 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
+ # A fake module to use for windows/synchronize on non-windows systems so the code can
19
+ # work for testing.
20
+ #
21
+ # @api private
22
+ module Windows
23
+ module Synchronize
24
+ end
25
+ end
@@ -0,0 +1,86 @@
1
+ #
2
+ # Copyright 2016, 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 'spec_helper'
18
+ require 'shellwords'
19
+
20
+ describe Poise::Utils::Win32 do
21
+ describe '#argv_quote' do
22
+ let(:input) { }
23
+ let(:force_quote) { false }
24
+ subject { described_class.argv_quote(input, force_quote: force_quote) }
25
+
26
+ context 'with an empty string' do
27
+ let(:input) { '' }
28
+ it { is_expected.to eq '""' }
29
+ end # /context with an empty string
30
+
31
+ context 'with one word' do
32
+ let(:input) { 'foo' }
33
+ it { is_expected.to eq 'foo' }
34
+ end # /context with one word
35
+
36
+ context 'with two words' do
37
+ let(:input) { 'foo bar' }
38
+ it { is_expected.to eq '"foo bar"' }
39
+ end # /context with two words
40
+
41
+ context 'with a quote' do
42
+ let(:input) { 'foo"bar' }
43
+ it { is_expected.to eq '"foo\\"bar"' }
44
+ end # /context with a quote
45
+
46
+ context 'with an escaped quote' do
47
+ let(:input) { '"foo \\"bar\\""' }
48
+ it { is_expected.to eq '"\\"foo \\\\\\"bar\\\\\\"\\""' }
49
+ end # /context with an escaped quote
50
+ end # /describe #argv_quote
51
+
52
+ describe 'reparse_command' do
53
+ let(:input) { [] }
54
+ subject { described_class.reparse_command(*input) }
55
+
56
+ context 'with a simple string' do
57
+ let(:input) { ['foo bar baz'] }
58
+ it { is_expected.to eq 'foo bar baz' }
59
+ end # /context with a simple string
60
+
61
+ context 'with a more complex string' do
62
+ let(:input) { [Shellwords.join(['pip', 'install', 'foo==1.2.3'])] }
63
+ it { is_expected.to eq 'pip install foo==1.2.3' }
64
+ end # /context with a more complex string
65
+
66
+ context 'with a quoted string' do
67
+ let(:input) { [Shellwords.join(['myapp', 'create', 'a thing'])] }
68
+ it { is_expected.to eq 'myapp create "a thing"' }
69
+ end # /context with a quoted string
70
+
71
+ context 'with metacharacters' do
72
+ let(:input) { ['myapp > tmp'] }
73
+ it { is_expected.to eq 'myapp > tmp' }
74
+ end # /context with metacharacters
75
+
76
+ context 'with an array' do
77
+ let(:input) { ['myapp', 'create', 'a thing'] }
78
+ it { is_expected.to eq 'myapp create "a thing"' }
79
+ end # /context with an array
80
+
81
+ context 'with an array with metacharacters' do
82
+ let(:input) { ['myapp', '>', 'tmp'] }
83
+ it { is_expected.to eq '^m^y^a^p^p^ ^>^ ^t^m^p' }
84
+ end # /context with an array with metacharacters
85
+ end # /describe reparse_command
86
+ 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.6.1
4
+ version: 2.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Noah Kantrowitz
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-03-28 00:00:00.000000000 Z
11
+ date: 2016-04-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: halite
@@ -24,20 +24,34 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '1.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: kitchen-inspec
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0.12'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0.12'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: poise-boiler
29
43
  requirement: !ruby/object:Gem::Requirement
30
44
  requirements:
31
45
  - - "~>"
32
46
  - !ruby/object:Gem::Version
33
- version: '1.0'
47
+ version: '1.8'
34
48
  type: :development
35
49
  prerelease: false
36
50
  version_requirements: !ruby/object:Gem::Requirement
37
51
  requirements:
38
52
  - - "~>"
39
53
  - !ruby/object:Gem::Version
40
- version: '1.0'
54
+ version: '1.8'
41
55
  description: Helpers for writing extensible Chef cookbooks.
42
56
  email:
43
57
  - noah@coderanger.net
@@ -81,6 +95,7 @@ files:
81
95
  - lib/poise/helpers/subresources/container.rb
82
96
  - lib/poise/helpers/subresources/default_containers.rb
83
97
  - lib/poise/helpers/template_content.rb
98
+ - lib/poise/helpers/win32_user.rb
84
99
  - lib/poise/provider.rb
85
100
  - lib/poise/resource.rb
86
101
  - lib/poise/subcontext.rb
@@ -89,6 +104,7 @@ files:
89
104
  - lib/poise/utils.rb
90
105
  - lib/poise/utils/resource_provider_mixin.rb
91
106
  - lib/poise/utils/shell_out.rb
107
+ - lib/poise/utils/win32.rb
92
108
  - lib/poise/version.rb
93
109
  - poise.gemspec
94
110
  - test/cookbook/attributes/default.rb
@@ -111,8 +127,8 @@ files:
111
127
  - test/gemfiles/chef-12.8.gemfile
112
128
  - test/gemfiles/chef-12.gemfile
113
129
  - test/gemfiles/master.gemfile
114
- - test/integration/default/serverspec/default_spec.rb
115
- - test/integration/default/serverspec/inversion_spec.rb
130
+ - test/integration/default/default_spec.rb
131
+ - test/integration/default/inversion_spec.rb
116
132
  - test/spec/backports/not_passed_spec.rb
117
133
  - test/spec/backports/verify_path_spec.rb
118
134
  - test/spec/helpers/chefspec_matchers_spec.rb
@@ -132,6 +148,7 @@ files:
132
148
  - test/spec/helpers/subresources/child_spec.rb
133
149
  - test/spec/helpers/subresources/container_spec.rb
134
150
  - test/spec/helpers/template_content_spec.rb
151
+ - test/spec/helpers/win32_user_spec.rb
135
152
  - test/spec/poise_spec.rb
136
153
  - test/spec/provider_spec.rb
137
154
  - test/spec/resource_spec.rb
@@ -139,6 +156,12 @@ files:
139
156
  - test/spec/subcontext/resource_collection_spec.rb
140
157
  - test/spec/utils/resource_provider_mixin_spec.rb
141
158
  - test/spec/utils/shell_out_spec.rb
159
+ - test/spec/utils/win32_helper/mixlib/shellout/windows/core_ext.rb
160
+ - test/spec/utils/win32_helper/win32/process.rb
161
+ - test/spec/utils/win32_helper/windows/handle.rb
162
+ - test/spec/utils/win32_helper/windows/process.rb
163
+ - test/spec/utils/win32_helper/windows/synchronize.rb
164
+ - test/spec/utils/win32_spec.rb
142
165
  - test/spec/utils_spec.rb
143
166
  homepage: https://github.com/poise/poise
144
167
  licenses:
@@ -185,8 +208,8 @@ test_files:
185
208
  - test/gemfiles/chef-12.8.gemfile
186
209
  - test/gemfiles/chef-12.gemfile
187
210
  - test/gemfiles/master.gemfile
188
- - test/integration/default/serverspec/default_spec.rb
189
- - test/integration/default/serverspec/inversion_spec.rb
211
+ - test/integration/default/default_spec.rb
212
+ - test/integration/default/inversion_spec.rb
190
213
  - test/spec/backports/not_passed_spec.rb
191
214
  - test/spec/backports/verify_path_spec.rb
192
215
  - test/spec/helpers/chefspec_matchers_spec.rb
@@ -206,6 +229,7 @@ test_files:
206
229
  - test/spec/helpers/subresources/child_spec.rb
207
230
  - test/spec/helpers/subresources/container_spec.rb
208
231
  - test/spec/helpers/template_content_spec.rb
232
+ - test/spec/helpers/win32_user_spec.rb
209
233
  - test/spec/poise_spec.rb
210
234
  - test/spec/provider_spec.rb
211
235
  - test/spec/resource_spec.rb
@@ -213,5 +237,11 @@ test_files:
213
237
  - test/spec/subcontext/resource_collection_spec.rb
214
238
  - test/spec/utils/resource_provider_mixin_spec.rb
215
239
  - test/spec/utils/shell_out_spec.rb
240
+ - test/spec/utils/win32_helper/mixlib/shellout/windows/core_ext.rb
241
+ - test/spec/utils/win32_helper/win32/process.rb
242
+ - test/spec/utils/win32_helper/windows/handle.rb
243
+ - test/spec/utils/win32_helper/windows/process.rb
244
+ - test/spec/utils/win32_helper/windows/synchronize.rb
245
+ - test/spec/utils/win32_spec.rb
216
246
  - test/spec/utils_spec.rb
217
247
  has_rdoc: