use crate::filesystem::mounts::{DatasetMetadata, FilesystemType};
use crate::library::results::{HttmError, HttmResult};
use std::borrow::Cow;
use std::collections::BTreeMap;
use std::ops::Deref;
use std::path::Path;
use std::sync::Arc;
#[derive(Debug, Clone)]
pub struct RemotePathAndFsType {
remote_dir: Arc<Path>,
#[allow(dead_code)]
fs_type: FilesystemType,
}
impl RemotePathAndFsType {
pub fn remote_dir(&self) -> &Path {
&self.remote_dir
}
}
#[derive(Debug, Clone)]
pub struct MapOfAliases {
inner: BTreeMap<Box<Path>, RemotePathAndFsType>,
}
impl From<BTreeMap<Box<Path>, RemotePathAndFsType>> for MapOfAliases {
fn from(map: BTreeMap<Box<Path>, RemotePathAndFsType>) -> Self {
Self { inner: map }
}
}
impl Deref for MapOfAliases {
type Target = BTreeMap<Box<Path>, RemotePathAndFsType>;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl MapOfAliases {
pub fn new(
map_of_datasets: &BTreeMap<Arc<Path>, DatasetMetadata>,
opt_raw_aliases: Option<Vec<Cow<str>>>,
opt_remote_dir: Option<&String>,
opt_local_dir: Option<&String>,
pwd: &Path,
) -> HttmResult<Option<MapOfAliases>> {
let alias_values: Option<Vec<Cow<str>>> = match std::env::var_os("HTTM_MAP_ALIASES") {
Some(env_map_alias) => Some(
env_map_alias
.to_string_lossy()
.split_terminator(',')
.map(|s: &str| Cow::Owned(s.to_string()))
.collect(),
),
None => opt_raw_aliases,
};
let opt_snap_dir: Option<Box<Path>> = if let Some(value) = opt_remote_dir {
Some(Box::from(Path::new(&value)))
} else if std::env::var_os("HTTM_REMOTE_DIR").is_some() {
std::env::var_os("HTTM_REMOTE_DIR").map(|s| Box::from(Path::new(&s)))
} else {
std::env::var_os("HTTM_SNAP_POINT").map(|s| Box::from(Path::new(&s)))
};
if alias_values.is_none() && opt_snap_dir.is_none() {
return Ok(None);
}
let opt_local_dir: Option<Box<Path>> = if let Some(value) = opt_local_dir {
Some(Box::from(Path::new(&value)))
} else {
std::env::var_os("HTTM_LOCAL_DIR").map(|s| Box::from(Path::new(&s)))
};
let mut aliases_iter: Vec<(Box<Path>, Box<Path>)> = match alias_values {
Some(input_aliases) => {
let res: Option<Vec<(Box<Path>, Box<Path>)>> = input_aliases
.iter()
.map(|alias| {
alias
.split_once(':')
.map(|(first, rest)| (Path::new(first).into(), Path::new(rest).into()))
})
.collect();
res.ok_or_else(|| {
HttmError::new(
"Must use specified delimiter (':') between aliases for MAP_ALIASES.",
)
})?
}
None => Vec::new(),
};
let snap_point = opt_snap_dir.map(|snap_dir| {
let local_dir = opt_local_dir.unwrap_or_else(|| pwd.into());
(snap_dir, local_dir)
});
if let Some(value) = snap_point {
aliases_iter.push(value)
}
let map_of_aliases: BTreeMap<Box<Path>, RemotePathAndFsType> = aliases_iter
.into_iter()
.filter_map(|(local_dir, snap_dir)| {
match map_of_datasets
.get_key_value(snap_dir.as_ref())
.map(|(k, _v)| k.clone())
{
Some(_snap_dir) if !local_dir.exists() => {
eprintln!(
"WARN: An alias path specified does not exist, or is not mounted: {:?}",
local_dir
);
return None;
}
Some(snap_dir) => Some((local_dir, snap_dir)),
None => {
eprintln!(
"WARN: An alias path specified does not exist, or is not mounted: {:?}",
snap_dir
);
None
}
}
})
.filter_map(|(local_dir, remote_dir)| {
FilesystemType::new(&remote_dir).map(|fs_type| {
(
local_dir,
RemotePathAndFsType {
remote_dir,
fs_type,
},
)
})
})
.collect();
if map_of_aliases.is_empty() {
return Ok(None);
}
Ok(Some(Self {
inner: map_of_aliases,
}))
}
}