247 lines
8.2 KiB
Python
Executable file
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)
|