From df143b0bf1fd8792f83624653c83235684c86f80 Mon Sep 17 00:00:00 2001 From: gasaichandesu Date: Sat, 30 May 2026 14:39:33 +0400 Subject: [PATCH] =?UTF-8?q?refactor(tool):=20=D0=9D=D0=B5=D0=B1=D0=BE?= =?UTF-8?q?=D0=BB=D1=8C=D1=88=D0=BE=D0=B9=20=D1=80=D0=B5=D1=84=D0=B0=D0=BA?= =?UTF-8?q?=D1=82=D0=BE=D1=80=D0=B8=D0=BD=D0=B3=20CLI?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- run.ps1 | 2 +- tool/.gitignore | 4 +- tool/Cargo.lock | 70 +++++++++++++++++++- tool/Cargo.toml | 3 +- tool/src/commands/build_mpq.rs | 100 ++++++++++++++++++++++++++++ tool/src/commands/mod.rs | 1 + tool/src/main.rs | 115 ++++++--------------------------- 7 files changed, 194 insertions(+), 101 deletions(-) create mode 100644 tool/src/commands/build_mpq.rs create mode 100644 tool/src/commands/mod.rs diff --git a/run.ps1 b/run.ps1 index e139258..3a3deda 100644 --- a/run.ps1 +++ b/run.ps1 @@ -47,7 +47,7 @@ if (!(Test-Path $TOOL)) { # --- Build MPQ archives into dist/ Write-Host "Building MPQ archives from src/ -> dist/..." -& $TOOL $SRC_DIR $DIST_DIR +& $TOOL build-mpq $SRC_DIR $DIST_DIR if ($LASTEXITCODE -ne 0) { Write-Error "MPQ build failed!" exit 1 diff --git a/tool/.gitignore b/tool/.gitignore index 9f97022..182a301 100644 --- a/tool/.gitignore +++ b/tool/.gitignore @@ -1 +1,3 @@ -target/ \ No newline at end of file +target/ +.sqlx/ +.env \ No newline at end of file diff --git a/tool/Cargo.lock b/tool/Cargo.lock index 74ac992..c63b507 100644 --- a/tool/Cargo.lock +++ b/tool/Cargo.lock @@ -624,6 +624,17 @@ dependencies = [ "simd-adler32", ] +[[package]] +name = "mio" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50b7e5b27aa02a74bac8c3f23f448f8d87ff11f92d3aac1a6ed369ee08cc56c1" +dependencies = [ + "libc", + "wasi", + "windows-sys 0.61.2", +] + [[package]] name = "num-bigint" version = "0.4.6" @@ -730,6 +741,12 @@ dependencies = [ "base64ct", ] +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + [[package]] name = "pkcs1" version = "0.7.5" @@ -1055,6 +1072,16 @@ dependencies = [ "digest", ] +[[package]] +name = "signal-hook-registry" +version = "1.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" +dependencies = [ + "errno", + "libc", +] + [[package]] name = "signature" version = "2.2.0" @@ -1077,6 +1104,16 @@ version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" +[[package]] +name = "socket2" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + [[package]] name = "spin" version = "0.9.8" @@ -1149,6 +1186,34 @@ dependencies = [ "syn", ] +[[package]] +name = "tokio" +version = "1.52.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc7f01b389ac15039e4dc9531aa973a135d7a4135281b12d7c1bc79fd57fffe" +dependencies = [ + "bytes", + "libc", + "mio", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "windows-sys 0.61.2", +] + +[[package]] +name = "tokio-macros" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "tool" version = "0.1.0" @@ -1156,15 +1221,16 @@ dependencies = [ "clap", "env_logger", "log", + "tokio", "walkdir", "wow-mpq", ] [[package]] name = "typenum" -version = "1.19.0" +version = "1.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" +checksum = "40ce102ab67701b8526c123c1bab5cbe42d7040ccfd0f64af1a385808d2f43de" [[package]] name = "unicode-ident" diff --git a/tool/Cargo.toml b/tool/Cargo.toml index d6a7e96..e8fc834 100644 --- a/tool/Cargo.toml +++ b/tool/Cargo.toml @@ -4,8 +4,9 @@ version = "0.1.0" edition = "2024" [dependencies] -clap = "4.6.1" +clap = { version = "4.6.1", features = ["derive"] } env_logger = "0.11.10" log = "0.4.30" +tokio = { version = "1.52.3", features = ["full"] } walkdir = "2.5.0" wow-mpq = "0.6.4" diff --git a/tool/src/commands/build_mpq.rs b/tool/src/commands/build_mpq.rs new file mode 100644 index 0000000..3df7300 --- /dev/null +++ b/tool/src/commands/build_mpq.rs @@ -0,0 +1,100 @@ +use clap::Args; +use log::info; +use std::{ + error::Error, + fs, + path::{Path, PathBuf}, +}; +use walkdir::WalkDir; +use wow_mpq::{ArchiveBuilder, FormatVersion, ListfileOption, compression::flags}; + +#[derive(Args, Debug)] +pub struct BuildMpqCommand { + input_dir: PathBuf, + + destination_dir: PathBuf, +} + +pub fn execute(args: BuildMpqCommand) -> Result<(), Box> { + let data_dir = args.input_dir.join("Data"); + if !data_dir.exists() { + return Err(format!("Data directory not found at {}", data_dir.display()).into()); + } + + info!("Found Data directory at {}", data_dir.display()); + + for entry in fs::read_dir(&data_dir)? { + let entry = entry?; + let path = entry.path(); + + if !path.is_dir() { + continue; + } + + let dir_name = entry.file_name().to_string_lossy().to_string(); + + if dir_name.starts_with("ruRU") { + for sub_entry in fs::read_dir(&path)? { + let sub_entry = sub_entry?; + let sub_path = sub_entry.path(); + + let sub_name = sub_entry.file_name().to_string_lossy().to_string(); + let destination = args + .destination_dir + .join("Data") + .join(&dir_name) + .join(&sub_name); + + let _ = build_mpq(&sub_path, &destination); + } + + continue; + } + + let destination = args.destination_dir.join("Data").join(&dir_name); + + let _ = build_mpq(&path, &destination)?; + } + + Ok(()) +} + +fn build_mpq(input_dir: &Path, destination: &Path) -> Result<(), Box> { + info!( + "Packing MPQ from {} to {}", + input_dir.display(), + destination.display() + ); + + let mut destination = destination.to_path_buf(); + destination.set_extension("MPQ"); + + if let Some(parent) = destination.parent() { + fs::create_dir_all(parent)?; + } + + let mut builder = ArchiveBuilder::new() + .version(FormatVersion::V2) + .block_size(7) + .default_compression(flags::ZLIB) + .listfile_option(ListfileOption::Generate); + + let base = input_dir.canonicalize()?; + + for entry in WalkDir::new(&base) + .into_iter() + .filter_map(|e| e.ok()) + .filter(|e| e.file_type().is_file()) + { + let absolute_path = entry.path().canonicalize()?; + let relative_path = absolute_path.strip_prefix(&base)?; + + builder = builder.add_file(&absolute_path, &relative_path.to_string_lossy().to_string()); + } + + let _ = builder.build(&destination); + + info!("Successfully packed {}", destination.display()); + + Ok(()) +} diff --git a/tool/src/commands/mod.rs b/tool/src/commands/mod.rs new file mode 100644 index 0000000..2c4a737 --- /dev/null +++ b/tool/src/commands/mod.rs @@ -0,0 +1 @@ +pub mod build_mpq; diff --git a/tool/src/main.rs b/tool/src/main.rs index 5a51f26..7602ee6 100644 --- a/tool/src/main.rs +++ b/tool/src/main.rs @@ -1,118 +1,41 @@ -use clap::Parser; +mod commands; + +use clap::{Parser, Subcommand}; use log::{error, info}; use std::error::Error; -use std::fs; -use std::path::{Path, PathBuf}; - -use walkdir::WalkDir; -use wow_mpq::compression::flags; -use wow_mpq::{ArchiveBuilder, FormatVersion, ListfileOption}; #[derive(Parser, Debug)] -struct Args { - input_dir: PathBuf, - - destination_dir: PathBuf, +struct Cli { + #[command(subcommand)] + command: Commands, } -fn main() { +#[derive(Subcommand, Debug)] +enum Commands { + BuildMpq(commands::build_mpq::BuildMpqCommand), +} + +#[tokio::main] +async fn main() { env_logger::builder() .filter_level(log::LevelFilter::Debug) .format_target(false) .format_timestamp(None) .init(); - let args = Args::parse(); + let args = Cli::parse(); - if let Err(err) = run(args) { + if let Err(err) = run(args).await { error!("{}", err); std::process::exit(1); } } -fn run(args: Args) -> Result<(), Box> { +async fn run(args: Cli) -> Result<(), Box> { info!("Starting tool..."); - let data_dir = args.input_dir.join("Data"); - if !data_dir.exists() { - return Err(format!("Data directory not found at {}", data_dir.display()).into()); - } - - info!("Found Data directory at {}", data_dir.display()); - - for entry in fs::read_dir(&data_dir)? { - let entry = entry?; - let path = entry.path(); - - if !path.is_dir() { - continue; - } - - let dir_name = entry.file_name().to_string_lossy().to_string(); - - if dir_name.starts_with("ruRU") { - for sub_entry in fs::read_dir(&path)? { - let sub_entry = sub_entry?; - let sub_path = sub_entry.path(); - - let sub_name = sub_entry.file_name().to_string_lossy().to_string(); - let destination = args - .destination_dir - .join("Data") - .join(&dir_name) - .join(&sub_name); - - let _ = build_mpq(&sub_path, &destination); - } - - continue; - } - - let destination = args.destination_dir.join("Data").join(&dir_name); - - let _ = build_mpq(&path, &destination)?; - } - - Ok(()) -} - -fn build_mpq(input_dir: &Path, destination: &Path) -> Result<(), Box> { - info!( - "Packing MPQ from {} to {}", - input_dir.display(), - destination.display() - ); - - let mut destination = destination.to_path_buf(); - destination.set_extension("MPQ"); - - if let Some(parent) = destination.parent() { - fs::create_dir_all(parent)?; - } - - let mut builder = ArchiveBuilder::new() - .version(FormatVersion::V2) - .block_size(7) - .default_compression(flags::ZLIB) - .listfile_option(ListfileOption::Generate); - - let base = input_dir.canonicalize()?; - - for entry in WalkDir::new(&base) - .into_iter() - .filter_map(|e| e.ok()) - .filter(|e| e.file_type().is_file()) - { - let absolute_path = entry.path().canonicalize()?; - let relative_path = absolute_path.strip_prefix(&base)?; - - builder = builder.add_file(&absolute_path, &relative_path.to_string_lossy().to_string()); - } - - let _ = builder.build(&destination); - - info!("Successfully packed {}", destination.display()); - - Ok(()) + return match args.command { + Commands::BuildMpq(args) => commands::build_mpq::execute(args), + }; }