use crate::path;
use crate::prelude::*;
use std::io;
use std::path::{Path, PathBuf};
#[derive(Debug, Error)]
pub enum VarError {
#[error("Environment variable not present.")]
NotPresent,
#[error("Environment variable contains non-Unicode characters.")]
NotUnicode,
}
#[derive(Debug, Error)]
pub enum WorkingPathError {
#[error("The current working directory was not found.")]
NotFound,
#[error("Permission denied reading the current working directory.")]
PermissionDenied,
#[error("The current working directory `{}` is not unicode.", .0.display())]
NotUnicode(PathBuf),
}
static EXE_PATH: Lazy<Result<(String, String), String>> = Lazy::new(|| {
let mut path: String = std::env::current_exe()
.map_err(|err| format!("IO error. {}.", err))?
.to_str()
.ok_or("non-unicode path name.")?
.into();
let file = path::pop(&mut path).unwrap_or_default();
Ok((path, file))
});
pub fn exe_name() -> &'static str {
&EXE_PATH.as_ref().expect("Failed to determine path to current executable").1
}
pub fn exe_path() -> &'static str {
&EXE_PATH.as_ref().expect("Failed to determine path to current executable").0
}
pub fn project_path() -> Option<&'static str> {
static PATH: Lazy<Option<&'static str>> = Lazy::new(|| {
let value = var("CARGO_MANIFEST_DIR").ok()?;
Some(Box::leak(value.into_boxed_str()))
});
*PATH
}
pub fn var(name: &str) -> Result<String, VarError> {
std::env::var(name).map_err(|err| match err {
std::env::VarError::NotPresent => VarError::NotPresent,
std::env::VarError::NotUnicode(_) => VarError::NotUnicode,
})
}
pub fn working_path() -> Result<String, WorkingPathError> {
let path = std::env::current_dir().map_err(|err| match err.kind() {
io::ErrorKind::NotFound => WorkingPathError::NotFound,
io::ErrorKind::PermissionDenied => WorkingPathError::PermissionDenied,
_ => panic!("{}", err),
})?;
Ok(path.to_str().map(String::from).ok_or(WorkingPathError::NotUnicode(path))?)
}
pub fn workspace_path() -> Option<&'static str> {
static PATH: Lazy<Option<&'static str>> = Lazy::new(|| {
let project_path = project_path()?;
let mut workspace_path: String = project_path.into();
loop {
path::append(&mut workspace_path, "Cargo.lock");
let found = AsRef::<Path>::as_ref(&workspace_path).exists();
path::pop(&mut workspace_path);
if found {
break;
}
if path::pop(&mut workspace_path).is_none() {
workspace_path.replace_range(.., project_path);
break;
}
}
Some(Box::leak(workspace_path.into_boxed_str()))
});
*PATH
}