Skip to main content

conduit_cli/core/engine/manager/
add.rs

1use futures_util::stream::{self, StreamExt};
2use std::sync::Arc;
3
4use crate::{
5    core::{
6        domain::addon::AddonType,
7        engine::{io::TomlFile, manager::ProjectManager, resolver::addon::ResolvedAddon},
8    },
9    errors::ConduitResult,
10};
11
12impl ProjectManager {
13    pub async fn add_addons(
14        &self,
15        identifiers: Vec<String>,
16        target_type: AddonType,
17    ) -> ConduitResult<()> {
18        let (mc_version, loader) = {
19            let manifest = self.ctx.manifest.read().await;
20            self.workflow
21                .validate_compatibility(&target_type, &manifest)?;
22            (
23                manifest.project.minecraft.clone(),
24                manifest.project.loader.clone(),
25            )
26        };
27
28        let resolved_results = stream::iter(identifiers.clone())
29            .map(|id| {
30                let resolver = &self.resolver;
31                let mc = mc_version.clone();
32                let lo = loader.clone();
33                let tt = target_type.clone();
34                async move { resolver.resolve_recursively(&id, &mc, &lo, tt).await }
35            })
36            .buffer_unordered(4)
37            .collect::<Vec<ConduitResult<Vec<ResolvedAddon>>>>()
38            .await;
39
40        let mut all_resolved = Vec::new();
41        for res in resolved_results {
42            all_resolved.extend(res?);
43        }
44
45        let id_map = Arc::new(self.workflow.prepare_addon_id(&all_resolved).await?);
46
47        for id in &identifiers {
48            if let Some(primary) = all_resolved.iter().find(|r| &r.slug == id || &r.id == id) {
49                self.workflow.update_manifest_addons(primary).await?;
50            }
51        }
52
53        let workflow = Arc::new(&self.workflow);
54        stream::iter(all_resolved)
55            .map(|resolved| {
56                let w = Arc::clone(&workflow);
57                let ids = Arc::clone(&id_map);
58                async move { w.install_addon_component(resolved, &ids).await }
59            })
60            .buffer_unordered(8)
61            .collect::<Vec<ConduitResult<()>>>()
62            .await
63            .into_iter()
64            .collect::<ConduitResult<Vec<()>>>()?;
65
66        let lock_path = self.ctx.paths.lock();
67        let lockfile = self.ctx.lockfile.read().await;
68        lockfile.save(lock_path).await?;
69
70        Ok(())
71    }
72}