proc.rs 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. use std::io;
  2. use std::process::{ExitStatus, Stdio};
  3. use tokio::io::{AsyncBufReadExt, BufReader};
  4. use tokio::process::{Command};
  5. use crate::logger::{LogWriter};
  6. use crate::syscall::error::ExecError;
  7. fn _exitstatus_convert(res: io::Result<ExitStatus>) -> Result<Option<i32>, ExecError> {
  8. match res {
  9. Ok(es) => {
  10. match es.code() {
  11. None => {
  12. Ok(None)
  13. }
  14. Some(code) => {
  15. Ok(Some(code))
  16. }
  17. }
  18. }
  19. Err(e) => {Err(ExecError::from(e))}
  20. }
  21. }
  22. pub fn shell_exec_cmd(program: String) {
  23. let r = exec_blocking(program);
  24. match r {
  25. Ok(ec) => {
  26. match ec {
  27. None => {
  28. println!("exit with no code.")
  29. }
  30. Some(c) => {
  31. println!("exit with code {}.", c)
  32. }
  33. }
  34. }
  35. Err(err) => {
  36. println!("failed run command: {:?}.", err)
  37. }
  38. }
  39. }
  40. pub fn exec_blocking(program: String) -> Result<Option<i32>, ExecError> {
  41. let p = std::process::Command::new(program.clone()).spawn();
  42. match p {
  43. Ok(mut ch) => {
  44. let res = ch.wait();
  45. _exitstatus_convert(res)
  46. }
  47. Err(err) => {
  48. Err(ExecError::from(err))
  49. }
  50. }
  51. }
  52. pub async fn exec_async(program: String) -> Result<Option<i32>, ExecError> {
  53. let p = tokio::process::Command::new(program.clone()).spawn();
  54. match p {
  55. Ok(mut ch) => {
  56. let res = ch.wait().await;
  57. _exitstatus_convert(res)
  58. }
  59. Err(err) => {
  60. Err(ExecError::from(err))
  61. }
  62. }
  63. }
  64. pub async fn exec_async_with_logger(bin: String, stdout_logger: LogWriter, stderr_logger: LogWriter) -> Result<Option<i32>, ExecError> {
  65. let mut cmd_run = Command::new(&bin)
  66. .stdin(Stdio::null())
  67. .stdout(Stdio::piped())
  68. .stderr(Stdio::piped())
  69. .spawn()?;
  70. let cmd_stdout = match cmd_run.stdout.take() {
  71. None => {
  72. return Err(ExecError::from_str("can not take stdout for child process"))
  73. }
  74. Some(v) => {v}
  75. };
  76. let cmd_stderr = match cmd_run.stderr.take(){
  77. None => {
  78. return Err(ExecError::from_str("can not take stderr for child process"))
  79. }
  80. Some(v) => {v}
  81. };
  82. let stdout_reader = BufReader::new(cmd_stdout);
  83. let stderr_reader = BufReader::new(cmd_stderr);
  84. let mut stdout_lines = stdout_reader.lines();
  85. let mut stderr_lines = stderr_reader.lines();
  86. let bin_name_for_stdout_error_msg = bin.clone();
  87. tokio::spawn(async move {
  88. while let Some(line) = stdout_lines.next_line().await.unwrap_or_else(|e| {
  89. eprintln!("error in reading stdout for '{}':{:?}", bin_name_for_stdout_error_msg, e);
  90. None
  91. }) {
  92. stdout_logger.info(line.as_str()).await;
  93. }
  94. });
  95. let bin_name_for_stderr_error_msg = bin.clone();
  96. tokio::spawn(async move {
  97. while let Some(line) = stderr_lines.next_line().await.unwrap_or_else(|e| {
  98. eprintln!("error in reading stderr for '{}':{:?}", bin_name_for_stderr_error_msg, e);
  99. None
  100. }) {
  101. stderr_logger.warn(line.as_str()).await;
  102. }
  103. });
  104. let run_result = cmd_run.wait().await;
  105. _exitstatus_convert(run_result)
  106. }