use slash_lang::parser::ast::Arg;
use crate::command::{MethodDef, SlashCommand};
use crate::executor::{CommandOutput, ExecutionError, PipeValue};
pub struct Write;
impl SlashCommand for Write {
fn name(&self) -> &str {
"write"
}
fn methods(&self) -> &[MethodDef] {
static METHODS: [MethodDef; 1] = [MethodDef::flag("append")];
&METHODS
}
fn execute(
&self,
primary: Option<&str>,
args: &[Arg],
input: Option<&PipeValue>,
) -> Result<CommandOutput, ExecutionError> {
let path = primary.ok_or_else(|| {
ExecutionError::Runner("/write requires a path: /write(file.txt)".into())
})?;
let data = match input {
Some(PipeValue::Bytes(b)) => b.as_slice(),
Some(PipeValue::Context(ctx)) => {
let json = ctx.to_json();
return write_data(path, json.as_bytes(), args);
}
None => return Err(ExecutionError::Runner("/write: no piped input".into())),
};
write_data(path, data, args)
}
}
fn write_data(path: &str, data: &[u8], args: &[Arg]) -> Result<CommandOutput, ExecutionError> {
let append = args.iter().any(|a| a.name == "append");
if append {
use std::io::Write as _;
let mut file = std::fs::OpenOptions::new()
.create(true)
.append(true)
.open(path)
.map_err(|e| ExecutionError::Runner(format!("/write({}): {}", path, e)))?;
file.write_all(data)
.map_err(|e| ExecutionError::Runner(format!("/write({}): {}", path, e)))?;
} else {
std::fs::write(path, data)
.map_err(|e| ExecutionError::Runner(format!("/write({}): {}", path, e)))?;
}
Ok(CommandOutput {
stdout: None,
stderr: None,
success: true,
})
}