rhcp_shell 0.0.9 → 0.2.11
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/rhcp_shell +25 -5
- data/bin/rhcp_shell.log +11 -0
- data/lib/base_shell.rb +14 -2
- data/lib/display_types/table.rb +106 -0
- data/lib/local_commands/context.rb +24 -0
- data/lib/local_commands/detail.rb +33 -0
- data/lib/local_commands/exit.rb +9 -0
- data/lib/local_commands/help.rb +74 -0
- data/lib/local_commands/set_prompt.rb +17 -0
- data/lib/rhcp_shell_backend.rb +184 -330
- data/lib/util/colorize.rb +15 -0
- data/lib/version.rb +2 -2
- data/test/rhcp_shell_backend_test.rb +54 -17
- data/test/setup_test_registry.rb +36 -0
- metadata +41 -13
data/bin/rhcp_shell
CHANGED
@@ -12,6 +12,8 @@ require 'base_shell'
|
|
12
12
|
require 'rhcp_shell_backend'
|
13
13
|
require 'version'
|
14
14
|
|
15
|
+
require 'uri'
|
16
|
+
|
15
17
|
module RHCP
|
16
18
|
class Shell
|
17
19
|
|
@@ -51,8 +53,14 @@ EOF
|
|
51
53
|
[ '--help', '-h', GetoptLong::NO_ARGUMENT ],
|
52
54
|
[ '--username', '-u', GetoptLong::REQUIRED_ARGUMENT ],
|
53
55
|
[ '--password', '-p', GetoptLong::REQUIRED_ARGUMENT ],
|
54
|
-
[ '--hostname', GetoptLong::REQUIRED_ARGUMENT ]
|
56
|
+
[ '--hostname', GetoptLong::REQUIRED_ARGUMENT ],
|
57
|
+
[ '--port', '-P', GetoptLong::REQUIRED_ARGUMENT ]
|
55
58
|
)
|
59
|
+
|
60
|
+
options = {
|
61
|
+
"hostname" => "localhost",
|
62
|
+
"port" => 42000
|
63
|
+
}
|
56
64
|
|
57
65
|
options = Hash.new
|
58
66
|
opts.each do |opt, arg|
|
@@ -62,7 +70,7 @@ EOF
|
|
62
70
|
Kernel.exit(1)
|
63
71
|
else
|
64
72
|
opt =~ /--(.+)/
|
65
|
-
$logger.debug "setting #{arg} for #{$1}" unless $1 == "password"
|
73
|
+
$logger.debug "setting #{arg} for #{$1}" unless $1 == "password"
|
66
74
|
options[$1] = arg
|
67
75
|
end
|
68
76
|
end
|
@@ -70,10 +78,8 @@ EOF
|
|
70
78
|
host = options["hostname"]
|
71
79
|
if host == nil then
|
72
80
|
host = "http://localhost:42000"
|
73
|
-
|
74
|
-
if host !~ /http:/ then
|
81
|
+
elsif host !~ /http:/ then
|
75
82
|
host = "http://#{host}:42000/rhcp"
|
76
|
-
end
|
77
83
|
end
|
78
84
|
$logger.debug "now connecting to #{host}"
|
79
85
|
|
@@ -81,6 +87,19 @@ EOF
|
|
81
87
|
|
82
88
|
begin
|
83
89
|
url = URI.parse(host)
|
90
|
+
|
91
|
+
if (false)
|
92
|
+
http_options = {
|
93
|
+
:host => options["hostname"],
|
94
|
+
:port => 80,
|
95
|
+
:path => "/rhcp"
|
96
|
+
}
|
97
|
+
if options.has_key?('username')
|
98
|
+
http_options[:userinfo] = "#{options['username']}:#{options['password']}"
|
99
|
+
end
|
100
|
+
url = URI::HTTP.build(http_options)
|
101
|
+
end
|
102
|
+
|
84
103
|
@http_broker = RHCP::Client::HttpBroker.new(url)
|
85
104
|
|
86
105
|
backend = RHCPShellBackend.new(@http_broker)
|
@@ -105,6 +124,7 @@ end
|
|
105
124
|
|
106
125
|
# TODO introduce something like the RAILS_ENVs
|
107
126
|
$logger = Logger.new("rhcp_shell.log")
|
127
|
+
$logger.level = Logger::DEBUG
|
108
128
|
RHCP::ModuleHelper.instance().logger = $logger
|
109
129
|
|
110
130
|
shell = RHCP::Shell.new
|
data/bin/rhcp_shell.log
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
# Logfile created on Sat Jun 25 20:16:10 +0000 2011 by logger.rb/22285
|
2
|
+
D, [2011-06-25T20:16:10.643948 #1686] DEBUG -- : now connecting to http://localhost:42000
|
3
|
+
D, [2011-06-25T20:16:10.644097 #1686] DEBUG -- : connecting to http://localhost:42000
|
4
|
+
D, [2011-06-25T20:16:31.881621 #1688] DEBUG -- : setting http://localhost for hostname
|
5
|
+
D, [2011-06-25T20:16:31.881756 #1688] DEBUG -- : now connecting to http://localhost
|
6
|
+
D, [2011-06-25T20:16:31.881865 #1688] DEBUG -- : connecting to http://localhost
|
7
|
+
E, [2011-06-25T20:16:31.883273 #1688] ERROR -- : cannot connect to 'http://localhost' : got http status code 404
|
8
|
+
D, [2011-06-25T20:16:45.728319 #1690] DEBUG -- : setting http://localhost/rhcp for hostname
|
9
|
+
D, [2011-06-25T20:16:45.728460 #1690] DEBUG -- : now connecting to http://localhost/rhcp
|
10
|
+
D, [2011-06-25T20:16:45.728582 #1690] DEBUG -- : connecting to http://localhost/rhcp
|
11
|
+
E, [2011-06-25T20:16:45.730109 #1690] ERROR -- : cannot connect to 'http://localhost/rhcp' : got http status code 404
|
data/lib/base_shell.rb
CHANGED
@@ -89,10 +89,22 @@ class BaseShell
|
|
89
89
|
else
|
90
90
|
@logger.debug "got an empty line"
|
91
91
|
end
|
92
|
-
|
92
|
+
|
93
93
|
backend.process_input line
|
94
94
|
}
|
95
|
-
|
95
|
+
begin
|
96
|
+
@thread.join
|
97
|
+
rescue
|
98
|
+
error = $!
|
99
|
+
if error == "exit"
|
100
|
+
puts "exiting"
|
101
|
+
Kernel.exit
|
102
|
+
else
|
103
|
+
puts "got an error in @thread.join: #{error}"
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
107
|
+
|
96
108
|
end
|
97
109
|
$stderr.puts "Exiting shell..."
|
98
110
|
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
def format_table_output(command, response)
|
2
|
+
|
3
|
+
# TODO make sure that the response really holds the correct data types and that we've got at least one column
|
4
|
+
# TODO check that all columns in overview_columns are valid
|
5
|
+
# TODO check that all columns in column_titles are valid and match overview_columns
|
6
|
+
output = ""
|
7
|
+
|
8
|
+
# let's find out which columns we want to display
|
9
|
+
$logger.debug "overview columns : #{command.result_hints[:overview_columns]}"
|
10
|
+
# TODO this will probably fail if no overview_columns are specified
|
11
|
+
columns_to_display = command.result_hints.has_key?(:overview_columns) ?
|
12
|
+
command.result_hints[:overview_columns].clone() :
|
13
|
+
# by default, we'll display all columns, sorted alphabetically
|
14
|
+
columns_to_display = response.data[0].keys.sort
|
15
|
+
|
16
|
+
# and which titles they should have (default : column names)
|
17
|
+
$logger.debug "column titles : #{command.result_hints[:column_titles].length}"
|
18
|
+
column_title_list = command.result_hints[:column_titles].length > 0 ?
|
19
|
+
command.result_hints[:column_titles].clone() :
|
20
|
+
column_title_list = columns_to_display
|
21
|
+
$logger.debug "column title list : #{column_title_list}"
|
22
|
+
|
23
|
+
# TODO the sorting column should be configurable
|
24
|
+
first_column = columns_to_display[0]
|
25
|
+
$logger.debug "sorting by #{first_column}"
|
26
|
+
response.data = response.data.sort { |a,b| a[first_column] <=> b[first_column] }
|
27
|
+
|
28
|
+
# add the index column
|
29
|
+
columns_to_display.unshift "__idx"
|
30
|
+
column_title_list.unshift "\#"
|
31
|
+
count = 1
|
32
|
+
response.data.each do |row|
|
33
|
+
row["__idx"] = count
|
34
|
+
count = count+1
|
35
|
+
end
|
36
|
+
|
37
|
+
column_titles = {}
|
38
|
+
0.upto(column_title_list.length - 1) do |i|
|
39
|
+
column_titles[columns_to_display[i]] = column_title_list[i]
|
40
|
+
end
|
41
|
+
$logger.debug "column titles : #{column_titles}"
|
42
|
+
|
43
|
+
# initialize the max_width for all columns
|
44
|
+
@max_width = {}
|
45
|
+
column_titles.each do |key, value|
|
46
|
+
@max_width[key] = 0
|
47
|
+
end
|
48
|
+
# find the maximum column width for each column
|
49
|
+
response.data.each do |row|
|
50
|
+
row.each do |k,v|
|
51
|
+
if ! @max_width.has_key?(k) || v.to_s.length > @max_width[k]
|
52
|
+
@max_width[k] = v.to_s.length
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# check the column_title for max width
|
58
|
+
columns_to_display.each do |col_name|
|
59
|
+
if column_titles[col_name].length > @max_width[col_name]
|
60
|
+
@max_width[col_name] = column_titles[col_name].length
|
61
|
+
end
|
62
|
+
end
|
63
|
+
#@max_width["row_count"] = response.data.length.to_s.length
|
64
|
+
$logger.debug "max width : #{@max_width}"
|
65
|
+
|
66
|
+
# and build headers
|
67
|
+
@total_width = 2 + columns_to_display.length-1 # separators at front and end of table and between the values
|
68
|
+
columns_to_display.each do |col|
|
69
|
+
@total_width += @max_width[col] + 2 # each column has a space in front and behind the value
|
70
|
+
end
|
71
|
+
output += print_line
|
72
|
+
|
73
|
+
columns_to_display.each do |col|
|
74
|
+
output += print_cell(col, column_titles[col])
|
75
|
+
end
|
76
|
+
output += "|\n"
|
77
|
+
|
78
|
+
output += print_line
|
79
|
+
|
80
|
+
# print the table values
|
81
|
+
response.data.each do |row|
|
82
|
+
columns_to_display.each do |col|
|
83
|
+
output += print_cell(col, row[col])
|
84
|
+
end
|
85
|
+
output += "|\n"
|
86
|
+
end
|
87
|
+
output += print_line
|
88
|
+
|
89
|
+
end
|
90
|
+
|
91
|
+
def print_cell(col_name, the_value)
|
92
|
+
result = "| "
|
93
|
+
result += the_value.to_s
|
94
|
+
1.upto(@max_width[col_name] - the_value.to_s.length) { |i|
|
95
|
+
result += " "
|
96
|
+
}
|
97
|
+
result += " "
|
98
|
+
result
|
99
|
+
end
|
100
|
+
|
101
|
+
def print_line
|
102
|
+
result = ""
|
103
|
+
@total_width.times { |i| result += "-" }
|
104
|
+
result += "\n"
|
105
|
+
result
|
106
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
def add_context_commands(broker, context_aware_broker)
|
2
|
+
|
3
|
+
command = RHCP::Command.new("show_context", "displays the context currently stored in the local ContextAwareBroker",
|
4
|
+
lambda { |req,res|
|
5
|
+
result = []
|
6
|
+
@command_broker.context.cookies.each do |k,v|
|
7
|
+
result << {
|
8
|
+
"key" => k,
|
9
|
+
"value" => v
|
10
|
+
}
|
11
|
+
end
|
12
|
+
result
|
13
|
+
}
|
14
|
+
)
|
15
|
+
|
16
|
+
command.result_hints[:display_type] = "table"
|
17
|
+
command.result_hints[:overview_columns] = [ "key", "value" ]
|
18
|
+
command.result_hints[:column_titles] = [ "key", "value" ]
|
19
|
+
command.mark_as_read_only
|
20
|
+
command.result_hints[:cache] = false
|
21
|
+
|
22
|
+
broker.register_command command
|
23
|
+
|
24
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
def add_detail_command(broker)
|
2
|
+
|
3
|
+
command = RHCP::Command.new("detail", "shows details about a single record of the last response\n" + (" " * 43) + "(makes sense if you executed a command that returned a table)",
|
4
|
+
lambda { |req,res|
|
5
|
+
if @last_response == nil
|
6
|
+
puts "did not find any old response data...is it possible that you did not execute a command yet that returned a table?"
|
7
|
+
return
|
8
|
+
end
|
9
|
+
row_count = @last_response.data.length
|
10
|
+
begin
|
11
|
+
row_index = req.get_param_value("row_index").to_i
|
12
|
+
raise "invalid index" if (row_index < 1 || row_index > row_count)
|
13
|
+
rescue
|
14
|
+
puts "invalid row index - please specify a number between 1 and #{row_count}"
|
15
|
+
return
|
16
|
+
end
|
17
|
+
puts "displaying details about row \# #{row_index}"
|
18
|
+
@last_response.data[row_index - 1].each do |k,v|
|
19
|
+
puts " #{k}\t#{v}"
|
20
|
+
end
|
21
|
+
|
22
|
+
}
|
23
|
+
).add_param(RHCP::CommandParam.new("row_index", "the index of the row you want to see details about",
|
24
|
+
{
|
25
|
+
:is_default_param => true,
|
26
|
+
:mandatory => true
|
27
|
+
}
|
28
|
+
)
|
29
|
+
)
|
30
|
+
command.result_hints[:display_type] = "hidden"
|
31
|
+
broker.register_command command
|
32
|
+
|
33
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
def param_example(param, suffix = "")
|
2
|
+
result = ""
|
3
|
+
result += "<" if param.is_default_param
|
4
|
+
|
5
|
+
if param.is_default_param then
|
6
|
+
result += "#{param.name}#{suffix}"
|
7
|
+
else
|
8
|
+
result += "#{param.name}"
|
9
|
+
result += "=<value#{suffix}>"
|
10
|
+
end
|
11
|
+
|
12
|
+
result += ">" if param.is_default_param
|
13
|
+
result
|
14
|
+
end
|
15
|
+
|
16
|
+
def add_help_commands(broker)
|
17
|
+
command = RHCP::Command.new("help", "displays help about this shell",
|
18
|
+
lambda {
|
19
|
+
|req,res|
|
20
|
+
|
21
|
+
if (req.has_param_value("command"))
|
22
|
+
command_name = req.get_param_value("command")
|
23
|
+
puts "Syntax:"
|
24
|
+
command_line = " #{command_name}"
|
25
|
+
command = @command_broker.get_command(command_name)
|
26
|
+
|
27
|
+
command.params.sort { |a,b| a.name <=> b.name }.each do |param|
|
28
|
+
command_line += " "
|
29
|
+
command_line += "[" unless param.mandatory
|
30
|
+
|
31
|
+
command_line += param_example(param)
|
32
|
+
|
33
|
+
if param.allows_multiple_values then
|
34
|
+
command_line += " "
|
35
|
+
command_line += param_example(param, "2")
|
36
|
+
command_line += " ..."
|
37
|
+
end
|
38
|
+
|
39
|
+
command_line += "]" unless param.mandatory
|
40
|
+
end
|
41
|
+
puts command_line
|
42
|
+
puts "Description:"
|
43
|
+
puts " #{command.description}"
|
44
|
+
if command.params.size > 0 then
|
45
|
+
puts "Parameters:"
|
46
|
+
command.params.sort { |a,b| a.name <=> b.name }.each do |param|
|
47
|
+
puts sprintf(" %-20s %s\n", param.name, param.description)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
puts ""
|
51
|
+
else
|
52
|
+
puts "The following commands are available:"
|
53
|
+
@command_broker.get_command_list.values.sort { |a,b| a.name <=> b.name }.each do |command|
|
54
|
+
# TODO calculate the maximum command name length dynamically
|
55
|
+
# TODO and allow for multiple lines of description (check if it's an array?)
|
56
|
+
puts sprintf(" %-40s %s\n", command.name, command.description)
|
57
|
+
end
|
58
|
+
puts ""
|
59
|
+
puts "Type help <command name> for detailed information about a command."
|
60
|
+
end
|
61
|
+
}
|
62
|
+
).add_param(RHCP::CommandParam.new("command", "the name of the command to display help for",
|
63
|
+
{
|
64
|
+
:mandatory => false,
|
65
|
+
:is_default_param => true,
|
66
|
+
:lookup_method => lambda {
|
67
|
+
@command_broker.get_command_list.values.map { |c| c.name }
|
68
|
+
}
|
69
|
+
}
|
70
|
+
)
|
71
|
+
)
|
72
|
+
command.result_hints[:display_type] = "hidden"
|
73
|
+
broker.register_command command
|
74
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
def add_set_prompt_command(broker, shell_backend)
|
2
|
+
|
3
|
+
command = RHCP::Command.new("set_prompt", "changes the current prompt",
|
4
|
+
lambda { |req,res|
|
5
|
+
res.set_context("prompt" => req.get_param_value("new_prompt"))
|
6
|
+
}
|
7
|
+
).add_param(RHCP::CommandParam.new("new_prompt", "the new prompt that should be used from now on",
|
8
|
+
{
|
9
|
+
:is_default_param => true,
|
10
|
+
:mandatory => true
|
11
|
+
}
|
12
|
+
)
|
13
|
+
)
|
14
|
+
command.result_hints[:display_type] = "hidden"
|
15
|
+
broker.register_command command
|
16
|
+
|
17
|
+
end
|
data/lib/rhcp_shell_backend.rb
CHANGED
@@ -1,7 +1,16 @@
|
|
1
1
|
require 'shell_backend.rb'
|
2
2
|
|
3
|
+
require 'local_commands/help'
|
4
|
+
require 'local_commands/detail'
|
5
|
+
require 'local_commands/exit'
|
6
|
+
require 'local_commands/context'
|
7
|
+
require 'local_commands/set_prompt'
|
8
|
+
|
9
|
+
require 'display_types/table'
|
10
|
+
|
3
11
|
require 'rubygems'
|
4
12
|
require 'rhcp'
|
13
|
+
require 'rhcp/memcached_broker'
|
5
14
|
|
6
15
|
# This shell presents RHCP commands to the user and handles all the parameter
|
7
16
|
# lookup, validation and command completion stuff
|
@@ -18,132 +27,44 @@ class RHCPShellBackend < ShellBackend
|
|
18
27
|
# TODO refactor this monstrosity
|
19
28
|
|
20
29
|
attr_reader :last_response
|
21
|
-
attr_reader :prompt
|
22
30
|
attr_accessor :banner
|
31
|
+
|
32
|
+
attr_reader :command_broker
|
33
|
+
attr_accessor :lookup_broker
|
23
34
|
|
24
|
-
def initialize(command_broker)
|
35
|
+
def initialize(command_broker, options = {})
|
25
36
|
super()
|
26
|
-
|
37
|
+
|
27
38
|
local_broker = setup_local_broker
|
28
|
-
|
29
|
-
|
30
|
-
|
39
|
+
dispatcher = RHCP::DispatchingBroker.new()
|
40
|
+
dispatcher.add_broker(command_broker)
|
41
|
+
dispatcher.add_broker(local_broker)
|
42
|
+
|
43
|
+
@command_broker = RHCP::Client::ContextAwareBroker.new(dispatcher)
|
44
|
+
@lookup_broker = @command_broker
|
45
|
+
|
46
|
+
@lookup_cache = {}
|
47
|
+
|
48
|
+
@current_prompt = nil
|
49
|
+
|
50
|
+
@prompt_color_enabled = options.has_key?(:color_prompt) ?
|
51
|
+
options[:color_prompt] : false
|
31
52
|
|
32
53
|
reset_to_command_mode
|
33
|
-
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def wrap_lookup_broker
|
57
|
+
@lookup_broker = RHCP::MemcachedBroker.new(@lookup_broker)
|
58
|
+
end
|
34
59
|
|
35
60
|
def setup_local_broker
|
36
61
|
broker = RHCP::Broker.new()
|
37
62
|
begin
|
38
|
-
broker
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
)
|
44
|
-
|
45
|
-
def param_example(param, suffix = "")
|
46
|
-
result = ""
|
47
|
-
result += "<" if param.is_default_param
|
48
|
-
|
49
|
-
if param.is_default_param then
|
50
|
-
result += "#{param.name}#{suffix}"
|
51
|
-
else
|
52
|
-
result += "#{param.name}"
|
53
|
-
result += "=<value#{suffix}>"
|
54
|
-
end
|
55
|
-
|
56
|
-
result += ">" if param.is_default_param
|
57
|
-
result
|
58
|
-
end
|
59
|
-
|
60
|
-
command = RHCP::Command.new("help", "displays help about this shell",
|
61
|
-
lambda {
|
62
|
-
|req,res|
|
63
|
-
|
64
|
-
if (req.has_param_value("command"))
|
65
|
-
command_name = req.get_param_value("command")
|
66
|
-
puts "Syntax:"
|
67
|
-
command_line = " #{command_name}"
|
68
|
-
command = @command_broker.get_command(command_name)
|
69
|
-
|
70
|
-
command.params.values.sort { |a,b| a.name <=> b.name }.each do |param|
|
71
|
-
command_line += " "
|
72
|
-
command_line += "[" unless param.mandatory
|
73
|
-
|
74
|
-
command_line += param_example(param)
|
75
|
-
|
76
|
-
if param.allows_multiple_values then
|
77
|
-
command_line += ", "
|
78
|
-
command_line += param_example(param, "2")
|
79
|
-
command_line += ", ..."
|
80
|
-
end
|
81
|
-
|
82
|
-
command_line += "]" unless param.mandatory
|
83
|
-
end
|
84
|
-
puts command_line
|
85
|
-
puts "Description:"
|
86
|
-
puts " #{command.description}"
|
87
|
-
if command.params.size > 0 then
|
88
|
-
puts "Parameters:"
|
89
|
-
command.params.values.sort { |a,b| a.name <=> b.name }.each do |param|
|
90
|
-
puts sprintf(" %-20s %s\n", param.name, param.description)
|
91
|
-
end
|
92
|
-
end
|
93
|
-
puts ""
|
94
|
-
else
|
95
|
-
puts "The following commands are available:"
|
96
|
-
@command_broker.get_command_list.values.sort { |a,b| a.name <=> b.name }.each do |command|
|
97
|
-
# TODO calculate the maximum command name length dynamically
|
98
|
-
puts sprintf(" %-40s %s\n", command.name, command.description)
|
99
|
-
end
|
100
|
-
puts ""
|
101
|
-
puts "Type help <command name> for detailed information about a command."
|
102
|
-
end
|
103
|
-
}
|
104
|
-
).add_param(RHCP::CommandParam.new("command", "the name of the command to display help for",
|
105
|
-
{
|
106
|
-
:mandatory => false,
|
107
|
-
:is_default_param => true,
|
108
|
-
:lookup_method => lambda {
|
109
|
-
@command_broker.get_command_list.values.map { |c| c.name }
|
110
|
-
}
|
111
|
-
}
|
112
|
-
)
|
113
|
-
)
|
114
|
-
command.result_hints[:display_type] = "hidden"
|
115
|
-
broker.register_command command
|
116
|
-
|
117
|
-
command = RHCP::Command.new("detail", "shows details about a single record of the last response\n" + (" " * 43) + "(makes sense if you executed a command that returned a table)",
|
118
|
-
lambda { |req,res|
|
119
|
-
if @last_response == nil
|
120
|
-
puts "did not find any old response data...is it possible that you did not execute a command yet that returned a table?"
|
121
|
-
return
|
122
|
-
end
|
123
|
-
row_count = @last_response.data.length
|
124
|
-
begin
|
125
|
-
row_index = req.get_param_value("row_index").to_i
|
126
|
-
raise "invalid index" if (row_index < 1 || row_index > row_count)
|
127
|
-
rescue
|
128
|
-
puts "invalid row index - please specify a number between 1 and #{row_count}"
|
129
|
-
return
|
130
|
-
end
|
131
|
-
puts "displaying details about row \# #{row_index}"
|
132
|
-
@last_response.data[row_index - 1].each do |k,v|
|
133
|
-
puts " #{k}\t#{v}"
|
134
|
-
end
|
135
|
-
|
136
|
-
}
|
137
|
-
).add_param(RHCP::CommandParam.new("row_index", "the index of the row you want to see details about",
|
138
|
-
{
|
139
|
-
:is_default_param => true,
|
140
|
-
:mandatory => true
|
141
|
-
}
|
142
|
-
)
|
143
|
-
)
|
144
|
-
command.result_hints[:display_type] = "hidden"
|
145
|
-
broker.register_command command
|
146
|
-
|
63
|
+
add_exit_command(broker)
|
64
|
+
add_help_commands(broker)
|
65
|
+
add_detail_command(broker)
|
66
|
+
add_context_commands(broker, @command_broker)
|
67
|
+
add_set_prompt_command(broker, self)
|
147
68
|
rescue RHCP::RhcpException => ex
|
148
69
|
# TODO do we really want to catch this here?
|
149
70
|
raise ex unless /duplicate command name/ =~ ex.to_s
|
@@ -152,8 +73,6 @@ class RHCPShellBackend < ShellBackend
|
|
152
73
|
end
|
153
74
|
|
154
75
|
def reset_to_command_mode
|
155
|
-
set_prompt nil
|
156
|
-
|
157
76
|
# this shell has two modes that determine the available tab completion proposals
|
158
77
|
# command_mode
|
159
78
|
# we're waiting for the user to pick a command that should be executed
|
@@ -164,7 +83,8 @@ class RHCPShellBackend < ShellBackend
|
|
164
83
|
|
165
84
|
# if the user selected a command already, we'll have to collect parameters for this command until
|
166
85
|
# we've got all mandatory parameters so that we can execute the command
|
167
|
-
@
|
86
|
+
@collected_values = {}
|
87
|
+
|
168
88
|
|
169
89
|
# the mandatory params that are still missing (valid in parameter mode only)
|
170
90
|
@missing_params = Array.new
|
@@ -175,13 +95,13 @@ class RHCPShellBackend < ShellBackend
|
|
175
95
|
|
176
96
|
def execute_command_if_possible
|
177
97
|
# check if we got all mandatory params now
|
178
|
-
mandatory_params = @command_selected.
|
179
|
-
|
98
|
+
mandatory_params = @command_broker.get_mandatory_params(@command_selected.name)
|
99
|
+
#mandatory_params = @command_selected.get_mandatory_params()
|
100
|
+
@missing_params = mandatory_params.select { |p| ! @collected_values.include? p.name }
|
180
101
|
|
181
102
|
if (@missing_params.size > 0) then
|
182
103
|
$logger.debug "got #{@missing_params.size} missing params : #{@missing_params.map{|param| param.name}}"
|
183
104
|
@current_param = @missing_params[0]
|
184
|
-
set_prompt "#{@command_selected.name}.#{@current_param.name}"
|
185
105
|
else
|
186
106
|
execute_command
|
187
107
|
end
|
@@ -199,7 +119,7 @@ class RHCPShellBackend < ShellBackend
|
|
199
119
|
# convert "*" into regexp notation ".*"
|
200
120
|
regex_str = new_value.gsub(/\*/, '.*')
|
201
121
|
|
202
|
-
# handle ranges (
|
122
|
+
# handle ranges (42..45)
|
203
123
|
result = /(.+?)(\d+)(\.{2})(\d+)(.*)/.match(regex_str)
|
204
124
|
ranged_regex = nil
|
205
125
|
if result then
|
@@ -214,7 +134,7 @@ class RHCPShellBackend < ShellBackend
|
|
214
134
|
end
|
215
135
|
end
|
216
136
|
else
|
217
|
-
ranged_regex = Regexp.new(regex_str)
|
137
|
+
ranged_regex = Regexp.new('^' + regex_str + '$')
|
218
138
|
end
|
219
139
|
|
220
140
|
$logger.debug "wildcard regexp : #{ranged_regex}"
|
@@ -222,7 +142,9 @@ class RHCPShellBackend < ShellBackend
|
|
222
142
|
re = ranged_regex
|
223
143
|
|
224
144
|
# get lookup values, filter and return them
|
225
|
-
|
145
|
+
request = RHCP::Request.new(@command_selected, @collected_values)
|
146
|
+
lookup_values = @command_broker.get_lookup_values(request, @current_param.name )
|
147
|
+
#lookup_values = @current_param.get_lookup_values()
|
226
148
|
lookup_values.select { |lookup_value| re.match(lookup_value) }
|
227
149
|
else
|
228
150
|
[ new_value ]
|
@@ -234,137 +156,43 @@ class RHCPShellBackend < ShellBackend
|
|
234
156
|
# returns the values that have been added (might be more than 'new_value' when wildcards are used)
|
235
157
|
def add_parameter_value(new_value)
|
236
158
|
# pre-process the value if necessary
|
237
|
-
|
159
|
+
# TODO reactivate wildcard checking (too expensive right now and we aren't using it)
|
160
|
+
#processed_param_values = pre_process_param_value(new_value)
|
161
|
+
processed_param_values = [ new_value ]
|
162
|
+
|
238
163
|
# TODO this check is already part of check_param_is_valid (which is called later in this method and when the request is created) - we do not want to check this three times...?
|
239
164
|
if processed_param_values.size == 0
|
240
165
|
raise RHCP::RhcpException.new("invalid value '#{new_value}' for parameter '#{@current_param.name}'")
|
241
166
|
end
|
242
|
-
|
167
|
+
|
243
168
|
processed_param_values.each do |value|
|
244
|
-
|
245
|
-
@
|
169
|
+
request = RHCP::Request.new(@command_selected, @collected_values)
|
170
|
+
@command_broker.check_param_is_valid(request, @current_param.name, [ value ])
|
246
171
|
$logger.debug "accepted value #{value} for param #{@current_param.name}"
|
247
172
|
|
248
|
-
@
|
249
|
-
@
|
173
|
+
@collected_values[@current_param.name] = Array.new if @collected_values[@current_param.name] == nil
|
174
|
+
@collected_values[@current_param.name] << value
|
250
175
|
end
|
251
176
|
processed_param_values
|
252
177
|
end
|
253
178
|
|
254
|
-
def print_cell(col_name, the_value)
|
255
|
-
result = "| "
|
256
|
-
result += the_value.to_s
|
257
|
-
1.upto(@max_width[col_name] - the_value.to_s.length) { |i|
|
258
|
-
result += " "
|
259
|
-
}
|
260
|
-
result += " "
|
261
|
-
result
|
262
|
-
end
|
263
|
-
|
264
|
-
def print_line
|
265
|
-
result = ""
|
266
|
-
@total_width.times { |i| result += "-" }
|
267
|
-
result += "\n"
|
268
|
-
result
|
269
|
-
end
|
270
|
-
|
271
179
|
def execute_command
|
272
180
|
begin
|
273
|
-
command
|
274
|
-
|
275
|
-
|
276
|
-
|
181
|
+
$logger.debug("(ShellBackend) gonna execute command '#{@command_selected.name}' on broker '#{@command_broker}'")
|
182
|
+
command = @command_broker.get_command(@command_selected.name)
|
183
|
+
request = RHCP::Request.new(command, @collected_values)
|
184
|
+
response = @command_broker.execute(request)
|
185
|
+
|
186
|
+
# we might want to access this response in further commands
|
187
|
+
@last_response = response
|
188
|
+
|
277
189
|
if (response.status == RHCP::Response::Status::OK)
|
190
|
+
|
278
191
|
$logger.debug "raw result : #{response.data}"
|
279
|
-
|
192
|
+
$logger.debug "result hints: #{command.result_hints}"
|
280
193
|
$logger.debug "display_type : #{command.result_hints[:display_type]}"
|
281
194
|
if command.result_hints[:display_type] == "table"
|
282
|
-
|
283
|
-
# TODO check that all columns in overview_columns are valid
|
284
|
-
# TODO check that all columns in column_titles are valid and match overview_columns
|
285
|
-
output = ""
|
286
|
-
|
287
|
-
# let's find out which columns we want to display
|
288
|
-
$logger.debug "overview columns : #{command.result_hints[:overview_columns]}"
|
289
|
-
# TODO this will probably fail if no overview_columns are specified
|
290
|
-
columns_to_display = command.result_hints.has_key?(:overview_columns) ?
|
291
|
-
command.result_hints[:overview_columns].clone() :
|
292
|
-
# by default, we'll display all columns, sorted alphabetically
|
293
|
-
columns_to_display = response.data[0].keys.sort
|
294
|
-
|
295
|
-
# and which titles they should have (default : column names)
|
296
|
-
$logger.debug "column titles : #{command.result_hints[:column_titles].length}"
|
297
|
-
column_title_list = command.result_hints[:column_titles].length > 0 ?
|
298
|
-
command.result_hints[:column_titles].clone() :
|
299
|
-
column_title_list = columns_to_display
|
300
|
-
$logger.debug "column title list : #{column_title_list}"
|
301
|
-
|
302
|
-
# TODO the sorting column should be configurable
|
303
|
-
first_column = columns_to_display[0]
|
304
|
-
$logger.debug "sorting by #{first_column}"
|
305
|
-
response.data = response.data.sort { |a,b| a[first_column] <=> b[first_column] }
|
306
|
-
|
307
|
-
# add the index column
|
308
|
-
columns_to_display.unshift "__idx"
|
309
|
-
column_title_list.unshift "\#"
|
310
|
-
count = 1
|
311
|
-
response.data.each do |row|
|
312
|
-
row["__idx"] = count
|
313
|
-
count = count+1
|
314
|
-
end
|
315
|
-
|
316
|
-
column_titles = {}
|
317
|
-
0.upto(column_title_list.length - 1) do |i|
|
318
|
-
column_titles[columns_to_display[i]] = column_title_list[i]
|
319
|
-
end
|
320
|
-
$logger.debug "column titles : #{column_titles}"
|
321
|
-
|
322
|
-
# initialize the max_width for all columns
|
323
|
-
@max_width = {}
|
324
|
-
column_titles.each do |key, value|
|
325
|
-
@max_width[key] = 0
|
326
|
-
end
|
327
|
-
# find the maximum column width for each column
|
328
|
-
response.data.each do |row|
|
329
|
-
row.each do |k,v|
|
330
|
-
if ! @max_width.has_key?(k) || v.to_s.length > @max_width[k]
|
331
|
-
@max_width[k] = v.to_s.length
|
332
|
-
end
|
333
|
-
end
|
334
|
-
end
|
335
|
-
|
336
|
-
# check the column_title for max width
|
337
|
-
columns_to_display.each do |col_name|
|
338
|
-
if column_titles[col_name].length > @max_width[col_name]
|
339
|
-
@max_width[col_name] = column_titles[col_name].length
|
340
|
-
end
|
341
|
-
end
|
342
|
-
#@max_width["row_count"] = response.data.length.to_s.length
|
343
|
-
$logger.debug "max width : #{@max_width}"
|
344
|
-
|
345
|
-
# and build headers
|
346
|
-
@total_width = 2 + columns_to_display.length-1 # separators at front and end of table and between the values
|
347
|
-
columns_to_display.each do |col|
|
348
|
-
@total_width += @max_width[col] + 2 # each column has a space in front and behind the value
|
349
|
-
end
|
350
|
-
output += print_line
|
351
|
-
|
352
|
-
columns_to_display.each do |col|
|
353
|
-
output += print_cell(col, column_titles[col])
|
354
|
-
end
|
355
|
-
output += "|\n"
|
356
|
-
|
357
|
-
output += print_line
|
358
|
-
|
359
|
-
# print the table values
|
360
|
-
response.data.each do |row|
|
361
|
-
columns_to_display.each do |col|
|
362
|
-
output += print_cell(col, row[col])
|
363
|
-
end
|
364
|
-
output += "|\n"
|
365
|
-
end
|
366
|
-
output += print_line
|
367
|
-
|
195
|
+
output = format_table_output(command, response)
|
368
196
|
puts output
|
369
197
|
elsif command.result_hints[:display_type] == "list"
|
370
198
|
output = ""
|
@@ -375,16 +203,35 @@ class RHCPShellBackend < ShellBackend
|
|
375
203
|
elsif command.result_hints[:display_type] == "hidden"
|
376
204
|
$logger.debug "suppressing output due to display_type 'hidden'"
|
377
205
|
else
|
378
|
-
puts "executed '#{@command_selected.name}' successfully : #{response.data}"
|
206
|
+
puts "executed '#{@command_selected.name}' successfully : #{@prompt_color_enabled ? green(response.data) : response.data}"
|
207
|
+
end
|
208
|
+
|
209
|
+
# if the command has been executed successfully, we might have to update the prompt
|
210
|
+
if @command_broker.context.cookies.has_key?('prompt')
|
211
|
+
set_prompt @command_broker.context.cookies['prompt']
|
379
212
|
end
|
213
|
+
|
380
214
|
else
|
381
|
-
|
215
|
+
if @command_selected.name == 'exit'
|
216
|
+
$logger.debug "exiting on user request"
|
217
|
+
Kernel.exit(0)
|
218
|
+
end
|
219
|
+
|
220
|
+
puts "could not execute '#{@command_selected.name}' : #{@prompt_color_enabled ? red(response.error_text) : response.error_text}"
|
382
221
|
$logger.error "#{response.error_text} : #{response.error_detail}"
|
222
|
+
|
223
|
+
set_prompt nil
|
383
224
|
end
|
384
225
|
reset_to_command_mode
|
385
226
|
rescue
|
386
|
-
|
387
|
-
|
227
|
+
error = $!
|
228
|
+
if (error == "exit")
|
229
|
+
puts "exiting"
|
230
|
+
Kernel.exit
|
231
|
+
else
|
232
|
+
puts "got an error : >>#{$!}<<"
|
233
|
+
raise
|
234
|
+
end
|
388
235
|
end
|
389
236
|
end
|
390
237
|
|
@@ -393,107 +240,103 @@ class RHCPShellBackend < ShellBackend
|
|
393
240
|
def process_input(command_line)
|
394
241
|
$logger.debug "processing input '#{command_line}'"
|
395
242
|
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
if
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
243
|
+
# we might have to setup the context aware broker for this thread
|
244
|
+
Thread.current['broker'] = @command_broker
|
245
|
+
|
246
|
+
begin
|
247
|
+
if (@command_selected) then
|
248
|
+
# we're in parameter processing mode - so check which parameter
|
249
|
+
# we've got now and switch modes if necessary
|
250
|
+
|
251
|
+
# we might have been waiting for multiple param values - check if the user finished
|
252
|
+
# adding values by selecting an empty string as value
|
253
|
+
if (@current_param.allows_multiple_values and command_line == "") then
|
254
|
+
$logger.debug "finished multiple parameter input mode for param #{@current_param.name}"
|
255
|
+
@missing_params.shift
|
256
|
+
execute_command_if_possible
|
257
|
+
else
|
258
|
+
accepted_params = add_parameter_value(command_line)
|
259
|
+
if accepted_params
|
260
|
+
# stop asking for more values if
|
261
|
+
# a) the parameter does not allow more than one value
|
262
|
+
# b) the user entered a wildcard parameter that has been expanded to multiple values
|
263
|
+
if (! @current_param.allows_multiple_values or accepted_params.length > 1) then
|
264
|
+
$logger.debug "finished parameter input mode for param #{@current_param.name}"
|
265
|
+
@missing_params.shift
|
266
|
+
execute_command_if_possible
|
267
|
+
else
|
268
|
+
$logger.debug "param '#{@current_param.name}' expects multiple values...deferring mode switching"
|
269
|
+
end
|
418
270
|
end
|
419
271
|
end
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
#
|
437
|
-
|
438
|
-
|
439
|
-
# $logger.debug "presetting global parameter '#{name}' to '#{values}'"
|
440
|
-
# values.each do |value|
|
441
|
-
# add_parameter_value(value)
|
442
|
-
# end
|
443
|
-
# end
|
444
|
-
# end
|
445
|
-
|
446
|
-
# process the params specified on the command line
|
447
|
-
if (params != nil) then
|
448
|
-
params.each do |param|
|
449
|
-
if param =~ /(.+?)=(.+)/ then
|
450
|
-
# --> named param
|
451
|
-
key = $1
|
452
|
-
value = $2
|
453
|
-
else
|
454
|
-
# TODO if there's only one param, we can always use this as default param (maybe do this in the command?)
|
455
|
-
# --> unnamed param
|
456
|
-
value = param
|
457
|
-
default_param = @command_selected.default_param
|
458
|
-
if default_param != nil then
|
459
|
-
key = default_param.name
|
460
|
-
$logger.debug "collecting value '#{value}' for default param '#{default_param.name}'"
|
272
|
+
else
|
273
|
+
# we're waiting for the user to enter a command
|
274
|
+
# we might have a command with params
|
275
|
+
command, *params = command_line.split
|
276
|
+
$logger.debug "got command '#{command}' (params: #{params})"
|
277
|
+
|
278
|
+
# remember what the user specified so far
|
279
|
+
begin
|
280
|
+
@command_selected = @command_broker.get_command(command)
|
281
|
+
#if (@command_selected != nil) then
|
282
|
+
$logger.debug "command_selected: #{@command_selected}"
|
283
|
+
|
284
|
+
# process the params specified on the command line
|
285
|
+
if (params != nil) then
|
286
|
+
params.each do |param|
|
287
|
+
if param =~ /(.+?)=(.+)/ then
|
288
|
+
# --> named param
|
289
|
+
key = $1
|
290
|
+
value = $2
|
461
291
|
else
|
462
|
-
|
292
|
+
# TODO if there's only one param, we can always use this as default param (maybe do this in the command?)
|
293
|
+
# --> unnamed param
|
294
|
+
value = param
|
295
|
+
default_param = @command_selected.default_param
|
296
|
+
if default_param != nil then
|
297
|
+
key = default_param.name
|
298
|
+
$logger.debug "collecting value '#{value}' for default param '#{default_param.name}'"
|
299
|
+
else
|
300
|
+
$logger.info "ignoring param '#{value}' because there's no default param"
|
301
|
+
end
|
463
302
|
end
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
303
|
+
|
304
|
+
if key then
|
305
|
+
begin
|
306
|
+
@current_param = @command_selected.get_param(key)
|
307
|
+
add_parameter_value(value)
|
308
|
+
rescue RHCP::RhcpException => ex
|
309
|
+
puts "ignoring parameter value '#{value}' for param '#{key}' : " + ex.to_s
|
310
|
+
end
|
472
311
|
end
|
473
312
|
end
|
474
313
|
end
|
314
|
+
|
315
|
+
$logger.debug "selected command #{@command_selected.name}"
|
316
|
+
execute_command_if_possible
|
317
|
+
rescue RHCP::RhcpException => ex
|
318
|
+
puts "#{ex}"
|
319
|
+
reset_to_command_mode
|
475
320
|
end
|
476
|
-
|
477
|
-
$logger.debug "selected command #{@command_selected.name}"
|
478
|
-
execute_command_if_possible
|
479
|
-
rescue RHCP::RhcpException => ex
|
480
|
-
puts "#{ex}"
|
481
321
|
end
|
322
|
+
rescue RHCP::RhcpException => ex
|
323
|
+
$logger.error ex
|
324
|
+
puts "exception raised: #{ex.to_s}"
|
325
|
+
reset_to_command_mode
|
482
326
|
end
|
483
|
-
rescue => err
|
484
|
-
$logger.error err
|
485
|
-
puts "exception raised: #{err.to_s}"
|
486
327
|
end
|
487
328
|
|
488
329
|
def complete(word = "")
|
489
|
-
$logger.debug "
|
330
|
+
$logger.debug "collecting completion values for '#{word}'"
|
331
|
+
|
332
|
+
Thread.current['broker'] = @command_broker
|
490
333
|
|
491
334
|
if (@command_selected) then
|
492
|
-
#
|
493
|
-
|
494
|
-
|
335
|
+
$logger.debug("asking for lookup values for command '#{@command_selected.name}' and param '#{@current_param.name}'")
|
336
|
+
request = RHCP::Request.new(@command_selected, @collected_values, @command_broker.context)
|
337
|
+
props = @lookup_broker.get_lookup_values(request, @current_param.name)
|
495
338
|
else
|
496
|
-
props = @
|
339
|
+
props = @lookup_broker.get_command_list(@command_broker.context).values.map{|command| command.name}.sort
|
497
340
|
end
|
498
341
|
|
499
342
|
proposal_list = props.map { |p| "'#{p}'" }.join(" ")
|
@@ -503,12 +346,23 @@ class RHCPShellBackend < ShellBackend
|
|
503
346
|
props.select{|name|name[0...(prefix.size)] == prefix}
|
504
347
|
end
|
505
348
|
|
506
|
-
def show_banner
|
349
|
+
def show_banner
|
507
350
|
puts @banner
|
508
351
|
end
|
509
352
|
|
353
|
+
require 'util/colorize'
|
354
|
+
|
355
|
+
def prompt
|
356
|
+
if @current_param != nil
|
357
|
+
"#{@command_selected.name}.#{@current_param.name} $ "
|
358
|
+
else
|
359
|
+
@current_prompt || "$ "
|
360
|
+
#"#{@current_prompt and @current_prompt != '' ? @current_prompt + " " : ""}$ "
|
361
|
+
end
|
362
|
+
end
|
363
|
+
|
510
364
|
def set_prompt(string)
|
511
|
-
@
|
365
|
+
@current_prompt = string
|
512
366
|
end
|
513
367
|
|
514
368
|
def process_ctrl_c
|
@@ -0,0 +1,15 @@
|
|
1
|
+
def colorize(text, color_code)
|
2
|
+
"\e[#{color_code}m#{text}\e[0m"
|
3
|
+
end
|
4
|
+
|
5
|
+
def red(text)
|
6
|
+
colorize(text, 31)
|
7
|
+
end
|
8
|
+
|
9
|
+
def green(text)
|
10
|
+
colorize(text, 32)
|
11
|
+
end
|
12
|
+
|
13
|
+
# Actual example
|
14
|
+
#puts 'Importing categories [ ' + green('DONE') + ' ]'
|
15
|
+
#puts 'Importing tags [' + red('FAILED') + ']'
|
data/lib/version.rb
CHANGED
@@ -50,7 +50,7 @@ class RhcpShellBackendTest < Test::Unit::TestCase
|
|
50
50
|
|
51
51
|
def setup
|
52
52
|
# set up a local broker that we'll use for testing
|
53
|
-
# TODO do something about this - it shouldn't be necessary to instantiate
|
53
|
+
# TODO do something about this - it shouldn't be necessary to instantiate the logger beforehand
|
54
54
|
$logger = Logger.new($stdout)
|
55
55
|
@log = Array.new()
|
56
56
|
@backend = BackendMock.new($broker, self.method(:add_to_log))
|
@@ -127,6 +127,8 @@ class RhcpShellBackendTest < Test::Unit::TestCase
|
|
127
127
|
commands << "help"
|
128
128
|
commands << "exit"
|
129
129
|
commands << "detail"
|
130
|
+
commands << "show_context"
|
131
|
+
commands << "set_prompt"
|
130
132
|
assert_equal commands.sort, @backend.complete.sort
|
131
133
|
assert_no_error
|
132
134
|
end
|
@@ -138,7 +140,7 @@ class RhcpShellBackendTest < Test::Unit::TestCase
|
|
138
140
|
|
139
141
|
def test_invalid_param_value
|
140
142
|
@backend.process_input "reverse input=bla"
|
141
|
-
assert_received [ "invalid value 'bla' for parameter 'input'" ]
|
143
|
+
assert_received [ "ignoring parameter value 'bla' for param 'input' : invalid value 'bla' for parameter 'input'" ]
|
142
144
|
end
|
143
145
|
|
144
146
|
def test_multi_params
|
@@ -164,24 +166,25 @@ class RhcpShellBackendTest < Test::Unit::TestCase
|
|
164
166
|
@backend.process_input "perpetuum_mobile"
|
165
167
|
assert_received [ "could not execute 'perpetuum_mobile' : don't know how to do this" ]
|
166
168
|
end
|
167
|
-
|
168
|
-
def test_wildcard_support
|
169
|
-
@backend.process_input "cook ingredient=m*"
|
170
|
-
assert_received [ "executed 'cook' successfully : mascarpone marzipan" ]
|
171
|
-
end
|
172
|
-
|
169
|
+
|
173
170
|
def test_preprocess_without_lookup_values
|
174
171
|
@backend.process_input "test thoroughly=yes"
|
175
172
|
assert_no_error
|
176
173
|
end
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
174
|
+
|
175
|
+
# TODO reactivate wildcards
|
176
|
+
# def test_wildcard_support
|
177
|
+
# @backend.process_input "cook ingredient=m*"
|
178
|
+
# assert_received [ "executed 'cook' successfully : mascarpone marzipan" ]
|
179
|
+
# end
|
180
|
+
#
|
181
|
+
# def test_wildcard_ranges
|
182
|
+
# @backend.process_input "echo input=string01..05"
|
183
|
+
# assert_received [ "executed 'echo' successfully : string01 string02 string03 string04 string05" ]
|
184
|
+
#
|
185
|
+
# @backend.process_input "echo input=string17..20"
|
186
|
+
# assert_received [ "executed 'echo' successfully : string17 string18 string19 string20" ]
|
187
|
+
# end
|
185
188
|
|
186
189
|
def test_help
|
187
190
|
@backend.process_input "help"
|
@@ -196,7 +199,7 @@ class RhcpShellBackendTest < Test::Unit::TestCase
|
|
196
199
|
@backend.process_input "help cook"
|
197
200
|
puts "LOG >>#{@log}<<"
|
198
201
|
assert_log_contains "Syntax:"
|
199
|
-
assert_log_contains "cook ingredient=<value
|
202
|
+
assert_log_contains "cook ingredient=<value> ingredient=<value2> ..."
|
200
203
|
end
|
201
204
|
|
202
205
|
def test_help_with_default_param
|
@@ -267,5 +270,39 @@ class RhcpShellBackendTest < Test::Unit::TestCase
|
|
267
270
|
# ./virtualop_rhcp.rb:131:in `setup_local_shell'
|
268
271
|
# ./virtualop_rhcp.rb:168
|
269
272
|
# exception raised: comparison of Fixnum with nil failed
|
273
|
+
|
274
|
+
# say_hello should be workable with normal parameters
|
275
|
+
def test_context_handling_normal_parameter
|
276
|
+
@backend.command_broker.context.cookies.clear
|
277
|
+
@backend.process_input "say_hello the_host=zaphod"
|
278
|
+
assert_received [ "executed 'say_hello' successfully : hello from zaphod" ]
|
279
|
+
end
|
280
|
+
|
281
|
+
def test_command_completion_with_context
|
282
|
+
# we should not see let_explode_host, but both say_hello and switch_host
|
283
|
+
assert @backend.complete.select { |command| command == "say_hello" }.size() > 0
|
284
|
+
assert @backend.complete.select { |command| command == "switch_host" }.size() > 0
|
285
|
+
assert @backend.complete.select { |command| command == "let_explode_host" }.size() == 0
|
286
|
+
|
287
|
+
# test if this changes with context
|
288
|
+
@backend.process_input "switch_host new_host=serenity"
|
289
|
+
assert @backend.complete.select { |command| command == "let_explode_host" }.size() > 0
|
290
|
+
end
|
291
|
+
|
292
|
+
def test_context_handling
|
293
|
+
# context values should be usable by commands
|
294
|
+
@backend.process_input "switch_host new_host=serenity"
|
295
|
+
#@backend.context['host'] = 'serenity'
|
296
|
+
@backend.process_input "say_hello"
|
297
|
+
assert_received [ "executed 'say_hello' successfully : hello from serenity" ]
|
298
|
+
end
|
299
|
+
|
300
|
+
def test_command_setting_context
|
301
|
+
@backend.process_input "switch_host new_host=moon"
|
302
|
+
@backend.process_input "say_hello"
|
303
|
+
assert_received [ "executed 'switch_host' successfully : hostmoon",
|
304
|
+
"executed 'say_hello' successfully : hello from moon" ]
|
305
|
+
end
|
306
|
+
|
270
307
|
|
271
308
|
end
|
data/test/setup_test_registry.rb
CHANGED
@@ -112,4 +112,40 @@ broker.register_command command2
|
|
112
112
|
|
113
113
|
p broker.get_command("build_a_table")
|
114
114
|
|
115
|
+
|
116
|
+
switch_host = RHCP::Command.new("switch_host", "modifies the context",
|
117
|
+
lambda { |request, response|
|
118
|
+
response.set_context({'host' => request.get_param_value('new_host')})
|
119
|
+
}
|
120
|
+
)
|
121
|
+
switch_host.add_param(RHCP::CommandParam.new("new_host", "the new host name",
|
122
|
+
{
|
123
|
+
:mandatory => true,
|
124
|
+
:is_default_param => true,
|
125
|
+
}
|
126
|
+
))
|
127
|
+
broker.register_command switch_host
|
128
|
+
|
129
|
+
host_command = RHCP::Command.new("say_hello", "uses context",
|
130
|
+
lambda { |request, response|
|
131
|
+
"hello from " + request.get_param_value('the_host')
|
132
|
+
}
|
133
|
+
)
|
134
|
+
host_command.add_param(RHCP::CommandParam.new("the_host", "the host name (should be taken from context)",
|
135
|
+
{
|
136
|
+
:mandatory => true,
|
137
|
+
:is_default_param => true,
|
138
|
+
:autofill_context_key => 'host'
|
139
|
+
}
|
140
|
+
))
|
141
|
+
broker.register_command host_command
|
142
|
+
|
143
|
+
context_command = RHCP::Command.new("let_explode_host", "available only in host context",
|
144
|
+
lambda { |request, response|
|
145
|
+
"kaboom."
|
146
|
+
}
|
147
|
+
)
|
148
|
+
context_command.enabled_through_context_keys = ['host']
|
149
|
+
broker.register_command context_command
|
150
|
+
|
115
151
|
$broker = broker
|
metadata
CHANGED
@@ -1,7 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rhcp_shell
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
4
|
+
hash: 1
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 2
|
9
|
+
- 11
|
10
|
+
version: 0.2.11
|
5
11
|
platform: ruby
|
6
12
|
authors:
|
7
13
|
- Philipp Traeder
|
@@ -9,19 +15,25 @@ autorequire:
|
|
9
15
|
bindir: bin
|
10
16
|
cert_chain: []
|
11
17
|
|
12
|
-
date:
|
18
|
+
date: 2011-07-26 00:00:00 +00:00
|
13
19
|
default_executable:
|
14
20
|
dependencies:
|
15
21
|
- !ruby/object:Gem::Dependency
|
16
22
|
name: rhcp
|
17
|
-
|
18
|
-
|
19
|
-
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
20
26
|
requirements:
|
21
27
|
- - ">="
|
22
28
|
- !ruby/object:Gem::Version
|
29
|
+
hash: 9
|
30
|
+
segments:
|
31
|
+
- 0
|
32
|
+
- 1
|
33
|
+
- 9
|
23
34
|
version: 0.1.9
|
24
|
-
|
35
|
+
type: :runtime
|
36
|
+
version_requirements: *id001
|
25
37
|
description:
|
26
38
|
email: philipp at hitchhackers.net
|
27
39
|
executables:
|
@@ -31,39 +43,55 @@ extensions: []
|
|
31
43
|
extra_rdoc_files: []
|
32
44
|
|
33
45
|
files:
|
46
|
+
- bin/rhcp_shell.log
|
34
47
|
- bin/rhcp_shell
|
48
|
+
- lib/util/colorize.rb
|
35
49
|
- lib/shell_backend.rb
|
50
|
+
- lib/version.rb
|
51
|
+
- lib/rhcp_shell_backend.rb
|
36
52
|
- lib/base_shell.rb
|
53
|
+
- lib/display_types/table.rb
|
37
54
|
- lib/test.log
|
38
|
-
- lib/
|
39
|
-
- lib/
|
40
|
-
-
|
55
|
+
- lib/local_commands/context.rb
|
56
|
+
- lib/local_commands/set_prompt.rb
|
57
|
+
- lib/local_commands/help.rb
|
58
|
+
- lib/local_commands/exit.rb
|
59
|
+
- lib/local_commands/detail.rb
|
41
60
|
- test/setup_test_registry.rb
|
61
|
+
- test/rhcp_shell_backend_test.rb
|
42
62
|
has_rdoc: true
|
43
63
|
homepage: http://rubyforge.org/projects/rhcp
|
64
|
+
licenses: []
|
65
|
+
|
44
66
|
post_install_message:
|
45
67
|
rdoc_options: []
|
46
68
|
|
47
69
|
require_paths:
|
48
70
|
- lib
|
49
71
|
required_ruby_version: !ruby/object:Gem::Requirement
|
72
|
+
none: false
|
50
73
|
requirements:
|
51
74
|
- - ">="
|
52
75
|
- !ruby/object:Gem::Version
|
76
|
+
hash: 3
|
77
|
+
segments:
|
78
|
+
- 0
|
53
79
|
version: "0"
|
54
|
-
version:
|
55
80
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
56
82
|
requirements:
|
57
83
|
- - ">="
|
58
84
|
- !ruby/object:Gem::Version
|
85
|
+
hash: 3
|
86
|
+
segments:
|
87
|
+
- 0
|
59
88
|
version: "0"
|
60
|
-
version:
|
61
89
|
requirements: []
|
62
90
|
|
63
91
|
rubyforge_project: rhcp
|
64
|
-
rubygems_version: 1.3.
|
92
|
+
rubygems_version: 1.3.7
|
65
93
|
signing_key:
|
66
|
-
specification_version:
|
94
|
+
specification_version: 3
|
67
95
|
summary: RHCP is a protocol designed for building up a command-metadata-based communication infrastructure making it easier for application developers to export commands in applications to generic clients - this is the generic shell for it.
|
68
96
|
test_files: []
|
69
97
|
|