mirror of
https://github.com/WarrenHood/MCModpackManager.git
synced 2025-04-30 00:04:59 +01:00
Add ability to download a modpack from git or from any local path
This commit is contained in:
parent
08eff7ea2a
commit
753c9d6417
68
Cargo.lock
generated
68
Cargo.lock
generated
|
@ -138,6 +138,8 @@ version = "1.1.13"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "72db2f7947ecee9b03b510377e8bb9077afa27176fdbff55c51027e976fdcc48"
|
checksum = "72db2f7947ecee9b03b510377e8bb9077afa27176fdbff55c51027e976fdcc48"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"jobserver",
|
||||||
|
"libc",
|
||||||
"shlex",
|
"shlex",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -365,6 +367,21 @@ version = "0.29.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd"
|
checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "git2"
|
||||||
|
version = "0.19.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b903b73e45dc0c6c596f2d37eccece7c1c8bb6e4407b001096387c63d0d93724"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.6.0",
|
||||||
|
"libc",
|
||||||
|
"libgit2-sys",
|
||||||
|
"log",
|
||||||
|
"openssl-probe",
|
||||||
|
"openssl-sys",
|
||||||
|
"url",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "h2"
|
name = "h2"
|
||||||
version = "0.4.5"
|
version = "0.4.5"
|
||||||
|
@ -553,6 +570,15 @@ version = "1.0.11"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
|
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "jobserver"
|
||||||
|
version = "0.1.32"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "js-sys"
|
name = "js-sys"
|
||||||
version = "0.3.70"
|
version = "0.3.70"
|
||||||
|
@ -574,6 +600,46 @@ version = "0.2.156"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a5f43f184355eefb8d17fc948dbecf6c13be3c141f20d834ae842193a448c72a"
|
checksum = "a5f43f184355eefb8d17fc948dbecf6c13be3c141f20d834ae842193a448c72a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libgit2-sys"
|
||||||
|
version = "0.17.0+1.8.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "10472326a8a6477c3c20a64547b0059e4b0d086869eee31e6d7da728a8eb7224"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"libc",
|
||||||
|
"libssh2-sys",
|
||||||
|
"libz-sys",
|
||||||
|
"openssl-sys",
|
||||||
|
"pkg-config",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libssh2-sys"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2dc8a030b787e2119a731f1951d6a773e2280c660f8ec4b0f5e1505a386e71ee"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"libc",
|
||||||
|
"libz-sys",
|
||||||
|
"openssl-sys",
|
||||||
|
"pkg-config",
|
||||||
|
"vcpkg",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libz-sys"
|
||||||
|
version = "1.1.19"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fdc53a7799a7496ebc9fd29f31f7df80e83c9bda5299768af5f9e59eeea74647"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"libc",
|
||||||
|
"pkg-config",
|
||||||
|
"vcpkg",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "linux-raw-sys"
|
name = "linux-raw-sys"
|
||||||
version = "0.4.14"
|
version = "0.4.14"
|
||||||
|
@ -601,11 +667,13 @@ name = "mcmpmgr"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap",
|
"clap",
|
||||||
|
"git2",
|
||||||
"lhash",
|
"lhash",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
"semver",
|
"semver",
|
||||||
"serde",
|
"serde",
|
||||||
"sha2",
|
"sha2",
|
||||||
|
"tempfile",
|
||||||
"tokio",
|
"tokio",
|
||||||
"toml",
|
"toml",
|
||||||
]
|
]
|
||||||
|
|
|
@ -5,10 +5,12 @@ edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
clap = { version = "4.5.15", features = ["derive"] }
|
clap = { version = "4.5.15", features = ["derive"] }
|
||||||
|
git2 = "0.19.0"
|
||||||
lhash = { version = "1.1.0", features = ["sha1", "sha512"] }
|
lhash = { version = "1.1.0", features = ["sha1", "sha512"] }
|
||||||
reqwest = { version = "0.12.5", features = ["json"] }
|
reqwest = { version = "0.12.5", features = ["json"] }
|
||||||
semver = { version = "1.0.23", features = ["serde"] }
|
semver = { version = "1.0.23", features = ["serde"] }
|
||||||
serde = { version = "1.0.207", features = ["derive"] }
|
serde = { version = "1.0.207", features = ["derive"] }
|
||||||
sha2 = "0.10.8"
|
sha2 = "0.10.8"
|
||||||
|
tempfile = "3.12.0"
|
||||||
tokio = { version = "1.39.2", features = ["full"] }
|
tokio = { version = "1.39.2", features = ["full"] }
|
||||||
toml = "0.8.19"
|
toml = "0.8.19"
|
||||||
|
|
22
src/main.rs
22
src/main.rs
|
@ -90,6 +90,12 @@ enum Commands {
|
||||||
/// Side to download for
|
/// Side to download for
|
||||||
#[arg(long, short, default_value_t = DownloadSide::Both)]
|
#[arg(long, short, default_value_t = DownloadSide::Both)]
|
||||||
side: DownloadSide,
|
side: DownloadSide,
|
||||||
|
/// Download mods from a remote modpack in a git repo
|
||||||
|
#[arg(long)]
|
||||||
|
git: Option<String>,
|
||||||
|
/// Download mods from a local modpack
|
||||||
|
#[arg(long)]
|
||||||
|
path: Option<PathBuf>,
|
||||||
},
|
},
|
||||||
/// Update all mods to the latest possible version
|
/// Update all mods to the latest possible version
|
||||||
Update {
|
Update {
|
||||||
|
@ -288,8 +294,20 @@ async fn main() -> Result<(), Box<dyn Error>> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
Commands::Download { mods_dir, side } => {
|
Commands::Download {
|
||||||
let pack_lock = resolver::PinnedPackMeta::load_from_current_directory(true).await?;
|
mods_dir,
|
||||||
|
side,
|
||||||
|
git,
|
||||||
|
path,
|
||||||
|
} => {
|
||||||
|
let pack_lock = if let Some(git_url) = git {
|
||||||
|
resolver::PinnedPackMeta::load_from_git_repo(&git_url, true).await?
|
||||||
|
} else if let Some(local_path) = path {
|
||||||
|
resolver::PinnedPackMeta::load_from_directory(&local_path, true).await?
|
||||||
|
} else {
|
||||||
|
resolver::PinnedPackMeta::load_from_current_directory(true).await?
|
||||||
|
};
|
||||||
|
|
||||||
pack_lock.download_mods(&mods_dir, side).await?;
|
pack_lock.download_mods(&mods_dir, side).await?;
|
||||||
println!("Mods updated");
|
println!("Mods updated");
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ use serde::{Deserialize, Serialize};
|
||||||
use std::{
|
use std::{
|
||||||
collections::{HashMap, HashSet},
|
collections::{HashMap, HashSet},
|
||||||
error::Error,
|
error::Error,
|
||||||
path::PathBuf,
|
path::{Path, PathBuf},
|
||||||
};
|
};
|
||||||
|
|
||||||
const MODPACK_FILENAME: &str = "modpack.toml";
|
const MODPACK_FILENAME: &str = "modpack.toml";
|
||||||
|
@ -38,7 +38,7 @@ impl std::str::FromStr for ModLoader {
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
pub struct ModpackMeta {
|
pub struct ModpackMeta {
|
||||||
pack_name: String,
|
pub pack_name: String,
|
||||||
pub mc_version: String,
|
pub mc_version: String,
|
||||||
pub modloader: ModLoader,
|
pub modloader: ModLoader,
|
||||||
pub mods: HashMap<String, ModMeta>,
|
pub mods: HashMap<String, ModMeta>,
|
||||||
|
@ -60,8 +60,8 @@ impl ModpackMeta {
|
||||||
self.mods.values().into_iter()
|
self.mods.values().into_iter()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load_from_directory(directory: &PathBuf) -> Result<Self, Box<dyn Error>> {
|
pub fn load_from_directory(directory: &Path) -> Result<Self, Box<dyn Error>> {
|
||||||
let modpack_meta_file_path = directory.clone().join(PathBuf::from(MODPACK_FILENAME));
|
let modpack_meta_file_path = directory.join(PathBuf::from(MODPACK_FILENAME));
|
||||||
if !modpack_meta_file_path.exists() {
|
if !modpack_meta_file_path.exists() {
|
||||||
return Err(format!(
|
return Err(format!(
|
||||||
"Directory '{}' does not seem to be a valid modpack project directory.",
|
"Directory '{}' does not seem to be a valid modpack project directory.",
|
||||||
|
@ -104,8 +104,8 @@ impl ModpackMeta {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init_project(&self, directory: &PathBuf) -> Result<(), Box<dyn Error>> {
|
pub fn init_project(&self, directory: &Path) -> Result<(), Box<dyn Error>> {
|
||||||
let modpack_meta_file_path = directory.clone().join(PathBuf::from(MODPACK_FILENAME));
|
let modpack_meta_file_path = directory.join(PathBuf::from(MODPACK_FILENAME));
|
||||||
if modpack_meta_file_path.exists() {
|
if modpack_meta_file_path.exists() {
|
||||||
return Err(format!(
|
return Err(format!(
|
||||||
"{MODPACK_FILENAME} already exists at {}",
|
"{MODPACK_FILENAME} already exists at {}",
|
||||||
|
|
|
@ -65,7 +65,7 @@ impl Modrinth {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_project(&self, project_id: &str) -> Result<ModrinthProject, Box<dyn Error>> {
|
async fn get_project(&self, project_id: &str) -> Result<ModrinthProject, Box<dyn Error>> {
|
||||||
let project: ModrinthProject = self
|
let project: ModrinthProject = self
|
||||||
.client
|
.client
|
||||||
.get(format!("https://api.modrinth.com/v2/project/{project_id}"))
|
.get(format!("https://api.modrinth.com/v2/project/{project_id}"))
|
||||||
|
|
|
@ -4,7 +4,7 @@ use std::{
|
||||||
collections::{HashMap, HashSet},
|
collections::{HashMap, HashSet},
|
||||||
error::Error,
|
error::Error,
|
||||||
ffi::{OsStr, OsString},
|
ffi::{OsStr, OsString},
|
||||||
path::PathBuf,
|
path::{Path, PathBuf},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -61,7 +61,7 @@ impl PinnedPackMeta {
|
||||||
match filesource {
|
match filesource {
|
||||||
crate::providers::FileSource::Download {
|
crate::providers::FileSource::Download {
|
||||||
url,
|
url,
|
||||||
sha1,
|
sha1: _,
|
||||||
sha512,
|
sha512,
|
||||||
filename,
|
filename,
|
||||||
} => {
|
} => {
|
||||||
|
@ -90,10 +90,10 @@ impl PinnedPackMeta {
|
||||||
tokio::fs::write(mods_dir.join(filename), file_contents).await?;
|
tokio::fs::write(mods_dir.join(filename), file_contents).await?;
|
||||||
}
|
}
|
||||||
crate::providers::FileSource::Local {
|
crate::providers::FileSource::Local {
|
||||||
path,
|
path: _,
|
||||||
sha1,
|
sha1: _,
|
||||||
sha512,
|
sha512: _,
|
||||||
filename,
|
filename: _,
|
||||||
} => unimplemented!(),
|
} => unimplemented!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -102,7 +102,12 @@ impl PinnedPackMeta {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn file_is_pinned(&self, file_name: &OsStr, mod_side: DownloadSide, cache: &mut HashSet<OsString>) -> bool {
|
pub fn file_is_pinned(
|
||||||
|
&self,
|
||||||
|
file_name: &OsStr,
|
||||||
|
mod_side: DownloadSide,
|
||||||
|
cache: &mut HashSet<OsString>,
|
||||||
|
) -> bool {
|
||||||
if cache.contains(file_name) {
|
if cache.contains(file_name) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -114,9 +119,9 @@ impl PinnedPackMeta {
|
||||||
for filesource in pinned_mod.source.iter() {
|
for filesource in pinned_mod.source.iter() {
|
||||||
match filesource {
|
match filesource {
|
||||||
crate::providers::FileSource::Download {
|
crate::providers::FileSource::Download {
|
||||||
url,
|
url: _,
|
||||||
sha1,
|
sha1: _,
|
||||||
sha512,
|
sha512: _,
|
||||||
filename,
|
filename,
|
||||||
} => {
|
} => {
|
||||||
let pinned_filename = OsStr::new(filename);
|
let pinned_filename = OsStr::new(filename);
|
||||||
|
@ -126,9 +131,9 @@ impl PinnedPackMeta {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
crate::providers::FileSource::Local {
|
crate::providers::FileSource::Local {
|
||||||
path,
|
path: _,
|
||||||
sha1,
|
sha1: _,
|
||||||
sha512,
|
sha512: _,
|
||||||
filename,
|
filename,
|
||||||
} => {
|
} => {
|
||||||
let pinned_filename = OsStr::new(filename);
|
let pinned_filename = OsStr::new(filename);
|
||||||
|
@ -353,10 +358,10 @@ impl PinnedPackMeta {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn load_from_directory(
|
pub async fn load_from_directory(
|
||||||
directory: &PathBuf,
|
directory: &Path,
|
||||||
ignore_transitive_versions: bool,
|
ignore_transitive_versions: bool,
|
||||||
) -> Result<Self, Box<dyn Error>> {
|
) -> Result<Self, Box<dyn Error>> {
|
||||||
let modpack_lock_file_path = directory.clone().join(PathBuf::from(MODPACK_LOCK_FILENAME));
|
let modpack_lock_file_path = directory.join(PathBuf::from(MODPACK_LOCK_FILENAME));
|
||||||
if !modpack_lock_file_path.exists() {
|
if !modpack_lock_file_path.exists() {
|
||||||
let mut new_modpack_lock = Self::new();
|
let mut new_modpack_lock = Self::new();
|
||||||
new_modpack_lock
|
new_modpack_lock
|
||||||
|
@ -376,4 +381,34 @@ impl PinnedPackMeta {
|
||||||
) -> Result<Self, Box<dyn Error>> {
|
) -> Result<Self, Box<dyn Error>> {
|
||||||
Self::load_from_directory(&std::env::current_dir()?, ignore_transitive_versions).await
|
Self::load_from_directory(&std::env::current_dir()?, ignore_transitive_versions).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn load_from_git_repo(
|
||||||
|
git_url: &str,
|
||||||
|
ignore_transitive_versions: bool,
|
||||||
|
) -> Result<Self, Box<dyn Error>> {
|
||||||
|
// TODO: Refactor the way this works since temp dirs will be deleted before we get to access local mods
|
||||||
|
// That is a problem for the future
|
||||||
|
|
||||||
|
let pack_dir = tempfile::tempdir()?;
|
||||||
|
println!(
|
||||||
|
"Cloning modpack from git repo {} to {:#?}...",
|
||||||
|
git_url,
|
||||||
|
pack_dir.path()
|
||||||
|
);
|
||||||
|
let _repo = git2::Repository::clone(git_url, pack_dir.path())?;
|
||||||
|
|
||||||
|
let modpack_meta = ModpackMeta::load_from_directory(pack_dir.path())?;
|
||||||
|
let pinned_pack_meta =
|
||||||
|
PinnedPackMeta::load_from_directory(pack_dir.path(), ignore_transitive_versions)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
println!(
|
||||||
|
"Loaded modpack '{}' (MC {} - {}) from git",
|
||||||
|
modpack_meta.pack_name,
|
||||||
|
modpack_meta.mc_version,
|
||||||
|
modpack_meta.modloader.to_string()
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(pinned_pack_meta)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue