104 lines
4.2 KiB
Rust
104 lines
4.2 KiB
Rust
use std::{
|
|
env, fs,
|
|
path::{Path, PathBuf},
|
|
};
|
|
|
|
fn content_hash(content: &str) -> String {
|
|
let value = content.bytes().fold(0xcbf29ce484222325_u64, |hash, byte| {
|
|
(hash ^ u64::from(byte)).wrapping_mul(0x100000001b3)
|
|
});
|
|
format!("{value:016x}")
|
|
}
|
|
|
|
fn write_asset(output: &Path, stem: &str, extension: &str, content: &str) -> String {
|
|
let file_name = format!("{stem}.{}.{extension}", content_hash(content));
|
|
fs::write(output.join(&file_name), content)
|
|
.unwrap_or_else(|error| panic!("write {file_name}: {error}"));
|
|
file_name
|
|
}
|
|
|
|
fn cargo_asset_env(name: &str, file_name: &str) {
|
|
println!("cargo:rustc-env={name}_FILE={file_name}");
|
|
println!("cargo:rustc-env={name}_ROUTE=/assets/{file_name}");
|
|
}
|
|
|
|
fn main() {
|
|
let output = PathBuf::from(env::var_os("OUT_DIR").expect("OUT_DIR"));
|
|
println!("cargo:rerun-if-changed=build.rs");
|
|
println!("cargo:rerun-if-changed=web");
|
|
println!("cargo:rerun-if-changed=docs/api-ui");
|
|
println!("cargo:rerun-if-changed=vendor/swagger-ui/swagger-ui-bundle.js");
|
|
println!("cargo:rerun-if-changed=vendor/swagger-ui/swagger-ui.css");
|
|
|
|
if let Ok(entries) = fs::read_dir(&output) {
|
|
for entry in entries.flatten() {
|
|
let name = entry.file_name();
|
|
let name = name.to_string_lossy();
|
|
let generated_asset = (name.starts_with("app.") || name.starts_with("docs."))
|
|
&& (name.ends_with(".js") || name.ends_with(".css"));
|
|
if generated_asset {
|
|
let _ = fs::remove_file(entry.path());
|
|
}
|
|
}
|
|
}
|
|
|
|
let manifest = fs::read_to_string("web/assets.list").expect("web/assets.list is required");
|
|
let mut js =
|
|
String::from("/* MikroTik Backup System 0.0.1; generated from web/assets.list */\n");
|
|
let mut css = String::new();
|
|
for entry in manifest
|
|
.lines()
|
|
.map(str::trim)
|
|
.filter(|value| !value.is_empty() && !value.starts_with('#'))
|
|
{
|
|
let source = fs::read_to_string(PathBuf::from("web").join(entry))
|
|
.unwrap_or_else(|error| panic!("{entry}: {error}"));
|
|
if entry.ends_with(".js") {
|
|
js.push_str(&source);
|
|
js.push_str("\n;\n");
|
|
} else if entry.ends_with(".css") {
|
|
css.push_str(&source);
|
|
css.push('\n');
|
|
} else {
|
|
panic!("Unsupported bundle input: {entry}");
|
|
}
|
|
}
|
|
|
|
let app_js_file = write_asset(&output, "app", "js", &js);
|
|
let app_css_file = write_asset(&output, "app", "css", &css);
|
|
cargo_asset_env("APP_JS", &app_js_file);
|
|
cargo_asset_env("APP_CSS", &app_css_file);
|
|
|
|
let html = fs::read_to_string("web/index.html")
|
|
.expect("web/index.html is required")
|
|
.replace("/assets/app.js", &format!("/assets/{app_js_file}"))
|
|
.replace("/assets/app.css", &format!("/assets/{app_css_file}"));
|
|
fs::write(output.join("index.html"), html).expect("write HTML shell");
|
|
|
|
let mut docs_js = fs::read_to_string("vendor/swagger-ui/swagger-ui-bundle.js")
|
|
.expect("Swagger UI JavaScript is required")
|
|
.lines()
|
|
.filter(|line| !line.starts_with("//# sourceMappingURL="))
|
|
.collect::<Vec<_>>()
|
|
.join("\n");
|
|
docs_js.push_str("\n;\n");
|
|
docs_js.push_str(&fs::read_to_string("docs/api-ui/init.js").expect("docs API initializer"));
|
|
|
|
let mut docs_css = fs::read_to_string("vendor/swagger-ui/swagger-ui.css")
|
|
.expect("Swagger UI stylesheet is required")
|
|
.replace("/*# sourceMappingURL=swagger-ui.css.map*/", "");
|
|
docs_css.push('\n');
|
|
docs_css.push_str(&fs::read_to_string("docs/api-ui/style.css").expect("docs API stylesheet"));
|
|
|
|
let docs_js_file = write_asset(&output, "docs", "js", &docs_js);
|
|
let docs_css_file = write_asset(&output, "docs", "css", &docs_css);
|
|
cargo_asset_env("DOCS_JS", &docs_js_file);
|
|
cargo_asset_env("DOCS_CSS", &docs_css_file);
|
|
|
|
let docs_html = fs::read_to_string("docs/api-ui/index.html")
|
|
.expect("docs API HTML is required")
|
|
.replace("/assets/docs.js", &format!("/assets/{docs_js_file}"))
|
|
.replace("/assets/docs.css", &format!("/assets/{docs_css_file}"));
|
|
fs::write(output.join("docs.html"), docs_html).expect("write API documentation HTML");
|
|
}
|