conduit_cli/core/engine/workflow/addon/
install.rs1use std::{collections::HashMap, path::PathBuf};
2
3use tokio::fs;
4use uuid::Uuid;
5
6use crate::core::{
7 domain::addon::{Addon, AddonType},
8 engine::{resolver::addon::ResolvedAddon, workflow::Workflow},
9 schemas::lock::LockedAddon,
10};
11use crate::errors::{ConduitError, ConduitResult};
12
13impl Workflow {
14 pub async fn install_addon_component(
15 &self,
16 resolved: ResolvedAddon,
17 id_map: &HashMap<String, Uuid>,
18 ) -> ConduitResult<()> {
19 {
20 let lockfile = self.ctx.lockfile.read().await;
21 if lockfile
22 .entries
23 .values()
24 .any(|e| e.metadata.slug == resolved.slug)
25 {
26 return Ok(());
27 }
28 }
29
30 let (hash, kind) = self
31 .ctx
32 .downloader
33 .download_to_store(&resolved.download_url, Some(&resolved.source.hash))
34 .await?;
35
36 let rel_path = get_addon_relative_path(&resolved);
37
38 if let Some(parent) = rel_path.parent() {
39 let full_parent = self.project_root.join(parent);
40 fs::create_dir_all(&full_parent).await?;
41 }
42
43 self.ctx
44 .store
45 .install_to_project(&hash, kind, rel_path)
46 .await?;
47
48 let addon_uuid = *id_map
49 .get(&resolved.id)
50 .ok_or_else(|| ConduitError::Deserialize(format!("UUID missing: {}", resolved.slug)))?;
51
52 let dependency_uuids = resolved
53 .dependencies
54 .iter()
55 .filter_map(|dep_id| id_map.get(dep_id))
56 .copied()
57 .collect();
58
59 let lock_key = format!("{}:{}", resolved.source.r#type, resolved.slug);
60
61 let mut lockfile = self.ctx.lockfile.write().await;
62 lockfile.entries.insert(
63 lock_key,
64 LockedAddon {
65 metadata: Addon {
66 id: addon_uuid,
67 slug: resolved.slug,
68 file_name: resolved.file_name,
69 r#type: resolved.r#type,
70 loaders: resolved.loaders,
71 dependencies: dependency_uuids,
72 },
73 source: resolved.source,
74 },
75 );
76
77 Ok(())
78 }
79}
80
81pub fn get_addon_relative_path(resolved: &ResolvedAddon) -> PathBuf {
82 match resolved.r#type {
83 AddonType::Mod => PathBuf::from("mods").join(&resolved.file_name),
84 AddonType::Plugin => PathBuf::from("plugins").join(&resolved.file_name),
85 AddonType::Datapack => PathBuf::from("world")
86 .join("datapacks")
87 .join(&resolved.file_name),
88 }
89}