From ab1f86384b76f2c33c8175e622b1ac16e91ef93e Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Mon, 16 Feb 2026 20:06:46 -0500 Subject: [PATCH] Move the running build into its own struct. --- src/nix_util/high_level.rs | 114 ++---------------------------- src/nix_util/mod.rs | 1 + src/nix_util/running_build.rs | 127 ++++++++++++++++++++++++++++++++++ 3 files changed, 133 insertions(+), 109 deletions(-) create mode 100644 src/nix_util/running_build.rs diff --git a/src/nix_util/high_level.rs b/src/nix_util/high_level.rs index 3353b32..6690ca4 100644 --- a/src/nix_util/high_level.rs +++ b/src/nix_util/high_level.rs @@ -3,17 +3,13 @@ use std::ffi::OsString; use std::path::Path; use std::process::Stdio; -use tokio::io::AsyncBufReadExt; -use tokio::io::BufReader; -use tokio::io::Lines; -use tokio::process::Child; -use tokio::process::ChildStderr; -use tokio::process::ChildStdout; use tokio::process::Command; use crate::Result; use crate::database::db_handle::DbHandle; +use super::running_build::RunningBuild; + pub(crate) async fn nixos_build_target( db_handle: &DbHandle, build_path: B, @@ -56,110 +52,10 @@ where command.arg(reference); command.kill_on_drop(true); - let mut child = command.spawn()?; + let child = command.spawn()?; - let mut output_stream = OutputSream::from_child(&mut child)?; - - let exit_status_handle = tokio::spawn(async move { - let status = child - .wait() - .await - .expect("nixos-rebuild encountered an error"); - status - }); - - loop { - let next_line = output_stream.next_line().await?; - match next_line { - OutputLine::Stdout(line) => { - println!("STDOUT: {line}"); - } - OutputLine::Stderr(line) => { - println!("STDERR: {line}"); - } - OutputLine::Done => break, - }; - } - - let exit_status = exit_status_handle.await?; - println!("nixos-rebuild status was: {}", exit_status); + let mut running_build = RunningBuild::new(db_handle)?; + running_build.run_to_completion(child).await?; Ok(()) } - -struct OutputSream { - stdout: Option>>, - stderr: Option>>, -} - -impl OutputSream { - pub(crate) fn from_child(child: &mut Child) -> Result { - let stdout = child - .stdout - .take() - .expect("child did not have a handle to stdout"); - let stderr = child - .stderr - .take() - .expect("child did not have a handle to stderr"); - let stdout = BufReader::new(stdout).lines(); - let stderr = BufReader::new(stderr).lines(); - Ok(OutputSream { - stdout: Some(stdout), - stderr: Some(stderr), - }) - } - - pub(crate) async fn next_line(&mut self) -> Result { - loop { - match (&mut self.stdout, &mut self.stderr) { - (None, None) => { - return Ok(OutputLine::Done); - } - (None, Some(err)) => { - if let Some(line) = err.next_line().await? { - return Ok(OutputLine::Stderr(line)); - } else { - return Ok(OutputLine::Done); - } - } - (Some(out), None) => { - if let Some(line) = out.next_line().await? { - return Ok(OutputLine::Stdout(line)); - } else { - return Ok(OutputLine::Done); - } - } - (Some(out), Some(err)) => { - tokio::select! { - Ok(line) = out.next_line() => match line { - Some(line) => { - return Ok(OutputLine::Stdout(line)); - }, - None => { - self.stdout.take(); - }, - }, - Ok(line) = err.next_line() => match line { - Some(line) => { - return Ok(OutputLine::Stderr(line)); - }, - None => { - self.stderr.take(); - }, - }, - else => { - return Ok(OutputLine::Done); - }, - }; - } - }; - } - } -} - -enum OutputLine { - Stdout(String), - Stderr(String), - Done, -} diff --git a/src/nix_util/mod.rs b/src/nix_util/mod.rs index 9c12d6c..8143d18 100644 --- a/src/nix_util/mod.rs +++ b/src/nix_util/mod.rs @@ -1,2 +1,3 @@ mod high_level; +mod running_build; pub(crate) use high_level::*; diff --git a/src/nix_util/running_build.rs b/src/nix_util/running_build.rs new file mode 100644 index 0000000..04e0e08 --- /dev/null +++ b/src/nix_util/running_build.rs @@ -0,0 +1,127 @@ +use tokio::io::AsyncBufReadExt; +use tokio::io::BufReader; +use tokio::io::Lines; +use tokio::process::Child; +use tokio::process::ChildStderr; +use tokio::process::ChildStdout; + +use crate::Result; +use crate::database::db_handle::DbHandle; + +pub(crate) struct RunningBuild<'db> { + db_handle: &'db DbHandle, +} + +impl<'db> RunningBuild<'db> { + pub(crate) fn new(db_handle: &'db DbHandle) -> Result { + Ok(RunningBuild { db_handle }) + } + + pub(crate) async fn run_to_completion(&mut self, mut child: Child) -> Result<()> { + let mut output_stream = OutputStream::from_child(&mut child)?; + + let exit_status_handle = tokio::spawn(async move { + let status = child + .wait() + .await + .expect("nixos-rebuild encountered an error"); + status + }); + + loop { + let next_line = output_stream.next_line().await?; + match next_line { + OutputLine::Stdout(line) | OutputLine::Stderr(line) => { + self.handle_line(line)?; + } + OutputLine::Done => break, + }; + } + + let exit_status = exit_status_handle.await?; + println!("nixos-rebuild status was: {}", exit_status); + + Ok(()) + } + + fn handle_line(&mut self, line: String) -> Result<()> { + Ok(()) + } +} + +struct OutputStream { + stdout: Option>>, + stderr: Option>>, +} + +impl OutputStream { + pub(crate) fn from_child(child: &mut Child) -> Result { + let stdout = child + .stdout + .take() + .expect("child did not have a handle to stdout"); + let stderr = child + .stderr + .take() + .expect("child did not have a handle to stderr"); + let stdout = BufReader::new(stdout).lines(); + let stderr = BufReader::new(stderr).lines(); + Ok(OutputStream { + stdout: Some(stdout), + stderr: Some(stderr), + }) + } + + pub(crate) async fn next_line(&mut self) -> Result { + loop { + match (&mut self.stdout, &mut self.stderr) { + (None, None) => { + return Ok(OutputLine::Done); + } + (None, Some(err)) => { + if let Some(line) = err.next_line().await? { + return Ok(OutputLine::Stderr(line)); + } else { + return Ok(OutputLine::Done); + } + } + (Some(out), None) => { + if let Some(line) = out.next_line().await? { + return Ok(OutputLine::Stdout(line)); + } else { + return Ok(OutputLine::Done); + } + } + (Some(out), Some(err)) => { + tokio::select! { + Ok(line) = out.next_line() => match line { + Some(line) => { + return Ok(OutputLine::Stdout(line)); + }, + None => { + self.stdout.take(); + }, + }, + Ok(line) = err.next_line() => match line { + Some(line) => { + return Ok(OutputLine::Stderr(line)); + }, + None => { + self.stderr.take(); + }, + }, + else => { + return Ok(OutputLine::Done); + }, + }; + } + }; + } + } +} + +enum OutputLine { + Stdout(String), + Stderr(String), + Done, +}