about summary refs log tree commit diff
path: root/build.rs
blob: 417f61cf1ac94b1d3f912da4053f9ae43c0809db (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
use std::{
  env, fs,
  io::Write,
  path::{Path, PathBuf},
};

const IGNORE_DIRS: &[&str] = &[];

const IGNORE_FILES: &[&str] = &["main.lua"];

fn main() {
  let crate_root = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
  let lua_src = crate_root.join("lua_src");
  let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
  let out_file = out_dir.join("bundled_modules.rs");

  println!("cargo:rerun-if-changed=lua_src");

  let mut entries: Vec<(String, String)> = Vec::new();
  collect(&lua_src, &lua_src, &mut entries);

  // Files are sorted alphabetically here to make output deterministic
  entries.sort_by(|a, b| a.0.cmp(&b.0));

  let mut out = match fs::File::create(&out_file) {
    Ok(f) => f,
    Err(e) => {
      eprintln!(
        "ERROR: could not write to '{}': {e}",
        out_file.display()
      );
      std::process::exit(1);
    }
  };

  writeln!(out, "// AUTO-GENERATED by build.rs").unwrap();
  writeln!(out, "pub const BUNDLED_MODULES: &[(&str, &str)] = &[").unwrap();

  for (module_name, rel_path) in &entries {
    writeln!(
            out,
            r#"    ("{module_name}", include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/lua_src/{rel_path}"))),"#
        ).unwrap();
  }

  writeln!(out, "];").unwrap();

  eprintln!("INFORMATION: Bundled {} Lua module(s)", entries.len());
  for (name, path) in &entries {
    eprintln!("               {name:30} ← lua_src/{path}");
  }
}

fn collect(root: &Path, dir: &Path, out: &mut Vec<(String, String)>) {
  let entries = match fs::read_dir(dir) {
    Ok(e) => e,
    Err(e) => {
      eprintln!("ERROR: could not read '{}': {e}", dir.display());
      return;
    }
  };

  for entry in entries.flatten() {
    let path = entry.path();
    let file_name = path.file_name().unwrap().to_string_lossy();

    if path.is_dir() {
      if IGNORE_DIRS.contains(&file_name.as_ref()) {
        eprintln!("INFORMATION: skipping directory lua_src/{file_name}/");
        continue;
      }
      collect(root, &path, out);
      continue;
    }

    if path.extension().and_then(|e| e.to_str()) != Some("lua") {
      continue;
    }

    let rel = path.strip_prefix(root).unwrap();
    let rel_str = rel.to_string_lossy();

    if IGNORE_FILES.contains(&rel_str.as_ref()) {
      eprintln!("INFORMATION: skipping file 'lua_src/{rel_str}'");
      continue;
    }

    let module_name = rel
      .with_extension("")
      .components()
      .map(|c| c.as_os_str().to_string_lossy())
      .collect::<Vec<_>>()
      .join(".");

    out.push((module_name, rel_str.replace('\\', "/")));
  }
}