rhcp_shell 0.0.9 → 0.2.11
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.
- 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
|
|