Skip to main content

conduit_cli/core/engine/workflow/loader/
migration.rs

1use crate::core::engine::io::TomlFile;
2use crate::core::engine::workflow::Workflow;
3use crate::core::schemas::lock::{InstanceSnapshot, Lockfile};
4use crate::core::schemas::manifest::Manifest;
5use crate::errors::ConduitResult;
6use crate::paths::ConduitPaths;
7
8impl Workflow {
9    pub async fn migration(
10        &self,
11        manifest: &Manifest,
12        lockfile: &Lockfile,
13    ) -> ConduitResult<Lockfile> {
14        let current_loader = &lockfile.instance.loader;
15        let current_mc = &lockfile.instance.minecraft_version;
16        let target_loader = &manifest.project.loader;
17        let target_mc = &manifest.project.minecraft;
18
19        let mut active_lock = lockfile.clone();
20
21        if lockfile.instance.loader_hash.is_some()
22            && (current_loader != target_loader || current_mc != target_mc)
23        {
24            let old_id = ConduitPaths::get_runtime_id(current_loader, current_mc);
25            let runtime_path = self.project_root.join(".conduit_runtimes").join(old_id);
26
27            tokio::fs::create_dir_all(&runtime_path).await?;
28
29            let mut entries = tokio::fs::read_dir(&self.project_root).await?;
30            while let Some(entry) = entries.next_entry().await? {
31                let name = entry.file_name();
32                let name_str = name.to_string_lossy();
33
34                if ConduitPaths::is_conduit_file(&name_str) {
35                    continue;
36                }
37
38                tokio::fs::rename(entry.path(), runtime_path.join(&name)).await?;
39            }
40
41            let manifest_path = self.ctx.paths.manifest();
42            let lock_path = self.ctx.paths.lock();
43
44            let mut old_instance_manifest = Manifest::load(&manifest_path).await?;
45            old_instance_manifest.project.loader = current_loader.clone();
46            old_instance_manifest.project.minecraft = current_mc.clone();
47
48            old_instance_manifest
49                .save(runtime_path.join("conduit.toml"))
50                .await?;
51
52            tokio::fs::copy(&lock_path, runtime_path.join("conduit.lock")).await?;
53
54            let mut clean_manifest = Manifest::load(&manifest_path).await?;
55            clean_manifest.plugins.clear();
56            clean_manifest.mods.clear();
57            clean_manifest.datapacks.clear();
58
59            clean_manifest.save(&manifest_path).await?;
60
61            let clean_lock = Lockfile {
62                instance: InstanceSnapshot {
63                    minecraft_version: target_mc.clone(),
64                    loader: target_loader.clone(),
65                    loader_hash: None,
66                    hash_kind: None,
67                },
68                ..Default::default()
69            };
70
71            clean_lock.save(&lock_path).await?;
72            active_lock = clean_lock;
73
74            let mut ctx_manifest = self.ctx.manifest.write().await;
75            *ctx_manifest = clean_manifest;
76        }
77
78        let new_id = ConduitPaths::get_runtime_id(target_loader, target_mc);
79        let target_runtime_path = self.project_root.join(".conduit_runtimes").join(&new_id);
80
81        if target_runtime_path.exists() {
82            let manifest_path = self.ctx.paths.manifest();
83            let lock_path = self.ctx.paths.lock();
84
85            let restored_manifest =
86                Manifest::load(&target_runtime_path.join("conduit.toml")).await?;
87            let restored_lock = Lockfile::load(&target_runtime_path.join("conduit.lock")).await?;
88
89            let mut entries = tokio::fs::read_dir(&target_runtime_path).await?;
90            while let Some(entry) = entries.next_entry().await? {
91                let name = entry.file_name();
92                let name_str = name.to_string_lossy();
93
94                if ConduitPaths::is_conduit_file(&name_str) {
95                    continue;
96                }
97
98                tokio::fs::rename(entry.path(), self.project_root.join(&name)).await?;
99            }
100
101            restored_manifest.save(&manifest_path).await?;
102            restored_lock.save(&lock_path).await?;
103
104            let mut ctx_manifest = self.ctx.manifest.write().await;
105            *ctx_manifest = restored_manifest;
106
107            active_lock = restored_lock;
108
109            tokio::fs::remove_dir_all(target_runtime_path).await?;
110        }
111
112        Ok(active_lock)
113    }
114}