// nixos-config - My current NixOS configuration // // Copyright (C) 2025 Benedikt Peetz // SPDX-License-Identifier: GPL-3.0-or-later // // This file is part of my nixos-config. // // You should have received a copy of the License along with this program. // If not, see . use std::{ env::args, io::{BufRead, BufReader, Read, Write}, path::PathBuf, process::{Command, Stdio}, thread::JoinHandle, }; use anyhow::{Context, Result}; fn main() -> Result<()> { let args = args().skip(1).collect::>(); let mut cmd = Command::new(&args[0]); if let Some(arguments) = args.get(1) { cmd.args(arguments.split(" ").collect::>().as_slice()); } eprintln!("notify-run> Spawning {:?}", cmd); let mut child = cmd .stderr(Stdio::piped()) .stdout(Stdio::piped()) .spawn() .with_context(|| format!("Failed to spawn {:?}", cmd))?; let (stdout, stderr) = ( child.stdout.take().expect("Was piped"), child.stderr.take().expect("Was piped"), ); let name = PathBuf::from(&args[0]) .file_name() .expect("this to be a command, and thus have a file_name") .to_string_lossy() .to_string(); let stdout_t = write_thread(stdout, name.to_owned()); let stderr_t = write_thread(stderr, name.to_owned()); stdout_t .join() .unwrap() .context("Failed to join stdout thread")?; stderr_t .join() .unwrap() .context("Failed to join stderr thread")?; let status = child.wait().context("Failed to wait for child output")?; if !status.success() { let mut notify_send = Command::new("notify-send"); notify_send.args([format!("Command {:?} failed", cmd).as_str()]); notify_send.status().with_context(|| { format!( "Failed to run `notify-send` to tell about failed command ({:?}).", cmd ) })?; } Ok(()) } fn write_thread(input: R, name: String) -> JoinHandle> { std::thread::spawn(move || { let mut reader = BufReader::new(input); let mut buf = String::new(); loop { buf.clear(); if reader .read_line(&mut buf) .context("Failed to read from child output")? == 0 { break; } write!(std::io::stdout(), "{name}> {buf}")?; } Ok(()) }) }