JAL-4023 store distances as doubles
[jalview.git] / build.gradle
index c3e89e5..b4636bc 100644 (file)
@@ -40,9 +40,9 @@ plugins {
   id 'eclipse'
   id "com.diffplug.gradle.spotless" version "3.28.0"
   id 'com.github.johnrengelman.shadow' version '4.0.3'
-  id 'com.install4j.gradle' version '8.0.4'
+  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
 }
 
 repositories {
@@ -52,29 +52,19 @@ repositories {
 }
 
 
+
 // in ext the values are cast to Object. Ensure string values are cast as String (and not GStringImpl) for later use
 def string(Object o) {
   return o == null ? "" : o.toString()
 }
 
-
-ext {
-  jalviewDirAbsolutePath = file(jalviewDir).getAbsolutePath()
-  jalviewDirRelativePath = jalviewDir
-
-  // local build environment properties
-  // can be "projectDir/local.properties"
-  def localProps = "${projectDir}/local.properties"
-  def propsFile = null;
-  if (file(localProps).exists()) {
-    propsFile = localProps
+def overrideProperties(String propsFileName, boolean output = false) {
+  if (propsFileName == null) {
+    return
   }
-  // or "../projectDir_local.properties"
-  def dirLocalProps = projectDir.getParent() + "/" + projectDir.getName() + "_local.properties"
-  if (file(dirLocalProps).exists()) {
-    propsFile = dirLocalProps
-  }
-  if (propsFile != null) {
+  def propsFile = file(propsFileName)
+  if (propsFile != null && propsFile.exists()) {
+    println("Using properties from file '${propsFileName}'")
     try {
       def p = new Properties()
       def localPropsFIS = new FileInputStream(propsFile)
@@ -82,24 +72,50 @@ ext {
       localPropsFIS.close()
       p.each {
         key, val -> 
-          def oldval = findProperty(key)
-          setProperty(key, val)
-          if (oldval != null) {
-            println("Overriding property '${key}' ('${oldval}') with ${file(propsFile).getName()} value '${val}'")
+          def oldval
+          if (project.hasProperty(key)) {
+            oldval = project.findProperty(key)
+            project.setProperty(key, val)
+            if (output) {
+              println("Overriding property '${key}' ('${oldval}') with ${file(propsFile).getName()} value '${val}'")
+            }
           } else {
-            println("Setting unknown property '${key}' with ${file(propsFile).getName()}s value '${val}'")
+            ext.setProperty(key, val)
+            if (output) {
+              println("Setting ext property '${key}' with ${file(propsFile).getName()}s value '${val}'")
+            }
           }
       }
     } catch (Exception e) {
-      System.out.println("Exception reading local.properties")
+      println("Exception reading local.properties")
+      e.printStackTrace()
     }
   }
+}
+
+ext {
+  jalviewDirAbsolutePath = file(jalviewDir).getAbsolutePath()
+  jalviewDirRelativePath = jalviewDir
+
+  getdownChannelName = CHANNEL.toLowerCase()
+  // default to "default". Currently only has different cosmetics for "develop", "release", "default"
+  propertiesChannelName = ["develop", "release", "test-release", "jalviewjs", "jalviewjs-release" ].contains(getdownChannelName) ? getdownChannelName : "default"
+  // Import channel_properties
+  channelDir = string("${jalviewDir}/${channel_properties_dir}/${propertiesChannelName}")
+  channelGradleProperties = string("${channelDir}/channel_gradle.properties")
+  channelPropsFile = string("${channelDir}/${resource_dir}/${channel_props}")
+  overrideProperties(channelGradleProperties, false)
+  // local build environment properties
+  // can be "projectDir/local.properties"
+  overrideProperties("${projectDir}/local.properties", true)
+  // or "../projectDir_local.properties"
+  overrideProperties(projectDir.getParent() + "/" + projectDir.getName() + "_local.properties", true)
 
   ////  
   // 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 {
@@ -147,6 +163,9 @@ ext {
   }
   */
 
+  // datestamp
+  buildDate = new Date().format("yyyyMMdd")
+
   // essentials
   bareSourceDir = string(source_dir)
   sourceDir = string("${jalviewDir}/${bareSourceDir}")
@@ -172,21 +191,27 @@ ext {
 
   getdownWebsiteDir = string("${jalviewDir}/${getdown_website_dir}/${JAVA_VERSION}")
   buildDist = true
+  buildProperties = null
 
   // the following values might be overridden by the CHANNEL switch
-  getdownChannelName = CHANNEL.toLowerCase()
   getdownDir = string("${getdownChannelName}/${JAVA_VERSION}")
   getdownAppBase = string("${getdown_channel_base}/${getdownDir}")
   getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher}")
   getdownAppDistDir = getdown_app_dir_alt
+  getdownImagesDir = string("${jalviewDir}/${getdown_images_dir}")
+  getdownSetAppBaseProperty = false // whether to pass the appbase and appdistdir to the application
   reportRsyncCommand = false
   jvlChannelName = CHANNEL.toLowerCase()
   install4jSuffix = CHANNEL.substring(0, 1).toUpperCase() + CHANNEL.substring(1).toLowerCase(); // BUILD -> Build
-  install4jDSStore = "DS_Store-NON-RELEASE"
-  install4jDMGBackgroundImage = "jalview_dmg_background-NON-RELEASE.png"
+  install4jDMGDSStore = "${install4j_images_dir}/${install4j_dmg_ds_store}"
+  install4jDMGBackgroundImage = "${install4j_images_dir}/${install4j_dmg_background}"
   install4jInstallerName = "${jalview_name} Non-Release Installer"
-  install4jExecutableName = jalview_name.replaceAll("[^\\w]+", "_").toLowerCase()
+  install4jExecutableName = install4j_executable_name
   install4jExtraScheme = "jalviewx"
+  install4jMacIconsFile = string("${install4j_images_dir}/${install4j_mac_icons_file}")
+  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}")
   switch (CHANNEL) {
 
     case "BUILD":
@@ -202,12 +227,10 @@ ext {
     install4jExtraScheme = "jalviewb"
     break
 
-    case "RELEASE":
+    case [ "RELEASE", "JALVIEWJS-RELEASE" ]:
     getdownAppDistDir = getdown_app_dir_release
     reportRsyncCommand = true
     install4jSuffix = ""
-    install4jDSStore = "DS_Store"
-    install4jDMGBackgroundImage = "jalview_dmg_background.png"
     install4jInstallerName = "${jalview_name} Installer"
     break
 
@@ -245,23 +268,13 @@ ext {
 
     case "DEVELOP":
     reportRsyncCommand = true
-    
+    getdownSetAppBaseProperty = true
     // DEVELOP-RELEASE is usually associated with a Jalview release series so set the version
-    JALVIEW_VERSION=JALVIEW_VERSION+"-develop"
+    JALVIEW_VERSION=JALVIEW_VERSION+"-d${buildDate}"
     
-    channelPropertiesFile = string("${channel_properties_dir}/develop_properties")
-    getdownImagesDir = "${getdown_images_dir}/develop"
-    getdownBgColour = "000000"
-    getdownFgColour = "FFFFFF"
-    getdownLightFgColour = "CCCCFF"
     install4jSuffix = "Develop"
-    install4jDSStore = "DS_Store-DEVELOP"
-    install4jDMGBackgroundImage = "jalview_dmg_background-DEVELOP.png"
     install4jExtraScheme = "jalviewd"
     install4jInstallerName = "${jalview_name} Develop Installer"
-    install4jMacIconsFile = string("${install4j_utils_dir}/develop/${install4j_mac_icons_file}")
-    install4jWindowsIconsFile = string("${install4j_utils_dir}/develop/${install4j_windows_icons_file}")
-    install4jPngIconFile = string("${install4j_utils_dir}/develop/${install4j_png_icon_file}")
     break
 
     case "TEST-RELEASE":
@@ -273,8 +286,6 @@ ext {
     }
     JALVIEW_VERSION = JALVIEW_VERSION+"-test"
     install4jSuffix = "Test"
-    install4jDSStore = "DS_Store-TEST-RELEASE"
-    install4jDMGBackgroundImage = "jalview_dmg_background-TEST.png"
     install4jExtraScheme = "jalviewt"
     install4jInstallerName = "${jalview_name} Test Installer"
     break
@@ -298,13 +309,11 @@ ext {
     }
     JALVIEW_VERSION = "TEST"
     install4jSuffix = "Test-Local"
-    install4jDSStore = "DS_Store-TEST-RELEASE"
-    install4jDMGBackgroundImage = "jalview_dmg_background-TEST.png"
     install4jExtraScheme = "jalviewt"
     install4jInstallerName = "${jalview_name} Test Installer"
     break
 
-    case "LOCAL":
+    case [ "LOCAL", "JALVIEWJS" ]:
     JALVIEW_VERSION = "TEST"
     getdownAppBase = file(getdownWebsiteDir).toURI().toString()
     getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher_local}")
@@ -318,7 +327,16 @@ ext {
   }
   // override getdownAppBase if requested
   if (findProperty("getdown_appbase_override") != null) {
-    getdownAppBase = string(getProperty("getdown_appbase_override"))
+    // revert to LOCAL if empty string
+    if (string(getdown_appbase_override) == "") {
+      getdownAppBase = file(getdownWebsiteDir).toURI().toString()
+      getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher_local}")
+    } else if (string(getdown_appbase_override).startsWith("file://")) {
+      getdownAppBase = string(getdown_appbase_override)
+      getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher_local}")
+    } else {
+      getdownAppBase = string(getdown_appbase_override)
+    }
     println("Overriding getdown appbase with '${getdownAppBase}'")
   }
   // sanitise file name for jalview launcher file for this channel
@@ -354,6 +372,7 @@ ext {
                                     .replaceAll("_*-_*", "-") // collapse _-_
                                     .toLowerCase()
 
+  getdownWrapperLink = install4jUnixApplicationFolder // e.g. "jalview_local"
   getdownAppDir = string("${getdownWebsiteDir}/${getdownAppDistDir}")
   //getdownJ11libDir = "${getdownWebsiteDir}/${getdown_j11lib_dir}"
   getdownResourceDir = string("${getdownWebsiteDir}/${getdown_resource_dir}")
@@ -364,9 +383,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.")
 
@@ -402,16 +433,16 @@ ext {
     '--add-modules', j11modules
     ]
      */
-  } else if (JAVA_VERSION.equals("12") || JAVA_VERSION.equals("13")) {
-    JAVA_INTEGER_VERSION = JAVA_VERSION
-    libDir = j11libDir
-    libDistDir = j11libDir
-    compile_source_compatibility = JAVA_VERSION
-    compile_target_compatibility = JAVA_VERSION
+  } else if (JAVA_VERSION.equals("17")) {
+    JAVA_INTEGER_VERSION = string("17")
+    libDir = j17libDir
+    libDistDir = j17libDir
+    compile_source_compatibility = 17
+    compile_target_compatibility = 17
     getdownAltJavaMinVersion = string(findProperty("getdown_alt_java11_min_version"))
     getdownAltJavaMaxVersion = string(findProperty("getdown_alt_java11_max_version"))
     getdownAltMultiJavaLocation = string(findProperty("getdown_alt_java11_txt_multi_java_location"))
-    eclipseJavaRuntimeName = string("JavaSE-11")
+    eclipseJavaRuntimeName = string("JavaSE-17")
     /* compile without modules -- using classpath libraries
     additional_compiler_args += [
     '--module-path', modules_compileClasspath.asPath,
@@ -431,11 +462,11 @@ ext {
     jreInstallsDir = System.getProperty("user.home") + jreInstallsDir.substring(1)
   }
   macosJavaVMDir = string("${jreInstallsDir}/jre-${JAVA_INTEGER_VERSION}-mac-x64/jre")
-  macosJavaVMTgz = string("${jreInstallsDir}/tgz/jre-${JAVA_INTEGER_VERSION}-mac-x64.tar.gz")
   windowsJavaVMDir = string("${jreInstallsDir}/jre-${JAVA_INTEGER_VERSION}-windows-x64/jre")
-  windowsJavaVMTgz = string("${jreInstallsDir}/tgz/jre-${JAVA_INTEGER_VERSION}-windows-x64.tar.gz")
   linuxJavaVMDir = string("${jreInstallsDir}/jre-${JAVA_INTEGER_VERSION}-linux-x64/jre")
-  linuxJavaVMTgz = string("${jreInstallsDir}/tgz/jre-${JAVA_INTEGER_VERSION}-linux-x64.tar.gz")
+  macosJavaVMTgz = string("${jreInstallsDir}/tgz/jre_${JAVA_INTEGER_VERSION}_mac_x64.tar.gz")
+  windowsJavaVMTgz = string("${jreInstallsDir}/tgz/jre_${JAVA_INTEGER_VERSION}_windows_x64.tar.gz")
+  linuxJavaVMTgz = string("${jreInstallsDir}/tgz/jre_${JAVA_INTEGER_VERSION}_linux_x64.tar.gz")
   install4jDir = string("${jalviewDir}/${install4j_utils_dir}")
   install4jConfFileName = string("jalview-install4j-conf.install4j")
   install4jConfFile = file("${install4jDir}/${install4jConfFileName}")
@@ -449,7 +480,9 @@ ext {
   helpBuildDir = string("${resourceBuildDir}/help_build")
   docBuildDir = string("${resourceBuildDir}/doc_build")
 
-  buildProperties = string("${resourcesBuildDir}/${build_properties_file}")
+  if (buildProperties == null) {
+    buildProperties = string("${resourcesBuildDir}/${build_properties_file}")
+  }
   buildingHTML = string("${jalviewDir}/${doc_dir}/building.html")
   helpParentDir = string("${jalviewDir}/${help_parent_dir}")
   helpSourceDir = string("${helpParentDir}/${help_dir}")
@@ -472,6 +505,7 @@ ext {
   jalviewjsCoreClasslists = []
   jalviewjsJalviewTemplateName = string(jalviewjs_name)
   jalviewjsJ2sSettingsFileName = string("${jalviewDir}/${jalviewjs_j2s_settings}")
+  jalviewjsJ2sAltSettingsFileName = string("${jalviewDir}/${jalviewjs_j2s_alt_settings}")
   jalviewjsJ2sProps = null
   jalviewjsJ2sPlugin = jalviewjs_j2s_plugin
 
@@ -1177,6 +1211,9 @@ task copyHelp(type: Copy) {
 
 
 task copyResources(type: Copy) {
+  group = "build"
+  description = "Copy (and make text substitutions in) the resources dir to the build area"
+
   def inputDir = resourceDir
   def outputDir = resourcesBuildDir
   from(inputDir) {
@@ -1205,6 +1242,19 @@ task copyResources(type: Copy) {
   outputs.dir(outputDir)
 }
 
+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 outputDir = resourcesBuildDir
+  from inputDir
+  into outputDir
+
+  inputs.dir(inputDir)
+  outputs.dir(outputDir)
+}
 
 task createBuildProperties(type: WriteProperties) {
   dependsOn copyResources
@@ -1220,6 +1270,10 @@ 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+"]"
+  if (getdownSetAppBaseProperty) {
+    property "GETDOWNAPPBASE", getdownAppBase
+    property "GETDOWNAPPDISTDIR", getdownAppDistDir
+  }
   outputs.file(outputFile)
 }
 
@@ -1243,12 +1297,16 @@ task buildIndices(type: JavaExec) {
   outputs.file("${workingDir}/JavaHelpSearch/TMAP")
 }
 
+task buildResources {
+  dependsOn copyResources
+  dependsOn copyChannelResources
+  dependsOn createBuildProperties
+}
 
 task prepare {
-  dependsOn copyResources
+  dependsOn buildResources
   dependsOn copyDocs
   dependsOn copyHelp
-  dependsOn createBuildProperties
   dependsOn convertMdFiles
   dependsOn buildIndices
 }
@@ -1284,6 +1342,11 @@ test {
     println("Setting Test LaF to '${testLaf}'")
     systemProperty "laf", testLaf
   }
+  def testHiDPIScale = project.findProperty("test_HiDPIScale")
+  if (testHiDPIScale != null) {
+    println("Setting Test HiDPI Scale to '${testHiDPIScale}'")
+    systemProperty "sun.java2d.uiScale", testHiDPIScale
+  }
   sourceCompatibility = compile_source_compatibility
   targetCompatibility = compile_target_compatibility
   jvmArgs += additional_compiler_args
@@ -1320,13 +1383,12 @@ task linkCheck(type: JavaExec) {
   args = [ "${helpBuildDir}/${help_dir}", "-nointernet" ]
 
   def outFOS = new FileOutputStream(helpLinksCheckerOutFile, false) // false == don't append
-  def errFOS = outFOS
   standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
     outFOS,
-    standardOutput)
+    System.out)
   errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
     outFOS,
-    errorOutput)
+    System.err)
 
   inputs.dir(helpBuildDir)
   outputs.file(helpLinksCheckerOutFile)
@@ -1358,8 +1420,11 @@ jar {
     "Implementation-Version": JALVIEW_VERSION
   }
 
-  destinationDirectory = file("${jalviewDir}/${package_dir}")
+  def outputDir = "${jalviewDir}/${package_dir}"
+  destinationDirectory = file(outputDir)
   archiveFileName = rootProject.name+".jar"
+  duplicatesStrategy "EXCLUDE"
+
 
   exclude "cache*/**"
   exclude "*.jar"
@@ -1371,7 +1436,7 @@ jar {
   sourceSets.main.resources.srcDirs.each{ dir ->
     inputs.dir(dir)
   }
-  outputs.file("${destinationDirectory}/${archiveFileName}")
+  outputs.file("${outputDir}/${archiveFileName}")
 }
 
 
@@ -1425,6 +1490,9 @@ shadowJar {
     attributes "Implementation-Version": JALVIEW_VERSION,
     "Application-Name": install4jApplicationName
   }
+
+  duplicatesStrategy "INCLUDE"
+
   mainClassName = shadow_jar_main_class
   mergeServiceFiles()
   classifier = "all-"+JALVIEW_VERSION+"-j"+JAVA_VERSION
@@ -1451,11 +1519,17 @@ task getdownWebsite() {
 
     copy {
       from buildProperties
-      rename(build_properties_file, getdown_build_properties)
+      rename(file(buildProperties).getName(), getdown_build_properties)
       into getdownAppDir
     }
     getdownWebsiteResourceFilenames += "${getdownAppDistDir}/${getdown_build_properties}"
 
+    copy {
+      from channelPropsFile
+      into getdownWebsiteDir
+    }
+    getdownWebsiteResourceFilenames += file(channelPropsFile).getName()
+
     // set some getdown_txt_ properties then go through all properties looking for getdown_txt_...
     def props = project.properties.sort { it.key }
     if (getdownAltJavaMinVersion != null && getdownAltJavaMinVersion.length() > 0) {
@@ -1467,6 +1541,14 @@ task getdownWebsite() {
     if (getdownAltMultiJavaLocation != null && getdownAltMultiJavaLocation.length() > 0) {
       props.put("getdown_txt_multi_java_location", getdownAltMultiJavaLocation)
     }
+    if (getdownImagesDir != null && file(getdownImagesDir).exists()) {
+      props.put("getdown_txt_ui.background_image", "${getdownImagesDir}/${getdown_background_image}")
+      props.put("getdown_txt_ui.instant_background_image", "${getdownImagesDir}/${getdown_instant_background_image}")
+      props.put("getdown_txt_ui.error_background", "${getdownImagesDir}/${getdown_error_background}")
+      props.put("getdown_txt_ui.progress_image", "${getdownImagesDir}/${getdown_progress_image}")
+      props.put("getdown_txt_ui.icon", "${getdownImagesDir}/${getdown_icon}")
+      props.put("getdown_txt_ui.mac_dock_icon", "${getdownImagesDir}/${getdown_mac_dock_icon}")
+    }
 
     props.put("getdown_txt_title", jalview_name)
     props.put("getdown_txt_ui.name", install4jApplicationName)
@@ -1515,6 +1597,18 @@ task getdownWebsite() {
         into getdownResourceDir
       }
     }
+    
+    def getdownWrapperScripts = [ getdown_bash_wrapper_script, getdown_powershell_wrapper_script, getdown_batch_wrapper_script ]
+    getdownWrapperScripts.each{ script ->
+      def s = file( "${jalviewDir}/utils/getdown/${getdown_wrapper_script_dir}/${script}" )
+      if (s.exists()) {
+        copy {
+          from s
+          into "${getdownWebsiteDir}/${getdown_wrapper_script_dir}"
+        }
+        getdownTextString += "resource = ${getdown_wrapper_script_dir}/${script}\n"
+      }
+    }
 
     def codeFiles = []
     fileTree(file(package_dir)).each{ f ->
@@ -1525,7 +1619,9 @@ task getdownWebsite() {
         codeFiles += f
       }
     }
-    codeFiles.sort().each{f ->
+    def jalviewJar = jar.archiveFileName.getOrNull()
+    // put jalview.jar first for CLASSPATH and .properties files reasons
+    codeFiles.sort{a, b -> ( a.getName() == jalviewJar ? -1 : ( b.getName() == jalviewJar ? 1 : a <=> b ) ) }.each{f ->
       def name = f.getName()
       def line = "code = ${getdownAppDistDir}/${name}\n"
       getdownTextString += line
@@ -1555,6 +1651,11 @@ task getdownWebsite() {
     //getdownTextString += "class = " + file(getdownLauncher).getName() + "\n"
     getdownTextString += "resource = ${getdown_launcher_new}\n"
     getdownTextString += "class = ${main_class}\n"
+    // Not setting these properties in general so that getdownappbase and getdowndistdir will default to release version in jalview.bin.Cache
+    if (getdownSetAppBaseProperty) {
+      getdownTextString += "jvmarg = -Dgetdowndistdir=${getdownAppDistDir}\n"
+      getdownTextString += "jvmarg = -Dgetdownappbase=${getdownAppBase}\n"
+    }
 
     def getdown_txt = file("${getdownWebsiteDir}/getdown.txt")
     getdown_txt.write(getdownTextString)
@@ -1563,12 +1664,14 @@ task getdownWebsite() {
     def launchJvl = file("${getdownWebsiteDir}/${getdownLaunchJvl}")
     launchJvl.write("appbase=${getdownAppBase}")
 
+    // files going into the getdown website dir: getdown-launcher.jar
     copy {
       from getdownLauncher
       rename(file(getdownLauncher).getName(), getdown_launcher_new)
       into getdownWebsiteDir
     }
 
+    // files going into the getdown website dir: getdown-launcher(-local).jar
     copy {
       from getdownLauncher
       if (file(getdownLauncher).getName() != getdown_launcher) {
@@ -1577,34 +1680,39 @@ task getdownWebsite() {
       into getdownWebsiteDir
     }
 
+    // files going into the getdown website dir: ./install dir and files
     if (! (CHANNEL.startsWith("ARCHIVE") || CHANNEL.startsWith("DEVELOP"))) {
       copy {
         from getdown_txt
         from getdownLauncher
-        from "${getdownWebsiteDir}/${getdown_build_properties}"
+        from "${getdownAppDir}/${getdown_build_properties}"
         if (file(getdownLauncher).getName() != getdown_launcher) {
           rename(file(getdownLauncher).getName(), getdown_launcher)
         }
         into getdownInstallDir
       }
 
+      // and make a copy in the getdown files dir (these are not downloaded by getdown)
       copy {
         from getdownInstallDir
         into getdownFilesInstallDir
       }
     }
 
+    // files going into the getdown files dir: getdown.txt, getdown-launcher.jar, channel-launch.jvl, build_properties
     copy {
       from getdown_txt
       from launchJvl
       from getdownLauncher
       from "${getdownWebsiteDir}/${getdown_build_properties}"
+      from "${getdownWebsiteDir}/${channel_props}"
       if (file(getdownLauncher).getName() != getdown_launcher) {
         rename(file(getdownLauncher).getName(), getdown_launcher)
       }
       into getdownFilesDir
     }
 
+    // and ./resources (not all downloaded by getdown)
     copy {
       from getdownResourceDir
       into "${getdownFilesDir}/${getdown_resource_dir}"
@@ -1722,6 +1830,12 @@ task copyInstall4jTemplate {
       }
     }
 
+    // disable install screen for OSX dmg (for 2.11.2.0)
+    install4jConfigXml.'**'.macosArchive.each { macosArchive -> 
+      macosArchive.attributes().remove('executeSetupApp')
+      macosArchive.attributes().remove('setupAppId')
+    }
+
     // turn off checksum creation for LOCAL channel
     def e = install4jConfigXml.application[0]
     if (CHANNEL == "LOCAL") {
@@ -1769,12 +1883,6 @@ task copyInstall4jTemplate {
       }
     }
 
-    // remove the "Uninstall Old Jalview (optional)" symlink from DMG for non-release DS_Stores
-    if (! (CHANNEL == "RELEASE" || CHANNEL == "TEST-RELEASE" ) ) {
-      def symlink = install4jConfigXml.'**'.topLevelFiles.symlink.find { sl -> sl.'@name' == "Uninstall Old Jalview (optional).app" }
-      symlink.parent().remove(symlink)
-    }
-
     // write install4j file
     install4jConfFile.text = XmlUtil.serialize(install4jConfigXml)
   }
@@ -1815,6 +1923,8 @@ task installers(type: com.install4j.gradle.Install4jTask) {
     'JALVIEW_APPLICATION_NAME': install4jApplicationName,
     'JALVIEW_DIR': "../..",
     'OSX_KEYSTORE': OSX_KEYSTORE,
+    'OSX_APPLEID': OSX_APPLEID,
+    'OSX_ALTOOLPASS': OSX_ALTOOLPASS,
     'JSIGN_SH': JSIGN_SH,
     'JRE_DIR': getdown_app_dir_java,
     'INSTALLER_TEMPLATE_VERSION': install4jTemplateVersion,
@@ -1834,8 +1944,12 @@ task installers(type: com.install4j.gradle.Install4jTask) {
     'BUNDLE_ID': install4jBundleId,
     'INTERNAL_ID': install4jInternalId,
     'WINDOWS_APPLICATION_ID': install4jWinApplicationId,
-    'MACOS_DS_STORE': install4jDSStore,
+    'MACOS_DMG_DS_STORE': install4jDMGDSStore,
     'MACOS_DMG_BG_IMAGE': install4jDMGBackgroundImage,
+    'WRAPPER_LINK': getdownWrapperLink,
+    'BASH_WRAPPER_SCRIPT': getdown_bash_wrapper_script,
+    'POWERSHELL_WRAPPER_SCRIPT': getdown_powershell_wrapper_script,
+    'WRAPPER_SCRIPT_BIN_DIR': getdown_wrapper_script_dir,
     'INSTALLER_NAME': install4jInstallerName,
     'INSTALL4J_UTILS_DIR': install4j_utils_dir,
     'GETDOWN_WEBSITE_DIR': getdown_website_dir,
@@ -1851,6 +1965,11 @@ task installers(type: com.install4j.gradle.Install4jTask) {
     'UNIX_APPLICATION_FOLDER': install4jUnixApplicationFolder,
     'EXECUTABLE_NAME': install4jExecutableName,
     'EXTRA_SCHEME': install4jExtraScheme,
+    'MAC_ICONS_FILE': install4jMacIconsFile,
+    'WINDOWS_ICONS_FILE': install4jWindowsIconsFile,
+    'PNG_ICON_FILE': install4jPngIconFile,
+    'BACKGROUND': install4jBackground,
+
   ]
 
   //println("INSTALL4J VARIABLES:")
@@ -1862,15 +1981,25 @@ task installers(type: com.install4j.gradle.Install4jTask) {
   if (install4j_faster.equals("true") || CHANNEL.startsWith("LOCAL")) {
     faster = true
     disableSigning = true
+    disableNotarization = true
   }
 
   if (OSX_KEYPASS) {
     macKeystorePassword = OSX_KEYPASS
+  } 
+  
+  if (OSX_ALTOOLPASS) {
+    appleIdPassword = OSX_ALTOOLPASS
+    disableNotarization = false
+  } else {
+    disableNotarization = true
   }
 
   doFirst {
     println("Using projectFile "+projectFile)
+    if (!disableNotarization) { println("Will notarize OSX App DMG") }
   }
+  //verbose=true
 
   inputs.dir(getdownWebsiteDir)
   inputs.file(install4jConfFile)
@@ -1887,12 +2016,32 @@ 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"
   description "Create a source .tar.gz file for distribution"
-  
+
+  dependsOn createBuildProperties
   dependsOn convertMdFiles
+  dependsOn eclipseAllPreferences
+  dependsOn createSourceReleaseProperties
+
 
   def VERSION_UNDERSCORES = JALVIEW_VERSION.replaceAll("\\.", "_")
   def outputFileName = "${project.name}_${VERSION_UNDERSCORES}.tar.gz"
@@ -1917,6 +2066,7 @@ task sourceDist(type: Tar) {
     "*locales/**",
     "utils/InstallAnywhere",
     "**/*.log",
+    "RELEASE",
   ] 
   def PROCESS_FILES=[
     "AUTHORS",
@@ -1926,7 +2076,6 @@ task sourceDist(type: Tar) {
     "FEATURETODO",
     "LICENSE",
     "**/README",
-    "RELEASE",
     "THIRDPARTYLIBS",
     "TESTNG",
     "build.gradle",
@@ -1941,7 +2090,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) {
@@ -1979,6 +2130,19 @@ task sourceDist(type: Tar) {
 //    exclude(EXCLUDE_FILES)
 //    exclude(PROCESS_FILES)
 //  }
+
+  from(file(buildProperties).getParent()) {
+    include(file(buildProperties).getName())
+    rename(file(buildProperties).getName(), "build_properties")
+    filter({ line ->
+      line.replaceAll("^INSTALLATION=.*\$","INSTALLATION=Source Release"+" git-commit\\\\:"+gitHash+" ["+gitBranch+"]")
+    })
+  }
+
+  def sourceTarBuildDir = "${buildDir}/sourceTar"
+  from(sourceTarBuildDir) {
+    // this includes the appended RELEASE properties file
+  }
 }
 
 
@@ -1998,6 +2162,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
@@ -2210,7 +2401,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"
@@ -2229,11 +2420,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)
   }
 }
 
@@ -2261,13 +2452,19 @@ task jalviewjsSyncAllLibs (type: Sync) {
   preserve {
     include "**"
   }
+
+  // should this be exclude really ?
+  duplicatesStrategy "INCLUDE"
+
   outputs.files outputFiles
   inputs.files inputFiles
 }
 
 
 task jalviewjsSyncResources (type: Sync) {
-  def inputFiles = fileTree(dir: resourceDir)
+  dependsOn buildResources
+
+  def inputFiles = fileTree(dir: resourcesBuildDir)
   def outputDir = "${jalviewDir}/${jalviewjsSiteDir}/${jalviewjs_j2s_subdir}"
 
   from inputFiles
@@ -2349,6 +2546,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")
@@ -2362,6 +2560,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
@@ -2381,6 +2582,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
@@ -2408,12 +2610,12 @@ DEBUG: ${eclipseDebug}
         new org.apache.tools.ant.util.TeeOutputStream(
           logOutFOS,
           stdout),
-        standardOutput)
+        System.out)
       errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
         new org.apache.tools.ant.util.TeeOutputStream(
           logErrFOS,
           stderr),
-        errorOutput)
+        System.err)
     } else {
       standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
         logOutFOS,
@@ -2501,7 +2703,7 @@ def jalviewjsCallCore(String name, FileCollection list, String prefixFile, Strin
           new org.apache.tools.ant.util.TeeOutputStream(
             logErrFOS,
             stderr),
-          errorOutput)
+          System.err)
     } else {
       standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
         logOutFOS,
@@ -2808,7 +3010,13 @@ task jalviewjsServer {
   def htmlFile = "${jalviewDirAbsolutePath}/${filename}"
   doLast {
 
-    SimpleHttpFileServerFactory factory = new SimpleHttpFileServerFactory()
+    def factory
+    try {
+      def f = Class.forName("org.gradle.plugins.javascript.envjs.http.simple.SimpleHttpFileServerFactory")
+      factory = f.newInstance()
+    } catch (ClassNotFoundException e) {
+      throw new GradleException("Unable to create SimpleHttpFileServerFactory")
+    }
     def port = Integer.valueOf(jalviewjs_server_port)
     def start = port
     def running = false
@@ -2861,7 +3069,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 } )