145 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			Python
		
	
	
	
			
		
		
	
	
			145 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			Python
		
	
	
	
| #!/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
 |