Files
pier/pier.py
2022-05-11 12:47:47 +02:00

138 lines
3.2 KiB
Python
Executable File

#!/usr/bin/env python3
DIR = "./scripts/"
HOST = "localhost"
PORT = 9090
import argparse
parser = argparse.ArgumentParser(
description="pier - Python Interpreter Executing Remotely",
formatter_class=argparse.ArgumentDefaultsHelpFormatter
)
parser.add_argument("-d", "--dir", default=DIR, help="directory containing python scripts")
parser.add_argument("-H", "--host", default=HOST, help="host name")
parser.add_argument("-P", "--port", default=PORT, help="port number", type=int)
clargs = parser.parse_args()
from contextlib import redirect_stdout, redirect_stderr
from functools import lru_cache
from glob import glob
from io import StringIO
import os
import sys
import shlex
import traceback
import http.server
import socketserver
URL_SPACE = "%20"
exec_globals = {}
exec_locals = {}
class ScriptServer(http.server.SimpleHTTPRequestHandler):
def do_GET(self):
args = self.path.lstrip("/").replace(URL_SPACE, " ")
args = shlex.split(args)
if not args:
super().do_GET()
return
scr = args[0]
if not scr.endswith(".py"):
scr += ".py"
scripts = sorted(glob("*.py"))
if scr not in scripts:
printable_scripts = "\n".join(scripts)
self.send_result(f"{scr} does not exist. choose from:\n", printable_scripts)
return
res = run_script(scr, args)
msg = f"{scr} output:\n"
msg += "_" * 80
msg += f"\n{res}"
self.send_result(msg)
def send_result(self, *msg):
self.send_response(200)
self.send_header("Content-type", "text/html")
self.end_headers()
msg = encode_html(*msg)
self.wfile.write(msg)
print(msg)
def run_script(fn, args):
sio = StringIO()
with redirect_stdout(sio), redirect_stderr(sio):
code = open_script(fn)
old_sys_argv, sys.argv = sys.argv, args
try:
exec(code, exec_globals, exec_locals)
except BaseException as e: # need to catch SystemExit etc. as well
print("_" * 80)
tn = type(e).__name__
msg = f"{tn}: {e}"
print(msg, file=sys.stderr)
traceback.print_exc()
sys.argv = old_sys_argv
return sio.getvalue()
@lru_cache()
def open_script(fn):
print("reading", fn)
print("_" * 80)
with open(fn) as f:
src = f.read()
code = compile(src, fn, "exec")
return code
def encode_html(*msg):
msg = (str(i) for i in msg)
msg = " ".join(msg)
msg = msg.split("\n")
msg = "<br>".join(msg)
msg = msg.encode()
return msg
if __name__ == "__main__":
try:
os.chdir(clargs.dir)
except Exception as e:
tn = type(e).__name__
msg = f"{tn}: {e}"
raise SystemExit(msg)
sys.path.insert(0, os.getcwd()) # add the script folder to the path
host = clargs.host
port = clargs.port
socketserver.TCPServer.allow_reuse_address = True
with socketserver.ThreadingTCPServer((host, port), ScriptServer) as httpd:
print(f"serving at {host}:{port}")
try:
httpd.serve_forever()
except KeyboardInterrupt:
print()