Skip to main content

canic_testkit/artifacts/
wasm.rs

1use super::workspace::prebuilt_wasm_dir;
2use std::{
3    fs,
4    path::{Path, PathBuf},
5    process::Command,
6};
7
8///
9/// WasmBuildProfile
10///
11
12#[derive(Clone, Copy, Debug, Eq, PartialEq)]
13pub enum WasmBuildProfile {
14    Debug,
15    Release,
16}
17
18impl WasmBuildProfile {
19    /// Return the Cargo profile flag for this build profile.
20    #[must_use]
21    pub const fn cargo_flag(self) -> Option<&'static str> {
22        match self {
23            Self::Debug => None,
24            Self::Release => Some("--release"),
25        }
26    }
27
28    /// Return the target-directory component for this build profile.
29    #[must_use]
30    pub const fn target_dir_name(self) -> &'static str {
31        match self {
32            Self::Debug => "debug",
33            Self::Release => "release",
34        }
35    }
36
37    /// Return the `RELEASE` environment value expected by `dfx`.
38    #[must_use]
39    pub const fn dfx_release_value(self) -> &'static str {
40        match self {
41            Self::Debug => "0",
42            Self::Release => "1",
43        }
44    }
45}
46
47/// Resolve the wasm artifact path for one crate under a target directory.
48#[must_use]
49pub fn wasm_path(
50    target_dir: &Path,
51    crate_name: &str,
52    profile: WasmBuildProfile,
53    prebuilt_env_var: &str,
54) -> PathBuf {
55    if let Some(dir) = prebuilt_wasm_dir(prebuilt_env_var) {
56        return dir.join(format!("{crate_name}.wasm"));
57    }
58
59    target_dir
60        .join("wasm32-unknown-unknown")
61        .join(profile.target_dir_name())
62        .join(format!("{crate_name}.wasm"))
63}
64
65/// Check whether all requested wasm artifacts already exist.
66#[must_use]
67pub fn wasm_artifacts_ready(
68    target_dir: &Path,
69    canisters: &[&str],
70    profile: WasmBuildProfile,
71    prebuilt_env_var: &str,
72) -> bool {
73    canisters
74        .iter()
75        .all(|name| wasm_path(target_dir, name, profile, prebuilt_env_var).is_file())
76}
77
78/// Read a compiled wasm artifact for one crate.
79#[must_use]
80pub fn read_wasm(
81    target_dir: &Path,
82    crate_name: &str,
83    profile: WasmBuildProfile,
84    prebuilt_env_var: &str,
85) -> Vec<u8> {
86    let path = wasm_path(target_dir, crate_name, profile, prebuilt_env_var);
87    fs::read(&path).unwrap_or_else(|err| panic!("failed to read {crate_name} wasm: {err}"))
88}
89
90/// Build one or more wasm canisters into the provided target directory.
91pub fn build_wasm_canisters(
92    workspace_root: &Path,
93    target_dir: &Path,
94    packages: &[&str],
95    profile: WasmBuildProfile,
96    extra_env: &[(&str, &str)],
97) {
98    let mut cmd = Command::new("cargo");
99    cmd.current_dir(workspace_root);
100    cmd.env("CARGO_TARGET_DIR", target_dir);
101    cmd.env("DFX_NETWORK", "local");
102    cmd.args(["build", "--target", "wasm32-unknown-unknown"]);
103
104    if let Some(flag) = profile.cargo_flag() {
105        cmd.arg(flag);
106    }
107
108    for (key, value) in extra_env {
109        cmd.env(key, value);
110    }
111
112    for name in packages {
113        cmd.args(["-p", name]);
114    }
115
116    let output = cmd.output().expect("failed to run cargo build");
117    assert!(
118        output.status.success(),
119        "cargo build failed: {}",
120        String::from_utf8_lossy(&output.stderr)
121    );
122}