use super::open;
use crate::BoxError;
use asimov_module::ModuleName;
use clientele::{StandardOptions, SysexitsError::*};
use color_print::ceprintln;
use std::io::Read;
pub async fn set(
module_name: &ModuleName,
assignments: &[String],
stdin: bool,
from_json: bool,
_flags: &StandardOptions,
) -> Result<(), BoxError> {
let module = open(module_name).await?;
module.require_variables()?;
let pairs: Vec<(String, String)> = if from_json {
let input: serde_json::Map<String, serde_json::Value> =
serde_json::from_reader(std::io::stdin().lock()).map_err(|e| {
ceprintln!("<s,r>error:</> failed to read a JSON object from standard input: {e}");
EX_DATAERR
})?;
input
.into_iter()
.map(|(key, value)| match value {
serde_json::Value::String(value) => Ok((key, value)),
_ => {
ceprintln!("<s,r>error:</> the value of `{key}` is not a string");
Err(EX_DATAERR.into())
},
})
.collect::<Result<_, BoxError>>()?
} else if stdin {
let [key] = assignments else {
ceprintln!(
"<s,r>error:</> expected exactly one variable name with --stdin, got {}",
assignments.len()
);
return Err(EX_USAGE.into());
};
let mut value = String::new();
std::io::stdin().lock().read_to_string(&mut value)?;
let value = value
.strip_suffix('\n')
.map(|value| value.strip_suffix('\r').unwrap_or(value))
.unwrap_or(&value);
vec![(key.clone(), value.to_string())]
} else {
assignments
.iter()
.map(|assignment| {
let Some((key, value)) = assignment.split_once('=') else {
ceprintln!("<s,r>error:</> expected `key=value`, got `{assignment}`");
ceprintln!(
"<s,dim>hint:</> Read a value instead with: <s>asimov module config get {module_name} {assignment}</>"
);
return Err(EX_USAGE.into());
};
Ok((key.to_string(), value.to_string()))
})
.collect::<Result<_, BoxError>>()?
};
for (key, _) in &pairs {
module.variable(key)?;
}
module.create_conf_dir().await?;
module.set_permissions().await?;
for (key, value) in &pairs {
tokio::fs::write(module.var_file(key), value).await?;
}
module.set_permissions().await?;
Ok(())
}