Skip to main content

ic_testkit/artifacts/
wasm.rs

1use std::{
2    fs,
3    path::{Path, PathBuf},
4};
5
6use super::wasm_cache::{WasmBuildSpec, build_wasm_canisters_cached};
7
8/// Resolve one crate's Wasm artifact under a caller-selected Cargo target directory.
9#[must_use]
10pub fn wasm_path(target_dir: &Path, crate_name: &str, profile_target_dir: &str) -> PathBuf {
11    target_dir
12        .join("wasm32-unknown-unknown")
13        .join(profile_target_dir)
14        .join(format!("{crate_name}.wasm"))
15}
16
17/// Check whether every requested Wasm artifact is a regular file.
18#[must_use]
19pub fn wasm_artifacts_ready(
20    target_dir: &Path,
21    canisters: &[&str],
22    profile_target_dir: &str,
23) -> bool {
24    canisters
25        .iter()
26        .all(|name| wasm_path(target_dir, name, profile_target_dir).is_file())
27}
28
29/// Read a compiled Wasm artifact for one crate.
30///
31/// # Panics
32///
33/// Panics with the crate name when the artifact cannot be read.
34#[must_use]
35pub fn read_wasm(target_dir: &Path, crate_name: &str, profile_target_dir: &str) -> Vec<u8> {
36    let path = wasm_path(target_dir, crate_name, profile_target_dir);
37    fs::read(&path).unwrap_or_else(|err| panic!("failed to read {crate_name} wasm: {err}"))
38}
39
40/// Build one or more Wasm canisters into the provided target directory.
41///
42/// `cargo_profile_args` accepts Cargo flags such as `--release`. `extra_env`
43/// applies only to the child Cargo process and does not mutate the current
44/// process environment.
45///
46/// # Panics
47///
48/// Panics when Cargo cannot be launched or returns a failing status.
49pub fn build_wasm_canisters(
50    workspace_root: &Path,
51    target_dir: &Path,
52    packages: &[&str],
53    cargo_profile_args: &[&str],
54    extra_env: &[(&str, &str)],
55) {
56    let profile_target_dir = profile_target_dir(cargo_profile_args);
57    let spec = WasmBuildSpec::new(workspace_root, target_dir, packages, &profile_target_dir)
58        .with_cargo_profile_args(cargo_profile_args)
59        .with_extra_env(extra_env);
60    build_wasm_canisters_cached(&spec)
61        .unwrap_or_else(|error| panic!("cargo Wasm build failed: {error}"));
62}
63
64fn profile_target_dir(cargo_profile_args: &[&str]) -> String {
65    let mut profile = "debug";
66    let mut args = cargo_profile_args.iter().copied();
67    while let Some(argument) = args.next() {
68        match argument {
69            "--release" => profile = "release",
70            "--profile" => {
71                if let Some(value) = args.next() {
72                    profile = value;
73                }
74            }
75            _ => {
76                if let Some(value) = argument.strip_prefix("--profile=") {
77                    profile = value;
78                }
79            }
80        }
81    }
82    profile.to_owned()
83}
84
85#[cfg(test)]
86mod tests {
87    use super::profile_target_dir;
88
89    #[test]
90    fn profile_target_directory_follows_cargo_arguments() {
91        assert_eq!(profile_target_dir(&[]), "debug");
92        assert_eq!(profile_target_dir(&["--release"]), "release");
93        assert_eq!(profile_target_dir(&["--profile", "fast"]), "fast");
94        assert_eq!(profile_target_dir(&["--profile=small"]), "small");
95    }
96}