#[cfg(not(feature = "async"))]
use std::io::Write;
use std::{
env,
path::{Path, PathBuf},
};
use path_absolutize::*;
use serde::Serialize;
#[cfg(not(feature = "async"))]
use tempfile::{Builder, NamedTempFile};
#[cfg(feature = "async")]
use tokio::io::AsyncWriteExt;
use uuid::Uuid;
use crate::error::Error;
pub fn abs_path_buf<P>(path: P) -> Result<PathBuf, Error>
where
P: AsRef<Path>,
{
Ok(path
.as_ref()
.absolutize()
.map_err(Error::InvalidPath)?
.to_path_buf())
}
fn path_to_string(path: impl AsRef<Path>) -> Result<String, Error> {
path.as_ref()
.to_str()
.map(|v| v.to_string())
.ok_or_else(|| {
let e = std::io::Error::new(
std::io::ErrorKind::Other,
format!("invalid UTF-8 string: {}", path.as_ref().to_string_lossy()),
);
Error::InvalidPath(e)
})
}
pub fn abs_string<P>(path: P) -> Result<String, Error>
where
P: AsRef<Path>,
{
path_to_string(abs_path_buf(path)?)
}
fn xdg_runtime_dir() -> String {
env::var("XDG_RUNTIME_DIR")
.unwrap_or_else(|_| abs_string(env::temp_dir()).unwrap_or_else(|_| ".".to_string()))
}
#[cfg(not(feature = "async"))]
pub fn write_value_to_temp_file<T: Serialize>(value: &T) -> Result<(NamedTempFile, String), Error> {
let filename = format!("{}/runc-process-{}", xdg_runtime_dir(), Uuid::new_v4());
let mut temp_file = Builder::new()
.prefix(&filename)
.rand_bytes(0)
.tempfile()
.map_err(Error::SpecFileCreationFailed)?;
let f = temp_file.as_file_mut();
let spec_json = serde_json::to_string(value).map_err(Error::JsonDeserializationFailed)?;
f.write(spec_json.as_bytes())
.map_err(Error::SpecFileCreationFailed)?;
f.flush().map_err(Error::SpecFileCreationFailed)?;
Ok((temp_file, filename))
}
#[cfg(feature = "async")]
pub async fn write_value_to_temp_file<T: Serialize>(value: &T) -> Result<String, Error> {
let filename = format!("{}/runc-process-{}", xdg_runtime_dir(), Uuid::new_v4());
let mut f = tokio::fs::OpenOptions::new()
.create(true)
.truncate(true)
.write(true)
.open(&filename)
.await
.map_err(Error::FileSystemError)?;
let spec_json = serde_json::to_string(value).map_err(Error::JsonDeserializationFailed)?;
f.write_all(spec_json.as_bytes())
.await
.map_err(Error::SpecFileCreationFailed)?;
f.flush().await.map_err(Error::SpecFileCreationFailed)?;
Ok(filename)
}
pub fn binary_path<P>(path: P) -> Option<PathBuf>
where
P: AsRef<Path>,
{
env::var_os("PATH").and_then(|paths| {
env::split_paths(&paths).find_map(|dir| {
let full_path = dir.join(path.as_ref());
if full_path.is_file() {
Some(full_path)
} else {
None
}
})
})
}