Skip to main content

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}