Repository: Cog-Creators/Red-DiscordBot

Issue:
[Audio] Handle more Java version strings
# Other bugs

#### What were you trying to do?

Load audio

#### What were you expecting to happen?

Audio is loaded.

#### What actually happened?
https://media.discordapp.net/attachments/723420331905253397/776865230886141952/putty_wsHs0S5W0E.png
Java version is 11.0.9.1
Audio's manager is looking for something formatted like 11.0.9
Audio won't load

#### How can we reproduce this issue?

Install Java 11.0.9.1, start the bot, try to load audio


Discussion:

Resolving patch:
diff --git a/redbot/cogs/audio/manager.py b/redbot/cogs/audio/manager.py
--- a/redbot/cogs/audio/manager.py
+++ b/redbot/cogs/audio/manager.py
@@ -36,12 +36,48 @@
 LAVALINK_APP_YML: Final[pathlib.Path] = LAVALINK_DOWNLOAD_DIR / "application.yml"
 
 _RE_READY_LINE: Final[Pattern] = re.compile(rb"Started Launcher in \S+ seconds")
-_FAILED_TO_START: Final[Pattern] = re.compile(rb"Web server failed to start. (.*)")
+_FAILED_TO_START: Final[Pattern] = re.compile(rb"Web server failed to start\. (.*)")
 _RE_BUILD_LINE: Final[Pattern] = re.compile(rb"Build:\s+(?P<build>\d+)")
-_RE_JAVA_VERSION_LINE: Final[Pattern] = re.compile(
-    r'version "(?P<major>\d+).(?P<minor>\d+).\d+(?:_\d+)?(?:-[A-Za-z0-9]+)?"'
+
+# Version regexes
+#
+# We expect the output to look something like:
+#     $ java -version
+#     ...
+#     ... version "VERSION STRING HERE" ...
+#     ...
+#
+# There are two version formats that we might get here:
+#
+# - Version scheme pre JEP 223 - used by Java 8 and older
+#
+# examples:
+# 1.8.0
+# 1.8.0_275
+# 1.8.0_272-b10
+# 1.8.0_202-internal-201903130451-b08
+# 1.8.0_272-ea-202010231715-b10
+# 1.8.0_272-ea-b10
+#
+# Implementation based on J2SE SDK/JRE Version String Naming Convention document:
+# https://www.oracle.com/java/technologies/javase/versioning-naming.html
+_RE_JAVA_VERSION_LINE_PRE223: Final[Pattern] = re.compile(
+    r'version "1\.(?P<major>[0-8])\.(?P<minor>0)(?:_(?:\d+))?(?:-.*)?"'
+)
+# - Version scheme introduced by JEP 223 - used by Java 9 and newer
+#
+# examples:
+# 11
+# 11.0.9
+# 11.0.9.1
+# 11.0.9-ea
+# 11.0.9-202011050024
+#
+# Implementation based on JEP 223 document:
+# https://openjdk.java.net/jeps/223
+_RE_JAVA_VERSION_LINE_223: Final[Pattern] = re.compile(
+    r'version "(?P<major>\d+)(?:\.(?P<minor>\d+))?(?:\.\d+)*(\-[a-zA-Z0-9]+)?"'
 )
-_RE_JAVA_SHORT_VERSION: Final[Pattern] = re.compile(r'version "(?P<major>\d+)"')
 
 LAVALINK_BRANCH_LINE: Final[Pattern] = re.compile(rb"Branch\s+(?P<branch>[\w\-\d_.]+)")
 LAVALINK_JAVA_LINE: Final[Pattern] = re.compile(rb"JVM:\s+(?P<jvm>\d+[.\d+]*)")
@@ -175,21 +211,19 @@ async def _get_java_version(self) -> Tuple[int, int]:
         _, err = await _proc.communicate()
 
         version_info: str = err.decode("utf-8")
-        # We expect the output to look something like:
-        #     $ java -version
-        #     ...
-        #     ... version "MAJOR.MINOR.PATCH[_BUILD]" ...
-        #     ...
-        # We only care about the major and minor parts though.
-
         lines = version_info.splitlines()
         for line in lines:
-            match = _RE_JAVA_VERSION_LINE.search(line)
-            short_match = _RE_JAVA_SHORT_VERSION.search(line)
-            if match:
-                return int(match["major"]), int(match["minor"])
-            elif short_match:
-                return int(short_match["major"]), 0
+            match = _RE_JAVA_VERSION_LINE_PRE223.search(line)
+            if match is None:
+                match = _RE_JAVA_VERSION_LINE_223.search(line)
+            if match is None:
+                continue
+            major = int(match["major"])
+            minor = 0
+            if minor_str := match["minor"]:
+                minor = int(minor_str)
+
+            return major, minor
 
         raise RuntimeError(f"The output of `{self._java_exc} -version` was unexpected.")
 


Test patch: