[lldb/Scripts] Remove SWIG bot

This is no longer used or maintained.

Differential revision: https://reviews.llvm.org/D72539
This commit is contained in:
Jonas Devlieghere 2020-01-13 09:23:48 -08:00
parent 05366870ee
commit f2bbe8ede0
5 changed files with 0 additions and 621 deletions

View File

@ -1,85 +0,0 @@
#!/usr/bin/env python
"""
SWIG generation top-level script. Supports both local and remote generation
of SWIG bindings for multiple languages.
"""
# Python modules
import argparse
import logging
import sys
import traceback
# LLDB modules
import use_lldb_suite
# swig_bot modules
from swig_bot_lib import client
from swig_bot_lib import server
def process_args(args):
parser = argparse.ArgumentParser(
description='Run swig-bot client or server.')
# Create and populate subparser arguments for when swig_bot is
# run in client or server mode
subparsers = parser.add_subparsers(
help="Pass --help to a sub-command to print detailed usage")
client_parser = subparsers.add_parser("client",
help="Run SWIG generation client")
client.add_subparser_args(client_parser)
client_parser.set_defaults(func=run_client)
server_parser = subparsers.add_parser("server",
help="Run SWIG generation server")
server.add_subparser_args(server_parser)
server_parser.set_defaults(func=run_server)
# Arguments to control logging verbosity.
parser.add_argument(
"--verbose", "-v",
action="store_true",
default=False,
help="Increase logging verbosity level.")
options = parser.parse_args(args)
# Set logging level.
if options.verbose:
log_level = logging.DEBUG
else:
log_level = logging.NOTSET
logging.basicConfig(level=log_level)
logging.info("logging is using level: %d", log_level)
return options
def run_client(options):
logging.info("Running swig_bot in client mode")
client.finalize_subparser_options(options)
client.run(options)
def run_server(options):
logging.info("Running swig_bot in server mode")
server.finalize_subparser_options(options)
server.run(options)
if __name__ == "__main__":
options = process_args(sys.argv[1:])
try:
if options.func is None:
logging.error(
"Unknown mode specified. Expected client or server.")
sys.exit(-1)
else:
options.func(options)
except KeyboardInterrupt as e:
logging.info("Ctrl+C received. Shutting down...")
sys.exit(-1)
except Exception as e:
error = traceback.format_exc()
logging.error("An error occurred running swig-bot.")
logging.error(error)

View File

