zabcon 0.0.6 → 0.0.327
Sign up to get free protection for your applications and to get access to all the features.
- data/libs/argument_processor.rb +430 -567
- data/libs/command_help.rb +11 -61
- data/libs/command_tree.rb +480 -280
- data/libs/lexer.rb +846 -0
- data/libs/printer.rb +25 -25
- data/libs/revision.rb +1 -0
- data/libs/utility_items.rb +137 -0
- data/libs/zabbix_server.rb +379 -0
- data/libs/zabcon_commands.rb +558 -0
- data/libs/zabcon_core.rb +177 -316
- data/libs/zabcon_exceptions.rb +4 -4
- data/libs/zabcon_globals.rb +29 -6
- data/zabcon.conf.default +38 -3
- data/zabcon.rb +72 -50
- metadata +23 -48
- data/libs/zbxcliserver.rb +0 -325
data/libs/command_tree.rb
CHANGED
@@ -16,133 +16,441 @@
|
|
16
16
|
#along with this program; if not, write to the Free Software
|
17
17
|
#Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
18
18
|
|
19
|
+
#--
|
19
20
|
##########################################
|
20
21
|
# Subversion information
|
21
|
-
# $Id: command_tree.rb
|
22
|
-
# $Revision:
|
22
|
+
# $Id: command_tree.rb 325 2011-09-26 08:57:00Z nelsonab $
|
23
|
+
# $Revision: 325 $
|
23
24
|
##########################################
|
25
|
+
#++
|
24
26
|
|
25
|
-
require '
|
27
|
+
require 'singleton'
|
28
|
+
require 'libs/lexer'
|
29
|
+
require 'zbxapi/zdebug'
|
26
30
|
require 'libs/zabcon_exceptions'
|
31
|
+
require 'libs/zabcon_globals'
|
32
|
+
require 'libs/argument_processor'
|
27
33
|
|
28
|
-
class
|
34
|
+
class ZabconExecuteBase
|
35
|
+
include ZDebug
|
36
|
+
|
37
|
+
attr_reader :results
|
38
|
+
|
39
|
+
def execute
|
40
|
+
raise "Unitialized base method"
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
class ZabconExecuteCommand < ZabconExecuteBase
|
46
|
+
|
47
|
+
class NilCommand < Exception
|
48
|
+
end
|
49
|
+
|
50
|
+
#TODO Calling/showing help needs to be streamlined and cleaned up better
|
51
|
+
class Help < Exception
|
52
|
+
attr_reader :obj
|
53
|
+
def initialize(obj)
|
54
|
+
@obj=obj
|
55
|
+
end
|
56
|
+
|
57
|
+
def show_help
|
58
|
+
@obj.help.call
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
attr_reader :show_params, :options, :help
|
63
|
+
|
64
|
+
#Configure the command item
|
65
|
+
#Also perform the necessary argument processing at this step.
|
66
|
+
def initialize(cmd_obj)
|
67
|
+
raise "cmd_obj must be fo type CommandList::Cmd" if cmd_obj.class!=CommandList::Cmd
|
68
|
+
|
69
|
+
@results=nil
|
70
|
+
@proc=cmd_obj.command_obj.method(:execute)
|
71
|
+
@command_obj=cmd_obj.command_obj
|
72
|
+
begin
|
73
|
+
arg_result=@command_obj.call_arg_processor(cmd_obj.parameters)
|
74
|
+
rescue ParameterError => e
|
75
|
+
e.help_func=cmd_obj.command_obj.help_method
|
76
|
+
raise e
|
77
|
+
end
|
78
|
+
@cmd_params=arg_result.cmd_params
|
79
|
+
@show_params=arg_result.show_params
|
80
|
+
@printing=cmd_obj.command_obj.print?
|
81
|
+
@command_name=cmd_obj.command_obj.command_name
|
82
|
+
# @help=cmd_obj.help
|
83
|
+
# @options=options
|
84
|
+
|
85
|
+
end
|
86
|
+
|
87
|
+
def print?
|
88
|
+
@printing==true
|
89
|
+
end
|
90
|
+
|
91
|
+
def execute
|
92
|
+
|
93
|
+
@results=@command_obj.execute(@cmd_params)
|
94
|
+
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
class ZabconExecuteVariable < ZabconExecuteBase
|
99
|
+
def initialize(var)
|
100
|
+
@var=var
|
101
|
+
end
|
102
|
+
|
103
|
+
def assign(val)
|
104
|
+
@results=val
|
105
|
+
GlobalVars.instance[@var]=val
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
109
|
+
|
110
|
+
class ZabconExecuteContainer
|
29
111
|
|
30
112
|
include ZDebug
|
31
113
|
|
32
|
-
attr_reader :
|
114
|
+
attr_reader :show_params, :results, :options
|
115
|
+
|
116
|
+
def initialize(usr_str)
|
117
|
+
@initial_string=usr_str
|
118
|
+
@commands=[]
|
119
|
+
@printing=true
|
120
|
+
commandlist=CommandList.instance
|
121
|
+
|
122
|
+
tokens=Tokenizer.new(usr_str)
|
123
|
+
|
124
|
+
#split_str=usr_str.split2(:split_char=>'=|\s', :include_split=>true)
|
125
|
+
#
|
126
|
+
#unravel=false #remove any extra space before the first =
|
127
|
+
#split_str2=split_str.map {|item|
|
128
|
+
# if unravel
|
129
|
+
# item
|
130
|
+
# elsif item=="="
|
131
|
+
# unravel=true
|
132
|
+
# item
|
133
|
+
# elsif item.empty?
|
134
|
+
# nil
|
135
|
+
# elsif item.scan(/\s/).empty?
|
136
|
+
# item
|
137
|
+
# else
|
138
|
+
# nil
|
139
|
+
# end
|
140
|
+
#}.delete_if {|i| i.nil?}
|
141
|
+
#
|
142
|
+
#if !split_str2[1].nil? && split_str2[1]=='='
|
143
|
+
# split_str=split_str2 #use the trimmed version
|
144
|
+
# var_name=split_str[0].strip
|
145
|
+
# raise ParseError.new("Variable names cannot contain spaces or invalid characters \"#{var_name}\"",:retry=>true) if !var_name.scan(/[^\w]/).empty?
|
146
|
+
#
|
147
|
+
# debug(5,:var=>var_name,:msg=>"Creating Variable assignment")
|
148
|
+
# add(ZabconExecuteVariable.new(var_name))
|
149
|
+
#
|
150
|
+
# usr_str=split_str[2..split_str.length-1].join.strip
|
151
|
+
# debug(5,:var=>usr_str,:msg=>"Continuging to parse with")
|
152
|
+
#end
|
153
|
+
#
|
154
|
+
#debug(6,:var=>split_str,:msg=>"Split Str")
|
155
|
+
#debug(6,:var=>split_str2,:msg=>"Split Str2")
|
156
|
+
#debug(6,:var=>usr_str,:msg=>"User Str")
|
157
|
+
pos=tokens.walk(0)
|
158
|
+
if (positions=tokens.assignment?(pos,:return_pos=>true))
|
159
|
+
var_name = tokens[positions[0]].value
|
160
|
+
debug(5,:var=>var_name,:msg=>"Creating Variable assignment")
|
161
|
+
add(ZabconExecuteVariable.new(var_name))
|
162
|
+
tokens=tokens.drop(positions[2]+1)
|
163
|
+
end
|
164
|
+
|
165
|
+
cmd_str=tokens.map{|i| i.value}.join
|
166
|
+
debug(5,:msg=>"Command String",:var=>cmd_str)
|
167
|
+
cmd=commandlist.find_and_parse(cmd_str)
|
168
|
+
add(ZabconExecuteCommand.new(cmd))
|
33
169
|
|
34
|
-
def initialize(default_argument_processor)
|
35
|
-
@commands=NewCommandTree.new
|
36
|
-
@default_argument_processor=default_argument_processor
|
37
170
|
end
|
38
171
|
|
39
|
-
def
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
172
|
+
def print?
|
173
|
+
@printing==true #Ensure we get a boolean ;-)
|
174
|
+
end
|
175
|
+
|
176
|
+
def add(obj)
|
177
|
+
raise "Expected ZabconExecuteCommand Class" if
|
178
|
+
obj.class!=ZabconExecuteCommand &&
|
179
|
+
obj.class!=ZabconExecuteVariable
|
180
|
+
@commands<<obj
|
181
|
+
if obj.class==ZabconExecuteCommand
|
182
|
+
@printing=@printing & obj.print?
|
183
|
+
@show_params=obj.show_params
|
184
|
+
@options=obj.options
|
185
|
+
end
|
186
|
+
|
187
|
+
end
|
188
|
+
|
189
|
+
def execute
|
190
|
+
stack=[]
|
191
|
+
ptr=0
|
192
|
+
while ptr<@commands.length
|
193
|
+
case @commands[ptr].class.to_s
|
194
|
+
when "ZabconExecuteCommand"
|
195
|
+
@commands[ptr].execute
|
196
|
+
@results=@commands[ptr].results
|
197
|
+
when "ZabconExecuteVariable"
|
198
|
+
stack<<ptr
|
199
|
+
end
|
200
|
+
ptr+=1
|
201
|
+
end
|
202
|
+
|
203
|
+
while !stack.empty?
|
204
|
+
ptr=stack.pop
|
205
|
+
@commands[ptr].assign(@results)
|
48
206
|
end
|
49
207
|
end
|
50
208
|
|
51
|
-
|
52
|
-
|
209
|
+
end
|
210
|
+
|
211
|
+
|
212
|
+
#Command is the main class used to define commands in Zabcon which are then
|
213
|
+
#inserted into the global singleton class CommandList
|
214
|
+
class Command
|
215
|
+
attr_reader :str, :aliases, :argument_processor, :flags
|
216
|
+
attr_reader :required_args, :valid_args
|
217
|
+
attr_reader :help_tag, :path
|
53
218
|
|
54
|
-
|
219
|
+
include ArgumentProcessor
|
220
|
+
|
221
|
+
#Class containing processed arguments to be passed to the command
|
222
|
+
class Arguments
|
223
|
+
class ParameterError < Exception
|
224
|
+
end
|
55
225
|
|
226
|
+
attr_accessor :cmd_params
|
227
|
+
attr_reader :show_params
|
56
228
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
229
|
+
def initialize(args, flags)
|
230
|
+
if args.class==String
|
231
|
+
@cmd_params=args
|
232
|
+
@show_params=nil
|
233
|
+
else
|
234
|
+
raise "Unknown Argument Object type: #{args.class}" if args.class!=Array && args.class!=Hash
|
235
|
+
|
236
|
+
@cmd_params=args
|
237
|
+
@show_params = {}
|
238
|
+
if args.class!=Array && (args["show"] || flags[:default_cols])
|
239
|
+
show=args["show"] || flags[:default_cols]
|
240
|
+
@show_params={:show=>show}
|
241
|
+
@cmd_params.delete("show") if args["show"]
|
242
|
+
@cmd_params.merge!({"extendoutput"=>true})
|
243
|
+
end
|
244
|
+
end
|
245
|
+
end
|
61
246
|
|
247
|
+
def show_params=(value)
|
248
|
+
raise ParameterError.new("Show argument must be of type Array") if !vaue.is_a?(Array)
|
249
|
+
@show_params=value
|
250
|
+
end
|
62
251
|
end
|
63
252
|
|
253
|
+
class LoginRequired < Exception
|
254
|
+
end
|
64
255
|
|
65
|
-
|
66
|
-
|
67
|
-
# of the return hash
|
68
|
-
# the return hash consists of:
|
69
|
-
# :proc - the name of the procedure which will execute the associated command
|
70
|
-
# :api_params - parameters to pass to the API call
|
71
|
-
# :show_params - parameters to pass to the print routines
|
72
|
-
# :helpproc - help procedure associated with the command
|
73
|
-
# The argument processor function is passed a string of the arguments after the command, along with the
|
74
|
-
# array of valid arguments and the help function associated with the command.
|
75
|
-
# If the argument processor has an error it should call the help function and return nil. In which case this function
|
76
|
-
# will return nil
|
77
|
-
def parse(str,user_vars=nil)
|
78
|
-
debug(7,str,"Parsing")
|
79
|
-
# options=
|
80
|
-
debug(7,user_vars,"User Variables")
|
256
|
+
class ParameterError < Exception
|
257
|
+
end
|
81
258
|
|
82
|
-
|
259
|
+
class ArgumentError < Exception
|
260
|
+
end
|
83
261
|
|
84
|
-
|
262
|
+
class LoopError < Exception
|
263
|
+
end
|
85
264
|
|
86
|
-
|
87
|
-
|
265
|
+
def initialize(path)
|
266
|
+
raise "Path must be an array" if path.class!=Array
|
267
|
+
@path=path
|
268
|
+
@cmd_method=nil
|
269
|
+
@valid_args=[]
|
270
|
+
@aliases=[]
|
271
|
+
@flags={}
|
272
|
+
@result_type=nil
|
273
|
+
|
274
|
+
#TODO Can the argument processor stuff be cleaned up?
|
275
|
+
@argument_processor=method(:default_processor)
|
276
|
+
@help_tag=nil
|
277
|
+
@depreciated=nil
|
278
|
+
end
|
279
|
+
|
280
|
+
def command_name
|
281
|
+
@path.join(" ")
|
282
|
+
end
|
283
|
+
|
284
|
+
def print?
|
285
|
+
if @flags.nil?
|
286
|
+
false
|
88
287
|
else
|
89
|
-
|
90
|
-
# command node is created
|
91
|
-
debug(6,result[:parameters],"calling argument processor")
|
92
|
-
args=cmd[:argument_processor].call(result[:parameters],user_vars)
|
93
|
-
debug(6,args,"received from argument processor")
|
94
|
-
retval = args.nil? ? nil : {:proc=>cmd[:commandproc], :helpproc=>cmd[:helpproc], :options=>cmd[:options]}.merge(args)
|
95
|
-
return retval
|
288
|
+
@flags[:print_output]==true
|
96
289
|
end
|
97
290
|
end
|
98
291
|
|
99
|
-
def
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
292
|
+
def set_method(&cmd_method)
|
293
|
+
@cmd_method=cmd_method
|
294
|
+
end
|
295
|
+
|
296
|
+
#Adds an alias name for the current command
|
297
|
+
def add_alias(name)
|
298
|
+
@aliases<<name.split2
|
299
|
+
end
|
300
|
+
|
301
|
+
#How many alias' are there?
|
302
|
+
def alias_total
|
303
|
+
@aliases.length
|
304
|
+
end
|
305
|
+
|
306
|
+
def generate_alias(index)
|
307
|
+
raise "Index out of bounds 0 >= i < N, i=#{index} N=#{alias_total}" if index<0 || index>=alias_total
|
308
|
+
new_alias=self.dup
|
309
|
+
new_alias.instance_variable_set("@path",@aliases[index])
|
310
|
+
new_alias.instance_variable_set("@aliases",[])
|
311
|
+
new_alias
|
312
|
+
end
|
313
|
+
|
314
|
+
#accepts an array of valid arguments
|
315
|
+
def set_valid_args(args)
|
316
|
+
@valid_args=args
|
317
|
+
end
|
318
|
+
|
319
|
+
def default_show(cols)
|
320
|
+
raise "Cols must be an array" if cols.class!=Array
|
321
|
+
@flags[:default_cols]=cols
|
322
|
+
end
|
323
|
+
|
324
|
+
def depreciated(str)
|
325
|
+
@depreciated=str
|
326
|
+
end
|
327
|
+
|
328
|
+
def arg_processor(&block)
|
329
|
+
@argument_processor=block
|
330
|
+
end
|
331
|
+
|
332
|
+
def set_arg_processor(method)
|
333
|
+
@argument_processor=method
|
334
|
+
end
|
335
|
+
|
336
|
+
def set_help_tag(sym)
|
337
|
+
@help_tag=sym
|
338
|
+
end
|
339
|
+
|
340
|
+
#--
|
341
|
+
#TODO Complete type casting section and add error checking
|
342
|
+
#++
|
343
|
+
#Valid flags:
|
344
|
+
# :login_required - command requires a valid login
|
345
|
+
# :print_output - the output of the command will be passed to the print processor
|
346
|
+
# :array_params - Only process the parameters as an array
|
347
|
+
def set_flag(flag)
|
348
|
+
case flag.class.to_s
|
349
|
+
when "Symbol"
|
350
|
+
flag={flag=>true}
|
108
351
|
end
|
109
352
|
|
110
|
-
|
111
|
-
|
112
|
-
|
353
|
+
@flags.merge!(flag)
|
354
|
+
end
|
355
|
+
|
356
|
+
def call_arg_processor(parameters)
|
357
|
+
def set_show_args(args)
|
358
|
+
@arguments.show_params=args
|
359
|
+
end
|
113
360
|
|
114
|
-
|
115
|
-
|
116
|
-
|
361
|
+
@arguments=Arguments.new("",@flags)
|
362
|
+
result=@argument_processor.call(parameters,@valid_args,@flags)
|
363
|
+
return result if result.is_a?(Arguments)
|
364
|
+
if !result.is_a?(String) && !result.is_a?(Hash) && !result.is_a?(Array)
|
365
|
+
raise ("Arugment processor for \"#{command_name}\" returned invalid parameters: class: #{result.class}, #{result}")
|
117
366
|
else
|
118
|
-
|
119
|
-
|
367
|
+
@arguments.cmd_params=result
|
368
|
+
arguments=@arguments
|
369
|
+
return arguments
|
120
370
|
end
|
121
371
|
end
|
122
372
|
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
373
|
+
#Sets the symbold describing the result type. May be used by the print processor
|
374
|
+
# as a hint for printing the output.
|
375
|
+
def result_type(type)
|
376
|
+
@result_type=type
|
377
|
+
end
|
378
|
+
|
379
|
+
def execute(parameters)
|
380
|
+
def set_result_message(msg)
|
381
|
+
@response.message=msg
|
382
|
+
end
|
383
|
+
|
384
|
+
def set_result_type(type)
|
385
|
+
@response.type=type
|
386
|
+
end
|
387
|
+
|
388
|
+
# def output(params)
|
389
|
+
# @response.data<<params
|
390
|
+
# end
|
391
|
+
|
392
|
+
raise LoopError.new("Loop detected, Command.execute called more than 3 times") if caller.grep(caller[0]).length>3
|
393
|
+
@response=Response.new
|
394
|
+
@response.type=@result_type if !@result_type.nil?
|
395
|
+
|
396
|
+
puts @depreciated if !@depreciated.nil?
|
397
|
+
if !@flags.nil? && @flags[:login_required] && !server.connected?
|
398
|
+
raise LoginRequired.new("\"#{@command_name}\" requires an active login")
|
399
|
+
end
|
400
|
+
|
401
|
+
@response.data=@cmd_method.call(parameters)
|
402
|
+
|
403
|
+
retval=@response #ensure @result is empty for our next use
|
404
|
+
@response=nil
|
127
405
|
|
128
|
-
|
129
|
-
arg_processor = argument_processor.nil? ? @default_argument_processor : argument_processor
|
130
|
-
@commands.insert(insert_path,commandproc,arguments,helpproc,arg_processor,options)
|
406
|
+
retval
|
131
407
|
end
|
132
408
|
|
133
|
-
|
409
|
+
private
|
134
410
|
|
135
|
-
|
411
|
+
def parameter_error(msg)
|
412
|
+
raise ParameterError.new(msg)
|
413
|
+
end
|
136
414
|
|
137
|
-
|
415
|
+
def server
|
416
|
+
ZabbixServer.instance
|
417
|
+
end
|
418
|
+
|
419
|
+
def global_vars
|
420
|
+
GlobalVars.instance
|
421
|
+
end
|
422
|
+
end
|
423
|
+
|
424
|
+
class CommandList
|
138
425
|
include ZDebug
|
426
|
+
include Singleton
|
427
|
+
|
428
|
+
class InvalidCommand < Exception
|
429
|
+
def initialize(str)
|
430
|
+
@str=str
|
431
|
+
end
|
432
|
+
|
433
|
+
def message
|
434
|
+
"Unknown or Invalid Command: #{@str}"
|
435
|
+
end
|
436
|
+
end
|
437
|
+
|
438
|
+
class Cmd
|
439
|
+
attr_reader :command_obj, :parameters
|
440
|
+
|
441
|
+
def initialize(command_obj,parameters)
|
442
|
+
@command_obj=command_obj
|
443
|
+
@parameters=parameters
|
444
|
+
end
|
445
|
+
end #End Cmd sub class
|
139
446
|
|
140
447
|
def initialize
|
141
|
-
@
|
448
|
+
@cmd_tree={}
|
142
449
|
end
|
143
450
|
|
144
|
-
def insert(insert_path,
|
145
|
-
|
451
|
+
def insert(insert_path, cmd_obj)
|
452
|
+
raise "Insert_path must be an array" if insert_path.class!=Array
|
453
|
+
tree_node=@cmd_tree
|
146
454
|
path_length=insert_path.length-1
|
147
455
|
insert_path.each_index do |index|
|
148
456
|
if tree_node[insert_path[index]].nil?
|
@@ -150,241 +458,133 @@ class NewCommandTree
|
|
150
458
|
tree_node[insert_path[index]]={}
|
151
459
|
tree_node=tree_node[insert_path[index]]
|
152
460
|
else
|
153
|
-
|
154
|
-
if argument_processor.nil?
|
155
|
-
nil
|
156
|
-
else
|
157
|
-
argument_processor.call(helpproc,arguments,params,user_vars,options) # We pass the list of valid arguments to
|
158
|
-
end
|
159
|
-
end
|
160
|
-
if options.nil?
|
161
|
-
local_options=nil
|
162
|
-
else
|
163
|
-
local_options = Hash[*options.collect { |v|
|
164
|
-
[v, true]
|
165
|
-
}.flatten]
|
166
|
-
end
|
167
|
-
tree_node[insert_path[index]]={:node=>
|
168
|
-
{:commandproc=>commandproc, :arguments=>arguments, :helpproc=>helpproc,
|
169
|
-
:argument_processor=>local_arg_processor,:options=>local_options}}
|
461
|
+
tree_node[insert_path[index]]={:node=>cmd_obj}
|
170
462
|
end
|
171
463
|
else
|
172
464
|
tree_node=tree_node[insert_path[index]]
|
173
465
|
end
|
174
466
|
end
|
467
|
+
|
468
|
+
(0..(cmd_obj.alias_total-1)).each {|i|
|
469
|
+
insert(cmd_obj.aliases[i],cmd_obj.generate_alias(i))} if cmd_obj.alias_total>0
|
175
470
|
end
|
176
471
|
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
#
|
182
|
-
#example:
|
183
|
-
# get_command("get host show=all")
|
184
|
-
# {:command=>{hash created from insert}, :parameters=>"show=all"}
|
185
|
-
#
|
186
|
-
# get_command("get host test test2")
|
187
|
-
# {:command=>{hash created from insert}, :parameters=>"test test2"
|
188
|
-
def get_command(str)
|
189
|
-
str_array=str.downcase.split #ensure all comparisons are done in lower case
|
190
|
-
str_items=str_array.length
|
191
|
-
|
192
|
-
cur_node=@tree
|
472
|
+
def get(path)
|
473
|
+
path=setup_path(path)
|
474
|
+
|
475
|
+
cur_node=@cmd_tree
|
193
476
|
count=0
|
194
477
|
|
195
|
-
|
478
|
+
path.collect do |item|
|
196
479
|
break if cur_node[item].nil?
|
197
480
|
count+=1
|
198
481
|
|
199
482
|
cur_node=cur_node[item]
|
200
483
|
end
|
201
484
|
|
202
|
-
cmd=
|
203
|
-
|
204
|
-
#remove preceding items found so we can return the remainder
|
205
|
-
#as the parameters
|
206
|
-
count.times do |i|
|
207
|
-
str=str.gsub(/^#{str_array[i]}/,"")
|
208
|
-
str=str.gsub(/^\s*/,"")
|
209
|
-
end
|
210
|
-
|
211
|
-
{:command=>cmd,:parameters=>str}
|
485
|
+
cmd=cur_node.nil? ? nil : cur_node[:node]
|
212
486
|
end
|
213
487
|
|
214
|
-
|
215
|
-
def search(search_path)
|
216
|
-
debug(10,search_path,"search_path")
|
217
|
-
return retval if results.empty? # no more children to search, return retval which may be self or nil, see logic above
|
218
|
-
debug(10)
|
488
|
+
def find_and_parse(str)
|
219
489
|
|
220
|
-
|
221
|
-
|
490
|
+
tokens=Tokenizer.new(str)
|
491
|
+
token_items=tokens.length
|
222
492
|
|
223
|
-
|
493
|
+
cur_node=@cmd_tree
|
494
|
+
pos=tokens.walk(0)
|
224
495
|
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
# Insert path is the path to insert the item into the tree
|
232
|
-
# Insert path is passed in as an array of names which associate with pre-existing nodes
|
233
|
-
# The function will recursively insert the command and will remove the top of the input path stack at each level until it
|
234
|
-
# finds the appropraite level. If the appropriate level is never found an exception is raised.
|
235
|
-
def do_insert(insert_path,command,commandproc,arguments,helpproc,argument_processor,options,depth)
|
236
|
-
debug(11,{"insert_path"=>insert_path, "command"=>command, "commandproc"=>commandproc, "arguments"=> arguments,
|
237
|
-
"helpproc"=>helpproc, "verify_func"=>argument_processor, "depth"=>depth})
|
238
|
-
debug(11,@command,"self.command")
|
239
|
-
# debug(11,@children.map {|child| child.command},"children")
|
240
|
-
|
241
|
-
if insert_path[0]==@command then
|
242
|
-
debug(11,"Found node")
|
243
|
-
if insert_path.length==1 then
|
244
|
-
debug(11,command,"inserting")
|
245
|
-
@children << CommandTree.new(command,commandproc,depth+1,arguments,helpproc,argument_processor,options)
|
246
|
-
else
|
247
|
-
debug(11,"Not found walking tree")
|
248
|
-
insert_path.shift
|
249
|
-
if !@children.empty? then
|
250
|
-
@children.each { |node| node.do_insert(insert_path,command,commandproc,arguments,helpproc,argument_processor,options,depth+1)}
|
251
|
-
else
|
252
|
-
raise(Command_Tree_Exception,"Unable to find insert point in Command Tree")
|
253
|
-
end
|
254
|
-
end
|
255
|
-
end
|
256
|
-
end
|
257
|
-
|
258
|
-
=begin
|
259
|
-
class CommandTree
|
260
|
-
|
261
|
-
include ZDebug
|
262
|
-
|
263
|
-
attr_reader :command, :commandproc, :children, :arguments, :helpproc, :depth, :argument_processor, :options
|
264
|
-
|
265
|
-
# Arguments hash takes the form of {"name"=>{:type=>Class, :optional=>true/false}}
|
266
|
-
# If type is nil then the argument takes no options
|
267
|
-
def initialize(command,commandproc,depth,arguments,helpproc,argument_processor,options)
|
268
|
-
debug(10,{"command"=>command, "commandproc"=>commandproc, "arguments"=> arguments,"helpproc"=>helpproc,
|
269
|
-
"verify_func"=>argument_processor, "depth"=>depth, "options"=>options})
|
270
|
-
@command=command
|
271
|
-
@commandproc=commandproc
|
272
|
-
@children=[]
|
273
|
-
@arguments=arguments
|
274
|
-
@helpproc=helpproc
|
275
|
-
@depth=depth
|
276
|
-
# verify functions are special.
|
277
|
-
# We pass them the list of valid arguments first and then the parameters which need to be verified
|
278
|
-
# This will allow for either unique or generalized verification functions
|
279
|
-
# The verify function can safely be called with objects with no verify function as nil checking is performed in the
|
280
|
-
# lambda
|
281
|
-
# If no verify function was setup we return true
|
282
|
-
@argument_processor=lambda do |params,user_vars|
|
283
|
-
if argument_processor.nil?
|
284
|
-
nil
|
285
|
-
else
|
286
|
-
argument_processor.call(@helpproc,@arguments,params,user_vars,options) # We pass the list of valid arguments to
|
287
|
-
end
|
288
|
-
end
|
289
|
-
if options.nil?
|
290
|
-
@options=nil
|
291
|
-
else
|
292
|
-
@options = Hash[*options.collect { |v|
|
293
|
-
[v, true]
|
294
|
-
}.flatten]
|
496
|
+
while !tokens.end?(pos)
|
497
|
+
item=tokens[pos].value
|
498
|
+
break if cur_node[item].nil?
|
499
|
+
cur_node=cur_node[item]
|
500
|
+
pos=tokens.walk(pos+1)
|
295
501
|
end
|
296
|
-
debug(10,self.inspect,"Initialization complete")
|
297
|
-
end
|
298
502
|
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
r_str+= children.inspect
|
309
|
-
end
|
310
|
-
r_str+=">"
|
311
|
-
r_str
|
312
|
-
end
|
503
|
+
#tokens.each do |item|
|
504
|
+
# if item.empty? || !item.scan(/^\s*$/).empty?
|
505
|
+
# count+=1
|
506
|
+
# else
|
507
|
+
# break if cur_node[item].nil?
|
508
|
+
# count+=1
|
509
|
+
# cur_node=cur_node[item]
|
510
|
+
# end
|
511
|
+
#end
|
313
512
|
|
314
|
-
|
315
|
-
# or the immediate children nodes. It does not search the tree beyond one level.
|
316
|
-
# The loggedin argument is used to differentiate searching for commands which require a valid
|
317
|
-
# login or not. If loggedin is false it will return commands which do not require a valid login.
|
318
|
-
debug(10,self,"self",300)
|
513
|
+
raise InvalidCommand.new(str) if cur_node.nil? || !cur_node[:node]
|
319
514
|
|
320
|
-
|
321
|
-
|
515
|
+
cmd=cur_node[:node]
|
516
|
+
#params=str_array[count..str_array.length].join.strip
|
322
517
|
|
323
|
-
|
518
|
+
debug(6,:msg=>"Tokens", :var=>tokens)
|
519
|
+
debug(6,:msg=>"Pos", :var=>pos)
|
520
|
+
debug(6,:msg=>"Parsed", :var=>tokens.parse)
|
521
|
+
params = tokens.drop(pos+1).join
|
324
522
|
|
325
|
-
|
523
|
+
debug(6,:msg=>"Parameters", :var=>params)
|
326
524
|
|
525
|
+
Cmd.new(cmd,params)
|
526
|
+
end
|
327
527
|
|
328
|
-
|
329
|
-
|
528
|
+
def get_command_list(tree=nil)
|
529
|
+
def get_subtree(tree)
|
530
|
+
tmp=tree.dup
|
531
|
+
path=nil
|
532
|
+
if !tmp[:node].nil?
|
533
|
+
path=tree[:node].path.join(" ")
|
534
|
+
tmp.delete(:node)
|
535
|
+
end
|
536
|
+
tree=tmp
|
330
537
|
|
331
|
-
|
538
|
+
if tree.empty?
|
539
|
+
return path if !path.nil?
|
540
|
+
return nil
|
541
|
+
end
|
542
|
+
results=tree.keys.sort.map {|key|
|
543
|
+
get_subtree(tree[key])
|
544
|
+
}
|
545
|
+
[path,results]
|
546
|
+
end
|
332
547
|
|
333
|
-
|
334
|
-
|
335
|
-
debug(10,@children.map{|child| child.command},"Current children")
|
548
|
+
get_subtree(@cmd_tree).flatten.compact.sort
|
549
|
+
end
|
336
550
|
|
337
|
-
|
338
|
-
results.compact!
|
339
|
-
debug(10,results,"Children search results",200)
|
551
|
+
private
|
340
552
|
|
553
|
+
def setup_path(path)
|
554
|
+
if path.class==Array
|
555
|
+
path
|
556
|
+
elsif path.class==String
|
557
|
+
path.split2
|
558
|
+
else
|
559
|
+
raise "Path must be Array or string"
|
560
|
+
end
|
561
|
+
end
|
341
562
|
end
|
342
|
-
=end
|
343
|
-
|
344
|
-
|
345
|
-
if __FILE__ == $0
|
346
|
-
|
347
|
-
require 'pp'
|
348
|
-
require 'argument_processor'
|
349
563
|
|
350
|
-
|
351
|
-
|
352
|
-
commands
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
564
|
+
#Base module for instantiating Zabcon commands.
|
565
|
+
module ZabconCommand
|
566
|
+
#Method used to add commands to the Zabcon command processor
|
567
|
+
#path is the command path such as "get host group"
|
568
|
+
#A block must also be passed, this block will be executed against the
|
569
|
+
# Command object to to define the command and then inserted into the
|
570
|
+
# global CommandList singleton.
|
571
|
+
def self.add_command (path, &block)
|
572
|
+
path=
|
573
|
+
if path.class==Array
|
574
|
+
path
|
575
|
+
elsif path.class==String
|
576
|
+
path.split2(:trim_empty=>true)
|
577
|
+
else
|
578
|
+
raise "Path must be Array or string"
|
579
|
+
end
|
580
|
+
cmd=Command.new(path)
|
581
|
+
cmd.instance_eval(&block)
|
582
|
+
raise "Help tag required for \"#{path.join(" ")}\", and must be of type symbol. Use the symbol :none for no help" if cmd.help_tag.class!=Symbol
|
583
|
+
CommandList.instance.insert(path,cmd)
|
360
584
|
end
|
361
|
-
commands.set_debug_level(0)
|
362
|
-
commands.insert "", "help", lambda { puts "This is a generic help stub" }
|
363
|
-
puts
|
364
|
-
commands.insert "", "get", nil
|
365
|
-
puts
|
366
|
-
commands.insert "get", "host", :gethost, {"show"=>{:type=>nil,:optional=>true}}
|
367
|
-
commands.set_debug_level(0)
|
368
|
-
puts
|
369
|
-
commands.insert "get", "user", :getuser
|
370
|
-
puts
|
371
|
-
commands.insert "get user", "group", :getusergroup
|
372
|
-
puts
|
373
|
-
|
374
|
-
pp commands
|
375
|
-
|
376
|
-
commands.set_debug_level(0)
|
377
|
-
|
378
|
-
test_parse("get user")
|
379
|
-
test_parse("get user show=all arg1 arg2")
|
380
|
-
test_parse("get user show=\"id, one, two, three\" arg1 arg2")
|
381
|
-
test_parse("get user group show=all arg1")
|
382
|
-
test_parse("set value")
|
383
|
-
test_parse("help")[:proc].call
|
384
585
|
|
586
|
+
end
|
385
587
|
|
386
|
-
|
387
|
-
p commands.complete("help")
|
388
|
-
p commands.complete("get user all")
|
588
|
+
if __FILE__ == $0
|
389
589
|
|
390
590
|
end
|