conduit_cli/core/engine/workflow/loader/
migration.rs1use 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}