rustywatch/watch/
reload.rs

1use crate::{
2    config::schema::CommandType,
3    watch::{binary, command, command::buf_reader},
4};
5use binary::{exists, remove, restart};
6use command::exec;
7use log::{error, info};
8use std::process::Child;
9
10pub async fn reload(
11    running_binary: &mut Option<Child>,
12    cmd: &CommandType,
13    bin_path: Option<&String>,
14    bin_arg: Option<&Vec<String>>,
15) {
16    // @NOTE
17    // restart with killed old binary.
18    match running_binary {
19        Some(ref mut child) => match child.kill() {
20            Ok(_) => info!("Restarting..."),
21            Err(e) => error!("Failed to restart binary: {:?}", e.to_string()),
22        },
23        None => (),
24    }
25
26    // @NOTE
27    // execute bin_path with option:
28    // if not exists execute.
29    // then any skip, just execute command.
30    match bin_path {
31        Some(bin_path) => {
32            if remove(bin_path) {
33                if !exists(bin_path) {
34                    match cmd {
35                        CommandType::Single(cmd) => match exec(cmd.clone()).await {
36                            Ok(child) => buf_reader(child),
37                            Err(e) => {
38                                error!("Failed to run command: {}", e.to_string())
39                            }
40                        },
41                        CommandType::Multiple(cmds) => {
42                            for cmd in cmds {
43                                match exec(cmd.clone()).await {
44                                    Ok(child) => buf_reader(child),
45                                    Err(e) => {
46                                        error!("Failed to run command: {}", e.to_string())
47                                    }
48                                }
49                            }
50                        }
51                    };
52                }
53
54                // @NOTE
55                // prevent restart in test environment
56                if cfg!(test) {
57                    return;
58                }
59
60                // @NOTE
61                // restart the binary
62                match restart(bin_path, bin_arg) {
63                    Ok(child) => *running_binary = Some(child),
64                    Err(e) => {
65                        error!("Failed to restart binary: {:?}", e.to_string());
66                        error!("Please check your <bin_path>: {}", bin_path);
67                        *running_binary = None
68                    }
69                }
70            }
71        }
72
73        // @NOTE
74        // if bin_path not defined, just execute command.
75        None => match cmd {
76            CommandType::Single(cmd) => match exec(cmd.clone()).await {
77                Ok(child) => buf_reader(child),
78                Err(e) => {
79                    error!("Failed to run command: {}", e.to_string())
80                }
81            },
82            CommandType::Multiple(cmds) => {
83                for cmd in cmds {
84                    match exec(cmd.clone()).await {
85                        Ok(child) => buf_reader(child),
86                        Err(e) => {
87                            error!("Failed to run command: {}", e.to_string())
88                        }
89                    }
90                }
91            }
92        },
93    }
94}
95
96#[cfg(test)]
97mod tests {
98    use super::*;
99    use std::process::Command;
100
101    #[tokio::test]
102    async fn test_reload_with_no_binary() {
103        let mut running_binary = None;
104        let cmd = CommandType::Single("echo test".to_string());
105        let bin_path = None;
106        let bin_arg = None;
107
108        reload(&mut running_binary, &cmd, bin_path, bin_arg).await;
109        assert!(running_binary.is_none());
110    }
111
112    #[tokio::test]
113    async fn test_reload_with_binary() {
114        let mut running_binary = Some(Command::new("sleep").arg("1000").spawn().unwrap());
115        let cmd = CommandType::Single("echo test".to_string());
116        let bin_path = Some("test_binary".to_string());
117        let bin_arg = Some(vec!["arg1".to_string(), "arg2".to_string()]);
118
119        reload(
120            &mut running_binary,
121            &cmd,
122            bin_path.as_ref(),
123            bin_arg.as_ref(),
124        )
125        .await;
126        assert!(running_binary.is_some());
127    }
128}