kontena-plugin-shell 0.1.0
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 +7 -0
- data/.gitignore +16 -0
- data/.rspec +2 -0
- data/.travis.yml +16 -0
- data/Gemfile +8 -0
- data/LICENSE.txt +191 -0
- data/README.md +105 -0
- data/bin/kosh +37 -0
- data/kontena-plugin-shell.gemspec +26 -0
- data/kosh.gif +0 -0
- data/lib/kontena/plugin/shell.rb +16 -0
- data/lib/kontena/plugin/shell/callbacks/stack_file.rb +31 -0
- data/lib/kontena/plugin/shell/command.rb +85 -0
- data/lib/kontena/plugin/shell/commands/batch.rb +29 -0
- data/lib/kontena/plugin/shell/commands/batch_do.rb +30 -0
- data/lib/kontena/plugin/shell/commands/context_top.rb +22 -0
- data/lib/kontena/plugin/shell/commands/context_up.rb +15 -0
- data/lib/kontena/plugin/shell/commands/debug.rb +29 -0
- data/lib/kontena/plugin/shell/commands/exit.rb +20 -0
- data/lib/kontena/plugin/shell/commands/help.rb +43 -0
- data/lib/kontena/plugin/shell/commands/kontena.rb +57 -0
- data/lib/kontena/plugin/shell/completer.rb +216 -0
- data/lib/kontena/plugin/shell/context.rb +59 -0
- data/lib/kontena/plugin/shell/session.rb +115 -0
- data/lib/kontena/plugin/shell/shell_command.rb +10 -0
- data/lib/kontena/plugin/shell/version.rb +7 -0
- data/lib/kontena_cli_plugin.rb +11 -0
- metadata +127 -0
@@ -0,0 +1,85 @@
|
|
1
|
+
module Kontena::Plugin
|
2
|
+
module Shell
|
3
|
+
class Command
|
4
|
+
|
5
|
+
attr_reader :context, :args, :session
|
6
|
+
|
7
|
+
def self.command(name = nil)
|
8
|
+
return @command if instance_variable_defined?(:@command)
|
9
|
+
disabled_commands = ENV['KOSH_DISABLED_COMMANDS'].to_s.split(/,/)
|
10
|
+
Array(name).each { |name| Shell.commands[name] = self unless disabled_commands.include?(name) }
|
11
|
+
@command = name
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.subcommands(subcommands = nil)
|
15
|
+
return @subcommands if instance_variable_defined?(:@subcommands)
|
16
|
+
@subcommands = {}
|
17
|
+
Array(subcommands).each do |sc|
|
18
|
+
Array(sc.command).each do |name|
|
19
|
+
@subcommands[name] = sc
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.has_subcommands?
|
25
|
+
!subcommands.nil? && !subcommands.empty?
|
26
|
+
end
|
27
|
+
|
28
|
+
def has_subcommands?
|
29
|
+
self.class.has_subcommands?
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.description(text = nil)
|
33
|
+
@description ||= text
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.help(text = nil)
|
37
|
+
@help ||= text
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.completions(*completions)
|
41
|
+
@completions ||= completions
|
42
|
+
end
|
43
|
+
|
44
|
+
def initialize(context = nil, args = nil, session = nil)
|
45
|
+
@args = Array(args)
|
46
|
+
@context = context
|
47
|
+
@session = session
|
48
|
+
end
|
49
|
+
|
50
|
+
def run
|
51
|
+
if has_subcommands?
|
52
|
+
if args[1]
|
53
|
+
subcommand = self.class.subcommands[args[1]]
|
54
|
+
if subcommand
|
55
|
+
subcommand.new(context, args[1..-1], session).run
|
56
|
+
else
|
57
|
+
puts Kontena.pastel.red("Unknown subcommand")
|
58
|
+
end
|
59
|
+
else
|
60
|
+
context << args[0]
|
61
|
+
end
|
62
|
+
else
|
63
|
+
execute
|
64
|
+
end
|
65
|
+
rescue Kontena::Plugin::Shell::ExitCommand::CleanExit
|
66
|
+
puts Kontena.pastel.green("Bye!")
|
67
|
+
exit 0
|
68
|
+
rescue => ex
|
69
|
+
puts Kontena.pastel.red("ERROR: " + ex.message)
|
70
|
+
puts Kontena.pastel.green(ex.backtrace.join("\n ")) if ENV["DEBUG"]
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# SubCommand is just like a command, except it doesn't register the
|
75
|
+
# class to Shell.commands.
|
76
|
+
class SubCommand < Command
|
77
|
+
def self.command(name = nil)
|
78
|
+
@command ||= name
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
Dir[File.expand_path('../commands/**/*.rb', __FILE__)].each { |file| require file }
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'kontena/plugin/shell/command'
|
2
|
+
require 'kontena/plugin/shell/commands/batch_do'
|
3
|
+
|
4
|
+
module Kontena::Plugin
|
5
|
+
module Shell
|
6
|
+
class BatchCommand < Command
|
7
|
+
|
8
|
+
command 'batch'
|
9
|
+
description 'Run/create command batches'
|
10
|
+
help -> (context, tokens) {
|
11
|
+
if tokens && tokens[2] && subcommands[tokens[2]]
|
12
|
+
subcommands[tokens[2]].help
|
13
|
+
else
|
14
|
+
<<-EOB.gsub(/^\s+/, '')
|
15
|
+
To run a series of commands in a batch, use:
|
16
|
+
|
17
|
+
> batch do
|
18
|
+
> command
|
19
|
+
> command 2
|
20
|
+
> end
|
21
|
+
EOB
|
22
|
+
end
|
23
|
+
}
|
24
|
+
|
25
|
+
subcommands [Kontena::Plugin::Shell::BatchDoCommand]
|
26
|
+
completions *subcommands.keys
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'kontena/plugin/shell/command'
|
2
|
+
|
3
|
+
module Kontena::Plugin
|
4
|
+
module Shell
|
5
|
+
class BatchDoCommand < SubCommand
|
6
|
+
|
7
|
+
command 'do'
|
8
|
+
description 'Run a batch of commands'
|
9
|
+
help "Example:\n> batch do\n> master users ls\n> master ls\n> end"
|
10
|
+
completions nil
|
11
|
+
|
12
|
+
def execute
|
13
|
+
if args.size > 1
|
14
|
+
lines = args[1..-1].join(' ').split(/(?<!\\);/).map(&:strip)
|
15
|
+
else
|
16
|
+
lines = []
|
17
|
+
while buf = Readline.readline("#{Kontena.pastel.green('..')}#{Kontena.pastel.red('>')} ", true)
|
18
|
+
buf.strip!
|
19
|
+
break if buf == 'end'
|
20
|
+
lines << buf unless buf.empty?
|
21
|
+
end
|
22
|
+
(lines.size + 1).times { Readline::HISTORY.pop }
|
23
|
+
Readline::HISTORY.push "batch do #{lines.join('; ')}"
|
24
|
+
end
|
25
|
+
|
26
|
+
lines.each { |line| session.run_command(line) }
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'kontena/plugin/shell/command'
|
2
|
+
|
3
|
+
module Kontena::Plugin
|
4
|
+
module Shell
|
5
|
+
class ContextTopCommand < Command
|
6
|
+
command '/'
|
7
|
+
description 'Clear context'
|
8
|
+
help "Go to top in context.\n\nYou can also directly call other commands without switching context first by using for example #{Kontena.pastel.yellow('/ master ls')}"
|
9
|
+
|
10
|
+
def execute
|
11
|
+
if args[1] && session
|
12
|
+
old_context = context.to_a.clone
|
13
|
+
context.top
|
14
|
+
session.run_command(args[1..-1].join(' '))
|
15
|
+
context.concat(old_context)
|
16
|
+
else
|
17
|
+
context.top
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'kontena/plugin/shell/command'
|
2
|
+
|
3
|
+
module Kontena::Plugin
|
4
|
+
module Shell
|
5
|
+
class DebugCommand < Command
|
6
|
+
command 'debug'
|
7
|
+
description 'Toggle debug output'
|
8
|
+
help 'Use debug on/off to toggle debug output.'
|
9
|
+
|
10
|
+
completions 'on', 'off', 'api'
|
11
|
+
|
12
|
+
def execute
|
13
|
+
case args[1]
|
14
|
+
when 'true', 'on', '1'
|
15
|
+
ENV['DEBUG'] = 'true'
|
16
|
+
when 'api'
|
17
|
+
ENV['DEBUG'] = 'api'
|
18
|
+
when 'off', 'false', '0'
|
19
|
+
ENV.delete('DEBUG')
|
20
|
+
when NilClass
|
21
|
+
# do nothing
|
22
|
+
else
|
23
|
+
puts Kontena.pastel.red("Unknown argument '#{args[1]}'")
|
24
|
+
end
|
25
|
+
puts "Debug #{Kontena.pastel.send(*ENV['DEBUG'] ? [:green, 'on'] : [:red, 'off'])}"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'kontena/plugin/shell/command'
|
2
|
+
|
3
|
+
module Kontena::Plugin
|
4
|
+
module Shell
|
5
|
+
class ExitCommand < Command
|
6
|
+
command 'exit'
|
7
|
+
description 'Quit shell'
|
8
|
+
help 'Enter "exit" to quit.'
|
9
|
+
|
10
|
+
completions nil
|
11
|
+
|
12
|
+
CleanExit = Class.new(StandardError)
|
13
|
+
|
14
|
+
def execute
|
15
|
+
raise CleanExit
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'kontena/plugin/shell/command'
|
2
|
+
|
3
|
+
module Kontena::Plugin
|
4
|
+
module Shell
|
5
|
+
class HelpCommand < Command
|
6
|
+
command 'help'
|
7
|
+
description 'Show help'
|
8
|
+
help 'Use "help <command>" to see help for a specific command'
|
9
|
+
#completions -> (context, tokens, word) { Kontena::Completer.complete(context.to_a + tokens) }
|
10
|
+
|
11
|
+
def cmd
|
12
|
+
full_line = context + args[1..-1]
|
13
|
+
cmd = Shell.command(full_line.first) || Shell.command('kontena')
|
14
|
+
end
|
15
|
+
|
16
|
+
def execute
|
17
|
+
if cmd.help.respond_to?(:call)
|
18
|
+
help_text = cmd.help.call(context, args[1..-1])
|
19
|
+
else
|
20
|
+
help_text = cmd.help
|
21
|
+
end
|
22
|
+
puts help_text
|
23
|
+
|
24
|
+
if cmd.has_subcommands?
|
25
|
+
puts
|
26
|
+
puts Kontena.pastel.green("Subcommands:")
|
27
|
+
cmd.subcommands.each do |name, sc|
|
28
|
+
puts sprintf(' %-29s %s', name, sc.description)
|
29
|
+
end
|
30
|
+
puts
|
31
|
+
end
|
32
|
+
|
33
|
+
if args.empty? || (args.size == 1 && args.first == 'help')
|
34
|
+
puts Kontena.pastel.green('KOSH commands:')
|
35
|
+
Shell.commands.each do |name, cmd|
|
36
|
+
next if cmd == Kontena::Plugin::Shell::KontenaCommand
|
37
|
+
puts sprintf(' %-29s %s', name, cmd.description)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'kontena/main_command' unless Kontena.const_defined?(:MainCommand)
|
2
|
+
require 'kontena/plugin/shell/command'
|
3
|
+
require 'kontena/plugin/shell/completer'
|
4
|
+
require 'kontena/plugin/shell/context'
|
5
|
+
|
6
|
+
module Kontena::Plugin
|
7
|
+
module Shell
|
8
|
+
class KontenaCommand < Command
|
9
|
+
|
10
|
+
command ['kontena'] + Kontena::MainCommand.recognised_subcommands.flat_map(&:names)
|
11
|
+
description 'Run Kontena-cli command'
|
12
|
+
help -> (context, tokens) { new(context, tokens).subcommand_class.help('').gsub(/^(\s+)\[OPTIONS\] SUB/, "\\1 SUB") }
|
13
|
+
completions -> (context, tokens, word) { Kontena::Plugin::Shell::Completer.complete(context.to_a + tokens) }
|
14
|
+
|
15
|
+
def cmd
|
16
|
+
cmd = Kontena::MainCommand.new('')
|
17
|
+
cmdline = context.to_a + args
|
18
|
+
cmdline.shift if cmdline.first == 'kontena'
|
19
|
+
cmd.parse(cmdline)
|
20
|
+
cmd
|
21
|
+
end
|
22
|
+
|
23
|
+
def execute
|
24
|
+
cmd.run([])
|
25
|
+
rescue Clamp::HelpWanted => ex
|
26
|
+
unless args.include?('--help') || args.include?('-h')
|
27
|
+
context.concat(args)
|
28
|
+
end
|
29
|
+
rescue SystemExit => ex
|
30
|
+
puts Kontena.pastel.red('[Command exited with error]') unless ex.status.zero?
|
31
|
+
rescue => ex
|
32
|
+
puts Kontena.pastel.red("ERROR: #{ex.message}")
|
33
|
+
end
|
34
|
+
|
35
|
+
def subcommand_class
|
36
|
+
(context + args).reject { |t| t.start_with?('-') }.inject(Kontena::MainCommand) do |base, token|
|
37
|
+
if base.has_subcommands?
|
38
|
+
sc = base.recognised_subcommands.find { |sc| sc.names.include?(token) }
|
39
|
+
sc ? sc.subcommand_class : base
|
40
|
+
else
|
41
|
+
base
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
if ENV["KOSH_DISABLED_COMMANDS"]
|
50
|
+
ENV["KOSH_DISABLED_COMMANDS"].split(',').each do |command|
|
51
|
+
tokens = command.split(' ')
|
52
|
+
subcommand = tokens.pop
|
53
|
+
kontena = Kontena::Plugin::Shell::KontenaCommand.new(Kontena::Plugin::Shell::Context.new(tokens))
|
54
|
+
found_subcommand = kontena.subcommand_class
|
55
|
+
found_subcommand.recognised_subcommands.delete_if { |sc| sc.names.include?(subcommand) }
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,216 @@
|
|
1
|
+
# this is mostly just a wrapped version of the completer in cli
|
2
|
+
require 'kontena/cli/common' unless Kontena.const_defined?(:Cli) && Kontena::Cli.const_defined?(:Common)
|
3
|
+
require 'yaml'
|
4
|
+
|
5
|
+
module Kontena::Plugin::Shell
|
6
|
+
module Completer
|
7
|
+
class Helper
|
8
|
+
include Kontena::Cli::Common
|
9
|
+
|
10
|
+
def grids
|
11
|
+
client.get("grids")['grids'].map{|grid| grid['id']}
|
12
|
+
rescue
|
13
|
+
[]
|
14
|
+
end
|
15
|
+
|
16
|
+
def nodes
|
17
|
+
client.get("grids/#{current_grid}/nodes")['nodes'].map{|node| node['name']}
|
18
|
+
rescue
|
19
|
+
[]
|
20
|
+
end
|
21
|
+
|
22
|
+
def stacks
|
23
|
+
stacks = client.get("grids/#{current_grid}/stacks")['stacks']
|
24
|
+
results = []
|
25
|
+
results.push stacks.map{|s| s['name']}
|
26
|
+
results.delete('null')
|
27
|
+
results
|
28
|
+
rescue
|
29
|
+
[]
|
30
|
+
end
|
31
|
+
|
32
|
+
def services
|
33
|
+
services = client.get("grids/#{current_grid}/services")['services']
|
34
|
+
results = []
|
35
|
+
results.push services.map{ |s|
|
36
|
+
stack = s['stack']['id'].split('/').last
|
37
|
+
if stack != 'null'
|
38
|
+
"#{stack}/#{s['name']}"
|
39
|
+
else
|
40
|
+
s['name']
|
41
|
+
end
|
42
|
+
}
|
43
|
+
results
|
44
|
+
rescue
|
45
|
+
[]
|
46
|
+
end
|
47
|
+
|
48
|
+
def containers
|
49
|
+
results = []
|
50
|
+
client.get("grids/#{current_grid}/services")['services'].each do |service|
|
51
|
+
containers = client.get("services/#{service['id']}/containers")['containers']
|
52
|
+
results.push(containers.map{|c| c['name'] })
|
53
|
+
results.push(containers.map{|c| c['id'] })
|
54
|
+
end
|
55
|
+
results
|
56
|
+
rescue
|
57
|
+
[]
|
58
|
+
end
|
59
|
+
|
60
|
+
def yml_services
|
61
|
+
if File.exist?('kontena.yml')
|
62
|
+
yaml = YAML.safe_load(File.read('kontena.yml'))
|
63
|
+
services = yaml['services']
|
64
|
+
services.keys
|
65
|
+
end
|
66
|
+
rescue
|
67
|
+
[]
|
68
|
+
end
|
69
|
+
|
70
|
+
def yml_files
|
71
|
+
Dir["./*.yml"].map{|file| file.sub('./', '')}
|
72
|
+
rescue
|
73
|
+
[]
|
74
|
+
end
|
75
|
+
|
76
|
+
def master_names
|
77
|
+
config_file = File.expand_path('~/.kontena_client.json')
|
78
|
+
if(File.exist?(config_file))
|
79
|
+
config = JSON.parse(File.read(config_file))
|
80
|
+
return config['servers'].map{|s| s['name']}
|
81
|
+
end
|
82
|
+
rescue
|
83
|
+
[]
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def self.complete(words)
|
88
|
+
while words.first == 'kontena' || words.first == 'complete'
|
89
|
+
words.shift
|
90
|
+
end
|
91
|
+
helper = Helper.new
|
92
|
+
completion = []
|
93
|
+
|
94
|
+
case words[0]
|
95
|
+
when NilClass, ''
|
96
|
+
completion.concat %w(cloud logout grid app service stack vault certificate node master vpn registry container etcd external-registry whoami plugin version)
|
97
|
+
when 'plugin'
|
98
|
+
sub_commands = %w(list ls search install uninstall)
|
99
|
+
if words[1]
|
100
|
+
completion.push(sub_commands) unless sub_commands.include?(words[1])
|
101
|
+
else
|
102
|
+
completion.push sub_commands
|
103
|
+
end
|
104
|
+
when 'etcd'
|
105
|
+
sub_commands = %w(get set mkdir mk list ls rm)
|
106
|
+
if words[1]
|
107
|
+
completion.push(sub_commands) unless sub_commands.include?(words[1])
|
108
|
+
else
|
109
|
+
completion.push sub_commands
|
110
|
+
end
|
111
|
+
when 'registry'
|
112
|
+
sub_commands = %w(create remove rm)
|
113
|
+
if words[1]
|
114
|
+
completion.push(sub_commands) unless sub_commands.include?(words[1])
|
115
|
+
else
|
116
|
+
completion.push sub_commands
|
117
|
+
end
|
118
|
+
when 'grid'
|
119
|
+
sub_commands = %w(add-user audit-log create current list user remove show use)
|
120
|
+
if words[1]
|
121
|
+
completion.push(sub_commands) unless sub_commands.include?(words[1])
|
122
|
+
completion.push helper.grids
|
123
|
+
else
|
124
|
+
completion.push sub_commands
|
125
|
+
end
|
126
|
+
when 'node'
|
127
|
+
sub_commands = %w(list show remove)
|
128
|
+
if words[1]
|
129
|
+
completion.push(sub_commands) unless sub_commands.include?(words[1])
|
130
|
+
completion.push helper.nodes
|
131
|
+
else
|
132
|
+
completion.push sub_commands
|
133
|
+
end
|
134
|
+
when 'master'
|
135
|
+
sub_commands = %w(list use users current remove rm config cfg login logout token join audit-log init-cloud)
|
136
|
+
if words[1] && words[1] == 'use'
|
137
|
+
completion.push helper.master_names
|
138
|
+
elsif words[1] && words[1] == 'users'
|
139
|
+
users_sub_commands = %(invite list role)
|
140
|
+
completion.push users_sub_commands
|
141
|
+
elsif words[1] && ['config', 'cfg'].include?(words[1])
|
142
|
+
config_sub_commands = %(set get dump load import export unset)
|
143
|
+
completion.push config_sub_commands
|
144
|
+
elsif words[1] && words[1] == 'token'
|
145
|
+
token_sub_commands = %(list ls rm remove show current create)
|
146
|
+
completion.push token_sub_commands
|
147
|
+
elsif words[1]
|
148
|
+
completion.push(sub_commands) unless sub_commands.include?(words[1])
|
149
|
+
else
|
150
|
+
completion.push sub_commands
|
151
|
+
end
|
152
|
+
when 'cloud'
|
153
|
+
sub_commands = %w(login logout master)
|
154
|
+
if words[1] && words[1] == 'master'
|
155
|
+
cloud_master_sub_commands = %(list ls remove rm add show update)
|
156
|
+
completion.push cloud_master_sub_commands
|
157
|
+
elsif words[1]
|
158
|
+
completion.push(sub_commands) unless sub_commands.include?(words[1])
|
159
|
+
else
|
160
|
+
completion.push sub_commands
|
161
|
+
end
|
162
|
+
when 'service'
|
163
|
+
sub_commands = %w(containers create delete deploy list logs restart
|
164
|
+
scale show start stats stop update monitor env
|
165
|
+
secret link unlink)
|
166
|
+
if words[1]
|
167
|
+
completion.push(sub_commands) unless sub_commands.include?(words[1])
|
168
|
+
completion.push helper.services
|
169
|
+
else
|
170
|
+
completion.push sub_commands
|
171
|
+
end
|
172
|
+
when 'container'
|
173
|
+
sub_commands = %w(exec inspect logs)
|
174
|
+
if words[1]
|
175
|
+
completion.push(sub_commands) unless sub_commands.include?(words[1])
|
176
|
+
completion.push helper.containers
|
177
|
+
else
|
178
|
+
completion.push sub_commands
|
179
|
+
end
|
180
|
+
when 'vpn'
|
181
|
+
completion.push %w(config create delete)
|
182
|
+
when 'external-registry'
|
183
|
+
completion.push %w(add list delete)
|
184
|
+
when 'app'
|
185
|
+
sub_commands = %w(init build config deploy start stop remove rm ps list
|
186
|
+
logs monitor show)
|
187
|
+
if words[1]
|
188
|
+
completion.push(sub_commands) unless sub_commands.include?(words[1])
|
189
|
+
completion.push helper.yml_services
|
190
|
+
else
|
191
|
+
completion.push sub_commands
|
192
|
+
end
|
193
|
+
when 'stack'
|
194
|
+
sub_commands = %w(build install upgrade deploy start stop remove rm ls list
|
195
|
+
logs monitor show registry)
|
196
|
+
if words[1]
|
197
|
+
if words[1] == 'registry'
|
198
|
+
registry_sub_commands = %(push pull search show rm)
|
199
|
+
completion.push registry_sub_commands
|
200
|
+
elsif %w(install).include?(words[1])
|
201
|
+
completion.push helper.yml_files
|
202
|
+
elsif words[1] == 'upgrade' && words[3]
|
203
|
+
completion.push helper.yml_files
|
204
|
+
else
|
205
|
+
completion.push(sub_commands) unless sub_commands.include?(words[1])
|
206
|
+
completion.push helper.stacks
|
207
|
+
end
|
208
|
+
else
|
209
|
+
completion.push sub_commands
|
210
|
+
end
|
211
|
+
else
|
212
|
+
end
|
213
|
+
completion.flatten.flat_map { |item| item.split(/\s+/) }
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|