JAL-3989 Changed to using com.google.common.hash for SHA256 sum, for gradle 7 compati...
[jalview.git] / build.gradle
index 8bf9f78..76ccefd 100644 (file)
@@ -12,6 +12,7 @@ import java.security.MessageDigest
 import groovy.transform.ExternalizeMethods
 import groovy.util.XmlParser
 import groovy.xml.XmlUtil
+import groovy.json.JsonBuilder
 import com.vladsch.flexmark.util.ast.Node
 import com.vladsch.flexmark.html.HtmlRenderer
 import com.vladsch.flexmark.parser.Parser
@@ -22,6 +23,9 @@ import com.vladsch.flexmark.ext.gfm.strikethrough.StrikethroughExtension
 import com.vladsch.flexmark.ext.autolink.AutolinkExtension
 import com.vladsch.flexmark.ext.anchorlink.AnchorLinkExtension
 import com.vladsch.flexmark.ext.toc.TocExtension
+import com.google.common.hash.HashCode
+import com.google.common.hash.Hashing
+import com.google.common.io.Files
 
 buildscript {
   repositories {
@@ -42,7 +46,9 @@ plugins {
   id 'com.github.johnrengelman.shadow' version '4.0.3'
   id 'com.install4j.gradle' version '9.0.6'
   id 'com.dorongold.task-tree' version '1.5' // only needed to display task dependency tree with  gradle task1 [task2 ...] taskTree
-  id 'com.palantir.git-version' version '0.12.3'
+  id 'com.palantir.git-version' version '0.13.0' apply false
+//  id 'org.gradle.crypto.checksum' version '1.4.0'
+
 }
 
 repositories {
@@ -96,6 +102,7 @@ def overrideProperties(String propsFileName, boolean output = false) {
 ext {
   jalviewDirAbsolutePath = file(jalviewDir).getAbsolutePath()
   jalviewDirRelativePath = jalviewDir
+  date = new Date()
 
   getdownChannelName = CHANNEL.toLowerCase()
   // default to "default". Currently only has different cosmetics for "develop", "release", "default"
@@ -115,7 +122,7 @@ ext {
   // Import releaseProps from the RELEASE file
   // or a file specified via JALVIEW_RELEASE_FILE if defined
   // Expect jalview.version and target release branch in jalview.release        
-  def releaseProps = new Properties();
+  releaseProps = new Properties();
   def releasePropFile = findProperty("JALVIEW_RELEASE_FILE");
   def defaultReleasePropFile = "${jalviewDirAbsolutePath}/RELEASE";
   try {
@@ -194,6 +201,7 @@ ext {
   getdownFullArchiveDir = null
   getdownTextLines = []
   getdownLaunchJvl = null
+  getdownVersionLaunchJvl = null
   buildDist = true
   buildProperties = null
 
@@ -217,6 +225,8 @@ ext {
   install4jWindowsIconsFile = string("${install4j_images_dir}/${install4j_windows_icons_file}")
   install4jPngIconFile = string("${install4j_images_dir}/${install4j_png_icon_file}")
   install4jBackground = string("${install4j_images_dir}/${install4j_background}")
+  install4jBuildDir = "${install4j_build_dir}/${JAVA_VERSION}"
+  install4jCheckSums = true
   switch (CHANNEL) {
 
     case "BUILD":
@@ -327,6 +337,7 @@ ext {
     getdownArchiveAppBase = file("${jalviewDir}/${getdown_archive_dir}").toURI().toString()
     getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher_local}")
     install4jExtraScheme = "jalviewl"
+    install4jCheckSums = false
     break
 
     default: // something wrong specified
@@ -393,9 +404,21 @@ ext {
   modules_compileClasspath = fileTree(dir: "${jalviewDir}/${j11modDir}", include: ["*.jar"])
   modules_runtimeClasspath = modules_compileClasspath
   */
-  def details = versionDetails()
-  gitHash = details.gitHash
-  gitBranch = details.branchName
+
+  gitHash = "SOURCE"
+  gitBranch = "Source"
+  try {
+    apply plugin: "com.palantir.git-version"
+    def details = versionDetails()
+    gitHash = details.gitHash
+    gitBranch = details.branchName
+  } catch(org.gradle.api.internal.plugins.PluginApplicationException e) {
+    println("Not in a git repository. Using git values from RELEASE properties file.")
+    gitHash = releaseProps.getProperty("git.hash")
+    gitBranch = releaseProps.getProperty("git.branch")
+  } catch(java.lang.RuntimeException e1) {
+    throw new GradleException("Error with git-version plugin.  Directory '.git' exists but versionDetails() cannot be found.")
+  }
 
   println("Using a ${CHANNEL} profile.")
 
@@ -1038,7 +1061,6 @@ cleanTest {
 
 // format is a string like date.format("dd MMMM yyyy")
 def getDate(format) {
-  def date = new Date()
   return date.format(format)
 }
 
@@ -1788,7 +1810,8 @@ task getdownArchiveBuild() {
   def v = "v${JALVIEW_VERSION_UNDERSCORES}"
   def vDir = "${getdownArchiveDir}/${v}"
   getdownFullArchiveDir = "${vDir}/getdown"
-  def vLaunchVersionJvl = "${vDir}/jalview-${v}.jvl"
+  getdownVersionLaunchJvl = "${vDir}/jalview-${v}.jvl"
+
   def vAltDir = "alt_${v}"
   def archiveImagesDir = "${jalviewDir}/${channel_properties_dir}/old/images"
 
@@ -1835,7 +1858,7 @@ task getdownArchiveBuild() {
 
     getdownArchiveTxt.write(getdownArchiveTextLines.join("\n"))
 
-    def vLaunchJvl = file(vLaunchVersionJvl)
+    def vLaunchJvl = file(getdownVersionLaunchJvl)
     vLaunchJvl.getParentFile().mkdirs()
     vLaunchJvl.write("appbase=${getdownFullArchiveAppBase}\n")
     def vLaunchJvlPath = vLaunchJvl.toPath().toAbsolutePath()
@@ -1939,11 +1962,7 @@ task copyInstall4jTemplate {
 
     // turn off checksum creation for LOCAL channel
     def e = install4jConfigXml.application[0]
-    if (CHANNEL == "LOCAL") {
-      e.'@createChecksums' = "false"
-    } else {
-      e.'@createChecksums' = "true"
-    }
+    e.'@createChecksums' = string(install4jCheckSums)
 
     // put file association actions where placeholder action is
     def install4jFileAssociationsText = install4jFileAssociationsFile.text
@@ -1996,12 +2015,24 @@ clean {
   }
 }
 
+task cleanInstallersDataFiles {
+  def installersOutputTxt = file("${jalviewDir}/${install4jBuildDir}/output.txt")
+  def installersSha256 = file("${jalviewDir}/${install4jBuildDir}/sha256sums")
+  def VERSION_UNDERSCORES = JALVIEW_VERSION.replaceAll("\\.", "_")
+  def hugoDataJsonFile = file("${jalviewDir}/${install4jBuildDir}/installers-${VERSION_UNDERSCORES}.json")
+  doFirst {
+    delete installersOutputTxt
+    delete installersSha256
+    delete hugoDataJsonFile
+  }
+}
 
-task installers(type: com.install4j.gradle.Install4jTask) {
+task installerFiles(type: com.install4j.gradle.Install4jTask) {
   group = "distribution"
   description = "Create the install4j installers"
   dependsOn getdown
   dependsOn copyInstall4jTemplate
+  dependsOn cleanInstallersDataFiles
 
   projectFile = install4jConfFile
 
@@ -2016,8 +2047,6 @@ task installers(type: com.install4j.gradle.Install4jTask) {
     filesMd5 = filesMd5.substring(0,8)
   }
   def install4jTemplateVersion = "${JALVIEW_VERSION}_F${filesMd5}_C${gitHash}"
-  // make install4jBuildDir relative to jalviewDir
-  def install4jBuildDir = "${install4j_build_dir}/${JAVA_VERSION}"
 
   variables = [
     'JALVIEW_NAME': jalview_name,
@@ -2110,6 +2139,94 @@ task installers(type: com.install4j.gradle.Install4jTask) {
   outputs.dir("${jalviewDir}/${install4j_build_dir}/${JAVA_VERSION}")
 }
 
+def getDataHash(File myFile) {
+  HashCode hash = Files.asByteSource(myFile).hash(Hashing.sha256())
+  return myFile.exists()
+  ? [
+      "filename" : myFile.getName(),
+      "filesize" : myFile.length(),
+      "sha256" : hash.toString()
+    ]
+  : null
+}
+
+def writeDataJsonFile(File installersOutputTxt, File installersSha256, File hugoDataJsonFile) {
+  if (!installersOutputTxt.exists()) {
+    throw new GradleException("Required input file '${installersOutputTxt.getPath()}' doesn't exist.")
+    return null;
+  }
+  if (install4jCheckSums && (!installersSha256)) {
+    throw new GradleException("Required input file '${installersSha256.getPath()}' doesn't exist.")
+    return null;
+  }
+  def hash = [
+    "channel" : getdownChannelName,
+    "date" : getDate("yyyy-MM-dd HH:mm:ss"),
+    "git-commit" : "${gitHash} [${gitBranch}]",
+    "version" : JALVIEW_VERSION
+  ]
+  def idHash = [:]
+  installersOutputTxt.readLines().each { def line ->
+    if (line.startsWith("#")) {
+      return;
+    }
+    line.replaceAll("\n","")
+    def vals = line.split("\t")
+    def filename = vals[3]
+    def filesize = file(filename).length()
+    filename = filename.replaceAll(/^.*\//, "")
+    hash[vals[0]] = [ "id" : vals[0], "os" : vals[1], "name" : vals[2], "file" : filename, "filesize" : filesize ]
+    idHash."${filename}" = vals[0]
+  }
+  if (install4jCheckSums) {
+    installersSha256.readLines().each { def line ->
+      if (line.startsWith("#")) {
+        return;
+      }
+      line.replaceAll("\n","")
+      def vals = line.split(/\s+\*?/)
+      def filename = vals[1]
+      def innerHash = (hash.(idHash."${filename}"))."sha256" = vals[0]
+    }
+  }
+
+  // executable JAR
+  def jarHash = getDataHash(file(shadowJar.archiveFile))
+  if (jarHash != null) {
+    hash."JAR" = jarHash;
+  }
+
+  // version JVL
+  def jvlHash =getDataHash(file(getdownVersionLaunchJvl))
+  if (jvlHash != null) {
+    hash."JVL" = jvlHash;
+  }
+
+  // source TGZ
+  def tarHash = getDataHash(file(sourceDist.archiveFile))
+  if (tarHash != null) {
+    hash."SOURCE" = tarHash;
+  }
+
+  return hugoDataJsonFile.write(new JsonBuilder(hash).toPrettyString())
+}
+
+task staticMakeInstallersJsonFile {
+  doFirst {
+    def output = findProperty("i4j_output")
+    def sha256 = findProperty("i4j_sha256")
+    def json = findProperty("i4j_json")
+    if (output == null || sha256 == null || json == null) {
+      throw new GradleException("Must provide paths to all of output.txt, sha256sums, and output.json with '-Pi4j_output=... -Pi4j_sha256=... -Pi4j_json=...")
+    }
+    writeDataJsonFile(file(output), file(sha256), file(json))
+  }
+}
+
+task installers {
+  dependsOn installerFiles
+}
+
 
 spotless {
   java {
@@ -2117,6 +2234,22 @@ spotless {
   }
 }
 
+task createSourceReleaseProperties(type: WriteProperties) {
+  group = "distribution"
+  description = "Create the source RELEASE properties file"
+  
+  def sourceTarBuildDir = "${buildDir}/sourceTar"
+  def sourceReleasePropertiesFile = "${sourceTarBuildDir}/RELEASE"
+  outputFile (sourceReleasePropertiesFile)
+
+  doFirst {
+    releaseProps.each{ key, val -> property key, val }
+    property "git.branch", gitBranch
+    property "git.hash", gitHash
+  }
+
+  outputs.file(outputFile)
+}
 
 task sourceDist(type: Tar) {
   group "distribution"
@@ -2124,6 +2257,9 @@ task sourceDist(type: Tar) {
 
   dependsOn createBuildProperties
   dependsOn convertMdFiles
+  dependsOn eclipseAllPreferences
+  dependsOn createSourceReleaseProperties
+
 
   def outputFileName = "${project.name}_${JALVIEW_VERSION_UNDERSCORES}.tar.gz"
   archiveFileName = outputFileName
@@ -2147,6 +2283,7 @@ task sourceDist(type: Tar) {
     "*locales/**",
     "utils/InstallAnywhere",
     "**/*.log",
+    "RELEASE",
   ] 
   def PROCESS_FILES=[
     "AUTHORS",
@@ -2156,7 +2293,6 @@ task sourceDist(type: Tar) {
     "FEATURETODO",
     "LICENSE",
     "**/README",
-    "RELEASE",
     "THIRDPARTYLIBS",
     "TESTNG",
     "build.gradle",
@@ -2171,7 +2307,9 @@ task sourceDist(type: Tar) {
     "**/*.sh",
   ]
   def INCLUDE_FILES=[
-    ".settings/org.eclipse.jdt.core.jalview.prefs",
+    ".classpath",
+    ".settings/org.eclipse.buildship.core.prefs",
+    ".settings/org.eclipse.jdt.core.prefs"
   ]
 
   from(jalviewDir) {
@@ -2218,8 +2356,33 @@ task sourceDist(type: Tar) {
     })
   }
 
+  def sourceTarBuildDir = "${buildDir}/sourceTar"
+  from(sourceTarBuildDir) {
+    // this includes the appended RELEASE properties file
+  }
 }
 
+task makeDataJsonFile {
+  dependsOn installerFiles
+  dependsOn sourceDist
+  dependsOn getdownArchive
+  dependsOn shadowJar
+
+  def installersOutputTxt = file("${jalviewDir}/${install4jBuildDir}/output.txt")
+  def installersSha256 = file("${jalviewDir}/${install4jBuildDir}/sha256sums")
+  def VERSION_UNDERSCORES = JALVIEW_VERSION.replaceAll("\\.", "_")
+  def hugoDataJsonFile = file("${jalviewDir}/${hugo_build_dir}/data/installers-${VERSION_UNDERSCORES}.json")
+
+  inputs.file(installersOutputTxt)
+  if (install4jCheckSums) {
+    inputs.file(installersSha256)
+  }
+  outputs.file(hugoDataJsonFile)
+
+  doFirst {
+    writeDataJsonFile(installersOutputTxt, installersSha256, hugoDataJsonFile)
+  }
+}
 
 task helppages {
   dependsOn copyHelp