aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/src-tauri/src/core/java/validation.rs
blob: ec7745d1b9e7e6e6c0d2622d50f066dad47c88e6 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
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<JavaInstallation> {
	let path = path.clone();
	tokio::task::spawn_blocking(move || {
		check_java_installation_blocking(&path)
	})
	.await
	.ok()?
}

fn check_java_installation_blocking(path: &PathBuf) -> Option<JavaInstallation> {
	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<String> {
    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()
    }
}