conduit_cli/core/engine/io/
mrpack.rs1use std::{collections::HashMap, fs::File, path::PathBuf};
2
3use crate::{
4 core::{engine::archive::SafeArchive, schemas::modpacks::modrinth::ModrinthIndex},
5 errors::{ConduitError, ConduitResult},
6};
7
8pub struct MrPackManager {
9 pub file: ModrinthIndex,
10}
11
12impl MrPackManager {
13 pub fn new(
14 path: &PathBuf,
15 index: ModrinthIndex,
16 extra_files: HashMap<String, Vec<u8>>,
17 overrides: Option<(PathBuf, Vec<PathBuf>)>,
18 ) -> ConduitResult<Self> {
19 let mut writer = SafeArchive::create(path)?;
20
21 SafeArchive::serialize_and_add(&mut writer, "modrinth.index.json", &index)?;
22
23 for (name, content) in extra_files {
24 SafeArchive::add_file(&mut writer, &name, &content)?;
25 }
26
27 if let Some((root, files)) = overrides {
28 for file_path in files {
29 if file_path.is_file() {
30 let relative = file_path.strip_prefix(&root).map_err(|_| {
31 ConduitError::Storage(
32 "Failed to strip prefix for mrpack override".to_string(),
33 )
34 })?;
35
36 let zip_path = format!(
37 "overrides/{}",
38 relative.to_string_lossy().replace('\\', "/")
39 );
40
41 let file = File::open(&file_path)?;
42 SafeArchive::add_file_from_reader(&mut writer, &zip_path, file)?;
43 }
44 }
45 }
46
47 writer
48 .finish()
49 .map_err(|e| ConduitError::Storage(format!("Failed to finalize mrpack: {e}")))?;
50
51 Ok(Self { file: index })
52 }
53
54 pub fn open(path: PathBuf) -> ConduitResult<Self> {
55 let mut zip = SafeArchive::open(path)?;
56
57 let file: ModrinthIndex =
58 SafeArchive::read_and_deserialize(&mut zip, "modrinth.index.json")?;
59
60 Ok(MrPackManager { file })
61 }
62}