Fix alignment and score calculation for cc_analysis
[jalview.git] / build.gradle
index 958343b..9161ed2 100644 (file)
@@ -45,10 +45,10 @@ plugins {
   id 'java'
   id 'application'
   id 'eclipse'
-  id "com.diffplug.gradle.spotless" version "3.28.0"
-  id 'com.github.johnrengelman.shadow' version '4.0.3'
+  id "com.diffplug.spotless" version "6.18.0" //.gradle.spotless" "3.28.0"
+  id 'com.github.johnrengelman.shadow' version '8.1.1' // was 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.dorongold.task-tree' version '2.1.0' // only needed to display task dependency tree with  gradle task1 [task2 ...] taskTree
   id 'com.palantir.git-version' version '0.13.0' apply false
 }
 
@@ -138,6 +138,7 @@ ext {
   if (findProperty("JALVIEW_VERSION")==null || "".equals(JALVIEW_VERSION)) {
     JALVIEW_VERSION = releaseProps.get("jalview.version")
   }
+  println("JALVIEW_VERSION is set to '${JALVIEW_VERSION}'")
   
   // this property set when running Eclipse headlessly
   j2sHeadlessBuildProperty = string("net.sf.j2s.core.headlessbuild")
@@ -182,6 +183,7 @@ ext {
   testDir = string("${jalviewDir}/${bareTestSourceDir}")
 
   classesDir = string("${jalviewDir}/${classes_dir}")
+  destinationDirectory = file(classesDir)
 
   // clover
   useClover = clover.equals("true")
@@ -546,14 +548,14 @@ sourceSets {
   main {
     java {
       srcDirs sourceDir
-      outputDir = file(classesDir)
+      destinationDirectory = file(classesDir)
     }
 
     resources {
       srcDirs = [ resourcesBuildDir, docBuildDir, helpBuildDir ]
     }
 
-    compileClasspath = files(sourceSets.main.java.outputDir)
+    compileClasspath = files(sourceSets.main.java.destinationDirectory)
     compileClasspath += fileTree(dir: "${jalviewDir}/${libDir}", include: ["*.jar"])
 
     runtimeClasspath = compileClasspath
@@ -563,14 +565,14 @@ sourceSets {
   clover {
     java {
       srcDirs cloverInstrDir
-      outputDir = cloverClassesDir
+      destinationDirectory = cloverClassesDir
     }
 
     resources {
       srcDirs = sourceSets.main.resources.srcDirs
     }
 
-    compileClasspath = files( sourceSets.clover.java.outputDir )
+    compileClasspath = files( sourceSets.clover.java.destinationDirectory )
     //compileClasspath += files( testClassesDir )
     compileClasspath += fileTree(dir: "${jalviewDir}/${libDir}", include: ["*.jar"])
     compileClasspath += fileTree(dir: "${jalviewDir}/${clover_lib_dir}", include: ["*.jar"])
@@ -582,14 +584,14 @@ sourceSets {
   test {
     java {
       srcDirs testSourceDir
-      outputDir = file(testClassesDir)
+      destinationDirectory = file(testClassesDir)
     }
 
     resources {
       srcDirs = useClover ? sourceSets.clover.resources.srcDirs : sourceSets.main.resources.srcDirs
     }
 
-    compileClasspath = files( sourceSets.test.java.outputDir )
+    compileClasspath = files( sourceSets.test.java.destinationDirectory )
     compileClasspath += useClover ? sourceSets.clover.compileClasspath : sourceSets.main.compileClasspath
     compileClasspath += fileTree(dir: "${jalviewDir}/${utils_dir}/testnglibs", include: ["**/*.jar"])
 
@@ -614,7 +616,7 @@ eclipse {
   }
 
   classpath {
-    //defaultOutputDir = sourceSets.main.java.outputDir
+    //defaultOutputDir = sourceSets.main.java.destinationDirectory
     configurations.each{ c->
       if (c.isCanBeResolved()) {
         minusConfigurations += [c]
@@ -653,7 +655,7 @@ eclipse {
         HashMap<String, Boolean> alreadyAddedLibPath = new HashMap<>();
 
         sourceSets.main.compileClasspath.findAll { it.name.endsWith(".jar") }.any {
-          //don't want to add outputDir as eclipse is using its own output dir in bin/main
+          //don't want to add destinationDirectory as eclipse is using its own output dir in bin/main
           if (it.isDirectory() || ! it.exists()) {
             // don't add dirs to classpath, especially if they don't exist
             return false // groovy "continue" in .any closure
@@ -673,7 +675,7 @@ eclipse {
         }
 
         sourceSets.test.compileClasspath.findAll { it.name.endsWith(".jar") }.any {
-          //no longer want to add outputDir as eclipse is using its own output dir in bin/main
+          //no longer want to add destinationDirectory as eclipse is using its own output dir in bin/main
           if (it.isDirectory() || ! it.exists()) {
             // don't add dirs to classpath
             return false // groovy "continue" in .any closure
@@ -1050,7 +1052,7 @@ compileTestJava {
 
 clean {
   doFirst {
-    delete sourceSets.main.java.outputDir
+    delete sourceSets.main.java.destinationDirectory
   }
 }
 
@@ -1058,7 +1060,7 @@ clean {
 cleanTest {
   dependsOn cleanClover
   doFirst {
-    delete sourceSets.test.java.outputDir
+    delete sourceSets.test.java.destinationDirectory
   }
 }
 
@@ -1150,7 +1152,7 @@ def convertMdToHtml (FileTree mdFiles, File cssFile) {
 
 task copyDocs(type: Copy) {
   def inputDir = "${jalviewDir}/${doc_dir}"
-  def outputDir = "${docBuildDir}/${doc_dir}"
+  def destinationDirectory = "${docBuildDir}/${doc_dir}"
   from(inputDir) {
     include('**/*.txt')
     include('**/*.md')
@@ -1171,10 +1173,10 @@ task copyDocs(type: Copy) {
     exclude('**/*.html')
     exclude('**/*.xml')
   }
-  into outputDir
+  into destinationDirectory
 
   inputs.dir(inputDir)
-  outputs.dir(outputDir)
+  outputs.dir(destinationDirectory)
 }
 
 
@@ -1199,9 +1201,217 @@ task convertMdFiles {
 }
 
 
+def hugoTemplateSubstitutions(String input, Map extras=null) {
+  def replacements = [
+    DATE: getDate("yyyy-MM-dd"),
+    CHANNEL: propertiesChannelName,
+    APPLICATION_NAME: applicationName,
+    GIT_HASH: gitHash,
+    GIT_BRANCH: gitBranch,
+    VERSION: JALVIEW_VERSION,
+    JAVA_VERSION: JAVA_VERSION,
+    VERSION_UNDERSCORES: JALVIEW_VERSION_UNDERSCORES,
+    DRAFT: "false",
+    JVL_HEADER: ""
+  ]
+  def output = input
+  if (extras != null) {
+    extras.each{ k, v ->
+      output = output.replaceAll("__${k}__", ((v == null)?"":v))
+    }
+  }
+  replacements.each{ k, v ->
+    output = output.replaceAll("__${k}__", ((v == null)?"":v))
+  }
+  return output
+}
+
+def mdFileComponents(File mdFile, def dateOnly=false) {
+  def map = [:]
+  def content = ""
+  if (mdFile.exists()) {
+    def inFrontMatter = false
+    def firstLine = true
+    mdFile.eachLine { line ->
+      if (line.matches("---")) {
+        def prev = inFrontMatter
+        inFrontMatter = firstLine
+        if (inFrontMatter != prev)
+          return false
+      }
+      if (inFrontMatter) {
+        def m = null
+        if (m == line =~ /^date:\s*(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})/) {
+          map["date"] = new Date().parse("yyyy-MM-dd HH:mm:ss", m[0][1])
+        } else if (m == line =~ /^date:\s*(\d{4}-\d{2}-\d{2})/) {
+          map["date"] = new Date().parse("yyyy-MM-dd", m[0][1])
+        } else if (m == line =~ /^channel:\s*(\S+)/) {
+          map["channel"] = m[0][1]
+        } else if (m == line =~ /^version:\s*(\S+)/) {
+          map["version"] = m[0][1]
+        } else if (m == line =~ /^\s*([^:]+)\s*:\s*(\S.*)/) {
+          map[ m[0][1] ] = m[0][2]
+        }
+        if (dateOnly && map["date"] != null) {
+          return false
+        }
+      } else {
+        if (dateOnly)
+          return false
+        content += line+"\n"
+      }
+      firstLine = false
+    }
+  }
+  return dateOnly ? map["date"] : [map, content]
+}
+
+task hugoTemplates {
+  group "website"
+  description "Create partially populated md pages for hugo website build"
+
+  def hugoTemplatesDir = file("${jalviewDir}/${hugo_templates_dir}")
+  def hugoBuildDir = "${jalviewDir}/${hugo_build_dir}"
+  def templateFiles = fileTree(dir: hugoTemplatesDir)
+  def releaseMdFile = file("${jalviewDir}/${releases_dir}/release-${JALVIEW_VERSION_UNDERSCORES}.md")
+  def whatsnewMdFile = file("${jalviewDir}/${whatsnew_dir}/whatsnew-${JALVIEW_VERSION_UNDERSCORES}.md")
+  def oldJvlFile = file("${jalviewDir}/${hugo_old_jvl}")
+  def jalviewjsFile = file("${jalviewDir}/${hugo_jalviewjs}")
+
+  doFirst {
+    // specific release template for version archive
+    def changes = ""
+    def whatsnew = null
+    def givenDate = null
+    def givenChannel = null
+    def givenVersion = null
+    if (CHANNEL == "RELEASE") {
+      def (map, content) = mdFileComponents(releaseMdFile)
+      givenDate = map.date
+      givenChannel = map.channel
+      givenVersion = map.version
+      changes = content
+      if (givenVersion != null && givenVersion != JALVIEW_VERSION) {
+        throw new GradleException("'version' header (${givenVersion}) found in ${releaseMdFile} does not match JALVIEW_VERSION (${JALVIEW_VERSION})")
+      }
+
+      if (whatsnewMdFile.exists())
+        whatsnew = whatsnewMdFile.text
+    }
+
+    def oldJvl = oldJvlFile.exists() ? oldJvlFile.collect{it} : []
+    def jalviewjsLink = jalviewjsFile.exists() ? jalviewjsFile.collect{it} : []
+
+    def changesHugo = null
+    if (changes != null) {
+      changesHugo = '<div class="release_notes">\n\n'
+      def inSection = false
+      changes.eachLine { line ->
+        def m = null
+        if (m == line =~ /^##([^#].*)$/) {
+          if (inSection) {
+            changesHugo += "</div>\n\n"
+          }
+          def section = m[0][1].trim()
+          section = section.toLowerCase()
+          section = section.replaceAll(/ +/, "_")
+          section = section.replaceAll(/[^a-z0-9_\-]/, "")
+          changesHugo += "<div class=\"${section}\">\n\n"
+          inSection = true
+        } else if (m == line =~ /^(\s*-\s*)<!--([^>]+)-->(.*?)(<br\/?>)?\s*$/) {
+          def comment = m[0][2].trim()
+          if (comment != "") {
+            comment = comment.replaceAll('"', "&quot;")
+            def issuekeys = []
+            comment.eachMatch(/JAL-\d+/) { jal -> issuekeys += jal }
+            def newline = m[0][1]
+            if (comment.trim() != "")
+              newline += "{{<comment>}}${comment}{{</comment>}}  "
+            newline += m[0][3].trim()
+            if (issuekeys.size() > 0)
+              newline += "  {{< jal issue=\"${issuekeys.join(",")}\" alt=\"${comment}\" >}}"
+            if (m[0][4] != null)
+              newline += m[0][4]
+            line = newline
+          }
+        }
+        changesHugo += line+"\n"
+      }
+      if (inSection) {
+        changesHugo += "\n</div>\n\n"
+      }
+      changesHugo += '</div>'
+    }
+
+    templateFiles.each{ templateFile ->
+      def newFileName = string(hugoTemplateSubstitutions(templateFile.getName()))
+      def relPath = hugoTemplatesDir.toPath().relativize(templateFile.toPath()).getParent()
+      def newRelPathName = hugoTemplateSubstitutions( relPath.toString() )
+
+      def outPathName = string("${hugoBuildDir}/$newRelPathName")
+
+      copy {
+        from templateFile
+        rename(templateFile.getName(), newFileName)
+        into outPathName
+      }
+
+      def newFile = file("${outPathName}/${newFileName}".toString())
+      def content = newFile.text
+      newFile.text = hugoTemplateSubstitutions(content,
+        [
+          WHATSNEW: whatsnew,
+          CHANGES: changesHugo,
+          DATE: givenDate == null ? "" : givenDate.format("yyyy-MM-dd"),
+          DRAFT: givenDate == null ? "true" : "false",
+          JALVIEWJSLINK: jalviewjsLink.contains(JALVIEW_VERSION) ? "true" : "false",
+          JVL_HEADER: oldJvl.contains(JALVIEW_VERSION) ? "jvl: true" : ""
+        ]
+      )
+    }
+
+  }
+
+  inputs.file(oldJvlFile)
+  inputs.dir(hugoTemplatesDir)
+  inputs.property("JALVIEW_VERSION", { JALVIEW_VERSION })
+  inputs.property("CHANNEL", { CHANNEL })
+}
+
+def getMdDate(File mdFile) {
+  return mdFileComponents(mdFile, true)
+}
+
+def getMdSections(String content) {
+  def sections = [:]
+  def sectionContent = ""
+  def sectionName = null
+  content.eachLine { line ->
+    def m = null
+    if (m == line =~ /^##([^#].*)$/) {
+      if (sectionName != null) {
+        sections[sectionName] = sectionContent
+        sectionName = null
+        sectionContent = ""
+      }
+      sectionName = m[0][1].trim()
+      sectionName = sectionName.toLowerCase()
+      sectionName = sectionName.replaceAll(/ +/, "_")
+      sectionName = sectionName.replaceAll(/[^a-z0-9_\-]/, "")
+    } else if (sectionName != null) {
+      sectionContent += line+"\n"
+    }
+  }
+  if (sectionContent != null) {
+    sections[sectionName] = sectionContent
+  }
+  return sections
+}
+
+
 task copyHelp(type: Copy) {
   def inputDir = helpSourceDir
-  def outputDir = "${helpBuildDir}/${help_dir}"
+  def destinationDirectory = "${helpBuildDir}/${help_dir}"
   from(inputDir) {
     include('**/*.txt')
     include('**/*.md')
@@ -1226,66 +1436,206 @@ task copyHelp(type: Copy) {
     exclude('**/*.xml')
     exclude('**/*.jhm')
   }
-  into outputDir
+  into destinationDirectory
 
   inputs.dir(inputDir)
   outputs.files(helpFile)
-  outputs.dir(outputDir)
+  outputs.dir(destinationDirectory)
 }
 
 
-task copyResources(type: Copy) {
-  group = "build"
-  description = "Copy (and make text substitutions in) the resources dir to the build area"
+/*
+task releasesTemplates {
+  group "help"
+  description "Recreate whatsNew.html and releases.html from markdown files and templates in help"
 
-  def inputDir = resourceDir
-  def outputDir = resourcesBuildDir
-  from(inputDir) {
-    include('**/*.txt')
-    include('**/*.md')
-    include('**/*.html')
-    include('**/*.xml')
-    filter(ReplaceTokens,
-      beginToken: '$$',
-      endToken: '$$',
-      tokens: [
-        'Version-Rel': JALVIEW_VERSION,
-        'Year-Rel': getDate("yyyy")
-      ]
-    )
-  }
-  from(inputDir) {
-    exclude('**/*.txt')
-    exclude('**/*.md')
-    exclude('**/*.html')
-    exclude('**/*.xml')
-  }
-  into outputDir
+  dependsOn copyHelp
 
-  inputs.dir(inputDir)
-  outputs.dir(outputDir)
-}
+  def releasesTemplateFile = file("${jalviewDir}/${releases_template}")
+  def whatsnewTemplateFile = file("${jalviewDir}/${whatsnew_template}")
+  def releasesHtmlFile = file("${helpBuildDir}/${help_dir}/${releases_html}")
+  def whatsnewHtmlFile = file("${helpBuildDir}/${help_dir}/${whatsnew_html}")
+  def releasesMdDir = "${jalviewDir}/${releases_dir}"
+  def whatsnewMdDir = "${jalviewDir}/${whatsnew_dir}"
 
-task copyChannelResources(type: Copy) {
-  dependsOn copyResources
-  group = "build"
-  description = "Copy the channel resources dir to the build resources area"
+  doFirst {
+    def releaseMdFile = file("${releasesMdDir}/release-${JALVIEW_VERSION_UNDERSCORES}.md")
+    def whatsnewMdFile = file("${whatsnewMdDir}/whatsnew-${JALVIEW_VERSION_UNDERSCORES}.md")
 
-  def inputDir = "${channelDir}/${resource_dir}"
-  def outputDir = resourcesBuildDir
-  from inputDir
-  into outputDir
+    if (CHANNEL == "RELEASE") {
+      if (!releaseMdFile.exists()) {
+        throw new GradleException("File ${releaseMdFile} must be created for RELEASE")
+      }
+      if (!whatsnewMdFile.exists()) {
+        throw new GradleException("File ${whatsnewMdFile} must be created for RELEASE")
+      }
+    }
 
-  inputs.dir(inputDir)
-  outputs.dir(outputDir)
-}
+    def releaseFiles = fileTree(dir: releasesMdDir, include: "release-*.md")
+    def releaseFilesDates = releaseFiles.collectEntries {
+      [(it): getMdDate(it)]
+    }
+    releaseFiles = releaseFiles.sort { a,b -> releaseFilesDates[a].compareTo(releaseFilesDates[b]) }
 
-task createBuildProperties(type: WriteProperties) {
-  dependsOn copyResources
-  group = "build"
-  description = "Create the ${buildProperties} file"
-  
-  inputs.dir(sourceDir)
+    def releasesTemplate = releasesTemplateFile.text
+    def m = releasesTemplate =~ /(?s)__VERSION_LOOP_START__(.*)__VERSION_LOOP_END__/
+    def versionTemplate = m[0][1]
+
+    MutableDataSet options = new MutableDataSet()
+
+    def extensions = new ArrayList<>()
+    options.set(Parser.EXTENSIONS, extensions)
+    options.set(Parser.HTML_BLOCK_COMMENT_ONLY_FULL_LINE, true)
+
+    Parser parser = Parser.builder(options).build()
+    HtmlRenderer renderer = HtmlRenderer.builder(options).build()
+
+    def actualVersions = releaseFiles.collect { rf ->
+      def (rfMap, rfContent) = mdFileComponents(rf)
+      return rfMap.version
+    }
+    def versionsHtml = ""
+    def linkedVersions = []
+    releaseFiles.reverse().each { rFile ->
+      def (rMap, rContent) = mdFileComponents(rFile)
+
+      def versionLink = ""
+      def partialVersion = ""
+      def firstPart = true
+      rMap.version.split("\\.").each { part ->
+        def displayPart = ( firstPart ? "" : "." ) + part
+        partialVersion += displayPart
+        if (
+            linkedVersions.contains(partialVersion)
+            || ( actualVersions.contains(partialVersion) && partialVersion != rMap.version )
+            ) {
+          versionLink += displayPart
+        } else {
+          versionLink += "<a id=\"Jalview.${partialVersion}\">${displayPart}</a>"
+          linkedVersions += partialVersion
+        }
+        firstPart = false
+      }
+      def displayDate = releaseFilesDates[rFile].format("dd/MM/yyyy")
+
+      def lm = null
+      def rContentProcessed = ""
+      rContent.eachLine { line ->
+        if (lm == line =~ /^(\s*-)(\s*<!--[^>]*?-->)(.*)$/) {
+          line = "${lm[0][1]}${lm[0][3]}${lm[0][2]}"
+      } else if (lm == line =~ /^###([^#]+.*)$/) {
+          line = "_${lm[0][1].trim()}_"
+        }
+        rContentProcessed += line + "\n"
+      }
+
+      def rContentSections = getMdSections(rContentProcessed)
+      def rVersion = versionTemplate
+      if (rVersion != "") {
+        def rNewFeatures = rContentSections["new_features"]
+        def rIssuesResolved = rContentSections["issues_resolved"]
+        Node newFeaturesNode = parser.parse(rNewFeatures)
+        String newFeaturesHtml = renderer.render(newFeaturesNode)
+        Node issuesResolvedNode = parser.parse(rIssuesResolved)
+        String issuesResolvedHtml = renderer.render(issuesResolvedNode)
+        rVersion = hugoTemplateSubstitutions(rVersion,
+          [
+            VERSION: rMap.version,
+            VERSION_LINK: versionLink,
+            DISPLAY_DATE: displayDate,
+            NEW_FEATURES: newFeaturesHtml,
+            ISSUES_RESOLVED: issuesResolvedHtml
+          ]
+        )
+        versionsHtml += rVersion
+      }
+    }
+
+    releasesTemplate = releasesTemplate.replaceAll("(?s)__VERSION_LOOP_START__.*__VERSION_LOOP_END__", versionsHtml)
+    releasesTemplate = hugoTemplateSubstitutions(releasesTemplate)
+    releasesHtmlFile.text = releasesTemplate
+
+    if (whatsnewMdFile.exists()) {
+      def wnDisplayDate = releaseFilesDates[releaseMdFile] != null ? releaseFilesDates[releaseMdFile].format("dd MMMM yyyy") : ""
+      def whatsnewMd = hugoTemplateSubstitutions(whatsnewMdFile.text)
+      Node whatsnewNode = parser.parse(whatsnewMd)
+      String whatsnewHtml = renderer.render(whatsnewNode)
+      whatsnewHtml = whatsnewTemplateFile.text.replaceAll("__WHATS_NEW__", whatsnewHtml)
+      whatsnewHtmlFile.text = hugoTemplateSubstitutions(whatsnewHtml,
+        [
+            VERSION: JALVIEW_VERSION,
+          DISPLAY_DATE: wnDisplayDate
+        ]
+      )
+    } else if (gradle.taskGraph.hasTask(":linkCheck")) {
+      whatsnewHtmlFile.text = "Development build " + getDate("yyyy-MM-dd HH:mm:ss")
+    }
+
+  }
+
+  inputs.file(releasesTemplateFile)
+  inputs.file(whatsnewTemplateFile)
+  inputs.dir(releasesMdDir)
+  inputs.dir(whatsnewMdDir)
+  outputs.file(releasesHtmlFile)
+  outputs.file(whatsnewHtmlFile)
+}
+
+*/
+
+task copyResources(type: Copy) {
+  group = "build"
+  description = "Copy (and make text substitutions in) the resources dir to the build area"
+
+  def inputDir = resourceDir
+  def destinationDirectory = resourcesBuildDir
+  from(inputDir) {
+    include('**/*.txt')
+    include('**/*.md')
+    include('**/*.html')
+    include('**/*.xml')
+    filter(ReplaceTokens,
+      beginToken: '$$',
+      endToken: '$$',
+      tokens: [
+        'Version-Rel': JALVIEW_VERSION,
+        'Year-Rel': getDate("yyyy")
+      ]
+    )
+  }
+  from(inputDir) {
+    exclude('**/*.txt')
+    exclude('**/*.md')
+    exclude('**/*.html')
+    exclude('**/*.xml')
+  }
+  into destinationDirectory
+
+  inputs.dir(inputDir)
+  outputs.dir(destinationDirectory)
+}
+
+task copyChannelResources(type: Copy) {
+  dependsOn copyResources
+  group = "build"
+  description = "Copy the channel resources dir to the build resources area"
+
+  def inputDir = "${channelDir}/${resource_dir}"
+  def destinationDirectory = resourcesBuildDir
+  from inputDir
+  into destinationDirectory
+
+  inputs.dir(inputDir)
+  outputs.dir(destinationDirectory)
+}
+
+task createBuildProperties(type: WriteProperties) {
+  dependsOn copyResources
+  dependsOn copyChannelResources
+  group = "build"
+  description = "Create the ${buildProperties} file"
+  
+  inputs.dir(sourceDir)
   inputs.dir(resourcesBuildDir)
   outputFile (buildProperties)
   // taking time specific comment out to allow better incremental builds
@@ -1294,6 +1644,7 @@ task createBuildProperties(type: WriteProperties) {
   property "BUILD_DATE", getDate("HH:mm:ss dd MMMM yyyy")
   property "VERSION", JALVIEW_VERSION
   property "INSTALLATION", INSTALLATION+" git-commit:"+gitHash+" ["+gitBranch+"]"
+  property "JAVA_COMPILE_VERSION", JAVA_INTEGER_VERSION
   if (getdownSetAppBaseProperty) {
     property "GETDOWNAPPBASE", getdownAppBase
     property "GETDOWNAPPDISTDIR", getdownAppDistDir
@@ -1304,6 +1655,7 @@ task createBuildProperties(type: WriteProperties) {
 
 task buildIndices(type: JavaExec) {
   dependsOn copyHelp
+  //dependsOn releasesTemplates
   classpath = sourceSets.main.compileClasspath
   main = "com.sun.java.help.search.Indexer"
   workingDir = "${helpBuildDir}/${help_dir}"
@@ -1331,14 +1683,25 @@ task prepare {
   dependsOn buildResources
   dependsOn copyDocs
   dependsOn copyHelp
+  //dependsOn releasesTemplates
   dependsOn convertMdFiles
   dependsOn buildIndices
 }
 
 
+// random block of dependencies
 compileJava.dependsOn prepare
 run.dependsOn compileJava
 //run.dependsOn prepare
+compileTestJava.dependsOn compileJava //
+compileTestJava.dependsOn buildIndices //
+processResources.dependsOn copyChannelResources //
+processResources.dependsOn copyResources //
+processResources.dependsOn createBuildProperties //
+processResources.dependsOn copyDocs //
+processResources.dependsOn convertMdFiles //
+processResources.dependsOn copyHelp //
+processResources.dependsOn buildIndices //
 
 
 //testReportDirName = "test-reports" // note that test workingDir will be $jalviewDir
@@ -1383,6 +1746,7 @@ test {
 }
 
 
+/*
 task compileLinkCheck(type: JavaCompile) {
   options.fork = true
   classpath = files("${jalviewDir}/${utils_dir}")
@@ -1403,7 +1767,7 @@ task linkCheck(type: JavaExec) {
   def helpLinksCheckerOutFile = file("${jalviewDir}/${utils_dir}/HelpLinksChecker.out")
   classpath = files("${jalviewDir}/${utils_dir}")
   main = "HelpLinksChecker"
-  workingDir = jalviewDir
+  workingDir = "${helpBuildDir}"
   args = [ "${helpBuildDir}/${help_dir}", "-nointernet" ]
 
   def outFOS = new FileOutputStream(helpLinksCheckerOutFile, false) // false == don't append
@@ -1417,6 +1781,7 @@ task linkCheck(type: JavaExec) {
   inputs.dir(helpBuildDir)
   outputs.file(helpLinksCheckerOutFile)
 }
+*/
 
 
 // import the pubhtmlhelp target
@@ -1431,10 +1796,14 @@ task cleanPackageDir(type: Delete) {
   }
 }
 
+// block of dependencies
+//compileTestJava.dependsOn compileLinkCheck //
+//copyChannelResources.dependsOn compileLinkCheck //
+//convertMdFiles.dependsOn compileLinkCheck //
 
 jar {
   dependsOn prepare
-  dependsOn linkCheck
+  dependsOn //linkCheck
 
   manifest {
     attributes "Main-Class": main_class,
@@ -1444,8 +1813,8 @@ jar {
     "Implementation-Version": JALVIEW_VERSION
   }
 
-  def outputDir = "${jalviewDir}/${package_dir}"
-  destinationDirectory = file(outputDir)
+  def destinationDirectory = "${jalviewDir}/${package_dir}"
+  destinationDirectory = file(destinationDirectory)
   archiveFileName = rootProject.name+".jar"
   duplicatesStrategy "EXCLUDE"
 
@@ -1456,11 +1825,11 @@ jar {
   exclude "**/*.jar"
   exclude "**/*.jar.*"
 
-  inputs.dir(sourceSets.main.java.outputDir)
+  inputs.dir(sourceSets.main.java.destinationDirectory)
   sourceSets.main.resources.srcDirs.each{ dir ->
     inputs.dir(dir)
   }
-  outputs.file("${outputDir}/${archiveFileName}")
+  outputs.file("${destinationDirectory}/${archiveFileName}")
 }
 
 
@@ -1519,7 +1888,7 @@ shadowJar {
 
   mainClassName = shadow_jar_main_class
   mergeServiceFiles()
-  classifier = "all-"+JALVIEW_VERSION+"-j"+JAVA_VERSION
+  archiveClassifier = "all-"+JALVIEW_VERSION+"-j"+JAVA_VERSION
   minimize()
 }
 
@@ -2388,304 +2757,10 @@ task dataInstallersJson {
   }
 }
 
-def hugoTemplateSubstitutions(String input, Map extras=null) {
-  def replacements = [
-    DATE: getDate("yyyy-MM-dd"),
-    CHANNEL: propertiesChannelName,
-    APPLICATION_NAME: applicationName,
-    GIT_HASH: gitHash,
-    GIT_BRANCH: gitBranch,
-    VERSION: JALVIEW_VERSION,
-    JAVA_VERSION: JAVA_VERSION,
-    VERSION_UNDERSCORES: JALVIEW_VERSION_UNDERSCORES,
-    DRAFT: "false",
-    JVL_HEADER: ""
-  ]
-  def output = input
-  if (extras != null) {
-    extras.each{ k, v ->
-      output = output.replaceAll("__${k}__", ((v == null)?"":v))
-    }
-  }
-  replacements.each{ k, v ->
-    output = output.replaceAll("__${k}__", ((v == null)?"":v))
-  }
-  return output
-}
-
-def mdFileComponents(File mdFile, def dateOnly=false) {
-  def map = [:]
-  def content = ""
-  if (mdFile.exists()) {
-    def inFrontMatter = false
-    def firstLine = true
-    mdFile.eachLine { line ->
-      if (line.matches("---")) {
-        def prev = inFrontMatter
-        inFrontMatter = firstLine
-        if (inFrontMatter != prev)
-          return false
-      }
-      if (inFrontMatter) {
-        def m = null
-        if (m = line =~ /^date:\s*(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})/) {
-          map["date"] = new Date().parse("yyyy-MM-dd HH:mm:ss", m[0][1])
-        } else if (m = line =~ /^date:\s*(\d{4}-\d{2}-\d{2})/) {
-          map["date"] = new Date().parse("yyyy-MM-dd", m[0][1])
-        } else if (m = line =~ /^channel:\s*(\S+)/) {
-          map["channel"] = m[0][1]
-        } else if (m = line =~ /^version:\s*(\S+)/) {
-          map["version"] = m[0][1]
-        } else if (m = line =~ /^\s*([^:]+)\s*:\s*(\S.*)/) {
-          map[ m[0][1] ] = m[0][2]
-        }
-        if (dateOnly && map["date"] != null) {
-          return false
-        }
-      } else {
-        if (dateOnly)
-          return false
-        content += line+"\n"
-      }
-      firstLine = false
-    }
-  }
-  return dateOnly ? map["date"] : [map, content]
-}
-
-task hugoTemplates {
-  group "website"
-  description "Create partially populated md pages for hugo website build"
-
-  def hugoTemplatesDir = file("${jalviewDir}/${hugo_templates_dir}")
-  def hugoBuildDir = "${jalviewDir}/${hugo_build_dir}"
-  def templateFiles = fileTree(dir: hugoTemplatesDir)
-  def releaseMdFile = file("${jalviewDir}/${releases_dir}/release-${JALVIEW_VERSION_UNDERSCORES}.md")
-  def whatsnewMdFile = file("${jalviewDir}/${whatsnew_dir}/whatsnew-${JALVIEW_VERSION_UNDERSCORES}.md")
-  def oldJvlFile = file("${jalviewDir}/${hugo_old_jvl}")
-  def jalviewjsFile = file("${jalviewDir}/${hugo_jalviewjs}")
-
-  doFirst {
-    // specific release template for version archive
-    def changes = ""
-    def whatsnew = null
-    def givenDate = null
-    def givenChannel = null
-    def givenVersion = null
-    if (CHANNEL == "RELEASE") {
-      def (map, content) = mdFileComponents(releaseMdFile)
-      givenDate = map.date
-      givenChannel = map.channel
-      givenVersion = map.version
-      changes = content
-      if (givenVersion != null && givenVersion != JALVIEW_VERSION) {
-        throw new GradleException("'version' header (${givenVersion}) found in ${releaseMdFile} does not match JALVIEW_VERSION (${JALVIEW_VERSION})")
-      }
-
-      if (whatsnewMdFile.exists())
-        whatsnew = whatsnewMdFile.text
-    }
-
-    def oldJvl = oldJvlFile.exists() ? oldJvlFile.collect{it} : []
-    def jalviewjsLink = jalviewjsFile.exists() ? jalviewjsFile.collect{it} : []
-
-    def changesHugo = null
-    if (changes != null) {
-      changesHugo = '<div class="release_notes">\n\n'
-      def inSection = false
-      changes.eachLine { line ->
-        def m = null
-        if (m = line =~ /^##([^#].*)$/) {
-          if (inSection) {
-            changesHugo += "</div>\n\n"
-          }
-          def section = m[0][1].trim()
-          section = section.toLowerCase()
-          section = section.replaceAll(/ +/, "_")
-          section = section.replaceAll(/[^a-z0-9_\-]/, "")
-          changesHugo += "<div class=\"${section}\">\n\n"
-          inSection = true
-        } else if (m = line =~ /^(\s*-\s*)<!--([^>]+)-->(.*?)(<br\/?>)?\s*$/) {
-          def comment = m[0][2].trim()
-          if (comment != "") {
-            comment = comment.replaceAll('"', "&quot;")
-            def issuekeys = []
-            comment.eachMatch(/JAL-\d+/) { jal -> issuekeys += jal }
-            def newline = m[0][1]
-            if (comment.trim() != "")
-              newline += "{{<comment>}}${comment}{{</comment>}}  "
-            newline += m[0][3].trim()
-            if (issuekeys.size() > 0)
-              newline += "  {{< jal issue=\"${issuekeys.join(",")}\" alt=\"${comment}\" >}}"
-            if (m[0][4] != null)
-              newline += m[0][4]
-            line = newline
-          }
-        }
-        changesHugo += line+"\n"
-      }
-      if (inSection) {
-        changesHugo += "\n</div>\n\n"
-      }
-      changesHugo += '</div>'
-    }
-
-    templateFiles.each{ templateFile ->
-      def newFileName = string(hugoTemplateSubstitutions(templateFile.getName()))
-      def relPath = hugoTemplatesDir.toPath().relativize(templateFile.toPath()).getParent()
-      def newRelPathName = hugoTemplateSubstitutions( relPath.toString() )
-
-      def outPathName = string("${hugoBuildDir}/$newRelPathName")
-
-      copy {
-        from templateFile
-        rename(templateFile.getName(), newFileName)
-        into outPathName
-      }
-
-      def newFile = file("${outPathName}/${newFileName}".toString())
-      def content = newFile.text
-      newFile.text = hugoTemplateSubstitutions(content,
-        [
-          WHATSNEW: whatsnew,
-          CHANGES: changesHugo,
-          DATE: givenDate == null ? "" : givenDate.format("yyyy-MM-dd"),
-          DRAFT: givenDate == null ? "true" : "false",
-          JALVIEWJSLINK: jalviewjsLink.contains(JALVIEW_VERSION) ? "true" : "false",
-          JVL_HEADER: oldJvl.contains(JALVIEW_VERSION) ? "jvl: true" : ""
-        ]
-      )
-    }
-
-  }
-
-  inputs.file(oldJvlFile)
-  inputs.dir(hugoTemplatesDir)
-  inputs.property("JALVIEW_VERSION", { JALVIEW_VERSION })
-  inputs.property("CHANNEL", { CHANNEL })
-}
-
-def getMdDate(File mdFile) {
-  return mdFileComponents(mdFile, true)
-}
-
-def getMdSections(String content) {
-  def sections = [:]
-  def sectionContent = ""
-  def sectionName = null
-  content.eachLine { line ->
-    def m = null
-    if (m = line =~ /^##([^#].*)$/) {
-      if (sectionName != null) {
-        sections[sectionName] = sectionContent
-        sectionName = null
-        sectionContent = ""
-      }
-      sectionName = m[0][1].trim()
-      sectionName = sectionName.toLowerCase()
-      sectionName = sectionName.replaceAll(/ +/, "_")
-      sectionName = sectionName.replaceAll(/[^a-z0-9_\-]/, "")
-    } else if (sectionName != null) {
-      sectionContent += line+"\n"
-    }
-  }
-  if (sectionContent != null) {
-    sections[sectionName] = sectionContent
-  }
-  return sections
-}
-
-task releasesTemplates {
-  def releasesTemplateFile = file("${jalviewDir}/${releases_template}")
-  def whatsnewTemplateFile = file("${jalviewDir}/${whatsnew_template}")
-  def releasesHtmlFile = file("${helpSourceDir}/${releases_html}")
-  def whatsnewHtmlFile = file("${helpSourceDir}/${whatsnew_html}")
-  def releasesMdDir = "${jalviewDir}/${releases_dir}"
-  def whatsnewMdDir = "${jalviewDir}/${whatsnew_dir}"
-
-  doFirst {
-    def releaseFiles = fileTree(dir: releasesMdDir, include: "release-*.md")
-    def releaseFilesDates = releaseFiles.collectEntries {
-      [(it): getMdDate(it)]
-    }
-    releaseFiles = releaseFiles.sort { a,b -> releaseFilesDates[a].compareTo(releaseFilesDates[b]) }
-
-    def releasesTemplate = releasesTemplateFile.text
-    def m = releasesTemplate =~ /(?s)__VERSION_LOOP_START__(.*)__VERSION_LOOP_END__/
-    def versionTemplate = m[0][1]
-
-    MutableDataSet options = new MutableDataSet()
-
-    def extensions = new ArrayList<>()
-    options.set(Parser.EXTENSIONS, extensions)
-    options.set(Parser.HTML_BLOCK_COMMENT_ONLY_FULL_LINE, true)
-
-    Parser parser = Parser.builder(options).build()
-    HtmlRenderer renderer = HtmlRenderer.builder(options).build()
-
-    def actualVersions = releaseFiles.collect { rf ->
-      def (rfMap, rfContent) = mdFileComponents(rf)
-      return rfMap.version
-    }
-    def versionsHtml = ""
-    def linkedVersions = []
-    releaseFiles.reverse().each { rFile ->
-      def (rMap, rContent) = mdFileComponents(rFile)
-
-      def versionLink = ""
-      def partialVersion = ""
-      def firstPart = true
-      rMap.version.split("\\.").each { part ->
-        def displayPart = ( firstPart ? "" : "." ) + part
-        partialVersion += displayPart
-        if (
-            linkedVersions.contains(partialVersion)
-            || ( actualVersions.contains(partialVersion) && partialVersion != rMap.version )
-            ) {
-          versionLink += displayPart
-        } else {
-          versionLink += "<a id=\"Jalview.${partialVersion}\">${displayPart}</a>"
-          linkedVersions += partialVersion
-        }
-        firstPart = false
-      }
-      def displayDate = releaseFilesDates[rFile].format("d MMMMM yyyy")
-
-      def rContentSections = getMdSections(rContent)
-      def rVersion = versionTemplate
-      if (rVersion != "") {
-        Node newFeaturesNode = parser.parse(rContentSections["new_features"])
-        String newFeaturesHtml = renderer.render(newFeaturesNode)
-        Node issuesResolvedNode = parser.parse(rContentSections["issues_resolved"])
-        String issuesResolvedHtml = renderer.render(issuesResolvedNode)
-        rVersion = hugoTemplateSubstitutions(rVersion,
-          [
-            VERSION: rMap.version,
-            VERSION_LINK: versionLink,
-            DISPLAY_DATE: displayDate,
-            NEW_FEATURES: newFeaturesHtml,
-            ISSUES_RESOLVED: issuesResolvedHtml
-          ]
-        )
-        versionsHtml += rVersion
-      }
-    }
-
-    releasesTemplate = releasesTemplate.replaceAll("(?s)__VERSION_LOOP_START__.*__VERSION_LOOP_END__", versionsHtml)
-    releasesTemplate = hugoTemplateSubstitutions(releasesTemplate)
-    releasesHtmlFile.text = releasesTemplate
-  }
-
-  inputs.file(releasesTemplateFile)
-  inputs.file(whatsnewTemplateFile)
-  inputs.dir(releasesMdDir)
-  inputs.dir(whatsnewMdDir)
-  outputs.file(releasesHtmlFile)
-  outputs.file(whatsnewHtmlFile)
-}
-
-
 task helppages {
+  group "help"
+  description "Copies all help pages to build dir. Runs ant task 'pubhtmlhelp'."
+
   dependsOn copyHelp
   dependsOn pubhtmlhelp
   
@@ -2868,10 +2943,10 @@ task jalviewjsEclipseCopyDropins(type: Copy) {
 
   def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjs_eclipse_dropins_dir}", include: "*.jar")
   inputFiles += file("${jalviewDir}/${jalviewjsJ2sPlugin}")
-  def outputDir = "${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_eclipse_tmp_dropins_dir}"
+  def destinationDirectory = "${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_eclipse_tmp_dropins_dir}"
 
   from inputFiles
-  into outputDir
+  into destinationDirectory
 }
 
 
@@ -2979,13 +3054,13 @@ task jalviewjsSyncAllLibs (type: Sync) {
   dependsOn jalviewjsTransferUnzipAllLibs
   def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjsTransferSiteLibDir}")
   inputFiles += fileTree(dir: "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}")
-  def outputDir = "${jalviewDir}/${jalviewjsSiteDir}"
+  def destinationDirectory = "${jalviewDir}/${jalviewjsSiteDir}"
 
   from inputFiles
-  into outputDir
+  into destinationDirectory
   def outputFiles = []
   rename { filename ->
-    outputFiles += "${outputDir}/${filename}"
+    outputFiles += "${destinationDirectory}/${filename}"
     null
   }
   preserve {
@@ -3004,13 +3079,13 @@ task jalviewjsSyncResources (type: Sync) {
   dependsOn buildResources
 
   def inputFiles = fileTree(dir: resourcesBuildDir)
-  def outputDir = "${jalviewDir}/${jalviewjsSiteDir}/${jalviewjs_j2s_subdir}"
+  def destinationDirectory = "${jalviewDir}/${jalviewjsSiteDir}/${jalviewjs_j2s_subdir}"
 
   from inputFiles
-  into outputDir
+  into destinationDirectory
   def outputFiles = []
   rename { filename ->
-    outputFiles += "${outputDir}/${filename}"
+    outputFiles += "${destinationDirectory}/${filename}"
     null
   }
   preserve {
@@ -3023,13 +3098,13 @@ task jalviewjsSyncResources (type: Sync) {
 
 task jalviewjsSyncSiteResources (type: Sync) {
   def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjs_site_resource_dir}")
-  def outputDir = "${jalviewDir}/${jalviewjsSiteDir}"
+  def destinationDirectory = "${jalviewDir}/${jalviewjsSiteDir}"
 
   from inputFiles
-  into outputDir
+  into destinationDirectory
   def outputFiles = []
   rename { filename ->
-    outputFiles += "${outputDir}/${filename}"
+    outputFiles += "${destinationDirectory}/${filename}"
     null
   }
   preserve {
@@ -3043,13 +3118,13 @@ task jalviewjsSyncSiteResources (type: Sync) {
 task jalviewjsSyncBuildProperties (type: Sync) {
   dependsOn createBuildProperties
   def inputFiles = [file(buildProperties)]
-  def outputDir = "${jalviewDir}/${jalviewjsSiteDir}/${jalviewjs_j2s_subdir}"
+  def destinationDirectory = "${jalviewDir}/${jalviewjsSiteDir}/${jalviewjs_j2s_subdir}"
 
   from inputFiles
-  into outputDir
+  into destinationDirectory
   def outputFiles = []
   rename { filename ->
-    outputFiles += "${outputDir}/${filename}"
+    outputFiles += "${destinationDirectory}/${filename}"
     null
   }
   preserve {
@@ -3268,7 +3343,7 @@ task jalviewjsBuildAllCores {
   def swingJ2sDir = "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}/${jalviewjs_j2s_subdir}"
   def libJ2sDir = "${jalviewDir}/${jalviewjsTransferSiteLibDir}/${jalviewjs_j2s_subdir}"
   def jsDir = "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}/${jalviewjs_js_subdir}"
-  def outputDir = "${jalviewDir}/${jalviewjsTransferSiteCoreDir}/${jalviewjs_j2s_subdir}/core"
+  def destinationDirectory = "${jalviewDir}/${jalviewjsTransferSiteCoreDir}/${jalviewjs_j2s_subdir}/core"
   def prefixFile = "${jsDir}/core/coretop2.js"
   def suffixFile = "${jsDir}/core/corebottom2.js"
 
@@ -3312,8 +3387,8 @@ task jalviewjsBuildAllCores {
     }
     def list = fileTree(dir: j2sDir, includes: filelist)
 
-    def jsfile = "${outputDir}/core${name}.js"
-    def zjsfile = "${outputDir}/core${name}.z.js"
+    def jsfile = "${destinationDirectory}/core${name}.js"
+    def zjsfile = "${destinationDirectory}/core${name}.z.js"
 
     jalviewjsCoreClasslists += [
       'jsfile': jsfile,
@@ -3331,8 +3406,8 @@ task jalviewjsBuildAllCores {
   // _stevesoft core. add any cores without a classlist here (and the inputs and outputs)
   def stevesoftClasslistName = "_stevesoft"
   def stevesoftClasslist = [
-    'jsfile': "${outputDir}/core${stevesoftClasslistName}.js",
-    'zjsfile': "${outputDir}/core${stevesoftClasslistName}.z.js",
+    'jsfile': "${destinationDirectory}/core${stevesoftClasslistName}.js",
+    'zjsfile': "${destinationDirectory}/core${stevesoftClasslistName}.z.js",
     'list': fileTree(dir: j2sDir, include: "com/stevesoft/pat/**/*.js"),
     'name': stevesoftClasslistName
   ]
@@ -3365,8 +3440,8 @@ task jalviewjsBuildAllCores {
     ]
   )
   def allClasslist = [
-    'jsfile': "${outputDir}/core${allClasslistName}.js",
-    'zjsfile': "${outputDir}/core${allClasslistName}.z.js",
+    'jsfile': "${destinationDirectory}/core${allClasslistName}.js",
+    'zjsfile': "${destinationDirectory}/core${allClasslistName}.z.js",
     'list': allJsFiles,
     'name': allClasslistName
   ]
@@ -3419,11 +3494,11 @@ task jalviewjsPublishCoreTemplates {
   dependsOn jalviewjsBuildAllCores
   def inputFileName = "${jalviewDir}/${j2s_coretemplate_html}"
   def inputFile = file(inputFileName)
-  def outputDir = "${jalviewDir}/${jalviewjsTransferSiteCoreDir}"
+  def destinationDirectory = "${jalviewDir}/${jalviewjsTransferSiteCoreDir}"
 
   def outputFiles = []
   jalviewjsCoreClasslists.each { cl ->
-    def outputFile = "${outputDir}/${jalviewjsJalviewTemplateName}_${cl.name}.html"
+    def outputFile = "${destinationDirectory}/${jalviewjsJalviewTemplateName}_${cl.name}.html"
     cl['outputfile'] = outputFile
     outputFiles += outputFile
   }
@@ -3442,13 +3517,13 @@ task jalviewjsSyncCore (type: Sync) {
   dependsOn jalviewjsBuildAllCores
   dependsOn jalviewjsPublishCoreTemplates
   def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjsTransferSiteCoreDir}")
-  def outputDir = "${jalviewDir}/${jalviewjsSiteDir}"
+  def destinationDirectory = "${jalviewDir}/${jalviewjsSiteDir}"
 
   from inputFiles
-  into outputDir
+  into destinationDirectory
   def outputFiles = []
   rename { filename ->
-    outputFiles += "${outputDir}/${filename}"
+    outputFiles += "${destinationDirectory}/${filename}"
     null
   }
   preserve {