@ -1,216 +0,0 @@
#!/usr/bin/env python
"""
SWIG generation client. Supports both local and remote generation of SWIG
bindings for multiple languages.
"""
# Future imports
from __future__ import absolute_import
from __future__ import print_function
# Python modules
import argparse
import io
import logging
import os
import socket
import struct
import sys
# 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_ip = "127.0.0.1"
default_port = 8537
def add_subparser_args(parser):
"""Returns options processed from the provided command line.
@param args the command line to process.
"""
# A custom action used by the --local command line option. It can be
# used with either 0 or 1 argument. If used with 0 arguments, it
# searches for a copy of swig located on the physical machine. If
# used with 1 argument, the argument is the path to a swig executable.
class FindLocalSwigAction(argparse.Action):
def __init__(self, option_strings, dest, **kwargs):
super(FindLocalSwigAction, self).__init__(
option_strings, dest, nargs='?', **kwargs)
def __call__(self, parser, namespace, values, option_string=None):
swig_exe = None
if values is None:
swig_exe = fs.find_executable('swig')
else:
swig_exe = values
setattr(namespace, self.dest, os.path.normpath(swig_exe))
# A custom action used by the --remote command line option. It can be
# used with either 0 or 1 arguments. If used with 0 arguments it chooses
# a default connection string. If used with one argument it is a string
# of the form `ip_address[:port]`. If the port is unspecified, the
# default port is used.
class RemoteIpAction(argparse.Action):
def __init__(self, option_strings, dest, **kwargs):
super(RemoteIpAction, self).__init__(
option_strings, dest, nargs='?', **kwargs)
def __call__(self, parser, namespace, values, option_string=None):
ip_port = None
if values is None:
ip_port = (default_ip, default_port)
else:
result = values.split(':')
if len(result) == 1:
ip_port = (result[0], default_port)
elif len(result) == 2:
ip_port = (result[0], int(result[1]))
else:
raise ValueError("Invalid connection string")
setattr(namespace, self.dest, ip_port)
parser.add_argument(
"--local",
action=FindLocalSwigAction,
dest="swig_executable",
help=(
"Run the copy of swig at the specified location, or search PATH"
"if the location is omitted"))
parser.add_argument(
"--remote",
action=RemoteIpAction,
help=(
"Use the given connection string to connect to a remote "
"generation service"))
parser.add_argument(
"--src-root",
required=True,
help="The root folder of the LLDB source tree.")
parser.add_argument(
"--target-dir",
default=os.getcwd(),
help=(
"Specifies the build dir where the language binding "
"should be placed"))
parser.add_argument(
"--language",
dest="languages",
action="append",
help="Specifies the language to generate bindings for")
def finalize_subparser_options(options):
if options.languages is None:
options.languages = ['python']
if options.remote is None and options.swig_executable is None:
logging.error("Must specify either --local or --remote")
sys.exit(-3)
return options
def establish_remote_connection(ip_port):
logging.debug("Creating socket...")
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
logging.info("Connecting to server {} on port {}"
.format(ip_port[0], ip_port[1]))
s.connect(ip_port)
logging.info("Connection established...")
return s
def transmit_request(connection, packed_input):
logging.info("Sending {} bytes of compressed data."
.format(len(packed_input)))
connection.sendall(struct.pack("!I", len(packed_input)))
connection.sendall(packed_input)
logging.info("Awaiting response.")
response_len = struct.unpack("!I", sockutil.recvall(connection, 4))[0]
logging.debug("Expecting {} byte response".format(response_len))
response = sockutil.recvall(connection, response_len)
return response
def handle_response(options, connection, response):
logging.debug("Received {} byte response.".format(len(response)))
logging.debug("Creating output directory {}"
.format(options.target_dir))
os.makedirs(options.target_dir, exist_ok=True)
logging.info("Unpacking response archive into {}"
.format(options.target_dir))
local.unpack_archive(options.target_dir, response)
response_file_path = os.path.normpath(
os.path.join(options.target_dir, "swig_output.json"))
if not os.path.isfile(response_file_path):
logging.error("Response file '{}' does not exist."
.format(response_file_path))
return
try:
response = remote.deserialize_response_status(
io.open(response_file_path))
if response[0] != 0:
logging.error("An error occurred during generation. Status={}"
.format(response[0]))
logging.error(response[1])
else:
logging.info("SWIG generation successful.")
if len(response[1]) > 0:
logging.info(response[1])
finally:
os.unlink(response_file_path)
def run(options):
if options.remote is None:
logging.info("swig bot client using local swig installation at '{}'"
.format(options.swig_executable))
if not os.path.isfile(options.swig_executable):
logging.error("Swig executable '{}' does not exist."
.format(options.swig_executable))
config = local.LocalConfig()
config.languages = options.languages
config.src_root = options.src_root
config.target_dir = options.target_dir
config.swig_executable = options.swig_executable
local.generate(config)
else:
logging.info("swig bot client using remote generation with server '{}'"
.format(options.remote))
connection = None
try:
config = remote.generate_config(options.languages)
logging.debug("Generated config json {}".format(config))
inputs = [("include/lldb", ".h"),
("include/lldb/API", ".h"),
("scripts", ".swig"),
("scripts/Python", ".swig"),
("scripts/interface", ".i")]
zip_data = io.BytesIO()
packed_input = local.pack_archive(
zip_data, options.src_root, inputs)
logging.info("(null) -> config.json")
packed_input.writestr("config.json", config)
packed_input.close()
connection = establish_remote_connection(options.remote)
response = transmit_request(connection, zip_data.getvalue())
handle_response(options, connection, response)
finally:
if connection is not None:
connection.close()

View File

