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/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 272 2011-01-06 21:04:22Z nelsonab $
22
- # $Revision: 272 $
22
+ # $Id: command_tree.rb 325 2011-09-26 08:57:00Z nelsonab $
23
+ # $Revision: 325 $
23
24
  ##########################################
25
+ #++
24
26
 
25
- require 'libs/zdebug'
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 Parser
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 :commands
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 strip_comments(str)
40
- str.lstrip!
41
- str.chomp!
42
- if str =~ /^ ## .*/ then
43
- str = ""
44
- elsif str =~ /(.+) ## .*/ then
45
- str = Regexp.last_match(1)
46
- else
47
- str
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
- def search(str)
52
- debug(7,str,"Searching")
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
- str=strip_comments(str)
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
- # cmd_node=@commands.search(nodes) # a side effect of the function is that it also manipulates nodes
58
- cmd_node=@commands.get_command(str)
59
- debug(7,cmd_node,"search result")
60
- return cmd_node[:command],cmd_node[:parameters]
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
- # Returns nil if the command is incomplete or unknown
66
- # If the command is known the associated argument processor is also called and it's results are returned as part
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
- result=@commands.get_command(str)
259
+ class ArgumentError < Exception
260
+ end
83
261
 
84
- cmd=result[:command]
262
+ class LoopError < Exception
263
+ end
85
264
 
86
- if cmd.nil? or cmd[:commandproc].nil? then
87
- raise ParseError.new("Parse error, incomplete/unknown command: #{str}",:retry=>true)
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
- # The call here to the argument process requires one argument as it's a lambda block which is setup when the
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 complete(str,loggedin=false)
100
- nodes = str.split
101
- cmd_node=@commands
102
- i=0
103
- while i<nodes.length
104
- tmp=cmd_node.search(nodes[i])
105
- break if tmp.nil?
106
- cmd_node=tmp
107
- i+=1
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
- if cmd_node.commandproc.nil? then
111
- # roll up the list of available commands.
112
- commands = cmd_node.children.collect {|node| node.command}
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
- # don't include the current node if the command is empty
115
- if cmd_node.command!="" then commands += [cmd_node.command] end
116
- return commands
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
- puts "complete"
119
- return nil
367
+ @arguments.cmd_params=result
368
+ arguments=@arguments
369
+ return arguments
120
370
  end
121
371
  end
122
372
 
123
- def insert(insert_path,commandproc,arguments=[],helpproc=nil,argument_processor=nil,*options)
124
- debug(10,{"insert_path"=>insert_path, "commandproc"=>commandproc, "arguments"=> arguments, "helpproc"=>helpproc, "argument_processor"=>argument_processor, "options"=>options})
125
- # insert_path_arr=[""]+insert_path.split # we must pre-load our array with a blank node at the front
126
- # p insert_path_arr
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
- # If the parameter "argument_processor" is nil use the default argument processor
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
- end
409
+ private
134
410
 
135
- #{"add"=>{:node=>proc, "host"=>{:node=>proc,"group"=>{:node=>proc}}},"delete"=>...}
411
+ def parameter_error(msg)
412
+ raise ParameterError.new(msg)
413
+ end
136
414
 
137
- class NewCommandTree
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
- @tree = {}
448
+ @cmd_tree={}
142
449
  end
143
450
 
144
- def insert(insert_path,commandproc,arguments,helpproc,argument_processor,options)
145
- tree_node=@tree
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
- local_arg_processor=lambda do |params,user_vars|
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
- #get_command(String)
178
- #returns a Hash with two items: :command and :parameters
179
- #:command is a hash denoting all of the components of a the command when it was inserted
180
- #:parameters is the remainder of the String passed in.
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
- str_array.collect do |item|
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= cur_node.nil? ? nil : cur_node[:node]
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
- end
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
- return results[0].search(search_path)
221
- debug(10,"Not digging deeper")
490
+ tokens=Tokenizer.new(str)
491
+ token_items=tokens.length
222
492
 
223
- return self if search_path[0]==@command
493
+ cur_node=@cmd_tree
494
+ pos=tokens.walk(0)
224
495
 
225
- end
226
-
227
- def insert(insert_path,command,commandproc,arguments,helpproc,argument_processor,options)
228
- do_insert(insert_path,command,commandproc,arguments,helpproc,argument_processor,options,0)
229
- end
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
- def inspect
300
- r_str ="#<#{self.class.to_s}:0x#{self.object_id.to_s(16)} @command=#{@command.inspect}, @commandproc=#{@commandproc.inspect}, "
301
- r_str+="@helpproc=#{@helpproc.inspect}, @argument_processor=#{@argument_processor.inspect}, @arguments=#{@arguments.inspect}, "
302
- r_str+="@options=#{@options.inspect}, "
303
- r_str+="@depth=#{@depth}, @children="
304
- if @children.empty?
305
- r_str+= "[]"
306
- else
307
- children=@children.map {|child| child.command }
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
- # search will search check to see if the parameter command is found in the current node
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
- return nil if search_path.nil?
321
- return nil if search_path.empty?
515
+ cmd=cur_node[:node]
516
+ #params=str_array[count..str_array.length].join.strip
322
517
 
323
- retval=nil
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
- retval=self if search_path[0]==@command
523
+ debug(6,:msg=>"Parameters", :var=>params)
326
524
 
525
+ Cmd.new(cmd,params)
526
+ end
327
527
 
328
- search_path.shift
329
- debug(10,search_path, "shifted search path")
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
- return retval if search_path.length==0
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
- # p search_path
334
- # p @children.map {|child| child.command}
335
- debug(10,@children.map{|child| child.command},"Current children")
548
+ get_subtree(@cmd_tree).flatten.compact.sort
549
+ end
336
550
 
337
- results=@children.map {|child| child.command==search_path[0] ? child : nil }
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
- arg_processor=ArgumentProcessor.new()
351
- commands=Parser.new(arg_processoor.method(:default))
352
- commands.set_debug_level(6)
353
-
354
-
355
- def test_parse(cmd)
356
- puts "\ntesting \"#{cmd}\""
357
- retval=commands.parse(cmd)
358
- puts "result:"
359
- return retval
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
- p commands.complete("hel")
387
- p commands.complete("help")
388
- p commands.complete("get user all")
588
+ if __FILE__ == $0
389
589
 
390
590
  end