cobble_core/instance/fabric/
backup.rs1use crate::error::{CobbleError, CobbleResult};
2use crate::instance::backup::{
3 append_assets, append_instance_folder, append_instance_information, append_libraries,
4 append_log_config, LIBRARIES_FOLDER,
5};
6use crate::minecraft::models::{AssetIndex, VersionData};
7use crate::minecraft::FabricVersionData;
8use crate::Instance;
9use flate2::write::GzEncoder;
10use std::fs::File;
11use std::path::PathBuf;
12
13impl Instance {
14 #[instrument(
20 name = "export_instance",
21 level = "trace",
22 skip_all,
23 fields(
24 instance_path = %self.instance_path.to_string_lossy(),
25 offline,
26 dest,
27 compression,
28 )
29 )]
30 #[cfg_attr(doc_cfg, doc(cfg(feature = "backup")))]
31 pub async fn export(
32 &self,
33 dest: impl AsRef<std::path::Path>,
34 offline: bool,
35 compression: u32,
36 ) -> CobbleResult<()> {
37 if !self.installed {
38 return Err(CobbleError::NotInstalled);
39 }
40
41 let this = self.clone();
42 let dest = PathBuf::from(dest.as_ref());
43
44 trace!("Getting version data");
45 let version_data = self.read_version_data().await?;
46 trace!("Getting asset index");
47 let asset_index = version_data.asset_index.fetch_index().await?;
48
49 let fabric_version_data = match &self.fabric_version {
50 Some(_) => {
51 trace!("Getting fabric version data");
52 Some(self.read_fabric_version_data().await?)
53 }
54 None => None,
55 };
56
57 tokio::task::spawn_blocking(move || {
58 this.export_blocking(
59 version_data,
60 fabric_version_data,
61 asset_index,
62 dest,
63 offline,
64 compression,
65 )
66 })
67 .await?
68 }
69
70 #[instrument(
71 name = "export_instance_blocking",
72 level = "trace",
73 skip_all,
74 fields(
75 instance_path = %self.instance_path.to_string_lossy(),
76 offline,
77 dest,
78 compression,
79 )
80 )]
81 fn export_blocking(
82 mut self,
83 version_data: VersionData,
84 fabric_version_data: Option<FabricVersionData>,
85 asset_index: AssetIndex,
86 dest: PathBuf,
87 offline: bool,
88 compression: u32,
89 ) -> CobbleResult<()> {
90 trace!("Creating archive file");
91 let archive_file = File::create(dest)?;
92 let encoder = GzEncoder::new(archive_file, flate2::Compression::new(compression));
93 let mut tar = tar::Builder::new(encoder);
94
95 append_instance_information(&mut self, offline, &mut tar)?;
96 append_instance_folder(&self, &mut tar)?;
97
98 if offline {
99 append_libraries(&self, &version_data, &mut tar)?;
100
101 if let Some(fabric_version_data) = fabric_version_data {
102 append_fabric_libraries(&self, &fabric_version_data, &mut tar)?;
103 }
104
105 append_assets(&self, &asset_index, &version_data, &mut tar)?;
106 append_log_config(&self, &version_data, &mut tar)?;
107 }
108
109 trace!("Flushing archive");
110 let mut encoder = tar.into_inner()?;
111 encoder.try_finish()?;
112
113 Ok(())
114 }
115}
116
117fn append_fabric_libraries(
118 instance: &Instance,
119 fabric_version_data: &FabricVersionData,
120 tar: &mut tar::Builder<GzEncoder<File>>,
121) -> CobbleResult<()> {
122 trace!("Adding fabric libraries to archive");
123 let libraries_path = instance.libraries_path();
124
125 fabric_version_data
126 .libraries
127 .iter()
128 .try_for_each(|library| -> CobbleResult<()> {
129 let file_path = library.jar_path(&libraries_path);
131 let mut file = File::open(file_path)?;
132
133 let mut relative_path = PathBuf::from(LIBRARIES_FOLDER);
135 relative_path.push(library.relative_jar_path());
136
137 trace!("Adding library {} to archive", &library.name);
138 tar.append_file(relative_path, &mut file)?;
139
140 Ok(())
141 })?;
142
143 Ok(())
144}