kontena-cli 1.0.6 → 1.1.0.pre1
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 +4 -4
- data/Dockerfile +1 -1
- data/VERSION +1 -1
- data/bin/kontena +4 -1
- data/kontena-cli.gemspec +1 -1
- data/lib/kontena/callback.rb +1 -1
- data/lib/kontena/callbacks/master/01_clear_current_master_after_terminate.rb +1 -1
- data/lib/kontena/callbacks/master/deploy/50_authenticate_after_deploy.rb +5 -5
- data/lib/kontena/callbacks/master/deploy/55_create_initial_grid_after_deploy.rb +1 -1
- data/lib/kontena/callbacks/master/deploy/56_set_server_provider_after_deploy.rb +25 -0
- data/lib/kontena/callbacks/master/deploy/70_invite_self_after_deploy.rb +1 -1
- data/lib/kontena/cli/common.rb +3 -3
- data/lib/kontena/cli/config.rb +1 -1
- data/lib/kontena/cli/grid_command.rb +2 -0
- data/lib/kontena/cli/grids/common.rb +12 -0
- data/lib/kontena/cli/grids/health_command.rb +69 -0
- data/lib/kontena/cli/helpers/health_helper.rb +53 -0
- data/lib/kontena/cli/localhost_web_server.rb +3 -3
- data/lib/kontena/cli/master/users/invite_command.rb +1 -1
- data/lib/kontena/cli/node_command.rb +2 -0
- data/lib/kontena/cli/nodes/health_command.rb +32 -0
- data/lib/kontena/cli/nodes/list_command.rb +40 -26
- data/lib/kontena/cli/nodes/show_command.rb +0 -1
- data/lib/kontena/cli/plugins/install_command.rb +28 -30
- data/lib/kontena/cli/plugins/search_command.rb +6 -14
- data/lib/kontena/cli/plugins/uninstall_command.rb +7 -11
- data/lib/kontena/cli/services/stats_command.rb +4 -2
- data/lib/kontena/cli/spinner.rb +20 -4
- data/lib/kontena/cli/stacks/show_command.rb +5 -1
- data/lib/kontena/cli/stacks/yaml/opto/service_instances_resolver.rb +22 -0
- data/lib/kontena/cli/stacks/yaml/opto/vault_setter.rb +1 -1
- data/lib/kontena/cli/stacks/yaml/reader.rb +1 -0
- data/lib/kontena/cli/vault/export_command.rb +22 -0
- data/lib/kontena/cli/vault/import_command.rb +80 -0
- data/lib/kontena/cli/vault/list_command.rb +4 -0
- data/lib/kontena/cli/vault/read_command.rb +8 -3
- data/lib/kontena/cli/vault/remove_command.rb +2 -1
- data/lib/kontena/cli/vault/update_command.rb +5 -7
- data/lib/kontena/cli/vault_command.rb +5 -1
- data/lib/kontena/client.rb +25 -2
- data/lib/kontena/command.rb +1 -1
- data/lib/kontena/debug_instrumentor.rb +70 -0
- data/lib/kontena/light_prompt.rb +103 -0
- data/lib/kontena/plugin_manager.rb +167 -6
- data/lib/kontena/stacks_cache.rb +1 -1
- data/lib/kontena_cli.rb +23 -6
- data/spec/kontena/cli/grids/health_command_spec.rb +390 -0
- data/spec/kontena/cli/nodes/health_command_spec.rb +206 -0
- data/spec/kontena/cli/nodes/list_command_spec.rb +205 -0
- data/spec/kontena/cli/vault/export_spec.rb +32 -0
- data/spec/kontena/cli/vault/import_spec.rb +69 -0
- data/spec/kontena/client_spec.rb +39 -0
- data/spec/kontena/plugin_manager_spec.rb +7 -7
- data/spec/spec_helper.rb +1 -0
- data/spec/support/output_helpers.rb +51 -0
- metadata +27 -6
@@ -1,8 +1,10 @@
|
|
1
|
-
require_relative 'vault/
|
1
|
+
require_relative 'vault/export_command'
|
2
|
+
require_relative 'vault/import_command'
|
2
3
|
require_relative 'vault/list_command'
|
3
4
|
require_relative 'vault/read_command'
|
4
5
|
require_relative 'vault/remove_command'
|
5
6
|
require_relative 'vault/update_command'
|
7
|
+
require_relative 'vault/write_command'
|
6
8
|
|
7
9
|
class Kontena::Cli::VaultCommand < Kontena::Command
|
8
10
|
|
@@ -11,6 +13,8 @@ class Kontena::Cli::VaultCommand < Kontena::Command
|
|
11
13
|
subcommand "read", "Read secret", Kontena::Cli::Vault::ReadCommand
|
12
14
|
subcommand "update", "Update secret", Kontena::Cli::Vault::UpdateCommand
|
13
15
|
subcommand ["remove", "rm"], "Remove secret", Kontena::Cli::Vault::RemoveCommand
|
16
|
+
subcommand "export", "Export secrets to STDOUT", Kontena::Cli::Vault::ExportCommand
|
17
|
+
subcommand "import", "Import secrets from a file or STDIN", Kontena::Cli::Vault::ImportCommand
|
14
18
|
|
15
19
|
def execute
|
16
20
|
end
|
data/lib/kontena/client.rb
CHANGED
@@ -23,6 +23,7 @@ module Kontena
|
|
23
23
|
CONTENT_JSON = 'application/json'.freeze
|
24
24
|
JSON_REGEX = /application\/(.+?\+)?json/.freeze
|
25
25
|
CONTENT_TYPE = 'Content-Type'.freeze
|
26
|
+
X_KONTENA_VERSION = 'X-Kontena-Version'.freeze
|
26
27
|
ACCEPT = 'Accept'.freeze
|
27
28
|
AUTHORIZATION = 'Authorization'.freeze
|
28
29
|
|
@@ -46,7 +47,7 @@ module Kontena
|
|
46
47
|
uri = URI.parse(@api_url)
|
47
48
|
@host = uri.host
|
48
49
|
|
49
|
-
@logger = Logger.new(STDOUT)
|
50
|
+
@logger = Logger.new(ENV["DEBUG"] ? STDERR : STDOUT)
|
50
51
|
@logger.level = ENV["DEBUG"].nil? ? Logger::INFO : Logger::DEBUG
|
51
52
|
@logger.progname = 'CLIENT'
|
52
53
|
|
@@ -59,6 +60,10 @@ module Kontena
|
|
59
60
|
write_timeout: ENV["EXCON_WRITE_TIMEOUT"] ? ENV["EXCON_WRITE_TIMEOUT"].to_i : 5,
|
60
61
|
ssl_verify_peer: ignore_ssl_errors? ? false : true
|
61
62
|
}
|
63
|
+
if ENV["DEBUG"]
|
64
|
+
require_relative 'debug_instrumentor'
|
65
|
+
excon_opts[:instrumentor] = Kontena::DebugInstrumentor
|
66
|
+
end
|
62
67
|
|
63
68
|
cert_file = File.join(Dir.home, "/.kontena/certs/#{uri.host}.pem")
|
64
69
|
if File.exist?(cert_file) && File.readable?(cert_file)
|
@@ -135,7 +140,7 @@ module Kontena
|
|
135
140
|
request(path: final_path)
|
136
141
|
true
|
137
142
|
rescue
|
138
|
-
|
143
|
+
logger.debug "Authentication verification exception: #{$!} #{$!.message} #{$!.backtrace}"
|
139
144
|
false
|
140
145
|
end
|
141
146
|
|
@@ -473,6 +478,8 @@ module Kontena
|
|
473
478
|
# @param [Excon::Response]
|
474
479
|
# @return [Hash,String]
|
475
480
|
def parse_response(response)
|
481
|
+
check_version_and_warn(response.headers[X_KONTENA_VERSION])
|
482
|
+
|
476
483
|
if response.headers[CONTENT_TYPE] =~ JSON_REGEX
|
477
484
|
parse_json(response.body)
|
478
485
|
else
|
@@ -480,6 +487,22 @@ module Kontena
|
|
480
487
|
end
|
481
488
|
end
|
482
489
|
|
490
|
+
def check_version_and_warn(server_version)
|
491
|
+
return nil if $VERSION_WARNING_ADDED
|
492
|
+
return nil unless server_version.to_s =~ /^\d+\.\d+\.\d+/
|
493
|
+
|
494
|
+
unless server_version[/^(\d+\.\d+)/, 1] == Kontena::Cli::VERSION[/^(\d+\.\d+)/, 1] # Just compare x.y
|
495
|
+
add_version_warning(server_version)
|
496
|
+
$VERSION_WARNING_ADDED = true
|
497
|
+
end
|
498
|
+
end
|
499
|
+
|
500
|
+
def add_version_warning(server_version)
|
501
|
+
at_exit do
|
502
|
+
warn Kontena.pastel.yellow("Warning: Server version is #{server_version}. You are using CLI version #{Kontena::Cli::VERSION}.")
|
503
|
+
end
|
504
|
+
end
|
505
|
+
|
483
506
|
# Parse json
|
484
507
|
#
|
485
508
|
# @param [String] json
|
data/lib/kontena/command.rb
CHANGED
@@ -169,7 +169,7 @@ class Kontena::Command < Clamp::Command
|
|
169
169
|
end
|
170
170
|
|
171
171
|
def run(arguments)
|
172
|
-
ENV["DEBUG"] && puts("Running #{self} -- callback matcher = '#{self.class.callback_matcher.nil? ? "nil" : self.class.callback_matcher.map(&:to_s).join(' ')}'")
|
172
|
+
ENV["DEBUG"] && STDERR.puts("Running #{self} -- callback matcher = '#{self.class.callback_matcher.nil? ? "nil" : self.class.callback_matcher.map(&:to_s).join(' ')}'")
|
173
173
|
@arguments = arguments
|
174
174
|
|
175
175
|
run_callbacks :before_parse unless help_requested?
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'uri'
|
2
|
+
module Kontena
|
3
|
+
class DebugInstrumentor
|
4
|
+
def self.instrument(name, params = {}, &block)
|
5
|
+
result = []
|
6
|
+
params = params.dup
|
7
|
+
|
8
|
+
direction = name.split('.').last.capitalize
|
9
|
+
|
10
|
+
if direction == 'Request'
|
11
|
+
uri = URI.parse("#{params[:scheme]}://#{params[:host]}:#{params[:port]}")
|
12
|
+
uri.path = params[:path]
|
13
|
+
uri.query = URI.encode_www_form(params[:query]) if params[:query] && !params[:query].empty?
|
14
|
+
str = "#{params[:method].to_s.upcase} #{uri}"
|
15
|
+
str << " (ssl_verify: #{params[:ssl_verify_peer]}) " if params[:scheme] == 'https'
|
16
|
+
result << str
|
17
|
+
end
|
18
|
+
|
19
|
+
if params[:headers]
|
20
|
+
str = "Headers: {"
|
21
|
+
heads = []
|
22
|
+
heads << "Accept: #{params[:headers]['Accept']}" if params[:headers]['Accept']
|
23
|
+
heads << "Content-Type: #{params[:headers]['Content-Type']}" if params[:headers]['Content-Type']
|
24
|
+
heads << "Authorization: #{params[:headers]['Authorization'].split(' ', 2).first}" if params[:headers]['Authorization']
|
25
|
+
str << heads.join(', ')
|
26
|
+
str << "} "
|
27
|
+
result << str
|
28
|
+
end
|
29
|
+
|
30
|
+
if params[:status]
|
31
|
+
str = "Status: "
|
32
|
+
if params[:status] < 299
|
33
|
+
str << Kontena.pastel.green(params[:status])
|
34
|
+
else
|
35
|
+
str << Kontena.pastel.red(params[:status])
|
36
|
+
end
|
37
|
+
result << str
|
38
|
+
end
|
39
|
+
|
40
|
+
if params[:body] && !params[:body].empty?
|
41
|
+
str = "Body: "
|
42
|
+
if ENV["DEBUG"] == "api"
|
43
|
+
str << "\n"
|
44
|
+
str << params[:body]
|
45
|
+
else
|
46
|
+
body = params[:body].inspect.strip
|
47
|
+
str << body[0,80]
|
48
|
+
if body.length > 80
|
49
|
+
str << "...\""
|
50
|
+
end
|
51
|
+
end
|
52
|
+
result << str
|
53
|
+
end
|
54
|
+
|
55
|
+
if $stderr.tty?
|
56
|
+
if direction == 'Request'
|
57
|
+
$stderr.puts(Kontena.pastel.blue("[API Client #{direction}]: #{result.join(" | ")}"))
|
58
|
+
else
|
59
|
+
$stderr.puts(Kontena.pastel.magenta("[API Client #{direction}]: #{result.join(" | ")}"))
|
60
|
+
end
|
61
|
+
else
|
62
|
+
$stderr.puts("[API Client #{direction}]: #{result.join(" | ")}")
|
63
|
+
end
|
64
|
+
|
65
|
+
if block_given?
|
66
|
+
yield
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
require 'tty-prompt'
|
2
|
+
require 'pastel'
|
3
|
+
|
4
|
+
module Kontena
|
5
|
+
class LightPrompt
|
6
|
+
|
7
|
+
attr_reader :prompt
|
8
|
+
|
9
|
+
extend Forwardable
|
10
|
+
|
11
|
+
class Menu
|
12
|
+
attr_reader :choices, :calls
|
13
|
+
|
14
|
+
def initialize
|
15
|
+
@choices = []
|
16
|
+
@calls = {}
|
17
|
+
end
|
18
|
+
|
19
|
+
def choice(text, label)
|
20
|
+
choices << [text, label]
|
21
|
+
end
|
22
|
+
|
23
|
+
def add_quit_choice
|
24
|
+
choice('(done)', :done)
|
25
|
+
end
|
26
|
+
|
27
|
+
def remove_choice(value)
|
28
|
+
choices.reject! { |c| c.last == value }
|
29
|
+
end
|
30
|
+
|
31
|
+
def remove_choices(values)
|
32
|
+
values.each { |v| remove_choice(v) }
|
33
|
+
end
|
34
|
+
|
35
|
+
def method_missing(meth, *args)
|
36
|
+
calls[meth] = args
|
37
|
+
end
|
38
|
+
|
39
|
+
def respond_to_missing?(meth, privates = false)
|
40
|
+
prompt.respond_to?(meth, privates)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def initialize(options={})
|
45
|
+
@prompt = TTY::Prompt.new(options)
|
46
|
+
end
|
47
|
+
|
48
|
+
def select(*args, &block)
|
49
|
+
choice_collector = Menu.new
|
50
|
+
yield choice_collector
|
51
|
+
|
52
|
+
prompt.enum_select(*args) do |menu|
|
53
|
+
choice_collector.calls.each do |meth, args|
|
54
|
+
if menu.respond_to?(meth)
|
55
|
+
menu.send(meth, *args)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
choice_collector.choices.each do |choice|
|
59
|
+
menu.choice choice.first, choice.last
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def multi_select(*args, &block)
|
65
|
+
choice_collector = Menu.new
|
66
|
+
yield choice_collector
|
67
|
+
choice_collector.add_quit_choice
|
68
|
+
|
69
|
+
selections = []
|
70
|
+
|
71
|
+
loop do
|
72
|
+
choice_collector.remove_choices(selections)
|
73
|
+
|
74
|
+
answer = prompt.enum_select(*args) do |menu|
|
75
|
+
choice_collector.calls.each do |meth, args|
|
76
|
+
if menu.respond_to?(meth)
|
77
|
+
menu.send(meth, *args)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
choice_collector.choices.each do |choice|
|
81
|
+
menu.choice choice.first, choice.last
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
break if answer == :done
|
86
|
+
selections << answer
|
87
|
+
end
|
88
|
+
|
89
|
+
selections
|
90
|
+
end
|
91
|
+
|
92
|
+
|
93
|
+
def_delegators :prompt, :ask, :yes?, :error
|
94
|
+
|
95
|
+
def method_missing(meth, *args)
|
96
|
+
prompt.send(meth, *args)
|
97
|
+
end
|
98
|
+
|
99
|
+
def respond_to_missing?(meth, privates = false)
|
100
|
+
prompt.respond_to?(meth, privates)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -2,27 +2,174 @@ require 'singleton'
|
|
2
2
|
|
3
3
|
module Kontena
|
4
4
|
class PluginManager
|
5
|
+
|
5
6
|
include Singleton
|
6
7
|
|
7
8
|
CLI_GEM = 'kontena-cli'.freeze
|
8
9
|
MIN_CLI_VERSION = '0.15.99'.freeze
|
9
10
|
|
10
|
-
|
11
|
+
# Initialize plugin manager
|
12
|
+
def init
|
13
|
+
ENV["GEM_HOME"] = install_dir
|
14
|
+
Gem.paths = ENV
|
15
|
+
plugins
|
16
|
+
use_dummy_ui unless ENV["DEBUG"]
|
17
|
+
true
|
18
|
+
end
|
19
|
+
|
20
|
+
# Install a plugin
|
21
|
+
# @param plugin_name [String]
|
22
|
+
# @param pre [Boolean] install a prerelease version if available
|
23
|
+
# @param version [String] install a specific version
|
24
|
+
def install_plugin(plugin_name, pre: false, version: nil)
|
25
|
+
require 'rubygems/dependency_installer'
|
26
|
+
require 'rubygems/requirement'
|
27
|
+
|
28
|
+
cmd = Gem::DependencyInstaller.new(
|
29
|
+
document: false,
|
30
|
+
force: true,
|
31
|
+
prerelease: pre,
|
32
|
+
minimal_deps: true
|
33
|
+
)
|
34
|
+
plugin_version = version.nil? ? Gem::Requirement.default : Gem::Requirement.new(version)
|
35
|
+
without_safe { cmd.install(prefix(plugin_name), plugin_version) }
|
36
|
+
cleanup_plugin(plugin_name)
|
37
|
+
cmd.installed_gems
|
38
|
+
end
|
39
|
+
|
40
|
+
# Uninstall a plugin
|
41
|
+
# @param plugin_name [String]
|
42
|
+
def uninstall_plugin(plugin_name)
|
43
|
+
installed = installed(plugin_name)
|
44
|
+
raise "Plugin #{plugin_name} not installed" unless installed
|
45
|
+
|
46
|
+
require 'rubygems/uninstaller'
|
47
|
+
cmd = Gem::Uninstaller.new(
|
48
|
+
installed.name,
|
49
|
+
all: true,
|
50
|
+
executables: true,
|
51
|
+
force: true,
|
52
|
+
install_dir: installed.base_dir
|
53
|
+
)
|
54
|
+
cmd.uninstall
|
55
|
+
end
|
56
|
+
|
57
|
+
# Search rubygems for kontena plugins
|
58
|
+
# @param pattern [String] optional search pattern
|
59
|
+
def search_plugins(pattern = nil)
|
60
|
+
client = Excon.new('https://rubygems.org')
|
61
|
+
response = client.get(
|
62
|
+
path: "/api/v1/search.json?query=#{prefix(pattern)}",
|
63
|
+
headers: {
|
64
|
+
'Content-Type' => 'application/json',
|
65
|
+
'Accept' => 'application/json'
|
66
|
+
}
|
67
|
+
)
|
68
|
+
|
69
|
+
JSON.parse(response.body) rescue nil
|
70
|
+
end
|
71
|
+
|
72
|
+
# Retrieve plugin versions from rubygems
|
73
|
+
# @param plugin_name [String]
|
74
|
+
def gem_versions(plugin_name)
|
75
|
+
client = Excon.new('https://rubygems.org')
|
76
|
+
response = client.get(
|
77
|
+
path: "/api/v1/versions/#{prefix(plugin_name)}.json",
|
78
|
+
headers: {
|
79
|
+
'Content-Type' => 'application/json',
|
80
|
+
'Accept' => 'application/json'
|
81
|
+
}
|
82
|
+
)
|
83
|
+
versions = JSON.parse(response.body)
|
84
|
+
versions.map { |version| Gem::Version.new(version["number"]) }.sort.reverse
|
85
|
+
end
|
86
|
+
|
87
|
+
# Get the latest version number from rubygems
|
88
|
+
# @param plugin_name [String]
|
89
|
+
# @param pre [Boolean] include prerelease versions
|
90
|
+
def latest_version(plugin_name, pre: false)
|
91
|
+
return gem_versions(plugin_name).first if pre
|
92
|
+
gem_versions(plugin_name).find { |version| !version.prerelease? }
|
93
|
+
end
|
94
|
+
|
95
|
+
# Find a plugin by name from installed plugins
|
96
|
+
# @param plugin_name [String]
|
97
|
+
def installed(plugin_name)
|
98
|
+
search = prefix(plugin_name)
|
99
|
+
plugins.find {|plugin| plugin.name == search }
|
100
|
+
end
|
101
|
+
|
102
|
+
# Upgrade an installed plugin
|
103
|
+
# @param plugin_name [String]
|
104
|
+
# @param pre [Boolean] upgrade to a prerelease version if available. Will happen always when the installed version is a prerelease version.
|
105
|
+
def upgrade_plugin(plugin_name, pre: false)
|
106
|
+
installed = installed(plugin_name)
|
107
|
+
if installed.version.prerelease?
|
108
|
+
pre = true
|
109
|
+
end
|
110
|
+
|
111
|
+
if installed
|
112
|
+
latest = latest_version(plugin_name, pre: pre)
|
113
|
+
if latest > installed.version
|
114
|
+
install_plugin(plugin_name, version: latest.to_s)
|
115
|
+
end
|
116
|
+
else
|
117
|
+
raise "Plugin #{plugin_name} not installed"
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
# Runs gem cleanup, removes remains from previous versions
|
122
|
+
# @param plugin_name [String]
|
123
|
+
def cleanup_plugin(plugin_name)
|
124
|
+
require 'rubygems/commands/cleanup_command'
|
125
|
+
cmd = Gem::Commands::CleanupCommand.new
|
126
|
+
options = ['--norc']
|
127
|
+
options += ['-q', '--no-verbose'] unless ENV["DEBUG"]
|
128
|
+
cmd.handle_options options
|
129
|
+
without_safe { cmd.execute }
|
130
|
+
rescue Gem::SystemExitException => e
|
131
|
+
return true if e.exit_code == 0
|
132
|
+
raise
|
133
|
+
end
|
11
134
|
|
12
|
-
|
13
|
-
|
135
|
+
# Gem installation directory
|
136
|
+
# @return [String]
|
137
|
+
def install_dir
|
138
|
+
return @install_dir if @install_dir
|
139
|
+
install_dir = File.join(Dir.home, '.kontena', 'gems', RUBY_VERSION)
|
140
|
+
unless File.directory?(install_dir)
|
141
|
+
require 'fileutils'
|
142
|
+
FileUtils.mkdir_p(install_dir, mode: 0700)
|
143
|
+
end
|
144
|
+
@install_dir = install_dir
|
14
145
|
end
|
15
146
|
|
147
|
+
|
16
148
|
# @return [Array<Gem::Specification>]
|
149
|
+
def plugins
|
150
|
+
@plugins ||= load_plugins
|
151
|
+
end
|
152
|
+
|
153
|
+
private
|
154
|
+
|
155
|
+
# Execute block without SafeYAML. Gem does security internally.
|
156
|
+
def without_safe(&block)
|
157
|
+
SafeYAML::OPTIONS[:default_mode] = :unsafe if Object.const_defined?(:SafeYAML)
|
158
|
+
yield
|
159
|
+
ensure
|
160
|
+
SafeYAML::OPTIONS[:default_mode] = :safe if Object.const_defined?(:SafeYAML)
|
161
|
+
end
|
162
|
+
|
17
163
|
def load_plugins
|
164
|
+
plugins = []
|
18
165
|
Gem::Specification.to_a.each do |spec|
|
19
166
|
spec.require_paths.to_a.each do |require_path|
|
20
167
|
plugin = File.join(spec.gem_dir, require_path, 'kontena_cli_plugin.rb')
|
21
|
-
if File.exist?(plugin) &&
|
168
|
+
if File.exist?(plugin) && !plugins.find{ |p| p.name == spec.name }
|
22
169
|
begin
|
23
170
|
if spec_has_valid_dependency?(spec)
|
24
171
|
load(plugin)
|
25
|
-
|
172
|
+
plugins << spec
|
26
173
|
else
|
27
174
|
plugin_name = spec.name.sub('kontena-plugin-', '')
|
28
175
|
STDERR.puts " [#{Kontena.pastel.red('error')}] Plugin #{Kontena.pastel.cyan(plugin_name)} (#{spec.version}) is not compatible with the current cli version."
|
@@ -39,11 +186,25 @@ module Kontena
|
|
39
186
|
end
|
40
187
|
end
|
41
188
|
end
|
42
|
-
|
189
|
+
plugins
|
43
190
|
rescue => exc
|
44
191
|
STDERR.puts exc.message
|
45
192
|
end
|
46
193
|
|
194
|
+
def prefix(plugin_name)
|
195
|
+
return plugin_name if plugin_name.to_s.start_with?('kontena-plugin-')
|
196
|
+
"kontena-plugin-#{plugin_name}"
|
197
|
+
end
|
198
|
+
|
199
|
+
def dummy_ui
|
200
|
+
Gem::StreamUI.new(StringIO.new, StringIO.new, StringIO.new, false)
|
201
|
+
end
|
202
|
+
|
203
|
+
def use_dummy_ui
|
204
|
+
require 'rubygems/user_interaction'
|
205
|
+
Gem::DefaultUserInteraction.ui = dummy_ui
|
206
|
+
end
|
207
|
+
|
47
208
|
# @param [Gem::Specification] spec
|
48
209
|
# @return [Boolean]
|
49
210
|
def spec_has_valid_dependency?(spec)
|