use std::env;
use std::fs;
use std::io;
use std::path::{Path, PathBuf};
pub(crate) fn jobs_root() -> io::Result<PathBuf> {
if let Ok(p) = env::var("PEND_DIR") {
let path = PathBuf::from(p);
fs::create_dir_all(&path)?;
Ok(path)
} else {
let mut dir = env::temp_dir();
dir.push("pend");
fs::create_dir_all(&dir)?;
Ok(dir)
}
}
#[derive(Debug, Clone)]
pub(crate) struct JobPaths {
pub(crate) out: PathBuf,
pub(crate) err: PathBuf,
pub(crate) exit: PathBuf,
pub(crate) meta: PathBuf,
pub(crate) log: PathBuf,
pub(crate) lock: PathBuf,
pub(crate) signal: PathBuf,
}
impl JobPaths {
pub(crate) fn new(job_name: &str) -> io::Result<Self> {
let root = jobs_root()?;
let paths = Self {
out: root.join(format!("{}.out", job_name)),
err: root.join(format!("{}.err", job_name)),
exit: root.join(format!("{}.exit", job_name)),
meta: root.join(format!("{}.json", job_name)),
log: root.join(format!("{}.log", job_name)),
lock: root.join(format!("{}.lock", job_name)),
signal: root.join(format!("{}.signal", job_name)),
};
paths.assert_paths_within_limit()?;
Ok(paths)
}
fn assert_paths_within_limit(&self) -> io::Result<()> {
#[cfg(windows)]
const MAX_PATH: usize = 260; #[cfg(unix)]
const MAX_PATH: usize = 4096;
for path in [
&self.out,
&self.err,
&self.exit,
&self.meta,
&self.log,
&self.lock,
&self.signal,
] {
if let Some(s) = path.to_str() {
if s.len() >= MAX_PATH {
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
format!(
"artifact path exceeds OS limit ({} > {}): {}",
s.len(),
MAX_PATH,
s
),
));
}
}
}
Ok(())
}
pub(crate) fn any_exist(&self) -> bool {
self.out.exists()
|| self.err.exists()
|| self.exit.exists()
|| self.meta.exists()
|| self.log.exists()
|| self.signal.exists()
|| self.lock.exists()
}
pub(crate) fn file_len(path: &Path) -> u64 {
std::fs::metadata(path).map(|m| m.len()).unwrap_or(0)
}
}