Support diffing against an older version
This commit is contained in:
parent
e524aba94b
commit
9e09e71623
95
src/main.rs
95
src/main.rs
@ -1,5 +1,6 @@
|
||||
use std::collections::HashMap;
|
||||
use std::env::args;
|
||||
use std::ffi::OsStr;
|
||||
use std::io::Read;
|
||||
use std::path::PathBuf;
|
||||
use zip::ZipArchive;
|
||||
@ -48,7 +49,8 @@ impl Dependency {
|
||||
.json::<Vec<FabricInstallerVersion>>()
|
||||
.await?
|
||||
.first()
|
||||
.ok_or("No fabric installer version found")?.version
|
||||
.ok_or("No fabric installer version found")?
|
||||
.version
|
||||
),
|
||||
Dependency::Minecraft => {
|
||||
let version_map = reqwest::get("https://raw.githubusercontent.com/liebki/MinecraftServerForkDownloads/refs/heads/main/release_vanilla_downloads.json")
|
||||
@ -65,7 +67,7 @@ impl Dependency {
|
||||
|
||||
let target = target.into();
|
||||
if target.exists() {
|
||||
println!("File {} already exists, skipping download", target.display());
|
||||
eprintln!("File {} already exists, skipping download", target.display());
|
||||
return Ok(());
|
||||
}
|
||||
let response = reqwest::get(url.clone()).await?;
|
||||
@ -80,7 +82,7 @@ impl Dependency {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
|
||||
struct ConfigFile {
|
||||
path: String,
|
||||
hashes: HashMap<String, String>,
|
||||
@ -94,21 +96,24 @@ impl ConfigFile {
|
||||
async fn download(&self, target: impl Into<PathBuf>) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let target = target.into();
|
||||
let target_path = target.join(&self.path);
|
||||
if target_path.exists() {
|
||||
println!("File {} already exists, skipping download", target_path.display());
|
||||
let mut disabled_path = target_path.extension().unwrap_or(OsStr::new("jar")).to_os_string();
|
||||
disabled_path.push(".disabled");
|
||||
if target_path.exists() || target_path.with_extension(disabled_path).exists() {
|
||||
eprintln!("File {} already exists (or is disabled), skipping download", target_path.display());
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
for link in &self.downloads {
|
||||
let response = reqwest::get(link).await?;
|
||||
if response.status().is_success() {
|
||||
println!("Downloading file from {}", link);
|
||||
let content = response.bytes().await?;
|
||||
let mut file = File::create(&target_path).await?;
|
||||
tokio::io::copy(&mut content.as_ref(), &mut file).await?;
|
||||
|
||||
return Ok(())
|
||||
} else {
|
||||
println!("Failed to download file from {}", link);
|
||||
eprintln!("Failed to download file from {}", link);
|
||||
}
|
||||
}
|
||||
|
||||
@ -143,6 +148,33 @@ struct FabricInstallerVersion {
|
||||
stable: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct GameSetupParams {
|
||||
dependency: Dependency,
|
||||
version: String,
|
||||
mc_version: String,
|
||||
}
|
||||
|
||||
impl GameSetupParams {
|
||||
fn new(config: &ModrinthConfig) -> Self {
|
||||
let (server, server_version, mc_version) = if config.is_modded() {
|
||||
let (dep, version) = config.dependencies.iter().find(|(k, _)| **k != Dependency::Minecraft).expect("Modded dependency version not found");
|
||||
let mc_version = config.dependencies.iter().find(|(k, _)| **k == Dependency::Minecraft).map(|(_, v)| v.clone()).expect("Minecraft version not found");
|
||||
|
||||
(dep.clone(), version.clone(), mc_version)
|
||||
} else {
|
||||
let (dep, version) = config.dependencies.iter().find(|(k, _)| **k == Dependency::Minecraft).expect("Modded dependency version not found");
|
||||
(dep.clone(), version.clone(), version.clone())
|
||||
};
|
||||
|
||||
Self {
|
||||
dependency: server,
|
||||
version: server_version,
|
||||
mc_version,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async fn get_config_from_archive(archive: &mut ZipArchive<std::fs::File>, out_dir: impl Into<PathBuf>) -> Option<ModrinthConfig> {
|
||||
let overrides = "overrides/";
|
||||
@ -155,7 +187,6 @@ async fn get_config_from_archive(archive: &mut ZipArchive<std::fs::File>, out_di
|
||||
if file.name() == modrinth_index {
|
||||
let mut contents = String::new();
|
||||
if let Ok(_) = file.read_to_string(&mut contents) {
|
||||
println!("Found modrinth index file");
|
||||
return Some(serde_json::from_str::<ModrinthConfig>(contents.as_str()).expect("Unable to parse modrinth config"))
|
||||
} else {
|
||||
eprintln!("Can't read contents");
|
||||
@ -178,17 +209,26 @@ async fn get_config_from_archive(archive: &mut ZipArchive<std::fs::File>, out_di
|
||||
None
|
||||
}
|
||||
|
||||
async fn get_config_from_file(file: &str) -> Option<ModrinthConfig> {
|
||||
let file = std::fs::File::open(file).expect("Unable to open file");
|
||||
let mut archive = ZipArchive::new(file).expect("Unable to read zip archive");
|
||||
get_config_from_archive(&mut archive, "out/").await
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
let args: Vec<String> = args().collect();
|
||||
if args.len() != 2 && args.len() != 3 {
|
||||
eprintln!("Usage: {} <mrpack> [target dir]", args[0]);
|
||||
if args.len() < 2 || args.len() > 4 {
|
||||
eprintln!("Usage: {} <mrpack> [target dir] [previous version]", args[0]);
|
||||
return;
|
||||
}
|
||||
let out_dir = if args.len() == 3 {
|
||||
PathBuf::from(&args[2])
|
||||
} else {
|
||||
PathBuf::from("out/")
|
||||
let out_dir = match args.len() {
|
||||
3 | 4 => PathBuf::from(&args[2]),
|
||||
_ => PathBuf::from("out/"),
|
||||
};
|
||||
let previous_version = match args.len() {
|
||||
4 => Some(get_config_from_file(args[3].as_str()).await.unwrap()),
|
||||
_ => None,
|
||||
};
|
||||
let file = std::fs::File::open(&args[1]).expect("Unable to open file");
|
||||
let mut archive = ZipArchive::new(file).expect("Unable to read zip archive");
|
||||
@ -196,22 +236,31 @@ async fn main() {
|
||||
// Create directory "out" and subdirectory "mods"
|
||||
std::fs::create_dir_all(&out_dir).expect("Unable to create directory");
|
||||
|
||||
println!("Extracting files from {}", args[1]);
|
||||
let config = get_config_from_archive(&mut archive, &out_dir).await.unwrap();
|
||||
for entry in &config.files {
|
||||
entry.download(&out_dir).await.unwrap();
|
||||
}
|
||||
|
||||
let (server, server_version, mc_version) = if config.is_modded() {
|
||||
let (dep, version) = config.dependencies.iter().find(|(k, _)| **k != Dependency::Minecraft).expect("Modded dependency version not found");
|
||||
let mc_version = config.dependencies.iter().find(|(k, _)| **k == Dependency::Minecraft).map(|(_, v)| v.clone()).expect("Minecraft version not found");
|
||||
|
||||
(dep.clone(), version.clone(), mc_version)
|
||||
} else {
|
||||
let (dep, version) = config.dependencies.iter().find(|(k, _)| **k == Dependency::Minecraft).expect("Modded dependency version not found");
|
||||
(dep.clone(), version.clone(), version.clone())
|
||||
};
|
||||
if let Some(ref previous_version) = previous_version {
|
||||
for removal in previous_version.files.iter().filter(|v| config.files.iter().filter(|v1| v1.path == v.path).count() == 0).map(|c| {
|
||||
tokio::fs::remove_file(c.path.clone())
|
||||
}) {
|
||||
let _ = removal.await;
|
||||
}
|
||||
}
|
||||
|
||||
server.download(out_dir.join("server.jar"), server_version, mc_version).await.unwrap();
|
||||
let server_jar = out_dir.join("server.jar");
|
||||
let old_params = previous_version.as_ref().map(|prev| GameSetupParams::new(prev));
|
||||
let params = GameSetupParams::new(&config);
|
||||
|
||||
if match old_params { None => true, Some(old_params) => old_params.dependency != params.dependency || !server_jar.exists() } {
|
||||
let _ = tokio::fs::remove_file(&server_jar).await;
|
||||
println!("Downloading server jar");
|
||||
params.dependency.download(server_jar, params.version, params.mc_version).await.unwrap();
|
||||
} else {
|
||||
println!("Server jar already exists, skipping download");
|
||||
}
|
||||
|
||||
let eula = "#By changing the setting below to TRUE you are indicating your agreement to our EULA (https://aka.ms/MinecraftEULA).
|
||||
#Thu Jan 01 00:00:00 GMT 1970
|
||||
|
Loading…
x
Reference in New Issue
Block a user