#!/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