-
Notifications
You must be signed in to change notification settings - Fork 178
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
237 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
[rust] | ||
template_dir = "rust/templates" | ||
extra_mounts = [["rust/.rustfmt.toml", "/app/.rustfmt.toml"]] | ||
extra_shell_commands = ["rm rust/src/api/{environment,health}.rs"] | ||
openapi = "lib-openapi.json" | ||
|
||
[[rust.task]] | ||
template = "rust/templates/api_resource.rs.jinja" | ||
output_dir = "rust/src/api" | ||
[[rust.task]] | ||
template = "rust/templates/component_type.rs.jinja" | ||
output_dir = "rust/src/models" | ||
|
||
|
||
[javascript] | ||
template_dir = "javascript/templates" | ||
openapi = "lib-openapi.json" | ||
|
||
[[javascript.task]] | ||
template = "javascript/templates/api_resource.ts.jinja" | ||
output_dir = "javascript/src/api" | ||
[[javascript.task]] | ||
template = "javascript/templates/component_type_summary.ts.jinja" | ||
output_dir = "javascript/src/models" | ||
[[javascript.task]] | ||
template = "javascript/templates/component_type.ts.jinja" | ||
output_dir = "javascript/src/models" | ||
|
||
|
||
[cli] | ||
template_dir = "svix-cli/templates" | ||
extra_mounts = [["svix-cli/.rustfmt.toml", "/app/.rustfmt.toml"]] | ||
extra_shell_commands = [ | ||
"cargo fix --manifest-path svix-cli/Cargo.toml --allow-dirty", | ||
"cargo fmt --manifest-path svix-cli/Cargo.toml", | ||
"rm svix-cli/src/cmds/api/{background_task,environment,health,operational_webhook_endpoint,statistics}.rs", | ||
] | ||
openapi = "lib-openapi.json" | ||
|
||
[[cli.task]] | ||
template = "svix-cli/templates/api_resource.rs.jinja" | ||
output_dir = "svix-cli/src/cmds/api" | ||
|
||
|
||
[python] | ||
template_dir = "python/templates" | ||
openapi = "lib-openapi.json" | ||
extra_shell_commands = ["rm python/svix/api/{environment,health}.py"] | ||
|
||
[[python.task]] | ||
template = "python/templates/api_resource.py.jinja" | ||
output_dir = "python/svix/api" | ||
[[python.task]] | ||
template = "python/templates/component_type_summary.py.jinja" | ||
output_dir = "python/svix/models" | ||
[[python.task]] | ||
template = "python/templates/component_type.py.jinja" | ||
output_dir = "python/svix/models" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,179 @@ | ||
#!/usr/bin/env python3 | ||
import pathlib | ||
from pathlib import Path | ||
import shutil | ||
import subprocess | ||
import os | ||
from concurrent.futures import ThreadPoolExecutor | ||
|
||
try: | ||
import tomllib | ||
except ImportError: | ||
print("Python 3.11 or greater is required to run the codegen") | ||
exit(1) | ||
|
||
OPENAPI_CODEGEN_IMAGE = "ghcr.io/svix/openapi-codegen:latest" | ||
REPO_ROOT = pathlib.Path(__file__).parent.resolve() | ||
DEBUG = os.getenv("DEBUG") is not None | ||
|
||
|
||
def get_docker_binary() -> str: | ||
# default to podman | ||
docker_binary = shutil.which("podman") | ||
if docker_binary is None: | ||
docker_binary = shutil.which("docker") | ||
if docker_binary is None: | ||
print("Please install docker or podman to run the codegen") | ||
exit(1) | ||
return docker_binary | ||
|
||
|
||
def docker_container_rm(prefix, container_id): | ||
cmd = [get_docker_binary(), "container", "rm", container_id] | ||
result = run_cmd(prefix, cmd) | ||
return result.stdout.decode("utf-8") | ||
|
||
|
||
def docker_container_logs(prefix, container_id): | ||
cmd = [get_docker_binary(), "container", "logs", container_id] | ||
result = run_cmd(prefix, cmd) | ||
return result.stdout.decode("utf-8") | ||
|
||
|
||
def docker_container_wait(prefix, container_id) -> int: | ||
cmd = [get_docker_binary(), "container", "wait", container_id] | ||
result = run_cmd(prefix, cmd) | ||
return int(result.stdout.decode("utf-8")) | ||
|
||
|
||
def docker_container_cp(prefix, container_id, task): | ||
cmd = [ | ||
get_docker_binary(), | ||
"container", | ||
"cp", | ||
f"{container_id}:/app/{task['output_dir']}/.", | ||
f"{task['output_dir']}/", | ||
] | ||
run_cmd(prefix, cmd) | ||
|
||
|
||
def docker_container_create(prefix, task) -> str: | ||
cmd = [ | ||
get_docker_binary(), | ||
"container", | ||
"run", | ||
"-d", | ||
"--workdir", | ||
"/app", | ||
"--mount", | ||
f"type=bind,src={Path(task['openapi']).absolute()},dst=/app/lib-openapi.json,ro", | ||
"--mount", | ||
f"type=bind,src={Path(task['template_dir']).absolute()},dst=/app/{task['template_dir']},ro", | ||
] | ||
for extra_mount in task["extra_mounts"]: | ||
cmd.append("--mount") | ||
cmd.append( | ||
f"type=bind,src={Path(extra_mount[0]).absolute()},dst={extra_mount[1]},ro" | ||
) | ||
cmd.extend( | ||
[ | ||
OPENAPI_CODEGEN_IMAGE, | ||
"openapi-codegen", | ||
"generate", | ||
"--create-file-parents", | ||
"--template", | ||
task["template"], | ||
"--input-file", | ||
task["openapi"], | ||
"--output-dir", | ||
task["output_dir"], | ||
] | ||
) | ||
result = run_cmd(prefix, cmd) | ||
return result.stdout.decode("utf-8") | ||
|
||
|
||
def run_cmd(prefix, cmd) -> subprocess.CompletedProcess[bytes]: | ||
dbg(prefix, " ".join(cmd)) | ||
result = subprocess.run(cmd, stdout=subprocess.PIPE, cwd=REPO_ROOT) | ||
if result.returncode != 0: | ||
print_cmd_result(result, prefix) | ||
exit(result.returncode) | ||
return result | ||
|
||
|
||
def print_cmd_result(result: subprocess.CompletedProcess[bytes], prefix: str): | ||
for i in [result.stdout, result.stderr]: | ||
if i is None: | ||
continue | ||
prefix_print(prefix, i.decode("utf-8")) | ||
|
||
|
||
def dbg(prefix, msg): | ||
if not DEBUG: | ||
return | ||
prefix_print(prefix, msg) | ||
|
||
|
||
def prefix_print(prefix, msg): | ||
prefix = f"{prefix.strip()} | " | ||
print("{}{}".format(prefix, msg.strip().replace("\n", f"\n{prefix} "))) | ||
|
||
|
||
def execute_codegen_task(task): | ||
prefix = f"{task['language']}[{task['language_index']+1}/{task['language_total']}]" | ||
prefix_print(prefix, "Starting codegen task") | ||
|
||
container_id = docker_container_create(prefix, task).strip() | ||
dbg(prefix, f"Container id {container_id}") | ||
|
||
exit_code = docker_container_wait(prefix, container_id) | ||
|
||
logs = docker_container_logs(prefix, container_id) | ||
prefix_print(prefix, logs) | ||
|
||
if exit_code != 0: | ||
exit(exit_code) | ||
|
||
docker_container_cp(prefix, container_id, task) | ||
|
||
docker_container_rm(prefix, container_id) | ||
|
||
|
||
def run_codegen_for_language(language, language_config): | ||
tasks = [] | ||
for index, task in enumerate(language_config.get("task", [])): | ||
tasks.append( | ||
{ | ||
"language": language, | ||
"language_index": index, | ||
"language_total": len(language_config.get("task", [])), | ||
"openapi": language_config["openapi"], | ||
"template": task["template"], | ||
"output_dir": task["output_dir"], | ||
"extra_mounts": language_config.get("extra_mounts", []), | ||
"template_dir": language_config["template_dir"], | ||
} | ||
) | ||
with ThreadPoolExecutor() as pool: | ||
pool.map(execute_codegen_task, tasks) | ||
pool.shutdown(wait=True) | ||
|
||
for shell_command in language_config.get("extra_shell_commands"): | ||
cmd = ["bash", "-c", shell_command] | ||
run_cmd(language, cmd) | ||
|
||
|
||
def main(): | ||
# TODO: pull image before running tasks | ||
with ThreadPoolExecutor() as pool: | ||
with open(REPO_ROOT.joinpath("codegen.toml"), "rb") as f: | ||
data = tomllib.load(f) | ||
for language, language_config in data.items(): | ||
pool.submit(run_codegen_for_language, language, language_config) | ||
|
||
pool.shutdown(wait=True) | ||
|
||
|
||
if __name__ == "__main__": | ||
main() |