torrust_tracker_deployer_lib/domain/environment/internal_config.rs
1//! Internal Config Module
2//!
3//! This module contains the `InternalConfig` struct which holds internal
4//! configuration derived from user inputs.
5//!
6//! ## Purpose
7//!
8//! Internal configuration represents automatically derived paths and settings
9//! that are calculated from user inputs. These are implementation details not
10//! directly controlled by users.
11//!
12//! ## Semantic Category
13//!
14//! **Internal Config** fields are:
15//! - Calculated from user inputs
16//! - Not directly controlled by users
17//! - Examples: build directory, data directory
18//!
19//! Add new fields here when: Need internal paths or derived configuration.
20
21use crate::domain::environment::EnvironmentName;
22use crate::domain::provider::Provider;
23use serde::{Deserialize, Serialize};
24use std::path::PathBuf;
25
26/// Base directory name for user data
27const DATA_DIR_NAME: &str = "data";
28
29/// Base directory name for build artifacts
30const BUILD_DIR_NAME: &str = "build";
31
32/// Internal paths and configuration derived from user inputs
33///
34/// This struct contains fields that are derived automatically from user inputs
35/// and are not directly controlled by users. These represent internal
36/// implementation details for organizing build artifacts and data.
37///
38/// # Examples
39///
40/// ```rust
41/// use torrust_tracker_deployer_lib::domain::environment::internal_config::InternalConfig;
42/// use std::path::PathBuf;
43///
44/// let internal_config = InternalConfig {
45/// build_dir: PathBuf::from("build/production"),
46/// data_dir: PathBuf::from("data/production"),
47/// };
48/// ```
49#[derive(Debug, Clone, Serialize, Deserialize)]
50pub struct InternalConfig {
51 /// Build directory for this environment (derived from environment name)
52 pub build_dir: PathBuf,
53
54 /// Data directory for this environment (derived from environment name)
55 pub data_dir: PathBuf,
56}
57
58impl InternalConfig {
59 /// Creates a new `InternalConfig` with auto-generated directories
60 ///
61 /// # Arguments
62 ///
63 /// * `env_name` - The environment name used to generate directories
64 ///
65 /// # Returns
66 ///
67 /// A new `InternalConfig` with:
68 /// - `data_dir`: `./data/{env_name}`
69 /// - `build_dir`: `./build/{env_name}`
70 ///
71 /// # Examples
72 ///
73 /// ```rust
74 /// use torrust_tracker_deployer_lib::domain::environment::internal_config::InternalConfig;
75 /// use torrust_tracker_deployer_lib::domain::environment::EnvironmentName;
76 /// use std::path::PathBuf;
77 ///
78 /// let env_name = EnvironmentName::new("production".to_string())?;
79 /// let config = InternalConfig::new(&env_name);
80 ///
81 /// assert_eq!(config.data_dir, PathBuf::from("./data/production"));
82 /// assert_eq!(config.build_dir, PathBuf::from("./build/production"));
83 /// # Ok::<(), Box<dyn std::error::Error>>(())
84 /// ```
85 #[must_use]
86 pub fn new(env_name: &EnvironmentName) -> Self {
87 let data_dir = PathBuf::from(".")
88 .join(DATA_DIR_NAME)
89 .join(env_name.as_str());
90
91 let build_dir = PathBuf::from(".")
92 .join(BUILD_DIR_NAME)
93 .join(env_name.as_str());
94
95 Self {
96 build_dir,
97 data_dir,
98 }
99 }
100
101 /// Creates a new `InternalConfig` with directories relative to a working directory
102 ///
103 /// This version creates absolute paths by prepending the working directory
104 /// to the generated data and build directories.
105 ///
106 /// # Arguments
107 ///
108 /// * `env_name` - The environment name used to generate directories
109 /// * `working_dir` - The base working directory for operations
110 ///
111 /// # Returns
112 ///
113 /// A new `InternalConfig` with:
114 /// - `data_dir`: `{working_dir}/data/{env_name}`
115 /// - `build_dir`: `{working_dir}/build/{env_name}`
116 ///
117 /// # Examples
118 ///
119 /// ```rust
120 /// use torrust_tracker_deployer_lib::domain::environment::internal_config::InternalConfig;
121 /// use torrust_tracker_deployer_lib::domain::environment::EnvironmentName;
122 /// use std::path::PathBuf;
123 ///
124 /// let env_name = EnvironmentName::new("production".to_string())?;
125 /// let working_dir = PathBuf::from("/opt/deployments");
126 /// let config = InternalConfig::with_working_dir(&env_name, &working_dir);
127 ///
128 /// assert_eq!(config.data_dir, PathBuf::from("/opt/deployments/data/production"));
129 /// assert_eq!(config.build_dir, PathBuf::from("/opt/deployments/build/production"));
130 ///
131 /// # Ok::<(), Box<dyn std::error::Error>>(())
132 /// ```
133 #[must_use]
134 pub fn with_working_dir(env_name: &EnvironmentName, working_dir: &std::path::Path) -> Self {
135 // Generate environment-specific directories relative to working directory
136 let data_dir = working_dir.join(DATA_DIR_NAME).join(env_name.as_str());
137 let build_dir = working_dir.join(BUILD_DIR_NAME).join(env_name.as_str());
138
139 Self {
140 build_dir,
141 data_dir,
142 }
143 }
144
145 /// Returns the templates directory for this environment
146 ///
147 /// Path: `data/{env_name}/templates/`
148 #[must_use]
149 pub fn templates_dir(&self) -> PathBuf {
150 self.data_dir.join(super::TEMPLATES_DIR_NAME)
151 }
152
153 /// Returns the traces directory for this environment
154 ///
155 /// Path: `data/{env_name}/traces/`
156 #[must_use]
157 pub fn traces_dir(&self) -> PathBuf {
158 self.data_dir.join(super::TRACES_DIR_NAME)
159 }
160
161 /// Returns the ansible build directory
162 ///
163 /// Path: `build/{env_name}/ansible`
164 #[must_use]
165 pub fn ansible_build_dir(&self) -> PathBuf {
166 self.build_dir.join(super::ANSIBLE_DIR_NAME)
167 }
168
169 /// Returns the `OpenTofu` build directory for a specific provider
170 ///
171 /// Path: `build/{env_name}/tofu/{provider_name}`
172 ///
173 /// # Arguments
174 ///
175 /// * `provider` - The provider type (LXD, Hetzner, etc.)
176 #[must_use]
177 pub fn tofu_build_dir_for_provider(&self, provider: Provider) -> PathBuf {
178 self.build_dir
179 .join(super::TOFU_DIR_NAME)
180 .join(provider.as_str())
181 }
182
183 /// Returns the ansible templates directory
184 ///
185 /// Path: `data/{env_name}/templates/ansible`
186 #[must_use]
187 pub fn ansible_templates_dir(&self) -> PathBuf {
188 self.templates_dir().join(super::ANSIBLE_DIR_NAME)
189 }
190
191 /// Returns the tofu templates directory
192 ///
193 /// Path: `data/{env_name}/templates/tofu`
194 #[must_use]
195 pub fn tofu_templates_dir(&self) -> PathBuf {
196 self.templates_dir().join(super::TOFU_DIR_NAME)
197 }
198}