builder.braak.pro/config/worker/doc_api.py
2024-11-19 21:59:53 +01:00

247 lines
8.2 KiB
Python
Executable file

#!/usr/bin/env python3
# SPDX-License-Identifier: GPL-2.0-or-later
# SPDX-FileCopyrightText: 2011-2024 Blender Authors
# <pep8 compliant>
import argparse
import os
import pathlib
import sys
from collections import OrderedDict
sys.path.append(str(pathlib.Path(__file__).resolve().parent.parent))
import worker.configure
import worker.utils
import worker.blender
import worker.blender.compile
import worker.blender.update
import worker.blender.version
class DocApiBuilder(worker.blender.CodeBuilder):
def __init__(self, args: argparse.Namespace):
super().__init__(args)
self.needs_package_delivery = args.needs_package_delivery
self.setup_track_path()
def download_api_dump_test_data(local_delivery_path: pathlib.Path) -> None:
import urllib.request
import json
api_base_url = "https://docs.blender.org/api"
api_dump_index_url = f"{api_base_url}/api_dump_index.json"
request = urllib.request.Request(
api_dump_index_url, headers={"User-Agent": "Mozilla"}
)
response = urllib.request.urlopen(request, timeout=5.0)
api_dump_index_text = response.read().decode("utf-8", "ignore")
api_dump_index_path = local_delivery_path / "api_dump_index.json"
os.makedirs(api_dump_index_path.parent, exist_ok=True)
api_dump_index_path.write_text(api_dump_index_text)
api_dump_index = json.loads(api_dump_index_text)
for version in api_dump_index.keys():
api_dump_url = f"{api_base_url}/{version}/api_dump.json"
worker.utils.info(f"Download {api_dump_url}")
request = urllib.request.Request(
api_dump_url, headers={"User-Agent": "Mozilla"}
)
response = urllib.request.urlopen(request, timeout=5.0)
api_dump_text = response.read().decode("utf-8", "ignore")
api_dump_path = local_delivery_path / version / "api_dump.json"
os.makedirs(api_dump_path.parent, exist_ok=True)
api_dump_path.write_text(api_dump_text)
def compile_doc(builder: DocApiBuilder) -> None:
# Install requirements
os.chdir(builder.track_path)
doc_api_script_path = builder.code_path / "doc" / "python_api"
worker.utils.call_pipenv(
["install", "--requirements", doc_api_script_path / "requirements.txt"]
)
# Clean build directory
worker.utils.remove_dir(builder.build_doc_path)
os.makedirs(builder.build_doc_path, exist_ok=True)
os.chdir(doc_api_script_path)
# Get API dumps data from server.
api_dump_build_path = builder.build_doc_path / "api_dump"
os.makedirs(api_dump_build_path, exist_ok=True)
api_dump_include_paths = ["api_dump_index.json", "*/", "api_dump.json"]
api_dump_build_path_index = api_dump_build_path / "api_dump_index.json"
worker_config = builder.get_worker_config()
connect_id = f"{worker_config.docs_user}@{worker_config.docs_machine}"
remote_path = (
pathlib.Path(worker_config.docs_folder)
/ "docs.blender.org"
/ "htdocs"
/ builder.service_env_id
/ "api"
)
# Get data from docs.blender.org for local testing.
if builder.service_env_id == "LOCAL":
worker.utils.info("Downloading API dump data from docs.blender.org for testing")
download_api_dump_test_data(remote_path)
source_path = f"{connect_id}:{remote_path}/"
dest_path = api_dump_build_path
worker.utils.rsync(
source_path,
dest_path,
include_paths=api_dump_include_paths,
exclude_paths=["*"],
)
version = worker.blender.version.VersionInfo(builder).short_version
api_dump_build_path_current_version = api_dump_build_path / version
os.makedirs(api_dump_build_path_current_version, exist_ok=True)
# Generate API docs
cmd = [
builder.blender_command_path(),
"--background",
"--factory-startup",
"-noaudio",
"--python",
doc_api_script_path / "sphinx_doc_gen.py",
"--",
"--output",
builder.build_doc_path,
"--api-changelog-generate",
"--api-dump-index-path",
api_dump_build_path_index,
]
worker.utils.call(cmd)
num_threads = worker.configure.get_thread_count(thread_memory_in_GB=1.25)
in_path = builder.build_doc_path / "sphinx-in"
out_path = builder.build_doc_path / "sphinx-out-html"
worker.utils.call(
["sphinx-build", "-b", "html", "-j", str(num_threads), in_path, out_path]
)
def package(builder: DocApiBuilder) -> None:
os.chdir(builder.build_doc_path)
version = worker.blender.version.VersionInfo(builder).short_version
version_file_label = version.replace(".", "_")
package_name = f"blender_python_reference_{version_file_label}"
package_file_name = f"{package_name}.zip"
cmd = ["7z", "a", "-tzip", package_file_name, "./sphinx-out-html", "-r"]
worker.utils.call(cmd)
cmd = ["7z", "rn", package_file_name, "sphinx-out-html", package_name]
worker.utils.call(cmd)
def deliver(builder: DocApiBuilder) -> None:
# Get versions
branches_config = builder.get_branches_config()
version = worker.blender.version.VersionInfo(builder).short_version
dev_version = branches_config.track_major_minor_versions["vdev"]
latest_version = branches_config.doc_stable_major_minor_version
# Get remote path
worker_config = builder.get_worker_config()
connect_id = f"{worker_config.docs_user}@{worker_config.docs_machine}"
remote_path = (
pathlib.Path(worker_config.docs_folder)
/ "docs.blender.org"
/ "htdocs"
/ builder.service_env_id
/ "api"
)
version_remote_path = remote_path / version
worker.utils.call_ssh(connect_id, ["mkdir", "-p", version_remote_path])
change_modes = ["D0755", "F0644"]
# Sync HTML files
source_path = f"{builder.build_doc_path}/sphinx-out-html/"
dest_path = f"{connect_id}:{version_remote_path}/"
worker.utils.rsync(
source_path, dest_path, exclude_paths=[".doctrees"], change_modes=change_modes
)
# Put API dumps data on the server.
api_dump_build_path = f"{builder.build_doc_path}/api_dump/"
api_dump_dest_path = f"{connect_id}:{remote_path}/"
worker.utils.rsync(
api_dump_build_path, api_dump_dest_path, change_modes=change_modes
)
# Sync zip package
if builder.needs_package_delivery:
version_file_label = version.replace(".", "_")
package_name = f"blender_python_reference_{version_file_label}"
package_file_name = f"{package_name}.zip"
source_file_path = builder.build_doc_path / package_file_name
dest_file_path = f"{connect_id}:{version_remote_path}/{package_file_name}"
worker.utils.rsync(
source_file_path,
dest_file_path,
exclude_paths=[".doctrees"],
change_modes=change_modes,
)
# Create links
if builder.track_id == "vdev":
worker.utils.call_ssh(
connect_id, ["ln", "-svF", remote_path / dev_version, remote_path / "dev"]
)
worker.utils.call_ssh(
connect_id,
["ln", "-svF", remote_path / dev_version, remote_path / "master"],
)
worker.utils.call_ssh(
connect_id, ["ln", "-svF", remote_path / dev_version, remote_path / "main"]
)
worker.utils.call_ssh(
connect_id,
["ln", "-svF", remote_path / latest_version, remote_path / "latest"],
)
worker.utils.call_ssh(
connect_id,
["ln", "-svF", remote_path / latest_version, remote_path / "current"],
)
if __name__ == "__main__":
steps: worker.utils.BuilderSteps = OrderedDict()
steps["configure-machine"] = worker.configure.configure_machine
steps["update-code"] = worker.blender.update.update
steps["compile-code"] = worker.blender.compile.compile_code
steps["compile-install"] = worker.blender.compile.compile_install
steps["compile"] = compile_doc
steps["package"] = package
steps["deliver"] = deliver
steps["clean"] = worker.blender.CodeBuilder.clean
parser = worker.blender.create_argument_parser(steps=steps)
parser.add_argument("--needs-package-delivery", action="store_true", required=False)
args = parser.parse_args()
builder = DocApiBuilder(args)
builder.run(args.step, steps)