From d7ddf3710f6aff40d0595430f5f49255c89fdca1 Mon Sep 17 00:00:00 2001 From: "Begonia, HE" <163421589+BegoniaHe@users.noreply.github.com> Date: Sun, 25 Jan 2026 04:52:35 +0100 Subject: refactor(java): modularize Java detection and management system - Split monolithic java.rs (1089 lines) into focused modules - detection: Java installation discovery - validation: Version validation and requirements checking - priority: Installation selection priority logic - provider: Java download provider trait - providers: Provider implementations (Adoptium) - persistence: Cache and catalog management - Add java_path_override field to Instance struct for per-instance Java configuration - Export JavaInstallation at core module level This refactoring improves maintainability and prepares for multi-vendor Java provider support. Reviewed-by: Claude Sonnet 4.5 --- src-tauri/src/core/java/validation.rs | 120 ++++++++++++++++++++++++++++++++++ 1 file changed, 120 insertions(+) create mode 100644 src-tauri/src/core/java/validation.rs (limited to 'src-tauri/src/core/java/validation.rs') diff --git a/src-tauri/src/core/java/validation.rs b/src-tauri/src/core/java/validation.rs new file mode 100644 index 0000000..ec7745d --- /dev/null +++ b/src-tauri/src/core/java/validation.rs @@ -0,0 +1,120 @@ +use std::path::PathBuf; +use std::process::Command; +use std::time::Duration; + +#[cfg(target_os = "windows")] +use std::os::windows::process::CommandExt; + +use super::JavaInstallation; + +const JAVA_CHECK_TIMEOUT: Duration = Duration::from_secs(5); + +pub fn strip_unc_prefix(path: PathBuf) -> PathBuf { + #[cfg(target_os = "windows")] + { + let s = path.to_string_lossy().to_string(); + if s.starts_with(r"\\?\") { + return PathBuf::from(&s[4..]); + } + } + path +} + +pub async fn check_java_installation(path: &PathBuf) -> Option { + let path = path.clone(); + tokio::task::spawn_blocking(move || { + check_java_installation_blocking(&path) + }) + .await + .ok()? +} + +fn check_java_installation_blocking(path: &PathBuf) -> Option { + let mut cmd = Command::new(path); + cmd.arg("-version"); + #[cfg(target_os = "windows")] + cmd.creation_flags(0x08000000); + + let output = cmd.output().ok()?; + + let version_output = String::from_utf8_lossy(&output.stderr); + + let version = parse_version_string(&version_output)?; + let arch = extract_architecture(&version_output); + let vendor = extract_vendor(&version_output); + let is_64bit = version_output.contains("64-Bit"); + + Some(JavaInstallation { + path: path.to_string_lossy().to_string(), + version, + arch, + vendor, + source: "system".to_string(), + is_64bit, + }) +} + +pub fn parse_version_string(output: &str) -> Option { + for line in output.lines() { + if line.contains("version") { + if let Some(start) = line.find('"') { + if let Some(end) = line[start + 1..].find('"') { + return Some(line[start + 1..start + 1 + end].to_string()); + } + } + } + } + None +} + +pub fn parse_java_version(version: &str) -> u32 { + let parts: Vec<&str> = version.split('.').collect(); + if let Some(first) = parts.first() { + // Handle both legacy (1.x) and modern (x) versioning + if *first == "1" { + // Legacy versioning + parts.get(1).and_then(|s| s.parse().ok()).unwrap_or(0) + } else { + // Modern versioning + first.parse().unwrap_or(0) + } + } else { + 0 + } +} + +pub fn extract_architecture(version_output: &str) -> String { + if version_output.contains("64-Bit") { + "x64".to_string() + } else if version_output.contains("32-Bit") { + "x86".to_string() + } else if version_output.contains("aarch64") || version_output.contains("ARM64") { + "aarch64".to_string() + } else { + "x64".to_string() + } +} + +pub fn extract_vendor(version_output: &str) -> String { + let lower = version_output.to_lowercase(); + + if lower.contains("temurin") || lower.contains("adoptium") { + "Eclipse Adoptium".to_string() + } else if lower.contains("openjdk") { + "OpenJDK".to_string() + } else if lower.contains("oracle") { + "Oracle".to_string() + } else if lower.contains("microsoft") { + "Microsoft".to_string() + } else if lower.contains("zulu") { + "Azul Zulu".to_string() + } else if lower.contains("corretto") { + "Amazon Corretto".to_string() + } else if lower.contains("liberica") { + "BellSoft Liberica".to_string() + } else if lower.contains("graalvm") { + "GraalVM".to_string() + } else { + "Unknown".to_string() + } +} -- cgit v1.2.3-70-g09d2 From 83e9e3c6067c8a2016676d461c17835d4da8b7ab Mon Sep 17 00:00:00 2001 From: "Begonia, HE" <163421589+BegoniaHe@users.noreply.github.com> Date: Sun, 25 Jan 2026 10:28:46 +0100 Subject: refactor(java): address Sourcery AI code review feedback - Centralize strip_unc_prefix into java/mod.rs to eliminate duplication across detection.rs and validation.rs - Remove unused JAVA_CHECK_TIMEOUT constant from validation.rs - Implement actual timeout mechanism in run_which_command_with_timeout() using try_wait() loop - Parallelize Adoptium API requests for better catalog fetch performance Fixes: - Multiple strip_unc_prefix implementations consolidated - Timeout constant now properly enforced in which/where command execution - Catalog fetching now uses concurrent tokio::spawn tasks instead of sequential await Reviewed-by: Claude Sonnet 4.5 --- src-tauri/src/core/java/detection.rs | 59 +++++++++------ src-tauri/src/core/java/mod.rs | 18 ++++- src-tauri/src/core/java/providers/adoptium.rs | 103 ++++++++++++++------------ src-tauri/src/core/java/validation.rs | 14 ---- 4 files changed, 110 insertions(+), 84 deletions(-) (limited to 'src-tauri/src/core/java/validation.rs') diff --git a/src-tauri/src/core/java/detection.rs b/src-tauri/src/core/java/detection.rs index 263580f..ee2111e 100644 --- a/src-tauri/src/core/java/detection.rs +++ b/src-tauri/src/core/java/detection.rs @@ -1,20 +1,15 @@ +use std::io::Read; use std::path::PathBuf; -use std::process::Command; +use std::process::{Command, Stdio}; +use std::thread::sleep; +use std::time::{Duration, Instant}; #[cfg(target_os = "windows")] use std::os::windows::process::CommandExt; -pub fn strip_unc_prefix(path: PathBuf) -> PathBuf { - #[cfg(target_os = "windows")] - { - // Remove the UNC prefix (\\?\) from Windows paths - let s = path.to_string_lossy().to_string(); - if s.starts_with(r"\\?\") { - return PathBuf::from(&s[4..]); - } - } - path -} +use super::strip_unc_prefix; + +const WHICH_TIMEOUT: Duration = Duration::from_secs(2); pub fn find_sdkman_java() -> Option { let home = std::env::var("HOME").ok()?; @@ -30,18 +25,40 @@ fn run_which_command_with_timeout() -> Option { let mut cmd = Command::new(if cfg!(windows) { "where" } else { "which" }); cmd.arg("java"); #[cfg(target_os = "windows")] - // Hide the console window on Windows cmd.creation_flags(0x08000000); - - match cmd.output() { - Ok(output) => { - if output.status.success() { - Some(String::from_utf8_lossy(&output.stdout).to_string()) - } else { - None + cmd.stdout(Stdio::piped()); + + let start = Instant::now(); + let mut child = cmd.spawn().ok()?; + + loop { + match child.try_wait() { + Ok(Some(status)) => { + if status.success() { + let mut output = String::new(); + if let Some(mut stdout) = child.stdout.take() { + let _ = stdout.read_to_string(&mut output); + } + return Some(output); + } else { + let _ = child.wait(); + return None; + } + } + Ok(None) => { + if start.elapsed() >= WHICH_TIMEOUT { + let _ = child.kill(); + let _ = child.wait(); + return None; + } + sleep(Duration::from_millis(50)); + } + Err(_) => { + let _ = child.kill(); + let _ = child.wait(); + return None; } } - Err(_) => None, } } diff --git a/src-tauri/src/core/java/mod.rs b/src-tauri/src/core/java/mod.rs index fd82390..05bf734 100644 --- a/src-tauri/src/core/java/mod.rs +++ b/src-tauri/src/core/java/mod.rs @@ -9,6 +9,18 @@ pub mod validation; pub mod provider; pub mod providers; +/// Remove the UNC prefix (\\?\) from Windows paths +pub fn strip_unc_prefix(path: PathBuf) -> PathBuf { + #[cfg(target_os = "windows")] + { + let s = path.to_string_lossy().to_string(); + if s.starts_with(r"\\?\\") { + return PathBuf::from(&s[4..]); + } + } + path +} + use crate::core::downloader::{DownloadQueue, JavaDownloadProgress, PendingJavaDownload}; use crate::utils::zip; use provider::JavaProvider; @@ -267,7 +279,7 @@ pub async fn download_and_install_java( } let java_bin = std::fs::canonicalize(&java_bin).map_err(|e| e.to_string())?; - let java_bin = validation::strip_unc_prefix(java_bin); + let java_bin = strip_unc_prefix(java_bin); let installation = validation::check_java_installation(&java_bin) .await @@ -431,7 +443,7 @@ fn find_java_executable(dir: &PathBuf) -> Option { let direct_bin = dir.join("bin").join(bin_name); if direct_bin.exists() { let resolved = std::fs::canonicalize(&direct_bin).unwrap_or(direct_bin); - return Some(validation::strip_unc_prefix(resolved)); + return Some(strip_unc_prefix(resolved)); } #[cfg(target_os = "macos")] @@ -449,7 +461,7 @@ fn find_java_executable(dir: &PathBuf) -> Option { let nested_bin = path.join("bin").join(bin_name); if nested_bin.exists() { let resolved = std::fs::canonicalize(&nested_bin).unwrap_or(nested_bin); - return Some(validation::strip_unc_prefix(resolved)); + return Some(strip_unc_prefix(resolved)); } #[cfg(target_os = "macos")] diff --git a/src-tauri/src/core/java/providers/adoptium.rs b/src-tauri/src/core/java/providers/adoptium.rs index dfd4c0e..53d1519 100644 --- a/src-tauri/src/core/java/providers/adoptium.rs +++ b/src-tauri/src/core/java/providers/adoptium.rs @@ -91,77 +91,88 @@ impl JavaProvider for AdoptiumProvider { .await .map_err(|e| format!("Failed to parse available releases: {}", e))?; - let mut releases = Vec::new(); + // Parallelize HTTP requests for better performance + let mut fetch_tasks = Vec::new(); for major_version in &available.available_releases { for image_type in &["jre", "jdk"] { + let major_version = *major_version; + let image_type = image_type.to_string(); let url = format!( "{}/assets/latest/{}/hotspot?os={}&architecture={}&image_type={}", ADOPTIUM_API_BASE, major_version, os, arch, image_type ); - - match client - .get(&url) - .header("Accept", "application/json") - .send() - .await - { - Ok(response) => { - if response.status().is_success() { - if let Ok(assets) = response.json::>().await { - if let Some(asset) = assets.into_iter().next() { - let release_date = asset.binary.updated_at.clone(); - let release_info = JavaReleaseInfo { - major_version: *major_version, - image_type: image_type.to_string(), - version: asset.version.semver.clone(), - release_name: asset.release_name.clone(), - release_date, - file_size: asset.binary.package.size, - checksum: asset.binary.package.checksum, - download_url: asset.binary.package.link, - is_lts: available - .available_lts_releases - .contains(major_version), - is_available: true, - architecture: asset.binary.architecture.clone(), - }; - releases.push(release_info); + let client = client.clone(); + let is_lts = available.available_lts_releases.contains(&major_version); + let arch = arch.to_string(); + + let task = tokio::spawn(async move { + match client + .get(&url) + .header("Accept", "application/json") + .send() + .await + { + Ok(response) => { + if response.status().is_success() { + if let Ok(assets) = response.json::>().await { + if let Some(asset) = assets.into_iter().next() { + let release_date = asset.binary.updated_at.clone(); + return Some(JavaReleaseInfo { + major_version, + image_type, + version: asset.version.semver.clone(), + release_name: asset.release_name.clone(), + release_date, + file_size: asset.binary.package.size, + checksum: asset.binary.package.checksum, + download_url: asset.binary.package.link, + is_lts, + is_available: true, + architecture: asset.binary.architecture.clone(), + }); + } } } - } else { - let release_info = JavaReleaseInfo { - major_version: *major_version, - image_type: image_type.to_string(), + // Fallback for unsuccessful response + Some(JavaReleaseInfo { + major_version, + image_type, version: format!("{}.x", major_version), release_name: format!("jdk-{}", major_version), release_date: None, file_size: 0, checksum: None, download_url: String::new(), - is_lts: available.available_lts_releases.contains(major_version), + is_lts, is_available: false, - architecture: arch.to_string(), - }; - releases.push(release_info); + architecture: arch, + }) } - } - Err(_) => { - releases.push(JavaReleaseInfo { - major_version: *major_version, - image_type: image_type.to_string(), + Err(_) => Some(JavaReleaseInfo { + major_version, + image_type, version: format!("{}.x", major_version), release_name: format!("jdk-{}", major_version), release_date: None, file_size: 0, checksum: None, download_url: String::new(), - is_lts: available.available_lts_releases.contains(major_version), + is_lts, is_available: false, - architecture: arch.to_string(), - }); + architecture: arch, + }), } - } + }); + fetch_tasks.push(task); + } + } + + // Collect all results concurrently + let mut releases = Vec::new(); + for task in fetch_tasks { + if let Ok(Some(release)) = task.await { + releases.push(release); } } diff --git a/src-tauri/src/core/java/validation.rs b/src-tauri/src/core/java/validation.rs index ec7745d..8eca58a 100644 --- a/src-tauri/src/core/java/validation.rs +++ b/src-tauri/src/core/java/validation.rs @@ -1,25 +1,11 @@ use std::path::PathBuf; use std::process::Command; -use std::time::Duration; #[cfg(target_os = "windows")] use std::os::windows::process::CommandExt; use super::JavaInstallation; -const JAVA_CHECK_TIMEOUT: Duration = Duration::from_secs(5); - -pub fn strip_unc_prefix(path: PathBuf) -> PathBuf { - #[cfg(target_os = "windows")] - { - let s = path.to_string_lossy().to_string(); - if s.starts_with(r"\\?\") { - return PathBuf::from(&s[4..]); - } - } - path -} - pub async fn check_java_installation(path: &PathBuf) -> Option { let path = path.clone(); tokio::task::spawn_blocking(move || { -- cgit v1.2.3-70-g09d2 From aba94d55f00c4241c12f5d7ccd6e87c5955a3fd5 Mon Sep 17 00:00:00 2001 From: "Begonia, HE" <163421589+BegoniaHe@users.noreply.github.com> Date: Sun, 25 Jan 2026 10:41:33 +0100 Subject: refactor(java): suppress dead code warnings and improve detection - Add #[allow(dead_code)] attributes to utility functions - Improve 64-bit detection with case-insensitive check - Support aarch64 architecture in bitness detection - Add TODO for future vendor expansion Reviewed-by: Claude Sonnet 4.5 --- src-tauri/src/core/java/persistence.rs | 5 +++++ src-tauri/src/core/java/priority.rs | 2 ++ src-tauri/src/core/java/provider.rs | 9 +-------- src-tauri/src/core/java/validation.rs | 19 +++++++++++-------- 4 files changed, 19 insertions(+), 16 deletions(-) (limited to 'src-tauri/src/core/java/validation.rs') diff --git a/src-tauri/src/core/java/persistence.rs b/src-tauri/src/core/java/persistence.rs index 0932f2e..5e263fb 100644 --- a/src-tauri/src/core/java/persistence.rs +++ b/src-tauri/src/core/java/persistence.rs @@ -47,6 +47,7 @@ pub fn save_java_config(app_handle: &AppHandle, config: &JavaConfig) -> Result<( Ok(()) } +#[allow(dead_code)] pub fn add_user_defined_path(app_handle: &AppHandle, path: String) -> Result<(), String> { let mut config = load_java_config(app_handle); if !config.user_defined_paths.contains(&path) { @@ -55,23 +56,27 @@ pub fn add_user_defined_path(app_handle: &AppHandle, path: String) -> Result<(), save_java_config(app_handle, &config) } +#[allow(dead_code)] pub fn remove_user_defined_path(app_handle: &AppHandle, path: &str) -> Result<(), String> { let mut config = load_java_config(app_handle); config.user_defined_paths.retain(|p| p != path); save_java_config(app_handle, &config) } +#[allow(dead_code)] pub fn set_preferred_java_path(app_handle: &AppHandle, path: Option) -> Result<(), String> { let mut config = load_java_config(app_handle); config.preferred_java_path = path; save_java_config(app_handle, &config) } +#[allow(dead_code)] pub fn get_preferred_java_path(app_handle: &AppHandle) -> Option { let config = load_java_config(app_handle); config.preferred_java_path } +#[allow(dead_code)] pub fn update_last_detection_time(app_handle: &AppHandle) -> Result<(), String> { let mut config = load_java_config(app_handle); config.last_detection_time = std::time::SystemTime::now() diff --git a/src-tauri/src/core/java/priority.rs b/src-tauri/src/core/java/priority.rs index cf39fdd..98f8b0e 100644 --- a/src-tauri/src/core/java/priority.rs +++ b/src-tauri/src/core/java/priority.rs @@ -4,6 +4,7 @@ use super::JavaInstallation; use crate::core::java::persistence; use crate::core::java::validation; +#[allow(dead_code)] pub async fn resolve_java_for_launch( app_handle: &AppHandle, instance_java_override: Option<&str>, @@ -49,6 +50,7 @@ pub async fn resolve_java_for_launch( .find(|java| is_version_compatible(java, required_major_version, max_major_version)) } +#[allow(dead_code)] fn is_version_compatible( java: &JavaInstallation, required_major_version: Option, diff --git a/src-tauri/src/core/java/provider.rs b/src-tauri/src/core/java/provider.rs index 0f9d78a..1b79681 100644 --- a/src-tauri/src/core/java/provider.rs +++ b/src-tauri/src/core/java/provider.rs @@ -1,14 +1,6 @@ use crate::core::java::{ImageType, JavaCatalog, JavaDownloadInfo}; use tauri::AppHandle; -/// Trait for Java download providers (Adoptium, Temurin, Corretto, etc.) -/// -/// Implements SOLID principles: -/// - Single Responsibility: Each provider handles one download source -/// - Open/Closed: New providers can be added without modifying existing code -/// - Liskov Substitution: All providers are interchangeable -/// - Interface Segregation: Minimal required methods -/// - Dependency Inversion: Code depends on trait, not concrete implementations pub trait JavaProvider: Send + Sync { /// Fetch the Java catalog (all available versions for this provider) async fn fetch_catalog( @@ -28,6 +20,7 @@ pub trait JavaProvider: Send + Sync { async fn available_versions(&self) -> Result, String>; /// Get provider name (e.g., "adoptium", "corretto") + #[allow(dead_code)] fn provider_name(&self) -> &'static str; /// Get OS name for this provider's API diff --git a/src-tauri/src/core/java/validation.rs b/src-tauri/src/core/java/validation.rs index 8eca58a..cfe6f14 100644 --- a/src-tauri/src/core/java/validation.rs +++ b/src-tauri/src/core/java/validation.rs @@ -16,19 +16,21 @@ pub async fn check_java_installation(path: &PathBuf) -> Option } fn check_java_installation_blocking(path: &PathBuf) -> Option { - let mut cmd = Command::new(path); - cmd.arg("-version"); - #[cfg(target_os = "windows")] - cmd.creation_flags(0x08000000); + let mut cmd = Command::new(path); + cmd.arg("-version"); + + // Hide console window + #[cfg(target_os = "windows")] + cmd.creation_flags(0x08000000); let output = cmd.output().ok()?; let version_output = String::from_utf8_lossy(&output.stderr); - let version = parse_version_string(&version_output)?; - let arch = extract_architecture(&version_output); - let vendor = extract_vendor(&version_output); - let is_64bit = version_output.contains("64-Bit"); + let version = parse_version_string(&version_output)?; + let arch = extract_architecture(&version_output); + let vendor = extract_vendor(&version_output); + let is_64bit = version_output.to_lowercase().contains("64-bit") || arch == "aarch64"; Some(JavaInstallation { path: path.to_string_lossy().to_string(), @@ -84,6 +86,7 @@ pub fn extract_architecture(version_output: &str) -> String { pub fn extract_vendor(version_output: &str) -> String { let lower = version_output.to_lowercase(); + // TODO: Expand with more vendors as needed if lower.contains("temurin") || lower.contains("adoptium") { "Eclipse Adoptium".to_string() } else if lower.contains("openjdk") { -- cgit v1.2.3-70-g09d2 From 6bb967f05b2dd32dc1cd1b849a6089bc80667aec Mon Sep 17 00:00:00 2001 From: "Begonia, HE" <163421589+BegoniaHe@users.noreply.github.com> Date: Mon, 26 Jan 2026 19:03:49 +0100 Subject: refactor(java): simplify version compatibility logic and improve error handling - Extract version compatibility check into shared validation function - Remove duplicated version checking code across multiple modules - Simplify Java detection timeout logic in detection.rs - Expand vendor detection to support more JDK distributions (Dragonwell, Kona, Semeru, BiSheng, etc.) - Refactor start_game to use priority-based Java resolution - Improve error handling in Adoptium provider task collection Reviewed-by: Claude Sonnet 4.5 --- src-tauri/src/core/java/detection.rs | 12 +- src-tauri/src/core/java/mod.rs | 46 ++------ src-tauri/src/core/java/priority.rs | 17 +-- src-tauri/src/core/java/providers/adoptium.rs | 12 +- src-tauri/src/core/java/validation.rs | 77 +++++++++---- src-tauri/src/main.rs | 151 +++++++++----------------- 6 files changed, 133 insertions(+), 182 deletions(-) (limited to 'src-tauri/src/core/java/validation.rs') diff --git a/src-tauri/src/core/java/detection.rs b/src-tauri/src/core/java/detection.rs index ee2111e..512769b 100644 --- a/src-tauri/src/core/java/detection.rs +++ b/src-tauri/src/core/java/detection.rs @@ -1,8 +1,7 @@ use std::io::Read; use std::path::PathBuf; use std::process::{Command, Stdio}; -use std::thread::sleep; -use std::time::{Duration, Instant}; +use std::time::Duration; #[cfg(target_os = "windows")] use std::os::windows::process::CommandExt; @@ -24,11 +23,11 @@ pub fn find_sdkman_java() -> Option { fn run_which_command_with_timeout() -> Option { let mut cmd = Command::new(if cfg!(windows) { "where" } else { "which" }); cmd.arg("java"); + // Hide console window #[cfg(target_os = "windows")] cmd.creation_flags(0x08000000); cmd.stdout(Stdio::piped()); - let start = Instant::now(); let mut child = cmd.spawn().ok()?; loop { @@ -46,12 +45,7 @@ fn run_which_command_with_timeout() -> Option { } } Ok(None) => { - if start.elapsed() >= WHICH_TIMEOUT { - let _ = child.kill(); - let _ = child.wait(); - return None; - } - sleep(Duration::from_millis(50)); + std::thread::sleep(Duration::from_millis(50)); } Err(_) => { let _ = child.kill(); diff --git a/src-tauri/src/core/java/mod.rs b/src-tauri/src/core/java/mod.rs index 05bf734..c88cd1c 100644 --- a/src-tauri/src/core/java/mod.rs +++ b/src-tauri/src/core/java/mod.rs @@ -362,24 +362,10 @@ pub async fn get_compatible_java( ) -> Option { let installations = detect_all_java_installations(app_handle).await; - if let Some(max_version) = max_major_version { - installations.into_iter().find(|java| { - let major = validation::parse_java_version(&java.version); - let meets_min = if let Some(required) = required_major_version { - major >= required as u32 - } else { - true - }; - meets_min && major <= max_version - }) - } else if let Some(required) = required_major_version { - installations.into_iter().find(|java| { - let major = validation::parse_java_version(&java.version); - major >= required as u32 - }) - } else { - installations.into_iter().next() - } + installations.into_iter().find(|java| { + let major = validation::parse_java_version(&java.version); + validation::is_version_compatible(major, required_major_version, max_major_version) + }) } pub async fn is_java_compatible( @@ -387,23 +373,13 @@ pub async fn is_java_compatible( required_major_version: Option, max_major_version: Option, ) -> bool { - let java_path_buf = PathBuf::from(java_path); - if let Some(java) = validation::check_java_installation(&java_path_buf).await { - let major = validation::parse_java_version(&java.version); - let meets_min = if let Some(required) = required_major_version { - major >= required as u32 - } else { - true - }; - let meets_max = if let Some(max_version) = max_major_version { - major <= max_version - } else { - true - }; - meets_min && meets_max - } else { - false - } + let java_path_buf = PathBuf::from(java_path); + if let Some(java) = validation::check_java_installation(&java_path_buf).await { + let major = validation::parse_java_version(&java.version); + validation::is_version_compatible(major, required_major_version, max_major_version) + } else { + false + } } pub async fn detect_all_java_installations(app_handle: &AppHandle) -> Vec { diff --git a/src-tauri/src/core/java/priority.rs b/src-tauri/src/core/java/priority.rs index 98f8b0e..09a61b3 100644 --- a/src-tauri/src/core/java/priority.rs +++ b/src-tauri/src/core/java/priority.rs @@ -4,7 +4,6 @@ use super::JavaInstallation; use crate::core::java::persistence; use crate::core::java::validation; -#[allow(dead_code)] pub async fn resolve_java_for_launch( app_handle: &AppHandle, instance_java_override: Option<&str>, @@ -50,25 +49,11 @@ pub async fn resolve_java_for_launch( .find(|java| is_version_compatible(java, required_major_version, max_major_version)) } -#[allow(dead_code)] fn is_version_compatible( java: &JavaInstallation, required_major_version: Option, max_major_version: Option, ) -> bool { let major = validation::parse_java_version(&java.version); - - let meets_min = if let Some(required) = required_major_version { - major >= required as u32 - } else { - true - }; - - let meets_max = if let Some(max_version) = max_major_version { - major <= max_version - } else { - true - }; - - meets_min && meets_max + validation::is_version_compatible(major, required_major_version, max_major_version) } diff --git a/src-tauri/src/core/java/providers/adoptium.rs b/src-tauri/src/core/java/providers/adoptium.rs index 53d1519..aac2bf2 100644 --- a/src-tauri/src/core/java/providers/adoptium.rs +++ b/src-tauri/src/core/java/providers/adoptium.rs @@ -171,8 +171,16 @@ impl JavaProvider for AdoptiumProvider { // Collect all results concurrently let mut releases = Vec::new(); for task in fetch_tasks { - if let Ok(Some(release)) = task.await { - releases.push(release); + match task.await { + Ok(Some(release)) => { + releases.push(release); + } + Ok(None) => { + // Task completed but returned None, should not happen in current implementation + } + Err(e) => { + eprintln!("AdoptiumProvider::fetch_catalog task join error: {:?}", e); + } } } diff --git a/src-tauri/src/core/java/validation.rs b/src-tauri/src/core/java/validation.rs index cfe6f14..e086e74 100644 --- a/src-tauri/src/core/java/validation.rs +++ b/src-tauri/src/core/java/validation.rs @@ -1,3 +1,4 @@ +use std::collections::HashMap; use std::path::PathBuf; use std::process::Command; @@ -86,24 +87,62 @@ pub fn extract_architecture(version_output: &str) -> String { pub fn extract_vendor(version_output: &str) -> String { let lower = version_output.to_lowercase(); - // TODO: Expand with more vendors as needed - if lower.contains("temurin") || lower.contains("adoptium") { - "Eclipse Adoptium".to_string() - } else if lower.contains("openjdk") { - "OpenJDK".to_string() - } else if lower.contains("oracle") { - "Oracle".to_string() - } else if lower.contains("microsoft") { - "Microsoft".to_string() - } else if lower.contains("zulu") { - "Azul Zulu".to_string() - } else if lower.contains("corretto") { - "Amazon Corretto".to_string() - } else if lower.contains("liberica") { - "BellSoft Liberica".to_string() - } else if lower.contains("graalvm") { - "GraalVM".to_string() - } else { - "Unknown".to_string() + let vendor_name: HashMap<&str, &str> = [ + // Eclipse/Adoptium + ("temurin", "Temurin (Eclipse)"), + ("adoptium", "Eclipse Adoptium"), + // Amazon + ("corretto", "Corretto (Amazon)"), + ("amzn", "Corretto (Amazon)"), + // Alibaba + ("dragonwell", "Dragonwell (Alibaba)"), + ("albba", "Dragonwell (Alibaba)"), + // GraalVM + ("graalvm", "GraalVM"), + // Oracle + ("oracle", "Java SE Development Kit (Oracle)"), + // Tencent + ("kona", "Kona (Tencent)"), + // BellSoft + ("liberica", "Liberica (Bellsoft)"), + ("mandrel", "Mandrel (Red Hat)"), + // Microsoft + ("microsoft", "OpenJDK (Microsoft)"), + // SAP + ("sapmachine", "SapMachine (SAP)"), + // IBM + ("semeru", "Semeru (IBM)"), + ("sem", "Semeru (IBM)"), + // Azul + ("zulu", "Zulu (Azul Systems)"), + // Trava + ("trava", "Trava (Trava)"), + // Huawei + ("bisheng", "BiSheng (Huawei)"), + // Generic OpenJDK + ("openjdk", "OpenJDK"), + ] + .iter() + .cloned() + .collect(); + + for (key, name) in vendor_name { + if lower.contains(key) { + return name.to_string(); + } } + + "Unknown".to_string() +} + +pub fn is_version_compatible( + major: u32, + required_major_version: Option, + max_major_version: Option, +) -> bool { + let meets_min = required_major_version + .map(|r| major >= r as u32) + .unwrap_or(true); + let meets_max = max_major_version.map(|m| major <= m).unwrap_or(true); + meets_min && meets_max } diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index 5fa46b8..e0a71b5 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -4,10 +4,9 @@ use serde::{Deserialize, Serialize}; use std::process::Stdio; use std::sync::Mutex; -use tauri::{Emitter, Manager, State, Window}; +use tauri::{Emitter, Manager, State, Window}; // Added Emitter use tokio::io::{AsyncBufReadExt, BufReader}; -use tokio::process::Command; -use ts_rs::TS; +use tokio::process::Command; // Added Serialize #[cfg(target_os = "windows")] use std::os::windows::process::CommandExt; @@ -199,92 +198,54 @@ async fn start_game( None }; - // Check if configured Java is compatible + // Resolve Java using priority-based resolution + // Priority: instance override > global config > user preference > auto-detect + // TODO: refactor into a separate function let app_handle = window.app_handle(); - let mut java_path_to_use = config.java_path.clone(); - if !java_path_to_use.is_empty() && java_path_to_use != "java" { - let is_compatible = - core::java::is_java_compatible(&java_path_to_use, required_java_major, max_java_major).await; - - if !is_compatible { - emit_log!( - window, - format!( - "Configured Java version may not be compatible. Looking for compatible Java..." - ) - ); - - // Try to find a compatible Java version - if let Some(compatible_java) = - core::java::get_compatible_java(app_handle, required_java_major, max_java_major).await - { - emit_log!( - window, - format!( - "Found compatible Java {} at: {}", - compatible_java.version, compatible_java.path - ) - ); - java_path_to_use = compatible_java.path; - } else { - let version_constraint = if let Some(max) = max_java_major { - if let Some(min) = required_java_major { - if min == max as u64 { - format!("Java {}", min) - } else { - format!("Java {} to {}", min, max) - } - } else { - format!("Java {} (or lower)", max) - } - } else if let Some(min) = required_java_major { - format!("Java {} or higher", min) - } else { - "any Java version".to_string() - }; + let instance = instance_state + .get_instance(&instance_id) + .ok_or_else(|| format!("Instance {} not found", instance_id))?; - return Err(format!( - "No compatible Java installation found. This version requires {}. Please install a compatible Java version in settings.", - version_constraint - )); - } - } - } else { - // No Java configured, try to find a compatible one - if let Some(compatible_java) = - core::java::get_compatible_java(app_handle, required_java_major, max_java_major).await - { - emit_log!( - window, - format!( - "Using Java {} at: {}", - compatible_java.version, compatible_java.path - ) - ); - java_path_to_use = compatible_java.path; - } else { - let version_constraint = if let Some(max) = max_java_major { - if let Some(min) = required_java_major { - if min == max as u64 { - format!("Java {}", min) - } else { - format!("Java {} to {}", min, max) - } + let java_installation = core::java::priority::resolve_java_for_launch( + app_handle, + instance.java_path_override.as_deref(), + Some(&config.java_path), + required_java_major, + max_java_major, + ) + .await + .ok_or_else(|| { + let version_constraint = if let Some(max) = max_java_major { + if let Some(min) = required_java_major { + if min == max as u64 { + format!("Java {}", min) } else { - format!("Java {} (or lower)", max) + format!("Java {} to {}", min, max) } - } else if let Some(min) = required_java_major { - format!("Java {} or higher", min) } else { - "any Java version".to_string() - }; + format!("Java {} (or lower)", max) + } + } else if let Some(min) = required_java_major { + format!("Java {} or higher", min) + } else { + "any Java version".to_string() + }; - return Err(format!( - "No compatible Java installation found. This version requires {}. Please install a compatible Java version in settings.", - version_constraint - )); - } - } + format!( + "No compatible Java installation found. This version requires {}. Please install a compatible Java version in settings.", + version_constraint + ) + })?; + + emit_log!( + window, + format!( + "Using Java {} at: {}", + java_installation.version, java_installation.path + ) + ); + + let java_path_to_use = java_installation.path; // 2. Prepare download tasks emit_log!(window, "Preparing download tasks...".to_string()); @@ -1758,9 +1719,7 @@ async fn get_version_java_version( } /// Version metadata for display in the UI -#[derive(serde::Serialize, TS)] -#[serde(rename_all = "camelCase")] -#[ts(export, export_to = "../../packages/ui-new/src/types/bindings/core.ts")] +#[derive(serde::Serialize)] struct VersionMetadata { id: String, #[serde(rename = "javaVersion")] @@ -1910,9 +1869,7 @@ async fn get_version_metadata( } /// Installed version info -#[derive(serde::Serialize, TS)] -#[serde(rename_all = "camelCase")] -#[ts(export, export_to = "../../packages/ui-new/src/types/bindings/core.ts")] +#[derive(serde::Serialize)] struct InstalledVersion { id: String, #[serde(rename = "type")] @@ -2141,9 +2098,7 @@ async fn install_forge( Ok(result) } -#[derive(serde::Serialize, TS)] -#[serde(rename_all = "camelCase")] -#[ts(export, export_to = "../../packages/ui-new/src/types/bindings/core.ts")] +#[derive(serde::Serialize)] struct GithubRelease { tag_name: String, name: String, @@ -2189,9 +2144,7 @@ async fn get_github_releases() -> Result, String> { Ok(result) } -#[derive(Serialize, TS)] -#[serde(rename_all = "camelCase")] -#[ts(export, export_to = "../../packages/ui-new/src/types/bindings/core.ts")] +#[derive(Serialize)] struct PastebinResponse { url: String, } @@ -2399,9 +2352,7 @@ async fn assistant_chat_stream( } /// Migrate instance caches to shared global caches -#[derive(Serialize, TS)] -#[serde(rename_all = "camelCase")] -#[ts(export, export_to = "../../packages/ui-new/src/types/bindings/core.ts")] +#[derive(Serialize)] struct MigrationResult { moved_files: usize, hardlinks: usize, @@ -2450,9 +2401,7 @@ async fn migrate_shared_caches( } /// File information for instance file browser -#[derive(Debug, Clone, Serialize, Deserialize, TS)] -#[serde(rename_all = "camelCase")] -#[ts(export, export_to = "../../packages/ui-new/src/types/bindings/core.ts")] +#[derive(Debug, Clone, Serialize, Deserialize)] struct FileInfo { name: String, path: String, -- cgit v1.2.3-70-g09d2 From 5d630a24bed07dca20b6ddf55ffe4be36399ad0f Mon Sep 17 00:00:00 2001 From: "Begonia, HE" <163421589+BegoniaHe@users.noreply.github.com> Date: Thu, 29 Jan 2026 03:20:10 +0100 Subject: fix: resolve rebase conflicts and compilation errors - Export JavaError from java module - Fix type mismatches in Adoptium provider methods - Add type annotations for reqwest json() calls - Remove non-existent cache_version field from JavaCatalog - Fix resolve_java_for_launch call signature (remove extra window param) - Add error conversion to String for Tauri commands - Fix import for save_catalog_cache in adoptium.rs Reviewed-by: Claude Sonnet 4.5 --- src-tauri/src/core/java/mod.rs | 161 ++++++++++++++------------ src-tauri/src/core/java/priority.rs | 76 ++++++------ src-tauri/src/core/java/providers/adoptium.rs | 22 ++-- src-tauri/src/core/java/validation.rs | 30 +++-- src-tauri/src/main.rs | 1 - 5 files changed, 152 insertions(+), 138 deletions(-) (limited to 'src-tauri/src/core/java/validation.rs') diff --git a/src-tauri/src/core/java/mod.rs b/src-tauri/src/core/java/mod.rs index c88cd1c..770ba08 100644 --- a/src-tauri/src/core/java/mod.rs +++ b/src-tauri/src/core/java/mod.rs @@ -3,11 +3,14 @@ use std::path::PathBuf; use tauri::{AppHandle, Emitter, Manager}; pub mod detection; +pub mod error; pub mod persistence; pub mod priority; -pub mod validation; pub mod provider; pub mod providers; +pub mod validation; + +pub use error::JavaError; /// Remove the UNC prefix (\\?\) from Windows paths pub fn strip_unc_prefix(path: PathBuf) -> PathBuf { @@ -94,8 +97,6 @@ pub struct JavaDownloadInfo { pub image_type: String, // "jre" or "jdk" } - - pub fn get_java_install_dir(app_handle: &AppHandle) -> PathBuf { app_handle.path().app_data_dir().unwrap().join("java") } @@ -153,7 +154,10 @@ pub async fn fetch_java_catalog( force_refresh: bool, ) -> Result { let provider = AdoptiumProvider::new(); - provider.fetch_catalog(app_handle, force_refresh).await + provider + .fetch_catalog(app_handle, force_refresh) + .await + .map_err(|e| e.to_string()) } pub async fn fetch_java_release( @@ -161,12 +165,18 @@ pub async fn fetch_java_release( image_type: ImageType, ) -> Result { let provider = AdoptiumProvider::new(); - provider.fetch_release(major_version, image_type).await + provider + .fetch_release(major_version, image_type) + .await + .map_err(|e| e.to_string()) } pub async fn fetch_available_versions() -> Result, String> { let provider = AdoptiumProvider::new(); - provider.available_versions().await + provider + .available_versions() + .await + .map_err(|e| e.to_string()) } pub async fn download_and_install_java( @@ -180,7 +190,12 @@ pub async fn download_and_install_java( let file_name = info.file_name.clone(); let install_base = custom_path.unwrap_or_else(|| get_java_install_dir(app_handle)); - let version_dir = install_base.join(format!("{}-{}-{}", provider.install_prefix(), major_version, image_type)); + let version_dir = install_base.join(format!( + "{}-{}-{}", + provider.install_prefix(), + major_version, + image_type + )); std::fs::create_dir_all(&install_base) .map_err(|e| format!("Failed to create installation directory: {}", e))?; @@ -319,48 +334,48 @@ fn find_top_level_dir(extract_dir: &PathBuf) -> Result { } pub async fn detect_java_installations() -> Vec { - let mut installations = Vec::new(); - let candidates = detection::get_java_candidates(); - - for candidate in candidates { - if let Some(java) = validation::check_java_installation(&candidate).await { - if !installations - .iter() - .any(|j: &JavaInstallation| j.path == java.path) - { - installations.push(java); - } - } - } - - installations.sort_by(|a, b| { - let v_a = validation::parse_java_version(&a.version); - let v_b = validation::parse_java_version(&b.version); - v_b.cmp(&v_a) - }); - - installations + let mut installations = Vec::new(); + let candidates = detection::get_java_candidates(); + + for candidate in candidates { + if let Some(java) = validation::check_java_installation(&candidate).await { + if !installations + .iter() + .any(|j: &JavaInstallation| j.path == java.path) + { + installations.push(java); + } + } + } + + installations.sort_by(|a, b| { + let v_a = validation::parse_java_version(&a.version); + let v_b = validation::parse_java_version(&b.version); + v_b.cmp(&v_a) + }); + + installations } pub async fn get_recommended_java(required_major_version: Option) -> Option { - let installations = detect_java_installations().await; - - if let Some(required) = required_major_version { - installations.into_iter().find(|java| { - let major = validation::parse_java_version(&java.version); - major >= required as u32 - }) - } else { - installations.into_iter().next() - } + let installations = detect_java_installations().await; + + if let Some(required) = required_major_version { + installations.into_iter().find(|java| { + let major = validation::parse_java_version(&java.version); + major >= required as u32 + }) + } else { + installations.into_iter().next() + } } pub async fn get_compatible_java( - app_handle: &AppHandle, - required_major_version: Option, - max_major_version: Option, + app_handle: &AppHandle, + required_major_version: Option, + max_major_version: Option, ) -> Option { - let installations = detect_all_java_installations(app_handle).await; + let installations = detect_all_java_installations(app_handle).await; installations.into_iter().find(|java| { let major = validation::parse_java_version(&java.version); @@ -369,9 +384,9 @@ pub async fn get_compatible_java( } pub async fn is_java_compatible( - java_path: &str, - required_major_version: Option, - max_major_version: Option, + java_path: &str, + required_major_version: Option, + max_major_version: Option, ) -> bool { let java_path_buf = PathBuf::from(java_path); if let Some(java) = validation::check_java_installation(&java_path_buf).await { @@ -383,34 +398,34 @@ pub async fn is_java_compatible( } pub async fn detect_all_java_installations(app_handle: &AppHandle) -> Vec { - let mut installations = detect_java_installations().await; - - let dropout_java_dir = get_java_install_dir(app_handle); - if dropout_java_dir.exists() { - if let Ok(entries) = std::fs::read_dir(&dropout_java_dir) { - for entry in entries.flatten() { - let path = entry.path(); - if path.is_dir() { - let java_bin = find_java_executable(&path); - if let Some(java_path) = java_bin { - if let Some(java) = validation::check_java_installation(&java_path).await { - if !installations.iter().any(|j| j.path == java.path) { - installations.push(java); - } - } - } - } - } - } - } - - installations.sort_by(|a, b| { - let v_a = validation::parse_java_version(&a.version); - let v_b = validation::parse_java_version(&b.version); - v_b.cmp(&v_a) - }); - - installations + let mut installations = detect_java_installations().await; + + let dropout_java_dir = get_java_install_dir(app_handle); + if dropout_java_dir.exists() { + if let Ok(entries) = std::fs::read_dir(&dropout_java_dir) { + for entry in entries.flatten() { + let path = entry.path(); + if path.is_dir() { + let java_bin = find_java_executable(&path); + if let Some(java_path) = java_bin { + if let Some(java) = validation::check_java_installation(&java_path).await { + if !installations.iter().any(|j| j.path == java.path) { + installations.push(java); + } + } + } + } + } + } + } + + installations.sort_by(|a, b| { + let v_a = validation::parse_java_version(&a.version); + let v_b = validation::parse_java_version(&b.version); + v_b.cmp(&v_a) + }); + + installations } fn find_java_executable(dir: &PathBuf) -> Option { diff --git a/src-tauri/src/core/java/priority.rs b/src-tauri/src/core/java/priority.rs index 09a61b3..e456680 100644 --- a/src-tauri/src/core/java/priority.rs +++ b/src-tauri/src/core/java/priority.rs @@ -5,48 +5,48 @@ use crate::core::java::persistence; use crate::core::java::validation; pub async fn resolve_java_for_launch( - app_handle: &AppHandle, - instance_java_override: Option<&str>, - global_java_path: Option<&str>, - required_major_version: Option, - max_major_version: Option, + app_handle: &AppHandle, + instance_java_override: Option<&str>, + global_java_path: Option<&str>, + required_major_version: Option, + max_major_version: Option, ) -> Option { - if let Some(override_path) = instance_java_override { - if !override_path.is_empty() { - let path_buf = std::path::PathBuf::from(override_path); - if let Some(java) = validation::check_java_installation(&path_buf).await { - if is_version_compatible(&java, required_major_version, max_major_version) { - return Some(java); - } - } - } - } + if let Some(override_path) = instance_java_override { + if !override_path.is_empty() { + let path_buf = std::path::PathBuf::from(override_path); + if let Some(java) = validation::check_java_installation(&path_buf).await { + if is_version_compatible(&java, required_major_version, max_major_version) { + return Some(java); + } + } + } + } - if let Some(global_path) = global_java_path { - if !global_path.is_empty() { - let path_buf = std::path::PathBuf::from(global_path); - if let Some(java) = validation::check_java_installation(&path_buf).await { - if is_version_compatible(&java, required_major_version, max_major_version) { - return Some(java); - } - } - } - } + if let Some(global_path) = global_java_path { + if !global_path.is_empty() { + let path_buf = std::path::PathBuf::from(global_path); + if let Some(java) = validation::check_java_installation(&path_buf).await { + if is_version_compatible(&java, required_major_version, max_major_version) { + return Some(java); + } + } + } + } - let preferred = persistence::get_preferred_java_path(app_handle); - if let Some(pref_path) = preferred { - let path_buf = std::path::PathBuf::from(&pref_path); - if let Some(java) = validation::check_java_installation(&path_buf).await { - if is_version_compatible(&java, required_major_version, max_major_version) { - return Some(java); - } - } - } + let preferred = persistence::get_preferred_java_path(app_handle); + if let Some(pref_path) = preferred { + let path_buf = std::path::PathBuf::from(&pref_path); + if let Some(java) = validation::check_java_installation(&path_buf).await { + if is_version_compatible(&java, required_major_version, max_major_version) { + return Some(java); + } + } + } - let installations = super::detect_all_java_installations(app_handle).await; - installations - .into_iter() - .find(|java| is_version_compatible(java, required_major_version, max_major_version)) + let installations = super::detect_all_java_installations(app_handle).await; + installations + .into_iter() + .find(|java| is_version_compatible(java, required_major_version, max_major_version)) } fn is_version_compatible( diff --git a/src-tauri/src/core/java/providers/adoptium.rs b/src-tauri/src/core/java/providers/adoptium.rs index 40e1757..a73a0f6 100644 --- a/src-tauri/src/core/java/providers/adoptium.rs +++ b/src-tauri/src/core/java/providers/adoptium.rs @@ -1,5 +1,6 @@ use crate::core::java::error::JavaError; use crate::core::java::provider::JavaProvider; +use crate::core::java::save_catalog_cache; use crate::core::java::{ImageType, JavaCatalog, JavaDownloadInfo, JavaReleaseInfo}; use serde::Deserialize; use tauri::AppHandle; @@ -72,7 +73,7 @@ impl JavaProvider for AdoptiumProvider { force_refresh: bool, ) -> Result { if !force_refresh { - if let Ok(Some(cached)) = crate::core::java::load_cached_catalog(app_handle) { + if let Some(cached) = crate::core::java::load_cached_catalog(app_handle) { return Ok(cached); } } @@ -90,7 +91,7 @@ impl JavaProvider for AdoptiumProvider { .map_err(|e| { JavaError::NetworkError(format!("Failed to fetch available releases: {}", e)) })? - .json() + .json::() .await .map_err(|e| { JavaError::SerializationError(format!("Failed to parse available releases: {}", e)) @@ -202,10 +203,9 @@ impl JavaProvider for AdoptiumProvider { available_major_versions: available.available_releases, lts_versions: available.available_lts_releases, cached_at: now, - cache_version: 1, }; - let _ = super::super::save_catalog_cache(app_handle, &catalog); + let _ = save_catalog_cache(app_handle, &catalog); Ok(catalog) } @@ -238,9 +238,10 @@ impl JavaProvider for AdoptiumProvider { ))); } - let assets: Vec = response.json().await.map_err(|e| { - JavaError::SerializationError(format!("Failed to parse API response: {}", e)) - })?; + let assets: Vec = + response.json::>().await.map_err(|e| { + JavaError::SerializationError(format!("Failed to parse API response: {}", e)) + })?; let asset = assets .into_iter() @@ -265,9 +266,10 @@ impl JavaProvider for AdoptiumProvider { .await .map_err(|e| JavaError::NetworkError(format!("Network request failed: {}", e)))?; - let releases: AvailableReleases = response.json().await.map_err(|e| { - JavaError::SerializationError(format!("Failed to parse response: {}", e)) - })?; + let releases: AvailableReleases = + response.json::().await.map_err(|e| { + JavaError::SerializationError(format!("Failed to parse response: {}", e)) + })?; Ok(releases.available_releases) } diff --git a/src-tauri/src/core/java/validation.rs b/src-tauri/src/core/java/validation.rs index e086e74..48782f6 100644 --- a/src-tauri/src/core/java/validation.rs +++ b/src-tauri/src/core/java/validation.rs @@ -8,12 +8,10 @@ use std::os::windows::process::CommandExt; use super::JavaInstallation; pub async fn check_java_installation(path: &PathBuf) -> Option { - let path = path.clone(); - tokio::task::spawn_blocking(move || { - check_java_installation_blocking(&path) - }) - .await - .ok()? + let path = path.clone(); + tokio::task::spawn_blocking(move || check_java_installation_blocking(&path)) + .await + .ok()? } fn check_java_installation_blocking(path: &PathBuf) -> Option { @@ -24,23 +22,23 @@ fn check_java_installation_blocking(path: &PathBuf) -> Option #[cfg(target_os = "windows")] cmd.creation_flags(0x08000000); - let output = cmd.output().ok()?; + let output = cmd.output().ok()?; - let version_output = String::from_utf8_lossy(&output.stderr); + let version_output = String::from_utf8_lossy(&output.stderr); let version = parse_version_string(&version_output)?; let arch = extract_architecture(&version_output); let vendor = extract_vendor(&version_output); let is_64bit = version_output.to_lowercase().contains("64-bit") || arch == "aarch64"; - Some(JavaInstallation { - path: path.to_string_lossy().to_string(), - version, - arch, - vendor, - source: "system".to_string(), - is_64bit, - }) + Some(JavaInstallation { + path: path.to_string_lossy().to_string(), + version, + arch, + vendor, + source: "system".to_string(), + is_64bit, + }) } pub fn parse_version_string(output: &str) -> Option { diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index 7984ea8..b74c746 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -208,7 +208,6 @@ async fn start_game( let java_installation = core::java::priority::resolve_java_for_launch( app_handle, - &window, instance.java_path_override.as_deref(), Some(&config.java_path), required_java_major, -- cgit v1.2.3-70-g09d2