# Copyright 2024 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import inspect import sys from .. import PebbleCommander, exceptions, parsers def trim_docstring(var): return inspect.getdoc(var) or '' def get_help_short(cmdr, cmd_name, help_output=None): """ cmd_name is the command's name. help_output is the raw output of the `!help` command. """ output = None func = cmdr.get_command(cmd_name) if func: # Host command # cmdstr is the actual function name cmdstr = func.name spec = inspect.getargspec(func) if len(spec.args) > 1: maxargs = len(spec.args) - 1 if spec.defaults is None: cmdstr += " {%d args}" % maxargs else: minargs = maxargs - len(spec.defaults) cmdstr += " {%d~%d args}" % (minargs, maxargs) if func.__doc__ is not None: output = "%-30s - %s" % (cmdstr, trim_docstring(func).splitlines()[0]) else: output = cmdstr else: # Prompt command if cmd_name[0] == '!': # Strip the bang if it's there cmd_name = cmd_name[1:] # Get the output if it wasn't provided if help_output is None: help_output = cmdr.send_prompt_command("help") for prompt_cmd in help_output[1:]: # Match, even with argument count provided if prompt_cmd == cmd_name or prompt_cmd.startswith(cmd_name+" "): # Output should be the full argument string with the bang output = '!' + prompt_cmd break return output def help_arginfo_nodefault(arg): return "%s" % arg.upper() def help_arginfo_default(arg, dflt): return "[%s (default: %s)]" % (arg.upper(), str(dflt)) def get_help_long(cmdr, cmd_name): output = "" func = cmdr.get_command(cmd_name) if func: spec = inspect.getargspec(func) specstr = [] for i, arg in enumerate(spec.args[1:]): if spec.defaults is not None: minargs = len(spec.args[1:]) - len(spec.defaults) if i >= minargs: specstr.append(help_arginfo_default(arg, spec.defaults[i - minargs])) else: specstr.append(help_arginfo_nodefault(arg)) else: specstr.append(help_arginfo_nodefault(arg)) specstr = ' '.join(specstr) cmdstr = func.name + " " + specstr if func.__doc__ is None: output = "%s\n\nNo help available." % cmdstr else: output = "%s - %s" % (cmdstr, trim_docstring(func)) else: # Prompt command cmdstr = get_help_short(cmdr, cmd_name) if cmdstr is None: output = None else: output = "%s\n\nNo help available, due to being a prompt command." % cmdstr return output @PebbleCommander.command() def help(cmdr, cmd=None): """ Show help. You're lookin' at it, dummy! """ out = [] if cmd is not None: helpstr = get_help_long(cmdr, cmd) if helpstr is None: raise exceptions.ParameterError("No command '%s' found." % cmd) out.append(helpstr) else: # List commands out.append("===Host commands===") # Bonus, this list is sorted for us already for cmd_name in dir(cmdr): if cmdr.get_command(cmd_name): out.append(get_help_short(cmdr, cmd_name)) out.append("\n===Prompt commands===") ret = cmdr.send_prompt_command("help") if ret[0] != 'Available Commands:': raise exceptions.PromptResponseError("'help' prompt command output invalid") for cmd_name in ret[1:]: out.append(get_help_short(cmdr, "!" + cmd_name, ret)) return out