| #!/usr/bin/env python |
| |
| """ |
| SWIG generation server. Listens for connections from swig generation clients |
| and runs swig in the requested fashion, sending back the results. |
| """ |
| |
| # Future imports |
| from __future__ import absolute_import |
| from __future__ import print_function |
| |
| # Python modules |
| import argparse |
| import io |
| import logging |
| import os |
| import select |
| import shutil |
| import socket |
| import struct |
| import sys |
| import tempfile |
| import traceback |
| |
| # LLDB modules |
| import use_lldb_suite |
| from lldbsuite.support import fs |
| from lldbsuite.support import sockutil |
| |
| # package imports |
| from . import local |
| from . import remote |
| |
| default_port = 8537 |
| |
| |
| def add_subparser_args(parser): |
| parser.add_argument( |
| "--port", |
| action="store", |
| default=default_port, |
| help=("The local port to bind to")) |
| |
| parser.add_argument( |
| "--swig-executable", |
| action="store", |
| default=fs.find_executable("swig"), |
| dest="swig_executable") |
| |
| |
| def finalize_subparser_options(options): |
| pass |
| |
| |
| def initialize_listening_socket(options): |
| logging.debug("Creating socket...") |
| s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) |
| |
| logging.info("Binding to ip address '', port {}".format(options.port)) |
| s.bind(('', options.port)) |
| |
| logging.debug("Putting socket in listen mode...") |
| s.listen() |
| return s |
| |
| |
| def accept_once(sock, options): |
| logging.debug("Waiting for connection...") |
| while True: |
| rlist, wlist, xlist = select.select([sock], [], [], 0.5) |
| if not rlist: |
| continue |
| |
| client, addr = sock.accept() |
| logging.info("Received connection from {}".format(addr)) |
| data_size = struct.unpack("!I", sockutil.recvall(client, 4))[0] |
| logging.debug("Expecting {} bytes of data from client" |
| .format(data_size)) |
| data = sockutil.recvall(client, data_size) |
| logging.info("Received {} bytes of data from client" |
| .format(len(data))) |
| |
| pack_location = None |
| try: |
| tempfolder = os.path.join(tempfile.gettempdir(), "swig-bot") |
| os.makedirs(tempfolder, exist_ok=True) |
| |
| pack_location = tempfile.mkdtemp(dir=tempfolder) |
| logging.debug("Extracting archive to {}".format(pack_location)) |
| |
| local.unpack_archive(pack_location, data) |
| logging.debug("Successfully unpacked archive...") |
| |
| config_file = os.path.normpath(os.path.join(pack_location, |
| "config.json")) |
| parsed_config = remote.parse_config(io.open(config_file)) |
| config = local.LocalConfig() |
| config.languages = parsed_config["languages"] |
| config.swig_executable = options.swig_executable |
| config.src_root = pack_location |
| config.target_dir = os.path.normpath( |
| os.path.join(config.src_root, "output")) |
| logging.info( |
| "Running swig. languages={}, swig={}, src_root={}, target={}" |
| .format(config.languages, config.swig_executable, |
| config.src_root, config.target_dir)) |
| |
| status = local.generate(config) |
| logging.debug("Finished running swig. Packaging up files {}" |
| .format(os.listdir(config.target_dir))) |
| zip_data = io.BytesIO() |
| zip_file = local.pack_archive(zip_data, config.target_dir, None) |
| response_status = remote.serialize_response_status(status) |
| logging.debug("Sending response status {}".format(response_status)) |
| logging.info("(swig output) -> swig_output.json") |
| zip_file.writestr("swig_output.json", response_status) |
| |
| zip_file.close() |
| response_data = zip_data.getvalue() |
| logging.info("Sending {} byte response".format(len(response_data))) |
| client.sendall(struct.pack("!I", len(response_data))) |
| client.sendall(response_data) |
| finally: |
| if pack_location is not None: |
| logging.debug("Removing temporary folder {}" |
| .format(pack_location)) |
| shutil.rmtree(pack_location) |
| |
| |
| def accept_loop(sock, options): |
| while True: |
| try: |
| accept_once(sock, options) |
| except Exception as e: |
| error = traceback.format_exc() |
| logging.error("An error occurred while processing the connection.") |
| logging.error(error) |
| |
| |
| def run(options): |
| print(options) |
| sock = initialize_listening_socket(options) |
| accept_loop(sock, options) |
| return options |