Skip to main content

idt/downloaders/
npm.rs

1use std::path::Path;
2use std::path::PathBuf;
3
4use rootcause::prelude::ResultExt as _;
5
6/// Downloads and installs Node.js packages using npm.
7///
8/// # Errors
9/// - Executing the `npm` command fails or returns a non-zero exit status.
10/// - A filesystem operation (create/read/write/remove) fails.
11pub fn run(dev_tools_dir: &Path, tool: &str, packages: &[&str]) -> rootcause::Result<PathBuf> {
12    let dev_tools_repo_dir = dev_tools_dir.join(tool);
13
14    std::fs::create_dir_all(&dev_tools_repo_dir)
15        .context("error creating npm tool directory")
16        .attach_with(|| format!("path={}", dev_tools_repo_dir.display()))?;
17
18    let mut cmd_args = vec!["install"];
19    if cfg!(debug_assertions) {
20        cmd_args.push("--silent");
21    }
22    let dev_tools_repo_dir_bind = dev_tools_repo_dir.to_string_lossy();
23    cmd_args.extend_from_slice(&["--prefix", &dev_tools_repo_dir_bind]);
24    cmd_args.extend_from_slice(packages);
25
26    ytil_cmd::silent_cmd("npm")
27        .args(cmd_args)
28        .status()
29        .context("failed to spawn npm")?
30        .exit_ok()
31        .context("npm install failed")
32        .attach_with(|| format!("tool={tool}"))
33        .attach_with(|| format!("packages={packages:?}"))?;
34
35    Ok(dev_tools_repo_dir.join("node_modules").join(".bin"))
36}