chef-config 16.3.45 → 16.5.77

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
  SHA256:
3
- metadata.gz: 1ade66dc16ffdf5ee8f8c5014fcf5d938aae6e556f7141b3e95e9c36514075b0
4
- data.tar.gz: '03098cd93b7521fb516aa6f85e595b6ca188061e35212c2bfcabc9d4fa331a4f'
3
+ metadata.gz: be09ac190045e0d04778b9d2121594585ab1e56bb6581ff0dfe5ff1591764141
4
+ data.tar.gz: 77fad1d3fb02f4de4e8442bfa0feea9c5afc659e289541e1984cc244f4cf6794
5
5
  SHA512:
6
- metadata.gz: 6208efdfa2e4880a2a28dd2c67ebfd5275699f875742277f3780de21377074dd75650b206b2a23ba2bcc1ccb317a93281913186de013e2919e0c2888d415f2cf
7
- data.tar.gz: 4f7d873f1940b88371832148c724a9c7e6e8688390e70169990915e6291364557d143089975fffade3502a8d8c0bf33690bdf8c1fa5423cc9023495e910c559a
6
+ metadata.gz: e507e5b152b916aa72aac2ce937daab4af31c356cbb9f83a7eaf71f9a1a3df9ba7f473990617983b5277a8351729432d41121094d4b0da524933230c92d80f24
7
+ data.tar.gz: ec00b7ea3951fa346a0d97123e06edb3b724322558085bd263817412c0fa3f3556a97c593529c23964dc48843316392768a7e9c58554e3394e7913eb517e0ac2
@@ -20,8 +20,8 @@
20
20
  # limitations under the License.
21
21
 
22
22
  require "mixlib/config" unless defined?(Mixlib::Config)
23
- require "pathname" unless defined?(Pathname)
24
- require "chef-utils" unless defined?(ChefUtils::CANARY)
23
+ autoload :Pathname, "pathname"
24
+ autoload :ChefUtils, "chef-utils"
25
25
 
26
26
  require_relative "fips"
27
27
  require_relative "logger"
@@ -29,12 +29,16 @@ require_relative "windows"
29
29
  require_relative "path_helper"
30
30
  require_relative "mixin/fuzzy_hostname_matcher"
31
31
 
32
- require "mixlib/shellout" unless defined?(Mixlib::ShellOut::DEFAULT_READ_TIMEOUT)
33
- require "uri" unless defined?(URI)
34
- require "addressable/uri" unless defined?(Addressable::URI)
35
- require "openssl" unless defined?(OpenSSL)
36
- require "yaml"
37
- require_relative "dist"
32
+ module Mixlib
33
+ autoload :ShellOut, "mixlib/shellout"
34
+ end
35
+ autoload :URI, "uri"
36
+ module Addressable
37
+ autoload :URI, "addressable/uri"
38
+ end
39
+ autoload :OpenSSL, "openssl"
40
+ autoload :YAML, "yaml"
41
+ require "chef-utils/dist" unless defined?(ChefUtils::Dist)
38
42
 
39
43
  module ChefConfig
40
44
 
@@ -74,42 +78,66 @@ module ChefConfig
74
78
  path
75
79
  end
76
80
 
77
- # On *nix, /etc/chef
78
- def self.etc_chef_dir(is_windows = ChefUtils.windows?)
79
- path = is_windows ? c_chef_dir : PathHelper.join("/etc", ChefConfig::Dist::DIR_SUFFIX)
80
- PathHelper.cleanpath(path)
81
+ # On *nix, /etc/chef, on Windows C:\chef
82
+ #
83
+ # @param windows [Boolean] optional flag to force to windows or unix-style
84
+ # @return [String] the platform-specific path
85
+ #
86
+ def self.etc_chef_dir(windows: ChefUtils.windows?)
87
+ path = windows ? c_chef_dir : PathHelper.join("/etc", ChefUtils::Dist::Infra::DIR_SUFFIX, windows: windows)
88
+ PathHelper.cleanpath(path, windows: windows)
81
89
  end
82
90
 
83
- # On *nix, /var/chef
84
- def self.var_chef_dir(is_windows = ChefUtils.windows?)
85
- path = is_windows ? c_chef_dir : PathHelper.join("/var", ChefConfig::Dist::DIR_SUFFIX)
86
- PathHelper.cleanpath(path)
91
+ # On *nix, /var/chef, on Windows C:\chef
92
+ #
93
+ # @param windows [Boolean] optional flag to force to windows or unix-style
94
+ # @return [String] the platform-specific path
95
+ #
96
+ def self.var_chef_dir(windows: ChefUtils.windows?)
97
+ path = windows ? c_chef_dir : PathHelper.join("/var", ChefUtils::Dist::Infra::DIR_SUFFIX, windows: windows)
98
+ PathHelper.cleanpath(path, windows: windows)
87
99
  end
88
100
 
89
- # On *nix, the root of /var/, used to test if we can create and write in /var/chef
90
- def self.var_root_dir(is_windows = ChefUtils.windows?)
91
- path = is_windows ? c_chef_dir : "/var"
92
- PathHelper.cleanpath(path)
101
+ # On *nix, /var, on Windows C:\
102
+ #
103
+ # @param windows [Boolean] optional flag to force to windows or unix-style
104
+ # @return [String] the platform-specific path
105
+ #
106
+ def self.var_root_dir(windows: ChefUtils.windows?)
107
+ path = windows ? "C:\\" : "/var"
108
+ PathHelper.cleanpath(path, windows: windows)
93
109
  end
94
110
 
95
111
  # On windows, C:/chef/
96
- def self.c_chef_dir
112
+ #
113
+ # (should only be called in a windows-context)
114
+ #
115
+ # @return [String] the platform-specific path
116
+ #
117
+ def self.c_chef_dir(windows: ChefUtils.windows?)
97
118
  drive = windows_installation_drive || "C:"
98
- path = PathHelper.join(drive, ChefConfig::Dist::DIR_SUFFIX)
99
- PathHelper.cleanpath(path)
119
+ PathHelper.join(drive, ChefUtils::Dist::Infra::DIR_SUFFIX, windows: windows)
100
120
  end
101
121
 
102
- def self.c_opscode_dir
122
+ # On windows, C:/opscode
123
+ #
124
+ # (should only be called in a windows-context)
125
+ #
126
+ # @return [String] the platform-specific path
127
+ #
128
+ def self.c_opscode_dir(windows: ChefUtils.windows?)
103
129
  drive = windows_installation_drive || "C:"
104
- path = PathHelper.join(drive, ChefConfig::Dist::LEGACY_CONF_DIR, ChefConfig::Dist::DIR_SUFFIX)
105
- PathHelper.cleanpath(path)
130
+ PathHelper.join(drive, ChefUtils::Dist::Org::LEGACY_CONF_DIR, ChefUtils::Dist::Infra::DIR_SUFFIX, windows: windows)
106
131
  end
107
132
 
108
133
  # the drive where Chef is installed on a windows host. This is determined
109
134
  # either by the drive containing the current file or by the SYSTEMDRIVE ENV
110
135
  # variable
111
136
  #
137
+ # (should only be called in a windows-context)
138
+ #
112
139
  # @return [String] the drive letter
140
+ #
113
141
  def self.windows_installation_drive
114
142
  if ChefUtils.windows?
115
143
  drive = File.expand_path(__FILE__).split("/", 2)[0]
@@ -164,7 +192,7 @@ module ChefConfig
164
192
  if config_file
165
193
  PathHelper.dirname(PathHelper.canonical_path(config_file, false))
