use std::{
path::{Path, PathBuf},
str::FromStr,
};
use serde::Serialize;
use super::{app_home_dir, app_home_dir_sync, ensure_dir_sync};
use crate::fs::{ensure_dir, error::Error};
pub const FERMAH_HOST_CONFIG_ENV_VAR: &str = "FERMAH_HOST_CONFIG";
const ASSETS_DIRECTORY: &str = "assets";
pub async fn app_home_dir_at_host() -> Result<Option<PathBuf>, Error> {
if let Ok(path) = std::env::var(FERMAH_HOST_CONFIG_ENV_VAR) {
let base: PathBuf = path.into();
ensure_dir(&base, None).await?;
Ok(Some(base))
} else {
Ok(None)
}
}
pub fn app_home_dir_at_host_sync() -> Result<Option<PathBuf>, Error> {
if let Ok(path) = std::env::var(FERMAH_HOST_CONFIG_ENV_VAR) {
let base: PathBuf = path.into();
ensure_dir_sync(&base, None)?;
Ok(Some(base))
} else {
Ok(None)
}
}
#[derive(Debug, Clone, Hash, PartialEq, Serialize)]
pub struct PathBufMountable {
local: PathBuf,
host: Option<PathBuf>,
}
impl PathBufMountable {
pub fn new(local: PathBuf, host: Option<PathBuf>) -> Self {
Self { local, host }
}
pub fn local(&self) -> &Path {
&self.local
}
pub fn at_host(&self) -> &Path {
self.host.as_ref().unwrap_or(&self.local)
}
}
impl From<PathBufMirror> for PathBufMountable {
fn from(value: PathBufMirror) -> Self {
Self {
local: value.local(),
host: Some(value.at_host()),
}
}
}
#[derive(Debug, Clone, Hash, PartialEq)]
pub struct PathBufMirror {
root: PathBuf,
root_at_host: Option<PathBuf>,
postfix: PathBuf,
}
impl PathBufMirror {
pub fn new(postfix: PathBuf, root: PathBuf, root_at_host: Option<PathBuf>) -> Self {
Self {
root,
root_at_host,
postfix,
}
}
pub async fn new_at_assets(postfix: PathBuf) -> Result<Self, Error> {
Ok(Self::new(
postfix,
app_home_dir().await?.join(ASSETS_DIRECTORY),
app_home_dir_at_host()
.await?
.map(|p| p.join(ASSETS_DIRECTORY)),
))
}
pub fn new_at_assets_sync(postfix: PathBuf) -> Result<Self, Error> {
Ok(Self::new(
postfix,
app_home_dir_sync()?.join(ASSETS_DIRECTORY),
app_home_dir_at_host_sync()?.map(|p| p.join(ASSETS_DIRECTORY)),
))
}
pub async fn from_str(s: &str) -> Result<Self, Error> {
let postfix = PathBuf::from_str(s).expect("Infalliable");
Self::new_at_assets(postfix).await
}
pub fn from_str_sync(s: &str) -> Result<Self, Error> {
let postfix = PathBuf::from_str(s).expect("Infalliable");
Self::new_at_assets_sync(postfix)
}
pub fn local(&self) -> PathBuf {
self.root.join(&self.postfix)
}
pub fn at_host(&self) -> PathBuf {
self.root_at_host
.as_ref()
.unwrap_or(&self.root)
.join(&self.postfix)
}
pub fn join<P>(&self, path: P) -> Self
where
P: AsRef<Path>,
{
let postfix = self.postfix.join(path);
Self {
root_at_host: self.root_at_host.clone(),
root: self.root.clone(),
postfix,
}
}
pub fn push<P>(&mut self, path: P)
where
P: AsRef<Path>,
{
self.postfix.push(path);
}
pub fn exists(&self) -> bool {
self.local().exists()
}
}
pub mod path_buf_mirror_serde {
use serde::{Deserialize, Deserializer, Serializer};
use super::PathBufMirror;
pub fn serialize<S>(x: &PathBufMirror, s: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
s.serialize_str(
x.postfix
.to_str()
.expect("If it is not serializable it is okay, as this is only a dev feature"),
)
}
pub fn deserialize<'de, D>(d: D) -> Result<PathBufMirror, D::Error>
where
D: Deserializer<'de>,
{
let buf = String::deserialize(d)?;
PathBufMirror::from_str_sync(&buf).map_err(serde::de::Error::custom)
}
}
pub mod path_buf_mountable_serde {
use std::{path::PathBuf, str::FromStr};
use serde::{Deserialize, Deserializer, Serializer};
use super::PathBufMountable;
pub fn serialize<S>(x: &PathBufMountable, s: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
s.serialize_str(
x.local()
.to_str()
.expect("If it is not serializable it is okay, as this is only a dev feature"),
)
}
pub fn deserialize<'de, D>(d: D) -> Result<PathBufMountable, D::Error>
where
D: Deserializer<'de>,
{
let buf = String::deserialize(d)?;
Ok(PathBufMountable {
local: PathBuf::from_str(&buf).map_err(serde::de::Error::custom)?,
host: None,
})
}
}