use std::collections::HashMap;
use std::ffi::{OsStr, OsString};
use std::path::PathBuf;
fn from_env_vars() -> HashMap<OsString, OsString> {
std::env::vars()
.map(|(k, v)| (k.into(), v.into()))
.collect()
}
#[derive(Debug, Clone, Default)]
pub struct Config {
pub env: HashMap<OsString, OsString>,
pub cwd: Option<PathBuf>,
pub stdin: Option<StdioConfig>,
pub stdout: Option<StdioConfig>,
pub stderr: Option<StdioConfig>,
}
#[derive(Debug, Clone, Copy, Default)]
pub enum StdioConfig {
#[default]
Inherit,
Piped,
Null,
Fd(u32),
}
impl Config {
pub fn new() -> Self {
Self::default()
}
pub fn from_env() -> std::io::Result<Self> {
let cwd = std::env::current_dir()?;
let env = from_env_vars();
Ok(Self {
env,
cwd: Some(cwd),
stdin: None,
stdout: None,
stderr: None,
})
}
#[must_use]
pub fn env<K, V>(mut self, key: K, value: V) -> Self
where
K: AsRef<OsStr>,
V: AsRef<OsStr>,
{
drop(
self.env
.insert(key.as_ref().to_os_string(), value.as_ref().to_os_string()),
);
self
}
#[must_use]
pub fn cwd<D: Into<PathBuf>>(mut self, dir: D) -> Self {
self.cwd = Some(dir.into());
self
}
#[must_use]
pub fn stdin(mut self, config: StdioConfig) -> Self {
self.stdin = Some(config);
self
}
#[must_use]
pub fn stdout(mut self, config: StdioConfig) -> Self {
self.stdout = Some(config);
self
}
#[must_use]
pub fn stderr(mut self, config: StdioConfig) -> Self {
self.stderr = Some(config);
self
}
}
pub trait ConfigExt {
fn with_config(self, config: &Config) -> Self;
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_config_new() {
let config = Config::new();
assert!(config.env.is_empty());
assert!(config.cwd.is_none());
}
#[test]
fn test_config_env() {
let config = Config::new().env("KEY", "value").env("OTHER", "123");
let key = OsString::from("KEY");
assert_eq!(
config.env.get(&key).map(|s| s.to_str()),
Some(Some("value"))
);
}
#[test]
fn test_config_cwd() {
let config = Config::new().cwd("/tmp");
assert!(config.cwd.is_some());
}
}