166
194
  else
167
- PathHelper.join(PathHelper.cleanpath(user_home), ChefConfig::Dist::USER_CONF_DIR, "")
195
+ PathHelper.join(PathHelper.cleanpath(user_home), ChefUtils::Dist::Infra::USER_CONF_DIR, "")
168
196
  end
169
197
  end
170
198
 
@@ -243,7 +271,7 @@ module ChefConfig
243
271
  end
244
272
  path = new_path
245
273
  end
246
- ChefConfig.logger.info("Auto-discovered #{ChefConfig::Dist::SHORT} repository at #{path}")
274
+ ChefConfig.logger.info("Auto-discovered #{ChefUtils::Dist::Infra::SHORT} repository at #{path}")
247
275
  path
248
276
  end
249
277
 
@@ -341,12 +369,12 @@ module ChefConfig
341
369
  # Otherwise, we'll create .chef under the user's home directory and use that as
342
370
  # the cache path.
343
371
  unless path_accessible?(primary_cache_path) || path_accessible?(primary_cache_root)
344
- secondary_cache_path = PathHelper.join(user_home, ChefConfig::Dist::USER_CONF_DIR)
345
- secondary_cache_path = target_mode? ? "#{secondary_cache_path}/#{target_mode.host}" : secondary_cache_path
372
+ secondary_cache_path = PathHelper.join(user_home, ChefUtils::Dist::Infra::USER_CONF_DIR)
373
+ secondary_cache_path = target_mode? ? PathHelper.join(secondary_cache_path, target_mode.host) : secondary_cache_path
346
374
  ChefConfig.logger.trace("Unable to access cache at #{primary_cache_path}. Switching cache to #{secondary_cache_path}")
347
375
  secondary_cache_path
348
376
  else
349
- target_mode? ? "#{primary_cache_path}/#{target_mode.host}" : primary_cache_path
377
+ target_mode? ? PathHelper.join(primary_cache_path, target_mode.host) : primary_cache_path
350
378
  end
351
379
  end
352
380
  end
@@ -355,7 +383,7 @@ module ChefConfig
355
383
  #
356
384
  # @param path [String]
357
385
  def self.path_accessible?(path)
358
- File.exists?(path) && File.readable?(path) && File.writable?(path)
386
+ File.exist?(path) && File.readable?(path) && File.writable?(path)
359
387
  end
360
388
 
361
389
  # Where cookbook files are stored on the server (by content checksum)
@@ -372,7 +400,7 @@ module ChefConfig
372
400
  # If your `file_cache_path` resides on a NFS (or non-flock()-supporting
373
401
  # fs), it's recommended to set this to something like
374
402
  # '/tmp/chef-client-running.pid'
375
- default(:lockfile) { PathHelper.join(file_cache_path, "#{ChefConfig::Dist::CLIENT}-running.pid") }
403
+ default(:lockfile) { PathHelper.join(file_cache_path, "#{ChefUtils::Dist::Infra::CLIENT}-running.pid") }
376
404
 
377
405
  ## Daemonization Settings ##
378
406
  # What user should Chef run as?
@@ -621,7 +649,7 @@ module ChefConfig
621
649
  # credentials toml files which doesn't allow ruby symbol values
622
650
  configurable(:ssl_verify_mode).writes_value do |value|
623
651
  if value.is_a?(String) && value[0] == ":"
624
- value[1..-1].to_sym
652
+ value[1..].to_sym
625
653
  else
626
654
  value.to_sym
627
655
  end
@@ -769,7 +797,7 @@ module ChefConfig
769
797
  if chef_server_url.to_s =~ %r{/organizations/(.*)$}
770
798
  "#{$1}-validator"
771
799
  else
772
- "#{ChefConfig::Dist::SHORT}-validator"
800
+ "#{ChefUtils::Dist::Infra::SHORT}-validator"
773
801
  end
774
802
  end
775
803
 
@@ -843,7 +871,7 @@ module ChefConfig
843
871
  default :profile, nil
844
872
 
845
873
  default :chef_guid_path do
846
- PathHelper.join(config_dir, "#{ChefConfig::Dist::SHORT}_guid")
874
+ PathHelper.join(config_dir, "#{ChefUtils::Dist::Infra::SHORT}_guid")
847
875
  end
848
876
 
849
877
  default :chef_guid, nil
@@ -1052,7 +1080,7 @@ module ChefConfig
1052
1080
  # generated by the DataCollector when Chef is run in Solo mode. This
1053
1081
  # allows users to associate their Solo nodes with faux organizations
1054
1082
  # without the nodes being connected to an actual Chef Server.
1055
- default :organization, "#{ChefConfig::Dist::SHORT}_solo"
1083
+ default :organization, "#{ChefUtils::Dist::Infra::SHORT}_solo"
1056
1084
  end
1057
1085
 
1058
1086
  configurable(:http_proxy)
@@ -1078,13 +1106,6 @@ module ChefConfig
1078
1106
  export_no_proxy(no_proxy) if key?(:no_proxy) && no_proxy
1079
1107
  end
1080
1108
 
1081
- # Character classes for Addressable
1082
- # See https://www.ietf.org/rfc/rfc3986.txt 3.2.1
1083
- # The user part may not have a : in it
1084
- USER = Addressable::URI::CharacterClasses::UNRESERVED + Addressable::URI::CharacterClasses::SUB_DELIMS
1085
- # The password part may have any valid USERINFO characters
1086
- PASSWORD = USER + "\\:"
1087
-
1088
1109
  # Builds a proxy uri and exports it to the appropriate environment variables. Examples:
1089
1110
  # http://username:password@hostname:port
1090
1111
  # https://username@hostname:port
@@ -1096,15 +1117,22 @@ module ChefConfig
1096
1117
  # pass = password
1097
1118
  # @api private
1098
1119
  def self.export_proxy(scheme, path, user, pass)
1120
+ # Character classes for Addressable
1121
+ # See https://www.ietf.org/rfc/rfc3986.txt 3.2.1
1122
+ # The user part may not have a : in it
1123
+ user_class = Addressable::URI::CharacterClasses::UNRESERVED + Addressable::URI::CharacterClasses::SUB_DELIMS
1124
+ # The password part may have any valid USERINFO characters
1125
+ password_class = user_class + "\\:"
1126
+
1099
1127
  path = "#{scheme}://#{path}" unless path.include?("://")
1100
1128
  # URI.split returns the following parts:
1101
1129
  # [scheme, userinfo, host, port, registry, path, opaque, query, fragment]
1102
1130
  uri = Addressable::URI.encode(path, Addressable::URI)
1103
1131
 
1104
1132
  if user && !user.empty?
1105
- userinfo = Addressable::URI.encode_component(user, USER)
1133
+ userinfo = Addressable::URI.encode_component(user, user_class)
1106
1134
  if pass
1107
- userinfo << ":#{Addressable::URI.encode_component(pass, PASSWORD)}"
1135
+ userinfo << ":#{Addressable::URI.encode_component(pass, password_class)}"
1108
1136
  end
1109
1137
  uri.userinfo = userinfo
1110
1138
  end
@@ -1179,7 +1207,7 @@ module ChefConfig
1179
1207
  # Transform into the form en_ZZ.UTF-8
1180
1208
  guessed_locale.gsub(/UTF-?8$/i, "UTF-8")
1181
1209
  else
1182
- ChefConfig.logger.warn "Please install an English UTF-8 locale for Chef to use, falling back to C locale and disabling UTF-8 support."
1210
+ ChefConfig.logger.warn "Please install an English UTF-8 locale for #{ChefUtils::Dist::Infra::PRODUCT} to use, falling back to C locale and disabling UTF-8 support."
1183
1211
  "C"
