treewide: migrate to multi-crate layout

Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I11a2103f3530f07409177404577b90136a6a6964
This commit is contained in:
raf 2026-05-03 00:33:21 +03:00
commit d445b1814a
Signed by: NotAShelf
GPG key ID: 29D95B64378DB4BF
68 changed files with 247 additions and 72 deletions

46
Cargo.lock generated
View file

@ -2886,6 +2886,16 @@ dependencies = [
[[package]] [[package]]
name = "pakker" name = "pakker"
version = "1.0.2" version = "1.0.2"
dependencies = [
"git2",
"pakker-cli",
"tempfile",
"tokio",
]
[[package]]
name = "pakker-cli"
version = "1.0.2"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"async-trait", "async-trait",
@ -2902,6 +2912,42 @@ dependencies = [
"libc", "libc",
"log", "log",
"md-5", "md-5",
"pakker-core",
"rand 0.10.1",
"regex",
"reqwest",
"semver",
"serde",
"serde_json",
"sha1",
"sha2 0.11.0",
"strsim",
"tempfile",
"textwrap",
"thiserror 2.0.18",
"tokio",
"walkdir",
"yansi",
"zip",
]
[[package]]
name = "pakker-core"
version = "1.0.2"
dependencies = [
"anyhow",
"async-trait",
"comfy-table",
"dialoguer",
"futures",
"git2",
"glob",
"indicatif",
"keyring",
"keyring-core",
"libc",
"log",
"md-5",
"mockito", "mockito",
"rand 0.10.1", "rand 0.10.1",
"regex", "regex",

View file

@ -1,53 +1,52 @@
[package] [workspace]
name = "pakker" members = [ "crates/*", "pakker" ]
version = "1.0.2" resolver = "3"
edition = "2024"
authors = [ "NotAShelf <raf@notashelf.dev>" ] [workspace.package]
description = "A fast, reliable multiplatform modpack manager for Minecraft"
keywords = [ "minecraft", "modpack", "modrinth", "curseforge", "package-manager" ]
categories = [ "command-line-utilities", "games" ] categories = [ "command-line-utilities", "games" ]
edition = "2024"
keywords = [ "minecraft", "modpack", "modrinth", "curseforge", "package-manager" ]
rust-version = "1.94.0" rust-version = "1.94.0"
readme = true version = "1.0.2"
[workspace.dependencies]
pakker-cli = { path = "./crates/pakker-cli" }
pakker-core = { path = "./crates/pakker-core" }
[dependencies] anyhow = "1.0.102"
anyhow = "1.0.102" async-trait = "0.1.89"
async-trait = "0.1.89" clap = { version = "4.6.1", features = [ "derive" ] }
clap = { version = "4.6.1", features = [ "derive" ] } comfy-table = "7.2.2"
comfy-table = "7.2.2" dialoguer = "0.12.0"
dialoguer = "0.12.0" env_logger = "0.11.10"
env_logger = "0.11.10" futures = "0.3.32"
futures = "0.3.32" git2 = "0.20.4"
git2 = "0.20.4" glob = "0.3.3"
glob = "0.3.3" indicatif = "0.18.4"
indicatif = "0.18.4"
keyring = "4.0.0" keyring = "4.0.0"
keyring-core = "1.0.0" keyring-core = "1.0.0"
libc = "0.2.186" libc = "0.2.186"
log = "0.4.29" log = "0.4.29"
md-5 = "0.11.0" md-5 = "0.11.0"
rand = "0.10.1" mockito = "1.7.2"
regex = "1.12.3" rand = "0.10.1"
reqwest = { version = "0.13.3", features = [ "json" ] } regex = "1.12.3"
semver = "1.0.28" reqwest = { version = "0.13.3", features = [ "json" ] }
serde = { version = "1.0.228", features = [ "derive" ] } semver = "1.0.28"
serde_json = "1.0.149" serde = { version = "1.0.228", features = [ "derive" ] }
sha1 = "0.11.0" serde_json = "1.0.149"
sha2 = "0.11.0" sha1 = "0.11.0"
strsim = "0.11.1" sha2 = "0.11.0"
tempfile = "3.27.0" strsim = "0.11.1"
textwrap = "0.16.2" tempfile = "3.27.0"
thiserror = "2.0.18" textwrap = "0.16.2"
tokio = { version = "1.52.1", features = [ "full" ] } thiserror = "2.0.18"
walkdir = "2.5.0" tokio = { version = "1.52.1", features = [ "full" ] }
yansi = "1.0.1" walkdir = "2.5.0"
zip = "8.6.0" yansi = "1.0.1"
zip = "8.6.0"
[dev-dependencies] [workspace.lints.clippy]
mockito = "1.7.2"
tempfile = "3.27.0"
[lints.clippy]
cargo = { level = "warn", priority = -1 } cargo = { level = "warn", priority = -1 }
complexity = { level = "warn", priority = -1 } complexity = { level = "warn", priority = -1 }
nursery = { level = "warn", priority = -1 } nursery = { level = "warn", priority = -1 }

View file

@ -0,0 +1,47 @@
[package]
name = "pakker-cli"
version.workspace = true
edition.workspace = true
description = "CLI library for Pakker"
keywords.workspace = true
categories.workspace = true
rust-version.workspace = true
readme = "../../docs/README.md"
[dependencies]
pakker-core.workspace = true
anyhow.workspace = true
async-trait.workspace = true
clap.workspace = true
comfy-table.workspace = true
dialoguer.workspace = true
env_logger.workspace = true
futures.workspace = true
git2.workspace = true
glob.workspace = true
indicatif.workspace = true
keyring.workspace = true
keyring-core.workspace = true
libc.workspace = true
log.workspace = true
md-5.workspace = true
rand.workspace = true
regex.workspace = true
reqwest.workspace = true
semver.workspace = true
serde.workspace = true
serde_json.workspace = true
sha1.workspace = true
sha2.workspace = true
strsim.workspace = true
tempfile.workspace = true
textwrap.workspace = true
thiserror.workspace = true
tokio.workspace = true
walkdir.workspace = true
yansi.workspace = true
zip.workspace = true
[lints]
workspace = true

View file

@ -7,28 +7,20 @@
reason = "license and repository not yet configured" reason = "license and repository not yet configured"
)] )]
mod cli;
mod error;
mod export;
mod fetch;
mod git;
mod http;
mod ipc;
mod model;
mod platform;
mod rate_limiter;
mod resolver;
mod ui_utils;
mod utils;
use std::{env, path::PathBuf}; use std::{env, path::PathBuf};
use clap::Parser; use clap::Parser;
pub mod cli;
pub use pakker_core::{
error, export, fetch, git, http, ipc, model, platform, rate_limiter, resolver,
ui_utils, utils,
};
use cli::{Cli, Commands}; use cli::{Cli, Commands};
use error::PakkerError; use error::PakkerError;
/// Search for pakker-lock.json in current directory and parent directories
/// Returns the directory containing pakker-lock.json, or None if not found
fn find_working_directory() -> Option<PathBuf> { fn find_working_directory() -> Option<PathBuf> {
let mut current_dir = env::current_dir().ok()?; let mut current_dir = env::current_dir().ok()?;
@ -38,24 +30,20 @@ fn find_working_directory() -> Option<PathBuf> {
return Some(current_dir); return Some(current_dir);
} }
// Try parent directory
if !current_dir.pop() { if !current_dir.pop() {
// Reached filesystem root
return None; return None;
} }
} }
} }
#[tokio::main] pub async fn run() -> Result<(), PakkerError> {
async fn main() -> Result<(), PakkerError> {
let cli = Cli::parse(); let cli = Cli::parse();
// Initialize logging based on verbosity level
let log_level = match cli.verbose { let log_level = match cli.verbose {
0 => "warn", // Default: only warnings and errors 0 => "warn",
1 => "info", // -v: info level 1 => "info",
2 => "debug", // -vv: debug level 2 => "debug",
_ => "trace", // -vvv+: trace level (most verbose) _ => "trace",
}; };
env_logger::Builder::from_env( env_logger::Builder::from_env(
@ -65,17 +53,14 @@ async fn main() -> Result<(), PakkerError> {
.format_module_path(false) .format_module_path(false)
.init(); .init();
// Initialize the platform keyring store so credential commands work.
if let Err(e) = keyring::use_native_store(false) { if let Err(e) = keyring::use_native_store(false) {
log::warn!("Failed to initialize platform keyring store: {e}"); log::warn!("Failed to initialize platform keyring store: {e}");
} }
// Search for pakker-lock.json in current directory and parent directories
let working_dir = let working_dir =
find_working_directory().unwrap_or_else(|| PathBuf::from(".")); find_working_directory().unwrap_or_else(|| PathBuf::from("."));
let lockfile_path = working_dir.join("pakker-lock.json"); let lockfile_path = working_dir.join("pakker-lock.json");
let config_path = working_dir.join("pakker.json"); let config_path = working_dir.join("pakker.json");
let global_yes = cli.yes; let global_yes = cli.yes;
match cli.command { match cli.command {

View file

@ -0,0 +1,47 @@
[package]
name = "pakker-core"
version.workspace = true
edition.workspace = true
description = "Core library for Pakker"
keywords.workspace = true
categories.workspace = true
rust-version.workspace = true
readme = "../../docs/README.md"
[dependencies]
anyhow.workspace = true
async-trait.workspace = true
comfy-table.workspace = true
dialoguer.workspace = true
futures.workspace = true
git2.workspace = true
glob.workspace = true
indicatif.workspace = true
keyring.workspace = true
keyring-core.workspace = true
libc.workspace = true
log.workspace = true
md-5.workspace = true
rand.workspace = true
regex.workspace = true
reqwest.workspace = true
semver.workspace = true
serde.workspace = true
serde_json.workspace = true
sha1.workspace = true
sha2.workspace = true
strsim.workspace = true
tempfile.workspace = true
textwrap.workspace = true
thiserror.workspace = true
tokio.workspace = true
walkdir.workspace = true
yansi.workspace = true
zip.workspace = true
[dev-dependencies]
mockito.workspace = true
tempfile.workspace = true
[lints]
workspace = true

View file

@ -10,10 +10,11 @@ pub enum ErrorSeverity {
/// Fatal error - operation cannot continue /// Fatal error - operation cannot continue
#[default] #[default]
Error, Error,
/// Warning - operation can continue but may have issues /// Warning - operation can continue but may have issues
Warning, Warning,
/// Info - informational message /// Info - informational message
#[expect(dead_code, reason = "reserved for future use")]
Info, Info,
} }

View file

@ -0,0 +1,21 @@
#![expect(
clippy::multiple_crate_versions,
reason = "transitive dependency version conflicts from upstream crates"
)]
#![expect(
clippy::cargo_common_metadata,
reason = "license and repository not yet configured"
)]
pub mod error;
pub mod export;
pub mod fetch;
pub mod git;
pub mod http;
pub mod ipc;
pub mod model;
pub mod platform;
pub mod rate_limiter;
pub mod resolver;
pub mod ui_utils;
pub mod utils;

21
pakker/Cargo.toml Normal file
View file

@ -0,0 +1,21 @@
[package]
name = "pakker"
version.workspace = true
edition.workspace = true
description = "A fast, reliable multiplatform modpack manager for Minecraft"
keywords.workspace = true
categories.workspace = true
rust-version.workspace = true
readme = "../docs/README.md"
[dependencies]
pakker-cli.workspace = true
tokio.workspace = true
[dev-dependencies]
git2.workspace = true
tempfile.workspace = true
[lints]
workspace = true

6
pakker/src/main.rs Normal file
View file

@ -0,0 +1,6 @@
use pakker_cli::error::PakkerError;
#[tokio::main]
async fn main() -> Result<(), PakkerError> {
pakker_cli::run().await
}

View file

@ -4,7 +4,9 @@ use git2::{Repository, Signature};
pub fn pakker_bin_path() -> PathBuf { pub fn pakker_bin_path() -> PathBuf {
let manifest = env!("CARGO_MANIFEST_DIR"); let manifest = env!("CARGO_MANIFEST_DIR");
PathBuf::from(manifest).join("target/debug/pakker") PathBuf::from(manifest)
.join("..")
.join("target/debug/pakker")
} }
pub fn init_bare_repo(path: &PathBuf) -> Result<Repository, git2::Error> { pub fn init_bare_repo(path: &PathBuf) -> Result<Repository, git2::Error> {