use std::fs;
use std::io::Write;
use crate::error::{DogeError, DogeResult};
use crate::stdlib::str_arg;
use crate::value::Value;
pub fn fetch_read(path: &Value) -> DogeResult {
let path = str_arg("fetch", "read", path)?;
match fs::read_to_string(path) {
Ok(text) => Ok(Value::str(text)),
Err(err) => Err(DogeError::io_error(format!("cannot read {path}: {err}"))),
}
}
pub fn fetch_write(path: &Value, text: &Value) -> DogeResult {
let path = str_arg("fetch", "write", path)?;
let text = str_arg("fetch", "write", text)?;
match fs::write(path, text) {
Ok(()) => Ok(Value::None),
Err(err) => Err(DogeError::io_error(format!("cannot write {path}: {err}"))),
}
}
pub fn fetch_append(path: &Value, text: &Value) -> DogeResult {
let path = str_arg("fetch", "append", path)?;
let text = str_arg("fetch", "append", text)?;
let result = fs::OpenOptions::new()
.create(true)
.append(true)
.open(path)
.and_then(|mut file| file.write_all(text.as_bytes()));
match result {
Ok(()) => Ok(Value::None),
Err(err) => Err(DogeError::io_error(format!(
"cannot append to {path}: {err}"
))),
}
}
pub fn fetch_exists(path: &Value) -> DogeResult {
let path = str_arg("fetch", "exists", path)?;
Ok(Value::Bool(fs::metadata(path).is_ok()))
}
pub fn fetch_delete(path: &Value) -> DogeResult {
let path = str_arg("fetch", "delete", path)?;
match fs::remove_file(path) {
Ok(()) => Ok(Value::None),
Err(err) => Err(DogeError::io_error(format!("cannot delete {path}: {err}"))),
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::error::ErrorKind;
use std::path::PathBuf;
fn scratch(tag: &str) -> PathBuf {
std::env::temp_dir().join(format!("doge_fetch_{}_{tag}", std::process::id()))
}
#[test]
fn write_append_read_round_trip() {
let path = scratch("round_trip");
let p = Value::str(path.to_string_lossy());
fetch_write(&p, &Value::str("much ")).unwrap();
fetch_append(&p, &Value::str("wow")).unwrap();
assert!(matches!(fetch_read(&p).unwrap(), Value::Str(s) if &*s == "much wow"));
assert!(matches!(fetch_exists(&p).unwrap(), Value::Bool(true)));
fetch_delete(&p).unwrap();
assert!(matches!(fetch_exists(&p).unwrap(), Value::Bool(false)));
}
#[test]
fn reading_a_missing_file_is_a_catchable_io_error() {
let path = scratch("missing");
let err = fetch_read(&Value::str(path.to_string_lossy())).unwrap_err();
assert_eq!(err.kind, ErrorKind::IOError);
}
#[test]
fn non_str_path_is_a_type_error() {
assert_eq!(
fetch_read(&Value::Int(1)).unwrap_err().kind,
ErrorKind::TypeError
);
}
}