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