@ -1,133 +0,0 @@
#!/usr/bin/env python
"""
Shared functionality used by `client` and `server` when generating or preparing
to generate SWIG on the local machine.
"""
# Future imports
from __future__ import absolute_import
from __future__ import print_function
# Python modules
import argparse
import imp
import io
import logging
import os
import subprocess
import sys
import tempfile
import zipfile
# LLDB modules
import use_lldb_suite
# Package imports
from lldbsuite.support import fs
class LocalConfig(object):
src_root = None
target_dir = None
languages = None
swig_executable = None
def pack_archive(bytes_io, src_root, filters):
logging.info("Creating input file package...")
zip_file = None
try:
# It's possible that a custom-built interpreter will not have the
# standard zlib module. If so, we can only store, not compress. By
# try to compress since we usually have a standard Python distribution.
zip_file = zipfile.ZipFile(bytes_io, mode='w',
compression=zipfile.ZIP_DEFLATED)
except RuntimeError:
zip_file = zipfile.ZipFile(bytes_io, mode='w',
compression=zipfile.ZIP_STORED)
archive_entries = []
if filters is not None:
def filter_func(t):
subfolder = t[0]
ext = t[1]
full_path = os.path.normpath(os.path.join(src_root, subfolder))
candidates = [os.path.normpath(os.path.join(full_path, f))
for f in os.listdir(full_path)]
actual = [f for f in candidates if os.path.isfile(f) and os.path.splitext(f)[1] == ext]
return (subfolder, [os.path.basename(f) for f in actual])
archive_entries = map(filter_func, filters)
else:
for (root, dirs, files) in os.walk(src_root):
logging.debug("Adding files {} from directory {} to output package"
.format(files, root))
if len(files) > 0:
rel_root = os.path.relpath(root, src_root)
archive_entries.append((rel_root, files))
archive_entries = list(archive_entries)
for entry in archive_entries:
subfolder = entry[0]
files = list(entry[1])
for file in files:
rel_path = os.path.normpath(os.path.join(subfolder, file))
full_path = os.path.join(src_root, rel_path)
logging.info("{} -> {}".format(full_path, rel_path))
zip_file.write(full_path, rel_path)
return zip_file
def unpack_archive(folder, archive_bytes):
zip_data = io.BytesIO(archive_bytes)
logging.debug("Opening zip archive...")
zip_file = zipfile.ZipFile(zip_data, mode='r')
zip_file.extractall(folder)
zip_file.close()
def generate(options):
include_folder = os.path.join(options.src_root, "include")
in_file = os.path.join(options.src_root, "scripts", "lldb.swig")
include_folder = os.path.normcase(include_folder)
for lang in options.languages:
lang = lang.lower()
out_dir = os.path.join(options.target_dir, lang.title())
if not os.path.exists(out_dir):
os.makedirs(out_dir)
out_file = os.path.join(out_dir, "LLDBWrap{}.cpp".format(lang.title()))
swig_command = [
options.swig_executable,
"-c++",
]
swig_command.append("-" + lang)
if lang == "python":
swig_command.append("-threads")
swig_command.extend([
"-I" + include_folder,
"-D__STDC_LIMIT_MACROS",
"-D__STDC_CONSTANT_MACROS",
"-outdir", out_dir,
"-o", out_file,
in_file
])
logging.info("generating swig {} bindings into {}"
.format(lang, out_dir))
logging.debug("swig command line: {}".format(swig_command))
try:
# Execute swig
swig_output = subprocess.check_output(
swig_command, stderr=subprocess.STDOUT, universal_newlines=True)
logging.info("swig generation succeeded")
if swig_output is not None and len(swig_output) > 0:
logging.info("swig output: %s", swig_output)
return (0, swig_output)
except subprocess.CalledProcessError as e:
logging.error("An error occurred executing swig. returncode={}"
.format(e.returncode))
logging.error(e.output)
return (e.returncode, e.output)

View File

@ -1,43 +0,0 @@
#!/usr/bin/env python
"""
Shared functionality used by `client` and `server` when dealing with
remote transmission
"""
# Future imports
from __future__ import absolute_import
from __future__ import print_function
# Python modules
import json
import logging
import os
import socket
import struct
import sys
# LLDB modules
import use_lldb_suite
def generate_config(languages):
config = {"languages": languages}
return json.dumps(config)
def parse_config(json_reader):
json_data = json_reader.read()
options_dict = json.loads(json_data)
return options_dict
def serialize_response_status(status):
status = {"retcode": status[0], "output": status[1]}
return json.dumps(status)
def deserialize_response_status(json_reader):
json_data = json_reader.read()
response_dict = json.loads(json_data)
return (response_dict["retcode"], response_dict["output"])

View File

@ -1,144 +0,0 @@
#!/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