diff --git a/buildSrc/src/main/groovy/tanzawa.java-conventions.gradle b/buildSrc/src/main/groovy/tanzawa.java-conventions.gradle index 05d4e0f..0c3bc14 100644 --- a/buildSrc/src/main/groovy/tanzawa.java-conventions.gradle +++ b/buildSrc/src/main/groovy/tanzawa.java-conventions.gradle @@ -65,6 +65,7 @@ jar { manifest.attributes ( 'Build-Timestamp': buildTimestamp, 'Build-Revision' : buildRevision, + 'Build-Version' : version, 'Created-By' : createdBy, 'Build-Jdk' : buildJdk, 'Build-OS' : buildOs, @@ -98,6 +99,7 @@ task writeVersion(type: WriteProperties) { properties ( 'Build-Timestamp': buildTimestamp, 'Build-Revision' : buildRevision, + 'Build-Version' : version, 'Created-By' : createdBy, 'Build-Jdk' : buildJdk, 'Build-OS' : buildOs, diff --git a/buildSrc/src/main/resources/checkstyle-suppressions.xml b/buildSrc/src/main/resources/checkstyle-suppressions.xml index 6cf1d2f..aa32995 100755 --- a/buildSrc/src/main/resources/checkstyle-suppressions.xml +++ b/buildSrc/src/main/resources/checkstyle-suppressions.xml @@ -4,4 +4,5 @@ + diff --git a/modules/cli/src/main/java/com/tsurugidb/console/cli/Main.java b/modules/cli/src/main/java/com/tsurugidb/console/cli/Main.java index 1edb6c8..1b29285 100644 --- a/modules/cli/src/main/java/com/tsurugidb/console/cli/Main.java +++ b/modules/cli/src/main/java/com/tsurugidb/console/cli/Main.java @@ -1,9 +1,11 @@ package com.tsurugidb.console.cli; import java.io.Closeable; +import java.io.IOException; import java.io.StringReader; import java.nio.file.Files; +import org.jline.utils.Log; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -24,6 +26,8 @@ import com.tsurugidb.console.cli.repl.jline.ReplJLineReader; import com.tsurugidb.console.cli.repl.jline.ReplJLineTerminal; import com.tsurugidb.console.core.ScriptRunner; +import com.tsurugidb.console.core.util.TanzawaVersion; +import com.tsurugidb.tsubakuro.util.TsubakuroVersion; /** * A program entry of Tsurugi SQL console cli. @@ -60,10 +64,17 @@ public static int execute(String... args) throws Exception { try (Closeable c0 = () -> ReplJLineTerminal.close()) { commander.parse(args); + if (argument.isVersion()) { + printVersion(); + // return + } if (argument.isHelp()) { commander.usage(); return 0; } + if (argument.isVersion()) { + return 0; + } switch (argument.getCliMode()) { case CONSOLE: @@ -104,6 +115,41 @@ public static int execute(String... args) throws Exception { } } + private static void printVersion() { + String core = TanzawaVersion.MODULE_CORE; + String tgsqlVersion = getVersion("tgsqlVersion", () -> TanzawaVersion.getBuildVersion(core)); + System.out.println("-------------------------------------"); + System.out.printf("Tsurugi SQL console %s%n", tgsqlVersion); + System.out.println("-------------------------------------"); + + System.out.println(); + String tgsqlTimestamp = getVersion("tgsqlTimestamp", () -> TanzawaVersion.getBuildTimestamp(core)); + System.out.printf("Build time: %s%n", tgsqlTimestamp); + String tgsqlRevision = getVersion("tgsqlRevision", () -> TanzawaVersion.getBuildRevision(core)); + System.out.printf("Revision: %s%n", tgsqlRevision); + + System.out.println(); + String tsubakuroVersion = getVersion("tsubakuroVersion", () -> TsubakuroVersion.getBuildVersion("session")); + System.out.printf("Tsubakuro: %s%n", tsubakuroVersion); + String jvmVersion = getVersion("jvmVersion", () -> System.getProperty("java.vm.version")); + String javaHome = getVersion("javaHome", () -> System.getProperty("java.home")); + System.out.printf("JVM: %s (%s)%n", jvmVersion, javaHome); + } + + @FunctionalInterface + private interface StringSupplier { + String get() throws IOException; + } + + private static String getVersion(String title, StringSupplier supplier) { + try { + return supplier.get(); + } catch (Exception e) { + Log.debug(title + " get error", e); + return "unknown"; + } + } + private static void executeConsole(JCommander commander, CliArgument argument) throws Exception { ReplCvKey.registerKey(); diff --git a/modules/cli/src/main/java/com/tsurugidb/console/cli/argument/CliArgument.java b/modules/cli/src/main/java/com/tsurugidb/console/cli/argument/CliArgument.java index 00276bb..2742996 100755 --- a/modules/cli/src/main/java/com/tsurugidb/console/cli/argument/CliArgument.java +++ b/modules/cli/src/main/java/com/tsurugidb/console/cli/argument/CliArgument.java @@ -37,6 +37,9 @@ public class CliArgument { @Parameter(names = { "--help", "-h" }, arity = 0, description = "print this message", help = true) private Boolean help; + @Parameter(names = { "--version" }, arity = 0, description = "print version", help = true) + private Boolean version; + @Parameter(names = { "--console" }, arity = 0, description = "SQL console mode") private Boolean console; @@ -227,6 +230,15 @@ public boolean isHelp() { return (this.help != null) && this.help; } + /** + * get --version. + * + * @return version + */ + public boolean isVersion() { + return (this.version != null) && this.version; + } + /** * get cli mode. * diff --git a/modules/core/src/main/java/com/tsurugidb/console/core/util/TanzawaVersion.java b/modules/core/src/main/java/com/tsurugidb/console/core/util/TanzawaVersion.java new file mode 100755 index 0000000..6186d5d --- /dev/null +++ b/modules/core/src/main/java/com/tsurugidb/console/core/util/TanzawaVersion.java @@ -0,0 +1,111 @@ +package com.tsurugidb.console.core.util; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.UncheckedIOException; +import java.text.MessageFormat; +import java.util.Map; +import java.util.Properties; +import java.util.concurrent.ConcurrentHashMap; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.tsurugidb.tsubakuro.util.TsubakuroVersion; + +/** + * Class to get the version of Tanzawa. + */ +public final class TanzawaVersion { + static final Logger LOG = LoggerFactory.getLogger(TanzawaVersion.class); + + /** core */ + public static final String MODULE_CORE = "core"; //$NON-NLS-1$ + + private static final String PATH_VERSION_DIR = "/META-INF/tsurugidb/"; //$NON-NLS-1$ + private static final String MODULE_PREFIX = "tanzawa-"; //$NON-NLS-1$ + private static final String VERSION_FILE_SUFFIX = ".properties"; //$NON-NLS-1$ + + private static final String ATTRIBUTE_BUILD_TIMESTAMP = "Build-Timestamp"; //$NON-NLS-1$ + private static final String ATTRIBUTE_BUILD_REVISION = "Build-Revision"; //$NON-NLS-1$ + private static final String ATTRIBUTE_BUILD_VERSION = "Build-Version"; //$NON-NLS-1$ + + private static final Map PROPERTIES_MAP = new ConcurrentHashMap<>(); + + private TanzawaVersion() { + } + + /** + * Get Build-Timestamp. + * + * @param moduleName module name + * @return Build-Timestamp + * @throws IOException if an I/O error occurs loading from the version file + */ + public static String getBuildTimestamp(String moduleName) throws IOException { + var properties = getProperties(moduleName); + return properties.getProperty(ATTRIBUTE_BUILD_TIMESTAMP); + } + + /** + * Get Build-Revision. + * + * @param moduleName module name + * @return Build-Revision + * @throws IOException if an I/O error occurs loading from the version file + */ + public static String getBuildRevision(String moduleName) throws IOException { + var properties = getProperties(moduleName); + return properties.getProperty(ATTRIBUTE_BUILD_REVISION); + } + + /** + * Get Build-Version. + * + * @param moduleName module name + * @return Build-Version + * @throws IOException if an I/O error occurs loading from the version file + */ + public static String getBuildVersion(String moduleName) throws IOException { + var properties = getProperties(moduleName); + return properties.getProperty(ATTRIBUTE_BUILD_VERSION); + } + + /** + * Get version properties. + * + * @param moduleName module name + * @return version properties + * @throws IOException if an I/O error occurs loading from the version file + */ + public static Properties getProperties(String moduleName) throws IOException { + try { + return PROPERTIES_MAP.computeIfAbsent(moduleName, key -> { + String module = MODULE_PREFIX + key; + try { + return loadProperties(module); + } catch (Exception e) { + LOG.debug("version file load error. module={}", module, e); // $NON-NLS-1$ + throw new UncheckedIOException(new IOException(MessageFormat.format("version file load error. module={0}", module), e)); + } + }); + } catch (UncheckedIOException e) { + throw e.getCause(); + } + } + + private static Properties loadProperties(String module) throws IOException { + String path = PATH_VERSION_DIR + module + VERSION_FILE_SUFFIX; + LOG.trace("searching for version file: {}", path); // $NON-NLS-1$ + var versionFile = TsubakuroVersion.class.getResource(path); + if (versionFile == null) { + throw new FileNotFoundException(MessageFormat.format("missing version file. path={0}", path)); + } + LOG.debug("loading version file: {}", versionFile); // $NON-NLS-1$ + try (var input = versionFile.openStream()) { + var properties = new Properties(); + properties.load(input); + return properties; + } + } +} diff --git a/modules/core/src/main/java/com/tsurugidb/console/core/util/package-info.java b/modules/core/src/main/java/com/tsurugidb/console/core/util/package-info.java new file mode 100755 index 0000000..d574a68 --- /dev/null +++ b/modules/core/src/main/java/com/tsurugidb/console/core/util/package-info.java @@ -0,0 +1,4 @@ +/** + * Utility classes for Tsurugi SQL console. + */ +package com.tsurugidb.console.core.util; \ No newline at end of file diff --git a/modules/core/src/test/java/com/tsurugidb/console/core/util/TanzawaVersionTest.java b/modules/core/src/test/java/com/tsurugidb/console/core/util/TanzawaVersionTest.java new file mode 100755 index 0000000..c56a531 --- /dev/null +++ b/modules/core/src/test/java/com/tsurugidb/console/core/util/TanzawaVersionTest.java @@ -0,0 +1,40 @@ +package com.tsurugidb.console.core.util; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.io.FileNotFoundException; +import java.io.IOException; + +import org.junit.jupiter.api.Test; + +class TanzawaVersionTest { + + @Test + void getBuildTimestamp() throws IOException { + String version = TanzawaVersion.getBuildTimestamp("version-test"); + assertEquals("2023-10-24T12:52:36.203+0900", version); + } + + @Test + void getBuildRevision() throws IOException { + String version = TanzawaVersion.getBuildRevision("version-test"); + assertEquals("abcdefg", version); + } + + @Test + void getBuildVersion() throws IOException { + String version = TanzawaVersion.getBuildVersion("version-test"); + assertEquals("1.0.0-TEST", version); + } + + @Test + void notFoundVersionFile() { + var e = assertThrows(IOException.class, () -> { + TanzawaVersion.getProperties("not-found"); + }); + assertEquals("version file load error. module=tanzawa-not-found", e.getMessage()); + var c = (FileNotFoundException) e.getCause(); + assertEquals("missing version file. path=/META-INF/tsurugidb/tanzawa-not-found.properties", c.getMessage()); + } +} diff --git a/modules/core/src/test/resources/META-INF/tsurugidb/tanzawa-version-test.properties b/modules/core/src/test/resources/META-INF/tsurugidb/tanzawa-version-test.properties new file mode 100755 index 0000000..d148004 --- /dev/null +++ b/modules/core/src/test/resources/META-INF/tsurugidb/tanzawa-version-test.properties @@ -0,0 +1,6 @@ +Build-Jdk=11.0.14.1+1 Eclipse Temurin 11.0.14.1+1 +Build-OS=Windows 10 amd64 10.0 +Build-Revision=abcdefg +Build-Timestamp=2023-10-24T12\:52\:36.203+0900 +Build-Version=1.0.0-TEST +Created-By=Gradle 8.3