From 1452a449a7d68d2b863a68c11df47ecd18b8eefd Mon Sep 17 00:00:00 2001 From: Nathan Glenn Date: Thu, 15 Aug 2024 14:28:19 -0500 Subject: [PATCH] Generate version/datetime string at build-time Since we can now release several jar versions a day, it's useful to have the version number update automatically. We place the version string in a file, add the file to the resources, and then load the resource file when the `AboutVersionPanel` is loaded. --- build.gradle.kts | 116 +++++++++++------- readme.md | 3 +- .../visualsoar/dialogs/AboutVersionPanel.java | 29 ++++- 3 files changed, 105 insertions(+), 43 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 5e6d809..4467d48 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,24 +1,28 @@ +import java.text.SimpleDateFormat import java.time.LocalDate +import java.util.* + +version = "4.6.22" plugins { - java - application + java + application } repositories { - // Use Maven Central for resolving dependencies. - mavenCentral() + // Use Maven Central for resolving dependencies. + mavenCentral() } dependencies { - testImplementation(libs.junit.jupiter) - testImplementation("org.mockito:mockito-core:5.12.0") - - testRuntimeOnly("org.junit.platform:junit-platform-launcher") - // load all the jars in the lib/ folder - implementation(fileTree("lib") { - include("*.jar") - }) + testImplementation(libs.junit.jupiter) + testImplementation("org.mockito:mockito-core:5.12.0") + + testRuntimeOnly("org.junit.platform:junit-platform-launcher") + // load all the jars in the lib/ folder + implementation(fileTree("lib") { + include("*.jar") + }) } // For loading the SML JNI library @@ -27,34 +31,34 @@ tasks.withType { } java { - toolchain { - languageVersion = JavaLanguageVersion.of(11) - } - sourceCompatibility = JavaVersion.VERSION_11 - targetCompatibility = JavaVersion.VERSION_11 + toolchain { + languageVersion = JavaLanguageVersion.of(11) + } + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 } tasks.withType { - options.encoding = "UTF-8" + options.encoding = "UTF-8" } // make an executable jar that will depend on other jars being available in the classpath tasks.jar { - manifest { - attributes( - mapOf( - "Title" to "${project.name} ${project.version}", - "Vendor" to "University of Michigan", - "Date" to LocalDate.now().toString(), - "Version" to "${project.version}", - "Copyright" to "(c) The Regents of the University of Michigan, 2024", - "Main-Class" to application.mainClass.get(), - "Class-Path" to ". java/sml.jar bin/java/sml.jar lib/sml.jar" - ) - ) - } - from(sourceSets.main.get().output) - dependsOn(configurations.runtimeClasspath) + manifest { + attributes( + mapOf( + "Title" to "${project.name} ${project.version}", + "Vendor" to "University of Michigan", + "Date" to LocalDate.now().toString(), + "Version" to "${project.version}", + "Copyright" to "(c) The Regents of the University of Michigan, 2024", + "Main-Class" to application.mainClass.get(), + "Class-Path" to ". java/sml.jar bin/java/sml.jar lib/sml.jar" + ) + ) + } + from(sourceSets.main.get().output) + dependsOn(configurations.runtimeClasspath) // Do not include runtime dependencies in the jar (we want a slim jar, not a fat one): // from({ // configurations.runtimeClasspath.get().filter { it.name.endsWith("jar") }.map { zipTree(it) } @@ -62,19 +66,49 @@ tasks.jar { } tasks.test { - useJUnitPlatform() + useJUnitPlatform() - reports { - junitXml.required.set(true) - junitXml.outputLocation.set(file("${layout.buildDirectory.get()}/reports/test-results")) - } + reports { + junitXml.required.set(true) + junitXml.outputLocation.set(file("${layout.buildDirectory.get()}/reports/test-results")) + } } application { - mainClass = "edu.umich.soar.visualsoar.VisualSoar" + mainClass = "edu.umich.soar.visualsoar.VisualSoar" } tasks.named("test") { - // Use JUnit Platform for unit tests. - useJUnitPlatform() + // Use JUnit Platform for unit tests. + useJUnitPlatform() +} + +///////////////////////////////////////////////////////////////// +// Generate version/datetime string to show in the application // +///////////////////////////////////////////////////////////////// + +val generateVersionFile by tasks.registering { + val dateFormat = SimpleDateFormat("dd MMM yyyy HH:mm:ss 'UTC'") + dateFormat.timeZone = TimeZone.getTimeZone("UTC") + val date = dateFormat.format(Date()) + val versionString = "${project.version} ($date)" + val templateContext = mapOf("versionString" to versionString) + // When versionString changes, the task is out of date + inputs.properties(templateContext) + // without doLast, the file is not consistently generated + doLast { + val versionFile = layout.buildDirectory.file("generated/resources/versionString.txt").get().asFile + versionFile.parentFile.mkdirs() + versionFile.writeText(versionString) + logger.lifecycle("Generating version file at: ${versionFile.absolutePath}") + } +} + +tasks.withType { + dependsOn(generateVersionFile) +} + +// Add the extra resource directory to the main source set +sourceSets.main { + resources.srcDir(layout.buildDirectory.dir("generated/resources")) } diff --git a/readme.md b/readme.md index cd2d8ec..4115e19 100644 --- a/readme.md +++ b/readme.md @@ -15,7 +15,8 @@ The slim jar we distribute with Soar: ./gradlew jar -There is also an Ant script that does the same (we will likely remove it in the future): +There is also an Ant script that does the same; it is outdated, however, and should not be used for distributing. +We will likely remove it in the future: ant build diff --git a/src/main/java/edu/umich/soar/visualsoar/dialogs/AboutVersionPanel.java b/src/main/java/edu/umich/soar/visualsoar/dialogs/AboutVersionPanel.java index fe6b910..54ef4ce 100644 --- a/src/main/java/edu/umich/soar/visualsoar/dialogs/AboutVersionPanel.java +++ b/src/main/java/edu/umich/soar/visualsoar/dialogs/AboutVersionPanel.java @@ -2,6 +2,10 @@ import javax.swing.*; import javax.swing.border.EmptyBorder; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; /** * Panel that displays the Version number of Visual Soar for the 'About' dialog @@ -15,8 +19,10 @@ class AboutVersionPanel extends JPanel { JLabel versionLabel = new JLabel("Visual Soar"); + + String version = loadVersionString(); JLabel versionLabel2 = - new JLabel(" Version 4.6.22 (14 Aug 2024)"); + new JLabel(" " + version); public AboutVersionPanel() { setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); @@ -24,4 +30,25 @@ public AboutVersionPanel() { add(versionLabel); add(versionLabel2); } + + private String loadVersionString() { + // this file is generated at build-time + String resourcePath = "versionString.txt"; + getClass().getClassLoader(); + try (InputStream inputStream = ClassLoader.getSystemResourceAsStream(resourcePath)) { + if (inputStream == null) { + throw new IOException("Could not find resource file 'versionString.txt'"); + } + try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) { + String line = reader.readLine(); + if (line == null) { + throw new IOException("No lines found in version.txt"); + } + return line; + } + } catch (IOException e) { + e.printStackTrace(); + return e.getMessage(); + } + } }