1184
1212
  end
1185
1213
  end
@@ -1232,9 +1260,9 @@ module ChefConfig
1232
1260
  # @api private
1233
1261
  def self.enable_fips_mode
1234
1262
  OpenSSL.fips_mode = true
1235
- require "digest"
1236
- require "digest/sha1"
1237
- require "digest/md5"
1263
+ require "digest" unless defined?(Digest)
1264
+ require "digest/sha1" unless defined?(Digest::SHA1)
1265
+ require "digest/md5" unless defined?(Digest::MD5)
1238
1266
  # Remove pre-existing constants if they do exist to reduce the
1239
1267
  # amount of log spam and warnings.
1240
1268
  Digest.send(:remove_const, "SHA1") if Digest.const_defined?("SHA1")
@@ -15,8 +15,9 @@
15
15
  # limitations under the License.
16
16
  #
17
17
 
18
- require "tomlrb"
18
+ autoload :Tomlrb, "tomlrb"
19
19
  require_relative "../path_helper"
20
+ require "chef-utils/dist" unless defined?(ChefUtils::Dist)
20
21
 
21
22
  module ChefConfig
22
23
  module Mixin
@@ -36,7 +37,7 @@ module ChefConfig
36
37
  # normally set via a command-line option.
37
38
  # @return [String]
38
39
  def credentials_profile(profile = nil)
39
- context_file = PathHelper.home(ChefConfig::Dist::USER_CONF_DIR, "context").freeze
40
+ context_file = PathHelper.home(ChefUtils::Dist::Infra::USER_CONF_DIR, "context").freeze
40
41
  if !profile.nil?
41
42
  profile
42
43
  elsif ENV.include?("CHEF_PROFILE")
@@ -53,7 +54,7 @@ module ChefConfig
53
54
  # @since 14.4
54
55
  # @return [String]
55
56
  def credentials_file_path
56
- PathHelper.home(ChefConfig::Dist::USER_CONF_DIR, "credentials").freeze
57
+ PathHelper.home(ChefUtils::Dist::Infra::USER_CONF_DIR, "credentials").freeze
57
58
  end
58
59
 
59
60
  # Load and parse the credentials file.
@@ -84,17 +85,17 @@ module ChefConfig
84
85
  # @return [void]
85
86
  def load_credentials(profile = nil)
86
87
  profile = credentials_profile(profile)
87
- config = parse_credentials_file
88
- return if config.nil? # No credentials, nothing to do here.
88
+ cred_config = parse_credentials_file
89
+ return if cred_config.nil? # No credentials, nothing to do here.
89
90
 
90
- if config[profile].nil?
91
+ if cred_config[profile].nil?
91
92
  # Unknown profile name. For "default" just silently ignore, otherwise
92
93
  # raise an error.
93
94
  return if profile == "default"
94
95
 
95
96
  raise ChefConfig::ConfigurationError, "Profile #{profile} doesn't exist. Please add it to #{credentials_file_path}."
96
97
  end
97
- apply_credentials(config[profile], profile)
98
+ apply_credentials(cred_config[profile], profile)
98
99
  end
99
100
  end
100
101
  end
@@ -0,0 +1,141 @@
1
+ # Author:: Bryan McLellan <btm@loftninjas.org>
2
+ # Copyright:: Copyright (c) Chef Software Inc.
3
+ # License:: Apache License, Version 2.0
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ #
17
+
18
+ require_relative "credentials"
19
+ autoload :Train, "train"
20
+ require_relative "../config"
21
+ require "chef-utils/dist" unless defined?(ChefUtils::Dist)
22
+
23
+ module ChefConfig
24
+ module Mixin
25
+ module TrainTransport
26
+ include ChefConfig::Mixin::Credentials
27
+
28
+ attr_accessor :logger
29
+
30
+ def initialize(logger)
31
+ @logger = logger
32
+ end
33
+
34
+ #
35
+ # Returns a RFC099 credentials profile as a hash
36
+ #
37
+ def load_credentials(profile)
38
+ # Tomlrb.load_file returns a hash with keys as strings
39
+ credentials = parse_credentials_file
40
+ if contains_split_fqdn?(credentials, profile)
41
+ logger.warn("Credentials file #{credentials_file_path} contains target '#{profile}' as a Hash, expected a string.")
42
+ logger.warn("Hostnames must be surrounded by single quotes, e.g. ['host.example.org']")
43
+ end
44
+
45
+ # host names must be specified in credentials file as ['foo.example.org'] with quotes
46
+ if !credentials.nil? && !credentials[profile].nil?
47
+ credentials[profile].transform_keys(&:to_sym) # return symbolized keys to match Train.options()
48
+ else
49
+ nil
50
+ end
51
+ end
52
+
53
+ # Toml creates hashes when a key is separated by periods, e.g.
54
+ # [host.example.org] => { host: { example: { org: {} } } }
55
+ #
56
+ # Returns true if the above example is true
57
+ #
58
+ # A hostname has to be specified as ['host.example.org']
59
+ # This will be a common mistake so we should catch it
60
+ #
61
+ def contains_split_fqdn?(hash, fqdn)
62
+ fqdn.split(".").reduce(hash) do |h, k|
63
+ v = h[k]
64
+ if Hash === v
65
+ v
66
+ else
67
+ break false
68
+ end
69
+ end
70
+ end
71
+
72
+ # ChefConfig::Mixin::Credentials.credentials_file_path is designed around knife,
73
+ # overriding it here.
74
+ #
75
+ # Credentials file preference:
76
+ #
77
+ # 1) target_mode.credentials_file
78
+ # 2) /etc/chef/TARGET_MODE_HOST/credentials
79
+ # 3) #credentials_file_path from parent ($HOME/.chef/credentials)
80
+ #
81
+ def credentials_file_path
82
+ tm_config = config.target_mode
83
+ profile = tm_config.host
84
+
85
+ credentials_file =
86
+ if tm_config.credentials_file && File.exist?(tm_config.credentials_file)
87
+ tm_config.credentials_file
88
+ elsif File.exist?(config.platform_specific_path("#{ChefConfig::Config.etc_chef_dir}/#{profile}/credentials"))
89
+ config.platform_specific_path("#{ChefConfig::Config.etc_chef_dir}/#{profile}/credentials")
90
+ else
91
+ super
92
+ end
93
+
94
+ raise ArgumentError, "No credentials file found for target '#{profile}'" unless credentials_file
95
+ raise ArgumentError, "Credentials file specified for target mode does not exist: '#{credentials_file}'" unless File.exist?(credentials_file)
96
+
97
+ logger.debug("Loading credentials file '#{credentials_file}' for target '#{profile}'")
98
+
99
+ credentials_file
100
+ end
101
+
102
+ def build_transport
103
+ return nil unless config.target_mode?
104
+
105
+ # TODO: Consider supporting parsing the protocol from a URI passed to `--target`
106
+ #
107
+ train_config = {}
108
+
109
+ # Load the target_mode config context from config, and place any valid settings into the train configuration
110
+ tm_config = config.target_mode
111
+ protocol = tm_config.protocol
112
+ train_config = tm_config.to_hash.select { |k| Train.options(protocol).key?(k) }
113
+ logger.trace("Using target mode options from #{ChefUtils::Dist::Infra::PRODUCT} config file: #{train_config.keys.join(", ")}") if train_config
114
+
115
+ # Load the credentials file, and place any valid settings into the train configuration
116
+ credentials = load_credentials(tm_config.host)
117
+ if credentials
118
+ valid_settings = credentials.select { |k| Train.options(protocol).key?(k) }
119
+ valid_settings[:enable_password] = credentials[:enable_password] if credentials.key?(:enable_password)
120
+ train_config.merge!(valid_settings)
121
+ logger.trace("Using target mode options from credentials file: #{valid_settings.keys.join(", ")}") if valid_settings
122
+ end
123
+
124
+ train_config[:logger] = logger
125
+
126
+ # Train handles connection retries for us
127
+ Train.create(protocol, train_config)
128
+ rescue SocketError => e # likely a dns failure, not caught by train
129
+ e.message.replace "Error connecting to #{train_config[:target]} - #{e.message}"
130
+ raise e
131
+ rescue Train::PluginLoadError
132
+ logger.error("Invalid target mode protocol: #{protocol}")
133
+ exit(1)
134
+ end
135
+
136
+ def config
137
+ raise NotImplementedError
138
+ end
139
+ end
140
+ end
141
+ end
@@ -26,14 +26,14 @@ module ChefConfig
26
26
  # Maximum characters in a standard Windows path (260 including drive letter and NUL)
