arachnid_cli/config/kinds/
workspace.rs

1/*
2    Appellation: workspace <config>
3    Contrib: FL03 <jo3mccain@icloud.com>
4*/
5use crate::config::Scope;
6use std::path::PathBuf;
7
8fn _application() -> String {
9    std::env::current_exe()
10        .map(|path| path.display().to_string())
11        .unwrap_or(crate::config::APP_NAME.to_string())
12}
13
14fn _application_option() -> Option<String> {
15    Some(_application())
16}
17
18fn _artifacts() -> String {
19    crate::config::DEFAULT_DIR_ARTIFACTS.to_string()
20}
21
22fn _default_scope() -> Scope {
23    Scope::from_workdir(crate::config::DEFAULT_WORKDIR)
24}
25
26fn _default_context() -> Option<String> {
27    Some(".".to_string())
28}
29
30fn _default_workdir() -> PathBuf {
31    std::env::current_dir().unwrap_or(crate::config::DEFAULT_WORKDIR.into())
32}
33
34/// [Scope] is a structure containing all of the information required for the service to operate.
35#[derive(
36    Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, serde::Deserialize, serde::Serialize,
37)]
38#[serde(default)]
39pub struct WorkspaceConfig {
40    /// the path to the executable
41    #[serde(default = "_application")]
42    pub(crate) application: String,
43    /// the path to the directory used to store any artifacts
44    #[serde(default = "_artifacts")]
45    pub(crate) artifacts: String,
46    /// a path to another build-script
47    pub(crate) build: Option<String>,
48    // The root directory of the service
49    #[serde(default = "_default_workdir")]
50    pub(crate) workdir: PathBuf,
51}
52
53impl WorkspaceConfig {
54    pub fn new<T>(workdir: T) -> Self
55    where
56        PathBuf: From<T>,
57    {
58        Self {
59            application: _application(),
60            artifacts: _artifacts(),
61            build: None,
62            workdir: workdir.into(),
63        }
64    }
65    /// returns a reference to the path of the artifacts directory, as a str
66    pub fn artifacts(&self) -> &str {
67        &self.artifacts
68    }
69    /// returns the name of the application
70    pub fn application(&self) -> &str {
71        &self.application
72    }
73    /// returns the configured build directory
74    pub fn build(&self) -> Option<&str> {
75        self.build.as_deref()
76    }
77    /// returns a reference to the workdir PathBuf
78    pub const fn workdir(&self) -> &PathBuf {
79        &self.workdir
80    }
81    /// consumes the workspace config to create another with the given artifacts directory
82    pub fn with_artifacts<T>(self, artifacts: T) -> Self
83    where
84        T: ToString,
85    {
86        Self {
87            artifacts: artifacts.to_string(),
88            ..self
89        }
90    }
91    /// consumes the workspace config to create another with the given application name
92    pub fn with_application<T>(self, application: T) -> Self
93    where
94        T: ToString,
95    {
96        Self {
97            application: application.to_string(),
98            ..self
99        }
100    }
101    /// consumes the workspace config to create another with the given build path
102    pub fn with_build<T>(self, build: T) -> Self
103    where
104        T: ToString,
105    {
106        Self {
107            build: Some(build.to_string()),
108            ..self
109        }
110    }
111    /// consumes the workspace config to create another with the given workdir
112    pub fn with_workdir(self, workdir: PathBuf) -> Self {
113        Self { workdir, ..self }
114    }
115
116    /// update the artifacts directory
117    pub fn set_artifacts<T>(&mut self, artifacts: T)
118    where
119        T: ToString,
120    {
121        self.artifacts = artifacts.to_string()
122    }
123    /// update the application name
124    pub fn set_application<T>(&mut self, application: T)
125    where
126        T: ToString,
127    {
128        self.application = application.to_string()
129    }
130    /// update the build path
131    pub fn set_build<T>(&mut self, build: T)
132    where
133        T: ToString,
134    {
135        self.build = Some(build.to_string())
136    }
137    /// change the current directory to the workspace
138    pub fn set_current_dir(&self) {
139        let path = self.workdir();
140        debug_assert!(self.is_workdir_valid());
141        tracing::info!("setting current directory to: {p}", p = path.display());
142        std::env::set_current_dir(path).unwrap();
143    }
144    /// set the working directory of the scope
145    pub fn set_workdir<T>(&mut self, workdir: T)
146    where
147        PathBuf: From<T>,
148    {
149        self.workdir = workdir.into();
150    }
151    /// if the workdir is set, set it to the given workdir
152    pub fn set_workdir_option<T>(&mut self, workdir: Option<T>)
153    where
154        PathBuf: From<T>,
155    {
156        workdir.map(|w| self.set_workdir(w));
157    }
158    /// check if the workdir is valid
159    pub fn is_workdir_valid(&self) -> bool {
160        self.workdir().is_dir()
161    }
162    /// get the path to the application binary; if unspecified, the current executable is used
163    /// otherwise, the path is assumed to be within the workspaces current directory.
164    pub fn path_to_application(&self) -> PathBuf {
165        let path = if self.application().is_empty() {
166            std::env::current_exe().expect("unable to determine the location of the executable")
167        } else {
168            self.workdir().join(self.application())
169        };
170        // ensure the path is a file
171        debug_assert!(path.is_file());
172        // return the path
173        path
174    }
175    /// get the path to the artifacts directory; the artifacts directory assumed to be a
176    /// subdirectory of the workspace and is used to store various build artifacts, logs,
177    /// temporary files, etc.
178    pub fn path_to_artifacts(&self) -> PathBuf {
179        self.workdir().join(self.artifacts())
180    }
181}
182
183impl Default for WorkspaceConfig {
184    fn default() -> Self {
185        Self::new(crate::config::DEFAULT_WORKDIR)
186    }
187}
188
189impl core::fmt::Display for WorkspaceConfig {
190    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
191        f.write_str(serde_json::to_string(self).unwrap().as_str())
192    }
193}