commandline.py 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  1. #!/usr/bin/env python
  2. # encoding: utf-8
  3. import sys
  4. from Naked.settings import debug as DEBUG_FLAG
  5. #####################################################################
  6. # [ Command class ]
  7. # Command line command string object
  8. # argv = list of command line arguments and options
  9. # argc = count of command line arguments and options
  10. # arg0 = first positional argument to command
  11. # arg1 = second positional argument to command
  12. # arglp = last positional argument to command
  13. # cmd = primary command for command suite application (=arg0)
  14. # cmd2 = secondary command for command suite application (=arg1)
  15. # snippet for py block comment = #py + TAB
  16. #####################################################################
  17. class Command:
  18. def __init__(self, app_path, argv):
  19. self.argobj = Argument(argv) # create an Argument obj
  20. self.optobj = Option(argv) # create an Option obj
  21. self.app = app_path # path to application executable file
  22. self.argv = argv # list of the command arguments argv[0] is first argument
  23. self.argc = len(argv) # length of the argument list
  24. self.arg0 = self.argobj._getArg(0) # define the first positional argument
  25. self.arg1 = self.argobj._getArg(1) # define the second positional argument
  26. self.arg2 = self.argobj._getArg(2) # define the third postitional argument
  27. self.arg3 = self.argobj._getArg(3) # define the fourth positional argument
  28. self.arg4 = self.argobj._getArg(4) # define the fifth positional argument
  29. self.arglp = self.argobj._getArg(len(argv) - 1) # define the last positional argument
  30. self.first = self.arg0
  31. self.second = self.arg1
  32. self.third = self.arg2
  33. self.fourth = self.arg3
  34. self.fifth = self.arg4
  35. self.last = self.arglp
  36. self.arg_to_exec = self.arg0 # argument to the executable
  37. self.arg_to_cmd = self.arg1 # argument to the primary command
  38. self.cmd = self.arg0 # define the primary command variable as the first positional argument (user dependent & optional, may be something else)
  39. self.cmd2 = self.arg1 # define the secondary command variable as the second positional argument (user dependent & optional, may be something else)
  40. self.options = self.option_exists() # test for presence of at least one option (boolean)
  41. self.flags = self.flag_exists() # test for presence of at least one flag (boolean)
  42. #------------------------------------------------------------------------------
  43. # [ app_validates_args method ] (boolean)
  44. # Test whether app validates on the criterion arguments (argc) > 0, i.e. there is at least one argument to the executable
  45. #------------------------------------------------------------------------------
  46. def app_validates_args(self):
  47. try:
  48. if self.argc > 0:
  49. return True
  50. else:
  51. return False
  52. except Exception as e:
  53. if DEBUG_FLAG:
  54. sys.stderr.write("Naked Framework Error: Validation of application error in the app_validates() method (Naked.commandline.py).")
  55. raise e
  56. #------------------------------------------------------------------------------------------
  57. # [ arg method ] (string)
  58. # Return the NEXT positional argument to a command line object (e.g. an option that requires an argument)
  59. # arg_recipient = the positional argument (at position n) to test for next positional argument
  60. # returns next positional argument string at position n + 1
  61. #------------------------------------------------------------------------------------------
  62. def arg(self, arg_recipient):
  63. try:
  64. recipient_position = self.argobj._getArgPosition(arg_recipient)
  65. return self.argobj._getArgNext(recipient_position)
  66. except Exception as e:
  67. if DEBUG_FLAG:
  68. sys.stderr.write("Naked Framework Error: Error parsing argument with arg() method (Naked.commandline.py).")
  69. raise e
  70. #------------------------------------------------------------------------------------------
  71. # [ command method ] (boolean)
  72. # Test that the command includes requested primary command suite command (cmd_str parameter)
  73. # cmd_str = the command string to test for in command
  74. # arugment_required = boolean - is an argument to this command required (default = no)?
  75. # returns boolean for presence of the cmd_str
  76. #------------------------------------------------------------------------------------------
  77. def command(self, cmd_str):
  78. try:
  79. if (cmd_str == self.cmd):
  80. return True
  81. else:
  82. return False # if command is missing, return false
  83. except Exception as e:
  84. if DEBUG_FLAG:
  85. sys.stderr.write("Naked Framework Error: Error parsing command with command() method (Naked.commandline.py).")
  86. raise e
  87. #------------------------------------------------------------------------------
  88. # [ command_arg method ] (string)
  89. # Return the argument to the primary command as a string
  90. #------------------------------------------------------------------------------
  91. def command_arg(self):
  92. try:
  93. return self.arg1
  94. except Exception as e:
  95. if DEBUG_FLAG:
  96. sys.stderr.write("Naked Framework Error: Error parsing command argument with command_arg() method (Naked.commandline.py).")
  97. raise e
  98. #------------------------------------------------------------------------------
  99. # [ command2_arg method ] (string)
  100. # Return the argument to the secondary command as a string
  101. #------------------------------------------------------------------------------
  102. def command2_arg(self):
  103. try:
  104. return self.arg2
  105. except Exception as e:
  106. if DEBUG_FLAG:
  107. sys.stderr.write("Naked Framework Error: Error parsing command argument with command_arg() method (Naked.commandline.py).")
  108. raise e
  109. #------------------------------------------------------------------------------------------
  110. # [ command_with_argument method ] (boolean)
  111. # Test that the command includes requested primary command suite command (cmd_str parameter) and argument to it
  112. # cmd_str = the command string to test for in command
  113. # returns boolean for presence of the cmd_str AND presence of argument to the command
  114. #------------------------------------------------------------------------------------------
  115. def command_with_argument(self, cmd_str):
  116. try:
  117. if (cmd_str == self.cmd):
  118. argument_to_cmd = self.argobj._getArgNext(0)
  119. if argument_to_cmd == "": # if the argument is missing, then return false
  120. return False
  121. else:
  122. return True
  123. else:
  124. return False # if command is missing return false
  125. except Exception as e:
  126. if DEBUG_FLAG:
  127. sys.stderr.write("Naked Framework Error: Error parsing command and argument with command_with_argument() method (Naked.commandline.py).")
  128. raise e
  129. #------------------------------------------------------------------------------------------
  130. # [ command_suite_validates method ] (boolean)
  131. # Test that there is a primary command in a command suite application (to be used at the top level of logic for command line application)
  132. # returns boolean for presence of the primary command
  133. #------------------------------------------------------------------------------------------
  134. def command_suite_validates(self, accept_options_as_argument = True):
  135. try:
  136. if self.argc > 0:
  137. if self.arg0.startswith("-") and accept_options_as_argument == False:
  138. return False # if no command and option present, return False
  139. else:
  140. return True # if a primary command present, return True
  141. else:
  142. return False # if user only entered the application name, return False
  143. except Exception as e:
  144. if DEBUG_FLAG:
  145. sys.stderr.write("Naked Framework Error: Command suite validation error with the command_suite_validation() method (Naked.commandline.py).")
  146. raise e
  147. #------------------------------------------------------------------------------
  148. # [ flag method ] (boolean)
  149. # Test for presence of flag in the command
  150. #------------------------------------------------------------------------------
  151. def flag(self, flag_string):
  152. try:
  153. for match_string in self.optobj: #iterate through the options and attempt to match beginning of option to the requested flag
  154. if match_string.startswith(flag_string):
  155. return True
  156. else:
  157. pass
  158. return False
  159. except Exception as e:
  160. if DEBUG_FLAG:
  161. sys.stderr.write("Naked Framework Error: Error parsing flags with the flag() method (Naked.commandline.py).")
  162. raise e
  163. #------------------------------------------------------------------------------
  164. # [flag_arg method] (string)
  165. # Return the argument string assigned to a flag
  166. #------------------------------------------------------------------------------
  167. def flag_arg(self, flag_string):
  168. try:
  169. for match_string in self.optobj:
  170. if match_string.startswith(flag_string) and '=' in match_string:
  171. flag_list = match_string.split("=") #split the flag on the equal symbol = list with [option, argument]
  172. return flag_list[1] #return the argument to the flag option
  173. else:
  174. pass
  175. return "" # return an empty string if unable to parse the argument
  176. except Exception as e:
  177. if DEBUG_FLAG:
  178. sys.stderr.write("Naked Framework Error: Error parsing flags with the flag_arg() method (Naked.commandline.py).")
  179. raise e
  180. #------------------------------------------------------------------------------
  181. # [ flag_exists method ] (boolean)
  182. # Test for the presence of a flag style option (--flag=argument) in the command
  183. #------------------------------------------------------------------------------
  184. def flag_exists(self):
  185. try:
  186. for item in self.optobj:
  187. if '=' in item: #test for presence of an = symbol in the option
  188. return True # if present return True
  189. break
  190. return False # if didn't match across all options, return False
  191. except Exception as e:
  192. if DEBUG_FLAG:
  193. sys.stderr.write("Naked Framework Error: Error parsing flags with the flag_arg() method (Naked.commandline.py).")
  194. raise e
  195. #------------------------------------------------------------------------------------------
  196. # [ option method ] (boolean)
  197. # Test that the command includes an option (option_string parameter)
  198. # option_string = the option string to test for in the command
  199. # arugment_required = boolean - is an argument to this option required (default = no)?
  200. # returns boolean for presence of the cmd_str
  201. #------------------------------------------------------------------------------------------
  202. def option(self, option_string, argument_required = False):
  203. try:
  204. if (option_string in self.optobj):
  205. argument_to_option = self.argobj._getArgNext(self.argobj._getArgPosition(option_string))
  206. if argument_required and ( argument_to_option == "" or argument_to_option.startswith("-") ):
  207. return False
  208. else:
  209. return True
  210. else:
  211. return False
  212. except Exception as e:
  213. if DEBUG_FLAG:
  214. sys.stderr.write("Naked Framework Error: Error parsing option with option() method (Naked.commandline.py).")
  215. raise e
  216. #------------------------------------------------------------------------------
  217. # [ option_arg method ] (string)
  218. # Return the argument string to an option
  219. #------------------------------------------------------------------------------
  220. def option_arg(self, option_string):
  221. try:
  222. return self.argobj._getArgNext(self.argobj._getArgPosition(option_string))
  223. except Exception as e:
  224. if DEBUG_FLAG:
  225. sys.stderr.write("Naked Framework Error: Error returning argument to option with option_arg() method (Naked.commandline.py).")
  226. raise e
  227. #------------------------------------------------------------------------------------------
  228. # [ option_with_arg method ] (boolean)
  229. # Test that the command includes an option (option_string parameter) and argument to that option
  230. # option_string = the option string to test for in the command
  231. # arugment_required = boolean - is an argument to this option required (default = yes)?
  232. # returns boolean for presence of the option_string AND the argument
  233. #------------------------------------------------------------------------------------------
  234. # test that command includes an option (option_string parameter) that includes an argument (=option(option_string, True))
  235. def option_with_arg(self, option_string, argument_required = True):
  236. try:
  237. if (option_string in self.optobj):
  238. argument_to_option = self.argobj._getArgNext(self.argobj._getArgPosition(option_string))
  239. if argument_required and ( argument_to_option == "" or argument_to_option.startswith("-") ):
  240. return False # argument is either missing or is another option, return false
  241. else:
  242. return True
  243. else:
  244. return False # option is not present
  245. except Exception as e:
  246. if DEBUG_FLAG:
  247. sys.stderr.write("Naked Framework Error: Error parsing option and argument with option_with_arg() method (Naked.commandline.py).")
  248. raise e
  249. #------------------------------------------------------------------------------
  250. # [ option_exists method ] (boolean)
  251. # Test whether there are any options in the command string
  252. # returns boolean value for test "Is there at least one option?"
  253. #------------------------------------------------------------------------------
  254. def option_exists(self):
  255. try:
  256. if len(self.optobj) > 0:
  257. return True
  258. else:
  259. return False
  260. except Exception as e:
  261. if DEBUG_FLAG:
  262. sys.stderr.write("Naked Framework Error: Error testing for the presence of at least one option with option_exists() method (Naked.commandline.py).")
  263. raise e
  264. #------------------------------------------------------------------------------
  265. # Naked provides the following commands for all applications that use the framework:
  266. # -- help
  267. # -- usage
  268. # -- version
  269. # These methods are accessed from the app.py module, main() as method calls on the command line object
  270. # Parsing logic is coded below
  271. #------------------------------------------------------------------------------
  272. #------------------------------------------------------------------------------
  273. # Help Command/Option Handler
  274. #------------------------------------------------------------------------------
  275. def help(self):
  276. if ( (self.option("--help")) or (self.cmd == "help") or (self.option("-h")) ):
  277. return True
  278. else:
  279. return False
  280. #------------------------------------------------------------------------------
  281. # Usage Command/Option Handler
  282. #------------------------------------------------------------------------------
  283. def usage(self):
  284. if ( (self.option("--usage")) or (self.cmd == "usage") ):
  285. return True
  286. else:
  287. return False
  288. #------------------------------------------------------------------------------
  289. # Version Command/Option Handler
  290. #------------------------------------------------------------------------------
  291. def version(self):
  292. if ( (self.option("--version")) or (self.cmd == "version") or (self.option("-v"))):
  293. return True
  294. else:
  295. return False
  296. #------------------------------------------------------------------------------
  297. # print the arguments with their corresponding argv list position to std out
  298. #------------------------------------------------------------------------------
  299. def show_args(self):
  300. x = 0
  301. for arg in self.argv:
  302. print("argv[" + str(x) + "] = " + arg)
  303. x = x + 1
  304. #------------------------------------------------------------------------------
  305. # [ Argument Class ]
  306. # all command line arguments (object inherited from Python list)
  307. #------------------------------------------------------------------------------
  308. class Argument(list):
  309. def __init__(self, argv):
  310. self.argv = argv
  311. list.__init__(self, self.argv)
  312. # return argument at position specified by the 'position' parameter
  313. def _getArg(self, position):
  314. if ( self.argv ) and ( len(self.argv) > position ):
  315. return self.argv[position]
  316. else:
  317. return ""
  318. # return position of user specified argument in the argument list
  319. def _getArgPosition(self, test_arg):
  320. if ( self.argv ):
  321. if test_arg in self.argv:
  322. return self.argv.index(test_arg)
  323. else:
  324. return -1
  325. # return the argument at the next position following a user specified positional argument (e.g. for argument to an option in cmd)
  326. def _getArgNext(self, position):
  327. if len(self.argv) > (position + 1):
  328. return self.argv[position + 1]
  329. else:
  330. return ""
  331. #------------------------------------------------------------------------------
  332. # [ Option Class ]
  333. # Command line options (object inherited from Python list)
  334. # Definition: string that begins with "-" (i.e. can be -h or --long)
  335. #------------------------------------------------------------------------------
  336. class Option(list):
  337. def __init__(self, argv):
  338. self.argv = argv
  339. list.__init__(self, self._make_option_list())
  340. # make a list of the options in the command (defined as anything that starts with "-" character)
  341. def _make_option_list(self):
  342. optargv = []
  343. for x in self.argv:
  344. if x.startswith("-"):
  345. optargv.append(x)
  346. return optargv