use std::{
borrow::Cow,
env,
error::Error,
fmt,
io,
path::{Path, PathBuf},
time::{Duration, Instant},
};
use lazycell::LazyCell;
use crate::{
drop::name::Query,
install::InstallTarget,
};
#[derive(Clone, Debug)]
pub struct RtConfig {
pub start_time: Instant,
pub current_dir: PathBuf,
pub user_home: PathBuf,
pub ocean_home: LazyCell<PathBuf>,
}
impl RtConfig {
#[inline]
pub fn create() -> Result<Self, CreateError> {
Self::create_at(Instant::now())
}
pub fn create_at(start_time: Instant) -> Result<Self, CreateError> {
Ok(Self {
start_time,
current_dir: env::current_dir()
.map_err(|e| CreateError::MissingCurrentDir(e))?,
user_home: dirs::home_dir()
.ok_or_else(|| CreateError::MissingUserHome)?,
ocean_home: LazyCell::new(),
})
}
#[inline]
pub fn time_elapsed(&self) -> Duration {
self.start_time.elapsed()
}
#[inline]
pub fn current_dir(&self) -> &Path {
&self.current_dir
}
pub fn ocean_home(&self) -> &Path {
self.ocean_home.borrow_with(|| {
self.user_home()
.join(".ocean")
})
}
#[inline]
pub fn user_home(&self) -> &Path {
&self.user_home
}
pub fn credentials_path(&self) -> PathBuf {
self.ocean_home()
.join("credentials.toml")
}
pub fn bin_dir(&self) -> PathBuf {
#[cfg(unix)]
{
self.ocean_home().join("bin")
}
#[cfg(windows)]
unimplemented!("TODO: Write & test on Windows :)");
}
pub fn cache_dir(&self) -> PathBuf {
self.ocean_home().join("cache")
}
pub fn tarball_cache_path(&self, query: Query<&str>) -> PathBuf {
let mut path = self.cache_dir();
path.push(query.tarball_name());
path
}
pub fn drops_dir(
&self,
target: &InstallTarget,
) -> Cow<'static, Path> {
#[cfg(unix)]
match target {
InstallTarget::CurrentUser => {
Cow::Owned(self.ocean_home().join("drops"))
},
InstallTarget::SpecificUser(username) => {
unimplemented!("TODO: Get base directory for {:?}", username);
},
InstallTarget::Global => {
if cfg!(target_os = "macos") {
Cow::Borrowed("/Library/Ocean/drops".as_ref())
} else {
Cow::Borrowed("/usr/local/Ocean/drops".as_ref())
}
},
}
#[cfg(windows)]
unimplemented!("TODO: Write & test on Windows :)");
}
}
#[derive(Debug)]
pub enum CreateError {
MissingCurrentDir(io::Error),
MissingUserHome,
}
impl fmt::Display for CreateError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::MissingCurrentDir(error) => {
match error.kind() {
io::ErrorKind::NotFound => write!(
f,
"Current directory does not exist",
),
io::ErrorKind::PermissionDenied => write!(
f,
"Not enough permissions to access current directory",
),
_ => write!(
f,
"Could not get current directory: {}",
error,
),
}
},
Self::MissingUserHome => {
write!(f, "Could not get current user's home")
},
}
}
}
impl Error for CreateError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
Self::MissingCurrentDir(error) => Some(error),
Self::MissingUserHome => None,
}
}
}