diff options
author | Dario Vladović <d.vladimyr@gmail.com> | 2020-07-29 18:26:46 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-07-29 18:26:46 +0200 |
commit | 997387ee50e39cf2a87cd494c49c93f551d2d28c (patch) | |
tree | 40523ae2bfda3599e02e5ec58bea264f3a9c29e5 /src | |
parent | 84f049f836c7e73e5bd2573dcd69213cd23eff8b (diff) |
refactor(java): parse version using regex (#1496)
* refactor(java): parse version using regex
Mock java version retrieval & extend java module test suite with
rendering tests.
* chore: remove nom crate
* fix(java): support parsing version from both stdout & stderr
* fix(java): fix java command mock
* refactor(java): simplify version regex
Diffstat (limited to 'src')
-rw-r--r-- | src/modules/java.rs | 250 | ||||
-rw-r--r-- | src/modules/utils/java_version_parser.rs | 65 | ||||
-rw-r--r-- | src/modules/utils/mod.rs | 1 | ||||
-rw-r--r-- | src/utils.rs | 4 |
4 files changed, 180 insertions, 140 deletions
diff --git a/src/modules/java.rs b/src/modules/java.rs index faf7d8c6e..4298108b6 100644 --- a/src/modules/java.rs +++ b/src/modules/java.rs @@ -3,9 +3,11 @@ use crate::formatter::StringFormatter; use super::{Context, Module, RootModuleConfig}; -use crate::modules::utils::java_version_parser; use crate::utils; +use regex::Regex; +const JAVA_VERSION_PATTERN: &str = "(?P<version>[\\d\\.]+)[^\\s]*\\s(?:built|from)"; + /// Creates a module with the current Java version /// /// Will display the Java version if any of the following criteria are met: @@ -22,39 +24,37 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> { return None; } - match get_java_version() { - Some(java_version) => { - let mut module = context.new_module("java"); - let config: JavaConfig = JavaConfig::try_load(module.config); - let formatted_version = format_java_version(java_version)?; - - let parsed = StringFormatter::new(config.format).and_then(|formatter| { - formatter - .map_meta(|var, _| match var { - "symbol" => Some(config.symbol), - _ => None, - }) - .map_style(|variable| match variable { - "style" => Some(Ok(config.style)), - _ => None, - }) - .map(|variable| match variable { - "version" => Some(Ok(&formatted_version)), - _ => None, - }) - .parse(None) - }); - module.set_segments(match parsed { - Ok(segments) => segments, - Err(error) => { - log::warn!("Error in module `java`:\n{}", error); - return None; - } - }); - Some(module) + let java_version = get_java_version()?; + + let mut module = context.new_module("java"); + let config: JavaConfig = JavaConfig::try_load(module.config); + + let parsed = StringFormatter::new(config.format).and_then(|formatter| { + formatter + .map_meta(|var, _| match var { + "symbol" => Some(config.symbol), + _ => None, + }) + .map_style(|variable| match variable { + "style" => Some(Ok(config.style)), + _ => None, + }) + .map(|variable| match variable { + "version" => Some(Ok(&java_version)), + _ => None, + }) + .parse(None) + }); + + module.set_segments(match parsed { + Ok(segments) => segments, + Err(error) => { + log::warn!("Error in module `java`:\n{}", error); + return None; } - None => None, - } + }); + + Some(module) } fn get_java_version() -> Option<String> { @@ -64,79 +64,181 @@ fn get_java_version() -> Option<String> { }; let output = utils::exec_cmd(&java_command.as_str(), &["-Xinternalversion"])?; - Some(format!("{}{}", output.stdout, output.stderr)) + let java_version = if output.stdout.is_empty() { + output.stderr + } else { + output.stdout + }; + + parse_java_version(&java_version) } -/// 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)) +fn parse_java_version(java_version: &str) -> Option<String> { + let re = Regex::new(JAVA_VERSION_PATTERN).ok()?; + let captures = re.captures(java_version)?; + let version = &captures["version"]; + + Some(format!("v{}", &version)) } #[cfg(test)] mod tests { use super::*; + use crate::modules::utils::test::render_module; + use ansi_term::Color; + use std::fs::File; + use std::io; + + #[test] + fn test_parse_java_version_openjdk() { + let java_8 = "OpenJDK 64-Bit Server VM (25.222-b10) for linux-amd64 JRE (1.8.0_222-b10), built on Jul 11 2019 10:18:43 by \"openjdk\" with gcc 4.4.7 20120313 (Red Hat 4.4.7-23)"; + let java_11 = "OpenJDK 64-Bit Server VM (11.0.4+11-post-Ubuntu-1ubuntu219.04) for linux-amd64 JRE (11.0.4+11-post-Ubuntu-1ubuntu219.04), built on Jul 18 2019 18:21:46 by \"build\" with gcc 8.3.0"; + assert_eq!(parse_java_version(java_11), Some("v11.0.4".to_string())); + assert_eq!(parse_java_version(java_8), Some("v1.8.0".to_string())); + } + + #[test] + fn test_parse_java_version_oracle() { + let java_8 = "Java HotSpot(TM) Client VM (25.65-b01) for linux-arm-vfp-hflt JRE (1.8.0_65-b17), built on Oct 6 2015 16:19:04 by \"java_re\" with gcc 4.7.2 20120910 (prerelease)"; + assert_eq!(parse_java_version(java_8), Some("v1.8.0".to_string())); + } + + #[test] + fn test_parse_java_version_redhat() { + let java_8 = "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_12 = "OpenJDK 64-Bit Server VM (12.0.2+10) for linux-amd64 JRE (12.0.2+10), built on Jul 18 2019 14:41:47 by \"jenkins\" with gcc 7.3.1 20180303 (Red Hat 7.3.1-5)"; + assert_eq!(parse_java_version(java_8), Some("v1.8.0".to_string())); + assert_eq!(parse_java_version(java_12), Some("v12.0.2".to_string())); + } + + #[test] + fn test_parse_java_version_zulu() { + let java_8 = "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)"; + let java_11 = "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!(parse_java_version(java_8), Some("v1.8.0".to_string())); + assert_eq!(parse_java_version(java_11), Some("v11.0.4".to_string())); + } + + #[test] + fn test_parse_java_version_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_version(java_8), Some("v1.8.0".to_string())); + assert_eq!(parse_java_version(java_11), Some("v11.0.4".to_string())); + } + + #[test] + fn test_parse_java_version_graalvm() { + let java_8 = "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!(parse_java_version(java_8), Some("v8".to_string())); + } + + #[test] + fn test_parse_java_version_amazon_corretto() { + let java_8 = "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 = "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!(parse_java_version(java_8), Some("v1.8.0".to_string())); + assert_eq!(parse_java_version(java_11), Some("v11.0.4".to_string())); + } + + #[test] + fn test_parse_java_version_sapmachine() { + let java_11 = "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!(parse_java_version(java_11), Some("v11.0.4".to_string())); + } + + #[test] + fn test_parse_java_version_unknown() { + let unknown_jre = "Unknown JRE"; + assert_eq!(parse_java_version(unknown_jre), None); + } #[test] - fn test_format_java_version_openjdk() { - 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 10:18:43 by \"openjdk\" with gcc 4.4.7 20120313 (Red Hat 4.4.7-23)"); - let java_11 = String::from("OpenJDK 64-Bit Server VM (11.0.4+11-post-Ubuntu-1ubuntu219.04) for linux-amd64 JRE (11.0.4+11-post-Ubuntu-1ubuntu219.04), built on Jul 18 2019 18:21:46 by \"build\" with gcc 8.3.0"); - assert_eq!(format_java_version(java_11), Some(String::from("v11.0.4"))); - assert_eq!(format_java_version(java_8), Some(String::from("v1.8.0"))); + fn folder_without_java_file() -> io::Result<()> { + let dir = tempfile::tempdir()?; + let actual = render_module("java", dir.path(), None); + let expected = None; + assert_eq!(expected, actual); + dir.close() } #[test] - fn test_format_java_version_oracle() { - let java_8 = String::from("Java HotSpot(TM) Client VM (25.65-b01) for linux-arm-vfp-hflt JRE (1.8.0_65-b17), built on Oct 6 2015 16:19:04 by \"java_re\" with gcc 4.7.2 20120910 (prerelease)"); - assert_eq!(format_java_version(java_8), Some(String::from("v1.8.0"))); + fn folder_with_java_file() -> io::Result<()> { + let dir = tempfile::tempdir()?; + File::create(dir.path().join("Main.java"))?.sync_all()?; + let actual = render_module("java", dir.path(), None); + let expected = Some(format!("via {} ", Color::Red.dimmed().paint("☕ v13.0.2"))); + assert_eq!(expected, actual); + dir.close() } #[test] - fn test_format_java_version_redhat() { - 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_12 = String::from("OpenJDK 64-Bit Server VM (12.0.2+10) for linux-amd64 JRE (12.0.2+10), built on Jul 18 2019 14:41:47 by \"jenkins\" 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_12), Some(String::from("v12.0.2"))); + fn folder_with_class_file() -> io::Result<()> { + let dir = tempfile::tempdir()?; + File::create(dir.path().join("Main.class"))?.sync_all()?; + let actual = render_module("java", dir.path(), None); + let expected = Some(format!("via {} ", Color::Red.dimmed().paint("☕ v13.0.2"))); + assert_eq!(expected, actual); + dir.close() } #[test] - fn test_format_java_version_zulu() { - 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)"); - 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"))); + fn folder_with_gradle_file() -> io::Result<()> { + let dir = tempfile::tempdir()?; + File::create(dir.path().join("build.gradle"))?.sync_all()?; + let actual = render_module("java", dir.path(), None); + let expected = Some(format!("via {} ", Color::Red.dimmed().paint("☕ v13.0.2"))); + assert_eq!(expected, actual); + dir.close() } #[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"))); + fn folder_with_jar_archive() -> io::Result<()> { + let dir = tempfile::tempdir()?; + File::create(dir.path().join("test.jar"))?.sync_all()?; + let actual = render_module("java", dir.path(), None); + let expected = Some(format!("via {} ", Color::Red.dimmed().paint("☕ v13.0.2"))); + assert_eq!(expected, actual); + dir.close() } #[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"))); + fn folder_with_pom_file() -> io::Result<()> { + let dir = tempfile::tempdir()?; + File::create(dir.path().join("pom.xml"))?.sync_all()?; + let actual = render_module("java", dir.path(), None); + let expected = Some(format!("via {} ", Color::Red.dimmed().paint("☕ v13.0.2"))); + assert_eq!(expected, actual); + dir.close() } #[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"))); + fn folder_with_gradle_kotlin_build_file() -> io::Result<()> { + let dir = tempfile::tempdir()?; + File::create(dir.path().join("build.gradle.kts"))?.sync_all()?; + let actual = render_module("java", dir.path(), None); + let expected = Some(format!("via {} ", Color::Red.dimmed().paint("☕ v13.0.2"))); + assert_eq!(expected, actual); + dir.close() } #[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"))); + fn folder_with_sbt_build_file() -> io::Result<()> { + let dir = tempfile::tempdir()?; + File::create(dir.path().join("build.gradle.kts"))?.sync_all()?; + let actual = render_module("java", dir.path(), None); + let expected = Some(format!("via {} ", Color::Red.dimmed().paint("☕ v13.0.2"))); + assert_eq!(expected, actual); + dir.close() } #[test] - fn test_format_java_version_unknown() { - let unknown_jre = String::from("Unknown JRE"); - assert_eq!(format_java_version(unknown_jre), None); + fn folder_with_java_version_file() -> io::Result<()> { + let dir = tempfile::tempdir()?; + File::create(dir.path().join(".java-version"))?.sync_all()?; + let actual = render_module("java", dir.path(), None); + let expected = Some(format!("via {} ", Color::Red.dimmed().paint("☕ v13.0.2"))); + assert_eq!(expected, actual); + dir.close() } } diff --git a/src/modules/utils/java_version_parser.rs b/src/modules/utils/java_version_parser.rs deleted file mode 100644 index cf9445dfe..000000000 --- a/src/modules/utils/java_version_parser.rs +++ /dev/null @@ -1,65 +0,0 @@ -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"))); - } -} diff --git a/src/modules/utils/mod.rs b/src/modules/utils/mod.rs index d164de4d7..89b124150 100644 --- a/src/modules/utils/mod.rs +++ b/src/modules/utils/mod.rs @@ -1,5 +1,4 @@ pub mod directory; -pub mod java_version_parser; #[cfg(target_os = "windows")] pub mod directory_win; diff --git a/src/utils.rs b/src/utils.rs index 34fafce60..75eb478e5 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -80,6 +80,10 @@ Elixir 1.10 (compiled with Erlang/OTP 22)\n", stdout: String::from("v3.1.1+gafe7058\n"), stderr: String::default(), }), + s if s.ends_with("java -Xinternalversion") => Some(CommandOutput { + stdout: String::from("OpenJDK 64-Bit Server VM (13.0.2+8) for bsd-amd64 JRE (13.0.2+8), built on Feb 6 2020 02:07:52 by \"brew\" with clang 4.2.1 Compatible Apple LLVM 11.0.0 (clang-1100.0.33.17)"), + stderr: String::default(), + }), "julia --version" => Some(CommandOutput { stdout: String::from("julia version 1.4.0\n"), stderr: String::default(), |