mirror of
https://github.com/NLnetLabs/krill.git
synced 2026-08-17 21:25:53 +02:00
176 lines
4.5 KiB
Rust
176 lines
4.5 KiB
Rust
//! Build script.
|
|
//!
|
|
//! This script collects the assets for serving the Krill UI and creates
|
|
//! a module for them in `$OUT_DIR/ui_assets.rs`.
|
|
use std::{env, fmt, fs, io, process};
|
|
use std::path::{PathBuf, Path};
|
|
|
|
const UI_DIR: &str = "ui";
|
|
const INDEX_PATH: &str = "ui/index.html";
|
|
const ASSETS_DIR: &str = "ui/assets";
|
|
const RS_FILE: &str = "ui_assets.rs";
|
|
|
|
const TYPES: &[(&str, &str)] = &[
|
|
("css", "text/css"),
|
|
("html", "text/html"),
|
|
("ico", "image/x-icon"),
|
|
("js", "text/javascript"),
|
|
("svg", "image/svg+xml"),
|
|
("woff", "font/woff"),
|
|
("woff2", "font/woff2"),
|
|
];
|
|
|
|
struct Asset {
|
|
path: PathBuf,
|
|
media_type: &'static str,
|
|
content: Vec<u8>,
|
|
}
|
|
|
|
impl Asset {
|
|
fn load(path: PathBuf, asset: bool) -> Result<Self, String> {
|
|
let path_ext = match path.extension().and_then(|s| s.to_str()) {
|
|
Some(ext) => ext,
|
|
None => {
|
|
return Err(format!(
|
|
"Asset without extension: '{}'", path.display()
|
|
))
|
|
}
|
|
};
|
|
|
|
let media_type = match TYPES.iter().find_map(|(ext, media_type)| {
|
|
(path_ext == *ext).then_some(*media_type)
|
|
}) {
|
|
Some(media) => media,
|
|
None => {
|
|
return Err(format!(
|
|
"Asset with unknown extension '{path_ext}'"
|
|
))
|
|
}
|
|
};
|
|
|
|
Ok(Self {
|
|
path: if asset {
|
|
path.strip_prefix(ASSETS_DIR).map_err(|_| {
|
|
format!("Asset path {} not under {}",
|
|
path.display(), ASSETS_DIR
|
|
)
|
|
})?.into()
|
|
}
|
|
else {
|
|
INDEX_PATH.into()
|
|
},
|
|
media_type,
|
|
content: fs::read(&path).map_err(|err| {
|
|
format!(
|
|
"Failed to read UI asset file {}: {}.",
|
|
path.display(), err
|
|
)
|
|
})?
|
|
})
|
|
}
|
|
}
|
|
|
|
impl fmt::Display for Asset {
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
write!(f,
|
|
"
|
|
Asset {{
|
|
path: r#\"{}\"#,
|
|
media_type: \"{}\",
|
|
content: &{:?},
|
|
}}
|
|
",
|
|
self.path.display(),
|
|
self.media_type,
|
|
self.content.as_slice(),
|
|
)
|
|
}
|
|
}
|
|
|
|
|
|
#[derive(Default)]
|
|
struct Assets(Vec<Asset>);
|
|
|
|
impl Assets {
|
|
fn load_dir(&mut self, path: PathBuf) -> Result<(), String> {
|
|
let dir = fs::read_dir(&path).map_err(|err| {
|
|
format!("Failed to open directory {}: {}", path.display(), err)
|
|
})?;
|
|
for entry in dir {
|
|
let entry = entry.map_err(|err| {
|
|
format!("Failed to read directory {}: {}", path.display(), err)
|
|
})?;
|
|
let path = entry.path();
|
|
if path.is_dir() {
|
|
self.load_dir(path)?;
|
|
}
|
|
else {
|
|
self.0.push(Asset::load(path, true)?)
|
|
}
|
|
}
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
|
|
fn write_mod(
|
|
index: Asset, assets: Assets, dest: &mut impl io::Write
|
|
) -> Result<(), io::Error> {
|
|
write!(dest,
|
|
r#"
|
|
pub struct Asset {{
|
|
pub path: &'static str,
|
|
pub media_type: &'static str,
|
|
pub content: &'static [u8],
|
|
}}
|
|
|
|
pub static INDEX: Asset = {index};
|
|
|
|
pub static ASSETS: &[Asset] = &[
|
|
"#
|
|
)?;
|
|
for item in assets.0 {
|
|
write!(dest, "{item},")?;
|
|
}
|
|
writeln!(dest, "];")
|
|
}
|
|
|
|
|
|
fn main() {
|
|
let out_dir = env::var_os("OUT_DIR").unwrap_or_default();
|
|
let target_path = Path::new(&out_dir).join(RS_FILE);
|
|
let mut target = match fs::File::create(&target_path) {
|
|
Ok(target) => io::BufWriter::new(target),
|
|
Err(err) => {
|
|
eprintln!("Failed to open assets module file {}: {}",
|
|
target_path.display(), err
|
|
);
|
|
process::exit(1);
|
|
}
|
|
};
|
|
|
|
let index = match Asset::load(INDEX_PATH.into(), false) {
|
|
Ok(index) => index,
|
|
Err(err) => {
|
|
eprintln!("{err}");
|
|
process::exit(1);
|
|
}
|
|
};
|
|
|
|
let mut assets = Assets::default();
|
|
if let Err(err) = assets.load_dir(ASSETS_DIR.into()) {
|
|
eprintln!("{err}");
|
|
process::exit(1);
|
|
}
|
|
|
|
if let Err(err) = write_mod(index, assets, &mut target) {
|
|
eprintln!("Failed to write to assets module file {}: {}",
|
|
target_path.display(), err
|
|
);
|
|
process::exit(1)
|
|
}
|
|
|
|
println!("cargo:rerun-if-changed={UI_DIR}");
|
|
}
|
|
|