diff --git a/.gitignore b/.gitignore index d264257..f6989bb 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ *.airi air*.tmp *.air +*.pyc diff --git a/.gitignore b/.gitignore index d264257..f6989bb 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ *.airi air*.tmp *.air +*.pyc diff --git a/ArgParser.py b/ArgParser.py deleted file mode 100644 index ba9e26b..0000000 --- a/ArgParser.py +++ /dev/null @@ -1,81 +0,0 @@ -import os -import os.path - -class ArgParser: - def __init__(self): - self.i = 0 - self.args = [] - - def parse_type(self, make_type): - opt = self.args[self.i] - self.i += 1 - if self.i >= len(self.args): - return ("Not enough params to " + opt, None) - val = None - try: - val = self.args[self.i] if make_type is None else make_type(self.args[self.i]) - except Exception, e: - pass - if val is None: - return ("Bad argument to " + opt + ": " + self.args[self.i], None) - return (None, val) - - def possible(self, opts, make_type): - return lambda v: make_type(v) if v in opts else None - - def condition(self, make_type, condition): - return lambda v: make_type(v) if condition(make_type(v)) else None - - def folder(self, v): - path = abspath(v) - if os.path.isdir(path): - return path - return None - - def parse_args(self, args): - self.args = args - self.i = 0 - ret = {"input":[]} - allow_opts = True - - while self.i < len(self.args): - arg = self.args[self.i].strip() - if arg == "--": - allow_opts = False - self.i += 1 - continue - - if arg == "--port" or arg == "-p": - (msg, p) = self.parse_type(int) - if msg is not None: - return (msg, None) - ret["port"] = p - elif arg == "--type" or arg == "-t": - (msg, t) = self.parse_type(self.possible(["1", "3"], int)) - if msg is not None: - return (msg, None) - ret["type"] = t - elif arg == "--scale" or arg == "-s": - (msg, s) = self.parse_type(self.condition(int, lambda s: s > 0.00001)) - if msg is not None: - return (msg, None) - ret["scale"] = s - elif arg == "--base" or arg == "-b": - (msg, b) = self.parse_type(self.folder) - if msg is not None: - return (msg, None) - ret["base"] = b - else: - ret["input"].append(arg) - self.i += 1 - return (None, ret) - -def abspath(path): - return os.path.abspath(os.path.expanduser(path)) - -def file_in_path(file, path): - file = abspath(file) - path = abspath(path) - if not os.path.isdir(path) or not os.path.isfile(file): - return False - return os.path.commonprefix(path, file) == path diff --git a/.gitignore b/.gitignore index d264257..f6989bb 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ *.airi air*.tmp *.air +*.pyc diff --git a/ArgParser.py b/ArgParser.py deleted file mode 100644 index ba9e26b..0000000 --- a/ArgParser.py +++ /dev/null @@ -1,81 +0,0 @@ -import os -import os.path - -class ArgParser: - def __init__(self): - self.i = 0 - self.args = [] - - def parse_type(self, make_type): - opt = self.args[self.i] - self.i += 1 - if self.i >= len(self.args): - return ("Not enough params to " + opt, None) - val = None - try: - val = self.args[self.i] if make_type is None else make_type(self.args[self.i]) - except Exception, e: - pass - if val is None: - return ("Bad argument to " + opt + ": " + self.args[self.i], None) - return (None, val) - - def possible(self, opts, make_type): - return lambda v: make_type(v) if v in opts else None - - def condition(self, make_type, condition): - return lambda v: make_type(v) if condition(make_type(v)) else None - - def folder(self, v): - path = abspath(v) - if os.path.isdir(path): - return path - return None - - def parse_args(self, args): - self.args = args - self.i = 0 - ret = {"input":[]} - allow_opts = True - - while self.i < len(self.args): - arg = self.args[self.i].strip() - if arg == "--": - allow_opts = False - self.i += 1 - continue - - if arg == "--port" or arg == "-p": - (msg, p) = self.parse_type(int) - if msg is not None: - return (msg, None) - ret["port"] = p - elif arg == "--type" or arg == "-t": - (msg, t) = self.parse_type(self.possible(["1", "3"], int)) - if msg is not None: - return (msg, None) - ret["type"] = t - elif arg == "--scale" or arg == "-s": - (msg, s) = self.parse_type(self.condition(int, lambda s: s > 0.00001)) - if msg is not None: - return (msg, None) - ret["scale"] = s - elif arg == "--base" or arg == "-b": - (msg, b) = self.parse_type(self.folder) - if msg is not None: - return (msg, None) - ret["base"] = b - else: - ret["input"].append(arg) - self.i += 1 - return (None, ret) - -def abspath(path): - return os.path.abspath(os.path.expanduser(path)) - -def file_in_path(file, path): - file = abspath(file) - path = abspath(path) - if not os.path.isdir(path) or not os.path.isfile(file): - return False - return os.path.commonprefix(path, file) == path diff --git a/args.py b/args.py new file mode 100644 index 0000000..ba9e26b --- /dev/null +++ b/args.py @@ -0,0 +1,81 @@ +import os +import os.path + +class ArgParser: + def __init__(self): + self.i = 0 + self.args = [] + + def parse_type(self, make_type): + opt = self.args[self.i] + self.i += 1 + if self.i >= len(self.args): + return ("Not enough params to " + opt, None) + val = None + try: + val = self.args[self.i] if make_type is None else make_type(self.args[self.i]) + except Exception, e: + pass + if val is None: + return ("Bad argument to " + opt + ": " + self.args[self.i], None) + return (None, val) + + def possible(self, opts, make_type): + return lambda v: make_type(v) if v in opts else None + + def condition(self, make_type, condition): + return lambda v: make_type(v) if condition(make_type(v)) else None + + def folder(self, v): + path = abspath(v) + if os.path.isdir(path): + return path + return None + + def parse_args(self, args): + self.args = args + self.i = 0 + ret = {"input":[]} + allow_opts = True + + while self.i < len(self.args): + arg = self.args[self.i].strip() + if arg == "--": + allow_opts = False + self.i += 1 + continue + + if arg == "--port" or arg == "-p": + (msg, p) = self.parse_type(int) + if msg is not None: + return (msg, None) + ret["port"] = p + elif arg == "--type" or arg == "-t": + (msg, t) = self.parse_type(self.possible(["1", "3"], int)) + if msg is not None: + return (msg, None) + ret["type"] = t + elif arg == "--scale" or arg == "-s": + (msg, s) = self.parse_type(self.condition(int, lambda s: s > 0.00001)) + if msg is not None: + return (msg, None) + ret["scale"] = s + elif arg == "--base" or arg == "-b": + (msg, b) = self.parse_type(self.folder) + if msg is not None: + return (msg, None) + ret["base"] = b + else: + ret["input"].append(arg) + self.i += 1 + return (None, ret) + +def abspath(path): + return os.path.abspath(os.path.expanduser(path)) + +def file_in_path(file, path): + file = abspath(file) + path = abspath(path) + if not os.path.isdir(path) or not os.path.isfile(file): + return False + return os.path.commonprefix(path, file) == path diff --git a/.gitignore b/.gitignore index d264257..f6989bb 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ *.airi air*.tmp *.air +*.pyc diff --git a/ArgParser.py b/ArgParser.py deleted file mode 100644 index ba9e26b..0000000 --- a/ArgParser.py +++ /dev/null @@ -1,81 +0,0 @@ -import os -import os.path - -class ArgParser: - def __init__(self): - self.i = 0 - self.args = [] - - def parse_type(self, make_type): - opt = self.args[self.i] - self.i += 1 - if self.i >= len(self.args): - return ("Not enough params to " + opt, None) - val = None - try: - val = self.args[self.i] if make_type is None else make_type(self.args[self.i]) - except Exception, e: - pass - if val is None: - return ("Bad argument to " + opt + ": " + self.args[self.i], None) - return (None, val) - - def possible(self, opts, make_type): - return lambda v: make_type(v) if v in opts else None - - def condition(self, make_type, condition): - return lambda v: make_type(v) if condition(make_type(v)) else None - - def folder(self, v): - path = abspath(v) - if os.path.isdir(path): - return path - return None - - def parse_args(self, args): - self.args = args - self.i = 0 - ret = {"input":[]} - allow_opts = True - - while self.i < len(self.args): - arg = self.args[self.i].strip() - if arg == "--": - allow_opts = False - self.i += 1 - continue - - if arg == "--port" or arg == "-p": - (msg, p) = self.parse_type(int) - if msg is not None: - return (msg, None) - ret["port"] = p - elif arg == "--type" or arg == "-t": - (msg, t) = self.parse_type(self.possible(["1", "3"], int)) - if msg is not None: - return (msg, None) - ret["type"] = t - elif arg == "--scale" or arg == "-s": - (msg, s) = self.parse_type(self.condition(int, lambda s: s > 0.00001)) - if msg is not None: - return (msg, None) - ret["scale"] = s - elif arg == "--base" or arg == "-b": - (msg, b) = self.parse_type(self.folder) - if msg is not None: - return (msg, None) - ret["base"] = b - else: - ret["input"].append(arg) - self.i += 1 - return (None, ret) - -def abspath(path): - return os.path.abspath(os.path.expanduser(path)) - -def file_in_path(file, path): - file = abspath(file) - path = abspath(path) - if not os.path.isdir(path) or not os.path.isfile(file): - return False - return os.path.commonprefix(path, file) == path diff --git a/args.py b/args.py new file mode 100644 index 0000000..ba9e26b --- /dev/null +++ b/args.py @@ -0,0 +1,81 @@ +import os +import os.path + +class ArgParser: + def __init__(self): + self.i = 0 + self.args = [] + + def parse_type(self, make_type): + opt = self.args[self.i] + self.i += 1 + if self.i >= len(self.args): + return ("Not enough params to " + opt, None) + val = None + try: + val = self.args[self.i] if make_type is None else make_type(self.args[self.i]) + except Exception, e: + pass + if val is None: + return ("Bad argument to " + opt + ": " + self.args[self.i], None) + return (None, val) + + def possible(self, opts, make_type): + return lambda v: make_type(v) if v in opts else None + + def condition(self, make_type, condition): + return lambda v: make_type(v) if condition(make_type(v)) else None + + def folder(self, v): + path = abspath(v) + if os.path.isdir(path): + return path + return None + + def parse_args(self, args): + self.args = args + self.i = 0 + ret = {"input":[]} + allow_opts = True + + while self.i < len(self.args): + arg = self.args[self.i].strip() + if arg == "--": + allow_opts = False + self.i += 1 + continue + + if arg == "--port" or arg == "-p": + (msg, p) = self.parse_type(int) + if msg is not None: + return (msg, None) + ret["port"] = p + elif arg == "--type" or arg == "-t": + (msg, t) = self.parse_type(self.possible(["1", "3"], int)) + if msg is not None: + return (msg, None) + ret["type"] = t + elif arg == "--scale" or arg == "-s": + (msg, s) = self.parse_type(self.condition(int, lambda s: s > 0.00001)) + if msg is not None: + return (msg, None) + ret["scale"] = s + elif arg == "--base" or arg == "-b": + (msg, b) = self.parse_type(self.folder) + if msg is not None: + return (msg, None) + ret["base"] = b + else: + ret["input"].append(arg) + self.i += 1 + return (None, ret) + +def abspath(path): + return os.path.abspath(os.path.expanduser(path)) + +def file_in_path(file, path): + file = abspath(file) + path = abspath(path) + if not os.path.isdir(path) or not os.path.isfile(file): + return False + return os.path.commonprefix(path, file) == path diff --git a/driver.py b/driver.py index ac004f6..d8becd0 100644 --- a/driver.py +++ b/driver.py @@ -3,31 +3,99 @@ import subprocess import sys import threading +import Queue -def get_driver_conn(): - s = socket.socket() - s.bind(("localhost", port)) +class Driver: + def __init__(self, port, use_stdin, use_air = False): + self.port = port + self.use_stdin = use_stdin + self.use_air = use_air + self.stdin = None + self.conn = None - s.settimeout(0.5) - s.listen(0) + def start(self): + self.sock = socket.socket() + self.sock.bind(("localhost", self.port)) - return s + self.sock.settimeout(0.5) + self.sock.listen(0) + + exporter_proc_args = [os.getcwd() + "/Exporter.exe"] + if self.use_air: + exporter_proc_args = [os.getcwd() + "/Exporter.app/Expoter.exe", str(self.port)] -def get_driver_proc(): - exporter_proc_args = [os.getcwd() + "/Exporter.exe"] - #exporter_proc_args = [os.getcwd() + "/Exporter.app/Expoter.exe", str(port)] - return subprocess.Popen(exporter_proc_args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + self.proc = subprocess.Popen(exporter_proc_args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) -def get_stdin_queue(): - stdin_q = Queue.Queue() - reader = threading.Thread(target=get_stdin, args=(stdin_q,)) - reader.daemon = True - reader.start() - return stdin_q + if self.use_stdin: + self.stdin = Queue.Queue() + reader = threading.Thread(target=self._get_stdin) + reader.daemon = True + reader.start() -def get_stdin(stdin_q): - while True: - line = sys.stdin.readline() - stdin_q.put(line) - if line == "": - return + while self.conn is None and self.proc.returncode is None: + try: + (self.conn, _) = self.sock.accept() + except socket.timeout, e: + pass + except e: + print e + self.sock.close() + self.proc.wait() + sys.exit(1) + self.conn.poll() + + if self.conn: + self.conn.setblocking(False) + return self.conn != None + + def send_msg(self, msg): + data = json.dumps(msg) + datalen = struct.pack(">H", len(data)) + self.sock.send(datalen) + self.sock.send(data) + + def loop(self, msg_callback, stdin_callback = None): + buf = "" + quit = False + while self.proc.returncode is None: + try: + d = self.conn.recv(4096) + if len(d): + buf += d + if len(buf) >= 2: + buf_len = struct.unpack_from(">H", buf, 0)[0] + if len(buf) >= 2 + buf_len: + msg = buf[2:2+buf_len] + buf = buf[2+buf_len:] + if not msg_callback(msg): + quit = True + except socket.error, e: + if e.args[0] == errno.EWOULDBLOCK or e.args[0] == errno.EAGAIN: + pass + else: + print e + quit = True + if not quit and self.use_stdin and self.stdin.qsize(): + line = self.stdin.get() + if line == "": + quit = True + elif stdin_callback: + stdin_callback(line) + if quit: + self.send_msg(self.conn, {"command":"quit"}) + self.conn.close() + self.sock.close() + self.proc.kill() + sys.exit(1) + self.proc.poll() + + if self.conn: + self.conn.close() + self.sock.close() + + def _get_stdin(self): + while True: + line = sys.stdin.readline() + self.stdin.put(line) + if line == "": + return diff --git a/.gitignore b/.gitignore index d264257..f6989bb 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ *.airi air*.tmp *.air +*.pyc diff --git a/ArgParser.py b/ArgParser.py deleted file mode 100644 index ba9e26b..0000000 --- a/ArgParser.py +++ /dev/null @@ -1,81 +0,0 @@ -import os -import os.path - -class ArgParser: - def __init__(self): - self.i = 0 - self.args = [] - - def parse_type(self, make_type): - opt = self.args[self.i] - self.i += 1 - if self.i >= len(self.args): - return ("Not enough params to " + opt, None) - val = None - try: - val = self.args[self.i] if make_type is None else make_type(self.args[self.i]) - except Exception, e: - pass - if val is None: - return ("Bad argument to " + opt + ": " + self.args[self.i], None) - return (None, val) - - def possible(self, opts, make_type): - return lambda v: make_type(v) if v in opts else None - - def condition(self, make_type, condition): - return lambda v: make_type(v) if condition(make_type(v)) else None - - def folder(self, v): - path = abspath(v) - if os.path.isdir(path): - return path - return None - - def parse_args(self, args): - self.args = args - self.i = 0 - ret = {"input":[]} - allow_opts = True - - while self.i < len(self.args): - arg = self.args[self.i].strip() - if arg == "--": - allow_opts = False - self.i += 1 - continue - - if arg == "--port" or arg == "-p": - (msg, p) = self.parse_type(int) - if msg is not None: - return (msg, None) - ret["port"] = p - elif arg == "--type" or arg == "-t": - (msg, t) = self.parse_type(self.possible(["1", "3"], int)) - if msg is not None: - return (msg, None) - ret["type"] = t - elif arg == "--scale" or arg == "-s": - (msg, s) = self.parse_type(self.condition(int, lambda s: s > 0.00001)) - if msg is not None: - return (msg, None) - ret["scale"] = s - elif arg == "--base" or arg == "-b": - (msg, b) = self.parse_type(self.folder) - if msg is not None: - return (msg, None) - ret["base"] = b - else: - ret["input"].append(arg) - self.i += 1 - return (None, ret) - -def abspath(path): - return os.path.abspath(os.path.expanduser(path)) - -def file_in_path(file, path): - file = abspath(file) - path = abspath(path) - if not os.path.isdir(path) or not os.path.isfile(file): - return False - return os.path.commonprefix(path, file) == path diff --git a/args.py b/args.py new file mode 100644 index 0000000..ba9e26b --- /dev/null +++ b/args.py @@ -0,0 +1,81 @@ +import os +import os.path + +class ArgParser: + def __init__(self): + self.i = 0 + self.args = [] + + def parse_type(self, make_type): + opt = self.args[self.i] + self.i += 1 + if self.i >= len(self.args): + return ("Not enough params to " + opt, None) + val = None + try: + val = self.args[self.i] if make_type is None else make_type(self.args[self.i]) + except Exception, e: + pass + if val is None: + return ("Bad argument to " + opt + ": " + self.args[self.i], None) + return (None, val) + + def possible(self, opts, make_type): + return lambda v: make_type(v) if v in opts else None + + def condition(self, make_type, condition): + return lambda v: make_type(v) if condition(make_type(v)) else None + + def folder(self, v): + path = abspath(v) + if os.path.isdir(path): + return path + return None + + def parse_args(self, args): + self.args = args + self.i = 0 + ret = {"input":[]} + allow_opts = True + + while self.i < len(self.args): + arg = self.args[self.i].strip() + if arg == "--": + allow_opts = False + self.i += 1 + continue + + if arg == "--port" or arg == "-p": + (msg, p) = self.parse_type(int) + if msg is not None: + return (msg, None) + ret["port"] = p + elif arg == "--type" or arg == "-t": + (msg, t) = self.parse_type(self.possible(["1", "3"], int)) + if msg is not None: + return (msg, None) + ret["type"] = t + elif arg == "--scale" or arg == "-s": + (msg, s) = self.parse_type(self.condition(int, lambda s: s > 0.00001)) + if msg is not None: + return (msg, None) + ret["scale"] = s + elif arg == "--base" or arg == "-b": + (msg, b) = self.parse_type(self.folder) + if msg is not None: + return (msg, None) + ret["base"] = b + else: + ret["input"].append(arg) + self.i += 1 + return (None, ret) + +def abspath(path): + return os.path.abspath(os.path.expanduser(path)) + +def file_in_path(file, path): + file = abspath(file) + path = abspath(path) + if not os.path.isdir(path) or not os.path.isfile(file): + return False + return os.path.commonprefix(path, file) == path diff --git a/driver.py b/driver.py index ac004f6..d8becd0 100644 --- a/driver.py +++ b/driver.py @@ -3,31 +3,99 @@ import subprocess import sys import threading +import Queue -def get_driver_conn(): - s = socket.socket() - s.bind(("localhost", port)) +class Driver: + def __init__(self, port, use_stdin, use_air = False): + self.port = port + self.use_stdin = use_stdin + self.use_air = use_air + self.stdin = None + self.conn = None - s.settimeout(0.5) - s.listen(0) + def start(self): + self.sock = socket.socket() + self.sock.bind(("localhost", self.port)) - return s + self.sock.settimeout(0.5) + self.sock.listen(0) + + exporter_proc_args = [os.getcwd() + "/Exporter.exe"] + if self.use_air: + exporter_proc_args = [os.getcwd() + "/Exporter.app/Expoter.exe", str(self.port)] -def get_driver_proc(): - exporter_proc_args = [os.getcwd() + "/Exporter.exe"] - #exporter_proc_args = [os.getcwd() + "/Exporter.app/Expoter.exe", str(port)] - return subprocess.Popen(exporter_proc_args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + self.proc = subprocess.Popen(exporter_proc_args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) -def get_stdin_queue(): - stdin_q = Queue.Queue() - reader = threading.Thread(target=get_stdin, args=(stdin_q,)) - reader.daemon = True - reader.start() - return stdin_q + if self.use_stdin: + self.stdin = Queue.Queue() + reader = threading.Thread(target=self._get_stdin) + reader.daemon = True + reader.start() -def get_stdin(stdin_q): - while True: - line = sys.stdin.readline() - stdin_q.put(line) - if line == "": - return + while self.conn is None and self.proc.returncode is None: + try: + (self.conn, _) = self.sock.accept() + except socket.timeout, e: + pass + except e: + print e + self.sock.close() + self.proc.wait() + sys.exit(1) + self.conn.poll() + + if self.conn: + self.conn.setblocking(False) + return self.conn != None + + def send_msg(self, msg): + data = json.dumps(msg) + datalen = struct.pack(">H", len(data)) + self.sock.send(datalen) + self.sock.send(data) + + def loop(self, msg_callback, stdin_callback = None): + buf = "" + quit = False + while self.proc.returncode is None: + try: + d = self.conn.recv(4096) + if len(d): + buf += d + if len(buf) >= 2: + buf_len = struct.unpack_from(">H", buf, 0)[0] + if len(buf) >= 2 + buf_len: + msg = buf[2:2+buf_len] + buf = buf[2+buf_len:] + if not msg_callback(msg): + quit = True + except socket.error, e: + if e.args[0] == errno.EWOULDBLOCK or e.args[0] == errno.EAGAIN: + pass + else: + print e + quit = True + if not quit and self.use_stdin and self.stdin.qsize(): + line = self.stdin.get() + if line == "": + quit = True + elif stdin_callback: + stdin_callback(line) + if quit: + self.send_msg(self.conn, {"command":"quit"}) + self.conn.close() + self.sock.close() + self.proc.kill() + sys.exit(1) + self.proc.poll() + + if self.conn: + self.conn.close() + self.sock.close() + + def _get_stdin(self): + while True: + line = sys.stdin.readline() + self.stdin.put(line) + if line == "": + return diff --git a/exporter.py b/exporter.py index 764b76c..6de7805 100755 --- a/exporter.py +++ b/exporter.py @@ -1,7 +1,6 @@ #! /usr/bin/python import socket -import subprocess import errno import sys import os @@ -10,9 +9,9 @@ import traceback import shlex import struct -import threading -import Queue -import * from ArgParser +from args import * +from job import * +from driver import * def usage(): print "usage 1: ./exporter.py [--port/-p wrapper_communication_port] [--type/-t (1,3)] [--scale/-s skeletal_scale] [--base/-b base_dir] input_files..." @@ -52,49 +51,11 @@ return {"type": args["type"] if "type" in args else 1, \ "scale": args["scale"] if "scale" in args else 1} -class Job: - next_id = 0 - def __init__(self, input, type = 1, scale = 1, base = None): - if not os.path.isfile(input): - raise Exception("Failed: couldn't open " + input) - self.id = next_id - next_id += 1 - self.input = abspath(input) - self.base = base if base is not None else os.path.split(input)[0] - if not file_in_path(self.input, self.base): - raise Exception("Failed: " + input + " is not in base dir " + self.base) - self.type = type - self.scale = scale - self.done = False - -def send_msg(conn, msg): - data = json.dumps(msg) - datalen = struct.pack(">H", len(data)) - conn.send(datalen) - conn.send(data) - - -conn = None -while conn is None and g.returncode is None: - try: - (conn, _) = s.accept() - except socket.timeout, e: - pass - except e: - print e - s.close() - g.wait() - sys.exit(1) - g.poll() - jobs = {} +driver = Driver(port) -if conn: - conn.setblocking(False) - - if from_stdin: - pass - else: +if driver.start(): + if not from_stdin: base_args = make_base_job_args(args) for i in args["input"]: try: @@ -103,64 +64,32 @@ except Exception, e: print e +driver.loop(handle_command, handle_stdin) +def handle_stdin(line): + parts = shlex.split(line) + (err, line_args) = ArgParser.parse_args(parts) + if err is not None: + print err + else: + base_args= make_base_job_args(line_args) + for i in line_args["input"]: + pass + #send_job(conn, base_cmd, i) def handle_command(msg_str): - global quit msg = json.loads(msg_str) if "command" in msg: cmd = msg["command"] if cmd == "exit": - quit = True + return False if cmd == "print" and "string" in msg: sys.stdout.write(msg["string"]) sys.stdout.flush() if cmd == "done" and "job_num" in msg: job_num = int(cmd["job_num"]) if job_num == num_jobs_sent: - quit = True + return False + return True -buf = "" -quit = False -while g.returncode is None: - try: - d = conn.recv(4096) - if len(d): - buf += d - if len(buf) >= 2: - buf_len = struct.unpack_from(">H", buf, 0)[0] - if len(buf) >= 2 + buf_len: - msg = buf[2:2+buf_len] - buf = buf[2+buf_len:] - handle_command(msg) - except socket.error, e: - if e.args[0] == errno.EWOULDBLOCK or e.args[0] == errno.EAGAIN: - pass - else: - print e - quit = True - if not quit and from_stdin and stdin_q.qsize(): - line = stdin_q.get() - if line == "": - quit = True - else: - parts = shlex.split(line) - (err, line_args) = ArgParser.parse_args(parts) - if err is not None: - print err - else: - base_args= make_base_job_args(line_args) - for i in line_args["input"]: - send_job(conn, base_cmd, i) - if quit: - send_msg(conn, {"command":"quit"}) - conn.close() - s.close() - g.kill() - sys.exit(1) - g.poll() - -if (conn): - conn.close() -s.close() diff --git a/.gitignore b/.gitignore index d264257..f6989bb 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ *.airi air*.tmp *.air +*.pyc diff --git a/ArgParser.py b/ArgParser.py deleted file mode 100644 index ba9e26b..0000000 --- a/ArgParser.py +++ /dev/null @@ -1,81 +0,0 @@ -import os -import os.path - -class ArgParser: - def __init__(self): - self.i = 0 - self.args = [] - - def parse_type(self, make_type): - opt = self.args[self.i] - self.i += 1 - if self.i >= len(self.args): - return ("Not enough params to " + opt, None) - val = None - try: - val = self.args[self.i] if make_type is None else make_type(self.args[self.i]) - except Exception, e: - pass - if val is None: - return ("Bad argument to " + opt + ": " + self.args[self.i], None) - return (None, val) - - def possible(self, opts, make_type): - return lambda v: make_type(v) if v in opts else None - - def condition(self, make_type, condition): - return lambda v: make_type(v) if condition(make_type(v)) else None - - def folder(self, v): - path = abspath(v) - if os.path.isdir(path): - return path - return None - - def parse_args(self, args): - self.args = args - self.i = 0 - ret = {"input":[]} - allow_opts = True - - while self.i < len(self.args): - arg = self.args[self.i].strip() - if arg == "--": - allow_opts = False - self.i += 1 - continue - - if arg == "--port" or arg == "-p": - (msg, p) = self.parse_type(int) - if msg is not None: - return (msg, None) - ret["port"] = p - elif arg == "--type" or arg == "-t": - (msg, t) = self.parse_type(self.possible(["1", "3"], int)) - if msg is not None: - return (msg, None) - ret["type"] = t - elif arg == "--scale" or arg == "-s": - (msg, s) = self.parse_type(self.condition(int, lambda s: s > 0.00001)) - if msg is not None: - return (msg, None) - ret["scale"] = s - elif arg == "--base" or arg == "-b": - (msg, b) = self.parse_type(self.folder) - if msg is not None: - return (msg, None) - ret["base"] = b - else: - ret["input"].append(arg) - self.i += 1 - return (None, ret) - -def abspath(path): - return os.path.abspath(os.path.expanduser(path)) - -def file_in_path(file, path): - file = abspath(file) - path = abspath(path) - if not os.path.isdir(path) or not os.path.isfile(file): - return False - return os.path.commonprefix(path, file) == path diff --git a/args.py b/args.py new file mode 100644 index 0000000..ba9e26b --- /dev/null +++ b/args.py @@ -0,0 +1,81 @@ +import os +import os.path + +class ArgParser: + def __init__(self): + self.i = 0 + self.args = [] + + def parse_type(self, make_type): + opt = self.args[self.i] + self.i += 1 + if self.i >= len(self.args): + return ("Not enough params to " + opt, None) + val = None + try: + val = self.args[self.i] if make_type is None else make_type(self.args[self.i]) + except Exception, e: + pass + if val is None: + return ("Bad argument to " + opt + ": " + self.args[self.i], None) + return (None, val) + + def possible(self, opts, make_type): + return lambda v: make_type(v) if v in opts else None + + def condition(self, make_type, condition): + return lambda v: make_type(v) if condition(make_type(v)) else None + + def folder(self, v): + path = abspath(v) + if os.path.isdir(path): + return path + return None + + def parse_args(self, args): + self.args = args + self.i = 0 + ret = {"input":[]} + allow_opts = True + + while self.i < len(self.args): + arg = self.args[self.i].strip() + if arg == "--": + allow_opts = False + self.i += 1 + continue + + if arg == "--port" or arg == "-p": + (msg, p) = self.parse_type(int) + if msg is not None: + return (msg, None) + ret["port"] = p + elif arg == "--type" or arg == "-t": + (msg, t) = self.parse_type(self.possible(["1", "3"], int)) + if msg is not None: + return (msg, None) + ret["type"] = t + elif arg == "--scale" or arg == "-s": + (msg, s) = self.parse_type(self.condition(int, lambda s: s > 0.00001)) + if msg is not None: + return (msg, None) + ret["scale"] = s + elif arg == "--base" or arg == "-b": + (msg, b) = self.parse_type(self.folder) + if msg is not None: + return (msg, None) + ret["base"] = b + else: + ret["input"].append(arg) + self.i += 1 + return (None, ret) + +def abspath(path): + return os.path.abspath(os.path.expanduser(path)) + +def file_in_path(file, path): + file = abspath(file) + path = abspath(path) + if not os.path.isdir(path) or not os.path.isfile(file): + return False + return os.path.commonprefix(path, file) == path diff --git a/driver.py b/driver.py index ac004f6..d8becd0 100644 --- a/driver.py +++ b/driver.py @@ -3,31 +3,99 @@ import subprocess import sys import threading +import Queue -def get_driver_conn(): - s = socket.socket() - s.bind(("localhost", port)) +class Driver: + def __init__(self, port, use_stdin, use_air = False): + self.port = port + self.use_stdin = use_stdin + self.use_air = use_air + self.stdin = None + self.conn = None - s.settimeout(0.5) - s.listen(0) + def start(self): + self.sock = socket.socket() + self.sock.bind(("localhost", self.port)) - return s + self.sock.settimeout(0.5) + self.sock.listen(0) + + exporter_proc_args = [os.getcwd() + "/Exporter.exe"] + if self.use_air: + exporter_proc_args = [os.getcwd() + "/Exporter.app/Expoter.exe", str(self.port)] -def get_driver_proc(): - exporter_proc_args = [os.getcwd() + "/Exporter.exe"] - #exporter_proc_args = [os.getcwd() + "/Exporter.app/Expoter.exe", str(port)] - return subprocess.Popen(exporter_proc_args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + self.proc = subprocess.Popen(exporter_proc_args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) -def get_stdin_queue(): - stdin_q = Queue.Queue() - reader = threading.Thread(target=get_stdin, args=(stdin_q,)) - reader.daemon = True - reader.start() - return stdin_q + if self.use_stdin: + self.stdin = Queue.Queue() + reader = threading.Thread(target=self._get_stdin) + reader.daemon = True + reader.start() -def get_stdin(stdin_q): - while True: - line = sys.stdin.readline() - stdin_q.put(line) - if line == "": - return + while self.conn is None and self.proc.returncode is None: + try: + (self.conn, _) = self.sock.accept() + except socket.timeout, e: + pass + except e: + print e + self.sock.close() + self.proc.wait() + sys.exit(1) + self.conn.poll() + + if self.conn: + self.conn.setblocking(False) + return self.conn != None + + def send_msg(self, msg): + data = json.dumps(msg) + datalen = struct.pack(">H", len(data)) + self.sock.send(datalen) + self.sock.send(data) + + def loop(self, msg_callback, stdin_callback = None): + buf = "" + quit = False + while self.proc.returncode is None: + try: + d = self.conn.recv(4096) + if len(d): + buf += d + if len(buf) >= 2: + buf_len = struct.unpack_from(">H", buf, 0)[0] + if len(buf) >= 2 + buf_len: + msg = buf[2:2+buf_len] + buf = buf[2+buf_len:] + if not msg_callback(msg): + quit = True + except socket.error, e: + if e.args[0] == errno.EWOULDBLOCK or e.args[0] == errno.EAGAIN: + pass + else: + print e + quit = True + if not quit and self.use_stdin and self.stdin.qsize(): + line = self.stdin.get() + if line == "": + quit = True + elif stdin_callback: + stdin_callback(line) + if quit: + self.send_msg(self.conn, {"command":"quit"}) + self.conn.close() + self.sock.close() + self.proc.kill() + sys.exit(1) + self.proc.poll() + + if self.conn: + self.conn.close() + self.sock.close() + + def _get_stdin(self): + while True: + line = sys.stdin.readline() + self.stdin.put(line) + if line == "": + return diff --git a/exporter.py b/exporter.py index 764b76c..6de7805 100755 --- a/exporter.py +++ b/exporter.py @@ -1,7 +1,6 @@ #! /usr/bin/python import socket -import subprocess import errno import sys import os @@ -10,9 +9,9 @@ import traceback import shlex import struct -import threading -import Queue -import * from ArgParser +from args import * +from job import * +from driver import * def usage(): print "usage 1: ./exporter.py [--port/-p wrapper_communication_port] [--type/-t (1,3)] [--scale/-s skeletal_scale] [--base/-b base_dir] input_files..." @@ -52,49 +51,11 @@ return {"type": args["type"] if "type" in args else 1, \ "scale": args["scale"] if "scale" in args else 1} -class Job: - next_id = 0 - def __init__(self, input, type = 1, scale = 1, base = None): - if not os.path.isfile(input): - raise Exception("Failed: couldn't open " + input) - self.id = next_id - next_id += 1 - self.input = abspath(input) - self.base = base if base is not None else os.path.split(input)[0] - if not file_in_path(self.input, self.base): - raise Exception("Failed: " + input + " is not in base dir " + self.base) - self.type = type - self.scale = scale - self.done = False - -def send_msg(conn, msg): - data = json.dumps(msg) - datalen = struct.pack(">H", len(data)) - conn.send(datalen) - conn.send(data) - - -conn = None -while conn is None and g.returncode is None: - try: - (conn, _) = s.accept() - except socket.timeout, e: - pass - except e: - print e - s.close() - g.wait() - sys.exit(1) - g.poll() - jobs = {} +driver = Driver(port) -if conn: - conn.setblocking(False) - - if from_stdin: - pass - else: +if driver.start(): + if not from_stdin: base_args = make_base_job_args(args) for i in args["input"]: try: @@ -103,64 +64,32 @@ except Exception, e: print e +driver.loop(handle_command, handle_stdin) +def handle_stdin(line): + parts = shlex.split(line) + (err, line_args) = ArgParser.parse_args(parts) + if err is not None: + print err + else: + base_args= make_base_job_args(line_args) + for i in line_args["input"]: + pass + #send_job(conn, base_cmd, i) def handle_command(msg_str): - global quit msg = json.loads(msg_str) if "command" in msg: cmd = msg["command"] if cmd == "exit": - quit = True + return False if cmd == "print" and "string" in msg: sys.stdout.write(msg["string"]) sys.stdout.flush() if cmd == "done" and "job_num" in msg: job_num = int(cmd["job_num"]) if job_num == num_jobs_sent: - quit = True + return False + return True -buf = "" -quit = False -while g.returncode is None: - try: - d = conn.recv(4096) - if len(d): - buf += d - if len(buf) >= 2: - buf_len = struct.unpack_from(">H", buf, 0)[0] - if len(buf) >= 2 + buf_len: - msg = buf[2:2+buf_len] - buf = buf[2+buf_len:] - handle_command(msg) - except socket.error, e: - if e.args[0] == errno.EWOULDBLOCK or e.args[0] == errno.EAGAIN: - pass - else: - print e - quit = True - if not quit and from_stdin and stdin_q.qsize(): - line = stdin_q.get() - if line == "": - quit = True - else: - parts = shlex.split(line) - (err, line_args) = ArgParser.parse_args(parts) - if err is not None: - print err - else: - base_args= make_base_job_args(line_args) - for i in line_args["input"]: - send_job(conn, base_cmd, i) - if quit: - send_msg(conn, {"command":"quit"}) - conn.close() - s.close() - g.kill() - sys.exit(1) - g.poll() - -if (conn): - conn.close() -s.close() diff --git a/job.py b/job.py new file mode 100644 index 0000000..4385544 --- /dev/null +++ b/job.py @@ -0,0 +1,16 @@ +import os.path + +class Job: + next_id = 0 + def __init__(self, input, type = 1, scale = 1, base = None): + if not os.path.isfile(input): + raise Exception("Failed: couldn't open " + input) + self.id = next_id + next_id += 1 + self.input = abspath(input) + self.base = base if base is not None else os.path.split(input)[0] + if not file_in_path(self.input, self.base): + raise Exception("Failed: " + input + " is not in base dir " + self.base) + self.type = type + self.scale = scale + self.done = False