mod actions; pub mod cli; mod error; mod interaction; mod os; mod plan; mod planner; mod settings; use std::{ffi::OsStr, fmt::Display, process::Output}; pub use error::HarmonicError; pub use plan::InstallPlan; pub use planner::BuiltinPlanner; use serde::Serializer; pub use settings::InstallSettings; use tokio::process::Command; #[tracing::instrument(skip_all, fields(command = %format!("{:?}", command.as_std())))] async fn execute_command(command: &mut Command) -> Result { tracing::trace!("Executing"); let command_str = format!("{:?}", command.as_std()); let output = command.output().await?; match output.status.success() { true => Ok(output), false => Err(std::io::Error::new( std::io::ErrorKind::Other, format!( "Command `{command_str}` failed status, stderr:\n{}\n", String::from_utf8(output.stderr).unwrap_or_else(|_e| String::from("")) ), )), } } #[tracing::instrument(skip_all, fields( k = %k.as_ref().to_string_lossy(), v = %v.as_ref().to_string_lossy(), ))] fn set_env(k: impl AsRef, v: impl AsRef) { tracing::trace!("Setting env"); std::env::set_var(k.as_ref(), v.as_ref()); } fn serialize_error_to_display(err: &E, ser: S) -> Result where E: Display, S: Serializer, { ser.serialize_str(&format!("{err:#}")) }