Initial commit

This commit is contained in:
Ian Adam Naval 2015-02-20 18:20:22 -05:00
commit c9b1b2fba9
6 changed files with 199 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
__pycache__
*.pyc

52
commands.py Normal file
View File

@ -0,0 +1,52 @@
from formatters import Printer
from io import StringIO
class BaseCommand(object):
def __call__(self, *args, **kwargs):
raise NotImplementedError(
"BaseCommands must be callable and return a generator")
class NoneCommand(BaseCommand):
def __call__(self, *args, **kwargs):
return []
class RawCommand(BaseCommand):
"""Fallback raw command that just invokes an existing Unix utility program
with the builtin subprocess module. Each output object is just a tree node
whose data is a simple string."""
def __init__(self, cmd, input_generator=[], args=tuple()):
self.input_generator = input_generator
self.cmd = cmd
self.args = args
def __call__(self, input_generator=[], *args, **kwargs):
import subprocess
try:
p = subprocess.Popen((self.cmd,) + self.args, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
def output_generator():
input_str = b""
for line in input_generator:
input_str += line
outs, errs = p.communicate(input_str)
if outs:
yield outs
return output_generator()
except:
import traceback
traceback.print_exc()
return []
registered_cmds = []
def register_cmd(cls):
registered_cmds.append(cls.__name__)
return cls

39
example.typescript Normal file
View File

@ -0,0 +1,39 @@
Script started on Fri 20 Feb 2015 06:18:07 PM EST
% 
(B(Bblazer(B (B~/dev/mqp (B(B18:18 (B
(B(B [?1h= 
(B(Bblazer(B (B~/dev/mqp (B(B18:18 (B
(B➤(B scriptpython main.py[?1l> 
(B(Bblazer(B (B~/dev/mqp (B(B18:18 (B
(B➤(B python main.py
Augmented Unix Userland
>>> ls
[DEBUG]: evaluating Python: Printer()(RawCommand('ls')())
commands.py
example_cmd.py
formatters.py
main.py
__pycache__
typescript
>>> ls | grep format
[DEBUG]: evaluating Python: Printer()(RawCommand('grep', args=('format',))(RawCommand('ls')()))
formatters.py
>>> >ls  2 + 2
4
>>> >ls  )ou     grep    ls_outu put = ls()
>>> >ls  grep.args = (', py',)
>>> >grepped_outpu          p.args = ('format',)
>>> >grepped_output = ls  grep(ls_output)
>>> >g Printer()(grepped_output)
formatters.py
>>>
% 
(B(Bblazer(B (B~/dev/mqp (B(B18:19 (B
(B➤(B [?1h= 
(B(Bblazer(B (B~/dev/mqp (B(B18:19 (B
(B➤(B 
Script done on Fri 20 Feb 2015 06:19:26 PM EST

20
example_cmd.py Normal file
View File

@ -0,0 +1,20 @@
from commands import BaseCommand, register_cmd
@register_cmd
class example_cmd(BaseCommand):
def __call__(self, *args, **kwargs):
def input_generator():
yield 'example'
yield 'command'
return input_generator
@register_cmd
class echo(BaseCommand):
def __call__(self, *args, **kwargs):
def input_generator():
for line in self.input_cmd():
yield line
return input_generator

23
formatters.py Normal file
View File

@ -0,0 +1,23 @@
class Formatter(object):
"""Formatters are callable objects who always accept a generator.
The generator represents the output stream of an executing program.
Formatters are special commands which produce no output themselves.
Instead, they always write to the standard out of the program. """
def __init__(self, *args, **kwargs):
# Always require no arguments
pass
def __call__(self, input_generator):
raise NotImplementedError(
"You must extend a Formatter and implement the __call__ method")
class Printer(Formatter):
"""Simple formatter which accepts any object from the input
generator and simply prints it as if it were a string."""
def __call__(self, input_generator):
for line in input_generator:
print(str(line.decode('utf-8')))
return None

63
main.py Normal file
View File

@ -0,0 +1,63 @@
from commands import RawCommand, registered_cmds
from formatters import Printer
from example_cmd import example_cmd, echo
import os
import os.path
for path in os.environ['PATH'].split(':'):
if os.path.exists(path):
binaries = os.listdir(path)
for binary in binaries:
globals()[binary] = RawCommand(binary)
def parse_cmd(potential_cmd):
"""Evaluates a potential command. If it exists in the list of
registered commands, we return a string that would call the
constructor for that command. If it does not exist, we wrap the
name of the command with the RawCommand class.
:return: A string that when evaluated by Python's `eval` feature
would build an object of the correct type
"""
args = potential_cmd.strip().split(' ')
cmd_name = args[0]
if args:
args = args[1:]
if cmd_name not in registered_cmds:
if args:
return "RawCommand('{}', args={})".format(cmd_name, str(tuple(args)))
else:
return "RawCommand('{}')".format(cmd_name)
else:
return "{}()".format(cmd_name)
def parse_cmds(raw):
potential_cmds = raw.split('|')
cmds = [parse_cmd(cmd) for cmd in potential_cmds]
return cmds
def handle_input(prompt=""):
raw = input(prompt)
if raw[0] == '>':
return raw[1:]
else:
cmds = parse_cmds(raw)
cmds.append("Printer()")
mangled_input = ""
for cmd in reversed(cmds):
mangled_input += cmd + "("
mangled_input += ")" * len(cmds)
print("[DEBUG]: evaluating Python: ", mangled_input)
return mangled_input
def main():
import code
code.interact("Augmented Unix Userland", handle_input, globals())
if __name__ == '__main__':
main()