99 lines
3.2 KiB
Rust
99 lines
3.2 KiB
Rust
use std::{
|
|
env, fs,
|
|
path::{Path, PathBuf},
|
|
};
|
|
|
|
const FNV_OFFSET: u64 = 0xcbf29ce484222325;
|
|
const FNV_PRIME: u64 = 0x100000001b3;
|
|
|
|
fn hash_bytes(mut hash: u64, bytes: &[u8]) -> u64 {
|
|
for byte in bytes {
|
|
hash ^= u64::from(*byte);
|
|
hash = hash.wrapping_mul(FNV_PRIME);
|
|
}
|
|
hash
|
|
}
|
|
|
|
fn collect_files(root: &Path, dir: &Path, files: &mut Vec<PathBuf>) {
|
|
let mut entries = fs::read_dir(dir)
|
|
.unwrap_or_else(|error| panic!("failed to read {}: {error}", dir.display()))
|
|
.filter_map(Result::ok)
|
|
.map(|entry| entry.path())
|
|
.collect::<Vec<_>>();
|
|
entries.sort();
|
|
for path in entries {
|
|
if path.is_dir() {
|
|
collect_files(root, &path, files);
|
|
} else if path.is_file() {
|
|
println!(
|
|
"cargo:rerun-if-changed={}",
|
|
path.strip_prefix(root).unwrap_or(&path).display()
|
|
);
|
|
files.push(path);
|
|
}
|
|
}
|
|
}
|
|
|
|
fn asset_version(manifest_dir: &Path) -> String {
|
|
let mut files = Vec::new();
|
|
collect_files(manifest_dir, &manifest_dir.join("static"), &mut files);
|
|
collect_files(manifest_dir, &manifest_dir.join("lang"), &mut files);
|
|
files.sort();
|
|
|
|
let mut hash = FNV_OFFSET;
|
|
for path in files {
|
|
let relative = path.strip_prefix(manifest_dir).unwrap_or(&path);
|
|
hash = hash_bytes(hash, relative.to_string_lossy().as_bytes());
|
|
hash = hash_bytes(hash, &[0]);
|
|
let bytes = fs::read(&path)
|
|
.unwrap_or_else(|error| panic!("failed to read {}: {error}", path.display()));
|
|
hash = hash_bytes(hash, &bytes);
|
|
hash = hash_bytes(hash, &[0xff]);
|
|
}
|
|
format!(
|
|
"{}-{hash:016x}",
|
|
env::var("CARGO_PKG_VERSION").expect("CARGO_PKG_VERSION")
|
|
)
|
|
}
|
|
|
|
fn main() {
|
|
println!("cargo:rerun-if-changed=lang");
|
|
println!("cargo:rerun-if-changed=static");
|
|
|
|
let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR"));
|
|
let lang_dir = manifest_dir.join("lang");
|
|
let mut files = fs::read_dir(&lang_dir)
|
|
.unwrap_or_else(|error| panic!("failed to read {}: {error}", lang_dir.display()))
|
|
.filter_map(Result::ok)
|
|
.map(|entry| entry.path())
|
|
.filter(|path| path.extension().and_then(|value| value.to_str()) == Some("json"))
|
|
.collect::<Vec<_>>();
|
|
files.sort();
|
|
|
|
if files.is_empty() {
|
|
panic!("lang directory must contain at least one .json language file");
|
|
}
|
|
|
|
let mut generated = String::from("pub const EMBEDDED_LANGUAGE_FILES: &[(&str, &str)] = &[\n");
|
|
for path in files {
|
|
let name = path
|
|
.file_name()
|
|
.and_then(|value| value.to_str())
|
|
.expect("language filename must be valid UTF-8");
|
|
println!("cargo:rerun-if-changed=lang/{name}");
|
|
generated.push_str(&format!(
|
|
" ({name:?}, include_str!(concat!(env!(\"CARGO_MANIFEST_DIR\"), \"/lang/{name}\"))),\n"
|
|
));
|
|
}
|
|
generated.push_str("];\n");
|
|
|
|
let out_dir = PathBuf::from(env::var("OUT_DIR").expect("OUT_DIR"));
|
|
fs::write(out_dir.join("languages.rs"), generated)
|
|
.expect("failed to generate embedded languages");
|
|
|
|
println!(
|
|
"cargo:rustc-env=RUSTPAD_ASSET_VERSION={}",
|
|
asset_version(&manifest_dir)
|
|
);
|
|
}
|