zabcon 0.0.6 → 0.0.327
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/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
|