27
27
  WIN_MAX_PATH = 259
28
28
 
29
- def self.dirname(path)
30
- if ChefUtils.windows?
29
+ def self.dirname(path, windows: ChefUtils.windows?)
30
+ if windows
31
31
  # Find the first slash, not counting trailing slashes
32
32
  end_slash = path.size
33
33
  loop do
34
- slash = path.rindex(/[#{Regexp.escape(File::SEPARATOR)}#{Regexp.escape(path_separator)}]/, end_slash - 1)
34
+ slash = path.rindex(/[#{Regexp.escape(File::SEPARATOR)}#{Regexp.escape(path_separator(windows: windows))}]/, end_slash - 1)
35
35
  if !slash
36
- return end_slash == path.size ? "." : path_separator
36
+ return end_slash == path.size ? "." : path_separator(windows: windows)
37
37
  elsif slash == end_slash - 1
38
38
  end_slash = slash
39
39
  else
@@ -47,29 +47,28 @@ module ChefConfig
47
47
 
48
48
  BACKSLASH = '\\'.freeze
49
49
 
50
- def self.path_separator
51
- if ChefUtils.windows?
52
- File::ALT_SEPARATOR || BACKSLASH
50
+ def self.path_separator(windows: ChefUtils.windows?)
51
+ if windows
52
+ BACKSLASH
53
53
  else
54
54
  File::SEPARATOR
55
55
  end
56
56
  end
57
57
 
58
- path_separator_regex = [Regexp.escape(File::SEPARATOR), Regexp.escape(path_separator)].uniq.join
58
+ def self.join(*args, windows: ChefUtils.windows?)
59
+ path_separator_regex = Regexp.escape(windows ? "#{File::SEPARATOR}#{BACKSLASH}" : File::SEPARATOR)
60
+ trailing_slashes_regex = /[#{path_separator_regex}]+$/.freeze
61
+ leading_slashes_regex = /^[#{path_separator_regex}]+/.freeze
59
62
 
60
- TRAILING_SLASHES_REGEX = /[#{path_separator_regex}]+$/.freeze
61
- LEADING_SLASHES_REGEX = /^[#{path_separator_regex}]+/.freeze
62
-
63
- def self.join(*args)
64
63
  args.flatten.inject do |joined_path, component|
65
- joined_path = joined_path.sub(TRAILING_SLASHES_REGEX, "")
66
- component = component.sub(LEADING_SLASHES_REGEX, "")
67
- joined_path + "#{path_separator}#{component}"
64
+ joined_path = joined_path.sub(trailing_slashes_regex, "")
65
+ component = component.sub(leading_slashes_regex, "")
66
+ joined_path + "#{path_separator(windows: windows)}#{component}"
68
67
  end
69
68
  end
70
69
 
71
- def self.validate_path(path)
72
- if ChefUtils.windows?
70
+ def self.validate_path(path, windows: ChefUtils.windows?)
71
+ if windows
73
72
  unless printable?(path)
74
73
  msg = "Path '#{path}' contains non-printable characters. Check that backslashes are escaped with another backslash (e.g. C:\\\\Windows) in double-quoted strings."
75
74
  ChefConfig.logger.error(msg)
@@ -108,14 +107,14 @@ module ChefConfig
108
107
  end
109
108
 
110
109
  # Produces a comparable path.
111
- def self.canonical_path(path, add_prefix = true)
110
+ def self.canonical_path(path, add_prefix = true, windows: ChefUtils.windows?)
112
111
  # First remove extra separators and resolve any relative paths
113
112
  abs_path = File.absolute_path(path)
114
113
 
115
- if ChefUtils.windows?
114
+ if windows
116
115
  # Add the \\?\ API prefix on Windows unless add_prefix is false
117
116
  # Downcase on Windows where paths are still case-insensitive
118
- abs_path.gsub!(::File::SEPARATOR, path_separator)
117
+ abs_path.gsub!(::File::SEPARATOR, path_separator(windows: windows))
119
118
  if add_prefix && abs_path !~ /^\\\\?\\/
120
119
  abs_path.insert(0, "\\\\?\\")
121
120
  end
@@ -126,36 +125,67 @@ module ChefConfig
126
125
  abs_path
127
126
  end
128
127
 
129
- # This is the INVERSE of Pathname#cleanpath, it converts forward
130
- # slashes to backslashes for Windows. Since the Ruby API and the
131
- # Windows APIs all consume forward slashes, this helper function
132
- # should only be used for *DISPLAY* logic to send strings back
133
- # to the user with backslashes. Internally, filename paths should
134
- # generally be stored with forward slashes for consistency. It is
135
- # not necessary or desired to blindly convert pathnames to have
136
- # backslashes on Windows.
128
+ # The built in ruby Pathname#cleanpath method does not clean up forward slashes and
129
+ # backslashes. This is a wrapper around that which does. In general this is NOT
130
+ # recommended for internal use within ruby/chef since ruby does not care about forward slashes
131
+ # vs. backslashes, even on Windows. Where this generally matters is when being rendered
132
+ # to the user, or being rendered into things like the windows PATH or to commands that
133
+ # are being executed. In some cases it may be easier on windows to render paths to
134
+ # unix-style for being eventually eval'd by ruby in the future (templates being rendered
135
+ # with code to be consumed by ruby) where forcing unix-style forward slashes avoids the
136
+ # issue of needing to escape the backslashes in rendered strings. This has a boolean
137
+ # operator to force windows-style or non-windows style operation, where the default is
138
+ # determined by the underlying node['platform'] value.
139
+ #
140
+ # In general if you don't know if you need this routine, do not use it, best practice
141
+ # within chef/ruby itself is not to care. Only use it to force windows or unix style
142
+ # when it really matters.
137
143
  #
138
- # Generally, if the user isn't going to be seeing it, you should be
139
- # using Pathname#cleanpath instead of this function.
140
- def self.cleanpath(path)
144
+ # @param path [String] the path to clean
145
+ # @param windows [Boolean] optional flag to force to windows or unix-style
146
+ # @return [String] cleaned path
147
+ #
148
+ def self.cleanpath(path, windows: ChefUtils.windows?)
141
149
  path = Pathname.new(path).cleanpath.to_s
142
- # ensure all forward slashes are backslashes
143
- if ChefUtils.windows?
144
- path = path.gsub(File::SEPARATOR, path_separator)
150
+ if windows
151
+ # ensure all forward slashes are backslashes
152
+ path.gsub(File::SEPARATOR, path_separator(windows: windows))
153
+ else
154
+ # ensure all backslashes are forward slashes
155
+ path.gsub(BACKSLASH, File::SEPARATOR)
145
156
  end
146
- path
147
157
  end
148
158
 
149
- def self.paths_eql?(path1, path2)
150
- canonical_path(path1) == canonical_path(path2)
159
+ # This is not just escaping for something like use in Regexps, or in globs. For the former
160
+ # just use Regexp.escape. For the latter, use escape_glob_dir below.
161
+ #
162
+ # This is escaping where the path to be rendered is being put into a ruby file which will
163
+ # later be read back by ruby (or something similar) so we need quadruple backslashes.
164
+ #
165
+ # In order to print:
166
+ #
167
+ # file_cache_path "C:\\chef"
168
+ #
169
+ # We need to convert "C:\chef" to "C:\\\\chef" to interpolate into a string which is rendered
170
+ # into the output file with that line in it.
171
+ #
172
+ # @param path [String] the path to escape
173
+ # @return [String] the escaped path
174
+ #
175
+ def self.escapepath(path)
176
+ path.gsub(BACKSLASH, BACKSLASH * 4)
177
+ end
178
+
179
+ def self.paths_eql?(path1, path2, windows: ChefUtils.windows?)
180
+ canonical_path(path1, windows: windows) == canonical_path(path2, windows: windows)
151
181
  end
152
182
 
153
183
  # @deprecated this method is deprecated. Please use escape_glob_dirs
154
184
  # Paths which may contain glob-reserved characters need
155
185
  # to be escaped before globbing can be done.
156
186
  # http://stackoverflow.com/questions/14127343
157
- def self.escape_glob(*parts)
158
- path = cleanpath(join(*parts))
187
+ def self.escape_glob(*parts, windows: ChefUtils.windows?)
188
+ path = cleanpath(join(*parts, windows: windows), windows: windows)
159
189
  path.gsub(/[\\\{\}\[\]\*\?]/) { |x| "\\" + x }
160
190
  end
161
191
 
@@ -166,8 +196,8 @@ module ChefConfig
166
196
  path.gsub(/[\\\{\}\[\]\*\?]/) { |x| "\\" + x }
167
197
  end
168
198
 
169
- def self.relative_path_from(from, to)
170
- Pathname.new(cleanpath(to)).relative_path_from(Pathname.new(cleanpath(from)))
199
+ def self.relative_path_from(from, to, windows: ChefUtils.windows?)
200
+ Pathname.new(cleanpath(to, windows: windows)).relative_path_from(Pathname.new(cleanpath(from, windows: windows)))
171
201
  end
172
202
 
173
203
  # Set the project-specific home directory environment variable.
@@ -213,11 +243,11 @@ module ChefConfig
213
243
  #
214
244
  # The return is a list of all the returned values from each block invocation or a list of paths
215
245
  # if no block is provided.
216
- def self.all_homes(*args)
246
+ def self.all_homes(*args, windows: ChefUtils.windows?)
217
247
  paths = []
218
248
  paths << ENV[@@per_tool_home_environment] if defined?(@@per_tool_home_environment) && @@per_tool_home_environment && ENV[@@per_tool_home_environment]
219
249
  paths << ENV["CHEF_HOME"] if ENV["CHEF_HOME"]
220
- if ChefUtils.windows?
250
+ if windows
221
251
  # By default, Ruby uses the the following environment variables to determine Dir.home:
222
252
  # HOME
223
253
  # HOMEDRIVE HOMEPATH
@@ -246,7 +276,7 @@ module ChefConfig
246
276
  # Note: Maybe this is a bad idea on some unixy systems where \ might be a valid character depending on
247
277
  # the particular brand of kool-aid you consume. This code assumes that \ and / are both
248
278
  # path separators on any system being used.
249
- paths = paths.map { |home_path| home_path.gsub(path_separator, ::File::SEPARATOR) if home_path }
279
+ paths = paths.map { |home_path| home_path.gsub(path_separator(windows: windows), ::File::SEPARATOR) if home_path }
250
280
 
251
281
  # Filter out duplicate paths and paths that don't exist.
252
282
  valid_paths = paths.select { |home_path| home_path && Dir.exist?(home_path.force_encoding("utf-8")) }
@@ -15,5 +15,5 @@
15
15
 
16
16
  module ChefConfig
17
17
  CHEFCONFIG_ROOT = File.expand_path("..", __dir__)
18
- VERSION = "16.3.45".freeze
18
+ VERSION = "16.5.77".freeze
19
19
  end
@@ -59,7 +59,7 @@ module ChefConfig
59
59
  @chef_config_dir = false
60
60
  full_path = working_directory.split(File::SEPARATOR)
61
61
  (full_path.length - 1).downto(0) do |i|
62
- candidate_directory = File.join(full_path[0..i] + [ChefConfig::Dist::USER_CONF_DIR])
62
+ candidate_directory = File.join(full_path[0..i] + [ChefUtils::Dist::Infra::USER_CONF_DIR])
63
63
  if File.exist?(candidate_directory) && File.directory?(candidate_directory)
64
64
  @chef_config_dir = candidate_directory
65
65
  break
@@ -129,7 +129,7 @@ module ChefConfig
129
129
  candidate_configs << File.join(chef_config_dir, "knife.rb")
130
130
  end
131
131
  # Look for $HOME/.chef/knife.rb
132
- PathHelper.home(ChefConfig::Dist::USER_CONF_DIR) do |dot_chef_dir|
132
+ PathHelper.home(ChefUtils::Dist::Infra::USER_CONF_DIR) do |dot_chef_dir|
133
133
  candidate_configs << File.join(dot_chef_dir, "config.rb")
134
134
  candidate_configs << File.join(dot_chef_dir, "knife.rb")
135
135
  end
@@ -140,13 +140,11 @@ module ChefConfig
140
140
  end
141
141
 
142
142
  def working_directory
143
- a = if ChefUtils.windows?
144
- env["CD"]
145
- else
146
- env["PWD"]
147
- end || Dir.pwd
148
-
149
- a
143
+ if ChefUtils.windows?
144
+ env["CD"]
145
+ else
146
+ env["PWD"]
147
+ end || Dir.pwd
150
148
  end
151
149
 
152
150
  def apply_credentials(creds, profile)
@@ -168,7 +166,7 @@ module ChefConfig
168
166
  when "client_key"
169
167
  extract_key(value, :client_key, :client_key_contents)
170
168
  when "knife"
171
- Config.knife.merge!(Hash[value.map { |k, v| [k.to_sym, v] }])
169
+ Config.knife.merge!(value.transform_keys(&:to_sym))
172
170
  else
173
171
  Config[key.to_sym] = value
174
172
  end
@@ -186,7 +184,7 @@ module ChefConfig
186
184
  end
187
185
 
188
186
  def home_chef_dir
189
- @home_chef_dir ||= PathHelper.home(ChefConfig::Dist::USER_CONF_DIR)
187
+ @home_chef_dir ||= PathHelper.home(ChefUtils::Dist::Infra::USER_CONF_DIR)
190
188
  end
191
189
 
192
190
  def apply_config(config_content, config_file_path)
@@ -170,7 +170,7 @@ RSpec.describe ChefConfig::Config do
170
170
  apply_config
171
171
  expect(described_class[:data_bag_path]).to eq("#{current_directory}/data_bags")
172
172
  expect(described_class[:cookbook_path]).to eq("#{current_directory}/cookbooks")
173
- expect(described_class[:chef_repo_path]).to eq("#{current_directory}")
173
+ expect(described_class[:chef_repo_path]).to eq(current_directory)
174
174
  end
175
175
  end
176
176
 
@@ -222,13 +222,70 @@ RSpec.describe ChefConfig::Config do
222
222
  ChefConfig::Config.add_formatter(:doc, "/var/log/formatter.log")
223
223
  expect(ChefConfig::Config.formatters).to eq([[:doc, "/var/log/formatter.log"]])
224
224
  end
225
+ end
226
+
227
+ describe "#var_chef_path" do
228
+ let (:dirname) { ChefUtils::Dist::Infra::DIR_SUFFIX }
229
+
230
+ context "on unix", :unix_only do
231
+ it "var_chef_dir is /var/chef" do
232
+ expect(ChefConfig::Config.var_chef_dir).to eql("/var/#{dirname}")
233
+ end
234
+
235
+ it "var_root_dir is /var" do
236
+ expect(ChefConfig::Config.var_root_dir).to eql("/var")
237
+ end
238
+
239
+ it "etc_chef_dir is /etc/chef" do
240
+ expect(ChefConfig::Config.etc_chef_dir).to eql("/etc/#{dirname}")
241
+ end
242
+ end
243
+
244
+ context "on windows", :windows_only do
245
+ it "var_chef_dir is C:\\chef" do
246
+ expect(ChefConfig::Config.var_chef_dir).to eql("C:\\#{dirname}")
247
+ end
248
+
249
+ it "var_root_dir is C:\\" do
250
+ expect(ChefConfig::Config.var_root_dir).to eql("C:\\")
251
+ end
252
+
253
+ it "etc_chef_dir is C:\\chef" do
254
+ expect(ChefConfig::Config.etc_chef_dir).to eql("C:\\#{dirname}")
255
+ end
256
+ end
225
257
 
258
+ context "when forced to unix" do
259
+ it "var_chef_dir is /var/chef" do
260
+ expect(ChefConfig::Config.var_chef_dir(windows: false)).to eql("/var/#{dirname}")
261
+ end
262
+
263
+ it "var_root_dir is /var" do
264
+ expect(ChefConfig::Config.var_root_dir(windows: false)).to eql("/var")
265
+ end
266
+
267
+ it "etc_chef_dir is /etc/chef" do
268
+ expect(ChefConfig::Config.etc_chef_dir(windows: false)).to eql("/etc/#{dirname}")
269
+ end
270
+ end
271
+
272
+ context "when forced to windows" do
273
+ it "var_chef_dir is C:\\chef" do
274
+ expect(ChefConfig::Config.var_chef_dir(windows: true)).to eql("C:\\#{dirname}")
275
+ end
276
+
277
+ it "var_root_dir is C:\\" do
278
+ expect(ChefConfig::Config.var_root_dir(windows: true)).to eql("C:\\")
279
+ end
280
+
281
+ it "etc_chef_dir is C:\\chef" do
282
+ expect(ChefConfig::Config.etc_chef_dir(windows: true)).to eql("C:\\#{dirname}")
283
+ end
284
+ end
226
285
  end
227
286
 
228
287
  [ false, true ].each do |is_windows|
229
-
230
288
  context "On #{is_windows ? "Windows" : "Unix"}" do
231
-
232
289
  before :each do
233
290
  allow(ChefUtils).to receive(:windows?).and_return(is_windows)
234
291
  end
@@ -430,8 +487,8 @@ RSpec.describe ChefConfig::Config do
430
487
 
431
488
  describe "ChefConfig::Config[:cache_path]" do
432
489
  let(:target_mode_host) { "fluffy.kittens.org" }
433
- let(:target_mode_primary_cache_path) { "#{primary_cache_path}/#{target_mode_host}" }
434
- let(:target_mode_secondary_cache_path) { "#{secondary_cache_path}/#{target_mode_host}" }
490
+ let(:target_mode_primary_cache_path) { ChefUtils.windows? ? "#{primary_cache_path}\\#{target_mode_host}" : "#{primary_cache_path}/#{target_mode_host}" }
491
+ let(:target_mode_secondary_cache_path) { ChefUtils.windows? ? "#{secondary_cache_path}\\#{target_mode_host}" : "#{secondary_cache_path}/#{target_mode_host}" }
435
492
 
436
493
  before do
437
494
  if is_windows
@@ -874,7 +931,7 @@ RSpec.describe ChefConfig::Config do
874
931
 
875
932
  shared_examples_for "a suitable locale" do
876
933
  it "returns an English UTF-8 locale" do
877
- expect(ChefConfig.logger).to_not receive(:warn).with(/Please install an English UTF-8 locale for Chef to use/)
934
+ expect(ChefConfig.logger).to_not receive(:warn).with(/Please install an English UTF-8 locale for Chef Infra Client to use/)
878
935
  expect(ChefConfig.logger).to_not receive(:trace).with(/Defaulting to locale en_US.UTF-8 on Windows/)
879
936
  expect(ChefConfig.logger).to_not receive(:trace).with(/No usable locale -a command found/)
880
937
  expect(ChefConfig::Config.guess_internal_locale).to eq expected_locale
@@ -927,7 +984,7 @@ RSpec.describe ChefConfig::Config do
927
984
  let(:locale_array) { ["af_ZA", "af_ZA.ISO8859-1", "af_ZA.ISO8859-15", "af_ZA.UTF-8"] }
928
985
 
929
986
  it "should fall back to C locale" do
930
- expect(ChefConfig.logger).to receive(:warn).with("Please install an English UTF-8 locale for Chef to use, falling back to C locale and disabling UTF-8 support.")
987
+ expect(ChefConfig.logger).to receive(:warn).with("Please install an English UTF-8 locale for Chef Infra Client to use, falling back to C locale and disabling UTF-8 support.")
931
988
  expect(ChefConfig::Config.guess_internal_locale).to eq "C"
932
989
  end
933
990
  end
@@ -20,7 +20,7 @@ require "chef-config/fips"
20
20
  require "spec_helper"
21
21
 
22
22
  begin
23
- require "win32/registry"
23
+ require "win32/registry" unless defined?(Win32::Registry)
24
24
  rescue LoadError
25
25
  # not on unix
26
26
  end
@@ -23,9 +23,8 @@ RSpec.describe ChefConfig::PathHelper do
23
23
 
24
24
  let(:path_helper) { described_class }
25
25
 
26
- shared_examples_for "common_functionality" do
27
- describe "join" do
28
-
26
+ context "common functionality" do
27
+ context "join" do
29
28
  it "joins starting with '' resolve to absolute paths" do
30
29
  expect(path_helper.join("", "a", "b")).to eq("#{path_helper.path_separator}a#{path_helper.path_separator}b")
31
30
  end
@@ -33,10 +32,9 @@ RSpec.describe ChefConfig::PathHelper do
33
32
  it "joins ending with '' add a / to the end" do
34
33
  expect(path_helper.join("a", "b", "")).to eq("a#{path_helper.path_separator}b#{path_helper.path_separator}")
35
34
  end
36
-
37
35
  end
38
36
 
39
- describe "dirname" do
37
+ context "dirname" do
40
38
  it "dirname('abc') is '.'" do
41
39
  expect(path_helper.dirname("abc")).to eq(".")
42
40
  end
@@ -55,42 +53,109 @@ RSpec.describe ChefConfig::PathHelper do
55
53
  end
56
54
  end
57
55
 
56
+ context "forcing windows/non-windows" do
57
+ context "forcing windows" do
58
+ it "path_separator is \\" do
59
+ expect(path_helper.path_separator(windows: true)).to eq('\\')
60
+ end
61
+
62
+ context "platform-specific #join behavior" do
63
+ it "joins components on Windows when some end with unix separators" do
64
+ expected = "C:\\foo\\bar\\baz"
65
+ expect(path_helper.join('C:\\foo/', "bar", "baz", windows: true)).to eq(expected)
66
+ end
67
+
68
+ it "joins components when some end with separators" do
69
+ expected = "C:\\foo\\bar\\baz"
70
+ expect(path_helper.join('C:\\foo\\', "bar", "baz", windows: true)).to eq(expected)
71
+ end
72
+
73
+ it "joins components when some end and start with separators" do
74
+ expected = "C:\\foo\\bar\\baz"
75
+ expect(path_helper.join('C:\\foo\\', "bar/", "/baz", windows: true)).to eq(expected)
76
+ end
77
+
78
+ it "joins components that don't end in separators" do
79
+ expected = "C:\\foo\\bar\\baz"
80
+ expect(path_helper.join('C:\\foo', "bar", "baz", windows: true)).to eq(expected)
81
+ end
82
+ end
83
+
84
+ it "cleanpath changes slashes into backslashes and leaves backslashes alone" do
85
+ expect(path_helper.cleanpath('/a/b\\c/d/', windows: true)).to eq('\\a\\b\\c\\d')
86
+ end
87
+
88
+ it "cleanpath does not remove leading double backslash" do
89
+ expect(path_helper.cleanpath('\\\\a/b\\c/d/', windows: true)).to eq('\\\\a\\b\\c\\d')
90
+ end
91
+ end
92
+
93
+ context "forcing unix" do
94
+ it "path_separator is /" do
95
+ expect(path_helper.path_separator(windows: false)).to eq("/")
96
+ end
97
+
98
+ it "cleanpath removes extra slashes alone" do
99
+ expect(path_helper.cleanpath("/a///b/c/d/", windows: false)).to eq("/a/b/c/d")
100
+ end
101
+
102
+ context "platform-specific #join behavior" do
103
+ it "joins components when some end with separators" do
104
+ expected = "/foo/bar/baz"
105
+ expect(path_helper.join("/foo/", "bar", "baz", windows: false)).to eq(expected)
106
+ end
107
+
108
+ it "joins components when some end and start with separators" do
109
+ expected = "/foo/bar/baz"
110
+ expect(path_helper.join("/foo/", "bar/", "/baz", windows: false)).to eq(expected)
111
+ end
112
+
113
+ it "joins components that don't end in separators" do
114
+ expected = "/foo/bar/baz"
115
+ expect(path_helper.join("/foo", "bar", "baz", windows: false)).to eq(expected)
116
+ end
117
+ end
118
+
119
+ it "cleanpath changes backslashes into slashes and leaves slashes alone" do
120
+ expect(path_helper.cleanpath('/a/b\\c/d/', windows: false)).to eq("/a/b/c/d")
121
+ end
122
+
123
+ it "cleanpath does not remove leading double backslash" do
124
+ expect(path_helper.cleanpath('\\\\a/b\\c/d/', windows: false)).to eq("//a/b/c/d")
125
+ end
126
+ end
127
+ end
128
+
58
129
  context "on windows", :windows_only do
59
130
 
60
131
  before(:each) do
61
132
  allow(ChefUtils).to receive(:windows?).and_return(true)
62
133
  end
63
134
 
64
- include_examples("common_functionality")
65
-
66
135
  it "path_separator is \\" do
67
136
  expect(path_helper.path_separator).to eq('\\')
68
137
  end
69
138
 
70
- describe "platform-specific #join behavior" do
71
-
139
+ context "platform-specific #join behavior" do
72
140
  it "joins components on Windows when some end with unix separators" do
73
- expect(path_helper.join('C:\\foo/', "bar", "baz")).to eq('C:\\foo\\bar\\baz')
141
+ expected = "C:\\foo\\bar\\baz"
142
+ expect(path_helper.join('C:\\foo/', "bar", "baz")).to eq(expected)
74
143
  end
75
144
 
76
145
  it "joins components when some end with separators" do
77
- expected = path_helper.cleanpath("/foo/bar/baz")
78
- expected = "C:#{expected}"
146
+ expected = "C:\\foo\\bar\\baz"
79
147
  expect(path_helper.join('C:\\foo\\', "bar", "baz")).to eq(expected)
80
148
  end
81
149
 
82
150
  it "joins components when some end and start with separators" do
83
- expected = path_helper.cleanpath("/foo/bar/baz")
84
- expected = "C:#{expected}"
151
+ expected = "C:\\foo\\bar\\baz"
85
152
  expect(path_helper.join('C:\\foo\\', "bar/", "/baz")).to eq(expected)
86
153
  end
87
154
 
88
155
  it "joins components that don't end in separators" do
89
- expected = path_helper.cleanpath("/foo/bar/baz")
90
- expected = "C:#{expected}"
156
+ expected = "C:\\foo\\bar\\baz"
91
157
  expect(path_helper.join('C:\\foo', "bar", "baz")).to eq(expected)
92
158
  end
93
-
94
159
  end
95
160
 
96
161
  it "cleanpath changes slashes into backslashes and leaves backslashes alone" do
@@ -100,17 +165,13 @@ RSpec.describe ChefConfig::PathHelper do
100
165
  it "cleanpath does not remove leading double backslash" do
101
166
  expect(path_helper.cleanpath('\\\\a/b\\c/d/')).to eq('\\\\a\\b\\c\\d')
102
167
  end
103
-
104
168
  end
105
169
 
106
170
  context "on unix", :unix_only do
107
-
108
171
  before(:each) do
109
172
  allow(ChefUtils).to receive(:windows?).and_return(false)
110
173
  end
111
174
 
112
- include_examples("common_functionality")
113
-
114
175
  it "path_separator is /" do
115
176
  expect(path_helper.path_separator).to eq("/")
116
177
  end
@@ -119,8 +180,7 @@ RSpec.describe ChefConfig::PathHelper do
119
180
  expect(path_helper.cleanpath("/a///b/c/d/")).to eq("/a/b/c/d")
120
181
  end
121
182
 
122
- describe "platform-specific #join behavior" do
123
-
183
+ context "platform-specific #join behavior" do
124
184
  it "joins components when some end with separators" do
125
185
  expected = path_helper.cleanpath("/foo/bar/baz")
126
186
  expect(path_helper.join("/foo/", "bar", "baz")).to eq(expected)
@@ -135,12 +195,19 @@ RSpec.describe ChefConfig::PathHelper do
135
195
  expected = path_helper.cleanpath("/foo/bar/baz")
136
196
  expect(path_helper.join("/foo", "bar", "baz")).to eq(expected)
137
197
  end
198
+ end
138
199
 
200
+ it "cleanpath changes backslashes into slashes and leaves slashes alone" do
201
+ expect(path_helper.cleanpath('/a/b\\c/d/', windows: false)).to eq("/a/b/c/d")
139
202
  end
140
203
 
204
+ # NOTE: this seems a bit weird to me, but this is just the way Pathname#cleanpath works
205
+ it "cleanpath does not remove leading double backslash" do
206
+ expect(path_helper.cleanpath('\\\\a/b\\c/d/')).to eq("//a/b/c/d")
207
+ end
141
208
  end
142
209
 
143
- describe "validate_path" do
210
+ context "validate_path" do
144
211
  context "on windows" do
145
212
  before(:each) do
146
213
  # pass by default
@@ -171,7 +238,7 @@ RSpec.describe ChefConfig::PathHelper do
171
238
  end
172
239
  end
173
240
 
174
- describe "windows_max_length_exceeded?" do
241
+ context "windows_max_length_exceeded?" do
175
242
  it "returns true if the path is too long (259 + NUL) for the API" do
176
243
  expect(path_helper.windows_max_length_exceeded?("C:\\" + "a" * 250 + "\\" + "b" * 6)).to be_truthy
177
244
  end
@@ -185,7 +252,7 @@ RSpec.describe ChefConfig::PathHelper do
185
252
  end
186
253
  end
187
254
 
188
- describe "printable?" do
255
+ context "printable?" do
189
256
  it "returns true if the string contains no non-printable characters" do
190
257
  expect(path_helper.printable?("C:\\Program Files (x86)\\Microsoft Office\\Files.lst")).to be_truthy
191
258
  end
@@ -208,7 +275,7 @@ RSpec.describe ChefConfig::PathHelper do
208
275
  end
209
276
  end
210
277
 
211
- describe "canonical_path" do
278
+ context "canonical_path" do
212
279
  context "on windows", :windows_only do
213
280
  it "returns an absolute path with backslashes instead of slashes" do
214
281
  expect(path_helper.canonical_path("\\\\?\\C:/windows/win.ini")).to eq("\\\\?\\c:\\windows\\win.ini")
@@ -230,25 +297,25 @@ RSpec.describe ChefConfig::PathHelper do
230
297
  end
231
298
  end
232
299
 
233
- describe "paths_eql?" do
300
+ context "paths_eql?" do
234
301
  it "returns true if the paths are the same" do
235
- allow(path_helper).to receive(:canonical_path).with("bandit").and_return("c:/bandit/bandit")
236
- allow(path_helper).to receive(:canonical_path).with("../bandit/bandit").and_return("c:/bandit/bandit")
302
+ allow(path_helper).to receive(:canonical_path).with("bandit", windows: ChefUtils.windows?).and_return("c:/bandit/bandit")
303
+ allow(path_helper).to receive(:canonical_path).with("../bandit/bandit", windows: ChefUtils.windows?).and_return("c:/bandit/bandit")
237
304
  expect(path_helper.paths_eql?("bandit", "../bandit/bandit")).to be_truthy
238
305
  end
239
306
 
240
307
  it "returns false if the paths are different" do
241
- allow(path_helper).to receive(:canonical_path).with("bandit").and_return("c:/Bo/Bandit")
242
- allow(path_helper).to receive(:canonical_path).with("../bandit/bandit").and_return("c:/bandit/bandit")
308
+ allow(path_helper).to receive(:canonical_path).with("bandit", windows: ChefUtils.windows?).and_return("c:/Bo/Bandit")
309
+ allow(path_helper).to receive(:canonical_path).with("../bandit/bandit", windows: ChefUtils.windows?).and_return("c:/bandit/bandit")
243
310
  expect(path_helper.paths_eql?("bandit", "../bandit/bandit")).to be_falsey
244
311
  end
245
312
  end
246
313
 
247
- describe "escape_glob" do
314
+ context "escape_glob" do
248
315
  it "escapes characters reserved by glob" do
249
316
  path = "C:\\this\\*path\\[needs]\\escaping?"
250
317
  escaped_path = "C:\\\\this\\\\\\*path\\\\\\[needs\\]\\\\escaping\\?"
251
- expect(path_helper.escape_glob(path)).to eq(escaped_path)
318
+ expect(path_helper.escape_glob(path, windows: true)).to eq(escaped_path)
252
319
  end
253
320
 
254
321
  context "when given more than one argument" do
@@ -259,14 +326,12 @@ RSpec.describe ChefConfig::PathHelper do
259
326
  else
260
327
  "this/\\*path/\\[needs\\]/escaping\\?"
261
328
  end
262
- expect(path_helper).to receive(:join).with(*args).and_call_original
263
- expect(path_helper).to receive(:cleanpath).and_call_original
264
329
  expect(path_helper.escape_glob(*args)).to eq(escaped_path)
265
330
  end
266
331
  end
267
332
  end
268
333
 
269
- describe "escape_glob_dir" do
334
+ context "escape_glob_dir" do
270
335
  it "escapes characters reserved by glob without using backslashes for path separators" do
271
336
  path = "C:/this/*path/[needs]/escaping?"
272
337
  escaped_path = "C:/this/\\*path/\\[needs\\]/escaping\\?"
@@ -283,7 +348,7 @@ RSpec.describe ChefConfig::PathHelper do
283
348
  end
284
349
  end
285
350
 
286
- describe "all_homes" do
351
+ context "all_homes" do
287
352
  before do
288
353
  stub_const("ENV", env)
289
354
  allow(ChefUtils).to receive(:windows?).and_return(is_windows)
@@ -17,7 +17,7 @@
17
17
  #
18
18
 
19
19
  require "spec_helper"
20
- require "tempfile"
20
+ require "tempfile" unless defined?(Tempfile)
21
21
 
22
22
  require "chef-config/exceptions"
23
23
  require "chef-utils"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: chef-config
3
3
  version: !ruby/object:Gem::Version
4
- version: 16.3.45
4
+ version: 16.5.77
5
5
  platform: ruby
6
6
  authors:
7
7
  - Adam Jacob
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-07-29 00:00:00.000000000 Z
11
+ date: 2020-09-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: chef-utils
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - '='
18
18
  - !ruby/object:Gem::Version
19
- version: 16.3.45
19
+ version: 16.5.77
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - '='
25
25
  - !ruby/object:Gem::Version
26
- version: 16.3.45
26
+ version: 16.5.77
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: mixlib-shellout
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -174,13 +174,13 @@ files:
174
174
  - chef-config.gemspec
175
175
  - lib/chef-config.rb
176
176
  - lib/chef-config/config.rb
177
- - lib/chef-config/dist.rb
178
177
  - lib/chef-config/exceptions.rb
179
178
  - lib/chef-config/fips.rb
180
179
  - lib/chef-config/logger.rb
181
180
  - lib/chef-config/mixin/credentials.rb
182
181
  - lib/chef-config/mixin/dot_d.rb
183
182
  - lib/chef-config/mixin/fuzzy_hostname_matcher.rb
183
+ - lib/chef-config/mixin/train_transport.rb
184
184
  - lib/chef-config/path_helper.rb
185
185
  - lib/chef-config/version.rb
186
186
  - lib/chef-config/windows.rb
@@ -1,26 +0,0 @@
1
- module ChefConfig
2
- class Dist
3
- # The chef executable name.
4
- EXEC = "chef".freeze
5
-
6
- # The client's alias (chef-client)
7
- CLIENT = "chef-client".freeze
8
-
9
- # A short name for the product
10
- SHORT = "chef".freeze
11
-
12
- # The suffix for Chef's /etc/chef, /var/chef and C:\\Chef directories
13
- # "cinc" => /etc/cinc, /var/cinc, C:\\cinc
14
- DIR_SUFFIX = "chef".freeze
15
-
16
- # The user's configuration directory
17
- USER_CONF_DIR = ".chef".freeze
18
-
19
- # The legacy conf folder: C:/opscode/chef. Specifically the "opscode" part
20
- # DIR_SUFFIX is appended to it in code where relevant
21
- LEGACY_CONF_DIR = "opscode".freeze
22
-
23
- # Enable forcing Chef EULA
24
- ENFORCE_LICENSE = true
25
- end
26
- end