2026-05-04 01:31:27 +08:00
|
|
|
use crate::error::{CliError, Result};
|
2025-11-29 17:31:00 +08:00
|
|
|
use serde_json::Value;
|
2026-05-04 01:31:27 +08:00
|
|
|
use std::{
|
|
|
|
|
fs, io,
|
|
|
|
|
path::{Path, PathBuf},
|
|
|
|
|
};
|
2025-11-29 17:31:00 +08:00
|
|
|
|
|
|
|
|
pub fn read_file_to_json(path: &PathBuf) -> Result<Value> {
|
2026-05-04 01:31:27 +08:00
|
|
|
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))
|
|
|
|
|
})
|
2025-11-29 17:31:00 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn write_json_to_file(path: &PathBuf, value: &Value) -> Result<()> {
|
2026-05-04 01:31:27 +08:00
|
|
|
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))?;
|
2025-11-29 17:31:00 +08:00
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn update_json_file<F>(path: &PathBuf, updater: F) -> Result<()>
|
|
|
|
|
where
|
|
|
|
|
F: FnOnce(&mut Value) -> Result<()>,
|
|
|
|
|
{
|
|
|
|
|
let mut json = read_file_to_json(path)?;
|
|
|
|
|
updater(&mut json)?;
|
|
|
|
|
write_json_to_file(path, &json)?;
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn find_project_dir(path: &Option<String>) -> Result<PathBuf> {
|
|
|
|
|
let path = path.as_deref().unwrap_or(".");
|
|
|
|
|
Ok(PathBuf::from(path))
|
|
|
|
|
}
|
2026-05-04 01:31:27 +08:00
|
|
|
|
|
|
|
|
/// 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),
|
|
|
|
|
))
|
|
|
|
|
}
|