aboutsummaryrefslogtreecommitdiffstats
path: root/src/platform/paths.rs
diff options
context:
space:
mode:
authorFilip Wandzio <contact@philw.dev>2026-02-25 16:10:23 +0100
committerFilip Wandzio <contact@philw.dev>2026-02-25 16:10:23 +0100
commitf7b4b643ebc52a4d72d90d9adbdddc9aa0721e4a (patch)
treec96432be342b02bc0409e5b78b6b5d54afcc7cd6 /src/platform/paths.rs
parent2e10b0713f5369f489d2ababd70108cc359c5d2d (diff)
downloaddml-f7b4b643ebc52a4d72d90d9adbdddc9aa0721e4a.tar.gz
dml-f7b4b643ebc52a4d72d90d9adbdddc9aa0721e4a.zip
Feat: Refactor core download logic with concurrency and async features
Implement basic unit testing Implement automatic java executable switching based on game version Split loader module into smaller modules Implement basic documentation
Diffstat (limited to 'src/platform/paths.rs')
-rw-r--r--src/platform/paths.rs270
1 files changed, 247 insertions, 23 deletions
diff --git a/src/platform/paths.rs b/src/platform/paths.rs
index b430f09..07313fd 100644
--- a/src/platform/paths.rs
+++ b/src/platform/paths.rs
@@ -1,44 +1,268 @@
1use std::{fs::create_dir_all, path::PathBuf}; 1use std::{fs::create_dir_all, path::PathBuf};
2 2
3use crate::{config::Config, errors::McError}; 3use crate::{config::Config, constants::directory, errors::McError};
4 4
5/// ~/.local/share/dml/minecraft 5/// Returns the path to the root Minecraft directory inside the launcher data folder.
6pub fn minecraft_root(cfg: &Config) -> PathBuf { 6///
7/// This directory acts as the root for all Minecraft-related files within the launcher data.
8/// By default, it joins the `minecraft` directory under the data folder (defined by the launcher).
9///
10/// The returned path does not include any specific assets, versions, or libraries directories.
11/// You can use this as the base path to construct other Minecraft-related paths.
12///
13/// # Parameters
14/// - `cfg`: The configuration object (`Config`) containing launcher and Minecraft data folder paths.
15///
16/// # Returns
17/// - A `PathBuf` pointing to the root Minecraft directory.
18pub fn root_directory(cfg: &Config) -> PathBuf {
19 // Remove DEFAULT_LAUNCHER_DIR to avoid duplicate "dml/dml"
7 cfg.data_dir.join("minecraft") 20 cfg.data_dir.join("minecraft")
8} 21}
9 22
10pub fn assets_dir(cfg: &Config) -> PathBuf { 23/// Returns the path to the Minecraft assets directory.
11 minecraft_root(cfg).join("assets") 24///
25/// This is where Minecraft assets such as textures, sounds, and other resources are stored.
26/// The assets directory is located inside the root Minecraft directory and can be used
27/// for accessing game assets.
28///
29/// # Parameters
30/// - `cfg`: The configuration object (`Config`) that contains paths for the launcher and Minecraft data.
31///
32/// # Returns
33/// - A `PathBuf` pointing to the assets directory inside the root Minecraft directory.
34pub fn assets_directory(cfg: &Config) -> PathBuf {
35 root_directory(cfg).join(directory::ASSETS)
12} 36}
13 37
14pub fn game_dir(cfg: &Config) -> PathBuf { minecraft_root(cfg) } 38/// Returns the path to the game directory (same as root directory for now).
15pub fn ensure_dirs(cfg: &Config) -> Result<(), McError> { 39///
16 let root = minecraft_root(cfg); 40/// The game directory currently points to the same location as the root directory.
17 create_dir_all(&root)?; 41/// In future iterations, this could be adjusted if game-specific files need to be handled separately.
18 create_dir_all(root.join("versions"))?; 42///
19 create_dir_all(root.join("libraries"))?; 43/// # Parameters
20 create_dir_all(assets_dir(cfg))?; 44/// - `cfg`: The configuration object (`Config`) that holds the paths to the launcher and Minecraft data.
21 create_dir_all(assets_dir(cfg).join("indexes"))?; 45///
22 create_dir_all(assets_dir(cfg).join("objects"))?; 46/// # Returns
23 create_dir_all(root.join("saves"))?; 47/// - A `PathBuf` pointing to the game directory, which is the same as the root Minecraft directory for now.
48pub fn game_directory(cfg: &Config) -> PathBuf {
49 root_directory(cfg)
50}
51
52/// Ensures that all necessary directories for Minecraft are created.
53///
54/// This function checks if essential directories for Minecraft's file structure exist and creates them
55/// if they do not. This includes directories for versions, libraries, assets, and saves.
56///
57/// # Parameters
58/// - `cfg`: The configuration object (`Config`) that contains paths for the Minecraft data and the required directories.
59///
60/// # Returns
61/// - `Ok(())` if all directories are created successfully.
62/// - `Err(McError)` if an error occurs while creating any directory (such as permission issues).
63///
64/// # Example
65/// ```rust
66/// let cfg = Config { /* configuration values */ };
67/// ensure_directories(&cfg)?;
68/// ```
69///
70/// # Notes
71/// The function creates several directories under the root Minecraft directory, including:
72/// - Root directory
73/// - Versions
74/// - Libraries
75/// - Assets (with subdirectories for `indexes` and `objects`)
76/// - Saves
77/// Each of these directories is essential for managing Minecraft game data and resources.
78pub fn ensure_directories(cfg: &Config) -> Result<(), McError> {
79 let root: PathBuf = root_directory(cfg);
80
81 for dir in [
82 root.clone(),
83 root.join(directory::VERSIONS),
84 root.join(directory::LIBRARIES),
85 assets_directory(cfg),
86 assets_directory(cfg).join(directory::INDEXES),
87 assets_directory(cfg).join(directory::OBJECTS),
88 root.join(directory::SAVES),
89 ] {
90 create_dir_all(dir)?;
91 }
24 92
25 Ok(()) 93 Ok(())
26} 94}
27 95
96/// Returns the path to a specific version directory inside the root Minecraft directory.
97///
98/// This directory is where the game version-specific files (such as the `.jar` file) are stored.
99/// The path is constructed by joining the `versions` directory with the provided version name.
100///
101/// # Parameters
102/// - `cfg`: The configuration object (`Config`) containing paths for the Minecraft data.
103/// - `version`: The version of Minecraft (e.g., "1.18.2") to generate the path for.
104///
105/// # Returns
106/// - A `PathBuf` pointing to the directory for the specified version inside the root Minecraft directory.
28pub fn version_dir(cfg: &Config, version: &str) -> PathBuf { 107pub fn version_dir(cfg: &Config, version: &str) -> PathBuf {
29 minecraft_root(cfg).join("versions").join(version) 108 root_directory(cfg)
109 .join(directory::VERSIONS)
110 .join(version)
30} 111}
31 112
32pub fn client_jar(cfg: &Config, version: &str) -> Result<PathBuf, McError> { 113/// Returns the path to the client `.jar` file for a specific Minecraft version.
33 Ok(version_dir(cfg, version).join(format!("{version}.jar"))) 114///
115/// This file is typically used to run the Minecraft client for a particular version.
116/// The path is constructed by joining the version directory with the name of the `.jar` file.
117///
118/// # Parameters
119/// - `cfg`: The configuration object (`Config`) containing paths for the Minecraft data.
120/// - `version`: The version of Minecraft (e.g., "1.18.2") to generate the path for.
121///
122/// # Returns
123/// - A `PathBuf` pointing to the `.jar` file for the specified version in the version directory.
124pub fn client_jar(cfg: &Config, version: &str) -> PathBuf {
125 version_dir(cfg, version).join(format!("{version}.jar"))
34} 126}
35 127
36pub fn library_file(cfg: &Config, rel_path: &str) -> Result<PathBuf, McError> { 128/// Returns the path to a specific library file inside the library directory.
37 Ok(minecraft_root(cfg) 129///
38 .join("libraries") 130/// This function is used to access library files required for running Minecraft. The `rel_path`
39 .join(rel_path)) 131/// argument specifies the relative path inside the `libraries` directory. It is useful for handling
132/// dependencies or loading required libraries based on the game version.
133///
134/// # Parameters
135/// - `cfg`: The configuration object (`Config`) that contains paths for the Minecraft data.
136/// - `rel_path`: The relative path of the library file inside the `libraries` directory.
137///
138/// # Returns
139/// - A `PathBuf` pointing to the specified library file inside the `libraries` directory.
140pub fn library_file(cfg: &Config, rel_path: &str) -> PathBuf {
141 root_directory(cfg)
142 .join(directory::LIBRARIES)
143 .join(rel_path)
40} 144}
41 145
146/// Returns the path to the natives directory for a specific Minecraft version.
147///
148/// The natives directory contains platform-specific native libraries (e.g., `.dll`, `.so`, `.dylib`)
149/// that Minecraft uses to run the game. This function returns the path to the directory for the
150/// specified version.
151///
152/// # Parameters
153/// - `cfg`: The configuration object (`Config`) containing paths for the Minecraft data.
154/// - `version`: The version of Minecraft (e.g., "1.18.2") to generate the path for.
155///
156/// # Returns
157/// - A `PathBuf` pointing to the natives directory for the specified version.
42pub fn natives_dir(cfg: &Config, version: &str) -> PathBuf { 158pub fn natives_dir(cfg: &Config, version: &str) -> PathBuf {
43 version_dir(cfg, version).join("natives") 159 version_dir(cfg, version).join(directory::NATIVES)
160}
161
162// /// Path to a version’s saves directory.
163// pub fn saves_dir(cfg: &Config) -> PathBuf {
164// minecraft_root(cfg).join(dirs::SAVES)
165// }
166
167#[cfg(test)]
168mod tests {
169 use super::*;
170 use std::path::Path;
171
172 fn test_config(tmp: &Path) -> Config {
173 Config {
174 data_dir: tmp.to_path_buf(),
175 ..Default::default()
176 }
177 }
178
179 #[test]
180 fn root_directory_is_correct() {
181 let tmp = tempfile::tempdir().unwrap();
182 let cfg = test_config(tmp.path());
183
184 let root = root_directory(&cfg);
185 assert_eq!(root, tmp.path().join("minecraft"));
186 }
187
188 #[test]
189 fn assets_directory_is_correct() {
190 let tmp = tempfile::tempdir().unwrap();
191 let cfg = test_config(tmp.path());
192
193 let assets = assets_directory(&cfg);
194 assert_eq!(assets, root_directory(&cfg).join(directory::ASSETS));
195 }
196
197 #[test]
198 fn version_paths_are_correct() {
199 let tmp = tempfile::tempdir().unwrap();
200 let cfg = test_config(tmp.path());
201
202 let version = "1.20.1";
203 assert_eq!(
204 version_dir(&cfg, version),
205 root_directory(&cfg)
206 .join(directory::VERSIONS)
207 .join(version)
208 );
209
210 assert_eq!(
211 client_jar(&cfg, version),
212 version_dir(&cfg, version).join("1.20.1.jar")
213 );
214 }
215
216 #[test]
217 fn library_file_path_is_correct() {
218 let tmp = tempfile::tempdir().unwrap();
219 let cfg = test_config(tmp.path());
220
221 let rel = "com/example/lib.jar";
222 assert_eq!(
223 library_file(&cfg, rel),
224 root_directory(&cfg)
225 .join(directory::LIBRARIES)
226 .join(rel)
227 );
228 }
229
230 #[test]
231 fn natives_dir_path_is_correct() {
232 let tmp = tempfile::tempdir().unwrap();
233 let cfg = test_config(tmp.path());
234
235 let version = "1.20.1";
236 assert_eq!(
237 natives_dir(&cfg, version),
238 version_dir(&cfg, version).join(directory::NATIVES)
239 );
240 }
241
242 #[test]
243 fn ensure_directories_creates_structure() {
244 let tmp = tempfile::tempdir().unwrap();
245 let cfg = test_config(tmp.path());
246
247 ensure_directories(&cfg).unwrap();
248
249 let root = root_directory(&cfg);
250
251 let expected_dirs = [
252 root.clone(),
253 root.join(directory::VERSIONS),
254 root.join(directory::LIBRARIES),
255 root.join(directory::ASSETS),
256 root.join(directory::ASSETS)
257 .join(directory::INDEXES),
258 root.join(directory::ASSETS)
259 .join(directory::OBJECTS),
260 root.join(directory::SAVES),
261 ];
262
263 for dir in expected_dirs {
264 assert!(dir.exists(), "Missing directory: {:?}", dir);
265 assert!(dir.is_dir());
266 }
267 }
44} 268}