From 6288c73695fc9e1cd252942b73982e55217708d2 Mon Sep 17 00:00:00 2001 From: "Flavio S. Glock" Date: Fri, 24 Jul 2026 13:33:35 +0200 Subject: [PATCH] fix: regenerate configuration before compilation Always derive Configuration.java from the tracked template in Gradle and Maven builds before injecting Git and timestamp metadata. This prevents existing checkouts from retaining stale version values across releases. Keep the generated source untracked to avoid build-specific hash and timestamp churn. Generated with [Codex](https://openai.com/codex/) Co-Authored-By: Codex --- .gitignore | 4 +- build.gradle | 37 ++++++----- pom.xml | 27 ++++---- scripts/inject-git-info.ps1 | 61 +++++++++---------- .../org/perlonjava/core/Configuration.java.in | 2 +- 5 files changed, 65 insertions(+), 66 deletions(-) diff --git a/.gitignore b/.gitignore index c0e9df34b..e6968023c 100644 --- a/.gitignore +++ b/.gitignore @@ -119,8 +119,8 @@ test-*.html # Configuration.java is auto-generated at build time from Configuration.java.in. # It is NOT tracked by git to avoid constant rebase conflicts on the injected -# git hash / date / build timestamp. The build (Gradle / Maven) recreates it -# automatically from the template on a fresh clone. +# git hash / date / build timestamp. The build (Gradle / Maven) regenerates it +# from the template before compilation. # To capture a specific build's version info: git add -f /Configuration.java src/main/java/org/perlonjava/core/Configuration.java diff --git a/build.gradle b/build.gradle index 42d4b352d..2d7277553 100644 --- a/build.gradle +++ b/build.gradle @@ -92,32 +92,31 @@ cyclonedxBom { // // Configuration.java is NOT tracked by git (it is listed in .gitignore). // The canonical template is Configuration.java.in, which is tracked and contains -// placeholder values. This task copies the template to Configuration.java when -// the file is absent (e.g. after a fresh clone) and then patches in the real -// git hash, commit date, and build timestamp. +// placeholder values. Always regenerate from that template so version and other +// configuration changes cannot leave a stale generated source in an existing +// checkout, then patch in the real git hash, commit date, and build timestamp. def configFilePath = layout.projectDirectory.file('src/main/java/org/perlonjava/core/Configuration.java') def configTemplPath = layout.projectDirectory.file('src/main/java/org/perlonjava/core/Configuration.java.in') tasks.register('injectGitInfo') { - description = 'Copies Configuration.java.in → Configuration.java (if needed) and injects git info' + description = 'Regenerates Configuration.java from its template and injects build metadata' group = 'build' - // Declare inputs/outputs for configuration cache compatibility def configFile = configFilePath.asFile def templateFile = configTemplPath.asFile + + inputs.file(configTemplPath) + outputs.file(configFilePath) + // The build timestamp and current git revision are dynamic inputs. + outputs.upToDateWhen { false } doLast { - // If Configuration.java is absent (fresh clone, gitignored), recreate it - // from the committed template so the compiler has a valid source file. - if (!configFile.exists()) { - if (templateFile.exists()) { - configFile.text = templateFile.text - logger.lifecycle("Created Configuration.java from template") - } else { - logger.warn("Neither Configuration.java nor Configuration.java.in found; skipping git info injection") - return - } + if (!templateFile.exists()) { + throw new GradleException("Configuration template not found: ${templateFile}") } + + // Never carry configuration values forward from a previous build. + def content = templateFile.text // Get git commit info using Runtime.exec def gitCommitId = 'dev' @@ -141,8 +140,6 @@ tasks.register('injectGitInfo') { // Only update if we got valid values if (gitCommitId && gitCommitId != 'dev') { - def content = configFile.text - // Use safe pattern matching for quoted string values content = content.replaceAll( /(gitCommitId\s*=\s*)"[^"]*"/, @@ -162,10 +159,10 @@ tasks.register('injectGitInfo') { /(buildTimestamp\s*=\s*)"[^"]*"/, "\$1\"${buildTimestamp}\"" ) - - configFile.text = content - logger.lifecycle("Injected git info: ${gitCommitId} (${gitCommitDate})") } + + configFile.text = content + logger.lifecycle("Regenerated Configuration.java and injected git info: ${gitCommitId} (${gitCommitDate})") } } diff --git a/pom.xml b/pom.xml index a8aa3c4da..322704852 100644 --- a/pom.xml +++ b/pom.xml @@ -365,22 +365,25 @@ -c &2 + exit 1 fi -if [ -f "$CONFIG_FILE" ]; then - GIT_COMMIT_ID=$(git rev-parse --short HEAD 2>/dev/null || echo "dev") - GIT_COMMIT_DATE=$(git log -1 --format=%cs HEAD 2>/dev/null || echo "unknown") - if [ "$GIT_COMMIT_ID" != "dev" ]; then - perl -i -pe "s/(gitCommitId\\s*=\\s*)\"[^\"]*\"/\$1\"$GIT_COMMIT_ID\"/" "$CONFIG_FILE" - perl -i -pe "s/(gitCommitDate\\s*=\\s*)\"[^\"]*\"/\$1\"$GIT_COMMIT_DATE\"/" "$CONFIG_FILE" - echo "Injected git info: $GIT_COMMIT_ID ($GIT_COMMIT_DATE)" - fi +cp "$TEMPLATE_FILE" "$CONFIG_FILE" +GIT_COMMIT_ID=$(git rev-parse --short HEAD 2>/dev/null || echo "dev") +GIT_COMMIT_DATE=$(git log -1 --format=%cs HEAD 2>/dev/null || echo "unknown") +BUILD_TIMESTAMP=$(LC_ALL=C date "+%b %e %Y %H:%M:%S") +if [ "$GIT_COMMIT_ID" != "dev" ]; then + perl -i -pe "s/(gitCommitId\\s*=\\s*)\"[^\"]*\"/\$1\"$GIT_COMMIT_ID\"/" "$CONFIG_FILE" + perl -i -pe "s/(gitCommitDate\\s*=\\s*)\"[^\"]*\"/\$1\"$GIT_COMMIT_DATE\"/" "$CONFIG_FILE" + perl -i -pe "s/(buildTimestamp\\s*=\\s*)\"[^\"]*\"/\$1\"$BUILD_TIMESTAMP\"/" "$CONFIG_FILE" fi +echo "Regenerated Configuration.java and injected git info: $GIT_COMMIT_ID ($GIT_COMMIT_DATE)" ]]> diff --git a/scripts/inject-git-info.ps1 b/scripts/inject-git-info.ps1 index 36806dbc9..2594a536c 100644 --- a/scripts/inject-git-info.ps1 +++ b/scripts/inject-git-info.ps1 @@ -1,40 +1,39 @@ # inject-git-info.ps1 -# Injects git commit ID and date into Configuration.java for Windows builds. -# Configuration.java is gitignored; this script recreates it from -# Configuration.java.in when the file is absent (e.g. after a fresh clone). +# Regenerates Configuration.java and injects build metadata for Windows builds. +# Configuration.java is gitignored; always recreate it from the tracked template +# so an existing checkout cannot retain stale version or configuration values. $ConfigFile = "src/main/java/org/perlonjava/core/Configuration.java" $TemplateFile = "src/main/java/org/perlonjava/core/Configuration.java.in" -# Recreate from template if absent (fresh clone / gitignored) -if (-not (Test-Path $ConfigFile)) { - if (Test-Path $TemplateFile) { - Copy-Item $TemplateFile $ConfigFile - Write-Host "Created Configuration.java from template" - } else { - Write-Host "Neither Configuration.java nor Configuration.java.in found; skipping" - exit 0 - } +if (-not (Test-Path $TemplateFile)) { + Write-Error "Configuration template not found: $TemplateFile" + exit 1 } -if (Test-Path $ConfigFile) { - try { - $GitCommitId = git rev-parse --short HEAD 2>$null - $GitCommitDate = git log -1 --format=%cs HEAD 2>$null - - if ($GitCommitId -and $GitCommitId -ne "dev") { - $content = Get-Content $ConfigFile -Raw - - # Replace gitCommitId value - $content = $content -replace '(gitCommitId\s*=\s*)"[^"]*"', ('$1"' + $GitCommitId + '"') - - # Replace gitCommitDate value - $content = $content -replace '(gitCommitDate\s*=\s*)"[^"]*"', ('$1"' + $GitCommitDate + '"') - - Set-Content $ConfigFile -Value $content -NoNewline - Write-Host "Injected git info: $GitCommitId ($GitCommitDate)" - } - } catch { - Write-Host "Git info injection skipped: $_" +Copy-Item $TemplateFile $ConfigFile -Force -ErrorAction Stop + +try { + $GitCommitId = git rev-parse --short HEAD 2>$null + $GitCommitDate = git log -1 --format=%cs HEAD 2>$null + + if ($GitCommitId -and $GitCommitId -ne "dev") { + $BuildTimestamp = (Get-Date).ToString( + "MMM dd yyyy HH:mm:ss", + [System.Globalization.CultureInfo]::InvariantCulture + ) -replace '^(\w{3}) 0', '$1 ' + $content = Get-Content $ConfigFile -Raw + + $content = $content -replace '(gitCommitId\s*=\s*)"[^"]*"', ('$1"' + $GitCommitId + '"') + $content = $content -replace '(gitCommitDate\s*=\s*)"[^"]*"', ('$1"' + $GitCommitDate + '"') + $content = $content -replace '(buildTimestamp\s*=\s*)"[^"]*"', ('$1"' + $BuildTimestamp + '"') + + Set-Content $ConfigFile -Value $content -NoNewline } +} catch { + $GitCommitId = "dev" + $GitCommitDate = "unknown" + Write-Host "Git info injection skipped: $_" } + +Write-Host "Regenerated Configuration.java and injected git info: $GitCommitId ($GitCommitDate)" diff --git a/src/main/java/org/perlonjava/core/Configuration.java.in b/src/main/java/org/perlonjava/core/Configuration.java.in index 2621763ee..58ec4ef16 100644 --- a/src/main/java/org/perlonjava/core/Configuration.java.in +++ b/src/main/java/org/perlonjava/core/Configuration.java.in @@ -51,7 +51,7 @@ public final class Configuration { /** * Build timestamp in Perl 5 "Compiled at" format (e.g., "Apr 7 2026 11:20:00"). - * Automatically populated by Gradle during build. + * Automatically populated by Gradle/Maven during build. * Parsed by App::perlbrew and other tools via: perl -V | grep "Compiled at" * DO NOT EDIT MANUALLY - this value is replaced at build time. */