JAL-3789 Use j2s.config.altfileproperty in .j2s for alternative temporary build/jalvi...
[jalview.git] / build.gradle
index bd0ae20..180d4ad 100644 (file)
@@ -12,13 +12,25 @@ import java.security.MessageDigest
 import groovy.transform.ExternalizeMethods
 import groovy.util.XmlParser
 import groovy.xml.XmlUtil
-
+import com.vladsch.flexmark.util.ast.Node
+import com.vladsch.flexmark.html.HtmlRenderer
+import com.vladsch.flexmark.parser.Parser
+import com.vladsch.flexmark.util.data.MutableDataSet
+import com.vladsch.flexmark.ext.gfm.tasklist.TaskListExtension
+import com.vladsch.flexmark.ext.tables.TablesExtension
+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
 
 buildscript {
   repositories {
     mavenCentral()
     mavenLocal()
   }
+  dependencies {
+    classpath "com.vladsch.flexmark:flexmark-all:0.62.0"
+  }
 }
 
 
@@ -98,7 +110,7 @@ ext {
   }
   ////
   // Set JALVIEW_VERSION if it is not already set
-  if (findProperty(JALVIEW_VERSION)==null || "".equals(JALVIEW_VERSION)) {
+  if (findProperty("JALVIEW_VERSION")==null || "".equals(JALVIEW_VERSION)) {
     JALVIEW_VERSION = releaseProps.get("jalview.version")
   }
   
@@ -148,7 +160,7 @@ ext {
   cloverBuildDir = "${buildDir}/clover"
   cloverInstrDir = file("${cloverBuildDir}/clover-instr")
   cloverClassesDir = file("${cloverBuildDir}/clover-classes")
-  cloverReportDir = file("${buildDir}/reports")
+  cloverReportDir = file("${buildDir}/reports/clover")
   cloverTestInstrDir = file("${cloverBuildDir}/clover-test-instr")
   cloverTestClassesDir = file("${cloverBuildDir}/clover-test-classes")
   //cloverTestClassesDir = cloverClassesDir
@@ -445,10 +457,10 @@ ext {
   jalviewjsTransferSiteSwingJsDir = string("${jalviewjsBuildDir}/tmp/${jalviewjs_site_dir}_swingjs")
   jalviewjsTransferSiteCoreDir = string("${jalviewjsBuildDir}/tmp/${jalviewjs_site_dir}_core")
   jalviewjsJalviewCoreHtmlFile = string("")
-  jalviewjsJalviewCoreName = string(jalviewjs_core_name)
   jalviewjsCoreClasslists = []
   jalviewjsJalviewTemplateName = string(jalviewjs_name)
   jalviewjsJ2sSettingsFileName = string("${jalviewDir}/${jalviewjs_j2s_settings}")
+  jalviewjsJ2sAltSettingsFileName = string("${jalviewDir}/${jalviewjs_j2s_alt_settings}")
   jalviewjsJ2sProps = null
   jalviewjsJ2sPlugin = jalviewjs_j2s_plugin
 
@@ -733,6 +745,7 @@ eclipseGroovyCorePreferences.mustRunAfter eclipseJdt
 task cleanClover {
   doFirst {
     delete cloverBuildDir
+    delete cloverReportDir
   }
 }
 
@@ -855,7 +868,7 @@ task cloverHtmlReport(type: JavaExec) {
     file(cloverDb).exists()
   }
 
-  def cloverHtmlDir = "${cloverReportDir}/clover"
+  def cloverHtmlDir = cloverReportDir
   inputs.dir cloverClassesDir
   outputs.dir cloverHtmlDir
 
@@ -893,7 +906,7 @@ task cloverXmlReport(type: JavaExec) {
     file(cloverDb).exists()
   }
 
-  def cloverXmlFile = "${cloverReportDir}/clover/clover.xml"
+  def cloverXmlFile = "${cloverReportDir}/clover.xml"
   inputs.dir cloverClassesDir
   outputs.file cloverXmlFile
 
@@ -991,22 +1004,25 @@ def getDate(format) {
 
 
 task setGitVals {
-  def hashStdOut = new ByteArrayOutputStream()
-  exec {
-    commandLine "git", "rev-parse", "--short", "HEAD"
-    standardOutput = hashStdOut
-    ignoreExitValue true
-  }
 
-  def branchStdOut = new ByteArrayOutputStream()
-  exec {
-    commandLine "git", "rev-parse", "--abbrev-ref", "HEAD"
-    standardOutput = branchStdOut
-    ignoreExitValue true
-  }
+  doFirst {
+    def hashStdOut = new ByteArrayOutputStream()
+    def resultHash = exec {
+      commandLine "git", "rev-parse", "--short", "HEAD"
+      standardOutput = hashStdOut
+      ignoreExitValue true
+    }
 
-  gitHash = hashStdOut.toString().trim()
-  gitBranch = branchStdOut.toString().trim()
+    def branchStdOut = new ByteArrayOutputStream()
+    def resultBranch = exec {
+      commandLine "git", "rev-parse", "--abbrev-ref", "HEAD"
+      standardOutput = branchStdOut
+      ignoreExitValue true
+    }
+
+    gitHash = resultHash.getExitValue() == 0 ? hashStdOut.toString().trim() : "NO_GIT_COMMITID_FOUND"
+    gitBranch = resultBranch.getExitValue() == 0 ? branchStdOut.toString().trim() : "NO_GIT_BRANCH_FOUND"
+  }
 
   outputs.upToDateWhen { false }
 }
@@ -1045,47 +1061,110 @@ task cleanBuildingHTML(type: Delete) {
 }
 
 
-task convertBuildingMD(type: Exec) {
+def convertMdToHtml (FileTree mdFiles, File cssFile) {
+  MutableDataSet options = new MutableDataSet()
+
+  def extensions = new ArrayList<>()
+  extensions.add(AnchorLinkExtension.create()) 
+  extensions.add(AutolinkExtension.create())
+  extensions.add(StrikethroughExtension.create())
+  extensions.add(TaskListExtension.create())
+  extensions.add(TablesExtension.create())
+  extensions.add(TocExtension.create())
+  
+  options.set(Parser.EXTENSIONS, extensions)
+
+  // set GFM table parsing options
+  options.set(TablesExtension.WITH_CAPTION, false)
+  options.set(TablesExtension.COLUMN_SPANS, false)
+  options.set(TablesExtension.MIN_HEADER_ROWS, 1)
+  options.set(TablesExtension.MAX_HEADER_ROWS, 1)
+  options.set(TablesExtension.APPEND_MISSING_COLUMNS, true)
+  options.set(TablesExtension.DISCARD_EXTRA_COLUMNS, true)
+  options.set(TablesExtension.HEADER_SEPARATOR_COLUMN_MATCH, true)
+  // GFM anchor links
+  options.set(AnchorLinkExtension.ANCHORLINKS_SET_ID, false)
+  options.set(AnchorLinkExtension.ANCHORLINKS_ANCHOR_CLASS, "anchor")
+  options.set(AnchorLinkExtension.ANCHORLINKS_SET_NAME, true)
+  options.set(AnchorLinkExtension.ANCHORLINKS_TEXT_PREFIX, "<span class=\"octicon octicon-link\"></span>")
+
+  Parser parser = Parser.builder(options).build()
+  HtmlRenderer renderer = HtmlRenderer.builder(options).build()
+
+  mdFiles.each { mdFile ->
+    // add table of contents
+    def mdText = "[TOC]\n"+mdFile.text
+
+    // grab the first top-level title
+    def title = null
+    def titleRegex = /(?m)^#(\s+|([^#]))(.*)/
+    def matcher = mdText =~ titleRegex
+    if (matcher.size() > 0) {
+      // matcher[0][2] is the first character of the title if there wasn't any whitespace after the #
+      title = (matcher[0][2] != null ? matcher[0][2] : "")+matcher[0][3]
+    }
+    // or use the filename if none found
+    if (title == null) {
+      title = mdFile.getName()
+    }
+
+    Node document = parser.parse(mdText)
+    String htmlBody = renderer.render(document)
+    def htmlText = '''<html>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+    <meta http-equiv="Content-Style-Type" content="text/css" />
+    <meta name="generator" content="flexmark" />
+'''
+    htmlText += ((title != null) ? "  <title>${title}</title>" : '' )
+    htmlText += '''
+    <style type="text/css">code{white-space: pre;}</style>
+'''
+    htmlText += ((cssFile != null) ? cssFile.text : '')
+    htmlText += '''</head>
+  <body>
+'''
+    htmlText += htmlBody
+    htmlText += '''
+  </body>
+</html>
+'''
+
+    def htmlFilePath = mdFile.getPath().replaceAll(/\..*?$/, ".html")
+    def htmlFile = file(htmlFilePath)
+    htmlFile.text = htmlText
+  }
+}
+
+
+task convertMdFiles {
   dependsOn cleanBuildingHTML
-  def buildingMD = "${jalviewDir}/${doc_dir}/building.md"
-  def css = "${jalviewDir}/${doc_dir}/github.css"
+  def mdFiles = fileTree(dir: "${jalviewDir}/${doc_dir}", include: "*.md")
+  def cssFile = file("${jalviewDir}/${flexmark_css}")
 
-  def pandoc = null
-  pandoc_exec.split(",").each {
-    if (file(it.trim()).exists()) {
-      pandoc = it.trim()
-      return true
-    }
+  doLast {
+    convertMdToHtml(mdFiles, cssFile)
   }
 
-  def buildtoolsPandoc = System.getProperty("user.home")+"/buildtools/pandoc/bin/pandoc"
-  if ((pandoc == null || ! file(pandoc).exists()) && file(buildtoolsPandoc).exists()) {
-    pandoc = System.getProperty("user.home")+"/buildtools/pandoc/bin/pandoc"
-  }
+  inputs.files(mdFiles)
+  inputs.file(cssFile)
 
-  doFirst {
-    if (pandoc != null && file(pandoc).exists()) {
-        commandLine pandoc, '-s', '-o', buildingHTML, '--metadata', 'pagetitle="Building Jalview from Source"', '--toc', '-H', css, buildingMD
-    } else {
-        println("Cannot find pandoc. Skipping convert building.md to HTML")
-        throw new StopExecutionException("Cannot find pandoc. Skipping convert building.md to HTML")
-    }
+  def htmlFiles = []
+  mdFiles.each { mdFile ->
+    def htmlFilePath = mdFile.getPath().replaceAll(/\..*?$/, ".html")
+    htmlFiles.add(file(htmlFilePath))
   }
-
-  ignoreExitValue true
-
-  inputs.file(buildingMD)
-  inputs.file(css)
-  outputs.file(buildingHTML)
+  outputs.files(htmlFiles)
 }
 
 
 task syncDocs(type: Sync) {
-  dependsOn convertBuildingMD
+  dependsOn convertMdFiles
   def syncDir = "${classesDir}/${doc_dir}"
   from fileTree("${jalviewDir}/${doc_dir}")
   into syncDir
-
 }
 
 
@@ -1308,6 +1387,7 @@ task cleanDist {
 
 shadowJar {
   group = "distribution"
+  description = "Create a single jar file with all dependency libraries merged. Can be run with java -jar"
   if (buildDist) {
     dependsOn makeDist
   }
@@ -1782,7 +1862,11 @@ spotless {
 
 
 task sourceDist(type: Tar) {
+  group "distribution"
+  description "Create a source .tar.gz file for distribution"
   
+  dependsOn convertMdFiles
+
   def VERSION_UNDERSCORES = JALVIEW_VERSION.replaceAll("\\.", "_")
   def outputFileName = "${project.name}_${VERSION_UNDERSCORES}.tar.gz"
   // cater for buildship < 3.1 [3.0.1 is max version in eclipse 2018-09]
@@ -1892,6 +1976,33 @@ task j2sSetHeadlessBuild {
 }
 
 
+task jalviewjsEnableAltFileProperty(type: WriteProperties) {
+  group "jalviewjs"
+  description "Enable the alternative J2S Config file for headless build"
+
+  outputFile = jalviewjsJ2sSettingsFileName
+  def j2sPropsFile = file(jalviewjsJ2sSettingsFileName)
+  def j2sProps = new Properties()
+  if (j2sPropsFile.exists()) {
+    try {
+      def j2sPropsFileFIS = new FileInputStream(j2sPropsFile)
+      j2sProps.load(j2sPropsFileFIS)
+      j2sPropsFileFIS.close()
+
+      j2sProps.each { prop, val ->
+        property(prop, val)
+      }
+    } catch (Exception e) {
+      println("Exception reading ${jalviewjsJ2sSettingsFileName}")
+      e.printStackTrace()
+    }
+  }
+  if (! j2sProps.stringPropertyNames().contains(jalviewjs_j2s_alt_file_property_config)) {
+    property(jalviewjs_j2s_alt_file_property_config, jalviewjs_j2s_alt_file_property)
+  }
+}
+
+
 task jalviewjsSetEclipseWorkspace {
   def propKey = "jalviewjs_eclipse_workspace"
   def propVal = null
@@ -2104,7 +2215,7 @@ task jalviewjsTransferUnzipAllLibs {
 
 task jalviewjsCreateJ2sSettings(type: WriteProperties) {
   group "JalviewJS"
-  description "Create the .j2s file from the j2s.* properties"
+  description "Create the alternative j2s file from the j2s.* properties"
 
   jalviewjsJ2sProps = project.properties.findAll { it.key.startsWith("j2s.") }.sort { it.key }
   def siteDirProperty = "j2s.site.directory"
@@ -2123,11 +2234,11 @@ task jalviewjsCreateJ2sSettings(type: WriteProperties) {
       property(siteDirProperty,"${jalviewDirRelativePath}/${jalviewjsTransferSiteJsDir}")
     }
   }
-  outputFile = jalviewjsJ2sSettingsFileName
+  outputFile = jalviewjsJ2sAltSettingsFileName
 
   if (! IN_ECLIPSE) {
     inputs.properties(jalviewjsJ2sProps)
-    outputs.file(jalviewjsJ2sSettingsFileName)
+    outputs.file(jalviewjsJ2sAltSettingsFileName)
   }
 }
 
@@ -2243,6 +2354,7 @@ task jalviewjsProjectImport(type: Exec) {
   args += [ "--launcher.appendVmargs", "-vmargs", "-Dorg.eclipse.equinox.p2.reconciler.dropins.directory=${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_eclipse_tmp_dropins_dir}" ]
   if (!IN_ECLIPSE) {
     args += [ "-D${j2sHeadlessBuildProperty}=true" ]
+    args += [ "-D${jalviewjs_j2s_alt_file_property}=${jalviewjsJ2sAltSettingsFileName}" ]
   }
 
   inputs.file("${jalviewDir}/.project")
@@ -2256,6 +2368,9 @@ task jalviewjsTranspile(type: Exec) {
   dependsOn jalviewjsEclipseSetup 
   dependsOn jalviewjsProjectImport
   dependsOn jalviewjsEclipsePaths
+  if (!IN_ECLIPSE) {
+    dependsOn jalviewjsEnableAltFileProperty
+  }
 
   doFirst {
     // do not run a headless transpile when we claim to be in Eclipse
@@ -2275,6 +2390,7 @@ task jalviewjsTranspile(type: Exec) {
   args += [ "--launcher.appendVmargs", "-vmargs", "-Dorg.eclipse.equinox.p2.reconciler.dropins.directory=${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_eclipse_tmp_dropins_dir}" ]
   if (!IN_ECLIPSE) {
     args += [ "-D${j2sHeadlessBuildProperty}=true" ]
+    args += [ "-D${jalviewjs_j2s_alt_file_property}=${jalviewjsJ2sAltSettingsFileName}" ]
   }
 
   def stdout
@@ -2439,10 +2555,6 @@ task jalviewjsBuildAllCores {
     ]
   }
 
-  // _jmol and _jalview cores. Add any other peculiar classlist.txt files here
-  //classlistFiles += [ 'file': file("${jalviewDir}/${jalviewjs_classlist_jmol}"), 'name': "_jvjmol" ]
-  classlistFiles += [ 'file': file("${jalviewDir}/${jalviewjs_classlist_jalview}"), 'name': jalviewjsJalviewCoreName ]
-
   jalviewjsCoreClasslists = []
 
   classlistFiles.each {
@@ -2465,8 +2577,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 = "${outputDir}/core_${name}.js"
+    def zjsfile = "${outputDir}/core_${name}.z.js"
 
     jalviewjsCoreClasslists += [
       'jsfile': jsfile,
@@ -2481,21 +2593,8 @@ task jalviewjsBuildAllCores {
     outputs.file(zjsfile)
   }
   
-  // _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",
-    'list': fileTree(dir: j2sDir, include: "com/stevesoft/pat/**/*.js"),
-    'name': stevesoftClasslistName
-  ]
-  jalviewjsCoreClasslists += stevesoftClasslist
-  inputs.files(stevesoftClasslist['list'])
-  outputs.file(stevesoftClasslist['jsfile'])
-  outputs.file(stevesoftClasslist['zjsfile'])
-
   // _all core
-  def allClasslistName = "_all"
+  def allClasslistName = "all"
   def allJsFiles = fileTree(dir: j2sDir, include: "**/*.js")
   allJsFiles += fileTree(
     dir: libJ2sDir,
@@ -2518,8 +2617,8 @@ task jalviewjsBuildAllCores {
     ]
   )
   def allClasslist = [
-    'jsfile': "${outputDir}/core${allClasslistName}.js",
-    'zjsfile': "${outputDir}/core${allClasslistName}.z.js",
+    'jsfile': "${outputDir}/core_${allClasslistName}.js",
+    'zjsfile': "${outputDir}/core_${allClasslistName}.z.js",
     'list': allJsFiles,
     'name': allClasslistName
   ]
@@ -2759,7 +2858,7 @@ task cleanJalviewjsAll {
     if (eclipseWorkspace != null && file(eclipseWorkspace.getAbsolutePath()+"/.metadata").exists()) {
       delete file(eclipseWorkspace.getAbsolutePath()+"/.metadata")
     }
-    delete "${jalviewDir}/${jalviewjs_j2s_settings}"
+    delete jalviewjsJ2sAltSettingsFileName
   }
 
   outputs.upToDateWhen( { false } )
@@ -2777,10 +2876,25 @@ task jalviewjsIDE_checkJ2sPlugin {
     if (eclipseHome == null || ! IN_ECLIPSE) {
       throw new StopExecutionException("Cannot find running Eclipse home from System.properties['eclipse.home.location']. Skipping J2S Plugin Check.")
     }
-    def eclipseJ2sPlugin = "${eclipseHome}/dropins/${j2sPluginFile.getName()}"
-    def eclipseJ2sPluginFile = file(eclipseJ2sPlugin)
-    if (!eclipseJ2sPluginFile.exists()) {
-      def msg = "Eclipse J2S Plugin is not installed (could not find '${eclipseJ2sPlugin}')\nTry running task jalviewjsIDE_copyJ2sPlugin"
+    def eclipseJ2sPluginDirs = [ "${eclipseHome}/dropins" ]
+    def altPluginsDir = System.properties["org.eclipse.equinox.p2.reconciler.dropins.directory"]
+    if (altPluginsDir != null && file(altPluginsDir).exists()) {
+      eclipseJ2sPluginDirs += altPluginsDir
+    }
+    def foundPlugin = false
+    def j2sPluginFileName = j2sPluginFile.getName()
+    def eclipseJ2sPlugin
+    def eclipseJ2sPluginFile
+    eclipseJ2sPluginDirs.any { dir ->
+      eclipseJ2sPlugin = "${dir}/${j2sPluginFileName}"
+      eclipseJ2sPluginFile = file(eclipseJ2sPlugin)
+      if (eclipseJ2sPluginFile.exists()) {
+        foundPlugin = true
+        return true
+      }
+    }
+    if (!foundPlugin) {
+      def msg = "Eclipse J2S Plugin is not installed (could not find '${j2sPluginFileName}' in\n"+eclipseJ2sPluginDirs.join("\n")+"\n)\nTry running task jalviewjsIDE_copyJ2sPlugin"
       System.err.println(msg)
       throw new StopExecutionException(msg)
     }
@@ -2798,7 +2912,7 @@ task jalviewjsIDE_checkJ2sPlugin {
       System.err.println(msg)
       throw new StopExecutionException(msg)
     } else {
-      def msg = "Eclipse J2S Plugin is the same as '${j2sPlugin}' (this is good)"
+      def msg = "Eclipse J2S Plugin '${eclipseJ2sPlugin}' is the same as '${j2sPlugin}' (this is good)"
       println(msg)
     }
   }
@@ -2858,7 +2972,7 @@ task jalviewjsIDE_PrepareSite {
   description "Sync libs and resources to site dir, but not closure cores"
 
   dependsOn jalviewjsIDE_SyncSiteAll
-  dependsOn cleanJalviewjsTransferSite
+  //dependsOn cleanJalviewjsTransferSite // not sure why this clean is here -- will slow down a re-run of this task
 }