makepad_hub/
process.rs

1//use closefds::*;
2use std::process::{Command, Child, Stdio};
3//use std::os::unix::process::{CommandExt};
4use std::sync::{mpsc};
5use std::io::{Read};
6use std::str;
7
8pub struct Process {
9    pub child: Option<Child>,
10    pub rx_line: Option<mpsc::Receiver<Option<(bool, String)>>>,
11}
12
13impl Process {
14    
15    pub fn start(cmd: &str, args: &[&str], current_dir: &str, env: &[(&str, &str)]) -> Result<Process, std::io::Error> {
16        fn create_process(cmd: &str, args: &[&str], current_dir: &str, env: &[(&str, &str)]) -> Result<Child, std::io::Error> {
17            let mut cbuild = if cmd.find("/").is_some() {
18                Command::new(&format!("{}/{}", current_dir, cmd))
19            }
20            else {
21                Command::new(cmd)
22            };
23            cbuild.args(args)
24                .stdin(Stdio::null())
25                .stdout(Stdio::piped())
26                .stderr(Stdio::piped())
27                .current_dir(current_dir);
28            for (key, value) in env {
29                cbuild.env(key, value);
30            }
31            cbuild.spawn()
32        }
33        
34        let mut child = create_process(cmd, args, current_dir, env) ?;
35        
36        let (tx_line, rx_line) = mpsc::channel();
37        let tx_err = tx_line.clone();
38        let mut stdout = child.stdout.take().expect("stdout cannot be taken!");
39        let mut stderr = child.stderr.take().expect("stderr cannot be taken!");
40        
41        let _stdout_thread = {
42            std::thread::spawn(move || {
43                let mut storage = Vec::new();
44                loop {
45                    let offset = storage.len();
46                    storage.resize(offset + 1024, 0u8);
47                    let new_len = storage.len();
48                    let n_bytes_read = stdout.read(&mut storage[offset..new_len]).expect("cannot read");
49                    if n_bytes_read == 0 {
50                        tx_line.send(None).expect("tx_line cannot send - unexpected");
51                        return;
52                    }
53                    storage.resize(offset + n_bytes_read, 0u8);
54                    let mut start = 0;
55                    for (index, ch) in storage.iter().enumerate() {
56                        if *ch == '\n' as u8 {
57                            // emit a line
58                            if let Ok(line) = str::from_utf8(&storage[start..(index + 1)]) {
59                                tx_line.send(Some((false, line.to_string()))).expect("tx_line cannot send - unexpected");
60                            }
61                            start = index + 1;
62                        }
63                    }
64                    storage.drain(0..start);
65                }
66            })
67        };
68        
69        let _stderr_thread = {
70            std::thread::spawn(move || {
71                let mut storage = Vec::new();
72                loop {
73                    let offset = storage.len();
74                    storage.resize(offset + 1024, 0u8);
75                    let new_len = storage.len();
76                    let n_bytes_read = stderr.read(&mut storage[offset..new_len]).expect("cannot read");
77                    if n_bytes_read == 0 {
78                        return;
79                    }
80                    storage.resize(offset + n_bytes_read, 0u8);
81                    let mut start = 0;
82                    for (index, ch) in storage.iter().enumerate() {
83                        if *ch == '\n' as u8 {
84                            // emit a line
85                            if let Ok(line) = str::from_utf8(&storage[start..(index + 1)]) {
86                                tx_err.send(Some((true, line.to_string()))).expect("tx_err cannot send - unexpected");
87                            }
88                            start = index + 1;
89                        }
90                    }
91                    storage.drain(0..start);
92                }
93            })
94        };
95        
96        Ok(Process {
97            child: Some(child),
98            rx_line: Some(rx_line),
99        })
100    }
101    
102    pub fn wait(&mut self) {
103        if let Some(child) = &mut self.child {
104            let _ = child.wait();
105            self.child = None;
106        }
107    }
108    
109    pub fn kill(&mut self) {
110        if let Some(child) = &mut self.child {
111            let _ = child.kill();
112            let _ = child.wait();
113            self.child = None;
114        }
115    }
116}