14
14
# Jython tools don't require sys.path modification
15
15
16
16
from wlsdeploy .aliases .aliases import Aliases
17
+ from wlsdeploy .aliases .wlst_modes import WlstModes
17
18
from wlsdeploy .exception import exception_helper
18
19
from wlsdeploy .logging .platform_logger import PlatformLogger
19
20
from wlsdeploy .tool .modelhelp .model_help_printer import ModelHelpPrinter
20
21
from wlsdeploy .tool .modelhelp .model_help_utils import ControlOptions
21
22
from wlsdeploy .tool .util import model_context_helper
22
23
from wlsdeploy .util import cla_helper
24
+ from wlsdeploy .util import model
23
25
from wlsdeploy .util .cla_utils import CommandLineArgUtil
24
26
from wlsdeploy .util .exit_code import ExitCode
25
27
34
36
__optional_arguments = [
35
37
CommandLineArgUtil .ATTRIBUTES_ONLY_SWITCH ,
36
38
CommandLineArgUtil .FOLDERS_ONLY_SWITCH ,
37
- CommandLineArgUtil .RECURSIVE_SWITCH
39
+ CommandLineArgUtil .RECURSIVE_SWITCH ,
40
+ CommandLineArgUtil .INTERACTIVE_MODE_SWITCH
38
41
]
39
42
40
43
__output_types = [
@@ -70,6 +73,314 @@ def __process_args(args):
70
73
return model_context_helper .create_context (_program_name , argument_map )
71
74
72
75
76
+ def canonical_path_from_model_path (model_path ):
77
+ """
78
+ helper function for interactive help
79
+ canonicalize a model path so it:
80
+ - has no ':'
81
+ - always starts with '/'
82
+ - does not end with a slash unless at top
83
+ - converts 'top' to '/'
84
+ - note: a standalone '/' implies "top"
85
+ - note: first string after first '/' is normally a section
86
+ :param model_path: the model path
87
+ :return: canonicalized path
88
+ """
89
+ ret_path = model_path .replace (':' ,'' )
90
+ while ret_path .endswith ('/' ):
91
+ ret_path = ret_path [:- 1 ]
92
+ while ret_path .startswith ('/' ):
93
+ ret_path = ret_path [1 :]
94
+ if ret_path == 'top' :
95
+ ret_path = ''
96
+ ret_path = '/' + ret_path
97
+ return ret_path
98
+
99
+
100
+ def model_path_from_canonical_path (canonical_path ):
101
+ """
102
+ helper function for interactive help
103
+ returns "normal" model path based on canonicalized path
104
+ :param canonical_path: the path in "/.../..." format
105
+ :return: the model path with "section:/..." format or "top"
106
+ """
107
+ ret_path = canonical_path [1 :]
108
+ slashpos = ret_path .find ('/' )
109
+ if slashpos > 0 :
110
+ ret_path = ret_path [0 :slashpos ] + ':' + ret_path [slashpos :]
111
+ if not ret_path :
112
+ ret_path = 'top'
113
+ return ret_path
114
+
115
+
116
+ def parse_dir_command_simple (model_path , command_str ):
117
+ """
118
+ helper function to process interactive help commands 'cd ..', 'cd', 'top', or 'ls'
119
+ :param model_path: the starting model path before the command
120
+ :param command_str: the command
121
+ :return: the resulting path (an absolute canonical path)
122
+ """
123
+
124
+ canonical_path = canonical_path_from_model_path (model_path )
125
+
126
+ if command_str == 'cd ..' :
127
+ new_path = canonical_path [:canonical_path .rfind ('/' )]
128
+ if not new_path :
129
+ return '/'
130
+ else :
131
+ return new_path
132
+
133
+ if command_str == 'ls' :
134
+ return canonical_path
135
+
136
+ # must be 'top' or 'cd'
137
+ return '/'
138
+
139
+ def add_section_if_missing (aliases , canonical_path , token ):
140
+ """
141
+ helper function to try find and prepend section if missing
142
+ :param aliases: aliases
143
+ :param canonical_path: candidate canonical path starting with "/"
144
+ :param token: first token in canonical_path
145
+ :return: potentially updated canonical path
146
+ """
147
+
148
+ if token not in model .get_model_top_level_keys ():
149
+ for section_name in model .get_model_top_level_keys ():
150
+ if token in aliases .get_model_section_top_level_folder_names (section_name ):
151
+ return '/' + section_name + canonical_path
152
+
153
+ return canonical_path
154
+
155
+ def parse_dir_command_cd_path (aliases , model_path , command_str ):
156
+ """
157
+ helper function to process interactive help command 'cd [path]'
158
+ :param aliases: aliases
159
+ :param model_path: the starting model path before the command
160
+ :param command_str: the 'cd' command
161
+ :return: the resulting path (an absolute canonical path)
162
+ """
163
+
164
+ print ("Parsing" )
165
+
166
+ ret_path = command_str [3 :].replace (':' ,'' ).strip ()
167
+ while ret_path .endswith ('/' ):
168
+ ret_path = ret_path [:- 1 ]
169
+ while ret_path .replace ('//' ,'/' ) != ret_path :
170
+ ret_path = ret_path .replace ('//' ,'/' )
171
+ if ret_path .startswith ('top/' ):
172
+ ret_path = ret_path [3 :]
173
+ while ret_path .startswith ('/top/' ):
174
+ ret_path = ret_path [4 :]
175
+
176
+ if not ret_path or ret_path == 'top' or ret_path == '/' :
177
+ return '/'
178
+
179
+ tokens = ret_path .split ('/' )
180
+
181
+ if tokens [0 ] in model .get_model_top_level_keys ():
182
+ # if first token is a section name, make it an absolute path
183
+ return '/' + ret_path
184
+
185
+ if ret_path .startswith ('/' ):
186
+ # user specified an absolute path '/token1[/...]'
187
+ # (starts with '/' so there must be a second token (tokens[1]))
188
+ return add_section_if_missing (aliases , ret_path , tokens [1 ])
189
+
190
+ # this is a relative path, so append it to the current path
191
+
192
+ canonical_path = canonical_path_from_model_path (model_path )
193
+
194
+ if canonical_path == "/" :
195
+ return "/" + ret_path
196
+
197
+ return canonical_path + "/" + ret_path
198
+
199
+
200
+ def parse_dir_command_all (aliases , model_path , command_str ):
201
+ """
202
+ helper function to process interactive help commands 'cd [path]', 'cd ..', 'cd', 'top', or 'ls'
203
+ :param aliases: aliases
204
+ :param model_path: the starting model path before the command
205
+ :param command_str: the command
206
+ :return: the resulting path (an absolute canonical path)
207
+ """
208
+
209
+ if command_str == 'cd ..' or command_str == 'cd' or command_str == 'top' or command_str == 'ls' :
210
+ return parse_dir_command_simple (model_path , command_str )
211
+ else :
212
+ return parse_dir_command_cd_path (aliases , model_path , command_str ) # handle 'cd [path]'
213
+
214
+
215
+ def interactive_help_prompt (model_path , input_file ):
216
+ """
217
+ Gets the next command from stdin or a file.
218
+ :param model_path: a current model path
219
+ :param input_file: specify a file to get input from file instead of stdin.
220
+ :param printer: a model help printer
221
+ :return: returns when user types 'exit'
222
+ """
223
+
224
+ # prompt using sys.stdout.write to avoid newline
225
+ sys .stdout .write ("[" + model_path + "] --> " )
226
+ sys .stdout .flush ()
227
+
228
+ if not input_file :
229
+ command_str = raw_input ("" ) # get command from stdin
230
+
231
+ else :
232
+ # get command from file instead of stdin (undocumented feature)
233
+ command_str = input_file .readline ()
234
+ if not command_str :
235
+ command_str = 'exit' # reached EOF
236
+ else :
237
+ command_str = command_str .rstrip (os .linesep )
238
+
239
+ # show retrieved command_str right after the prompt
240
+ print (command_str )
241
+
242
+ command_str = " " .join (command_str .split ()) # remove extra white-space
243
+ return command_str
244
+
245
+
246
+ def interactive_help_print_path (printer , model_path , history ):
247
+ """
248
+ Prints help for the given model_path, or an error message.
249
+ Also updates the help history on success.
250
+ :param model_path: the model path
251
+ :param history: history of successful model paths
252
+ :param printer: a model help printer
253
+ """
254
+ try :
255
+ printer .print_model_help (model_path , ControlOptions .NORMAL )
256
+
257
+ # the print_model_help succeeded, add successful path to the history
258
+ if history [- 1 ] != model_path :
259
+ history .append (model_path )
260
+
261
+ except CLAException , ex :
262
+ print ("" )
263
+ print ("Error getting '" + model_path + "': " + ex .getLocalizedMessage ())
264
+ print ("" )
265
+ interactive_help_print_short_instructions ()
266
+
267
+ def interactive_help_print_short_instructions ():
268
+ """
269
+ Prints short instructions for interactive help.
270
+ """
271
+ print ("In interactive mode! Type 'help' for help." )
272
+
273
+
274
+ def interactive_help_print_full_instructions ():
275
+ """
276
+ Prints full instructions for interactive help.
277
+ """
278
+ print ("" )
279
+ print ("Commands:" )
280
+ print ("" )
281
+ print (" ls - list contents of current location" )
282
+ print (" top, cd, cd /, cd top - go to \" top\" " )
283
+ print (" cd x[/[...]] - relative change (go to child location x...)" )
284
+ print (" cd section[:/[...]] - absolute change (go to exact section and location)" )
285
+ print (" cd /folder[/...] - find section that contains the folder and go there" )
286
+ print (" cd .. - go up" )
287
+ print (" history - history of visited locations" )
288
+ print (" exit - exit" )
289
+ print ("" )
290
+ print ("Sections:" )
291
+ print ("" )
292
+ print (" " + str (', ' .join (model .get_model_top_level_keys ())))
293
+ print ("" )
294
+ print ("Examples:" )
295
+ print ("" )
296
+ print (" cd topology" )
297
+ print (" cd topology:/Server/Log/StdoutSeverity" )
298
+ print (" cd /Server/Log/StdoutSeverity" )
299
+ print ("" )
300
+
301
+
302
+ def interactive_help_process_command (aliases , printer , model_path , command_str , history ):
303
+ """
304
+ Process an interactive help command.
305
+ :param aliases: aliases
306
+ :param printer: a model help printer
307
+ :param model_path: current model path before applying command
308
+ :param history: current history, a new model path added is added if command changes it
309
+ :param command_str: the command
310
+ """
311
+
312
+ if command_str == 'help' :
313
+ interactive_help_print_full_instructions ()
314
+
315
+ elif command_str == 'history' :
316
+ for line in history :
317
+ print ("" )
318
+ print (line )
319
+
320
+ elif command_str .count (' ' ) > 1 :
321
+ print ("" )
322
+ print ("Syntax error '" + command_str + "'" )
323
+ print ("" )
324
+ interactive_help_print_short_instructions ()
325
+
326
+ elif command_str == 'ls' or command_str == 'cd' or command_str == 'top' or command_str .startswith ('cd ' ):
327
+ canonical_path = parse_dir_command_all (aliases , model_path , command_str )
328
+ model_path = model_path_from_canonical_path (canonical_path )
329
+ interactive_help_print_path (printer , model_path , history )
330
+
331
+ elif command_str :
332
+ print ("" )
333
+ print ("Unknown command '" + command_str + "'" )
334
+ print ("" )
335
+ interactive_help_print_short_instructions ()
336
+
337
+
338
+ def interactive_help_main_loop (aliases , model_path , printer ):
339
+ """
340
+ Runs the interactive help.
341
+ :param aliases: aliases
342
+ :param model_path: the model path to start with
343
+ :param printer: a model help printer
344
+ :return: returns when user types 'exit'
345
+ """
346
+ _method_name = 'interactive_help_main_loop'
347
+
348
+ __logger .entering (model_path , class_name = _class_name , method_name = _method_name )
349
+
350
+ # setup starting history
351
+ history = ['top' ]
352
+
353
+ # optionally get input from file instead of stdin (undocumented feature)
354
+ input_file_name = os .environ .get ('WDT_INTERACTIVE_MODE_INPUT_FILE' )
355
+ input_file = None
356
+ if input_file_name :
357
+ input_file = open (input_file_name , "r" )
358
+
359
+ # initial command (seeded from the command line)
360
+ command_str = "cd " + model_path
361
+
362
+ print ("" )
363
+ interactive_help_print_short_instructions ()
364
+ print ("" )
365
+ print ("Starting with '" + command_str + "'." )
366
+
367
+ while True :
368
+ if command_str == 'exit' :
369
+ break
370
+
371
+ # the "process command" prints the help (or error) for the command_str
372
+ # plus appends a new path to the history if the str specifies a successful directory change
373
+
374
+ interactive_help_process_command (aliases , printer , history [- 1 ], command_str , history )
375
+ print ("" )
376
+
377
+ # get the next command (from either stdin, or the input_file if input_file is set)
378
+
379
+ command_str = interactive_help_prompt (history [- 1 ], input_file )
380
+
381
+ __logger .exiting (class_name = _class_name , method_name = _method_name )
382
+
383
+
73
384
def print_help (model_path , model_context ):
74
385
"""
75
386
Prints the folders and/or attributes for the specified given model_path,
@@ -95,7 +406,11 @@ def print_help(model_path, model_context):
95
406
96
407
aliases = Aliases (model_context )
97
408
printer = ModelHelpPrinter (aliases , __logger )
98
- printer .print_model_help (model_path , control_option )
409
+
410
+ if model_context .get_interactive_mode_option ():
411
+ interactive_help_main_loop (aliases , model_path , printer )
412
+ else :
413
+ printer .print_model_help (model_path , control_option )
99
414
100
415
__logger .exiting (class_name = _class_name , method_name = _method_name )
101
416
return ExitCode .OK
0 commit comments