tools/scripts/run_code_generation.py (127 lines of code) (raw):
#!/usr/bin/env python3
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0.
import argparse
import os
import sys
from concurrent.futures import ProcessPoolExecutor, wait, FIRST_COMPLETED, ALL_COMPLETED
from pathlib import Path
from codegen.legacy_c2j_cpp_gen import LegacyC2jCppGen, CLIENT_MODEL_FILE_LOCATION, ENDPOINT_RULES_LOCATION
from codegen.model_utils import ModelUtils
from codegen.protocol_tests_gen import ProtocolTestsGen
from codegen.smoke_tests_gen import SmokeTestsGen
def parse_arguments() -> dict:
"""Parse arguments and/or print help
:return: dict with parsed arguments
"""
parser = argparse.ArgumentParser(description="Code generation wrapper for AWS-SDK-CPP")
parser.add_argument("--debug", action="store_true", help="Print additional information")
parser.add_argument("--client_list", type=str, help="Comma-separated or semi-colon-separated list of SDK clients "
"to be (re)generated")
parser.add_argument("--defaults", action="store_true", help="Generates defaults configuration")
parser.add_argument("--partitions", action="store_true", help="Generates partitions blob")
parser.add_argument("--all",
help="Generate all found clients and defaults. Always True unless client_list provided",
action="store_true")
parser.add_argument("--output_location", action="store", help="Where generated clients should be extracted")
parser.add_argument("--api_definition_file", action="store", help="Override input client definition model file")
parser.add_argument("--path_to_api_definitions", action="store")
parser.add_argument("--path_to_endpoint_rules", action="store")
parser.add_argument("--path_to_generator", action="store")
parser.add_argument("--prepare_tools", help="Just build the generator", action="store_true")
parser.add_argument("--list_all", help="Lists all available SDKs for generation.", action="store_true")
# raw generator params to pass through
parser.add_argument("--license-text", action="store", help="License text to use, "
"raw argument to be passed to the generator")
parser.add_argument("--namespace", action="store", help="Namespace to use,"
" raw argument to be passed to the generator")
parser.add_argument("--standalone",
help="Code generator raw argument to be passed through to "
"build a custom client as a separate package, with prebuilt C++ SDK as dependency. "
"Always off by default.",
action="store_true")
parser.add_argument("--enable-virtual-operations",
help="Code generator raw argument to be passed through to "
"mark operation functions in service client as virtual functions. Always on by default",
action="store_true")
parser.add_argument("--generate_smoke_tests",
help="Run smithy code generator for smoke tests",
action="store_true")
parser.add_argument("--generate_protocol_tests",
help="Run protocol tests generation",
action="store_true")
args = vars(parser.parse_args())
arg_map = {"debug": args.get("debug", False)}
if args.get("all", None):
arg_map["all"] = True
arg_map["defaults"] = True
arg_map["partitions"] = True
elif args.get("api_definition_file", None):
arg_map["api_definition_file"] = args.get("api_definition_file")
else:
raw_client_list = args.get("client_list", None)
arg_map["all"] = False
arg_map["defaults"] = False
arg_map["partitions"] = False
arg_map["client_list"] = False
if args.get("defaults", None):
arg_map["defaults"] = args.get("defaults")
if args.get("partitions", None):
arg_map["partitions"] = args.get("partitions")
if raw_client_list:
arg_map["client_list"] = raw_client_list.replace(";", ",").split(",")
output_location = args["output_location"] or None
if not output_location:
output_location = os.getcwd()
if output_location.endswith("scripts"):
output_location = output_location[:-len("tools/scripts")]
output_location += "/generated"
arg_map["output_location"] = output_location
for cli_argument, default_value in [("path_to_api_definitions", CLIENT_MODEL_FILE_LOCATION),
("path_to_endpoint_rules", ENDPOINT_RULES_LOCATION)]:
models_location = args[cli_argument] or default_value
models_location = str(Path(models_location).absolute())
if not os.path.exists(models_location):
if args[cli_argument] is not None and args[cli_argument] != "":
raise RuntimeError(f"Provided {cli_argument} does not exist!")
models_location = str(Path(sys.path[0] + "/../" + default_value).absolute())
if not os.path.exists(models_location) and cli_argument != "path_to_endpoint_rules":
raise RuntimeError("Could not find api definitions location!")
arg_map[cli_argument] = models_location
arg_map["path_to_generator"] = args.get("path_to_generator", None)
arg_map["prepare_tools"] = args["prepare_tools"] or False
arg_map["list_all"] = args["list_all"] or False
raw_generator_arguments = dict()
for raw_argument in ["license-text", "namespace", "standalone"]:
if args.get(raw_argument):
raw_generator_arguments[raw_argument] = args[raw_argument]
arg_map["raw_generator_arguments"] = raw_generator_arguments
arg_map["generate_smoke_tests"] = args.get("generate_smoke_tests", None)
arg_map["generate_protocol_tests"] = args.get("generate_protocol_tests", None)
if arg_map["debug"]:
print("args=", arg_map)
return arg_map
def main():
"""Main entrypoint for this script that wraps AWS-SDK-CPP code generation
:return: 0 if success, failure otherwise
"""
args = parse_arguments()
model_utils = ModelUtils(args)
if args.get("list_all"):
model_list = model_utils.models_to_generate.keys()
print(sorted(model_list))
return 0
highly_refined_percent_of_cores_to_take = 0.9
max_workers = max(1, int(highly_refined_percent_of_cores_to_take * os.cpu_count()))
if args["debug"]:
print(f"Parallel executor thread count: {max_workers}")
with ProcessPoolExecutor(max_workers=max_workers) as executor:
c2j_gen = LegacyC2jCppGen(args, model_utils.models_to_generate)
if c2j_gen.generate(executor, max_workers, args) != 0:
print("ERROR: Failed to generate service client(s)!")
return -1
if args["generate_protocol_tests"]:
protocol_tests_generator = ProtocolTestsGen(args)
if protocol_tests_generator.generate(executor, max_workers) != 0:
print("ERROR: Failed to generate protocol test(s)!")
return -1
# generate code using smithy for all discoverable clients
# clients_to_build check is present because user can generate only defaults or partitions or protocol-tests
clients_to_build = model_utils.get_clients_to_build()
if args["generate_smoke_tests"] and clients_to_build:
smoke_tests_gen = SmokeTestsGen(args["debug"])
if smoke_tests_gen.generate(clients_to_build) != 0:
print("ERROR: Failed to generate smoke test(s)!")
return -1
return 0
if __name__ == "__main__":
ret_code = main()
exit(ret_code)