oseda_cli/cmd/
run.rs

1use std::{error::Error, process::Command, sync::mpsc};
2
3#[derive(Debug)]
4pub enum OsedaRunError {
5    BuildError(String),
6    ServeError(String),
7}
8
9impl std::error::Error for OsedaRunError {}
10impl std::fmt::Display for OsedaRunError {
11    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
12        match self {
13            Self::BuildError(msg) => write!(f, "Oseda Build Error: {}", msg),
14            Self::ServeError(msg) => write!(f, "Oseda Serve Error: {}", msg),
15        }
16    }
17}
18
19pub fn run() -> Result<(), OsedaRunError> {
20    // command run failure and command status are considered different, handled accordingly
21    match Command::new("npx").arg("vite").arg("build").status() {
22        Ok(status) => {
23            if !status.success() {
24                println!("Error: `npx vite build` exited with a failure.");
25                println!("Please ensure that npx and vite are installed properly.");
26                return Err(OsedaRunError::BuildError(
27                    "could not 'npx vite build'".to_string(),
28                ));
29            }
30        }
31        Err(e) => {
32            println!("Error: failed to execute `npx vite build`: {e}");
33            println!("Please ensure that `npx` and `vite` are installed and in your PATH.");
34            return Err(OsedaRunError::BuildError(
35                "could not 'npx vite build'".to_string(),
36            ));
37        }
38    }
39
40    let mut child = Command::new("serve").arg("dist").spawn().map_err(|e| {
41        println!("Error starting `serve dist`: {e}");
42        OsedaRunError::ServeError("failed to start serve".into())
43    })?;
44    // spawn will leave child running the background. Need to listen for ctrl+c, snatch it. Then kill subprocess
45
46    // https://github.com/Detegr/rust-ctrlc
47    let (tx, rx) = mpsc::channel();
48    ctrlc::set_handler(move || {
49        println!("\nSIGINT received. Attempting graceful shutdown...");
50        let _ = tx.send(());
51    })
52    .expect("Error setting Ctrl+C handler");
53
54    // block until ctrl+c
55    rx.recv().unwrap();
56
57    // attempt to kill the child process
58    if let Err(e) = child.kill() {
59        println!("Failed to kill `serve`: {e}");
60    } else {
61        println!("`serve` process terminated.");
62    }
63
64    let _ = child.wait();
65
66    Ok(())
67}