poise 2.6.1 → 2.7.0

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: 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: