build_helper/
npm.rs

1use std::error::Error;
2use std::path::{Path, PathBuf};
3use std::process::Command;
4use std::{fs, io};
5
6use crate::ci::CiEnv;
7
8/// Install all the npm deps, and return the path of `node_modules`.
9pub fn install(src_root_path: &Path, out_dir: &Path, npm: &Path) -> Result<PathBuf, io::Error> {
10    let nm_path = out_dir.join("node_modules");
11    let copy_to_build = |p| {
12        fs::copy(src_root_path.join(p), out_dir.join(p)).map_err(|e| {
13            eprintln!("unable to copy {p:?} to build directory: {e:?}");
14            e
15        })
16    };
17    // copy stuff to the output directory to make node_modules get put there.
18    copy_to_build("package.json")?;
19    copy_to_build("package-lock.json")?;
20
21    let mut cmd = Command::new(npm);
22    if CiEnv::is_ci() {
23        // `npm ci` redownloads every time and thus is too slow for local development.
24        cmd.arg("ci");
25    } else {
26        cmd.arg("install");
27    }
28    // disable a bunch of things we don't want.
29    // this makes tidy output less noisy, and also significantly improves runtime
30    // of repeated tidy invokations.
31    cmd.args(&["--audit=false", "--save=false", "--fund=false"]);
32    cmd.current_dir(out_dir);
33    let exit_status = cmd.spawn()?.wait()?;
34    if !exit_status.success() {
35        eprintln!("npm install did not exit successfully");
36        return Err(io::Error::other(Box::<dyn Error + Send + Sync>::from(format!(
37            "npm install returned exit code {exit_status}"
38        ))));
39    }
40    Ok(nm_path)
41}