/makepad/hub/src/process.rs

https://github.com/makepad/makepad.github.io · Rust · 111 lines · 97 code · 10 blank · 4 comment · 17 complexity · 1c78bae294389865a81374a6d6efb9a3 MD5 · raw file

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