use clap::{Parser, Subcommand};
pub mod apis;
pub mod cache;
pub mod commands;
pub mod config;
pub mod db;
pub mod errors;
pub mod files;
pub mod data;
use commands::{download::download, io::{export, import}, list, modification::{mod_add, mod_remove}, update::update};
use config::Cfg;
use data::{gameversion::VersionLevel, list::List, modification::{AddMod, IDSelector}, modloader::Modloader};
pub use data::{STYLE_BAR_POS, STYLE_MESSAGE, STYLE_SPINNER, STYLE_BAR_BYTE, STYLE_OPERATION, PROGRESS_CHARS};
use db::{config_get_current_list, lists_get, lists_get_all_ids};
use errors::MLE;
#[derive(Parser)]
#[command(author, version, about)]
struct Cli {
#[command(subcommand)]
command: Commands,
/// config file path
#[arg(short, long)]
config: Option<String>,
}
#[derive(Subcommand)]
enum Commands {
r#Mod {
#[command(subcommand)]
command: ModCommands,
},
List {
#[command(subcommand)]
command: ListCommands,
/// Force `GameVersion` update
#[arg(long)]
force_gameupdate: bool,
},
Download {
/// download all lists
#[arg(short, long)]
all: bool,
/// clean all mods before downloading them
#[arg(short, long)]
clean: bool,
/// remove disabled versions
#[arg(short, long)]
remove: bool,
/// optional List selection, else default list will be used
#[arg(short, long)]
list: Option<String>,
},
Update {
/// download all lists
#[arg(short, long)]
all: bool,
/// directly download updated mods
#[arg(short, long)]
download: bool,
/// clean all mods before downloading them
#[arg(short, long)]
clean: bool,
/// delete disabled versions
#[arg(short, long)]
remove: bool,
/// optional List selection, else default list will be used
#[arg(short, long)]
list: Option<String>,
},
Import {
#[arg(short, long)]
file: Option<String>,
/// directly download imported mods
#[arg(short, long)]
download: bool,
},
Export {
/// the list you want to export
list: Option<String>,
},
Test,
}
#[derive(Subcommand)]
enum ModCommands {
Add {
/// id of the mod/version
id: String,
/// set id mode to version
#[arg(short, long)]
version: bool,
/// directly download the mod
#[arg(short, long)]
download: bool,
/// lock the version added
#[arg(/* short , */long)]
lock: bool,
/// optional List selection, else default list will be used
#[arg(short, long)]
list: Option<String>,
},
Remove {
/// id, name or title of the mod
id: String,
/// optional List selection, else default list will be used
#[arg(short, long)]
list: Option<String>,
},
}
#[derive(Subcommand)]
enum ListCommands {
Add {
/// list id
id: String,
directory: String,
modloader: Option<String>,
version: Option<String>,
},
Remove {
/// id, name or title of the list
id: String,
},
List,
Change {
/// id of the list to change to
id: String,
},
Version {
/// list id
id: String,
/// desired minecraft version
version: String,
/// directly download updated mods
#[arg(long, short)]
download: bool,
/// delete disabled versions
#[arg(short, long)]
remove: bool,
},
}
#[tokio::main]
async fn main() {
let cli = Cli::parse();
let config = Cfg::init(cli.config).await.unwrap();
match cli.command {
Commands::Mod { command } => handle_mod(config, command).await,
Commands::List {
command,
force_gameupdate,
} => handle_list(config, command, force_gameupdate).await,
Commands::Update {
all,
download,
clean,
remove,
list,
} => {
let mut liststack: Vec<List> = vec![];
if all {
let list_ids = lists_get_all_ids(&config).unwrap();
for id in list_ids {
liststack.push(lists_get(&config, &id).unwrap());
}
} else {
let current = match list {
Some(l) => lists_get(&config, &l).unwrap(),
None => List::get_current_list(&config).unwrap(),
};
liststack.push(current);
}
update(&config, liststack, clean, download, remove).await
}
Commands::Download {
all,
clean,
remove,
list,
} => {
let mut liststack: Vec<List> = vec![];
if all {
let list_ids = lists_get_all_ids(&config).unwrap();
for id in list_ids {
liststack.push(lists_get(&config, &id).unwrap());
}
} else {
let current = match list {
Some(l) => lists_get(&config, &l).unwrap(),
None => List::get_current_list(&config).unwrap(),
};
liststack.push(current);
}
download(&config, liststack, clean, remove).await
}
Commands::Import { file, download } => {
let filestr: String = match file {
Some(args) => args,
None => dirs::home_dir()
.unwrap()
.join("mlexport.toml")
.into_os_string()
.into_string()
.unwrap(),
};
import(&config, &filestr, download).await
}
Commands::Export { list } => export(&config, list),
Commands::Test => Ok(()),
}
.unwrap();
}
async fn handle_mod(config: Cfg, command: ModCommands) -> MLE<()> {
match command {
ModCommands::Add {
id,
version,
list,
download,
lock,
} => {
let listf = match list {
Some(list) => lists_get(&config, &list).unwrap(),
None => lists_get(
&config,
&config_get_current_list(&config).unwrap(),
)
.unwrap(),
};
let marked_id = if version {
IDSelector::VersionID(id)
} else {
IDSelector::ModificationID(id)
};
let add_id = AddMod {
id: marked_id,
set_version: lock,
};
mod_add(&config, vec![add_id], listf, download).await
}
ModCommands::Remove { id, list } => {
let listf = match list {
Some(list) => lists_get(&config, &list).unwrap(),
None => lists_get(
&config,
&config_get_current_list(&config).unwrap(),
)
.unwrap(),
};
mod_remove(&config, &id, &listf)
}
}
}
async fn handle_list(
config: Cfg,
command: ListCommands,
force_gameupdate: bool,
) -> MLE<()> {
match command {
ListCommands::Add {
id,
directory,
modloader,
version,
} => {
let ml = match modloader {
Some(ml) => Modloader::try_from(ml.as_str())?,
None => config.defaults.modloader.clone(),
};
let versions_path = &config.versions;
let ver = match version {
Some(ver) => VersionLevel::from(&ver)
.get(versions_path, force_gameupdate)
.await
.unwrap(),
None => config
.defaults
.version
.clone()
.get(versions_path, force_gameupdate)
.await
.unwrap(),
};
list::add(&config, &id, &ver, &ml, &directory)
}
ListCommands::Remove { id } => list::remove(&config, &id),
ListCommands::List => list::list(&config),
ListCommands::Change { id } => list::change(&config, &id),
ListCommands::Version {
id,
version,
download,
remove,
} => list::version(&config, &id, version, download, remove).await,
}
}