use std::path::PathBuf;
use crate::error::{Error, Result};
pub const REGISTRY_DEFAULT: &str = "default";
pub const DEFAULT_REGISTRY_URL: &str = "https://github.com/ryanravn/ryra-registry.git";
pub const REGISTRY_DIR_ENV: &str = "RYRA_REGISTRY_DIR";
pub const CONFIG_DIR_ENV: &str = "RYRA_CONFIG_DIR";
pub const DATA_DIR_ENV: &str = "RYRA_DATA_DIR";
pub(crate) fn data_dir_override() -> Option<PathBuf> {
match std::env::var_os(DATA_DIR_ENV) {
Some(v) if !v.is_empty() => Some(PathBuf::from(v)),
_ => None,
}
}
pub(crate) fn home_dir() -> Result<PathBuf> {
dirs::home_dir()
.or_else(|| std::env::var("HOME").ok().map(PathBuf::from))
.ok_or(Error::HomeDirNotFound)
}
pub fn service_data_root() -> Result<PathBuf> {
if let Some(dir) = data_dir_override() {
return Ok(dir);
}
let base = match dirs::data_dir() {
Some(d) => d,
None => home_dir()?.join(".local").join("share"),
};
Ok(base.join("services"))
}
pub fn service_home(service_name: &str) -> Result<PathBuf> {
if service_name.is_empty()
|| service_name == "."
|| service_name == ".."
|| service_name.contains('/')
|| service_name.contains('\\')
{
return Err(Error::ConfigValidation(format!(
"invalid service name '{service_name}': names must not be paths"
)));
}
Ok(service_data_root()?.join(service_name))
}
pub fn metadata_path(service_name: &str) -> Result<PathBuf> {
Ok(service_home(service_name)?.join("metadata.toml"))
}
pub fn quadlet_dir() -> Result<PathBuf> {
let base = match dirs::config_dir() {
Some(d) => d,
None => home_dir()?.join(".config"),
};
Ok(base.join("containers").join("systemd"))
}
pub fn systemd_user_dir() -> Result<PathBuf> {
let base = match dirs::config_dir() {
Some(d) => d,
None => home_dir()?.join(".config"),
};
Ok(base.join("systemd").join("user"))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn service_home_rejects_path_like_names() {
for bad in [
"/home/user/code/ryra-api",
".",
"..",
"../x",
"a/b",
"a\\b",
"",
] {
assert!(
service_home(bad).is_err(),
"expected '{bad}' to be rejected as a service name"
);
}
}
#[test]
fn service_home_accepts_plain_names() {
for good in ["forgejo", "ryra-api", "node-exporter", "caddy"] {
let home = service_home(good).expect("plain name should resolve");
assert!(home.ends_with(good));
}
}
}