fix: Show Java version from OpenJ9 Java runtimes (#507)

This PR tries to improve the version detection across multiple Java VM vendors. The module captures both STDOUT and STDERR outputs of the java -Xinternalversion call.

Eclipse OpenJ9, Azul Zulu, SapMachine, Amazon Corretto and GraalVM outputs are unit tested now.
This commit is contained in:
yuri 2019-10-25 03:00:05 +02:00 committed by Matan Kushner
parent edf5176c37
commit b7762a3e91
6 changed files with 158 additions and 18 deletions

37
Cargo.lock generated
View File

@ -375,6 +375,18 @@ name = "lazycell"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "lexical-core"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"static_assertions 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "libc"
version = "0.2.62"
@ -458,6 +470,16 @@ name = "nodrop"
version = "0.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "nom"
version = "5.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"lexical-core 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-integer"
version = "0.1.41"
@ -767,6 +789,7 @@ dependencies = [
"gethostname 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"git2 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"nom 5.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"once_cell 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"path-slash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"pretty_env_logger 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
@ -789,6 +812,11 @@ dependencies = [
"syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "static_assertions"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "strsim"
version = "0.8.0"
@ -962,6 +990,11 @@ name = "vec_map"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "version_check"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "void"
version = "1.0.2"
@ -1062,6 +1095,7 @@ dependencies = [
"checksum jobserver 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "f2b1d42ef453b30b7387e113da1c83ab1605d90c5b4e0eb8e96d016ed3b8c160"
"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
"checksum lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f"
"checksum lexical-core 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2304bccb228c4b020f3a4835d247df0a02a7c4686098d4167762cfbbe4c5cb14"
"checksum libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)" = "34fcd2c08d2f832f376f4173a231990fa5aef4e99fb569867318a227ef4c06ba"
"checksum libgit2-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a30f8637eb59616ee3b8a00f6adff781ee4ddd8343a615b8238de756060cc1b3"
"checksum libz-sys 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "2eb5e43362e38e2bca2fd5f5134c4d4564a23a5c28e9b95411652021a8675ebe"
@ -1073,6 +1107,7 @@ dependencies = [
"checksum memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ce6075db033bbbb7ee5a0bbd3a3186bbae616f57fb001c485c7ff77955f8177f"
"checksum nix 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6c722bee1037d430d0f8e687bbdbf222f27cc6e4e68d5caf630857bb2b6dbdce"
"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945"
"checksum nom 5.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c618b63422da4401283884e6668d39f819a106ef51f5f59b81add00075da35ca"
"checksum num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "b85e541ef8255f6cf42bbfe4ef361305c6c135d10919ecc26126c4e5ae94bc09"
"checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32"
"checksum num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bcef43580c035376c0705c42792c294b66974abbfd2789b511784023f71f3273"
@ -1112,6 +1147,7 @@ dependencies = [
"checksum serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)" = "9796c9b7ba2ffe7a9ce53c2287dfc48080f4b2b362fcc245a259b3a7201119dd"
"checksum serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)" = "2f72eb2a68a7dc3f9a691bfda9305a1c017a6215e5a4545c258500d2099a37c2"
"checksum smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ab606a9c5e214920bb66c458cd7be8ef094f813f20fe77a54cc7dbfff220d4b7"
"checksum static_assertions 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7f3eb36b47e512f8f1c9e3d10c2c1965bc992bd9cdb024fa581e2194501c83d3"
"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
"checksum syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)" = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5"
"checksum syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "66850e97125af79138385e9b88339cbcd037e3f28ceab8c5ad98e64f0f1f80bf"
@ -1134,6 +1170,7 @@ dependencies = [
"checksum url 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "75b414f6c464c879d7f9babf951f23bc3743fb7313c081b2e6ca719067ea9d61"
"checksum vcpkg 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "33dd455d0f96e90a75803cfeb7f948768c08d70a6de9a8d2362461935698bf95"
"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a"
"checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd"
"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
"checksum wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b89c3ce4ce14bdc6fb6beaf9ec7928ca331de5df7e5ea278375642a2f478570d"
"checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6"

View File

@ -45,6 +45,7 @@ sysinfo = "0.9.5"
byte-unit = "3.0.3"
starship_module_config_derive = { version = "0.1.0", path = "starship_module_config_derive" }
yaml-rust = "0.4"
nom = "5.0.1"
[dev-dependencies]
tempfile = "3.1.0"

View File

@ -1,9 +1,12 @@
use std::process::Command;
use std::process::Output;
use ansi_term::Color;
use super::{Context, Module};
use crate::modules::utils::java_version_parser;
/// Creates a module with the current Java version
///
/// Will display the Java version if any of the following criteria are met:
@ -47,27 +50,24 @@ fn get_java_version() -> Option<String> {
};
match Command::new(java_command).arg("-Xinternalversion").output() {
Ok(output) => Some(String::from_utf8(output.stdout).unwrap()),
Ok(output) => Some(combine_outputs(output)),
Err(_) => None,
}
}
/// Extract the java version from `java_stdout`.
/// The expected format is similar to: "JRE (1.8.0_222-b10)".
/// Some Java vendors don't follow this format: "JRE (Zulu 8.40.0.25-CA-linux64)").
fn format_java_version(java_stdout: String) -> Option<String> {
let start = java_stdout.find("JRE (")? + "JRE (".len();
let end = start
+ (java_stdout[start..].find(|c| match c {
'0'..='9' | '.' => false,
_ => true,
})?);
/// Combines the standard and error outputs.
///
/// This is due some Java vendors using `STDERR` as the output.
fn combine_outputs(output: Output) -> String {
let std_out = String::from_utf8(output.stdout).unwrap();
let std_err = String::from_utf8(output.stderr).unwrap();
if start == end {
None
} else {
Some(format!("v{}", &java_stdout[start..end]))
}
format!("{}{}", std_out, std_err)
}
/// Extract the java version from `java_out`.
fn format_java_version(java_out: String) -> Option<String> {
java_version_parser::parse_jre_version(&java_out).map(|result| format!("v{}", result))
}
#[cfg(test)]
@ -98,8 +98,43 @@ mod tests {
#[test]
fn test_format_java_version_zulu() {
// Not currently supported
let java_8 = String::from("OpenJDK 64-Bit Server VM (25.222-b10) for linux-amd64 JRE (Zulu 8.40.0.25-CA-linux64) (1.8.0_222-b10), built on Jul 11 2019 11:36:39 by \"zulu_re\" with gcc 4.4.7 20120313 (Red Hat 4.4.7-3)");
assert_eq!(format_java_version(java_8), None);
let java_11 = String::from("OpenJDK 64-Bit Server VM (11.0.4+11-LTS) for linux-amd64 JRE (Zulu11.33+15-CA) (11.0.4+11-LTS), built on Jul 11 2019 21:37:17 by \"zulu_re\" with gcc 4.9.2 20150212 (Red Hat 4.9.2-6)");
assert_eq!(format_java_version(java_8), Some(String::from("v1.8.0")));
assert_eq!(format_java_version(java_11), Some(String::from("v11.0.4")));
}
#[test]
fn test_format_java_version_eclipse_openj9() {
let java_8 = String::from("Eclipse OpenJ9 OpenJDK 64-bit Server VM (1.8.0_222-b10) from linux-amd64 JRE with Extensions for OpenJDK for Eclipse OpenJ9 8.0.222.0, built on Jul 17 2019 21:29:18 by jenkins with g++ (GCC) 7.3.1 20180303 (Red Hat 7.3.1-5)");
let java_11 = String::from("Eclipse OpenJ9 OpenJDK 64-bit Server VM (11.0.4+11) from linux-amd64 JRE with Extensions for OpenJDK for Eclipse OpenJ9 11.0.4.0, built on Jul 17 2019 21:51:37 by jenkins with g++ (GCC) 7.3.1 20180303 (Red Hat 7.3.1-5)");
assert_eq!(format_java_version(java_8), Some(String::from("v1.8.0")));
assert_eq!(format_java_version(java_11), Some(String::from("v11.0.4")));
}
#[test]
fn test_format_java_version_graalvm() {
let java_8 = String::from("OpenJDK 64-Bit GraalVM CE 19.2.0.1 (25.222-b08-jvmci-19.2-b02) for linux-amd64 JRE (8u222), built on Jul 19 2019 17:37:13 by \"buildslave\" with gcc 7.3.0");
assert_eq!(format_java_version(java_8), Some(String::from("v8")));
}
#[test]
fn test_format_java_version_amazon_corretto() {
let java_8 = String::from("OpenJDK 64-Bit Server VM (25.222-b10) for linux-amd64 JRE (1.8.0_222-b10), built on Jul 11 2019 20:48:53 by \"root\" with gcc 7.3.1 20180303 (Red Hat 7.3.1-5)");
let java_11 = String::from("OpenJDK 64-Bit Server VM (11.0.4+11-LTS) for linux-amd64 JRE (11.0.4+11-LTS), built on Jul 11 2019 20:06:11 by \"\" with gcc 7.3.1 20180303 (Red Hat 7.3.1-5)");
assert_eq!(format_java_version(java_8), Some(String::from("v1.8.0")));
assert_eq!(format_java_version(java_11), Some(String::from("v11.0.4")));
}
#[test]
fn test_format_java_version_sapmachine() {
let java_11 = String::from("OpenJDK 64-Bit Server VM (11.0.4+11-LTS-sapmachine) for linux-amd64 JRE (11.0.4+11-LTS-sapmachine), built on Jul 17 2019 08:58:43 by \"\" with gcc 7.3.0");
assert_eq!(format_java_version(java_11), Some(String::from("v11.0.4")));
}
#[test]
fn test_format_java_version_unknown() {
let unknown_jre = String::from("Unknown JRE");
assert_eq!(format_java_version(unknown_jre), None);
}
}

View File

@ -24,6 +24,7 @@ mod ruby;
mod rust;
mod time;
mod username;
mod utils;
#[cfg(feature = "battery")]
mod battery;

View File

@ -0,0 +1,65 @@
use nom::{
branch::alt,
bytes::complete::{tag, take_until, take_while1},
combinator::rest,
sequence::{preceded, tuple},
IResult,
};
fn is_version(c: char) -> bool {
c >= '0' && c <= '9' || c == '.'
}
fn version(input: &str) -> IResult<&str, &str> {
take_while1(&is_version)(input)
}
fn zulu(input: &str) -> IResult<&str, &str> {
let zulu_prefix_value = preceded(take_until("("), tag("("));
preceded(zulu_prefix_value, version)(input)
}
fn jre_prefix(input: &str) -> IResult<&str, &str> {
preceded(take_until("JRE ("), tag("JRE ("))(input)
}
fn j9_prefix(input: &str) -> IResult<&str, &str> {
preceded(take_until("VM ("), tag("VM ("))(input)
}
fn suffix(input: &str) -> IResult<&str, &str> {
rest(input)
}
fn parse(input: &str) -> IResult<&str, &str> {
let prefix = alt((jre_prefix, j9_prefix));
let version_or_zulu = alt((version, zulu));
let (input, (_, version, _)) = tuple((prefix, version_or_zulu, suffix))(input)?;
Ok((input, version))
}
/// Parse the java version from `java -Xinternalversion` format.
///
/// The expected format is similar to:
/// "JRE (1.8.0_222-b10)"
/// "JRE (Zulu 8.40.0.25-CA-linux64) (1.8.0_222-b10)"
/// "VM (1.8.0_222-b10)".
///
/// Some Java vendors might not follow this format.
pub fn parse_jre_version(input: &str) -> Option<&str> {
parse(input).map(|result| result.1).ok()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_parse_eclipse_openj9() {
let java_8 = "Eclipse OpenJ9 OpenJDK 64-bit Server VM (1.8.0_222-b10) from linux-amd64 JRE with Extensions for OpenJDK for Eclipse OpenJ9 8.0.222.0, built on Jul 17 2019 21:29:18 by jenkins with g++ (GCC) 7.3.1 20180303 (Red Hat 7.3.1-5)";
let java_11 = "Eclipse OpenJ9 OpenJDK 64-bit Server VM (11.0.4+11) from linux-amd64 JRE with Extensions for OpenJDK for Eclipse OpenJ9 11.0.4.0, built on Jul 17 2019 21:51:37 by jenkins with g++ (GCC) 7.3.1 20180303 (Red Hat 7.3.1-5)";
assert_eq!(parse(java_8), Ok(("", "1.8.0")));
assert_eq!(parse(java_11), Ok(("", "11.0.4")));
}
}

1
src/modules/utils/mod.rs Normal file
View File

@ -0,0 +1 @@
pub mod java_version_parser;