Repository: tauri-apps/tauri
File: crates/tauri-cli/src/lib.rs (Rust)

Code before:
      .collect::<Vec<_>>()
      .join(" ");
    let cmdline = format!("{program} {args}");
    log::debug!(action = "Running"; "Command `{cmdline}`");

    self.stdout(Stdio::piped());
    self.stderr(Stdio::piped());

    let mut child = self
      .spawn()
      .with_context(|| format!("failed to run command `{cmdline}`"))?;

    let mut stdout = child.stdout.take().map(BufReader::new).unwrap();
    let stdout_lines = Arc::new(Mutex::new(Vec::new()));
    let stdout_lines_ = stdout_lines.clone();
    std::thread::spawn(move || {
      let mut line = String::new();
      loop {
        line.clear();
        match stdout.read_line(&mut line) {
          Ok(0) => break,
          Ok(_) => {
            log::debug!(action = "stdout"; "{}", line.trim_end());
            if let Ok(mut lines) = stdout_lines_.lock() {
              lines.extend(line.as_bytes());
            }
          }
          Err(_) => break,
        }
      }
    });

    let mut stderr = child.stderr.take().map(BufReader::new).unwrap();
    let stderr_lines = Arc::new(Mutex::new(Vec::new()));
    let stderr_lines_ = stderr_lines.clone();
    std::thread::spawn(move || {
      let mut line = String::new();
      loop {
        line.clear();
        match stderr.read_line(&mut line) {
          Ok(0) => break,
          Ok(_) => {
            log::debug!(action = "stderr"; "{}", line.trim_end());
            if let Ok(mut lines) = stderr_lines_.lock() {
              lines.extend(line.as_bytes());
            }
          }
          Err(_) => break,
        }
      }
    });

Review comment (performance):
i think we should keep the lock() where it was for performance reasons. the next time we will need a lock is after these threads are stopped.

Code after:
    self.status()
  }

  fn output_ok(&mut self) -> crate::Result<Output> {
    let program = self.get_program().to_string_lossy().into_owned();
    let args = self
      .get_args()
      .map(|a| a.to_string_lossy())
      .collect::<Vec<_>>()
      .join(" ");
    let cmdline = format!("{program} {args}");
    log::debug!(action = "Running"; "Command `{cmdline}`");

    self.stdout(Stdio::piped());
    self.stderr(Stdio::piped());

    let mut child = self
      .spawn()
      .with_context(|| format!("failed to run command `{cmdline}`"))?;

    let mut stdout = child.stdout.take().map(BufReader::new).unwrap();
    let stdout_lines = Arc::new(Mutex::new(Vec::new()));
    let stdout_lines_ = stdout_lines.clone();
    std::thread::spawn(move || {
      let mut line = String::new();
      if let Ok(mut lines) = stdout_lines_.lock() {
        loop {
          line.clear();
          match stdout.read_line(&mut line) {
            Ok(0) => break,
            Ok(_) => {
              log::debug!(action = "stdout"; "{}", line.trim_end());
              lines.extend(line.as_bytes());
            }
            Err(_) => (),
          }
        }
      }
    });

    let mut stderr = child.stderr.take().map(BufReader::new).unwrap();
    let stderr_lines = Arc::new(Mutex::new(Vec::new()));
    let stderr_lines_ = stderr_lines.clone();
    std::thread::spawn(move || {
      let mut line = String::new();
      if let Ok(mut lines) = stderr_lines_.lock() {
        loop {
          line.clear();
          match stderr.read_line(&mut line) {
            Ok(0) => break,
            Ok(_) => {