diff --git a/scripts/build_twilio_library.py b/scripts/build_twilio_library.py index b39ed5916..5a128005e 100644 --- a/scripts/build_twilio_library.py +++ b/scripts/build_twilio_library.py @@ -1,11 +1,15 @@ import argparse +import glob import json import os import re +import shlex import shutil +import subprocess from pathlib import Path from typing import List, Tuple + from clean_unused_imports import remove_unused_imports, remove_duplicate_imports from process_orgs_api import preprocess_orgs_spec @@ -40,6 +44,10 @@ def build(openapi_spec_path: str, output_path: str, language: str) -> None: def generate(spec_folder: str, spec_files: List[str], output_path: str, language: str) -> None: + """ + spec_folder: typically "examples/spec/json" + config_path: typically "tmp" + """ sub_dir = subdirectories.get(language, 'rest') parent_dir = Path(__file__).parent.parent output_path = os.path.join(output_path, sub_dir) @@ -56,7 +64,9 @@ def generate(spec_folder: str, spec_files: List[str], output_path: str, language generate_domain_for_language(input_path_versionless, config_path, spec_dir, output_path, language, parent_dir) if language in generateForLanguages.get(spec_file): generate_domain_for_language(spec_file, config_path, spec_folder, output_path, language, parent_dir) - else: generate_domain_for_language(spec_file, config_path, spec_folder, output_path, language, parent_dir) + else: + generate_domain_for_language(spec_file, config_path, spec_folder, output_path, language, parent_dir) + if spec_files[0] in generateForLanguages: if language in generateForLanguages.get(spec_files[0]) or language in dynamic_languages: print(f'Generating {output_path} from {spec_folder}') @@ -74,6 +84,7 @@ def generate(spec_folder: str, spec_files: List[str], output_path: str, language def generate_domain_for_language(spec_file: str, config_path: str, spec_folder: str, output_path: str, language: str, parent_dir: str) -> None: + print("generate domain for language: {}, config: {}, spec folder: {}, file: {}".format(language, config_path, spec_folder, spec_file)) full_path = os.path.join(spec_folder, spec_file) full_config_path = os.path.join(config_path, spec_file) config = { @@ -86,20 +97,38 @@ def generate_domain_for_language(spec_file: str, config_path: str, spec_folder: } # print(config) with open(full_config_path, 'w') as f: - f.write(json.dumps(config)) - + f.write(json.dumps(config) + "\n") def run_openapi_generator(parent_dir: Path, language: str) -> None: - properties = '-DapiTests=false' - if language in {'node', 'python'}: - properties += ' -DskipFormModel=false' - - command = f'cd {parent_dir} && java {properties} ' \ - f'-cp target/twilio-openapi-generator.jar ' \ - f'org.openapitools.codegen.OpenAPIGenerator batch {CONFIG_FOLDER}/{language}/*' - - if os.system(command + '> /dev/null') != 0: # Suppress stdout - raise RuntimeError() + properties = "-DapiTests=false" + if language in {"node", "python"}: + properties += " -DskipFormModel=false" + + paths = glob.glob(os.path.join(CONFIG_FOLDER, language, "*")) + + command = [ + "java", + *properties.split(), # Splits e.g. "-DapiTests=false -DskipFormModel=false" into separate arguments + "-cp", + "target/twilio-openapi-generator.jar", + "org.openapitools.codegen.OpenAPIGenerator", + "batch", + *paths, + ] + + printable_cmd = " ".join(shlex.quote(arg) for arg in command) + print(f"Running command: {printable_cmd}") + + try: + subprocess.run( + command, + cwd=parent_dir, # Change working directory to parent_dir + check=True, # Raise CalledProcessError on non-zero exit + stdout=subprocess.DEVNULL, # Suppress standard output + ) + except subprocess.CalledProcessError as exc: + # Wrap the original exception for more informative error handling + raise RuntimeError("OpenAPI generation failed.") from exc def get_domain_info(oai_spec_location: str, domain: str, is_file: bool = False) -> Tuple[str, str, str]: diff --git a/scripts/generate_libraries/__init__.py b/scripts/generate_libraries/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/scripts/generate_libraries/main.py b/scripts/generate_libraries/main.py new file mode 100644 index 000000000..fd1104629 --- /dev/null +++ b/scripts/generate_libraries/main.py @@ -0,0 +1,101 @@ +#!/usr/bin/env python3 + +# an example way to run this script would be: +# +# cd /path/to/twilio-oai-generator +# python -m scripts.generate_libraries.main --language go --input=../twilio-oai/spec/json --base=.. +# +# and have twilio-oai and twilio-go as sibling directories to twilio-oai-generator + +import argparse +import glob +import os +from .. import build_twilio_library as build_library + + +def parse_args(): + parser = argparse.ArgumentParser( + description="Generate files for Twilio library in different languages." + ) + parser.add_argument( + "--language", + choices=["csharp", "java", "node", "php", "go", "python", "ruby", "terraform"], + required=True, + help="Specify the target language for code generation." + ) + parser.add_argument( + "--base", + default=".", + help="Base directory for code generation. Defaults to current directory." + ) + parser.add_argument( + "--input", + default=None, + help="Path to the OpenAPI spec JSON files. If not specified, defaults to 'spec/json' inside the base directory." + ) + return parser.parse_args() + + +def get_output_dir(base, language): + """ + Constructs the output directory for each language based on the given base path. + Update these paths as needed for your environment or repository layout. + """ + if language == "csharp": + return os.path.join(base, "twilio-csharp/src/Twilio") + elif language == "java": + return os.path.join(base, "twilio-java/src/main/java/com/twilio") + elif language == "node": + return os.path.join(base, "twilio-node/src") + elif language == "php": + return os.path.join(base, "twilio-php/src/Twilio") + elif language == "go": + return os.path.join(base, "twilio-go") + elif language == "python": + return os.path.join(base, "twilio-python/twilio") + elif language == "ruby": + return os.path.join(base, "twilio-ruby/lib/twilio-ruby") + elif language == "terraform": + return os.path.join(base, "terraform-provider-twilio") + else: + return None + + +def generate_files(input_dir, output_dir, language): + # If needed, you can iterate over the input spec files here using glob: + # for filepath in glob.glob(os.path.join(input_dir, "*.json")): + # print(filepath) + build_library.build(input_dir, output_dir, language) + + +def main(): + args = parse_args() + + # Determine input directory + input_dir = args.input if args.input else os.path.join(args.base, "spec/json") + + # Determine output directory for the chosen language + output_dir = get_output_dir(args.base, args.language) + + if not output_dir: + print("Unsupported language or path couldn't be resolved.") + return + + # Ensure the output directory exists + os.makedirs(output_dir, exist_ok=True) + + # Run a make install (if needed for your environment) + os.system("make install") + + # Generate files + generate_files(input_dir, output_dir, args.language) + + # Optional language-specific post-processing + if args.language == "go": + os.chdir(output_dir) + os.system("go fmt ./...") + os.system("goimports -w .") + + +if __name__ == "__main__": + main()