chef-config 16.3.38 → 16.5.64
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/chef-config/config.rb +71 -45
- data/lib/chef-config/mixin/credentials.rb +8 -7
- data/lib/chef-config/mixin/train_transport.rb +141 -0
- data/lib/chef-config/path_helper.rb +74 -44
- data/lib/chef-config/version.rb +1 -1
- data/lib/chef-config/workstation_config_loader.rb +8 -10
- data/spec/unit/config_spec.rb +62 -5
- data/spec/unit/path_helper_spec.rb +103 -38
- metadata +5 -5
- data/lib/chef-config/dist.rb +0 -26
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 98200061cdf7f6987f89d2810c4f4cf06e73e946703207b1e03270bed58c2a72
|
4
|
+
data.tar.gz: 4c97416eaa59a81959b65596d40efe4f24e10e6e8dc1e5f9f26d5467c0f13385
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7a3923de2e675cd239dde70ac73595d043da585f5350f083c093fbefe6bd86a5fdd29165e7229fc2ba082018ac645420eb6991db993ea626735cd882ff0ac047
|
7
|
+
data.tar.gz: b0270e4feee69bde6219ec09e07529a40e0b1849ba42ea1066638b74754c7e45c6fdb6d73ec2fb0c78c727f77c131a86d4a0399d5f4fe1b46243a8765e1e6def
|
data/lib/chef-config/config.rb
CHANGED
@@ -20,8 +20,8 @@
|
|
20
20
|
# limitations under the License.
|
21
21
|
|
22
22
|
require "mixlib/config" unless defined?(Mixlib::Config)
|
23
|
-
|
24
|
-
|
23
|
+
autoload :Pathname, "pathname"
|
24
|
+
autoload :ChefUtils, "chef-utils"
|
25
25
|
|
26
26
|
require_relative "fips"
|
27
27
|
require_relative "logger"
|
@@ -29,12 +29,14 @@ require_relative "windows"
|
|
29
29
|
require_relative "path_helper"
|
30
30
|
require_relative "mixin/fuzzy_hostname_matcher"
|
31
31
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
32
|
+
module Mixlib
|
33
|
+
autoload :ShellOut, "mixlib/shellout"
|
34
|
+
end
|
35
|
+
autoload :URI, "uri"
|
36
|
+
autoload :Addressable, "addressable/uri"
|
37
|
+
autoload :OpenSSL, "openssl"
|
38
|
+
autoload :YAML, "yaml"
|
39
|
+
require "chef-utils/dist" unless defined?(ChefUtils::Dist)
|
38
40
|
|
39
41
|
module ChefConfig
|
40
42
|
|
@@ -74,42 +76,66 @@ module ChefConfig
|
|
74
76
|
path
|
75
77
|
end
|
76
78
|
|
77
|
-
# On *nix, /etc/chef
|
78
|
-
|
79
|
-
|
80
|
-
|
79
|
+
# On *nix, /etc/chef, on Windows C:\chef
|
80
|
+
#
|
81
|
+
# @param windows [Boolean] optional flag to force to windows or unix-style
|
82
|
+
# @return [String] the platform-specific path
|
83
|
+
#
|
84
|
+
def self.etc_chef_dir(windows: ChefUtils.windows?)
|
85
|
+
path = windows ? c_chef_dir : PathHelper.join("/etc", ChefUtils::Dist::Infra::DIR_SUFFIX, windows: windows)
|
86
|
+
PathHelper.cleanpath(path, windows: windows)
|
81
87
|
end
|
82
88
|
|
83
|
-
# On *nix, /var/chef
|
84
|
-
|
85
|
-
|
86
|
-
|
89
|
+
# On *nix, /var/chef, on Windows C:\chef
|
90
|
+
#
|
91
|
+
# @param windows [Boolean] optional flag to force to windows or unix-style
|
92
|
+
# @return [String] the platform-specific path
|
93
|
+
#
|
94
|
+
def self.var_chef_dir(windows: ChefUtils.windows?)
|
95
|
+
path = windows ? c_chef_dir : PathHelper.join("/var", ChefUtils::Dist::Infra::DIR_SUFFIX, windows: windows)
|
96
|
+
PathHelper.cleanpath(path, windows: windows)
|
87
97
|
end
|
88
98
|
|
89
|
-
# On *nix,
|
90
|
-
|
91
|
-
|
92
|
-
|
99
|
+
# On *nix, /var, on Windows C:\
|
100
|
+
#
|
101
|
+
# @param windows [Boolean] optional flag to force to windows or unix-style
|
102
|
+
# @return [String] the platform-specific path
|
103
|
+
#
|
104
|
+
def self.var_root_dir(windows: ChefUtils.windows?)
|
105
|
+
path = windows ? "C:\\" : "/var"
|
106
|
+
PathHelper.cleanpath(path, windows: windows)
|
93
107
|
end
|
94
108
|
|
95
109
|
# On windows, C:/chef/
|
96
|
-
|
110
|
+
#
|
111
|
+
# (should only be called in a windows-context)
|
112
|
+
#
|
113
|
+
# @return [String] the platform-specific path
|
114
|
+
#
|
115
|
+
def self.c_chef_dir(windows: ChefUtils.windows?)
|
97
116
|
drive = windows_installation_drive || "C:"
|
98
|
-
|
99
|
-
PathHelper.cleanpath(path)
|
117
|
+
PathHelper.join(drive, ChefUtils::Dist::Infra::DIR_SUFFIX, windows: windows)
|
100
118
|
end
|
101
119
|
|
102
|
-
|
120
|
+
# On windows, C:/opscode
|
121
|
+
#
|
122
|
+
# (should only be called in a windows-context)
|
123
|
+
#
|
124
|
+
# @return [String] the platform-specific path
|
125
|
+
#
|
126
|
+
def self.c_opscode_dir(windows: ChefUtils.windows?)
|
103
127
|
drive = windows_installation_drive || "C:"
|
104
|
-
|
105
|
-
PathHelper.cleanpath(path)
|
128
|
+
PathHelper.join(drive, ChefUtils::Dist::Org::LEGACY_CONF_DIR, ChefUtils::Dist::Infra::DIR_SUFFIX, windows: windows)
|
106
129
|
end
|
107
130
|
|
108
131
|
# the drive where Chef is installed on a windows host. This is determined
|
109
132
|
# either by the drive containing the current file or by the SYSTEMDRIVE ENV
|
110
133
|
# variable
|
111
134
|
#
|
135
|
+
# (should only be called in a windows-context)
|
136
|
+
#
|
112
137
|
# @return [String] the drive letter
|
138
|
+
#
|
113
139
|
def self.windows_installation_drive
|
114
140
|
if ChefUtils.windows?
|
115
141
|
drive = File.expand_path(__FILE__).split("/", 2)[0]
|
@@ -164,7 +190,7 @@ module ChefConfig
|
|
164
190
|
if config_file
|
165
191
|
PathHelper.dirname(PathHelper.canonical_path(config_file, false))
|
166
192
|
else
|
167
|
-
PathHelper.join(PathHelper.cleanpath(user_home),
|
193
|
+
PathHelper.join(PathHelper.cleanpath(user_home), ChefUtils::Dist::Infra::USER_CONF_DIR, "")
|
168
194
|
end
|
169
195
|
end
|
170
196
|
|
@@ -243,7 +269,7 @@ module ChefConfig
|
|
243
269
|
end
|
244
270
|
path = new_path
|
245
271
|
end
|
246
|
-
ChefConfig.logger.info("Auto-discovered #{
|
272
|
+
ChefConfig.logger.info("Auto-discovered #{ChefUtils::Dist::Infra::SHORT} repository at #{path}")
|
247
273
|
path
|
248
274
|
end
|
249
275
|
|
@@ -341,12 +367,12 @@ module ChefConfig
|
|
341
367
|
# Otherwise, we'll create .chef under the user's home directory and use that as
|
342
368
|
# the cache path.
|
343
369
|
unless path_accessible?(primary_cache_path) || path_accessible?(primary_cache_root)
|
344
|
-
secondary_cache_path = PathHelper.join(user_home,
|
345
|
-
secondary_cache_path = target_mode? ?
|
370
|
+
secondary_cache_path = PathHelper.join(user_home, ChefUtils::Dist::Infra::USER_CONF_DIR)
|
371
|
+
secondary_cache_path = target_mode? ? PathHelper.join(secondary_cache_path, target_mode.host) : secondary_cache_path
|
346
372
|
ChefConfig.logger.trace("Unable to access cache at #{primary_cache_path}. Switching cache to #{secondary_cache_path}")
|
347
373
|
secondary_cache_path
|
348
374
|
else
|
349
|
-
target_mode? ?
|
375
|
+
target_mode? ? PathHelper.join(primary_cache_path, target_mode.host) : primary_cache_path
|
350
376
|
end
|
351
377
|
end
|
352
378
|
end
|
@@ -355,7 +381,7 @@ module ChefConfig
|
|
355
381
|
#
|
356
382
|
# @param path [String]
|
357
383
|
def self.path_accessible?(path)
|
358
|
-
File.
|
384
|
+
File.exist?(path) && File.readable?(path) && File.writable?(path)
|
359
385
|
end
|
360
386
|
|
361
387
|
# Where cookbook files are stored on the server (by content checksum)
|
@@ -372,7 +398,7 @@ module ChefConfig
|
|
372
398
|
# If your `file_cache_path` resides on a NFS (or non-flock()-supporting
|
373
399
|
# fs), it's recommended to set this to something like
|
374
400
|
# '/tmp/chef-client-running.pid'
|
375
|
-
default(:lockfile) { PathHelper.join(file_cache_path, "#{
|
401
|
+
default(:lockfile) { PathHelper.join(file_cache_path, "#{ChefUtils::Dist::Infra::CLIENT}-running.pid") }
|
376
402
|
|
377
403
|
## Daemonization Settings ##
|
378
404
|
# What user should Chef run as?
|
@@ -769,7 +795,7 @@ module ChefConfig
|
|
769
795
|
if chef_server_url.to_s =~ %r{/organizations/(.*)$}
|
770
796
|
"#{$1}-validator"
|
771
797
|
else
|
772
|
-
"#{
|
798
|
+
"#{ChefUtils::Dist::Infra::SHORT}-validator"
|
773
799
|
end
|
774
800
|
end
|
775
801
|
|
@@ -843,7 +869,7 @@ module ChefConfig
|
|
843
869
|
default :profile, nil
|
844
870
|
|
845
871
|
default :chef_guid_path do
|
846
|
-
PathHelper.join(config_dir, "#{
|
872
|
+
PathHelper.join(config_dir, "#{ChefUtils::Dist::Infra::SHORT}_guid")
|
847
873
|
end
|
848
874
|
|
849
875
|
default :chef_guid, nil
|
@@ -1052,7 +1078,7 @@ module ChefConfig
|
|
1052
1078
|
# generated by the DataCollector when Chef is run in Solo mode. This
|
1053
1079
|
# allows users to associate their Solo nodes with faux organizations
|
1054
1080
|
# without the nodes being connected to an actual Chef Server.
|
1055
|
-
default :organization, "#{
|
1081
|
+
default :organization, "#{ChefUtils::Dist::Infra::SHORT}_solo"
|
1056
1082
|
end
|
1057
1083
|
|
1058
1084
|
configurable(:http_proxy)
|
@@ -1078,13 +1104,6 @@ module ChefConfig
|
|
1078
1104
|
export_no_proxy(no_proxy) if key?(:no_proxy) && no_proxy
|
1079
1105
|
end
|
1080
1106
|
|
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
1107
|
# Builds a proxy uri and exports it to the appropriate environment variables. Examples:
|
1089
1108
|
# http://username:password@hostname:port
|
1090
1109
|
# https://username@hostname:port
|
@@ -1096,15 +1115,22 @@ module ChefConfig
|
|
1096
1115
|
# pass = password
|
1097
1116
|
# @api private
|
1098
1117
|
def self.export_proxy(scheme, path, user, pass)
|
1118
|
+
# Character classes for Addressable
|
1119
|
+
# See https://www.ietf.org/rfc/rfc3986.txt 3.2.1
|
1120
|
+
# The user part may not have a : in it
|
1121
|
+
user_class = Addressable::URI::CharacterClasses::UNRESERVED + Addressable::URI::CharacterClasses::SUB_DELIMS
|
1122
|
+
# The password part may have any valid USERINFO characters
|
1123
|
+
password_class = user_class + "\\:"
|
1124
|
+
|
1099
1125
|
path = "#{scheme}://#{path}" unless path.include?("://")
|
1100
1126
|
# URI.split returns the following parts:
|
1101
1127
|
# [scheme, userinfo, host, port, registry, path, opaque, query, fragment]
|
1102
1128
|
uri = Addressable::URI.encode(path, Addressable::URI)
|
1103
1129
|
|
1104
1130
|
if user && !user.empty?
|
1105
|
-
userinfo = Addressable::URI.encode_component(user,
|
1131
|
+
userinfo = Addressable::URI.encode_component(user, user_class)
|
1106
1132
|
if pass
|
1107
|
-
userinfo << ":#{Addressable::URI.encode_component(pass,
|
1133
|
+
userinfo << ":#{Addressable::URI.encode_component(pass, password_class)}"
|
1108
1134
|
end
|
1109
1135
|
uri.userinfo = userinfo
|
1110
1136
|
end
|
@@ -15,8 +15,9 @@
|
|
15
15
|
# limitations under the License.
|
16
16
|
#
|
17
17
|
|
18
|
-
|
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(
|
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(
|
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
|
-
|
88
|
-
return if
|
88
|
+
cred_config = parse_credentials_file
|
89
|
+
return if cred_config.nil? # No credentials, nothing to do here.
|
89
90
|
|
90
|
-
if
|
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(
|
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].map { |k, v| [k.to_sym, v] }.to_h # 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
|
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
|
52
|
-
|
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
|
-
|
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(
|
66
|
-
component = component.sub(
|
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
|
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
|
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
|
-
#
|
130
|
-
#
|
131
|
-
#
|
132
|
-
#
|
133
|
-
# to the user
|
134
|
-
#
|
135
|
-
#
|
136
|
-
#
|
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
|
-
#
|
139
|
-
#
|
140
|
-
|
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
|
-
|
143
|
-
|
144
|
-
path
|
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
|
-
|
150
|
-
|
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
|
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")) }
|
data/lib/chef-config/version.rb
CHANGED
@@ -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] + [
|
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(
|
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
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
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)
|
@@ -186,7 +184,7 @@ module ChefConfig
|
|
186
184
|
end
|
187
185
|
|
188
186
|
def home_chef_dir
|
189
|
-
@home_chef_dir ||= PathHelper.home(
|
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)
|
data/spec/unit/config_spec.rb
CHANGED
@@ -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(
|
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
|
@@ -23,9 +23,8 @@ RSpec.describe ChefConfig::PathHelper do
|
|
23
23
|
|
24
24
|
let(:path_helper) { described_class }
|
25
25
|
|
26
|
-
|
27
|
-
|
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
|
-
|
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
|
-
|
71
|
-
|
139
|
+
context "platform-specific #join behavior" do
|
72
140
|
it "joins components on Windows when some end with unix separators" do
|
73
|
-
|
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 =
|
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 =
|
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 =
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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)
|
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.
|
4
|
+
version: 16.5.64
|
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-
|
11
|
+
date: 2020-09-17 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.
|
19
|
+
version: 16.5.64
|
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.
|
26
|
+
version: 16.5.64
|
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
|
data/lib/chef-config/dist.rb
DELETED
@@ -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
|