Skip to main content

conduit_cli/core/engine/workflow/addon/
install.rs

1use 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}