Read the output from the build process.
This commit is contained in:
@@ -1,16 +1,25 @@
|
||||
use std::ffi::OsStr;
|
||||
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::error::CustomError;
|
||||
use crate::Result;
|
||||
use crate::database::db_handle::DbHandle;
|
||||
|
||||
pub(crate) async fn nixos_build_target<B, F, A>(
|
||||
db_handle: &DbHandle,
|
||||
build_path: B,
|
||||
flake_path: F,
|
||||
attr: A,
|
||||
) -> Result<(), CustomError>
|
||||
) -> Result<()>
|
||||
where
|
||||
B: AsRef<Path>,
|
||||
F: AsRef<Path>,
|
||||
@@ -29,6 +38,9 @@ where
|
||||
// nixos-rebuild build --show-trace --sudo --max-jobs "$JOBS" --flake "$DIR/../../#odo" --log-format internal-json -v "${@}"
|
||||
let mut command = Command::new("nixos-rebuild");
|
||||
command.current_dir(build_path);
|
||||
command.stdout(Stdio::piped());
|
||||
command.stderr(Stdio::piped());
|
||||
command.stdin(Stdio::null());
|
||||
command.args([
|
||||
"build",
|
||||
"--show-trace",
|
||||
@@ -38,21 +50,116 @@ where
|
||||
"--log-format",
|
||||
"internal-json",
|
||||
"-v",
|
||||
"--keep-going",
|
||||
]);
|
||||
command.arg("--flake");
|
||||
command.arg(reference);
|
||||
command.kill_on_drop(true);
|
||||
|
||||
let mut child = command.spawn()?;
|
||||
let status = child.wait().await?;
|
||||
if !status.success() {
|
||||
return Err("Nixos rebuild failed.".into());
|
||||
|
||||
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,
|
||||
};
|
||||
}
|
||||
|
||||
// tokio::spawn(async move {
|
||||
// let status = child.wait().await.expect("mpv encountered an error");
|
||||
// println!("mpv status was: {}", status);
|
||||
// });
|
||||
let exit_status = exit_status_handle.await?;
|
||||
println!("nixos-rebuild status was: {}", exit_status);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
struct OutputSream {
|
||||
stdout: Option<Lines<BufReader<ChildStdout>>>,
|
||||
stderr: Option<Lines<BufReader<ChildStderr>>>,
|
||||
}
|
||||
|
||||
impl OutputSream {
|
||||
pub(crate) fn from_child(child: &mut Child) -> Result<Self> {
|
||||
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<OutputLine> {
|
||||
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,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user