makepad_studio/build_manager/
child_process.rs1use std::{
2 process::{Command, Child, Stdio},
3 sync::mpsc::{self, Sender, Receiver},
4 thread,
5 io::prelude::*,
6 io::BufReader,
7 str,
8 path::PathBuf,
9};
10use crate::makepad_platform::cx_stdin::aux_chan;
11
12pub struct ChildProcess {
13 pub child: Child,
14 pub stdin_sender: Sender<ChildStdIn>,
15 pub line_sender: Sender<ChildStdIO>,
16 pub line_receiver: Receiver<ChildStdIO>,
17 pub aux_chan_host_endpoint: aux_chan::HostEndpoint,
18}
19
20pub enum ChildStdIO {
21 StdOut(String),
22 StdErr(String),
23 Term,
24 Kill
25}
26
27pub enum ChildStdIn {
28 Send(String),
29 Term,
30}
31
32impl ChildProcess {
33
34 pub fn start(cmd: &str, args: &[String], current_dir: PathBuf, env: &[(&str, &str)]) -> Result<ChildProcess, std::io::Error> {
35 let (aux_chan_host_endpoint, aux_chan_client_endpoint) =
36 aux_chan::make_host_and_client_endpoint_pair()?;
37
38 let aux_chan_client_endpoint_inheritable =
39 aux_chan_client_endpoint.into_child_process_inheritable()?;
40
41 let mut cmd_build = Command::new(cmd);
42
43 cmd_build.args(args)
44 .args(aux_chan_client_endpoint_inheritable.extra_args_for_client_spawning())
45 .stdin(Stdio::piped())
46 .stdout(Stdio::piped())
47 .stderr(Stdio::piped())
48 .current_dir(current_dir);
49
50 for (key, value) in env {
51 cmd_build.env(key, value);
52 }
53
54 let mut child = cmd_build.spawn()?;
55
56 drop(aux_chan_client_endpoint_inheritable);
59
60 let (line_sender, line_receiver) = mpsc::channel();
61 let (stdin_sender, stdin_receiver) = mpsc::channel();
62
63 let mut stdin = child.stdin.take().expect("stdin cannot be taken!");
64 let stdout = child.stdout.take().expect("stdout cannot be taken!");
65 let stderr = child.stderr.take().expect("stderr cannot be taken!");
66
67 let _stdout_thread = {
68 let line_sender = line_sender.clone();
69 let stdin_sender = stdin_sender.clone();
70 thread::spawn(move || {
71 let mut reader = BufReader::new(stdout);
72 loop{
73 let mut line = String::new();
74 if let Ok(len) = reader.read_line(&mut line){
75 if len == 0{
76 break
77 }
78 if line_sender.send(ChildStdIO::StdOut(line)).is_err(){
79 break;
80 }
81 }
82 else{
83 let _ = line_sender.send(ChildStdIO::Term);
84 let _ = stdin_sender.send(ChildStdIn::Term);
85 break;
86 }
87 }
88 })
89 };
90
91 let _stderr_thread = {
92 let line_sender = line_sender.clone();
93 thread::spawn(move || {
94 let mut reader = BufReader::new(stderr);
95 loop{
96 let mut line = String::new();
97 if let Ok(len) = reader.read_line(&mut line){
98 if len == 0{
99 break
100 }
101 if line_sender.send(ChildStdIO::StdErr(line)).is_err(){
102 break
103 };
104 }
105 else{
106 break;
107 }
108 }
109 });
110 };
111
112 let _stdin_thread = {
113 thread::spawn(move || {
114 while let Ok(line) = stdin_receiver.recv() {
115 match line {
116 ChildStdIn::Send(line) => {
117 if let Err(_) = stdin.write_all(line.as_bytes()){
118 }
120 let _ = stdin.flush();
121 }
122 ChildStdIn::Term=>{
123 break;
124 }
125 }
126 }
127 });
128 };
129 Ok(ChildProcess {
130 stdin_sender,
131 line_sender,
132 child,
133 line_receiver,
134 aux_chan_host_endpoint,
135 })
136 }
137
138 pub fn wait(mut self) {
139 let _ = self.child.wait();
140 }
141
142 pub fn kill(mut self) {
143 let _ = self.stdin_sender.send(ChildStdIn::Term);
144 let _ = self.child.kill();
145 let _ = self.child.wait();
146 }
147}