1use colored::Colorize;
2use std::collections::HashMap;
3use std::io::Write;
4use std::io::{BufRead, BufReader};
5use std::path::Path;
6use std::process::{Command, Stdio};
7use std::{env, io};
8
9use crate::errors::BeautifulErrors;
10use crate::npm_process::NpmProcessContext;
11
12fn handle_process_stdout(process_name: &String, msg: &str) {
13 if msg.len() > 0 {
14 print!("{}: {}", process_name.blue().bold(), msg);
15 io::stdout().flush().expect("Could not flush stdout");
16 }
17}
18
19pub fn start_npm_process(context: NpmProcessContext) {
20 let path = Path::new(&context.dir);
21 let mut root_env: HashMap<String, String> = env::vars().collect();
22
23 if let Some(envs) = context.args.env {
24 envs.iter().for_each(|var| {
25 let key_value: Vec<&str> = var.split(":").collect();
26 let key = key_value.get(0).expect_or_err(
27 &format!("Invalid environment variable provided: {} - Usage: hammer dev -e node_env:development", var)
28 );
29
30 let val = key_value.get(1).expect_or_err(
31 &format!("Invalid environment variable provided: {} - Usage: hammer dev -e node_env:development", var)
32 );
33
34 root_env.insert(key.to_string(), val.to_string());
35 });
36 }
37 let mut child = Command::new("npm")
38 .current_dir(path)
39 .envs(&root_env)
40 .arg("run")
41 .arg(context.args.script)
42 .stdout(Stdio::piped())
43 .spawn()
44 .expect(&format!(
45 "Could not start child process on directory {}",
46 path.display()
47 ));
48
49 tokio::spawn(async move {
50 let mut f = BufReader::new(
51 child
52 .stdout
53 .take()
54 .expect("Could not retrieve child std output"),
55 );
56 loop {
57 let mut buf = String::new();
58 match f.read_line(&mut buf) {
59 Ok(_) => {
60 handle_process_stdout(&context.name, buf.as_str());
61 }
62 Err(e) => println!("child err: {:?}", e),
63 }
64 if let Ok(status) = child.try_wait() {
65 if let Some(_status) = status {
66 break;
67 }
68 }
69 }
70 });
71}