bolt 3.13.0 → 3.14.1
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/functions/background.rb +2 -1
- data/bolt-modules/boltlib/lib/puppet/functions/parallelize.rb +5 -1
- data/bolt-modules/boltlib/lib/puppet/functions/run_plan.rb +13 -0
- data/bolt-modules/boltlib/lib/puppet/functions/wait.rb +47 -7
- data/bolt-modules/out/lib/puppet/functions/out/message.rb +4 -2
- data/bolt-modules/out/lib/puppet/functions/out/verbose.rb +4 -2
- data/lib/bolt/analytics.rb +1 -1
- data/lib/bolt/bolt_option_parser.rb +4 -1
- data/lib/bolt/cli.rb +21 -6
- data/lib/bolt/config/transport/options.rb +12 -0
- data/lib/bolt/config/transport/ssh.rb +7 -0
- data/lib/bolt/executor.rb +12 -4
- data/lib/bolt/fiber_executor.rb +57 -12
- data/lib/bolt/outputter/human.rb +117 -12
- data/lib/bolt/outputter/json.rb +3 -5
- data/lib/bolt/outputter/logger.rb +1 -1
- data/lib/bolt/pal.rb +36 -3
- data/lib/bolt/pal/yaml_plan/step.rb +2 -0
- data/lib/bolt/pal/yaml_plan/step/message.rb +0 -8
- data/lib/bolt/pal/yaml_plan/step/verbose.rb +31 -0
- data/lib/bolt/plan_future.rb +21 -6
- data/lib/bolt/transport/ssh/exec_connection.rb +3 -1
- data/lib/bolt/version.rb +1 -1
- data/lib/bolt_server/schemas/partials/target-ssh.json +4 -0
- data/lib/bolt_server/schemas/partials/target-winrm.json +4 -0
- data/lib/bolt_server/transport_app.rb +81 -50
- data/lib/bolt_spec/plans/mock_executor.rb +16 -6
- metadata +11 -14
- data/guides/debugging.txt +0 -28
- data/guides/guide.txt +0 -17
- data/guides/inventory.txt +0 -24
- data/guides/links.txt +0 -13
- data/guides/logging.txt +0 -18
- data/guides/module.txt +0 -19
- data/guides/modulepath.txt +0 -25
- data/guides/project.txt +0 -22
- data/guides/targets.txt +0 -29
- data/guides/transports.txt +0 -23
data/lib/bolt/outputter/human.rb
CHANGED
@@ -341,7 +341,7 @@ module Bolt
|
|
341
341
|
info << if task.description
|
342
342
|
indent(2, task.description.chomp)
|
343
343
|
else
|
344
|
-
indent(2, 'No description')
|
344
|
+
indent(2, 'No description available.')
|
345
345
|
end
|
346
346
|
info << "\n\n"
|
347
347
|
|
@@ -400,7 +400,7 @@ module Bolt
|
|
400
400
|
info << if plan['description']
|
401
401
|
indent(2, plan['description'].chomp)
|
402
402
|
else
|
403
|
-
indent(2, 'No description')
|
403
|
+
indent(2, 'No description available.')
|
404
404
|
end
|
405
405
|
info << "\n\n"
|
406
406
|
|
@@ -471,8 +471,16 @@ module Bolt
|
|
471
471
|
@stream.puts info
|
472
472
|
end
|
473
473
|
|
474
|
-
def print_guide(guide
|
475
|
-
|
474
|
+
def print_guide(topic:, guide:, documentation: nil)
|
475
|
+
info = +"#{colorize(:cyan, topic)}\n"
|
476
|
+
info << indent(2, guide)
|
477
|
+
|
478
|
+
if documentation
|
479
|
+
info << "\n#{colorize(:cyan, 'Documentation')}\n"
|
480
|
+
info << indent(2, documentation.join("\n"))
|
481
|
+
end
|
482
|
+
|
483
|
+
@stream.puts info
|
476
484
|
end
|
477
485
|
|
478
486
|
def print_plan_lookup(value)
|
@@ -480,15 +488,19 @@ module Bolt
|
|
480
488
|
end
|
481
489
|
|
482
490
|
def print_module_list(module_list)
|
491
|
+
info = +''
|
492
|
+
|
483
493
|
module_list.each do |path, modules|
|
484
|
-
if (mod = modules.find { |m| m[:internal_module_group] })
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
494
|
+
info << if (mod = modules.find { |m| m[:internal_module_group] })
|
495
|
+
colorize(:cyan, mod[:internal_module_group])
|
496
|
+
else
|
497
|
+
colorize(:cyan, path)
|
498
|
+
end
|
499
|
+
|
500
|
+
info << "\n"
|
489
501
|
|
490
502
|
if modules.empty?
|
491
|
-
|
503
|
+
info << '(no modules installed)'
|
492
504
|
else
|
493
505
|
module_info = modules.map do |m|
|
494
506
|
version = if m[:version].nil?
|
@@ -500,11 +512,87 @@ module Bolt
|
|
500
512
|
[m[:name], version]
|
501
513
|
end
|
502
514
|
|
503
|
-
|
515
|
+
info << format_table(module_info, 2, 1).to_s
|
516
|
+
end
|
517
|
+
|
518
|
+
info << "\n\n"
|
519
|
+
end
|
520
|
+
|
521
|
+
command = Bolt::Util.powershell? ? 'Get-BoltModule -Name <MODULE>' : 'bolt module show <MODULE>'
|
522
|
+
info << colorize(:cyan, "Additional information\n")
|
523
|
+
info << indent(2, "Use '#{command}' to view details for a specific module.")
|
524
|
+
|
525
|
+
@stream.puts info
|
526
|
+
end
|
527
|
+
|
528
|
+
# Prints detailed module information.
|
529
|
+
#
|
530
|
+
# @param name [String] The module's short name.
|
531
|
+
# @param metadata [Hash] The module's metadata.
|
532
|
+
# @param path [String] The path to the module.
|
533
|
+
# @param plans [Array] The module's plans.
|
534
|
+
# @param tasks [Array] The module's tasks.
|
535
|
+
#
|
536
|
+
def print_module_info(name:, metadata:, path:, plans:, tasks:, **_kwargs)
|
537
|
+
info = +''
|
538
|
+
|
539
|
+
info << colorize(:cyan, name)
|
540
|
+
|
541
|
+
info << colorize(:dim, " [#{metadata['version']}]") if metadata['version']
|
542
|
+
info << "\n"
|
543
|
+
|
544
|
+
info << if metadata['summary']
|
545
|
+
indent(2, wrap(metadata['summary'].strip, 76))
|
546
|
+
else
|
547
|
+
indent(2, "No description available.\n")
|
548
|
+
end
|
549
|
+
info << "\n"
|
550
|
+
|
551
|
+
if tasks.any?
|
552
|
+
length = tasks.map(&:first).map(&:length).max
|
553
|
+
data = tasks.map { |task, desc| [task, truncate(desc, 76 - length)] }
|
554
|
+
info << colorize(:cyan, "Tasks\n")
|
555
|
+
info << format_table(data, 2).to_s
|
556
|
+
info << "\n\n"
|
557
|
+
end
|
558
|
+
|
559
|
+
if plans.any?
|
560
|
+
length = plans.map(&:first).map(&:length).max
|
561
|
+
data = plans.map { |plan, desc| [plan, truncate(desc, 76 - length)] }
|
562
|
+
info << colorize(:cyan, "Plans\n")
|
563
|
+
info << format_table(data, 2).to_s
|
564
|
+
info << "\n\n"
|
565
|
+
end
|
566
|
+
|
567
|
+
if metadata['operatingsystem_support']&.any?
|
568
|
+
supported = metadata['operatingsystem_support'].map do |os|
|
569
|
+
[os['operatingsystem'], os['operatingsystemrelease']&.join(', ')]
|
570
|
+
end
|
571
|
+
|
572
|
+
info << colorize(:cyan, "Operating system support\n")
|
573
|
+
info << format_table(supported, 2).to_s
|
574
|
+
info << "\n\n"
|
575
|
+
end
|
576
|
+
|
577
|
+
if metadata['dependencies']&.any?
|
578
|
+
dependencies = metadata['dependencies'].map do |dep|
|
579
|
+
[dep['name'], dep['version_requirement']]
|
504
580
|
end
|
505
581
|
|
506
|
-
|
582
|
+
info << colorize(:cyan, "Dependencies\n")
|
583
|
+
info << format_table(dependencies, 2).to_s
|
584
|
+
info << "\n\n"
|
507
585
|
end
|
586
|
+
|
587
|
+
info << colorize(:cyan, "Path\n")
|
588
|
+
info << if path.start_with?(Bolt::Config::Modulepath::MODULES_PATH) ||
|
589
|
+
path.start_with?(Bolt::Config::Modulepath::BOLTLIB_PATH)
|
590
|
+
indent(2, 'built-in module')
|
591
|
+
else
|
592
|
+
indent(2, path)
|
593
|
+
end
|
594
|
+
|
595
|
+
@stream.puts info
|
508
596
|
end
|
509
597
|
|
510
598
|
def print_plugin_list(plugin_list, modulepath)
|
@@ -665,6 +753,12 @@ module Bolt
|
|
665
753
|
print_container_result(value.result)
|
666
754
|
when Bolt::ResultSet
|
667
755
|
print_result_set(value)
|
756
|
+
when Bolt::Result
|
757
|
+
print_result(value)
|
758
|
+
when Bolt::ApplyResult
|
759
|
+
print_apply_result(value)
|
760
|
+
when Bolt::Error
|
761
|
+
print_bolt_error(**value.to_h.transform_keys(&:to_sym))
|
668
762
|
else
|
669
763
|
@stream.puts(::JSON.pretty_generate(plan_result, quirks_mode: true))
|
670
764
|
end
|
@@ -704,6 +798,17 @@ module Bolt
|
|
704
798
|
@stream.puts(colorize(:red, message))
|
705
799
|
end
|
706
800
|
|
801
|
+
def print_bolt_error(msg:, details:, **_kwargs)
|
802
|
+
err = msg
|
803
|
+
if (f = details[:file])
|
804
|
+
err += "\n (file: #{f}"
|
805
|
+
err += ", line: #{details[:line]}" if details[:line]
|
806
|
+
err += ", column: #{details[:column]}" if details[:column]
|
807
|
+
err += ")"
|
808
|
+
end
|
809
|
+
@stream.puts(colorize(:red, err))
|
810
|
+
end
|
811
|
+
|
707
812
|
def print_prompt(prompt)
|
708
813
|
@stream.print(colorize(:cyan, indent(4, prompt)))
|
709
814
|
end
|
data/lib/bolt/outputter/json.rb
CHANGED
@@ -47,6 +47,7 @@ module Bolt
|
|
47
47
|
@stream.puts results.to_json
|
48
48
|
end
|
49
49
|
alias print_module_list print_table
|
50
|
+
alias print_module_info print_table
|
50
51
|
|
51
52
|
def print_task_info(task)
|
52
53
|
path = task.files.first['path'].chomp("/tasks/#{task.files.first['name']}")
|
@@ -98,11 +99,8 @@ module Bolt
|
|
98
99
|
print_table('topics' => topics)
|
99
100
|
end
|
100
101
|
|
101
|
-
def print_guide(
|
102
|
-
@stream.puts(
|
103
|
-
'topic' => topic,
|
104
|
-
'guide' => guide
|
105
|
-
}.to_json)
|
102
|
+
def print_guide(**kwargs)
|
103
|
+
@stream.puts(kwargs.to_json)
|
106
104
|
end
|
107
105
|
|
108
106
|
def print_plan_lookup(value)
|
data/lib/bolt/pal.rb
CHANGED
@@ -339,7 +339,7 @@ module Bolt
|
|
339
339
|
end
|
340
340
|
|
341
341
|
# Write the cache if any entries were updated
|
342
|
-
File.write(@project.task_cache_file, task_cache.to_json) if updated
|
342
|
+
File.write(@project.task_cache_file, task_cache.to_json) if updated && @project
|
343
343
|
filter_content ? filter_content(task_list, @project&.tasks) : task_list
|
344
344
|
end
|
345
345
|
|
@@ -435,7 +435,7 @@ module Bolt
|
|
435
435
|
list << [plan_name, data['description']] unless data['private']
|
436
436
|
end
|
437
437
|
|
438
|
-
File.write(@project.plan_cache_file, plan_cache.to_json) if updated
|
438
|
+
File.write(@project.plan_cache_file, plan_cache.to_json) if updated && @project
|
439
439
|
|
440
440
|
filter_content ? filter_content(plan_list, @project&.plans) : plan_list
|
441
441
|
end
|
@@ -635,6 +635,36 @@ module Bolt
|
|
635
635
|
end
|
636
636
|
end
|
637
637
|
|
638
|
+
# Return information about a module.
|
639
|
+
#
|
640
|
+
# @param name [String] The name of the module.
|
641
|
+
# @return [Hash]
|
642
|
+
#
|
643
|
+
def show_module(name)
|
644
|
+
name = name.tr('-', '/')
|
645
|
+
|
646
|
+
data = in_bolt_compiler do |_compiler|
|
647
|
+
mod = Puppet.lookup(:current_environment).module(name.split(%r{[/-]}, 2).last)
|
648
|
+
|
649
|
+
unless mod && (mod.forge_name == name || mod.name == name)
|
650
|
+
raise Bolt::Error.new("Could not find module '#{name}' on the modulepath.", 'bolt/unknown-module')
|
651
|
+
end
|
652
|
+
|
653
|
+
{
|
654
|
+
name: mod.forge_name || mod.name,
|
655
|
+
metadata: mod.metadata,
|
656
|
+
path: mod.path,
|
657
|
+
plans: mod.plans.map(&:name).sort,
|
658
|
+
tasks: mod.tasks.map(&:name).sort
|
659
|
+
}
|
660
|
+
end
|
661
|
+
|
662
|
+
data[:plans] = list_plans_with_cache.to_h.slice(*data[:plans]).to_a
|
663
|
+
data[:tasks] = list_tasks_with_cache.to_h.slice(*data[:tasks]).to_a
|
664
|
+
|
665
|
+
data
|
666
|
+
end
|
667
|
+
|
638
668
|
def generate_types(cache: false)
|
639
669
|
require 'puppet/face/generate'
|
640
670
|
in_bolt_compiler do
|
@@ -683,7 +713,10 @@ module Bolt
|
|
683
713
|
# Create a Fiber for the main plan. This will be run along with any
|
684
714
|
# other Fibers created during the plan run in the round_robin, with the
|
685
715
|
# main plan always taking precedence in being resumed.
|
686
|
-
|
716
|
+
#
|
717
|
+
# Every future except for the main plan needs to have a plan id in
|
718
|
+
# order to be tracked for the `wait()` function with no arguments.
|
719
|
+
future = executor.create_future(name: plan_name, plan_id: 1) do |_scope|
|
687
720
|
r = compiler.call_function('run_plan', plan_name, params.merge('_bolt_api_call' => true))
|
688
721
|
Bolt::PlanResult.from_pcore(r, 'success')
|
689
722
|
rescue Bolt::Error => e
|
@@ -13,6 +13,7 @@ module Bolt
|
|
13
13
|
download
|
14
14
|
eval
|
15
15
|
message
|
16
|
+
verbose
|
16
17
|
plan
|
17
18
|
resources
|
18
19
|
script
|
@@ -219,3 +220,4 @@ require 'bolt/pal/yaml_plan/step/task'
|
|
219
220
|
require 'bolt/pal/yaml_plan/step/upload'
|
220
221
|
require 'bolt/pal/yaml_plan/step/download'
|
221
222
|
require 'bolt/pal/yaml_plan/step/message'
|
223
|
+
require 'bolt/pal/yaml_plan/step/verbose'
|
@@ -24,14 +24,6 @@ module Bolt
|
|
24
24
|
private def function
|
25
25
|
'out::message'
|
26
26
|
end
|
27
|
-
|
28
|
-
# Transpiles the step into the plan language
|
29
|
-
#
|
30
|
-
def transpile
|
31
|
-
code = String.new(" ")
|
32
|
-
code << function_call(function, format_args(body))
|
33
|
-
code << "\n"
|
34
|
-
end
|
35
27
|
end
|
36
28
|
end
|
37
29
|
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bolt
|
4
|
+
class PAL
|
5
|
+
class YamlPlan
|
6
|
+
class Step
|
7
|
+
class Verbose < Step
|
8
|
+
def self.allowed_keys
|
9
|
+
super + Set['verbose']
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.required_keys
|
13
|
+
Set['verbose']
|
14
|
+
end
|
15
|
+
|
16
|
+
# Returns an array of arguments to pass to the step's function call
|
17
|
+
#
|
18
|
+
private def format_args(body)
|
19
|
+
[body['verbose']]
|
20
|
+
end
|
21
|
+
|
22
|
+
# Returns the function corresponding to the step
|
23
|
+
#
|
24
|
+
private def function
|
25
|
+
'out::verbose'
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/lib/bolt/plan_future.rb
CHANGED
@@ -5,13 +5,28 @@ require 'fiber'
|
|
5
5
|
module Bolt
|
6
6
|
class PlanFuture
|
7
7
|
attr_reader :fiber, :id
|
8
|
-
attr_accessor :value
|
8
|
+
attr_accessor :value, :plan_stack
|
9
9
|
|
10
|
-
def initialize(fiber, id, name
|
11
|
-
@fiber
|
12
|
-
@id
|
13
|
-
@name
|
14
|
-
@value
|
10
|
+
def initialize(fiber, id, plan_id:, name: nil)
|
11
|
+
@fiber = fiber
|
12
|
+
@id = id
|
13
|
+
@name = name
|
14
|
+
@value = nil
|
15
|
+
# The plan invocation ID when the Future is created may be
|
16
|
+
# different from the plan ID of the Future when we switch to it if a new
|
17
|
+
# plan was run inside the Future, so keep track of the plans that a
|
18
|
+
# Future is executing in as a stack. When one plan finishes, pop it off
|
19
|
+
# since now we're in the calling plan. These IDs are unique to each plan
|
20
|
+
# invocation, not just plan names.
|
21
|
+
@plan_stack = [plan_id]
|
22
|
+
end
|
23
|
+
|
24
|
+
def original_plan
|
25
|
+
@plan_stack.last
|
26
|
+
end
|
27
|
+
|
28
|
+
def current_plan
|
29
|
+
@plan_stack.first
|
15
30
|
end
|
16
31
|
|
17
32
|
def name
|
@@ -47,7 +47,9 @@ module Bolt
|
|
47
47
|
cmd = []
|
48
48
|
# BatchMode is SSH's noninteractive option: if key authentication
|
49
49
|
# fails it will error out instead of falling back to password prompt
|
50
|
-
|
50
|
+
batch_mode = @target.transport_config['batch-mode'] ? 'yes' : 'no'
|
51
|
+
cmd += %W[-o BatchMode=#{batch_mode}]
|
52
|
+
|
51
53
|
cmd += %W[-o Port=#{@target.port}] if @target.port
|
52
54
|
|
53
55
|
if @target.transport_config.key?('host-key-check')
|
data/lib/bolt/version.rb
CHANGED
@@ -389,6 +389,63 @@ module BoltServer
|
|
389
389
|
end
|
390
390
|
end
|
391
391
|
|
392
|
+
# The provided block takes a module object and returns the list
|
393
|
+
# of directories to search through. This is similar to
|
394
|
+
# Bolt::Applicator.build_plugin_tarball.
|
395
|
+
def build_project_plugins_tarball(versioned_project, &block)
|
396
|
+
start_time = Time.now
|
397
|
+
|
398
|
+
# Fetch the plugin files
|
399
|
+
plugin_files = in_bolt_project(versioned_project) do |context|
|
400
|
+
files = {}
|
401
|
+
|
402
|
+
# Bolt also sets plugin_modulepath to user modulepath so do it here too for
|
403
|
+
# consistency
|
404
|
+
plugin_modulepath = context[:pal].user_modulepath
|
405
|
+
Puppet.lookup(:current_environment).override_with(modulepath: plugin_modulepath).modules.each do |mod|
|
406
|
+
search_dirs = block.call(mod)
|
407
|
+
|
408
|
+
files[mod] ||= []
|
409
|
+
Find.find(*search_dirs).each do |file|
|
410
|
+
files[mod] << file if File.file?(file)
|
411
|
+
end
|
412
|
+
end
|
413
|
+
|
414
|
+
files
|
415
|
+
end
|
416
|
+
|
417
|
+
# Pack the plugin files
|
418
|
+
sio = StringIO.new
|
419
|
+
begin
|
420
|
+
output = Minitar::Output.new(Zlib::GzipWriter.new(sio))
|
421
|
+
|
422
|
+
plugin_files.each do |mod, files|
|
423
|
+
tar_dir = Pathname.new(mod.name)
|
424
|
+
mod_dir = Pathname.new(mod.path)
|
425
|
+
|
426
|
+
files.each do |file|
|
427
|
+
tar_path = tar_dir + Pathname.new(file).relative_path_from(mod_dir)
|
428
|
+
stat = File.stat(file)
|
429
|
+
content = File.binread(file)
|
430
|
+
output.tar.add_file_simple(
|
431
|
+
tar_path.to_s,
|
432
|
+
data: content,
|
433
|
+
size: content.size,
|
434
|
+
mode: stat.mode & 0o777,
|
435
|
+
mtime: stat.mtime
|
436
|
+
)
|
437
|
+
end
|
438
|
+
end
|
439
|
+
|
440
|
+
duration = Time.now - start_time
|
441
|
+
@logger.trace("Packed plugins in #{duration * 1000} ms")
|
442
|
+
ensure
|
443
|
+
output.close
|
444
|
+
end
|
445
|
+
|
446
|
+
Base64.encode64(sio.string)
|
447
|
+
end
|
448
|
+
|
392
449
|
get '/' do
|
393
450
|
200
|
394
451
|
end
|
@@ -441,7 +498,7 @@ module BoltServer
|
|
441
498
|
'uri' => target_hash['hostname'],
|
442
499
|
'config' => {
|
443
500
|
'transport' => 'ssh',
|
444
|
-
'ssh' => opts
|
501
|
+
'ssh' => opts.slice(*Bolt::Config::Transport::SSH.options)
|
445
502
|
}
|
446
503
|
}
|
447
504
|
|
@@ -479,7 +536,7 @@ module BoltServer
|
|
479
536
|
'uri' => target_hash['hostname'],
|
480
537
|
'config' => {
|
481
538
|
'transport' => 'winrm',
|
482
|
-
'winrm' => opts
|
539
|
+
'winrm' => opts.slice(*Bolt::Config::Transport::WinRM.options)
|
483
540
|
}
|
484
541
|
}
|
485
542
|
|
@@ -699,60 +756,34 @@ module BoltServer
|
|
699
756
|
raise BoltServer::RequestError, "'versioned_project' is a required argument" if params['versioned_project'].nil?
|
700
757
|
content_type :json
|
701
758
|
|
702
|
-
|
703
|
-
|
704
|
-
|
705
|
-
|
706
|
-
|
707
|
-
files = {}
|
708
|
-
|
709
|
-
# Bolt also sets plugin_modulepath to user modulepath so do it here too for
|
710
|
-
# consistency
|
711
|
-
plugin_modulepath = context[:pal].user_modulepath
|
712
|
-
Puppet.lookup(:current_environment).override_with(modulepath: plugin_modulepath).modules.each do |mod|
|
713
|
-
search_dirs = []
|
714
|
-
search_dirs << mod.plugins if mod.plugins?
|
715
|
-
search_dirs << mod.pluginfacts if mod.pluginfacts?
|
716
|
-
|
717
|
-
files[mod] ||= []
|
718
|
-
Find.find(*search_dirs).each do |file|
|
719
|
-
files[mod] << file if File.file?(file)
|
720
|
-
end
|
721
|
-
end
|
722
|
-
|
723
|
-
files
|
759
|
+
plugins_tarball = build_project_plugins_tarball(params['versioned_project']) do |mod|
|
760
|
+
search_dirs = []
|
761
|
+
search_dirs << mod.plugins if mod.plugins?
|
762
|
+
search_dirs << mod.pluginfacts if mod.pluginfacts?
|
763
|
+
search_dirs
|
724
764
|
end
|
725
765
|
|
726
|
-
|
727
|
-
|
728
|
-
begin
|
729
|
-
output = Minitar::Output.new(Zlib::GzipWriter.new(sio))
|
730
|
-
|
731
|
-
plugin_files.each do |mod, files|
|
732
|
-
tar_dir = Pathname.new(mod.name)
|
733
|
-
mod_dir = Pathname.new(mod.path)
|
766
|
+
[200, plugins_tarball.to_json]
|
767
|
+
end
|
734
768
|
|
735
|
-
|
736
|
-
|
737
|
-
|
738
|
-
|
739
|
-
|
740
|
-
|
741
|
-
data: content,
|
742
|
-
size: content.size,
|
743
|
-
mode: stat.mode & 0o777,
|
744
|
-
mtime: stat.mtime
|
745
|
-
)
|
746
|
-
end
|
747
|
-
end
|
769
|
+
# Returns the base64 encoded tar archive of _all_ plugin code for a project
|
770
|
+
#
|
771
|
+
# @param versioned_project [String] the versioned_project to build the plugin tarball from
|
772
|
+
get '/project_plugin_tarball' do
|
773
|
+
raise BoltServer::RequestError, "'versioned_project' is a required argument" if params['versioned_project'].nil?
|
774
|
+
content_type :json
|
748
775
|
|
749
|
-
|
750
|
-
|
751
|
-
|
752
|
-
|
776
|
+
plugins_tarball = build_project_plugins_tarball(params['versioned_project']) do |mod|
|
777
|
+
search_dirs = []
|
778
|
+
search_dirs << mod.plugins if mod.plugins?
|
779
|
+
search_dirs << mod.pluginfacts if mod.pluginfacts?
|
780
|
+
search_dirs << mod.files if mod.files?
|
781
|
+
type_files = "#{mod.path}/types"
|
782
|
+
search_dirs << type_files if File.exist?(type_files)
|
783
|
+
search_dirs
|
753
784
|
end
|
754
785
|
|
755
|
-
[200,
|
786
|
+
[200, plugins_tarball.to_json]
|
756
787
|
end
|
757
788
|
|
758
789
|
error 404 do
|