mirror of
https://github.com/AsahiLinux/m1n1
synced 2024-11-14 03:17:05 +00:00
Add ipython shell to proxyclient
Same functionality as the readline shell, but based on ipython so that it has nicer help/autocomplete/etc Signed-off-by: Daniel Berlin <dberlin@dberlin.org>
This commit is contained in:
parent
232836bd64
commit
b48c6d2ea4
3 changed files with 212 additions and 0 deletions
177
proxyclient/m1n1/ishell.py
Normal file
177
proxyclient/m1n1/ishell.py
Normal file
|
@ -0,0 +1,177 @@
|
||||||
|
# SPDX-License-Identifier: MIT
|
||||||
|
import builtins
|
||||||
|
import sys
|
||||||
|
|
||||||
|
import __main__
|
||||||
|
from IPython import embed
|
||||||
|
from traitlets.config import get_config
|
||||||
|
|
||||||
|
c = get_config()
|
||||||
|
c.InteractiveShellEmbed.colors = "Linux"
|
||||||
|
from inspect import signature
|
||||||
|
|
||||||
|
from . import sysreg
|
||||||
|
from .proxy import *
|
||||||
|
from .proxyutils import *
|
||||||
|
from .utils import *
|
||||||
|
|
||||||
|
__all__ = ["run_ishell"]
|
||||||
|
|
||||||
|
|
||||||
|
cmd_list = {}
|
||||||
|
subcmd_list = {}
|
||||||
|
# Debug levels
|
||||||
|
DBL_NONE = 0
|
||||||
|
DBL_INFO = 1
|
||||||
|
DBL_TRACE = 2
|
||||||
|
DBL_DEBUG = 3
|
||||||
|
DBL_EDEBUG = 4
|
||||||
|
|
||||||
|
db_level = DBL_NONE
|
||||||
|
|
||||||
|
|
||||||
|
def debug_cmd(db=None):
|
||||||
|
"""Set debug level to integer %d(none)...%d(extreme debug)""" % (
|
||||||
|
DBL_NONE,
|
||||||
|
DBL_EDEBUG,
|
||||||
|
)
|
||||||
|
global db_level
|
||||||
|
if db:
|
||||||
|
db_level = db
|
||||||
|
print("debug level=%d" % db_level)
|
||||||
|
|
||||||
|
|
||||||
|
def help_cmd(arg=None):
|
||||||
|
if db_level >= DBL_DEBUG:
|
||||||
|
print("arg=%s" % repr(arg))
|
||||||
|
if arg:
|
||||||
|
# cmd = arg.__qualname__
|
||||||
|
if callable(arg):
|
||||||
|
cmd = arg.__name__
|
||||||
|
elif isinstance(arg, str):
|
||||||
|
cmd = arg
|
||||||
|
else:
|
||||||
|
print("Unknown command: %s" % repr(arg))
|
||||||
|
return
|
||||||
|
if db_level >= DBL_DEBUG:
|
||||||
|
print("cmd=%s" % repr(cmd))
|
||||||
|
if cmd not in cmd_list:
|
||||||
|
print("Undocumented command %s" % cmd)
|
||||||
|
return
|
||||||
|
hinfo = cmd_list[cmd]
|
||||||
|
if isinstance(hinfo, str):
|
||||||
|
print("%-10s : %s" % (cmd, hinfo))
|
||||||
|
return
|
||||||
|
if cmd in subcmd_list:
|
||||||
|
clist = subcmd_list[cmd]
|
||||||
|
aname = cmd
|
||||||
|
if db_level >= DBL_DEBUG:
|
||||||
|
print("subcmd_list[%s] = %s" % (repr(cmd), repr(clist)))
|
||||||
|
else:
|
||||||
|
print("command %s is not documented" % cmd)
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
clist = cmd_list
|
||||||
|
aname = "top level"
|
||||||
|
print("Note: To display a category's commands quote the name e.g. help('HV')")
|
||||||
|
print("List of %s commands:" % aname)
|
||||||
|
for cmd in clist.keys():
|
||||||
|
hinfo = clist[cmd]
|
||||||
|
if isinstance(hinfo, str):
|
||||||
|
msg = hinfo.strip().split("\n", 1)[0]
|
||||||
|
elif isinstance(hinfo, int):
|
||||||
|
msg = "%s category - %d subcommands" % (cmd, hinfo)
|
||||||
|
else:
|
||||||
|
print("%s ?" % cmd)
|
||||||
|
continue
|
||||||
|
if len(cmd) <= 10:
|
||||||
|
print("%-10s : %s" % (cmd, msg))
|
||||||
|
else:
|
||||||
|
print("%s:\n %s" % (cmd, msg))
|
||||||
|
|
||||||
|
|
||||||
|
# commands is a dictionary for constructing the
|
||||||
|
# InteractiveConsole with. It adds in the callables
|
||||||
|
# in proxy utils iface and sysreg into commands
|
||||||
|
def run_ishell(commands, msg=""):
|
||||||
|
saved_display = sys.displayhook
|
||||||
|
try:
|
||||||
|
|
||||||
|
def display(val):
|
||||||
|
if isinstance(val, int) and not isinstance(val, bool):
|
||||||
|
builtins._ = val
|
||||||
|
print(hex(val))
|
||||||
|
elif callable(val):
|
||||||
|
val()
|
||||||
|
else:
|
||||||
|
saved_display(val)
|
||||||
|
|
||||||
|
sys.displayhook = display
|
||||||
|
|
||||||
|
# convenience
|
||||||
|
commands["h"] = hex
|
||||||
|
commands["sysreg"] = sysreg
|
||||||
|
|
||||||
|
if "proxy" in commands and "p" not in commands:
|
||||||
|
commands["p"] = commands["proxy"]
|
||||||
|
if "utils" in commands and "u" not in commands:
|
||||||
|
commands["u"] = commands["utils"]
|
||||||
|
|
||||||
|
for obj_name in ("iface", "p", "u"):
|
||||||
|
obj = commands.get(obj_name)
|
||||||
|
obj_class = type(obj)
|
||||||
|
if obj is None:
|
||||||
|
continue
|
||||||
|
|
||||||
|
for attr in dir(obj_class):
|
||||||
|
if attr in commands or attr.startswith("_"):
|
||||||
|
continue
|
||||||
|
|
||||||
|
member = getattr(obj_class, attr)
|
||||||
|
if callable(member) and not isinstance(member, property):
|
||||||
|
cmd = getattr(obj, attr)
|
||||||
|
commands[attr] = cmd
|
||||||
|
|
||||||
|
for attr in dir(sysreg):
|
||||||
|
commands[attr] = getattr(sysreg, attr)
|
||||||
|
|
||||||
|
commands["help"] = help_cmd
|
||||||
|
commands["debug"] = debug_cmd
|
||||||
|
for obj_name in commands.keys():
|
||||||
|
obj = commands.get(obj_name)
|
||||||
|
if obj is None or obj_name.startswith("_"):
|
||||||
|
continue
|
||||||
|
if callable(obj) and not isinstance(obj, property):
|
||||||
|
try:
|
||||||
|
desc = obj_name + str(signature(obj))
|
||||||
|
except:
|
||||||
|
continue
|
||||||
|
qn = obj.__qualname__
|
||||||
|
if qn.find(".") > 0:
|
||||||
|
a = qn.split(".")
|
||||||
|
if a[0] not in subcmd_list:
|
||||||
|
subcmd_list[a[0]] = {}
|
||||||
|
if a[0] not in cmd_list:
|
||||||
|
cmd_list[a[0]] = 1
|
||||||
|
else:
|
||||||
|
cmd_list[a[0]] += 1
|
||||||
|
clist = subcmd_list[a[0]]
|
||||||
|
else:
|
||||||
|
clist = None
|
||||||
|
if commands[obj_name].__doc__:
|
||||||
|
desc += " - " + commands[obj_name].__doc__
|
||||||
|
cmd_list[obj_name] = desc
|
||||||
|
if isinstance(clist, dict):
|
||||||
|
clist[obj_name] = desc
|
||||||
|
|
||||||
|
embed(config=c, extensions=["m1n1.ishell_ext"], header=msg, user_ns=commands)
|
||||||
|
finally:
|
||||||
|
sys.displayhook = saved_display
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
from .setup import *
|
||||||
|
|
||||||
|
commands = dict(__main__.__dict__)
|
||||||
|
|
||||||
|
run_ishell(commands, msg="Have fun!")
|
24
proxyclient/m1n1/ishell_ext.py
Normal file
24
proxyclient/m1n1/ishell_ext.py
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
# SPDX-License-Identifier: MIT
|
||||||
|
# Extension for ipython to handle monitor polling
|
||||||
|
# and simd context after each executed line
|
||||||
|
|
||||||
|
|
||||||
|
class PostExecuteWatcher(object):
|
||||||
|
def __init__(self, ip):
|
||||||
|
self.shell = ip
|
||||||
|
|
||||||
|
def post_execute(self):
|
||||||
|
mon = self.shell.user_ns.get("mon", None)
|
||||||
|
if mon != None:
|
||||||
|
try:
|
||||||
|
mon.poll()
|
||||||
|
except Exception as e:
|
||||||
|
print(f"mon.poll() failed: {e!r}")
|
||||||
|
u = self.shell.user_ns.get("u", None)
|
||||||
|
if u != None:
|
||||||
|
u.push_simd()
|
||||||
|
|
||||||
|
|
||||||
|
def load_ipython_extension(ip):
|
||||||
|
pew = PostExecuteWatcher(ip)
|
||||||
|
ip.events.register("post_execute", pew.post_execute)
|
11
proxyclient/tools/ishell.py
Executable file
11
proxyclient/tools/ishell.py
Executable file
|
@ -0,0 +1,11 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# SPDX-License-Identifier: MIT
|
||||||
|
import pathlib
|
||||||
|
import sys
|
||||||
|
|
||||||
|
sys.path.append(str(pathlib.Path(__file__).resolve().parents[1]))
|
||||||
|
|
||||||
|
from m1n1.setup import *
|
||||||
|
from m1n1.ishell import run_ishell
|
||||||
|
|
||||||
|
run_ishell(globals(), msg="Have fun!")
|
Loading…
Reference in a new issue