diff --git a/src/utils/file.rs b/src/utils/file.rs index 29e877b..71519b6 100644 --- a/src/utils/file.rs +++ b/src/utils/file.rs @@ -1,16 +1,22 @@ -use crate::error::Result; +use crate::error::{CliError, Result}; use serde_json::Value; -use std::{fs, path::PathBuf}; +use std::{ + fs, io, + path::{Path, PathBuf}, +}; pub fn read_file_to_json(path: &PathBuf) -> Result { - let file = fs::read_to_string(path)?; - let json: Value = serde_json::from_str(&file)?; - Ok(json) + let content = fs::read_to_string(path).map_err(|e| io_error("读取文件", path, e))?; + serde_json::from_str(&content).map_err(|e| { + CliError::InvalidData(format!("解析 JSON '{}' 失败: {}", path.display(), e)) + }) } pub fn write_json_to_file(path: &PathBuf, value: &Value) -> Result<()> { - let content = serde_json::to_string_pretty(value)?; - fs::write(path, content)?; + let content = serde_json::to_string_pretty(value).map_err(|e| { + CliError::InvalidData(format!("序列化 JSON '{}' 失败: {}", path.display(), e)) + })?; + fs::write(path, content).map_err(|e| io_error("写入文件", path, e))?; Ok(()) } @@ -28,3 +34,12 @@ pub fn find_project_dir(path: &Option) -> Result { let path = path.as_deref().unwrap_or("."); Ok(PathBuf::from(path)) } + +/// Wraps an [`io::Error`] with the operation name and path so error messages +/// stop being anonymous "os error 3" strings. +pub fn io_error(op: &str, path: &Path, err: io::Error) -> CliError { + CliError::Io(io::Error::new( + err.kind(), + format!("{} '{}' 失败: {}", op, path.display(), err), + )) +}