refactor(java): simpler java check (#698)
This commit is contained in:
parent
fdb3b9a0a3
commit
b60ce5af12
15 changed files with 158 additions and 254 deletions
4
.gitattributes
vendored
4
.gitattributes
vendored
|
|
@ -1,6 +1,2 @@
|
|||
* text=auto eol=lf
|
||||
Cargo.lock -diff linguist-generated
|
||||
pnpm-lock.yaml -diff linguist-generated
|
||||
packages/client/src/bindings.ts -diff linguist-generated=true
|
||||
.github/actions/publish-artifacts/dist/index.js -diff linguist-generated=true
|
||||
.github/actions/clippy/dist/index.js -diff linguist-generated=true
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "\n\t\tINSERT INTO java_versions (absolute_path, major, version, vendor, os_arch)\n\t\tVALUES (?, ?, ?, ?, ?)\n\t\tON CONFLICT(absolute_path) DO UPDATE SET\n\t\t\tmajor = excluded.major,\n\t\t\tversion = excluded.version,\n\t\t\tvendor = excluded.vendor,\n\t\t\tos_arch = excluded.os_arch\n\t\tRETURNING absolute_path, major, version, vendor, os_arch\n\t\t",
|
||||
"query": "\n\t\tINSERT INTO java_versions (absolute_path, major, version, vendor, os_arch, is_jdk)\n\t\tVALUES (?, ?, ?, ?, ?, ?)\n\t\tON CONFLICT(absolute_path) DO UPDATE SET\n\t\t\tmajor = excluded.major,\n\t\t\tversion = excluded.version,\n\t\t\tvendor = excluded.vendor,\n\t\t\tos_arch = excluded.os_arch,\n\t\t\tis_jdk = excluded.is_jdk\n\t\tRETURNING absolute_path, major, version, vendor, os_arch, is_jdk as \"is_jdk: bool\"\n\t\t",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
|
|
@ -57,18 +57,30 @@
|
|||
"name": "os_arch"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "is_jdk: bool",
|
||||
"ordinal": 5,
|
||||
"type_info": "Integer",
|
||||
"origin": {
|
||||
"Table": {
|
||||
"table": "java_versions",
|
||||
"name": "is_jdk"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 5
|
||||
"Right": 6
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "a3bd6cf3048a6a5ed9d29e6bbb7f517676fe715c8af45eb5c58d69073e2d0304"
|
||||
"hash": "010f5dcda59ec32eaad1b9c3e2e9807f547a1376372c8b201653a36d6dd14cbc"
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "\n SELECT absolute_path, major, version, vendor, os_arch FROM java_versions \n ORDER BY major DESC, version DESC\n ",
|
||||
"query": "\n SELECT absolute_path, major, version, vendor, os_arch, is_jdk as \"is_jdk: bool\"\n FROM java_versions\n ORDER BY major DESC, version DESC\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
|
|
@ -57,6 +57,17 @@
|
|||
"name": "os_arch"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "is_jdk: bool",
|
||||
"ordinal": 5,
|
||||
"type_info": "Integer",
|
||||
"origin": {
|
||||
"Table": {
|
||||
"table": "java_versions",
|
||||
"name": "is_jdk"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
|
|
@ -67,8 +78,9 @@
|
|||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "c1d3cf930d5f38e8f1046da1a8f895ee1de2d3fe9a40ecb47731618962d2a4ad"
|
||||
"hash": "0d9fb5d2fa8a788770e946241ea2f62f4b794c0fdda3ccbde49384689911aeba"
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "\n\t\tSELECT absolute_path, major, version, vendor, os_arch\n\t\tFROM java_versions\n\t\tWHERE major = ?\n\t\tORDER BY version DESC\n\t\tLIMIT 1\n\t\t",
|
||||
"query": "\n\t\tSELECT absolute_path, major, version, vendor, os_arch, is_jdk as \"is_jdk: bool\"\n\t\tFROM java_versions\n\t\tWHERE major = ?\n\t\tORDER BY version DESC\n\t\tLIMIT 1\n\t\t",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
|
|
@ -57,6 +57,17 @@
|
|||
"name": "os_arch"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "is_jdk: bool",
|
||||
"ordinal": 5,
|
||||
"type_info": "Integer",
|
||||
"origin": {
|
||||
"Table": {
|
||||
"table": "java_versions",
|
||||
"name": "is_jdk"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
|
|
@ -67,8 +78,9 @@
|
|||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "b153f762849649456dd97b6a5cd35fb7dafc3d5539441328e03442cea195483a"
|
||||
"hash": "33771b7003e64c8f19d15d663de773afa568d626c60a37bbc32cc932746ad49b"
|
||||
}
|
||||
62
.sqlx/query-bbbc24e8d4f13a39ebce8e8598f4adbc864909984313ea1c065ba226465b23ca.json
generated
Normal file
62
.sqlx/query-bbbc24e8d4f13a39ebce8e8598f4adbc864909984313ea1c065ba226465b23ca.json
generated
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "\n\t\tSELECT DISTINCT ca.cluster_id, ca.hash, ca.cluster_file_name, ca.enabled\n\t\tFROM cluster_artifacts ca\n\t\tJOIN provider_releases pr ON pr.hash = ca.hash\n\t\tWHERE ca.cluster_id = ?\n\t\t\tAND pr.provider = ?\n\t\t\tAND pr.project_id = ?\n\t\t\tAND ca.hash <> ?\n\t\t",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "cluster_id",
|
||||
"ordinal": 0,
|
||||
"type_info": "Integer",
|
||||
"origin": {
|
||||
"Table": {
|
||||
"table": "cluster_artifacts",
|
||||
"name": "cluster_id"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "hash",
|
||||
"ordinal": 1,
|
||||
"type_info": "Text",
|
||||
"origin": {
|
||||
"Table": {
|
||||
"table": "cluster_artifacts",
|
||||
"name": "hash"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "cluster_file_name",
|
||||
"ordinal": 2,
|
||||
"type_info": "Text",
|
||||
"origin": {
|
||||
"Table": {
|
||||
"table": "cluster_artifacts",
|
||||
"name": "cluster_file_name"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "enabled",
|
||||
"ordinal": 3,
|
||||
"type_info": "Integer",
|
||||
"origin": {
|
||||
"Table": {
|
||||
"table": "cluster_artifacts",
|
||||
"name": "enabled"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 4
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "bbbc24e8d4f13a39ebce8e8598f4adbc864909984313ea1c065ba226465b23ca"
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "\n SELECT absolute_path, major, version, vendor, os_arch FROM java_versions \n WHERE absolute_path = ?\n ",
|
||||
"query": "\n SELECT absolute_path, major, version, vendor, os_arch, is_jdk as \"is_jdk: bool\"\n FROM java_versions\n WHERE absolute_path = ?\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
|
|
@ -57,6 +57,17 @@
|
|||
"name": "os_arch"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "is_jdk: bool",
|
||||
"ordinal": 5,
|
||||
"type_info": "Integer",
|
||||
"origin": {
|
||||
"Table": {
|
||||
"table": "java_versions",
|
||||
"name": "is_jdk"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
|
|
@ -67,8 +78,9 @@
|
|||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "c570e309195b6063cf0fbee866d68972de05107769dab983524fd2e74a7ae31a"
|
||||
"hash": "f5992c9cec6a6d7015cda4c04b463bd5fd9c42ac38b434fa8a0c0fe4f7517cf2"
|
||||
}
|
||||
|
|
@ -30,6 +30,7 @@ fn row_to_runtime(row: JavaVersionRow) -> JavaRuntime {
|
|||
version: row.version,
|
||||
vendor: JavaVendor::from_str(&row.vendor).unwrap_or(JavaVendor::Other(row.vendor)),
|
||||
os_arch: row.os_arch,
|
||||
is_jdk: row.is_jdk,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -43,6 +44,7 @@ impl JavaStore for SqlJavaStore {
|
|||
&runtime.version,
|
||||
&runtime.vendor.to_string(),
|
||||
&runtime.os_arch,
|
||||
runtime.is_jdk,
|
||||
)
|
||||
.await
|
||||
.map_err(StoreError::new)?;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
-- Whether a recorded runtime is a development kit rather than a bare runtime
|
||||
-- image. Probing for it means spawning the java process, so it is remembered
|
||||
-- alongside the version instead. Rows written before this migration default to
|
||||
-- 0 and are corrected the next time they are probed.
|
||||
ALTER TABLE `java_versions` ADD COLUMN `is_jdk` INTEGER NOT NULL DEFAULT 0;
|
||||
|
|
@ -10,24 +10,27 @@ pub async fn insert(
|
|||
version: &str,
|
||||
vendor: &str,
|
||||
os_arch: &str,
|
||||
is_jdk: bool,
|
||||
) -> Result<JavaVersionRow, DbError> {
|
||||
sqlx::query_as!(
|
||||
JavaVersionRow,
|
||||
r#"
|
||||
INSERT INTO java_versions (absolute_path, major, version, vendor, os_arch)
|
||||
VALUES (?, ?, ?, ?, ?)
|
||||
INSERT INTO java_versions (absolute_path, major, version, vendor, os_arch, is_jdk)
|
||||
VALUES (?, ?, ?, ?, ?, ?)
|
||||
ON CONFLICT(absolute_path) DO UPDATE SET
|
||||
major = excluded.major,
|
||||
version = excluded.version,
|
||||
vendor = excluded.vendor,
|
||||
os_arch = excluded.os_arch
|
||||
RETURNING absolute_path, major, version, vendor, os_arch
|
||||
os_arch = excluded.os_arch,
|
||||
is_jdk = excluded.is_jdk
|
||||
RETURNING absolute_path, major, version, vendor, os_arch, is_jdk as "is_jdk: bool"
|
||||
"#,
|
||||
absolute_path,
|
||||
i64::from(major),
|
||||
version,
|
||||
vendor,
|
||||
os_arch,
|
||||
is_jdk,
|
||||
)
|
||||
.fetch_one(pool)
|
||||
.await
|
||||
|
|
@ -41,7 +44,8 @@ pub async fn get_by_path(
|
|||
let row = sqlx::query_as!(
|
||||
JavaVersionRow,
|
||||
r#"
|
||||
SELECT absolute_path, major, version, vendor, os_arch FROM java_versions
|
||||
SELECT absolute_path, major, version, vendor, os_arch, is_jdk as "is_jdk: bool"
|
||||
FROM java_versions
|
||||
WHERE absolute_path = ?
|
||||
"#,
|
||||
absolute_path,
|
||||
|
|
@ -59,7 +63,7 @@ pub async fn get_latest_by_major(
|
|||
let row = sqlx::query_as!(
|
||||
JavaVersionRow,
|
||||
r#"
|
||||
SELECT absolute_path, major, version, vendor, os_arch
|
||||
SELECT absolute_path, major, version, vendor, os_arch, is_jdk as "is_jdk: bool"
|
||||
FROM java_versions
|
||||
WHERE major = ?
|
||||
ORDER BY version DESC
|
||||
|
|
@ -90,7 +94,8 @@ pub async fn list_all(pool: &SqlitePool) -> Result<Vec<JavaVersionRow>, DbError>
|
|||
let rows = sqlx::query_as!(
|
||||
JavaVersionRow,
|
||||
r#"
|
||||
SELECT absolute_path, major, version, vendor, os_arch FROM java_versions
|
||||
SELECT absolute_path, major, version, vendor, os_arch, is_jdk as "is_jdk: bool"
|
||||
FROM java_versions
|
||||
ORDER BY major DESC, version DESC
|
||||
"#,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -7,4 +7,5 @@ pub struct JavaVersionRow {
|
|||
pub version: String,
|
||||
pub vendor: String,
|
||||
pub os_arch: String,
|
||||
pub is_jdk: bool,
|
||||
}
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -14,11 +14,7 @@ public final class JavaInfo {
|
|||
}
|
||||
}
|
||||
|
||||
// Minecraft needs AWT. Stripped, headless and hand-jlinked images drop
|
||||
// java.desktop and only blow up once the game reaches for it.
|
||||
System.out.println("java.awt=" + hasClass("java.awt.Toolkit"));
|
||||
// A kit ships a compiler, a runtime image does not. On 8 this finds the
|
||||
// one in tools.jar, on 9+ the jdk.compiler module.
|
||||
System.out.println("java.jdk=" + hasCompiler());
|
||||
|
||||
System.exit(returnCode);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,4 @@
|
|||
use std::{
|
||||
collections::HashMap,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
use std::{collections::HashMap, path::PathBuf};
|
||||
|
||||
use async_tempfile::TempDir;
|
||||
use tokio::sync::OnceCell;
|
||||
|
|
@ -10,19 +7,6 @@ use crate::error::{JavaError, JavaResult};
|
|||
|
||||
const JAVA_INFO_CLASS: &[u8] = include_bytes!("../assets/java/JavaInfo.class");
|
||||
|
||||
/// Tools that only ever ship with a development kit, never with a runtime image.
|
||||
const JAVAC_BIN: &str = if cfg!(windows) { "javac.exe" } else { "javac" };
|
||||
const JMOD_BIN: &str = if cfg!(windows) { "jmod.exe" } else { "jmod" };
|
||||
|
||||
/// The native library behind `java.awt`. An image linked without `java.desktop`
|
||||
/// simply does not ship it.
|
||||
#[cfg(target_os = "windows")]
|
||||
const AWT_LIBRARY: &str = "awt.dll";
|
||||
#[cfg(target_os = "macos")]
|
||||
const AWT_LIBRARY: &str = "libawt.dylib";
|
||||
#[cfg(all(unix, not(target_os = "macos")))]
|
||||
const AWT_LIBRARY: &str = "libawt.so";
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct JavaCheckInfo {
|
||||
pub version: String,
|
||||
|
|
@ -84,15 +68,12 @@ pub async fn check_java_runtime(absolute_path: String) -> JavaResult<JavaCheckIn
|
|||
return Err(JavaError::InvalidJavaPath { path: absolute_path });
|
||||
};
|
||||
|
||||
let home = java_home(&absolute_path, info.get("java.home"));
|
||||
|
||||
// Minecraft draws its window through AWT. A headless or hand-jlinked image
|
||||
// without `java.desktop` launches happily and then dies mid-game, so it is
|
||||
// rejected here rather than recorded as usable.
|
||||
if !has_awt_support(&info, &home) {
|
||||
if !probe_flag(&info, "java.awt") {
|
||||
tracing::warn!(
|
||||
path = %absolute_path,
|
||||
home = %home.display(),
|
||||
"java installation has no java.awt support"
|
||||
);
|
||||
return Err(JavaError::MissingAwtSupport { path: absolute_path });
|
||||
|
|
@ -108,99 +89,14 @@ pub async fn check_java_runtime(absolute_path: String) -> JavaResult<JavaCheckIn
|
|||
.get("java.vendor")
|
||||
.cloned()
|
||||
.unwrap_or_else(|| String::from("unknown")),
|
||||
is_jdk: probe_flag(&info, "java.jdk").unwrap_or(false) || is_jdk_home(&home),
|
||||
is_jdk: probe_flag(&info, "java.jdk"),
|
||||
})
|
||||
}
|
||||
|
||||
/// Whether the installation behind a `java` executable is a development kit.
|
||||
///
|
||||
/// Nothing is recorded about kit-ness in the store, so callers holding only a
|
||||
/// path ask the filesystem again instead of the schema growing a column for a
|
||||
/// hint this cheap to recompute.
|
||||
pub(crate) fn is_jdk_executable(absolute_path: &str) -> bool {
|
||||
is_jdk_home(&java_home(absolute_path, None))
|
||||
}
|
||||
|
||||
/// Whether `home` is a development kit rather than a runtime image.
|
||||
///
|
||||
/// Directory names lie in both directions (`.../jdk-21/jre`, runtimes unpacked
|
||||
/// into a folder someone called `jdk`), so this only looks for artefacts a
|
||||
/// runtime image never carries: the compiler, `jmod`, the JDK 8 `tools.jar`,
|
||||
/// and the JNI headers.
|
||||
pub(crate) fn is_jdk_home(home: &Path) -> bool {
|
||||
let bin = home.join("bin");
|
||||
|
||||
bin.join(JAVAC_BIN).is_file()
|
||||
|| bin.join(JMOD_BIN).is_file()
|
||||
|| home.join("jmods").is_dir()
|
||||
|| home.join("lib").join("tools.jar").is_file()
|
||||
|| home.join("include").join("jni.h").is_file()
|
||||
}
|
||||
|
||||
/// The installation root.
|
||||
///
|
||||
/// `java.home` as the probe reports it is authoritative; when the compiled
|
||||
/// probe class predates that property we fall back to the executable's own
|
||||
/// location, resolving symlinks first so a `/usr/bin/java` shim lands in the
|
||||
/// real home rather than in `/usr`.
|
||||
fn java_home(absolute_path: &str, reported: Option<&String>) -> PathBuf {
|
||||
if let Some(home) = reported.filter(|home| !home.is_empty()) {
|
||||
return PathBuf::from(home);
|
||||
}
|
||||
|
||||
let executable = std::fs::canonicalize(absolute_path)
|
||||
.unwrap_or_else(|_| PathBuf::from(absolute_path));
|
||||
|
||||
executable
|
||||
.parent()
|
||||
.and_then(Path::parent)
|
||||
.map(Path::to_path_buf)
|
||||
.unwrap_or(executable)
|
||||
}
|
||||
|
||||
/// Whether `java.awt` is there: the probe's own answer when it gave one, and
|
||||
/// otherwise what the installation ships on disk.
|
||||
fn has_awt_support(info: &HashMap<String, String>, home: &Path) -> bool {
|
||||
if let Some(reported) = probe_flag(info, "java.awt") {
|
||||
return reported;
|
||||
}
|
||||
|
||||
// Java 9+ images record the modules they were linked with.
|
||||
if let Some(modules) = release_modules(home) {
|
||||
return modules.split_whitespace().any(|module| module == "java.desktop");
|
||||
}
|
||||
|
||||
// Java 8, and anything else without a `release` file: AWT is a native
|
||||
// library sitting next to the runtime.
|
||||
awt_library_exists(home)
|
||||
}
|
||||
|
||||
/// The `MODULES` line of an image's `release` file, if it has one.
|
||||
fn release_modules(home: &Path) -> Option<String> {
|
||||
let release = std::fs::read_to_string(home.join("release")).ok()?;
|
||||
|
||||
release.lines().find_map(|line| {
|
||||
let modules = line.strip_prefix("MODULES=")?;
|
||||
Some(modules.trim_matches('"').to_string())
|
||||
})
|
||||
}
|
||||
|
||||
fn awt_library_exists(home: &Path) -> bool {
|
||||
// Windows keeps native libraries in `bin` and everyone else in `lib`; a
|
||||
// JDK 8 also nests a whole runtime under `jre`.
|
||||
[
|
||||
home.join("lib"),
|
||||
home.join("bin"),
|
||||
home.join("jre").join("lib"),
|
||||
home.join("jre").join("bin"),
|
||||
]
|
||||
.iter()
|
||||
.any(|dir| dir.join(AWT_LIBRARY).exists())
|
||||
}
|
||||
|
||||
/// Reads a boolean the probe printed, `None` when it printed no such line.
|
||||
fn probe_flag(info: &HashMap<String, String>, key: &str) -> Option<bool> {
|
||||
info.get(key).map(|value| value.eq_ignore_ascii_case("true"))
|
||||
/// Reads a boolean the probe printed; anything else counts as `false`.
|
||||
fn probe_flag(info: &HashMap<String, String>, key: &str) -> bool {
|
||||
info.get(key)
|
||||
.is_some_and(|value| value.eq_ignore_ascii_case("true"))
|
||||
}
|
||||
|
||||
static TEMP_JAVA_INFO: OnceCell<TempDir> = OnceCell::const_new();
|
||||
|
|
@ -232,126 +128,14 @@ mod tests {
|
|||
.collect()
|
||||
}
|
||||
|
||||
fn touch(path: &Path) {
|
||||
if let Some(parent) = path.parent() {
|
||||
std::fs::create_dir_all(parent).expect("create parent");
|
||||
}
|
||||
std::fs::write(path, b"").expect("write file");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn a_runtime_image_is_not_mistaken_for_a_kit() {
|
||||
let dir = polyio::tempdir().await.expect("tempdir");
|
||||
let home = dir.dir_path();
|
||||
|
||||
touch(&home.join("bin").join("java"));
|
||||
touch(&home.join("lib").join("modules"));
|
||||
|
||||
assert!(!is_jdk_home(home));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn a_kit_is_recognised_by_its_compiler() {
|
||||
let dir = polyio::tempdir().await.expect("tempdir");
|
||||
let home = dir.dir_path();
|
||||
|
||||
touch(&home.join("bin").join("java"));
|
||||
touch(&home.join("bin").join(JAVAC_BIN));
|
||||
|
||||
assert!(is_jdk_home(home));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn a_kit_is_recognised_by_its_headers_alone() {
|
||||
let dir = polyio::tempdir().await.expect("tempdir");
|
||||
let home = dir.dir_path();
|
||||
|
||||
touch(&home.join("bin").join("java"));
|
||||
touch(&home.join("include").join("jni.h"));
|
||||
|
||||
assert!(is_jdk_home(home));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn a_legacy_kit_is_recognised_by_tools_jar() {
|
||||
let dir = polyio::tempdir().await.expect("tempdir");
|
||||
let home = dir.dir_path();
|
||||
|
||||
touch(&home.join("lib").join("tools.jar"));
|
||||
|
||||
assert!(is_jdk_home(home));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn the_directory_name_alone_proves_nothing() {
|
||||
let dir = polyio::tempdir().await.expect("tempdir");
|
||||
let home = dir.dir_path().join("jdk-21");
|
||||
|
||||
touch(&home.join("bin").join("java"));
|
||||
|
||||
assert!(!is_jdk_home(&home));
|
||||
#[test]
|
||||
fn a_flag_the_probe_never_printed_is_false() {
|
||||
assert!(!probe_flag(&info(&[]), "java.awt"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn the_probe_has_the_last_word_on_awt() {
|
||||
let missing = Path::new("/nonexistent-java-home");
|
||||
|
||||
assert!(has_awt_support(&info(&[("java.awt", "true")]), missing));
|
||||
assert!(!has_awt_support(&info(&[("java.awt", "false")]), missing));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn a_module_list_without_java_desktop_fails_the_check() {
|
||||
let dir = polyio::tempdir().await.expect("tempdir");
|
||||
let home = dir.dir_path();
|
||||
|
||||
std::fs::write(
|
||||
home.join("release"),
|
||||
"JAVA_VERSION=\"21.0.3\"\nMODULES=\"java.base java.logging\"\n",
|
||||
)
|
||||
.expect("write release");
|
||||
|
||||
assert!(!has_awt_support(&info(&[]), home));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn a_module_list_with_java_desktop_passes() {
|
||||
let dir = polyio::tempdir().await.expect("tempdir");
|
||||
let home = dir.dir_path();
|
||||
|
||||
std::fs::write(
|
||||
home.join("release"),
|
||||
"JAVA_VERSION=\"21.0.3\"\nMODULES=\"java.base java.desktop java.logging\"\n",
|
||||
)
|
||||
.expect("write release");
|
||||
|
||||
assert!(has_awt_support(&info(&[]), home));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn a_release_less_image_falls_back_to_the_native_library() {
|
||||
let dir = polyio::tempdir().await.expect("tempdir");
|
||||
let home = dir.dir_path();
|
||||
|
||||
assert!(!has_awt_support(&info(&[]), home));
|
||||
|
||||
touch(&home.join("lib").join(AWT_LIBRARY));
|
||||
|
||||
assert!(has_awt_support(&info(&[]), home));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_missing_home_falls_back_to_the_executable_location() {
|
||||
let home = java_home("/opt/jdk-21/bin/java", None);
|
||||
|
||||
assert_eq!(home, PathBuf::from("/opt/jdk-21"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_reported_home_wins_over_the_executable_location() {
|
||||
let reported = String::from("/opt/real-home");
|
||||
let home = java_home("/usr/bin/java", Some(&reported));
|
||||
|
||||
assert_eq!(home, PathBuf::from("/opt/real-home"));
|
||||
fn a_flag_is_read_regardless_of_case() {
|
||||
assert!(probe_flag(&info(&[("java.awt", "TRUE")]), "java.awt"));
|
||||
assert!(!probe_flag(&info(&[("java.awt", "false")]), "java.awt"));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,10 @@ pub struct JavaRuntime {
|
|||
pub version: String,
|
||||
pub vendor: JavaVendor,
|
||||
pub os_arch: String,
|
||||
/// Whether this is a development kit rather than a bare runtime image, as
|
||||
/// the probe reported it when the runtime was recorded (see
|
||||
/// [`crate::JavaCheckInfo::is_jdk`]).
|
||||
pub is_jdk: bool,
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -149,7 +149,7 @@ impl JavaService {
|
|||
let recorded = self.store.latest_by_major(major).await?;
|
||||
|
||||
if let Some(runtime) = &recorded
|
||||
&& checker::is_jdk_executable(&runtime.absolute_path)
|
||||
&& runtime.is_jdk
|
||||
{
|
||||
return Ok(runtime.clone());
|
||||
}
|
||||
|
|
@ -347,6 +347,7 @@ impl JavaService {
|
|||
vendor: JavaVendor::from_str(&info.vendor)
|
||||
.unwrap_or_else(|_| JavaVendor::Other(info.vendor.clone())),
|
||||
os_arch: info.os_arch.clone(),
|
||||
is_jdk: info.is_jdk,
|
||||
};
|
||||
|
||||
Ok(self.store.upsert(&runtime).await?)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue