use std::path::{Path, PathBuf};
pub struct ZLayerDirs {
data_dir: PathBuf,
}
impl ZLayerDirs {
pub fn new(data_dir: impl Into<PathBuf>) -> Self {
Self {
data_dir: data_dir.into(),
}
}
pub fn system_default() -> Self {
Self::new(Self::default_data_dir())
}
pub fn default_data_dir() -> PathBuf {
#[cfg(target_os = "macos")]
{
home_dir_or_tmp().join(".zlayer")
}
#[cfg(target_os = "windows")]
{
if let Some(local_app_data) = std::env::var_os("LOCALAPPDATA") {
PathBuf::from(local_app_data).join("ZLayer")
} else {
PathBuf::from(r"C:\ProgramData\ZLayer")
}
}
#[cfg(not(any(target_os = "macos", target_os = "windows")))]
{
if is_root() {
PathBuf::from("/var/lib/zlayer")
} else {
home_dir_or_tmp().join(".zlayer")
}
}
}
pub fn default_run_dir() -> PathBuf {
#[cfg(not(any(target_os = "macos", target_os = "windows")))]
{
PathBuf::from("/var/run/zlayer")
}
#[cfg(any(target_os = "macos", target_os = "windows"))]
{
Self::default_data_dir().join("run")
}
}
pub fn default_log_dir() -> PathBuf {
#[cfg(not(any(target_os = "macos", target_os = "windows")))]
{
PathBuf::from("/var/log/zlayer")
}
#[cfg(any(target_os = "macos", target_os = "windows"))]
{
Self::default_data_dir().join("logs")
}
}
pub fn default_socket_path() -> String {
#[cfg(target_os = "windows")]
{
"tcp://127.0.0.1:3669".to_string()
}
#[cfg(not(target_os = "windows"))]
{
#[cfg(target_os = "macos")]
{
Self::default_data_dir()
.join("run")
.join("zlayer.sock")
.to_string_lossy()
.into_owned()
}
#[cfg(not(target_os = "macos"))]
{
"/var/run/zlayer.sock".to_string()
}
}
}
pub fn default_binary_dir() -> PathBuf {
#[cfg(unix)]
{
let probe = PathBuf::from("/usr/local/bin/.zlayer_write_probe");
if std::fs::write(&probe, b"").is_ok() {
let _ = std::fs::remove_file(&probe);
return PathBuf::from("/usr/local/bin");
}
}
let dirs = Self::system_default();
let bin_dir = dirs.bin();
let _ = std::fs::create_dir_all(&bin_dir);
bin_dir
}
pub fn data_dir(&self) -> &Path {
&self.data_dir
}
pub fn containers(&self) -> PathBuf {
self.data_dir.join("containers")
}
pub fn rootfs(&self) -> PathBuf {
self.data_dir.join("rootfs")
}
pub fn bundles(&self) -> PathBuf {
self.data_dir.join("bundles")
}
pub fn cache(&self) -> PathBuf {
self.data_dir.join("cache")
}
pub fn volumes(&self) -> PathBuf {
self.data_dir.join("volumes")
}
pub fn wasm(&self) -> PathBuf {
self.data_dir.join("wasm")
}
pub fn wasm_compiled(&self) -> PathBuf {
self.data_dir.join("wasm").join("compiled")
}
pub fn secrets(&self) -> PathBuf {
self.data_dir.join("secrets")
}
pub fn certs(&self) -> PathBuf {
self.data_dir.join("certs")
}
pub fn raft(&self) -> PathBuf {
self.data_dir.join("raft")
}
pub fn admin_password(&self) -> PathBuf {
self.data_dir.join("admin_password")
}
pub fn daemon_json(&self) -> PathBuf {
self.data_dir.join("daemon.json")
}
pub fn logs(&self) -> PathBuf {
self.data_dir.join("logs")
}
pub fn vms(&self) -> PathBuf {
self.data_dir.join("vms")
}
pub fn images(&self) -> PathBuf {
self.data_dir.join("images")
}
pub fn bin(&self) -> PathBuf {
self.data_dir.join("bin")
}
pub fn toolchain_cache(&self) -> PathBuf {
self.data_dir.join("toolchain-cache")
}
pub fn tmp(&self) -> PathBuf {
self.data_dir.join("tmp")
}
}
fn home_dir_or_tmp() -> PathBuf {
std::env::var_os("HOME")
.map(PathBuf::from)
.unwrap_or_else(|| PathBuf::from("/tmp"))
}
#[cfg(not(any(target_os = "macos", target_os = "windows")))]
fn is_root() -> bool {
#[cfg(unix)]
{
nix::unistd::geteuid().is_root()
}
#[cfg(not(unix))]
{
false
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn subdirectories_are_relative_to_data_dir() {
let dirs = ZLayerDirs::new("/test/data");
assert_eq!(dirs.containers(), PathBuf::from("/test/data/containers"));
assert_eq!(dirs.rootfs(), PathBuf::from("/test/data/rootfs"));
assert_eq!(dirs.bundles(), PathBuf::from("/test/data/bundles"));
assert_eq!(dirs.cache(), PathBuf::from("/test/data/cache"));
assert_eq!(dirs.volumes(), PathBuf::from("/test/data/volumes"));
assert_eq!(dirs.wasm(), PathBuf::from("/test/data/wasm"));
assert_eq!(
dirs.wasm_compiled(),
PathBuf::from("/test/data/wasm/compiled")
);
assert_eq!(dirs.secrets(), PathBuf::from("/test/data/secrets"));
assert_eq!(dirs.certs(), PathBuf::from("/test/data/certs"));
assert_eq!(dirs.raft(), PathBuf::from("/test/data/raft"));
assert_eq!(
dirs.admin_password(),
PathBuf::from("/test/data/admin_password")
);
assert_eq!(dirs.daemon_json(), PathBuf::from("/test/data/daemon.json"));
assert_eq!(dirs.logs(), PathBuf::from("/test/data/logs"));
assert_eq!(dirs.vms(), PathBuf::from("/test/data/vms"));
assert_eq!(dirs.images(), PathBuf::from("/test/data/images"));
assert_eq!(dirs.bin(), PathBuf::from("/test/data/bin"));
assert_eq!(
dirs.toolchain_cache(),
PathBuf::from("/test/data/toolchain-cache")
);
assert_eq!(dirs.tmp(), PathBuf::from("/test/data/tmp"));
}
#[test]
fn system_default_uses_default_data_dir() {
let dirs = ZLayerDirs::system_default();
assert_eq!(dirs.data_dir(), ZLayerDirs::default_data_dir().as_path());
}
}