treewide: remove dead code
Also deletes some dead_code annotations from functions that are *actually used*. Signed-off-by: NotAShelf <raf@notashelf.dev> Change-Id: Ic815cacc93c464078ead1674e7523d8b6a6a6964
This commit is contained in:
parent
b0a594e892
commit
f4287de795
3 changed files with 30 additions and 112 deletions
|
|
@ -13,6 +13,7 @@ use crate::{
|
||||||
|
|
||||||
pub async fn execute(
|
pub async fn execute(
|
||||||
parallel: bool,
|
parallel: bool,
|
||||||
|
skip_prompts: bool,
|
||||||
lockfile_path: &Path,
|
lockfile_path: &Path,
|
||||||
config_path: &Path,
|
config_path: &Path,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
|
|
@ -77,15 +78,15 @@ pub async fn execute(
|
||||||
// Prompt to update if there are updates available
|
// Prompt to update if there are updates available
|
||||||
if !updates.is_empty() {
|
if !updates.is_empty() {
|
||||||
println!();
|
println!();
|
||||||
if crate::ui_utils::prompt_yes_no("Update now?", false)? {
|
if crate::ui_utils::prompt_yes_no("Update now?", false, skip_prompts)? {
|
||||||
// Call update command programmatically (update all projects)
|
// Call update command programmatically (update all projects)
|
||||||
let update_args = crate::cli::UpdateArgs {
|
let update_args = crate::cli::UpdateArgs {
|
||||||
inputs: vec![],
|
inputs: vec![],
|
||||||
all: true,
|
all: true,
|
||||||
yes: true, // Auto-yes for status command
|
|
||||||
};
|
};
|
||||||
crate::cli::commands::update::execute(
|
crate::cli::commands::update::execute(
|
||||||
update_args,
|
update_args,
|
||||||
|
true, // Auto-yes for status command
|
||||||
lockfile_path,
|
lockfile_path,
|
||||||
config_path,
|
config_path,
|
||||||
)
|
)
|
||||||
|
|
@ -380,17 +381,6 @@ fn display_update_results(updates: &[ProjectUpdate]) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
fn get_project_display_name(project: &Project) -> String {
|
|
||||||
project
|
|
||||||
.name
|
|
||||||
.values()
|
|
||||||
.next()
|
|
||||||
.or_else(|| project.slug.values().next())
|
|
||||||
.cloned()
|
|
||||||
.unwrap_or_else(|| "Unknown".to_string())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_api_key(platform: &str) -> Option<String> {
|
fn get_api_key(platform: &str) -> Option<String> {
|
||||||
match platform {
|
match platform {
|
||||||
"modrinth" => std::env::var("MODRINTH_TOKEN").ok(),
|
"modrinth" => std::env::var("MODRINTH_TOKEN").ok(),
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
use std::io;
|
use std::io;
|
||||||
|
|
||||||
use dialoguer::{Confirm, Input, MultiSelect, Select, theme::ColorfulTheme};
|
use dialoguer::{Confirm, Input, Select, theme::ColorfulTheme};
|
||||||
|
|
||||||
/// Creates a terminal hyperlink using OSC 8 escape sequence
|
/// Creates a terminal hyperlink using OSC 8 escape sequence
|
||||||
/// Format: \x1b]8;;<URL>\x1b\\<TEXT>\x1b]8;;\x1b\\
|
/// Format: \x1b]8;;<URL>\x1b\\<TEXT>\x1b]8;;\x1b\\
|
||||||
|
|
@ -12,7 +12,16 @@ pub fn hyperlink(url: &str, text: &str) -> String {
|
||||||
|
|
||||||
/// Prompts user with a yes/no question
|
/// Prompts user with a yes/no question
|
||||||
/// Returns true for yes, false for no
|
/// Returns true for yes, false for no
|
||||||
pub fn prompt_yes_no(question: &str, default: bool) -> io::Result<bool> {
|
/// If `skip_prompts` is true, returns the default value without prompting
|
||||||
|
pub fn prompt_yes_no(
|
||||||
|
question: &str,
|
||||||
|
default: bool,
|
||||||
|
skip_prompts: bool,
|
||||||
|
) -> io::Result<bool> {
|
||||||
|
if skip_prompts {
|
||||||
|
return Ok(default);
|
||||||
|
}
|
||||||
|
|
||||||
Confirm::with_theme(&ColorfulTheme::default())
|
Confirm::with_theme(&ColorfulTheme::default())
|
||||||
.with_prompt(question)
|
.with_prompt(question)
|
||||||
.default(default)
|
.default(default)
|
||||||
|
|
@ -22,7 +31,6 @@ pub fn prompt_yes_no(question: &str, default: bool) -> io::Result<bool> {
|
||||||
|
|
||||||
/// Prompts user to select from a list of options
|
/// Prompts user to select from a list of options
|
||||||
/// Returns the index of the selected option
|
/// Returns the index of the selected option
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn prompt_select(question: &str, options: &[&str]) -> io::Result<usize> {
|
pub fn prompt_select(question: &str, options: &[&str]) -> io::Result<usize> {
|
||||||
Select::with_theme(&ColorfulTheme::default())
|
Select::with_theme(&ColorfulTheme::default())
|
||||||
.with_prompt(question)
|
.with_prompt(question)
|
||||||
|
|
@ -32,28 +40,12 @@ pub fn prompt_select(question: &str, options: &[&str]) -> io::Result<usize> {
|
||||||
.map_err(io::Error::other)
|
.map_err(io::Error::other)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Prompts user to select multiple items from a list
|
|
||||||
/// Returns the indices of the selected options
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn prompt_multi_select(
|
|
||||||
question: &str,
|
|
||||||
options: &[&str],
|
|
||||||
) -> io::Result<Vec<usize>> {
|
|
||||||
MultiSelect::with_theme(&ColorfulTheme::default())
|
|
||||||
.with_prompt(question)
|
|
||||||
.items(options)
|
|
||||||
.interact()
|
|
||||||
.map_err(io::Error::other)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates a formatted project URL for Modrinth
|
/// Creates a formatted project URL for Modrinth
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn modrinth_project_url(slug: &str) -> String {
|
pub fn modrinth_project_url(slug: &str) -> String {
|
||||||
format!("https://modrinth.com/mod/{slug}")
|
format!("https://modrinth.com/mod/{slug}")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a formatted project URL for `CurseForge`
|
/// Creates a formatted project URL for `CurseForge`
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn curseforge_project_url(project_id: &str) -> String {
|
pub fn curseforge_project_url(project_id: &str) -> String {
|
||||||
format!("https://www.curseforge.com/minecraft/mc-mods/{project_id}")
|
format!("https://www.curseforge.com/minecraft/mc-mods/{project_id}")
|
||||||
}
|
}
|
||||||
|
|
@ -118,16 +110,22 @@ pub fn suggest_similar<'a>(
|
||||||
|
|
||||||
/// Prompt user if they meant a similar project name.
|
/// Prompt user if they meant a similar project name.
|
||||||
/// Returns `Some(suggested_name)` if user confirms, None otherwise.
|
/// Returns `Some(suggested_name)` if user confirms, None otherwise.
|
||||||
|
/// If `skip_prompts` is true, automatically accepts the first suggestion.
|
||||||
pub fn prompt_typo_suggestion(
|
pub fn prompt_typo_suggestion(
|
||||||
input: &str,
|
input: &str,
|
||||||
candidates: &[String],
|
candidates: &[String],
|
||||||
|
skip_prompts: bool,
|
||||||
) -> io::Result<Option<String>> {
|
) -> io::Result<Option<String>> {
|
||||||
// Use a max distance based on input length for reasonable suggestions
|
// Use a max distance based on input length for reasonable suggestions
|
||||||
let max_distance = (input.len() / 2).clamp(2, 4);
|
let max_distance = (input.len() / 2).clamp(2, 4);
|
||||||
let suggestions = suggest_similar(input, candidates, max_distance);
|
let suggestions = suggest_similar(input, candidates, max_distance);
|
||||||
|
|
||||||
if let Some(first_suggestion) = suggestions.first()
|
if let Some(first_suggestion) = suggestions.first()
|
||||||
&& prompt_yes_no(&format!("Did you mean '{first_suggestion}'?"), true)?
|
&& prompt_yes_no(
|
||||||
|
&format!("Did you mean '{first_suggestion}'?"),
|
||||||
|
true,
|
||||||
|
skip_prompts,
|
||||||
|
)?
|
||||||
{
|
{
|
||||||
return Ok(Some((*first_suggestion).to_string()));
|
return Ok(Some((*first_suggestion).to_string()));
|
||||||
}
|
}
|
||||||
|
|
@ -164,7 +162,14 @@ pub fn prompt_input_optional(prompt: &str) -> io::Result<Option<String>> {
|
||||||
|
|
||||||
/// Prompt for `CurseForge` API key when authentication fails.
|
/// Prompt for `CurseForge` API key when authentication fails.
|
||||||
/// Returns the API key if provided, None if cancelled.
|
/// Returns the API key if provided, None if cancelled.
|
||||||
pub fn prompt_curseforge_api_key() -> io::Result<Option<String>> {
|
/// If `skip_prompts` is true, returns None immediately.
|
||||||
|
pub fn prompt_curseforge_api_key(
|
||||||
|
skip_prompts: bool,
|
||||||
|
) -> io::Result<Option<String>> {
|
||||||
|
if skip_prompts {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
|
||||||
use dialoguer::Password;
|
use dialoguer::Password;
|
||||||
|
|
||||||
println!();
|
println!();
|
||||||
|
|
@ -172,7 +177,7 @@ pub fn prompt_curseforge_api_key() -> io::Result<Option<String>> {
|
||||||
println!("Get your API key from: https://console.curseforge.com/");
|
println!("Get your API key from: https://console.curseforge.com/");
|
||||||
println!();
|
println!();
|
||||||
|
|
||||||
if !prompt_yes_no("Would you like to enter your API key now?", true)? {
|
if !prompt_yes_no("Would you like to enter your API key now?", true, false)? {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,58 +10,6 @@ use sha2::{Sha256, Sha512};
|
||||||
|
|
||||||
use crate::error::{PakkerError, Result};
|
use crate::error::{PakkerError, Result};
|
||||||
|
|
||||||
/// Compute Murmur2 hash (32-bit) for `CurseForge` fingerprinting
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn compute_murmur2_hash(data: &[u8]) -> u32 {
|
|
||||||
murmur2_hash(data, 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Murmur2 hash implementation
|
|
||||||
#[allow(dead_code)]
|
|
||||||
fn murmur2_hash(data: &[u8], seed: u32) -> u32 {
|
|
||||||
const M: u32 = 0x5BD1E995;
|
|
||||||
const R: i32 = 24;
|
|
||||||
|
|
||||||
let mut h: u32 = seed ^ (data.len() as u32);
|
|
||||||
let mut chunks = data.chunks_exact(4);
|
|
||||||
|
|
||||||
for chunk in chunks.by_ref() {
|
|
||||||
let mut k = u32::from_le_bytes([chunk[0], chunk[1], chunk[2], chunk[3]]);
|
|
||||||
k = k.wrapping_mul(M);
|
|
||||||
k ^= k >> R;
|
|
||||||
k = k.wrapping_mul(M);
|
|
||||||
|
|
||||||
h = h.wrapping_mul(M);
|
|
||||||
h ^= k;
|
|
||||||
}
|
|
||||||
|
|
||||||
let remainder = chunks.remainder();
|
|
||||||
match remainder.len() {
|
|
||||||
3 => {
|
|
||||||
h ^= u32::from(remainder[2]) << 16;
|
|
||||||
h ^= u32::from(remainder[1]) << 8;
|
|
||||||
h ^= u32::from(remainder[0]);
|
|
||||||
h = h.wrapping_mul(M);
|
|
||||||
},
|
|
||||||
2 => {
|
|
||||||
h ^= u32::from(remainder[1]) << 8;
|
|
||||||
h ^= u32::from(remainder[0]);
|
|
||||||
h = h.wrapping_mul(M);
|
|
||||||
},
|
|
||||||
1 => {
|
|
||||||
h ^= u32::from(remainder[0]);
|
|
||||||
h = h.wrapping_mul(M);
|
|
||||||
},
|
|
||||||
_ => {},
|
|
||||||
}
|
|
||||||
|
|
||||||
h ^= h >> 13;
|
|
||||||
h = h.wrapping_mul(M);
|
|
||||||
h ^= h >> 15;
|
|
||||||
|
|
||||||
h
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Compute SHA1 hash of a file
|
/// Compute SHA1 hash of a file
|
||||||
pub fn compute_sha1<P: AsRef<Path>>(path: P) -> Result<String> {
|
pub fn compute_sha1<P: AsRef<Path>>(path: P) -> Result<String> {
|
||||||
let file = File::open(path)?;
|
let file = File::open(path)?;
|
||||||
|
|
@ -167,31 +115,6 @@ pub fn verify_hash<P: AsRef<Path>>(
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_murmur2_hash_deterministic() {
|
|
||||||
let data = b"hello world";
|
|
||||||
let hash1 = compute_murmur2_hash(data);
|
|
||||||
let hash2 = compute_murmur2_hash(data);
|
|
||||||
assert_eq!(hash1, hash2, "Murmur2 hash must be deterministic");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_murmur2_hash_empty() {
|
|
||||||
let data = b"";
|
|
||||||
let hash = compute_murmur2_hash(data);
|
|
||||||
assert_ne!(hash, 0, "Empty data should produce a non-zero hash");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_murmur2_hash_different_inputs() {
|
|
||||||
let hash1 = compute_murmur2_hash(b"hello");
|
|
||||||
let hash2 = compute_murmur2_hash(b"world");
|
|
||||||
assert_ne!(
|
|
||||||
hash1, hash2,
|
|
||||||
"Different inputs should produce different hashes"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_sha256_bytes_deterministic() {
|
fn test_sha256_bytes_deterministic() {
|
||||||
let data = b"test data";
|
let data = b"test data";
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue