Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(cli): implement cli sub commands #36

Merged
merged 1 commit into from
Jan 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion dar2oar_cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ path = "./src/main.rs"

[dependencies]
anyhow = { version = "1.0.75", features = ["backtrace"] }
clap = { version = "4.4.4", features = ["derive"] } # For CLI
# NOTE: clap uses v3.2.23, the last successfully built version, because color mode was erased in v4
clap = { version = "3.2.23", features = ["derive"] } # For CLI
dar2oar_core = { path = "../dar2oar_core" }
tokio = { version = "1.33.0", features = [
"fs",
Expand All @@ -25,6 +26,7 @@ tokio = { version = "1.33.0", features = [
"macros",
] }
tracing = "0.1.40" # Logger
tracing-appender = "0.2.2"
tracing-subscriber = "0.3.17"

[dev-dependencies]
Expand Down
59 changes: 59 additions & 0 deletions dar2oar_cli/src/cli/commands.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
use crate::convert::Convert;
use clap::Args;

#[derive(Debug, clap::Parser)]
#[clap(version, about)]
pub(crate) enum Commands {
/// Convert DAR to OAR
#[clap(arg_required_else_help = true)]
Convert(Convert),

#[clap(arg_required_else_help = true)]
/// Unhide all files in the `DynamicAnimationReplacer` directory
/// by removing the `mohidden` extension
UnhideDar(UnhideDarOption),

#[clap(arg_required_else_help = true)]
/// Find and delete `OpenAnimationReplacer` directory
RemoveOar(RemoveOarOption),
}

#[derive(Debug, Args)]
pub(super) struct UnhideDarOption {
#[clap(value_parser)]
/// DAR directory containing files with ".mohidden" extension
pub dar_dir: String,

// ---logger
#[clap(long)]
/// Log output to stdout as well
pub stdout: bool,
#[clap(long, default_value = "error")]
/// Log level
///
/// trace | debug | info | warn | error
pub log_level: String,
#[clap(long, default_value = "./convert.log")]
/// Output path of log file
pub log_path: String,
}

#[derive(Debug, Args)]
pub(super) struct RemoveOarOption {
#[clap(value_parser)]
/// Path containing the "OpenAnimationReplacer" directory
pub target_path: String,

// ---logger
#[clap(long)]
/// Log output to stdout as well
pub stdout: bool,
#[clap(long, default_value = "error")]
/// Log level
///
/// trace | debug | info | warn | error
pub log_level: String,
#[clap(long, default_value = "./convert.log")]
/// Output path of log file
pub log_path: String,
}
45 changes: 45 additions & 0 deletions dar2oar_cli/src/cli/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
mod commands;

use crate::cli::commands::Commands;
use crate::convert::dar2oar;
use crate::init_tracing;
use dar2oar_core::{remove_oar, unhide_dar, Closure};
use std::str::FromStr;
use tracing::Level;

/// Converter CLI version
#[derive(Debug, clap::Parser)]
#[clap(name = "dar2oar", about)]
pub(crate) struct Cli {
#[clap(subcommand)]
command: Commands,
}

macro_rules! init_logger {
($args:ident) => {
init_tracing(
&$args.log_path,
Level::from_str(&$args.log_level).unwrap_or(Level::ERROR),
$args.stdout,
)?;
};
}

pub(crate) async fn run_cli(args: Cli) -> anyhow::Result<()> {
match args.command {
Commands::Convert(args) => {
init_logger!(args);
dar2oar(args).await?;
}
Commands::UnhideDar(args) => {
init_logger!(args);
unhide_dar(args.dar_dir, Closure::default).await?;
}
Commands::RemoveOar(args) => {
init_logger!(args);
remove_oar(args.target_path, Closure::default).await?;
}
}

Ok(())
}
70 changes: 70 additions & 0 deletions dar2oar_cli/src/convert.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
use dar2oar_core::{convert_dar_to_oar, get_mapping_table, Closure, ConvertOptions};

pub(crate) async fn dar2oar(args: Convert) -> anyhow::Result<()> {
let config = ConvertOptions {
dar_dir: args.src,
oar_dir: args.dist,
mod_name: args.name,
author: args.author,
section_table: get_mapping_table(args.mapping_file).await,
section_1person_table: get_mapping_table(args.mapping_1person_file).await,
run_parallel: args.run_parallel,
hide_dar: args.hide_dar,
};
match convert_dar_to_oar(config, Closure::default).await {
Ok(()) => Ok(()),
Err(err) => {
tracing::error!("{}", err);
anyhow::bail!("{}", err)
}
}
}

#[derive(Debug, clap::Args)]
pub(crate) struct Convert {
#[clap(value_parser)]
/// DAR source dir path
src: String,
#[clap(long)]
/// OAR destination dir path(If not, it is inferred from DAR path)
dist: Option<String>,
#[clap(long)]
/// Mod name in config.json & directory name(If not, it is inferred from DAR path)
name: Option<String>,
#[clap(long)]
/// Mod author in config.json
author: Option<String>,
#[clap(long)]
/// Path to section name table
///
/// - See more details
/// https://github.com/SARDONYX-sard/dar-to-oar/wiki#what-is-the-mapping-file
mapping_file: Option<String>,
#[clap(long)]
/// Path to section name table(For _1st_person)
mapping_1person_file: Option<String>,
#[clap(long)]
/// Use multi thread
///
/// [Note]
/// More than twice the processing speed can be expected,
/// but the concurrent processing results in thread termination timings being out of order,
/// so log writes will be out of order as well, greatly reducing readability of the logs.
run_parallel: bool,
#[clap(long)]
/// After conversion, add ".mohidden" to all DAR files to hide them(For MO2 user)
hide_dar: bool,

// ---logger
#[clap(long)]
/// Log output to stdout as well
pub stdout: bool,
#[clap(long, default_value = "error")]
/// Log level
///
/// trace | debug | info | warn | error
pub log_level: String,
#[clap(long, default_value = "./convert.log")]
/// Output path of log file
pub log_path: String,
}
37 changes: 37 additions & 0 deletions dar2oar_cli/src/logger.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
use std::fs::File;
use std::path::Path;
use tracing::level_filters::LevelFilter;

/// Init logger.
pub(crate) fn init_tracing(
log_path: impl AsRef<Path>,
filter: impl Into<LevelFilter>,
with_stdout: bool,
) -> anyhow::Result<()> {
use tracing_subscriber::{fmt, layer::SubscriberExt};
let log_path = log_path.as_ref();
if let Some(log_path) = log_path.parent() {
std::fs::create_dir_all(log_path)?;
};

match with_stdout {
true => tracing::subscriber::set_global_default(
fmt::Subscriber::builder()
.with_max_level(filter)
.finish()
.with(
fmt::Layer::default()
.with_writer(File::create(log_path)?)
.with_line_number(true)
.with_ansi(false),
),
)?,
false => tracing_subscriber::fmt()
.with_ansi(false)
.with_writer(File::create(log_path)?)
.with_max_level(filter)
.init(),
}

Ok(())
}
68 changes: 8 additions & 60 deletions dar2oar_cli/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,69 +1,17 @@
use clap::{arg, Parser};
use dar2oar_core::{convert_dar_to_oar, get_mapping_table, Closure, ConvertOptions};
use std::fs::File;
use std::str::FromStr;
use tokio::time::Instant;
use tracing::Level;
mod cli;
mod convert;
mod logger;

/// dar2oar --src "DAR path" --dist "OAR path"
#[derive(Debug, Parser)]
#[command(version, about)]
pub struct Args {
/// DAR source dir path
#[arg(long)]
src: String,
/// OAR destination dir path(If not, it is inferred from src)
#[arg(long)]
dist: Option<String>,
/// mod name in config.json & directory name(If not, it is inferred from src)
#[arg(long)]
name: Option<String>,
/// mod author in config.json
#[arg(long)]
author: Option<String>,
/// path to section name table
#[arg(long)]
mapping_file: Option<String>,
/// path to section name table(For _1st_person)
#[arg(long)]
mapping_1person_file: Option<String>,
/// log_level trace | debug | info | warn | error
#[arg(long, default_value = "error")]
log_level: String,
/// Output path of log file
#[arg(long, default_value = "./convert.log")]
log_path: String,
/// use multi thread(More than twice the processing speed can be expected, but the logs are difficult to read and may fail due to unexpected bugs.)
#[arg(long)]
run_parallel: bool,
#[arg(long)]
/// After converting to OAR, add mohidden to the DAR directory before conversion to treat it as a hidden directory. (for MO2 users)
/// NOTE: It appears to work on the MO2 Tree view, but it is doubtful that it works in the author's actual experience.
hide_dar: bool,
}
use crate::cli::{run_cli, Cli};
use crate::logger::init_tracing;
use clap::Parser;
use tokio::time::Instant;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
let start = Instant::now();
let args = Args::parse();
tracing_subscriber::fmt()
.with_ansi(false)
.with_writer(File::create(&args.log_path)?)
.with_max_level(Level::from_str(&args.log_level).unwrap_or(Level::ERROR))
.init();

let config = ConvertOptions {
dar_dir: args.src,
oar_dir: args.dist,
mod_name: args.name,
author: args.author,
section_table: get_mapping_table(args.mapping_file).await,
section_1person_table: get_mapping_table(args.mapping_1person_file).await,
run_parallel: args.run_parallel,
hide_dar: args.hide_dar,
};

match convert_dar_to_oar(config, Closure::default).await {
match run_cli(Cli::parse()).await {
Ok(()) => {
let elapsed = start.elapsed();
tracing::info!(
Expand Down
10 changes: 3 additions & 7 deletions dar2oar_core/src/fs/converter/support_cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,8 @@ use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use tokio::fs;

/// # Returns
/// Report which dirs have been shown
///
/// # NOTE
/// It is currently used only in GUI, but is implemented in Core as an API.
/// A parallel search will find the `DynamicAnimationReplacer` directory in the path passed as the argument
/// and remove only the `mohidden` extension names from the files in that directory.
pub async fn unhide_dar(
dar_dir: impl AsRef<Path>,
mut progress_fn: impl FnMut(usize),
Expand Down Expand Up @@ -58,8 +55,7 @@ pub async fn unhide_dar(
}
}

/// # NOTE
/// It is currently used only in GUI, but is implemented in Core as an API.
/// A parallel search will find and remove the `OpenAnimationReplacer` directory from the path passed as the argument.
pub async fn remove_oar(
search_dir: impl AsRef<Path>,
mut progress_fn: impl FnMut(usize),
Expand Down
Loading