help.py 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. # Copyright 2024 Google LLC
  2. #
  3. # Licensed under the Apache License, Version 2.0 (the "License");
  4. # you may not use this file except in compliance with the License.
  5. # You may obtain a copy of the License at
  6. #
  7. # http://www.apache.org/licenses/LICENSE-2.0
  8. #
  9. # Unless required by applicable law or agreed to in writing, software
  10. # distributed under the License is distributed on an "AS IS" BASIS,
  11. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. # See the License for the specific language governing permissions and
  13. # limitations under the License.
  14. import inspect
  15. import sys
  16. from .. import PebbleCommander, exceptions, parsers
  17. def trim_docstring(var):
  18. return inspect.getdoc(var) or ''
  19. def get_help_short(cmdr, cmd_name, help_output=None):
  20. """
  21. cmd_name is the command's name.
  22. help_output is the raw output of the `!help` command.
  23. """
  24. output = None
  25. func = cmdr.get_command(cmd_name)
  26. if func: # Host command
  27. # cmdstr is the actual function name
  28. cmdstr = func.name
  29. spec = inspect.getargspec(func)
  30. if len(spec.args) > 1:
  31. maxargs = len(spec.args) - 1
  32. if spec.defaults is None:
  33. cmdstr += " {%d args}" % maxargs
  34. else:
  35. minargs = maxargs - len(spec.defaults)
  36. cmdstr += " {%d~%d args}" % (minargs, maxargs)
  37. if func.__doc__ is not None:
  38. output = "%-30s - %s" % (cmdstr, trim_docstring(func).splitlines()[0])
  39. else:
  40. output = cmdstr
  41. else: # Prompt command
  42. if cmd_name[0] == '!': # Strip the bang if it's there
  43. cmd_name = cmd_name[1:]
  44. # Get the output if it wasn't provided
  45. if help_output is None:
  46. help_output = cmdr.send_prompt_command("help")
  47. for prompt_cmd in help_output[1:]:
  48. # Match, even with argument count provided
  49. if prompt_cmd == cmd_name or prompt_cmd.startswith(cmd_name+" "):
  50. # Output should be the full argument string with the bang
  51. output = '!' + prompt_cmd
  52. break
  53. return output
  54. def help_arginfo_nodefault(arg):
  55. return "%s" % arg.upper()
  56. def help_arginfo_default(arg, dflt):
  57. return "[%s (default: %s)]" % (arg.upper(), str(dflt))
  58. def get_help_long(cmdr, cmd_name):
  59. output = ""
  60. func = cmdr.get_command(cmd_name)
  61. if func:
  62. spec = inspect.getargspec(func)
  63. specstr = []
  64. for i, arg in enumerate(spec.args[1:]):
  65. if spec.defaults is not None:
  66. minargs = len(spec.args[1:]) - len(spec.defaults)
  67. if i >= minargs:
  68. specstr.append(help_arginfo_default(arg, spec.defaults[i - minargs]))
  69. else:
  70. specstr.append(help_arginfo_nodefault(arg))
  71. else:
  72. specstr.append(help_arginfo_nodefault(arg))
  73. specstr = ' '.join(specstr)
  74. cmdstr = func.name + " " + specstr
  75. if func.__doc__ is None:
  76. output = "%s\n\nNo help available." % cmdstr
  77. else:
  78. output = "%s - %s" % (cmdstr, trim_docstring(func))
  79. else: # Prompt command
  80. cmdstr = get_help_short(cmdr, cmd_name)
  81. if cmdstr is None:
  82. output = None
  83. else:
  84. output = "%s\n\nNo help available, due to being a prompt command." % cmdstr
  85. return output
  86. @PebbleCommander.command()
  87. def help(cmdr, cmd=None):
  88. """ Show help.
  89. You're lookin' at it, dummy!
  90. """
  91. out = []
  92. if cmd is not None:
  93. helpstr = get_help_long(cmdr, cmd)
  94. if helpstr is None:
  95. raise exceptions.ParameterError("No command '%s' found." % cmd)
  96. out.append(helpstr)
  97. else: # List commands
  98. out.append("===Host commands===")
  99. # Bonus, this list is sorted for us already
  100. for cmd_name in dir(cmdr):
  101. if cmdr.get_command(cmd_name):
  102. out.append(get_help_short(cmdr, cmd_name))
  103. out.append("\n===Prompt commands===")
  104. ret = cmdr.send_prompt_command("help")
  105. if ret[0] != 'Available Commands:':
  106. raise exceptions.PromptResponseError("'help' prompt command output invalid")
  107. for cmd_name in ret[1:]:
  108. out.append(get_help_short(cmdr, "!" + cmd_name, ret))
  109. return out