Files
Martin Hoffmann 5b7d38526b Import and switch to new UI. (#952)
This PR switches to using version 0.4.0 of the Routinator UI. It also changes
the way we import the UI into Routinator by simply including the built assets
in the contrib/ui directory and updating them if necessary.

The PR also imports the mechanism to collect assets and provide them to the
HTTP server from the now deprecated routinator-ui crate.
2024-05-01 14:58:41 +02:00

135 lines
3.9 KiB
Rust

//! Build script.
//!
//! This script collects the assets for serving the Routinator UI and creates
//! a module for them in `$OUT_DIR/ui_assets.rs`.
//!
//! If built without the ui feature, does nothing.
use std::{env, fs, io, process};
use std::path::{PathBuf, Path};
const UI_DIR: &str = "contrib/ui";
const RS_FILE: &str = "ui_assets.rs";
const TYPES: &[(&str, &str)] = &[
("css", "text/css"),
("html", "text/html"),
("js", "text/javascript"),
("svg", "image/svg+xml")
];
struct Asset {
path: PathBuf,
media_type: &'static str,
content: Vec<u8>,
}
#[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 {
let path_ext = match path.extension().and_then(|s| s.to_str()) {
Some(ext) => ext,
None => continue,
};
for (type_ext, media_type) in TYPES {
if path_ext == *type_ext {
self.0.push(Asset {
path: path.strip_prefix(UI_DIR).map_err(|_| {
format!("Asset path {} not under {}",
path.display(), UI_DIR
)
})?.into(),
media_type,
content: fs::read(&path).map_err(|err| {
format!(
"Failed to read UI asset file {}: {}.",
path.display(), err
)
})?
})
}
}
}
}
Ok(())
}
fn write_mod(self, dest: &mut impl io::Write) -> Result<(), io::Error> {
dest.write_all(
r#"
pub struct Asset {
pub path: &'static str,
pub media_type: &'static str,
pub content: &'static [u8],
}
pub static ASSETS: &[Asset] = &[
"#.as_ref()
)?;
for item in self.0 {
writeln!(dest,
"
Asset {{
path: r#\"{}\"#,
media_type: \"{}\",
content: &{:?},
}},
",
item.path.display(),
item.media_type,
item.content.as_slice(),
)?;
}
writeln!(dest, "];")
}
}
fn main() {
if env::var_os("CARGO_FEATURE_UI").is_none() {
return
}
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 mut assets = Assets::default();
if let Err(err) = assets.load_dir(UI_DIR.into()) {
eprintln!("{}", err);
process::exit(1);
}
if let Err(err) = assets.write_mod(&mut target) {
eprintln!("Failed to write to assets module file {}: {}",
target_path.display(), err
);
process::exit(1)
}
println!("cargo:rerun-if-changed={}", UI_DIR);
}