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