| 1 | // Copyright © SixtyFPS GmbH <info@slint.dev> |
| 2 | // SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0 |
| 3 | |
| 4 | // cspell:ignore cppdocs pipenv pipfile |
| 5 | |
| 6 | use anyhow::{Context, Result}; |
| 7 | use std::ffi::OsString; |
| 8 | use std::path::{Path, PathBuf}; |
| 9 | |
| 10 | #[path = "../../api/cpp/cbindgen.rs" ] |
| 11 | mod cbindgen; |
| 12 | |
| 13 | fn symlink_file<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> Result<()> { |
| 14 | if dst.as_ref().exists() { |
| 15 | std::fs::remove_file(path:dst.as_ref()).context("Error removing old symlink" )?; |
| 16 | } |
| 17 | #[cfg (target_os = "windows" )] |
| 18 | return std::os::windows::fs::symlink_file(&src, &dst).context("Error creating symlink" ); |
| 19 | #[cfg (not(target_os = "windows" ))] |
| 20 | return std::os::unix::fs::symlink(&src, &dst).context(format!( |
| 21 | "Error creating symlink from {} to {}" , |
| 22 | src.as_ref().display(), |
| 23 | dst.as_ref().display() |
| 24 | )); |
| 25 | } |
| 26 | |
| 27 | fn symlink_dir<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> Result<()> { |
| 28 | if dst.as_ref().exists() { |
| 29 | std::fs::remove_dir_all(path:dst.as_ref()).context("Error removing old symlink" )?; |
| 30 | } |
| 31 | #[cfg (target_os = "windows" )] |
| 32 | return std::os::windows::fs::symlink_dir(&src, &dst).context("Error creating symlink" ); |
| 33 | #[cfg (not(target_os = "windows" ))] |
| 34 | return std::os::unix::fs::symlink(&src, &dst).context(format!( |
| 35 | "Error creating symlink from {} to {}" , |
| 36 | src.as_ref().display(), |
| 37 | dst.as_ref().display() |
| 38 | )); |
| 39 | } |
| 40 | |
| 41 | fn symlink_files_in_dir<S: AsRef<Path>, T: AsRef<Path>, TS: AsRef<Path>>( |
| 42 | src: S, |
| 43 | target: T, |
| 44 | target_to_source: TS, |
| 45 | ) -> Result<()> { |
| 46 | for entry: Result in std::fs::read_dir(path:src.as_ref()).context("Error reading docs source directory" )? { |
| 47 | let entry: DirEntry = entry.context("Error reading directory entry" )?; |
| 48 | let path: PathBuf = entry.path(); |
| 49 | let file_name: &OsStr = path.file_name().unwrap(); |
| 50 | let symlink_source: PathBuf = target_to_source.as_ref().to_path_buf().join(&file_name); |
| 51 | let symlink_target: PathBuf = target.as_ref().to_path_buf().join(path.file_name().unwrap()); |
| 52 | let filetype: FileType = entry.file_type().context("Cannot determine file type" )?; |
| 53 | if filetype.is_file() { |
| 54 | symlink_file(src:symlink_source, dst:symlink_target).context("Could not symlink file" )?; |
| 55 | } else if filetype.is_dir() { |
| 56 | symlink_dir(src:symlink_source, dst:symlink_target).context("Could not symlink directory" )?; |
| 57 | } |
| 58 | } |
| 59 | Ok(()) |
| 60 | } |
| 61 | |
| 62 | pub fn generate(show_warnings: bool, experimental: bool) -> Result<(), Box<dyn std::error::Error>> { |
| 63 | let root = super::root_dir(); |
| 64 | |
| 65 | let docs_source_dir = root.join("api/cpp" ); |
| 66 | let docs_build_dir = root.join("target/cppdocs" ); |
| 67 | let html_static_dir = docs_build_dir.join("_static" ); |
| 68 | |
| 69 | std::fs::create_dir_all(docs_build_dir.as_path()).context("Error creating docs build dir" )?; |
| 70 | std::fs::create_dir_all(html_static_dir.as_path()) |
| 71 | .context("Error creating _static path for docs build" )?; |
| 72 | |
| 73 | symlink_files_in_dir( |
| 74 | docs_source_dir.join("docs" ), |
| 75 | &docs_build_dir, |
| 76 | [".." , ".." , "api" , "cpp" , "docs" ].iter().collect::<PathBuf>(), |
| 77 | ) |
| 78 | .context("Error creating symlinks from docs source to docs build dir" )?; |
| 79 | |
| 80 | symlink_file( |
| 81 | [".." , ".." , "api" , "cpp" , "README.md" ].iter().collect::<PathBuf>(), |
| 82 | docs_build_dir.join("README.md" ), |
| 83 | )?; |
| 84 | |
| 85 | let generated_headers_dir = docs_build_dir.join("generated_include" ); |
| 86 | let enabled_features = cbindgen::EnabledFeatures { |
| 87 | interpreter: true, |
| 88 | testing: true, |
| 89 | backend_qt: true, |
| 90 | backend_winit: true, |
| 91 | backend_winit_x11: false, |
| 92 | backend_winit_wayland: false, |
| 93 | backend_linuxkms: true, |
| 94 | backend_linuxkms_noseat: false, |
| 95 | renderer_femtovg: true, |
| 96 | renderer_skia: true, |
| 97 | renderer_skia_opengl: false, |
| 98 | renderer_skia_vulkan: false, |
| 99 | renderer_software: true, |
| 100 | gettext: true, |
| 101 | accessibility: true, |
| 102 | system_testing: true, |
| 103 | freestanding: true, |
| 104 | experimental, |
| 105 | }; |
| 106 | cbindgen::gen_all(&root, &generated_headers_dir, enabled_features)?; |
| 107 | |
| 108 | let pip_env = vec![(OsString::from("PIPENV_PIPFILE" ), docs_source_dir.join("docs/Pipfile" ))]; |
| 109 | |
| 110 | println!("Generating third-party license list with cargo-about" ); |
| 111 | |
| 112 | let cargo_about_output = super::run_command( |
| 113 | "cargo" , |
| 114 | &[ |
| 115 | "about" , |
| 116 | "generate" , |
| 117 | "--manifest-path" , |
| 118 | "api/cpp/Cargo.toml" , |
| 119 | "api/cpp/docs/thirdparty.hbs" , |
| 120 | "-o" , |
| 121 | docs_build_dir.join("thirdparty.md" ).to_str().unwrap(), |
| 122 | ], |
| 123 | pip_env.clone(), |
| 124 | )?; |
| 125 | |
| 126 | println!( |
| 127 | " {}\n{}" , |
| 128 | String::from_utf8_lossy(&cargo_about_output.stdout), |
| 129 | String::from_utf8_lossy(&cargo_about_output.stderr) |
| 130 | ); |
| 131 | |
| 132 | println!("Running pipenv install" ); |
| 133 | |
| 134 | super::run_command("pipenv" , &["install" ], pip_env.clone()) |
| 135 | .context("Error running pipenv install" )?; |
| 136 | |
| 137 | println!("Running sphinx-build" ); |
| 138 | |
| 139 | let output = super::run_command( |
| 140 | "pipenv" , |
| 141 | &[ |
| 142 | "run" , |
| 143 | "sphinx-build" , |
| 144 | docs_build_dir.to_str().unwrap(), |
| 145 | docs_build_dir.join("html" ).to_str().unwrap(), |
| 146 | ], |
| 147 | pip_env, |
| 148 | ) |
| 149 | .context("Error running pipenv install" )?; |
| 150 | |
| 151 | println!(" {}" , String::from_utf8_lossy(&output.stdout)); |
| 152 | |
| 153 | if show_warnings { |
| 154 | println!(" {}" , String::from_utf8_lossy(&output.stderr)); |
| 155 | } |
| 156 | |
| 157 | Ok(()) |
| 158 | } |
| 159 | |