// Build script for Subplot, locates and builds the embedded resource set from // the share directory use anyhow::Result; use std::io::Write; use std::path::{Component, Path, PathBuf}; use walkdir::WalkDir; fn path_ignore(path: &Path) -> bool { // We have a number of rules for ignoring any given path. path.components().any(|component| { match component { Component::Prefix(_) => true, Component::RootDir => true, Component::CurDir => true, Component::ParentDir => true, Component::Normal(part) => { if let Some(part) = part.to_str() { // We don't want dot files, tilde files, bak files // or the python cache. Add other things here if // there's stuff ending up in the resources tree // which we don't want. part.starts_with('.') || part.ends_with('~') || part.ends_with(".bak") || part == "__pycache__" } else { // We don't want any non-unicode paths true } } } }) } fn gather_share_files() -> Result> { let base_path = Path::new(env!("CARGO_MANIFEST_DIR")).join("share"); println!("cargo:rerun-if-changed={}", base_path.display()); let mut ret = Vec::new(); for entry in WalkDir::new(&base_path) { let entry = entry?; let entry_path = entry.path().strip_prefix(&base_path)?; if entry_path.components().count() == 0 || path_ignore(entry_path) { continue; } // If this path part is a directory, we want to watch it but we don't // represent directories in the resources tree if entry.file_type().is_dir() { println!("cargo:rerun-if-changed={}", entry.path().display()); continue; } // If this is a symlink we need cargo to watch the target of the link // even though we'll treat it as a basic file when we embed it if entry.file_type().is_symlink() { let target = std::fs::read_link(entry.path())?; println!("cargo:rerun-if-changed={}", target.display()); } println!("cargo:rerun-if-changed={}", entry.path().display()); ret.push(entry_path.into()); } Ok(ret) } fn write_out_resource_file<'a>(paths: impl Iterator) -> Result<()> { let mut out_path: PathBuf = std::env::var("OUT_DIR")?.into(); out_path.push("embedded_files.inc"); let mut fh = std::fs::File::create(out_path)?; writeln!(fh, "&[")?; for entry in paths { let sharepath = Path::new("/share").join(entry); writeln!( fh, r#"({:?}, include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), {:?}))),"#, entry.display(), sharepath.display() )?; } writeln!(fh, "]")?; fh.flush()?; Ok(()) } fn main() { println!("cargo:rerun-if-env-changed=DEB_BUILD_OPTIONS"); let paths = if std::env::var("DEB_BUILD_OPTIONS").is_err() { println!("cargo:rustc-env=FALLBACK_PATH="); gather_share_files().expect("Unable to scan the share tree") } else { println!("cargo:rustc-env=FALLBACK_PATH=/usr/share/subplot"); vec![] }; write_out_resource_file(paths.iter().map(PathBuf::as_path)) .expect("Unable to write the resource file out"); }