2025-02-06 20:58:59 +09:00
|
|
|
//! File IO for generated codes.
|
|
|
|
|
2025-02-12 22:10:48 +09:00
|
|
|
use std::{collections::HashMap, fs, io, path, process};
|
|
|
|
|
|
|
|
use thiserror::Error;
|
|
|
|
|
|
|
|
use crate::types::XmlGitInfo;
|
|
|
|
|
|
|
|
#[derive(Debug, Error)]
|
|
|
|
pub enum XmlGitInfoError {
|
|
|
|
#[error("io error while getting xml git info: {msg} {source}")]
|
|
|
|
IOError {
|
|
|
|
msg: &'static str,
|
|
|
|
#[source]
|
|
|
|
source: io::Error,
|
|
|
|
},
|
|
|
|
#[error("git failed: {msg}: {stderr}")]
|
|
|
|
CommandFailed { msg: &'static str, stderr: String },
|
|
|
|
}
|
|
|
|
|
|
|
|
impl XmlGitInfoError {
|
|
|
|
fn io_error(e: io::Error, msg: &'static str) -> Self {
|
|
|
|
XmlGitInfoError::IOError { msg, source: e }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn get_xml_gitinfo(xml_path: &path::Path) -> Result<XmlGitInfo, XmlGitInfoError> {
|
|
|
|
let describe = process::Command::new("git")
|
|
|
|
.args(["describe", "--always", "--dirty"])
|
|
|
|
.current_dir(xml_path.parent().unwrap())
|
|
|
|
.output()
|
|
|
|
.map_err(|e| XmlGitInfoError::io_error(e, "git describe"))?;
|
|
|
|
let describe = if describe.status.success() {
|
|
|
|
String::from_utf8_lossy(&describe.stdout).trim().to_owned()
|
|
|
|
} else {
|
|
|
|
return Err(XmlGitInfoError::CommandFailed {
|
|
|
|
msg: "git describe",
|
|
|
|
stderr: String::from_utf8_lossy(&describe.stderr).into_owned(),
|
|
|
|
});
|
|
|
|
};
|
|
|
|
let timestamp = process::Command::new("git")
|
|
|
|
.args(["log", "-1", "--pretty=format:'%cI'"])
|
|
|
|
.current_dir(xml_path.parent().unwrap())
|
|
|
|
.output()
|
|
|
|
.map_err(|e| XmlGitInfoError::io_error(e, "git log (timestamp)"))?;
|
|
|
|
let timestamp = if timestamp.status.success() {
|
|
|
|
String::from_utf8_lossy(×tamp.stdout).trim().to_owned()
|
|
|
|
} else {
|
|
|
|
return Err(XmlGitInfoError::CommandFailed {
|
|
|
|
msg: "git log (timestamp)",
|
|
|
|
stderr: String::from_utf8_lossy(×tamp.stderr).into_owned(),
|
|
|
|
});
|
|
|
|
};
|
|
|
|
let sha = process::Command::new("git")
|
|
|
|
.args(["rev-parse", "HEAD"])
|
|
|
|
.current_dir(xml_path.parent().unwrap())
|
|
|
|
.output()
|
|
|
|
.map_err(|e| XmlGitInfoError::io_error(e, "git rev-parse (sha)"))?;
|
|
|
|
let git_sha = if sha.status.success() {
|
|
|
|
String::from_utf8_lossy(&sha.stdout).trim().to_owned()
|
|
|
|
} else {
|
|
|
|
return Err(XmlGitInfoError::CommandFailed {
|
|
|
|
msg: "git rev-parse (sha)",
|
|
|
|
stderr: String::from_utf8_lossy(&sha.stderr).into_owned(),
|
|
|
|
});
|
|
|
|
};
|
|
|
|
Ok(XmlGitInfo {
|
|
|
|
describe,
|
|
|
|
commit_timestamp: timestamp,
|
|
|
|
sha: git_sha,
|
|
|
|
})
|
|
|
|
}
|
2025-02-06 20:58:59 +09:00
|
|
|
|
|
|
|
/// Write formatted codes generated with [`Module::generate_code`](crate::types::Module::generate_code).
|
|
|
|
pub fn write_to_files(
|
|
|
|
files: HashMap<path::PathBuf, syn::File>,
|
|
|
|
out_path: &path::Path,
|
|
|
|
) -> io::Result<()> {
|
|
|
|
if !out_path.is_dir() {
|
|
|
|
return Err(io::Error::from(io::ErrorKind::NotADirectory));
|
|
|
|
}
|
|
|
|
if fs::read_dir(out_path)?.next().is_some() {
|
|
|
|
return Err(io::Error::new(
|
|
|
|
io::ErrorKind::AlreadyExists,
|
2025-02-07 19:37:18 +09:00
|
|
|
format!("out path `{}` is not empty", out_path.display()),
|
2025-02-06 20:58:59 +09:00
|
|
|
));
|
|
|
|
}
|
|
|
|
for (file_path, code) in files {
|
|
|
|
fs::DirBuilder::new()
|
|
|
|
.recursive(true)
|
|
|
|
.create(out_path.join(&file_path).parent().unwrap())?;
|
|
|
|
|
|
|
|
fs::write(out_path.join(&file_path), prettyplease::unparse(&code))?;
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|