1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
//! Paths for resources used by the application.
//!
//! Implemented as a trait to support extensibility and customizability, but
//! with a a set of framework conventions.
pub use canonical_path::{CanonicalPath as AbsPath, CanonicalPathBuf as AbsPathBuf};
// Just in case anyone gets confused why `Path` is private
pub use std::path::{Path, PathBuf};
use crate::FrameworkError;
/// Name of the application's secrets directory
pub(crate) const SECRETS_DIR: &str = "secrets";
/// Path to the application's executable.
pub trait ExePath {
/// Get the path to the application's executable
fn exe(&self) -> &AbsPath;
}
/// Path to application's root directory
pub trait RootPath {
/// Get the path to the application's root directory
fn root(&self) -> &AbsPath;
}
/// Path to the application's secrets directory
pub trait SecretsPath {
/// Get the path to the application's secrets directory
fn secrets(&self) -> &AbsPath;
}
/// Standard set of "happy paths" used by Abscissa applications.
///
/// These are not yet finalized, but provide a standard application layout
/// (further expressed in the template) which future Abscissa
/// components/extensions should seek to adhere to.
#[derive(Clone, Debug)]
pub struct StandardPaths {
/// Path to the application's executable.
exe: AbsPathBuf,
/// Path to the application's root directory
root: AbsPathBuf,
/// Path to the application's secrets
secrets: Option<AbsPathBuf>,
}
impl StandardPaths {
/// Compute paths to application resources from the path of the
/// application's executable:
///
/// - `./` (root): application root directory
/// - `./{{~name~}}` (bin): application executable path
/// - `./secrets` (secrets): location of files containing app's secrets
fn from_exe_path<P>(exe_path: P) -> Result<Self, FrameworkError>
where
P: Into<AbsPathBuf>,
{
let exe = exe_path.into();
let root = exe.parent()?;
let secrets = root.join(SECRETS_DIR).ok();
Ok(StandardPaths { exe, root, secrets })
}
}
impl Default for StandardPaths {
// TODO(tarcieri): better error handling for canonicalization failures
fn default() -> Self {
let exe_path = canonical_path::current_exe().unwrap_or_else(|e| {
panic!("error canonicalizing application path: {}", e);
});
Self::from_exe_path(exe_path).unwrap_or_else(|e| {
panic!("error computing application paths: {}", e);
})
}
}
impl ExePath for StandardPaths {
fn exe(&self) -> &AbsPath {
self.exe.as_ref()
}
}
impl RootPath for StandardPaths {
fn root(&self) -> &AbsPath {
self.root.as_ref()
}
}
impl SecretsPath for StandardPaths {
fn secrets(&self) -> &AbsPath {
self.secrets
.as_ref()
.unwrap_or_else(|| {
// TODO(tarcieri): better error handling for this case
panic!("secrets directory does not exist");
})
.as_ref()
}
}