Skip to main content

memory_serve/build/
mod.rs

1use std::path::PathBuf;
2
3use fs_err as fs;
4
5mod code;
6mod file_asset;
7mod list;
8
9const ASSET_FILE: &str = "memory_serve_assets.rs";
10const QUIET_ENV_NAME: &str = "MEMORY_SERVE_QUIET";
11
12pub use code::assets_to_code;
13
14/// Load a directory of assets, keeping an administration of all files
15/// and optionally embedding them into the binary
16pub fn load_directory<P: Into<PathBuf>>(path: P) {
17    // determine whether to dynamically load assets or embed them in the binary
18    let embed = !cfg!(debug_assertions) || cfg!(feature = "force-embed");
19
20    load_directory_with_embed(path, embed);
21}
22
23/// Load a directory of assets, optionally embedding them into the binary
24pub fn load_directory_with_embed<P: Into<PathBuf>>(path: P, embed: bool) {
25    load_names_directories(vec![("default", path)], embed);
26}
27
28/// Load multiple named directories of assets, optionally embedding them into the binary
29pub fn load_names_directories<N, P>(named_paths: impl IntoIterator<Item = (N, P)>, embed: bool)
30where
31    N: Into<String>,
32    P: Into<PathBuf>,
33{
34    let out_dir: PathBuf = std::env::var("OUT_DIR")
35        .expect("OUT_DIR environment variable not set, make sure you call this from a build.rs")
36        .into();
37
38    println!("cargo::rerun-if-env-changed={QUIET_ENV_NAME}");
39    fn log(msg: &str) {
40        if std::env::var(QUIET_ENV_NAME) != Ok("1".to_string()) {
41            println!("cargo:warning={}", msg);
42        }
43    }
44
45    // using a string is faster than using quote ;)
46    let mut code = "&[".to_string();
47
48    for (name, asset_dir) in named_paths {
49        let asset_dir =
50            fs::canonicalize(asset_dir.into()).expect("Could not canonicalize the provided path");
51        let asset_dir_label = asset_dir.to_string_lossy();
52        let assets = code::assets_to_code(&asset_dir_label, &asset_dir, &out_dir, embed, log);
53
54        println!("cargo::rerun-if-changed={asset_dir_label}");
55
56        code = format!("{code}(\"{}\", {assets}),", name.into());
57    }
58
59    code.push(']');
60
61    let target = out_dir.join(ASSET_FILE);
62
63    fs::write(target, code).expect("Unable to write memory-serve asset file.");
64}
65
66#[cfg(test)]
67/// Load assets directly from disk for use in integration tests.
68pub(super) fn load_test_assets<P: Into<PathBuf>>(path: P) -> &'static [crate::Asset] {
69    fn log(msg: &str) {
70        println!("{}", msg);
71    }
72
73    let embed = !cfg!(debug_assertions) || cfg!(feature = "force-embed");
74    let assets = list::list_assets(&path.into(), embed, log);
75
76    let assets = assets
77        .into_iter()
78        .map(|fa| crate::Asset {
79            route: fa.route.leak(),
80            is_compressed: fa.compressed_bytes.is_some(),
81            path: fa.path.to_string_lossy().to_string().leak(),
82            etag: fa.etag.leak(),
83            content_type: fa.content_type.leak(),
84            bytes: fa.compressed_bytes.map(|v| {
85                let s: &'static [u8] = v.leak();
86
87                s
88            }),
89            should_compress: fa.should_compress,
90        })
91        .collect::<Vec<_>>();
92
93    Box::leak(assets.into_boxed_slice())
94}