Skip to content

Commit

Permalink
Implement scanning of mods
Browse files Browse the repository at this point in the history
  • Loading branch information
theRookieCoder committed Jun 11, 2024
1 parent 7816162 commit 9929937
Show file tree
Hide file tree
Showing 10 changed files with 179 additions and 51 deletions.
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
# Changelog for Ferium

## `v4.7.0`
### 11.06.2024

- Features
- Scan a directory (the profile's output directory by default) to automatically add the mods
- Uses a maximum of 4 network requests! Unfortunately file hashing and searching for the file on the server take some time so it's not instant, especially with a large number of mods.

- Internal Changes
- Move code for displaying successes and failures to the `add` module

## `v4.6.0`
### 10.06.2024

Expand Down
18 changes: 10 additions & 8 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
[package]

name = "ferium"
version = "4.6.0"
version = "4.7.0"
repository = "https://github.com/gorilla-devs/ferium"
description = "Fast CLI program for managing Minecraft mods and modpacks from Modrinth, CurseForge, and Github Releases"
authors = [
## Code
"Ilesh Thiada (theRookieCoder) <[email protected]>", # AUR, Scoop, Homebrew, winget
"atamakahere (atamakahere-git)",
"Tuxinal",

## Package Management
"KyleUltimateS", # AUR
Expand Down Expand Up @@ -58,7 +59,7 @@ octocrab = "0.38"
fs_extra = "1.3"
ferinth = "2.11"
colored = "2.1"
libium = "1.28"
libium = "1.29"
anyhow = "1.0"
furse = "1.5"
size = "0.4"
Expand Down
48 changes: 48 additions & 0 deletions src/add.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
use std::collections::HashMap;

use colored::Colorize as _;
use itertools::Itertools as _;
use libium::add::Error;

pub fn display_successes_failures(successes: &[String], failures: Vec<(String, Error)>) -> bool {
if !successes.is_empty() {
println!(
"{} {}",
"Successfully added".green(),
successes.iter().map(|s| s.bold()).format(", ")
);
}

let mut grouped_errors = HashMap::new();

for (id, error) in failures {
grouped_errors
.entry(error.to_string())
.or_insert_with(Vec::new)
.push(id);
}

let pad_len = grouped_errors
.keys()
.map(String::len)
.max()
.unwrap_or(0)
.clamp(0, 50);

let mut exit_error = false;
for (err, ids) in grouped_errors {
println!(
"{:pad_len$}: {}",
// Change already added into a warning
if err == libium::add::Error::AlreadyAdded.to_string() {
err.yellow()
} else {
exit_error = true;
err.red()
},
ids.iter().map(|s| s.italic()).format(", ")
);
}

exit_error
}
37 changes: 36 additions & 1 deletion src/cli.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#![deny(missing_docs)]

use clap::{Parser, Subcommand, ValueHint};
use clap::{Parser, Subcommand, ValueEnum, ValueHint};
use clap_complete::Shell;
use libium::config::structs::ModLoader;
use std::path::PathBuf;
Expand Down Expand Up @@ -55,6 +55,23 @@ pub enum SubCommands {
#[clap(long, short = 'M', alias = "dont-check-mod-loader")]
ignore_mod_loader: bool,
},
/// Scan the profile's output directory (or the specified directory) for mods and add them to the profile
Scan {
/// The platform you prefer mods to be added from.
/// If a mod isn't available from this platform, the other platform will still be used.
#[clap(long, short, default_value_t)]
platform: Platform,
/// The directory to scan mods from.
/// Defaults to the profile's output directory.
#[clap(long, short,
visible_aliases = ["dir", "folder"],
aliases = ["output_directory", "out_dir"]
)]
directory: Option<PathBuf>,
/// Temporarily ignore game version and mod loader checks and add the mods anyway
#[clap(long, short, visible_alias = "override")]
force: bool,
},
/// Print shell auto completions for the specified shell
Complete {
/// The shell to generate auto completions for
Expand Down Expand Up @@ -224,3 +241,21 @@ pub enum ModpackSubCommands {
#[clap(visible_aliases = ["download", "install"])]
Upgrade,
}

#[derive(Clone, Copy, Default, ValueEnum)]
pub enum Platform {
#[default]
#[clap(alias = "mr")]
Modrinth,
#[clap(alias = "cf")]
Curseforge,
}

impl std::fmt::Display for Platform {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Modrinth => write!(f, "modrinth"),
Self::Curseforge => write!(f, "curseforge"),
}
}
}
104 changes: 64 additions & 40 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
clippy::too_many_lines
)]

