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: Option<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)], aux_chan:bool) -> Result<ChildProcess, std::io::Error> {
35 let (mut child, aux_chan_host_endpoint) = if aux_chan{
36 let (aux_chan_host_endpoint, aux_chan_client_endpoint) =
37 aux_chan::make_host_and_client_endpoint_pair()?;
38
39 let aux_chan_client_endpoint_inheritable =
40 aux_chan_client_endpoint.into_child_process_inheritable()?;
41 let mut cmd_build = Command::new(cmd);
42 cmd_build.args(args)
43 .args(aux_chan_client_endpoint_inheritable.extra_args_for_client_spawning())
44 .stdin(Stdio::piped())
45 .stdout(Stdio::piped())
46 .stderr(Stdio::piped())
47 .current_dir(current_dir);
48
49 for (key, value) in env {
50 cmd_build.env(key, value);
51 }
52
53 let child = cmd_build.spawn()?;
54 drop(aux_chan_client_endpoint_inheritable);
55 (child, Some(aux_chan_host_endpoint))
56 }
57 else{
58 let mut cmd_build = Command::new(cmd);
59 cmd_build.args(args)
60 .stdin(Stdio::piped())
61 .stdout(Stdio::piped())
62 .stderr(Stdio::piped())
63 .current_dir(current_dir);
64
65 for (key, value) in env {
66 cmd_build.env(key, value);
67 }
68 (cmd_build.spawn()?, None)
69 };
70
71 let (line_sender, line_receiver) = mpsc::channel();
75 let (stdin_sender, stdin_receiver) = mpsc::channel();
76
77 let mut stdin = child.stdin.take().expect("stdin cannot be taken!");
78 let stdout = child.stdout.take().expect("stdout cannot be taken!");
79 let stderr = child.stderr.take().expect("stderr cannot be taken!");
80
81 let _stdout_thread = {
82 let line_sender = line_sender.clone();
83 let stdin_sender = stdin_sender.clone();
84 thread::spawn(move || {
85 let mut reader = BufReader::new(stdout);
86 loop{
87 let mut line = String::new();
88 if let Ok(len) = reader.read_line(&mut line){
89 if len == 0{
90 break
91 }
92 if line_sender.send(ChildStdIO::StdOut(line)).is_err(){
93 break;
94 }
95 }
96 else{
97 let _ = line_sender.send(ChildStdIO::Term);
98 let _ = stdin_sender.send(ChildStdIn::Term);
99 break;
100 }
101 }
102 })
103 };
104
105 let _stderr_thread = {
106 let line_sender = line_sender.clone();
107 thread::spawn(move || {
108 let mut reader = BufReader::new(stderr);
109 loop{
110 let mut line = String::new();
111 if let Ok(len) = reader.read_line(&mut line){
112 if len == 0{
113 break
114 }
115 if line_sender.send(ChildStdIO::StdErr(line)).is_err(){
116 break
117 };
118 }
119 else{
120 break;
121 }
122 }
123 });
124 };
125
126 let _stdin_thread = {
127 thread::spawn(move || {
128 while let Ok(line) = stdin_receiver.recv() {
129 match line {
130 ChildStdIn::Send(line) => {
131 if let Err(_) = stdin.write_all(line.as_bytes()){
132 }
135 let _ = stdin.flush();
136 }
137 ChildStdIn::Term=>{
138 break;
139 }
140 }
141 }
142 });
143 };
144 Ok(ChildProcess {
145 stdin_sender,
146 line_sender,
147 child,
148 line_receiver,
149 aux_chan_host_endpoint,
150 })
151 }
152
153 pub fn wait(mut self) {
154 let _ = self.child.wait();
155 }
156
157 pub fn kill(mut self) {
158 let _ = self.stdin_sender.send(ChildStdIn::Term);
159 let _ = self.child.kill();
160 let _ = self.child.wait();
161 }
162}