clankers-cli 0.1.6

Command-line interface for clankeRS
Documentation
use std::env;
use std::fs;
use std::path::{Path, PathBuf};

// Generates OUT_DIR/templates_gen.rs: a static table embedding every bundled
// template file into the binary via include_str!. Embedding (rather than
// copying to OUT_DIR) is what keeps `clankers new` working after
// `cargo install`, where the build directory is deleted.
//
// Template manifests are stored as `Cargo.toml.tmpl` because `cargo package`
// silently excludes any directory containing a `Cargo.toml` (nested-package
// rule); the table maps them back to their real destination name.
fn main() {
    let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
    let templates = manifest_dir.join("templates");
    assert!(
        templates.is_dir(),
        "templates/ must ship inside the clankers-cli package (missing at {})",
        templates.display()
    );

    let mut entries = Vec::new();
    collect(&templates, &templates, &mut entries);
    entries.sort();
    assert!(
        entries.iter().any(|e| e.ends_with("Cargo.toml.tmpl")),
        "no template manifests found under {}",
        templates.display()
    );

    let mut out = String::from(
        "/// (destination path, contents) for every bundled template file.\n\
         pub static TEMPLATE_FILES: &[(&str, &str)] = &[\n",
    );
    for rel in &entries {
        let dest = rel.strip_suffix(".tmpl").unwrap_or(rel);
        let abs = templates.join(rel);
        out.push_str(&format!(
            "    ({:?}, include_str!({:?})),\n",
            dest,
            abs.display().to_string()
        ));
    }
    out.push_str("];\n");

    let out_path = Path::new(&env::var("OUT_DIR").unwrap()).join("templates_gen.rs");
    fs::write(&out_path, out).unwrap();
    println!("cargo:rerun-if-changed={}", templates.display());
}

fn collect(root: &Path, dir: &Path, entries: &mut Vec<String>) {
    for entry in fs::read_dir(dir).unwrap() {
        let path = entry.unwrap().path();
        if path.is_dir() {
            collect(root, &path, entries);
        } else {
            entries.push(
                path.strip_prefix(root)
                    .unwrap()
                    .to_string_lossy()
                    .replace('\\', "/"),
            );
        }
    }
}