mod add;
mod cli;
mod download;
mod subcommands;
Expand All @@ -41,7 +42,6 @@ use libium::{
};
use once_cell::sync::Lazy;
use std::{
collections::HashMap,
env::{var, var_os},
process::ExitCode,
};
Expand Down Expand Up @@ -170,6 +170,63 @@ async fn actual_main(mut cli_app: Ferium) -> Result<()> {
SubCommands::Complete { .. } | SubCommands::Profiles | SubCommands::Modpacks => {
unreachable!();
}
SubCommands::Scan {
platform,
directory,
force,
} => {
let profile = get_active_profile(&mut config)?;

let spinner = indicatif::ProgressBar::new_spinner().with_message("Reading files");
spinner.enable_steady_tick(std::time::Duration::from_millis(100));

let ids = libium::scan(
&modrinth,
&curseforge,
directory.as_ref().unwrap_or(&profile.output_dir),
|| {
spinner.set_message("Querying servers");
},
)
.await?;

spinner.set_message("Adding mods");

let mut send_ids = Vec::new();
for id in ids {
use libium::config::structs::ModIdentifier;
match id {
(filename, None, None) => {
println!("{} {}", "Unknown file:".yellow(), filename.dimmed());
}
(_, Some(mr_id), None) => send_ids.push(ModIdentifier::ModrinthProject(mr_id)),
(_, None, Some(cf_id)) => {
send_ids.push(ModIdentifier::CurseForgeProject(cf_id));
}
(_, Some(mr_id), Some(cf_id)) => match platform {
cli::Platform::Modrinth => {
send_ids.push(ModIdentifier::ModrinthProject(mr_id));
}
cli::Platform::Curseforge => {
send_ids.push(ModIdentifier::CurseForgeProject(cf_id));
}
},
}
}

let (successes, failures) = libium::add(
libium::APIs::new(&modrinth, &curseforge, &github.build()?),
profile,
send_ids,
!force,
true,
true,
)
.await?;
spinner.finish_and_clear();

add_error = add::display_successes_failures(&successes, failures);
}
SubCommands::Add {
identifiers,
force,
Expand All @@ -182,53 +239,20 @@ async fn actual_main(mut cli_app: Ferium) -> Result<()> {
bail!("Only use the ignore flags when adding a single mod!")
}

let (successes, failures) = libium::add::add(
let (successes, failures) = libium::add(
libium::APIs::new(&modrinth, &curseforge, &github.build()?),
profile,
identifiers,
identifiers
.into_iter()
.map(libium::add::parse_id)
.collect_vec(),
!force,
!ignore_game_version,
!ignore_mod_loader,
)
.await?;

if !successes.is_empty() {
println!(
"{} {}",
"Successfully added".green(),
successes.iter().map(|s| s.bold()).format(", ")
);
}

let mut grouped_errors = HashMap::new();

for (id, error) in failures {
grouped_errors
.entry(error.to_string())
.or_insert_with(Vec::new)
.push(id);
}

let pad_len = grouped_errors
.keys()
.map(String::len)
.max()
.unwrap_or(0)
.clamp(0, 50);

for (err, ids) in grouped_errors {
println!(
"{:pad_len$}: {}",
// Change already added into a warning
if err == libium::add::Error::AlreadyAdded.to_string() {
err.yellow()
} else {
add_error |= true;
err.red()
},
ids.iter().map(|s| s.italic()).format(", ")
);
}
add_error = add::display_successes_failures(&successes, failures);
}
SubCommands::List { verbose, markdown } => {
let profile = get_active_profile(&mut config)?;
Expand Down
8 changes: 8 additions & 0 deletions tests/integration_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,14 @@ fn add_all() -> Result {
)
}

#[test]
fn scan_dir() -> Result {
run_command(
vec!["scan", "--directory", "./tests/test_mods"],
Some("empty_profile"),
)
}

#[test]
fn modpack_add_modrinth() -> Result {
// Add Fabulously Optimised
Expand Down
Binary file added tests/test_mods/Incendium.jar
Binary file not shown.
Binary file added tests/test_mods/Sodium.jar
Binary file not shown.
Binary file added tests/test_mods/Starlight.jar
Binary file not shown.

0 comments on commit 9929937

Please sign in to comment.