use crate::error::{CobbleError, CobbleResult};
use crate::instance::backup::{
append_assets, append_instance_folder, append_instance_information, append_libraries,
append_log_config, LIBRARIES_FOLDER,
};
use crate::minecraft::models::{AssetIndex, VersionData};
use crate::minecraft::FabricVersionData;
use crate::Instance;
use flate2::write::GzEncoder;
use std::fs::File;
use std::path::PathBuf;
impl Instance {
#[instrument(
name = "export_instance",
level = "trace",
skip_all,
fields(
instance_path = %self.instance_path.to_string_lossy(),
offline,
dest,
compression,
)
)]
#[cfg_attr(doc_cfg, doc(cfg(feature = "backup")))]
pub async fn export(
&self,
dest: impl AsRef<std::path::Path>,
offline: bool,
compression: u32,
) -> CobbleResult<()> {
if !self.installed {
return Err(CobbleError::NotInstalled);
}
let this = self.clone();
let dest = PathBuf::from(dest.as_ref());
trace!("Getting version data");
let version_data = self.read_version_data().await?;
trace!("Getting asset index");
let asset_index = version_data.asset_index.fetch_index().await?;
let fabric_version_data = match &self.fabric_version {
Some(_) => {
trace!("Getting fabric version data");
Some(self.read_fabric_version_data().await?)
}
None => None,
};
tokio::task::spawn_blocking(move || {
this.export_blocking(
version_data,
fabric_version_data,
asset_index,
dest,
offline,
compression,
)
})
.await?
}
#[instrument(
name = "export_instance_blocking",
level = "trace",
skip_all,
fields(
instance_path = %self.instance_path.to_string_lossy(),
offline,
dest,
compression,
)
)]
fn export_blocking(
mut self,
version_data: VersionData,
fabric_version_data: Option<FabricVersionData>,
asset_index: AssetIndex,
dest: PathBuf,
offline: bool,
compression: u32,
) -> CobbleResult<()> {
trace!("Creating archive file");
let archive_file = File::create(dest)?;
let encoder = GzEncoder::new(archive_file, flate2::Compression::new(compression));
let mut tar = tar::Builder::new(encoder);
append_instance_information(&mut self, offline, &mut tar)?;
append_instance_folder(&self, &mut tar)?;
if offline {
append_libraries(&self, &version_data, &mut tar)?;
if let Some(fabric_version_data) = fabric_version_data {
append_fabric_libraries(&self, &fabric_version_data, &mut tar)?;
}
append_assets(&self, &asset_index, &version_data, &mut tar)?;
append_log_config(&self, &version_data, &mut tar)?;
}
trace!("Flushing archive");
let mut encoder = tar.into_inner()?;
encoder.try_finish()?;
Ok(())
}
}
fn append_fabric_libraries(
instance: &Instance,
fabric_version_data: &FabricVersionData,
tar: &mut tar::Builder<GzEncoder<File>>,
) -> CobbleResult<()> {
trace!("Adding fabric libraries to archive");
let libraries_path = instance.libraries_path();
fabric_version_data
.libraries
.iter()
.try_for_each(|library| -> CobbleResult<()> {
let file_path = library.jar_path(&libraries_path);
let mut file = File::open(file_path)?;
let mut relative_path = PathBuf::from(LIBRARIES_FOLDER);
relative_path.push(library.relative_jar_path());
trace!("Adding library {} to archive", &library.name);
tar.append_file(relative_path, &mut file)?;
Ok(())
})?;
Ok(())
}