bolt 2.33.2 → 2.38.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of bolt might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/Puppetfile +1 -1
- data/bolt-modules/boltlib/lib/puppet/datatypes/applyresult.rb +1 -0
- data/bolt-modules/boltlib/lib/puppet/functions/catch_errors.rb +1 -3
- data/bolt-modules/boltlib/lib/puppet/functions/download_file.rb +17 -6
- data/bolt-modules/boltlib/lib/puppet/functions/parallelize.rb +56 -0
- data/bolt-modules/boltlib/lib/puppet/functions/run_command.rb +24 -6
- data/bolt-modules/boltlib/lib/puppet/functions/run_script.rb +27 -8
- data/bolt-modules/boltlib/lib/puppet/functions/run_task.rb +21 -1
- data/bolt-modules/boltlib/lib/puppet/functions/run_task_with.rb +18 -1
- data/bolt-modules/boltlib/lib/puppet/functions/upload_file.rb +24 -6
- data/lib/bolt/analytics.rb +27 -8
- data/lib/bolt/apply_result.rb +3 -3
- data/lib/bolt/bolt_option_parser.rb +48 -16
- data/lib/bolt/cli.rb +154 -249
- data/lib/bolt/config.rb +188 -55
- data/lib/bolt/config/options.rb +147 -87
- data/lib/bolt/config/transport/base.rb +10 -19
- data/lib/bolt/config/transport/local.rb +1 -7
- data/lib/bolt/config/transport/options.rb +10 -68
- data/lib/bolt/config/transport/ssh.rb +8 -14
- data/lib/bolt/error.rb +33 -3
- data/lib/bolt/executor.rb +92 -6
- data/lib/bolt/inventory.rb +25 -0
- data/lib/bolt/inventory/group.rb +2 -1
- data/lib/bolt/inventory/options.rb +130 -0
- data/lib/bolt/inventory/target.rb +10 -11
- data/lib/bolt/module_installer.rb +21 -13
- data/lib/bolt/module_installer/resolver.rb +1 -1
- data/lib/bolt/outputter.rb +19 -5
- data/lib/bolt/outputter/human.rb +41 -10
- data/lib/bolt/outputter/json.rb +1 -1
- data/lib/bolt/outputter/logger.rb +1 -1
- data/lib/bolt/outputter/rainbow.rb +13 -2
- data/lib/bolt/pal.rb +19 -7
- data/lib/bolt/pal/yaml_plan.rb +7 -0
- data/lib/bolt/plan_creator.rb +160 -0
- data/lib/bolt/plugin.rb +42 -13
- data/lib/bolt/plugin/cache.rb +76 -0
- data/lib/bolt/plugin/module.rb +4 -4
- data/lib/bolt/plugin/puppetdb.rb +1 -1
- data/lib/bolt/project.rb +59 -40
- data/lib/bolt/project_manager.rb +201 -0
- data/lib/bolt/{project_migrator/config.rb → project_manager/config_migrator.rb} +51 -5
- data/lib/bolt/{project_migrator/inventory.rb → project_manager/inventory_migrator.rb} +5 -5
- data/lib/bolt/{project_migrator/base.rb → project_manager/migrator.rb} +2 -2
- data/lib/bolt/{project_migrator/modules.rb → project_manager/module_migrator.rb} +5 -3
- data/lib/bolt/puppetdb/client.rb +11 -2
- data/lib/bolt/puppetdb/config.rb +9 -8
- data/lib/bolt/rerun.rb +1 -5
- data/lib/bolt/shell/bash.rb +8 -2
- data/lib/bolt/shell/powershell.rb +22 -4
- data/lib/bolt/target.rb +4 -0
- data/lib/bolt/task/run.rb +1 -1
- data/lib/bolt/transport/local.rb +13 -0
- data/lib/bolt/transport/orch.rb +0 -5
- data/lib/bolt/transport/orch/connection.rb +10 -3
- data/lib/bolt/transport/remote.rb +1 -1
- data/lib/bolt/transport/ssh/exec_connection.rb +6 -2
- data/lib/bolt/util.rb +41 -7
- data/lib/bolt/validator.rb +226 -0
- data/lib/bolt/version.rb +1 -1
- data/lib/bolt/yarn.rb +23 -0
- data/lib/bolt_server/base_config.rb +3 -1
- data/lib/bolt_server/config.rb +3 -1
- data/lib/bolt_server/file_cache.rb +2 -0
- data/lib/bolt_server/plugin.rb +13 -0
- data/lib/bolt_server/plugin/puppet_connect_data.rb +37 -0
- data/lib/bolt_server/schemas/connect-data.json +22 -0
- data/lib/bolt_server/schemas/partials/task.json +2 -2
- data/lib/bolt_server/transport_app.rb +82 -23
- data/lib/bolt_spec/plans/mock_executor.rb +4 -1
- data/libexec/apply_catalog.rb +1 -1
- data/libexec/custom_facts.rb +1 -1
- data/libexec/query_resources.rb +1 -1
- metadata +22 -13
- data/lib/bolt/project_migrator.rb +0 -80
@@ -1,17 +1,17 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'bolt/
|
3
|
+
require 'bolt/project_manager/migrator'
|
4
4
|
|
5
5
|
module Bolt
|
6
|
-
class
|
7
|
-
class
|
6
|
+
class ProjectManager
|
7
|
+
class InventoryMigrator < Migrator
|
8
8
|
def migrate(inventory_file, backup_dir)
|
9
|
-
|
9
|
+
inventory1to2(inventory_file, backup_dir)
|
10
10
|
end
|
11
11
|
|
12
12
|
# Migrates an inventory v1 file to inventory v2.
|
13
13
|
#
|
14
|
-
private def
|
14
|
+
private def inventory1to2(inventory_file, backup_dir)
|
15
15
|
unless File.exist?(inventory_file)
|
16
16
|
return true
|
17
17
|
end
|
@@ -1,10 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'bolt/
|
3
|
+
require 'bolt/project_manager/migrator'
|
4
4
|
|
5
5
|
module Bolt
|
6
|
-
class
|
7
|
-
class
|
6
|
+
class ProjectManager
|
7
|
+
class ModuleMigrator < Migrator
|
8
8
|
def migrate(project, configured_modulepath)
|
9
9
|
return true unless project.modules.nil?
|
10
10
|
|
@@ -61,6 +61,7 @@ module Bolt
|
|
61
61
|
# Create specs to resolve from
|
62
62
|
specs = Bolt::ModuleInstaller::Specs.new(modules.map(&:to_hash))
|
63
63
|
|
64
|
+
@outputter.start_spin
|
64
65
|
# Attempt to resolve dependencies
|
65
66
|
begin
|
66
67
|
@outputter.print_message('')
|
@@ -72,6 +73,7 @@ module Bolt
|
|
72
73
|
end
|
73
74
|
|
74
75
|
migrate_managed_modules(puppetfile, puppetfile_path, managed_moduledir)
|
76
|
+
@outputter.stop_spin
|
75
77
|
|
76
78
|
# Move remaining modules to 'modules'
|
77
79
|
consolidate_modules(modulepath)
|
data/lib/bolt/puppetdb/client.rb
CHANGED
@@ -2,7 +2,6 @@
|
|
2
2
|
|
3
3
|
require 'json'
|
4
4
|
require 'logging'
|
5
|
-
require 'uri'
|
6
5
|
|
7
6
|
module Bolt
|
8
7
|
module PuppetDB
|
@@ -19,6 +18,7 @@ module Bolt
|
|
19
18
|
def query_certnames(query)
|
20
19
|
return [] unless query
|
21
20
|
|
21
|
+
@logger.debug("Querying certnames")
|
22
22
|
results = make_query(query)
|
23
23
|
|
24
24
|
if results&.first && !results.first&.key?('certname')
|
@@ -35,6 +35,8 @@ module Bolt
|
|
35
35
|
certnames.uniq!
|
36
36
|
name_query = certnames.map { |c| ["=", "certname", c] }
|
37
37
|
name_query.insert(0, "or")
|
38
|
+
|
39
|
+
@logger.debug("Querying certnames")
|
38
40
|
result = make_query(name_query, 'inventory')
|
39
41
|
|
40
42
|
result&.each_with_object({}) do |node, coll|
|
@@ -53,6 +55,8 @@ module Bolt
|
|
53
55
|
facts_query.insert(0, "or")
|
54
56
|
|
55
57
|
query = ['and', name_query, facts_query]
|
58
|
+
|
59
|
+
@logger.debug("Querying certnames")
|
56
60
|
result = make_query(query, 'fact-contents')
|
57
61
|
result.map! { |h| h.delete_if { |k, _v| %w[environment name].include?(k) } }
|
58
62
|
result.group_by { |c| c['certname'] }
|
@@ -64,11 +68,13 @@ module Bolt
|
|
64
68
|
url += "/#{path}" if path
|
65
69
|
|
66
70
|
begin
|
71
|
+
@logger.debug("Sending PuppetDB query to #{url}")
|
67
72
|
response = http_client.post(url, body: body, header: headers)
|
68
73
|
rescue StandardError => e
|
69
74
|
raise Bolt::PuppetDBFailoverError, "Failed to query PuppetDB: #{e}"
|
70
75
|
end
|
71
76
|
|
77
|
+
@logger.debug("Got response code #{response.code} from PuppetDB")
|
72
78
|
if response.code != 200
|
73
79
|
msg = "Failed to query PuppetDB: #{response.body}"
|
74
80
|
if response.code == 400
|
@@ -93,6 +99,7 @@ module Bolt
|
|
93
99
|
return @http if @http
|
94
100
|
# lazy-load expensive gem code
|
95
101
|
require 'httpclient'
|
102
|
+
@logger.trace("Creating HTTP Client")
|
96
103
|
@http = HTTPClient.new
|
97
104
|
@http.ssl_config.set_client_cert_file(@config.cert, @config.key) if @config.cert
|
98
105
|
@http.ssl_config.add_trust_ca(@config.cacert)
|
@@ -108,13 +115,15 @@ module Bolt
|
|
108
115
|
end
|
109
116
|
|
110
117
|
def uri
|
118
|
+
require 'addressable/uri'
|
119
|
+
|
111
120
|
@current_url ||= (@config.server_urls - @bad_urls).first
|
112
121
|
unless @current_url
|
113
122
|
msg = "Failed to connect to all PuppetDB server_urls: #{@config.server_urls.to_a.join(', ')}."
|
114
123
|
raise Bolt::PuppetDBError, msg
|
115
124
|
end
|
116
125
|
|
117
|
-
uri = URI.parse(@current_url)
|
126
|
+
uri = Addressable::URI.parse(@current_url)
|
118
127
|
uri.port ||= 8081
|
119
128
|
uri
|
120
129
|
end
|
data/lib/bolt/puppetdb/config.rb
CHANGED
@@ -6,20 +6,19 @@ require 'bolt/util'
|
|
6
6
|
module Bolt
|
7
7
|
module PuppetDB
|
8
8
|
class Config
|
9
|
-
if
|
10
|
-
DEFAULT_TOKEN = File.expand_path('~/.puppetlabs/token')
|
11
|
-
DEFAULT_CONFIG = { user: File.expand_path('~/.puppetlabs/client-tools/puppetdb.conf'),
|
12
|
-
global: '/etc/puppetlabs/client-tools/puppetdb.conf' }.freeze
|
13
|
-
else
|
9
|
+
if ENV['HOME'].nil?
|
14
10
|
DEFAULT_TOKEN = Bolt::Util.windows? ? 'nul' : '/dev/null'
|
15
11
|
DEFAULT_CONFIG = { user: '/etc/puppetlabs/puppet/puppetdb.conf',
|
16
12
|
global: '/etc/puppetlabs/puppet/puppetdb.conf' }.freeze
|
13
|
+
else
|
14
|
+
DEFAULT_TOKEN = File.expand_path('~/.puppetlabs/token')
|
15
|
+
DEFAULT_CONFIG = { user: File.expand_path('~/.puppetlabs/client-tools/puppetdb.conf'),
|
16
|
+
global: '/etc/puppetlabs/client-tools/puppetdb.conf' }.freeze
|
17
17
|
|
18
18
|
end
|
19
19
|
|
20
20
|
def self.default_windows_config
|
21
|
-
|
22
|
-
File.expand_path(File.join(Dir::COMMON_APPDATA, 'PuppetLabs/client-tools/puppetdb.conf'))
|
21
|
+
File.expand_path(File.join(ENV['ALLUSERSPROFILE'], 'PuppetLabs/client-tools/puppetdb.conf'))
|
23
22
|
end
|
24
23
|
|
25
24
|
def self.load_config(options, project_path = nil)
|
@@ -89,6 +88,8 @@ module Bolt
|
|
89
88
|
|
90
89
|
def uri
|
91
90
|
return @uri if @uri
|
91
|
+
require 'addressable/uri'
|
92
|
+
|
92
93
|
uri = case @settings['server_urls']
|
93
94
|
when String
|
94
95
|
@settings['server_urls']
|
@@ -100,7 +101,7 @@ module Bolt
|
|
100
101
|
raise Bolt::PuppetDBError, "server_urls must be a string or array"
|
101
102
|
end
|
102
103
|
|
103
|
-
@uri = URI.parse(uri)
|
104
|
+
@uri = Addressable::URI.parse(uri)
|
104
105
|
@uri.port ||= 8081
|
105
106
|
@uri
|
106
107
|
end
|
data/lib/bolt/rerun.rb
CHANGED
@@ -12,15 +12,11 @@ module Bolt
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def data
|
15
|
-
@data ||=
|
15
|
+
@data ||= Bolt::Util.read_json_file(@path, 'rerun')
|
16
16
|
unless @data.is_a?(Array) && @data.all? { |r| r['target'] && r['status'] }
|
17
17
|
raise Bolt::FileError.new("Missing data in rerun file: #{@path}", @path)
|
18
18
|
end
|
19
19
|
@data
|
20
|
-
rescue JSON::ParserError
|
21
|
-
raise Bolt::FileError.new("Could not parse rerun file: #{@path}", @path)
|
22
|
-
rescue IOError, SystemCallError
|
23
|
-
raise Bolt::FileError.new("Could not read rerun file: #{@path}", @path)
|
24
20
|
end
|
25
21
|
|
26
22
|
def get_targets(filter)
|
data/lib/bolt/shell/bash.rb
CHANGED
@@ -199,7 +199,7 @@ module Bolt
|
|
199
199
|
lines = buffer.split(/(?<=\n)/)
|
200
200
|
# handle_sudo will return the line if it is not a sudo prompt or error
|
201
201
|
lines.map! { |line| handle_sudo(inp, line, stdin) }
|
202
|
-
lines.join
|
202
|
+
lines.join
|
203
203
|
# If stream has reached EOF, no password prompt is expected
|
204
204
|
# return an empty string
|
205
205
|
rescue EOFError
|
@@ -436,8 +436,14 @@ module Bolt
|
|
436
436
|
result_output.stderr << read_streams[err]
|
437
437
|
result_output.exit_code = t.value.respond_to?(:exitstatus) ? t.value.exitstatus : t.value
|
438
438
|
|
439
|
-
|
439
|
+
case result_output.exit_code
|
440
|
+
when 0
|
440
441
|
@logger.trace { "Command `#{command_str}` returned successfully" }
|
442
|
+
when 126
|
443
|
+
msg = "\n\nThis may be caused by the default tmpdir being mounted "\
|
444
|
+
"using 'noexec'. See http://pup.pt/task-failure for details and workarounds."
|
445
|
+
result_output.stderr << msg
|
446
|
+
@logger.trace { "Command #{command_str} failed with exit code #{result_output.exit_code}" }
|
441
447
|
else
|
442
448
|
@logger.trace { "Command #{command_str} failed with exit code #{result_output.exit_code}" }
|
443
449
|
end
|
@@ -11,9 +11,25 @@ module Bolt
|
|
11
11
|
def initialize(target, conn)
|
12
12
|
super
|
13
13
|
|
14
|
-
extensions = [target.options['extensions'] || []].flatten.map { |ext| ext[0]
|
14
|
+
extensions = [target.options['extensions'] || []].flatten.map { |ext| ext[0] == '.' ? ext : '.' + ext }
|
15
15
|
extensions += target.options['interpreters'].keys if target.options['interpreters']
|
16
16
|
@extensions = DEFAULT_EXTENSIONS + extensions
|
17
|
+
validate_ps_version
|
18
|
+
end
|
19
|
+
|
20
|
+
def validate_ps_version
|
21
|
+
version = execute("$PSVersionTable.PSVersion.Major").stdout.string.chomp
|
22
|
+
if !version.empty? && version.to_i < 3
|
23
|
+
# This lets us know how many targets have Powershell 2, and lets the
|
24
|
+
# user know how many targets they have with PS2
|
25
|
+
msg = "Detected PowerShell 2 on one or more targets.\nPowerShell 2 "\
|
26
|
+
"is deprecated, and support will be removed in Bolt 3.0. See "\
|
27
|
+
"bolt-debug.log or run with '--log-level debug' to see the full "\
|
28
|
+
"list of targets with PowerShell 2."
|
29
|
+
|
30
|
+
Bolt::Logger.deprecation_warning("PowerShell 2", msg)
|
31
|
+
@logger.debug("Detected PowerShell 2 on #{target}.")
|
32
|
+
end
|
17
33
|
end
|
18
34
|
|
19
35
|
def provided_features
|
@@ -177,7 +193,8 @@ module Bolt
|
|
177
193
|
def run_command(command, options = {}, position = [])
|
178
194
|
command = [*env_declarations(options[:env_vars]), command].join("\r\n") if options[:env_vars]
|
179
195
|
|
180
|
-
|
196
|
+
wrap_command = conn.is_a?(Bolt::Transport::Local::Connection)
|
197
|
+
output = execute(command, wrap_command)
|
181
198
|
Bolt::Result.for_command(target,
|
182
199
|
output.stdout.string,
|
183
200
|
output.stderr.string,
|
@@ -268,8 +285,9 @@ module Bolt
|
|
268
285
|
end
|
269
286
|
end
|
270
287
|
|
271
|
-
def execute(command)
|
272
|
-
if conn.max_command_length && command.length > conn.max_command_length
|
288
|
+
def execute(command, wrap_command = false)
|
289
|
+
if (conn.max_command_length && command.length > conn.max_command_length) ||
|
290
|
+
wrap_command
|
273
291
|
return with_tmpdir do |dir|
|
274
292
|
command += "\r\nif (!$?) { if($LASTEXITCODE) { exit $LASTEXITCODE } else { exit 1 } }"
|
275
293
|
script_file = File.join(dir, "#{SecureRandom.uuid}_wrapper.ps1")
|
data/lib/bolt/target.rb
CHANGED
data/lib/bolt/task/run.rb
CHANGED
@@ -42,7 +42,7 @@ module Bolt
|
|
42
42
|
if targets.empty?
|
43
43
|
Bolt::ResultSet.new([])
|
44
44
|
else
|
45
|
-
result = executor.run_task(targets, task, params, options)
|
45
|
+
result = executor.run_task(targets, task, params, options, [], :trace)
|
46
46
|
|
47
47
|
if !result.ok && !options[:catch_errors]
|
48
48
|
raise Bolt::RunFailure.new(result, 'run_task', task.name)
|
data/lib/bolt/transport/local.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'bolt/logger'
|
3
4
|
require 'bolt/transport/simple'
|
4
5
|
|
5
6
|
module Bolt
|
@@ -10,6 +11,18 @@ module Bolt
|
|
10
11
|
end
|
11
12
|
|
12
13
|
def with_connection(target)
|
14
|
+
if target.transport_config['bundled-ruby'] || target.name == 'localhost'
|
15
|
+
target.set_local_defaults
|
16
|
+
end
|
17
|
+
|
18
|
+
if target.name != 'localhost' &&
|
19
|
+
!target.transport_config.key?('bundled-ruby')
|
20
|
+
msg = "The local transport will default to using Bolt's Ruby interpreter and "\
|
21
|
+
"setting the 'puppet-agent' feature in Bolt 3.0. Enable or disable these "\
|
22
|
+
"defaults by setting 'bundled-ruby' in the local transport config."
|
23
|
+
Bolt::Logger.warn_once('local default config', msg)
|
24
|
+
end
|
25
|
+
|
13
26
|
yield Connection.new(target)
|
14
27
|
end
|
15
28
|
end
|
data/lib/bolt/transport/orch.rb
CHANGED
@@ -10,11 +10,6 @@ require 'bolt/transport/orch/connection'
|
|
10
10
|
module Bolt
|
11
11
|
module Transport
|
12
12
|
class Orch < Base
|
13
|
-
CONF_FILE = if !ENV['HOME'].nil?
|
14
|
-
File.expand_path('~/.puppetlabs/client-tools/orchestrator.conf')
|
15
|
-
else
|
16
|
-
'/etc/puppetlabs/client-tools/orchestrator.conf'
|
17
|
-
end
|
18
13
|
BOLT_COMMAND_TASK = Struct.new(:name).new('bolt_shim::command').freeze
|
19
14
|
BOLT_SCRIPT_TASK = Struct.new(:name).new('bolt_shim::script').freeze
|
20
15
|
BOLT_UPLOAD_TASK = Struct.new(:name).new('bolt_shim::upload').freeze
|
@@ -17,13 +17,20 @@ module Bolt
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def initialize(opts, plan_context, logger)
|
20
|
+
require 'addressable/uri'
|
21
|
+
|
20
22
|
@logger = logger
|
21
23
|
@key = self.class.get_key(opts)
|
22
|
-
|
23
|
-
|
24
|
-
|
24
|
+
client_opts = opts.slice('token-file', 'cacert', 'job-poll-interval', 'job-poll-timeout')
|
25
|
+
|
26
|
+
if opts['service-url']
|
27
|
+
uri = Addressable::URI.parse(opts['service-url'])
|
28
|
+
uri&.port ||= 8143
|
29
|
+
client_opts['service-url'] = uri.to_s
|
25
30
|
end
|
31
|
+
|
26
32
|
client_opts['User-Agent'] = "Bolt/#{VERSION}"
|
33
|
+
|
27
34
|
%w[token-file cacert].each do |f|
|
28
35
|
client_opts[f] = File.expand_path(client_opts[f]) if client_opts[f]
|
29
36
|
end
|
@@ -29,7 +29,7 @@ module Bolt
|
|
29
29
|
def run_task(target, task, arguments, options = {}, position = [])
|
30
30
|
proxy_target = get_proxy(target)
|
31
31
|
transport = @executor.transport(proxy_target.transport)
|
32
|
-
arguments = arguments.merge('_target' => target.to_h.
|
32
|
+
arguments = arguments.merge('_target' => target.to_h.compact)
|
33
33
|
|
34
34
|
remote_task = task.remote_instance
|
35
35
|
|
@@ -12,8 +12,12 @@ module Bolt
|
|
12
12
|
raise Bolt::ValidationError, "Target #{target.safe_name} does not have a host" unless target.host
|
13
13
|
|
14
14
|
@target = target
|
15
|
-
|
16
|
-
|
15
|
+
begin
|
16
|
+
ssh_config = Net::SSH::Config.for(target.host)
|
17
|
+
@user = @target.user || ssh_config[:user] || Etc.getlogin
|
18
|
+
rescue StandardError
|
19
|
+
@user = @target.user || Etc.getlogin
|
20
|
+
end
|
17
21
|
@logger = Bolt::Logger.logger(self)
|
18
22
|
end
|
19
23
|
|
data/lib/bolt/util.rb
CHANGED
@@ -22,6 +22,28 @@ module Bolt
|
|
22
22
|
raise Bolt::FileError.new("Error attempting to read #{file}: #{e}", file)
|
23
23
|
end
|
24
24
|
|
25
|
+
def read_json_file(path, filename)
|
26
|
+
require 'json'
|
27
|
+
|
28
|
+
logger = Bolt::Logger.logger(self)
|
29
|
+
path = File.expand_path(path)
|
30
|
+
content = JSON.parse(File.read(path))
|
31
|
+
logger.trace("Loaded #{filename} from #{path}")
|
32
|
+
content
|
33
|
+
rescue Errno::ENOENT
|
34
|
+
raise Bolt::FileError.new("Could not read #{filename} file at #{path}", path)
|
35
|
+
rescue JSON::ParserError => e
|
36
|
+
msg = "Unable to parse #{filename} file at #{path} as JSON: #{e.message}"
|
37
|
+
raise Bolt::FileError.new(msg, path)
|
38
|
+
rescue IOError, SystemCallError => e
|
39
|
+
raise Bolt::FileError.new("Could not read #{filename} file at #{path}\n#{e.message}",
|
40
|
+
path)
|
41
|
+
end
|
42
|
+
|
43
|
+
def read_optional_json_file(path, file_name)
|
44
|
+
File.exist?(path) && !File.zero?(path) ? read_yaml_hash(path, file_name) : {}
|
45
|
+
end
|
46
|
+
|
25
47
|
def read_yaml_hash(path, file_name)
|
26
48
|
require 'yaml'
|
27
49
|
|
@@ -29,19 +51,26 @@ module Bolt
|
|
29
51
|
path = File.expand_path(path)
|
30
52
|
content = File.open(path, "r:UTF-8") { |f| YAML.safe_load(f.read) } || {}
|
31
53
|
unless content.is_a?(Hash)
|
32
|
-
|
33
|
-
|
54
|
+
raise Bolt::FileError.new(
|
55
|
+
"Invalid content for #{file_name} file at #{path}\nContent should be a Hash or empty, "\
|
56
|
+
"not #{content.class}",
|
57
|
+
path
|
58
|
+
)
|
34
59
|
end
|
35
60
|
logger.trace("Loaded #{file_name} from #{path}")
|
36
61
|
content
|
37
62
|
rescue Errno::ENOENT
|
38
|
-
raise Bolt::FileError.new("Could not read #{file_name} file
|
63
|
+
raise Bolt::FileError.new("Could not read #{file_name} file at #{path}", path)
|
64
|
+
rescue Psych::SyntaxError => e
|
65
|
+
raise Bolt::FileError.new("Could not parse #{file_name} file at #{path}, line #{e.line}, "\
|
66
|
+
"column #{e.column}\n#{e.problem}",
|
67
|
+
path)
|
39
68
|
rescue Psych::Exception => e
|
40
|
-
raise Bolt::FileError.new("Could not parse #{file_name} file
|
41
|
-
|
69
|
+
raise Bolt::FileError.new("Could not parse #{file_name} file at #{path}\n#{e.message}",
|
70
|
+
path)
|
42
71
|
rescue IOError, SystemCallError => e
|
43
|
-
raise Bolt::FileError.new("Could not read #{file_name} file
|
44
|
-
|
72
|
+
raise Bolt::FileError.new("Could not read #{file_name} file at #{path}\n#{e.message}",
|
73
|
+
path)
|
45
74
|
end
|
46
75
|
|
47
76
|
def read_optional_yaml_hash(path, file_name)
|
@@ -273,6 +302,11 @@ module Bolt
|
|
273
302
|
!!File::ALT_SEPARATOR
|
274
303
|
end
|
275
304
|
|
305
|
+
# Returns true if running in PowerShell.
|
306
|
+
def powershell?
|
307
|
+
!!ENV['PSModulePath']
|
308
|
+
end
|
309
|
+
|
276
310
|
# Accept hash and return hash with top level keys of type "String" converted to symbols.
|
277
311
|
def symbolize_top_level_keys(hsh)
|
278
312
|
hsh.each_with_object({}) { |(k, v), h| k.is_a?(String) ? h[k.to_sym] = v : h[k] = v }
|