|
1 | 1 | import subprocess
|
2 | 2 | import os
|
3 | 3 | import json
|
| 4 | +import jinja2 |
4 | 5 |
|
5 | 6 | from launcher.config import check_config
|
6 | 7 | from launcher.skyportal import patch as patch_skyportal
|
7 | 8 |
|
8 | 9 |
|
| 10 | +def patch_api_doc_template(): |
| 11 | + """Patch the API documentation template with the OpenAPI spec. |
| 12 | +
|
| 13 | + This function reads the OpenAPI specification from the openapi.json file, |
| 14 | + populates it with server information from the configuration, and renders |
| 15 | + a HTML documentation page from https://github.com/scalar/scalar |
| 16 | + using a Jinja2 template. |
| 17 | +
|
| 18 | + Raises: |
| 19 | + ValueError: If the server information is not valid. |
| 20 | + """ |
| 21 | + # open the openapi.json file generated by build-spec.py |
| 22 | + from baselayer.app.env import load_env |
| 23 | + |
| 24 | + _, cfg = load_env() |
| 25 | + |
| 26 | + with open("openapi.json") as f: |
| 27 | + openapi_spec = json.load(f) |
| 28 | + |
| 29 | + # populate the OpenAPI spec with (optional) server information |
| 30 | + servers = cfg.get("docs.servers", []) |
| 31 | + if servers is None: |
| 32 | + servers = [] |
| 33 | + if not isinstance(servers, list): |
| 34 | + raise ValueError("API servers must be a list.") |
| 35 | + |
| 36 | + for server in servers: |
| 37 | + if not all(k in server for k in ("url", "description")): |
| 38 | + raise ValueError("Each server must have 'url' and 'description' keys.") |
| 39 | + openapi_spec["servers"] = servers |
| 40 | + |
| 41 | + # Create a Jinja2 template environment |
| 42 | + template_env = jinja2.Environment(loader=jinja2.FileSystemLoader(searchpath="./")) |
| 43 | + |
| 44 | + # Load the template file |
| 45 | + template = template_env.get_template("skyportal/doc/openapi.html.template") |
| 46 | + |
| 47 | + # Render the template with the OpenAPI spec |
| 48 | + output = template.render(openapi_spec=json.dumps(openapi_spec, indent=2)) |
| 49 | + |
| 50 | + # Write the output to a new HTML file |
| 51 | + os.makedirs("./doc/_build/html", exist_ok=True) |
| 52 | + with open("./doc/_build/html/api.html", "w") as f: |
| 53 | + f.write(output) |
| 54 | + |
| 55 | + |
9 | 56 | def doc(yes: bool = False, upload: bool = False):
|
10 | 57 | """Build the documentation
|
11 | 58 |
|
@@ -43,27 +90,12 @@ def doc(yes: bool = False, upload: bool = False):
|
43 | 90 | "servers": [{"url": "https://fritz.science"}],
|
44 | 91 | },
|
45 | 92 | )
|
46 |
| - with open("skyportal/openapi.json", "w") as f: |
| 93 | + with open("openapi.json", "w") as f: |
47 | 94 | json.dump(spec.to_dict(), f)
|
48 | 95 |
|
49 |
| - subprocess.run( |
50 |
| - [ |
51 |
| - "npx", |
52 |
| - "redoc-cli@0.13.21", |
53 |
| - "bundle", |
54 |
| - "openapi.json", |
55 |
| - "--title", |
56 |
| - "Fritz API docs", |
57 |
| - "--cdn", |
58 |
| - "--options.theme.logo.gutter", |
59 |
| - "2rem", |
60 |
| - "-o", |
61 |
| - "../doc/_build/html/api.html", |
62 |
| - ], |
63 |
| - check=True, |
64 |
| - cwd="skyportal", |
65 |
| - ) |
66 |
| - os.remove("skyportal/openapi.json") |
| 96 | + patch_api_doc_template() |
| 97 | + |
| 98 | + os.remove("openapi.json") |
67 | 99 |
|
68 | 100 | if upload:
|
69 | 101 | subprocess.run(
|
|
0 commit comments