JAL-3543 remove debugging output
[jalview.git] / build.gradle
1 import org.apache.tools.ant.filters.ReplaceTokens
2 import org.gradle.internal.os.OperatingSystem
3 import org.gradle.plugins.ide.eclipse.model.Output
4 import org.gradle.plugins.ide.eclipse.model.Library
5 import java.security.MessageDigest
6 import groovy.transform.ExternalizeMethods
7 import groovy.util.XmlParser
8 import groovy.xml.XmlUtil
9
10 buildscript {
11   dependencies {
12     classpath 'org.openclover:clover:4.4.1'
13   }
14 }
15
16 plugins {
17   id 'java'
18   id 'application'
19   id 'eclipse'
20   id 'com.github.johnrengelman.shadow' version '4.0.3'
21   id 'com.install4j.gradle' version '8.0.2'
22   id 'com.dorongold.task-tree' version '1.5' // only needed to display task dependency tree with  gradle task1 [task2 ...] taskTree
23 }
24
25 repositories {
26   jcenter()
27   mavenCentral()
28   mavenLocal()
29   flatDir {
30     dirs gradlePluginsDir
31   }
32 }
33
34 dependencies {
35 }
36
37
38 // in ext the values are cast to Object. Ensure string values are cast as String (and not GStringImpl) for later use
39 def string(Object o) {
40   return o == null ? "" : o.toString()
41 }
42
43
44 ext {
45   jalviewDirAbsolutePath = file(jalviewDir).getAbsolutePath()
46   jalviewDirRelativePath = jalviewDir
47
48   // local build environment properties
49   def localProps = "${jalviewDirAbsolutePath}/local.properties"
50   if (file(localProps).exists()) {
51     try {
52       def p = new Properties()
53       def localPropsFIS = new FileInputStream(localProps)
54       p.load(localPropsFIS)
55       localPropsFIS.close()
56       p.each {
57         key, val -> 
58           def oldval = findProperty(key)
59           setProperty(key, val)
60           if (oldval != null) {
61             println("Overriding property '${key}' ('${oldval}') with local.properties value '${val}'")
62           } else {
63             println("Setting unknown property '${key}' with local.properties value '${val}'")
64           }
65       }
66     } catch (Exception e) {
67       System.out.println("Exception reading local.properties")
68     }
69   }
70
71   // this property set when running Eclipse headlessly
72   j2sHeadlessBuildProperty = string("net.sf.j2s.core.headlessbuild")
73   // this property set by Eclipse
74   eclipseApplicationProperty = string("eclipse.application")
75   // CHECK IF RUNNING FROM WITHIN ECLIPSE
76   def eclipseApplicationPropertyVal = System.properties[eclipseApplicationProperty]
77   IN_ECLIPSE = eclipseApplicationPropertyVal != null && eclipseApplicationPropertyVal.startsWith("org.eclipse.ui.")
78   // BUT WITHOUT THE HEADLESS BUILD PROPERTY SET
79   if (System.properties[j2sHeadlessBuildProperty].equals("true")) {
80     println("Setting IN_ECLIPSE to ${IN_ECLIPSE} as System.properties['${j2sHeadlessBuildProperty}'] == '${System.properties[j2sHeadlessBuildProperty]}'")
81     IN_ECLIPSE = false
82   }
83   if (IN_ECLIPSE) {
84     println("WITHIN ECLIPSE IDE")
85   } else {
86     println("HEADLESS BUILD")
87   }
88   /* *-/
89   System.properties.sort { it.key }.each {
90     key, val -> println("SYSTEM PROPERTY ${key}='${val}'")
91   }
92   /-* *-/
93   if (false && IN_ECLIPSE) {
94     jalviewDir = jalviewDirAbsolutePath
95   }
96   */
97
98   // essentials
99   bareSourceDir = string(source_dir)
100   sourceDir = string("${jalviewDir}/${bareSourceDir}")
101   resourceDir = string("${jalviewDir}/${resource_dir}")
102   bareTestSourceDir = string(test_source_dir)
103   testSourceDir = string("${jalviewDir}/${bareTestSourceDir}")
104
105   // clover
106   cloverInstrDir = file("${buildDir}/${cloverSourcesInstrDir}")
107   classesDir = string("${jalviewDir}/${classes_dir}")
108   if (clover.equals("true")) {
109     use_clover = true
110     classesDir = string("${buildDir}/${cloverClassesDir}")
111   } else {
112     use_clover = false
113     classesDir = string("${jalviewDir}/${classes_dir}")
114   }
115
116   classes = classesDir
117
118   getdownWebsiteDir = string("${jalviewDir}/${getdown_website_dir}/${JAVA_VERSION}")
119   buildDist = true
120
121   // the following values might be overridden by the CHANNEL switch
122   getdownChannelName = CHANNEL.toLowerCase()
123   getdownDir = string("${getdownChannelName}/${JAVA_VERSION}")
124   getdownAppBase = string("${getdown_channel_base}/${getdownDir}")
125   getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher}")
126   getdownAppDistDir = getdown_app_dir_alt
127   buildProperties = string("${classesDir}/${build_properties_file}")
128   reportRsyncCmd = false
129   jvlChannelName = CHANNEL.toLowerCase()
130   switch (CHANNEL) {
131
132     case "BUILD":
133     // TODO: get bamboo build artifact URL for getdown artifacts
134     getdown_channel_base = bamboo_channelbase
135     getdownChannelName = string("${bamboo_planKey}/${JAVA_VERSION}")
136     getdownAppBase = string("${bamboo_channelbase}/${bamboo_planKey}${bamboo_getdown_channel_suffix}/${JAVA_VERSION}")
137     jvlChannelName += "_${getdownChannelName}"
138     break
139
140     case "RELEASE":
141     getdownAppDistDir = getdown_app_dir_release
142     reportRsyncCommand = true
143     break
144
145     case "ARCHIVE":
146     getdownChannelName = CHANNEL.toLowerCase()+"/${JALVIEW_VERSION}"
147     getdownDir = string("${getdownChannelName}/${JAVA_VERSION}")
148     getdownAppBase = string("${getdown_channel_base}/${getdownDir}")
149     if (!file("${ARCHIVEDIR}/${packageDir}").exists()) {
150       throw new GradleException("Must provide an ARCHIVEDIR value to produce an archive distribution")
151     } else {
152       packageDir = string("${ARCHIVEDIR}/${packageDir}")
153       buildProperties = string("${ARCHIVEDIR}/${classes_dir}/${build_properties_file}")
154       buildDist = false
155     }
156     reportRsyncCommand = true
157     break
158
159     case "ARCHIVELOCAL":
160     getdownChannelName = string("archive/${JALVIEW_VERSION}")
161     getdownDir = string("${getdownChannelName}/${JAVA_VERSION}")
162     getdownAppBase = file(getdownWebsiteDir).toURI().toString()
163     if (!file("${ARCHIVEDIR}/${packageDir}").exists()) {
164       throw new GradleException("Must provide an ARCHIVEDIR value to produce an archive distribution")
165     } else {
166       packageDir = string("${ARCHIVEDIR}/${packageDir}")
167       buildProperties = string("${ARCHIVEDIR}/${classes_dir}/${build_properties_file}")
168       buildDist = false
169     }
170     reportRsyncCommand = true
171     getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher_local}")
172     break
173
174     case "DEVELOP":
175     reportRsyncCommand = true
176     break
177
178     case "TEST-RELEASE":
179     reportRsyncCommand = true
180     break
181
182     case ~/^SCRATCH(|-[-\w]*)$/:
183     getdownChannelName = CHANNEL
184     getdownDir = string("${getdownChannelName}/${JAVA_VERSION}")
185     getdownAppBase = string("${getdown_channel_base}/${getdownDir}")
186     reportRsyncCommand = true
187     break
188
189     case "TEST-LOCAL":
190     if (!file("${LOCALDIR}").exists()) {
191       throw new GradleException("Must provide a LOCALDIR value to produce a local distribution")
192     } else {
193       getdownAppBase = file(file("${LOCALDIR}").getAbsolutePath()).toURI().toString()
194       getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher_local}")
195     }
196     break
197
198     case "LOCAL":
199     getdownAppBase = file(getdownWebsiteDir).toURI().toString()
200     getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher_local}")
201     break
202
203     default: // something wrong specified
204     throw new GradleException("CHANNEL must be one of BUILD, RELEASE, ARCHIVE, DEVELOP, TEST-RELEASE, SCRATCH-..., LOCAL [default]")
205     break
206
207   }
208   // override getdownAppBase if requested
209   if (findProperty("getdown_appbase_override") != null) {
210     getdownAppBase = string(getProperty("getdown_appbase_override"))
211     println("Overriding getdown appbase with '${getdownAppBase}'")
212   }
213   // sanitise file name for jalview launcher file for this channel
214   jvlChannelName = jvlChannelName.replaceAll(/[^\w\-]/,"_")
215
216   getdownAppDir = string("${getdownWebsiteDir}/${getdownAppDistDir}")
217   //getdownJ11libDir = "${getdownWebsiteDir}/${getdown_j11lib_dir}"
218   getdownResourceDir = string("${getdownWebsiteDir}/${getdown_resource_dir}")
219   getdownInstallDir = string("${getdownWebsiteDir}/${getdown_install_dir}")
220   getdownFilesDir = string("${jalviewDir}/${getdown_files_dir}/${JAVA_VERSION}/")
221   getdownFilesInstallDir = string("${getdownFilesDir}/${getdown_install_dir}")
222   /* compile without modules -- using classpath libraries
223   modules_compileClasspath = fileTree(dir: "${jalviewDir}/${j11modDir}", include: ["*.jar"])
224   modules_runtimeClasspath = modules_compileClasspath
225   */
226   gitHash = string("")
227   gitBranch = string("")
228
229   println("Using a ${CHANNEL} profile.")
230
231   additional_compiler_args = []
232   // configure classpath/args for j8/j11 compilation
233   if (JAVA_VERSION.equals("1.8")) {
234     JAVA_INTEGER_VERSION = string("8")
235     //libDir = j8libDir
236     libDir = j11libDir
237     libDistDir = j8libDir
238     compile_source_compatibility = 1.8
239     compile_target_compatibility = 1.8
240     // these are getdown.txt properties defined dependent on the JAVA_VERSION
241     getdownAltJavaMinVersion = string(findProperty("getdown_alt_java8_min_version"))
242     getdownAltJavaMaxVersion = string(findProperty("getdown_alt_java8_max_version"))
243     // this property is assigned below and expanded to multiple lines in the getdown task
244     getdownAltMultiJavaLocation = string(findProperty("getdown_alt_java8_txt_multi_java_location"))
245     // this property is for the Java library used in eclipse
246     eclipseJavaRuntimeName = string("JavaSE-1.8")
247   } else if (JAVA_VERSION.equals("11")) {
248     JAVA_INTEGER_VERSION = string("11")
249     libDir = j11libDir
250     libDistDir = j11libDir
251     compile_source_compatibility = 11
252     compile_target_compatibility = 11
253     getdownAltJavaMinVersion = string(findProperty("getdown_alt_java11_min_version"))
254     getdownAltJavaMaxVersion = string(findProperty("getdown_alt_java11_max_version"))
255     getdownAltMultiJavaLocation = string(findProperty("getdown_alt_java11_txt_multi_java_location"))
256     eclipseJavaRuntimeName = string("JavaSE-11")
257     /* compile without modules -- using classpath libraries
258     additional_compiler_args += [
259     '--module-path', modules_compileClasspath.asPath,
260     '--add-modules', j11modules
261     ]
262      */
263   } else if (JAVA_VERSION.equals("12") || JAVA_VERSION.equals("13")) {
264     JAVA_INTEGER_VERSION = JAVA_VERSION
265     libDir = j11libDir
266     libDistDir = j11libDir
267     compile_source_compatibility = JAVA_VERSION
268     compile_target_compatibility = JAVA_VERSION
269     getdownAltJavaMinVersion = string(findProperty("getdown_alt_java11_min_version"))
270     getdownAltJavaMaxVersion = string(findProperty("getdown_alt_java11_max_version"))
271     getdownAltMultiJavaLocation = string(findProperty("getdown_alt_java11_txt_multi_java_location"))
272     eclipseJavaRuntimeName = string("JavaSE-11")
273     /* compile without modules -- using classpath libraries
274     additional_compiler_args += [
275     '--module-path', modules_compileClasspath.asPath,
276     '--add-modules', j11modules
277     ]
278      */
279   } else {
280     throw new GradleException("JAVA_VERSION=${JAVA_VERSION} not currently supported by Jalview")
281   }
282
283
284   // for install4j
285   JAVA_MIN_VERSION = JAVA_VERSION
286   JAVA_MAX_VERSION = JAVA_VERSION
287   def jreInstallsDir = string(jre_installs_dir)
288   if (jreInstallsDir.startsWith("~/")) {
289     jreInstallsDir = System.getProperty("user.home") + jreInstallsDir.substring(1)
290   }
291   macosJavaVMDir = string("${jreInstallsDir}/jre-${JAVA_INTEGER_VERSION}-mac-x64/jre")
292   macosJavaVMTgz = string("${jreInstallsDir}/tgz/jre-${JAVA_INTEGER_VERSION}-mac-x64.tar.gz")
293   windowsJavaVMDir = string("${jreInstallsDir}/jre-${JAVA_INTEGER_VERSION}-windows-x64/jre")
294   windowsJavaVMTgz = string("${jreInstallsDir}/tgz/jre-${JAVA_INTEGER_VERSION}-windows-x64.tar.gz")
295   linuxJavaVMDir = string("${jreInstallsDir}/jre-${JAVA_INTEGER_VERSION}-linux-x64/jre")
296   linuxJavaVMTgz = string("${jreInstallsDir}/tgz/jre-${JAVA_INTEGER_VERSION}-linux-x64.tar.gz")
297   install4jDir = string("${jalviewDir}/${install4j_utils_dir}")
298   install4jConfFileName = string("jalview-install4j-conf.install4j")
299   install4jConfFile = file("${install4jDir}/${install4jConfFileName}")
300   install4jHomeDir = install4j_home_dir
301   if (install4jHomeDir.startsWith("~/")) {
302     install4jHomeDir = System.getProperty("user.home") + install4jHomeDir.substring(1)
303   }
304
305
306
307   buildingHTML = string("${jalviewDir}/${docDir}/building.html")
308   helpFile = string("${classesDir}/${help_dir}/help.jhm")
309   helpParentDir = string("${jalviewDir}/${help_parent_dir}")
310   helpSourceDir = string("${helpParentDir}/${help_dir}")
311
312
313   relativeBuildDir = file(jalviewDirAbsolutePath).toPath().relativize(buildDir.toPath())
314   jalviewjsBuildDir = string("${relativeBuildDir}/jalviewjs")
315   jalviewjsSiteDir = string("${jalviewjsBuildDir}/${jalviewjs_site_dir}")
316   if (IN_ECLIPSE) {
317     jalviewjsTransferSiteJsDir = string(jalviewjsSiteDir)
318   } else {
319     jalviewjsTransferSiteJsDir = string("${jalviewjsBuildDir}/tmp/${jalviewjs_site_dir}_js")
320   }
321   jalviewjsTransferSiteLibDir = string("${jalviewjsBuildDir}/tmp/${jalviewjs_site_dir}_lib")
322   jalviewjsTransferSiteSwingJsDir = string("${jalviewjsBuildDir}/tmp/${jalviewjs_site_dir}_swingjs")
323   jalviewjsTransferSiteCoreDir = string("${jalviewjsBuildDir}/tmp/${jalviewjs_site_dir}_core")
324   jalviewjsJalviewCoreHtmlFile = string("")
325   jalviewjsJalviewCoreName = string(jalviewjs_core_name)
326   jalviewjsCoreClasslists = []
327   jalviewjsJalviewTemplateName = string(jalviewjs_name)
328   jalviewjsJ2sSettingsFileName = string("${jalviewDir}/${jalviewjs_j2s_settings}")
329   jalviewjsJ2sProps = null
330
331   eclipseWorkspace = null
332   eclipseBinary = string("")
333   eclipseVersion = string("")
334   eclipseDebug = false
335   // ENDEXT
336 }
337
338
339 sourceSets {
340   main {
341     java {
342       srcDirs sourceDir
343       outputDir = file(classesDir)
344     }
345
346     resources {
347       srcDirs resourceDir
348       srcDirs += helpParentDir
349     }
350
351     jar.destinationDir = file("${jalviewDir}/${packageDir}")
352
353     compileClasspath = files(sourceSets.main.java.outputDir)
354     //compileClasspath += files(sourceSets.main.resources.srcDirs)
355     compileClasspath += fileTree(dir: "${jalviewDir}/${libDir}", include: ["*.jar"])
356
357     runtimeClasspath = compileClasspath
358   }
359
360   clover {
361     java {
362       srcDirs = [ cloverInstrDir ]
363       outputDir = file("${buildDir}/${cloverClassesDir}")
364     }
365
366     resources {
367       srcDirs = sourceSets.main.resources.srcDirs
368     }
369     compileClasspath = configurations.cloverRuntime + files( sourceSets.clover.java.outputDir )
370     compileClasspath += files(sourceSets.main.java.outputDir)
371     compileClasspath += sourceSets.main.compileClasspath
372     compileClasspath += fileTree(dir: "${jalviewDir}/${utilsDir}", include: ["**/*.jar"])
373     compileClasspath += fileTree(dir: "${jalviewDir}/${libDir}", include: ["*.jar"])
374
375     runtimeClasspath = compileClasspath
376   }
377
378   test {
379     java {
380       srcDirs testSourceDir
381       outputDir = file("${jalviewDir}/${testOutputDir}")
382     }
383
384     resources {
385       srcDirs = sourceSets.main.resources.srcDirs
386     }
387
388     compileClasspath = files( sourceSets.test.java.outputDir )
389
390     if (use_clover) {
391       compileClasspath = sourceSets.clover.compileClasspath
392     } else {
393       compileClasspath += files(sourceSets.main.java.outputDir)
394     }
395
396     compileClasspath += fileTree(dir: "${jalviewDir}/${libDir}", include: ["*.jar"])
397     compileClasspath += fileTree(dir: "${jalviewDir}/${utilsDir}/testnglibs", include: ["**/*.jar"])
398     compileClasspath += fileTree(dir: "${jalviewDir}/${utilsDir}/testlibs", include: ["**/*.jar"])
399
400     runtimeClasspath = compileClasspath
401   }
402 }
403
404
405 // clover bits
406 dependencies {
407   if (use_clover) {
408     cloverCompile 'org.openclover:clover:4.4.1'
409     testCompile 'org.openclover:clover:4.4.1'
410   }
411 }
412
413
414 configurations {
415   cloverRuntime
416   cloverRuntime.extendsFrom cloverCompile
417 }
418
419 eclipse {
420   project {
421     name = eclipse_project_name
422
423     natures 'org.eclipse.jdt.core.javanature',
424     'org.eclipse.jdt.groovy.core.groovyNature',
425     'org.eclipse.buildship.core.gradleprojectnature'
426
427     buildCommand 'org.eclipse.jdt.core.javabuilder'
428     buildCommand 'org.eclipse.buildship.core.gradleprojectbuilder'
429   }
430
431   classpath {
432     //defaultOutputDir = sourceSets.main.java.outputDir
433     def removeThese = []
434     configurations.each{
435       if (it.isCanBeResolved()) {
436         removeThese += it
437       }
438     }
439
440     minusConfigurations += removeThese
441     plusConfigurations = [ ]
442     file {
443
444       whenMerged { cp ->
445         def removeTheseToo = []
446         HashMap<String, Boolean> alreadyAddedSrcPath = new HashMap<>();
447         cp.entries.each { entry ->
448           // This conditional removes all src classpathentries that a) have already been added or b) aren't "src" or "test".
449           // e.g. this removes the resources dir being copied into bin/main, bin/test AND bin/clover
450           // we add the resources and help/help dirs in as libs afterwards (see below)
451           if (entry.kind == 'src') {
452             if (alreadyAddedSrcPath.getAt(entry.path) || !(entry.path == bareSourceDir || entry.path == bareTestSourceDir)) {
453               removeTheseToo += entry
454             } else {
455               alreadyAddedSrcPath.putAt(entry.path, true)
456             }
457           }
458
459         }
460         cp.entries.removeAll(removeTheseToo)
461
462         //cp.entries += new Output("${eclipse_bin_dir}/main")
463         if (file(helpParentDir).isDirectory()) {
464           cp.entries += new Library(fileReference(helpParentDir))
465         }
466         if (file(resourceDir).isDirectory()) {
467           cp.entries += new Library(fileReference(resourceDir))
468         }
469
470         HashMap<String, Boolean> alreadyAddedLibPath = new HashMap<>();
471
472         sourceSets.main.compileClasspath.findAll { it.name.endsWith(".jar") }.any {
473           //don't want to add outputDir as eclipse is using its own output dir in bin/main
474           if (it.isDirectory() || ! it.exists()) {
475             // don't add dirs to classpath, especially if they don't exist
476             return false // groovy "continue" in .any closure
477           }
478           def itPath = it.toString()
479           if (itPath.startsWith("${jalviewDirAbsolutePath}/")) {
480             // make relative path
481             itPath = itPath.substring(jalviewDirAbsolutePath.length()+1)
482           }
483           if (alreadyAddedLibPath.get(itPath)) {
484             //println("Not adding duplicate entry "+itPath)
485           } else {
486             //println("Adding entry "+itPath)
487             cp.entries += new Library(fileReference(itPath))
488             alreadyAddedLibPath.put(itPath, true)
489           }
490         }
491
492         sourceSets.test.compileClasspath.findAll { it.name.endsWith(".jar") }.any {
493           //no longer want to add outputDir as eclipse is using its own output dir in bin/main
494           if (it.isDirectory() || ! it.exists()) {
495             // don't add dirs to classpath
496             return false // groovy "continue" in .any closure
497           }
498
499           def itPath = it.toString()
500           if (itPath.startsWith("${jalviewDirAbsolutePath}/")) {
501             itPath = itPath.substring(jalviewDirAbsolutePath.length()+1)
502           }
503           if (alreadyAddedLibPath.get(itPath)) {
504             // don't duplicate
505           } else {
506             def lib = new Library(fileReference(itPath))
507             lib.entryAttributes["test"] = "true"
508             cp.entries += lib
509             alreadyAddedLibPath.put(itPath, true)
510           }
511         }
512
513       } // whenMerged
514
515     } // file
516
517     containers 'org.eclipse.buildship.core.gradleclasspathcontainer'
518
519   } // classpath
520
521   jdt {
522     // for the IDE, use java 11 compatibility
523     sourceCompatibility = compile_source_compatibility
524     targetCompatibility = compile_target_compatibility
525     javaRuntimeName = eclipseJavaRuntimeName
526
527     // add in jalview project specific properties/preferences into eclipse core preferences
528     file {
529       withProperties { props ->
530         def jalview_prefs = new Properties()
531         def ins = new FileInputStream("${jalviewDirAbsolutePath}/${eclipse_extra_jdt_prefs_file}")
532         jalview_prefs.load(ins)
533         ins.close()
534         jalview_prefs.forEach { t, v ->
535           if (props.getAt(t) == null) {
536             props.putAt(t, v)
537           }
538         }
539       }
540     }
541
542   } // jdt
543
544   if (IN_ECLIPSE) {
545     // Don't want these to be activated if in headless build
546     synchronizationTasks "eclipseSynchronizationTask"
547     autoBuildTasks "eclipseAutoBuildTask"
548
549   }
550 }
551
552
553 task cloverInstr() {
554   // only instrument source, we build test classes as normal
555   inputs.files files (sourceSets.main.allJava,sourceSets.test.allJava) // , fileTree(dir:"$jalviewDir/$testSourceDir", include: ["**/*.java"]))
556   outputs.dir cloverInstrDir
557
558   doFirst {
559     delete cloverInstrDir
560     def argsList = ["--initstring", "${buildDir}/clover/clover.db",
561     "-d", "${buildDir}/${cloverSourcesInstrDir}"]
562     argsList.addAll(inputs.files.files.collect({ file ->
563       file.absolutePath
564     }))
565     String[] args = argsList.toArray()
566     println("About to instrument "+args.length +" files")
567     com.atlassian.clover.CloverInstr.mainImpl(args)
568   }
569 }
570
571
572 task cloverReportHTML (type: JavaExec) {
573     inputs.dir "${buildDir}/clover"
574     outputs.dir "${reportsDir}/clover"
575
576     classpath configurations.cloverRuntime
577     maxHeapSize "${cloverReportJVMHeap}"
578     jvmArgs += "${cloverReportJVMArgs}"
579     main = "com.atlassian.clover.reporters.html.HtmlReporter"
580     args  "--initstring", "${buildDir}/clover/clover.db", "-o", "${reportsDir}/clover"
581     "${cloverReportHTMLOptions}".split(",").each {
582       args+= it.trim()
583       }
584 }
585
586 task cloverReportXML (type: JavaExec) {
587     inputs.dir "${buildDir}/clover"
588     outputs.dir "${reportsDir}/clover"
589     maxHeapSize "${cloverReportJVMHeap}"
590     jvmArgs "${cloverReportJVMArgs}"
591     classpath configurations.cloverRuntime
592     main = "com.atlassian.clover.reporters.xml.XMLReporter"
593     args  "--initstring", "${buildDir}/clover/clover.db", "-o", "${reportsDir}/clover/clover.xml"
594     
595     "${cloverReportXMLOptions}".split(",").each {
596       args+= it.trim()
597       }
598 }
599 task cloverReport {
600   group = "Verification"
601     description = "Creates the Clover report"
602     inputs.dir "${buildDir}/clover"
603     outputs.dir "${reportsDir}/clover"
604     onlyIf {
605       file("${buildDir}/clover/clover.db").exists()
606     }
607     dependsOn cloverReportXML
608     dependsOn cloverReportHTML
609 }
610 // end clover bits
611
612
613 compileJava {
614
615   doFirst {
616     sourceCompatibility = compile_source_compatibility
617     targetCompatibility = compile_target_compatibility
618     options.compilerArgs = additional_compiler_args
619     print ("Setting target compatibility to "+targetCompatibility+"\n")
620   }
621
622 }
623
624
625 compileTestJava {
626   if (use_clover) {
627     dependsOn compileCloverJava
628     classpath += configurations.cloverRuntime
629   } else {
630     classpath += sourceSets.main.runtimeClasspath
631   }
632   doFirst {
633     sourceCompatibility = compile_source_compatibility
634     targetCompatibility = compile_target_compatibility
635     options.compilerArgs = additional_compiler_args
636     print ("Setting target compatibility to "+targetCompatibility+"\n")
637   }
638 }
639
640
641 compileCloverJava {
642
643   doFirst {
644     sourceCompatibility = compile_source_compatibility
645     targetCompatibility = compile_target_compatibility
646     options.compilerArgs += additional_compiler_args
647     print ("Setting target compatibility to "+targetCompatibility+"\n")
648   }
649   classpath += configurations.cloverRuntime
650 }
651
652
653 clean {
654   doFirst {
655     delete sourceSets.main.java.outputDir
656   }
657 }
658
659
660 cleanTest {
661   doFirst {
662     delete sourceSets.test.java.outputDir
663     delete cloverInstrDir
664   }
665 }
666
667
668 // format is a string like date.format("dd MMMM yyyy")
669 def getDate(format) {
670   def date = new Date()
671   return date.format(format)
672 }
673
674
675 task setGitVals {
676   def hashStdOut = new ByteArrayOutputStream()
677   exec {
678     commandLine "git", "rev-parse", "--short", "HEAD"
679     standardOutput = hashStdOut
680     ignoreExitValue true
681   }
682
683   def branchStdOut = new ByteArrayOutputStream()
684   exec {
685     commandLine "git", "rev-parse", "--abbrev-ref", "HEAD"
686     standardOutput = branchStdOut
687     ignoreExitValue true
688   }
689
690   gitHash = hashStdOut.toString().trim()
691   gitBranch = branchStdOut.toString().trim()
692
693   outputs.upToDateWhen { false }
694 }
695
696
697 task createBuildProperties(type: WriteProperties) {
698   dependsOn setGitVals
699   inputs.dir(sourceDir)
700   inputs.dir(resourceDir)
701   file(buildProperties).getParentFile().mkdirs()
702   outputFile (buildProperties)
703   // taking time specific comment out to allow better incremental builds
704   comment "--Jalview Build Details--\n"+getDate("yyyy-MM-dd HH:mm:ss")
705   //comment "--Jalview Build Details--\n"+getDate("yyyy-MM-dd")
706   property "BUILD_DATE", getDate("HH:mm:ss dd MMMM yyyy")
707   property "VERSION", JALVIEW_VERSION
708   property "INSTALLATION", INSTALLATION+" git-commit:"+gitHash+" ["+gitBranch+"]"
709   outputs.file(outputFile)
710 }
711
712
713 task cleanBuildingHTML(type: Delete) {
714   doFirst {
715     delete buildingHTML
716   }
717 }
718
719
720 task convertBuildingMD(type: Exec) {
721   dependsOn cleanBuildingHTML
722   def buildingMD = "${jalviewDir}/${docDir}/building.md"
723   def css = "${jalviewDir}/${docDir}/github.css"
724
725   def pandoc = null
726   pandoc_exec.split(",").each {
727     if (file(it.trim()).exists()) {
728       pandoc = it.trim()
729       return true
730     }
731   }
732
733   def hostname = "hostname".execute().text.trim()
734   def buildtoolsPandoc = System.getProperty("user.home")+"/buildtools/pandoc/bin/pandoc"
735   if ((pandoc == null || ! file(pandoc).exists()) && file(buildtoolsPandoc).exists()) {
736     pandoc = System.getProperty("user.home")+"/buildtools/pandoc/bin/pandoc"
737   }
738
739   doFirst {
740     if (pandoc != null && file(pandoc).exists()) {
741         commandLine pandoc, '-s', '-o', buildingHTML, '--metadata', 'pagetitle="Building Jalview from Source"', '--toc', '-H', css, buildingMD
742     } else {
743         println("Cannot find pandoc. Skipping convert building.md to HTML")
744         throw new StopExecutionException("Cannot find pandoc. Skipping convert building.md to HTML")
745     }
746   }
747
748   ignoreExitValue true
749
750   inputs.file(buildingMD)
751   inputs.file(css)
752   outputs.file(buildingHTML)
753 }
754
755
756 clean {
757   doFirst {
758     delete buildingHTML
759   }
760 }
761
762
763 task syncDocs(type: Sync) {
764   dependsOn convertBuildingMD
765   def syncDir = "${classesDir}/${docDir}"
766   from fileTree("${jalviewDir}/${docDir}")
767   into syncDir
768
769 }
770
771
772 task copyHelp(type: Copy) {
773   def inputDir = helpSourceDir
774   def outputDir = "${classesDir}/${help_dir}"
775   from(inputDir) {
776     exclude '**/*.gif'
777     exclude '**/*.jpg'
778     exclude '**/*.png'
779     filter(ReplaceTokens,
780       beginToken: '$$',
781       endToken: '$$',
782       tokens: [
783         'Version-Rel': JALVIEW_VERSION,
784         'Year-Rel': getDate("yyyy")
785       ]
786     )
787   }
788   from(inputDir) {
789     include '**/*.gif'
790     include '**/*.jpg'
791     include '**/*.png'
792   }
793   into outputDir
794
795   inputs.dir(inputDir)
796   outputs.files(helpFile)
797   outputs.dir(outputDir)
798 }
799
800
801 task syncLib(type: Sync) {
802   def syncDir = "${classesDir}/${libDistDir}"
803   from fileTree("${jalviewDir}/${libDistDir}")
804   into syncDir
805 }
806
807
808 task syncResources(type: Sync) {
809   from resourceDir
810   include "**/*.*"
811   into "${classesDir}"
812   preserve {
813     include "**"
814   }
815 }
816
817
818 task prepare {
819   dependsOn syncResources
820   dependsOn syncDocs
821   dependsOn copyHelp
822 }
823
824
825 //testReportDirName = "test-reports" // note that test workingDir will be $jalviewDir
826 test {
827   dependsOn prepare
828   dependsOn compileJava
829   if (use_clover) {
830     dependsOn cloverInstr
831   }
832
833   if (use_clover) {
834     print("Running tests " + (use_clover?"WITH":"WITHOUT") + " clover [clover="+use_clover+"]\n")
835   }
836
837   useTestNG() {
838     includeGroups testngGroups
839     preserveOrder true
840     useDefaultListeners=true
841   }
842
843   workingDir = jalviewDir
844   //systemProperties 'clover.jar' System.properties.clover.jar
845   sourceCompatibility = compile_source_compatibility
846   targetCompatibility = compile_target_compatibility
847   jvmArgs += additional_compiler_args
848
849 }
850
851
852 task buildIndices(type: JavaExec) {
853   dependsOn copyHelp
854   classpath = sourceSets.main.compileClasspath
855   main = "com.sun.java.help.search.Indexer"
856   workingDir = "${classesDir}/${help_dir}"
857   def argDir = "html"
858   args = [ argDir ]
859   inputs.dir("${workingDir}/${argDir}")
860
861   outputs.dir("${classesDir}/doc")
862   outputs.dir("${classesDir}/help")
863   outputs.file("${workingDir}/JavaHelpSearch/DOCS")
864   outputs.file("${workingDir}/JavaHelpSearch/DOCS.TAB")
865   outputs.file("${workingDir}/JavaHelpSearch/OFFSETS")
866   outputs.file("${workingDir}/JavaHelpSearch/POSITIONS")
867   outputs.file("${workingDir}/JavaHelpSearch/SCHEMA")
868   outputs.file("${workingDir}/JavaHelpSearch/TMAP")
869 }
870
871
872 task compileLinkCheck(type: JavaCompile) {
873   options.fork = true
874   classpath = files("${jalviewDir}/${utilsDir}")
875   destinationDir = file("${jalviewDir}/${utilsDir}")
876   source = fileTree(dir: "${jalviewDir}/${utilsDir}", include: ["HelpLinksChecker.java", "BufferedLineReader.java"])
877
878   inputs.file("${jalviewDir}/${utilsDir}/HelpLinksChecker.java")
879   inputs.file("${jalviewDir}/${utilsDir}/HelpLinksChecker.java")
880   outputs.file("${jalviewDir}/${utilsDir}/HelpLinksChecker.class")
881   outputs.file("${jalviewDir}/${utilsDir}/BufferedLineReader.class")
882 }
883
884
885 task linkCheck(type: JavaExec) {
886   dependsOn prepare, compileLinkCheck
887
888   def helpLinksCheckerOutFile = file("${jalviewDir}/${utilsDir}/HelpLinksChecker.out")
889   classpath = files("${jalviewDir}/${utilsDir}")
890   main = "HelpLinksChecker"
891   workingDir = jalviewDir
892   args = [ "${classesDir}/${help_dir}", "-nointernet" ]
893
894   def outFOS = new FileOutputStream(helpLinksCheckerOutFile, false) // false == don't append
895   def errFOS = outFOS
896   standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
897     outFOS,
898     standardOutput)
899   errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
900     outFOS,
901     errorOutput)
902
903   inputs.dir("${classesDir}/${help_dir}")
904   outputs.file(helpLinksCheckerOutFile)
905 }
906
907 // import the pubhtmlhelp target
908 ant.properties.basedir = "${jalviewDir}"
909 ant.properties.helpBuildDir = "${jalviewDirAbsolutePath}/${classes_dir}/${help_dir}"
910 ant.importBuild "${utilsDir}/publishHelp.xml"
911
912
913 task cleanPackageDir(type: Delete) {
914   doFirst {
915     delete fileTree(dir: "${jalviewDir}/${packageDir}", include: "*.jar")
916   }
917 }
918
919 jar {
920   dependsOn linkCheck
921   dependsOn buildIndices
922   dependsOn createBuildProperties
923
924   manifest {
925     attributes "Main-Class": mainClass,
926     "Permissions": "all-permissions",
927     "Application-Name": "Jalview Desktop",
928     "Codebase": application_codebase
929   }
930
931   destinationDir = file("${jalviewDir}/${packageDir}")
932   archiveName = rootProject.name+".jar"
933
934   exclude "cache*/**"
935   exclude "*.jar"
936   exclude "*.jar.*"
937   exclude "**/*.jar"
938   exclude "**/*.jar.*"
939
940   inputs.dir(classesDir)
941   outputs.file("${jalviewDir}/${packageDir}/${archiveName}")
942 }
943
944
945 task copyJars(type: Copy) {
946   from fileTree(dir: classesDir, include: "**/*.jar").files
947   into "${jalviewDir}/${packageDir}"
948 }
949
950
951 // doing a Sync instead of Copy as Copy doesn't deal with "outputs" very well
952 task syncJars(type: Sync) {
953   from fileTree(dir: "${jalviewDir}/${libDistDir}", include: "**/*.jar").files
954   into "${jalviewDir}/${packageDir}"
955   preserve {
956     include jar.archiveName
957   }
958 }
959
960
961 task makeDist {
962   group = "build"
963   description = "Put all required libraries in dist"
964   // order of "cleanPackageDir", "copyJars", "jar" important!
965   jar.mustRunAfter cleanPackageDir
966   syncJars.mustRunAfter cleanPackageDir
967   dependsOn cleanPackageDir
968   dependsOn syncJars
969   dependsOn jar
970   outputs.dir("${jalviewDir}/${packageDir}")
971 }
972
973
974 task cleanDist {
975   dependsOn cleanPackageDir
976   dependsOn cleanTest
977   dependsOn clean
978 }
979
980 shadowJar {
981   group = "distribution"
982   if (buildDist) {
983     dependsOn makeDist
984   }
985   from ("${jalviewDir}/${libDistDir}") {
986     include("*.jar")
987   }
988   manifest {
989     attributes 'Implementation-Version': JALVIEW_VERSION
990   }
991   mainClassName = shadowJarMainClass
992   mergeServiceFiles()
993   classifier = "all-"+JALVIEW_VERSION+"-j"+JAVA_VERSION
994   minimize()
995 }
996
997
998 task getdownWebsite() {
999   group = "distribution"
1000   description = "Create the getdown minimal app folder, and website folder for this version of jalview. Website folder also used for offline app installer"
1001   if (buildDist) {
1002     dependsOn makeDist
1003   }
1004
1005   def getdownWebsiteResourceFilenames = []
1006   def getdownTextString = ""
1007   def getdownResourceDir = getdownResourceDir
1008   def getdownResourceFilenames = []
1009
1010   doFirst {
1011     // clean the getdown website and files dir before creating getdown folders
1012     delete getdownWebsiteDir
1013     delete getdownFilesDir
1014
1015     copy {
1016       from buildProperties
1017       rename(build_properties_file, getdown_build_properties)
1018       into getdownAppDir
1019     }
1020     getdownWebsiteResourceFilenames += "${getdownAppDistDir}/${getdown_build_properties}"
1021
1022     // go through properties looking for getdown_txt_...
1023     def props = project.properties.sort { it.key }
1024     if (getdownAltJavaMinVersion != null && getdownAltJavaMinVersion.length() > 0) {
1025       props.put("getdown_txt_java_min_version", getdownAltJavaMinVersion)
1026     }
1027     if (getdownAltJavaMaxVersion != null && getdownAltJavaMaxVersion.length() > 0) {
1028       props.put("getdown_txt_java_max_version", getdownAltJavaMaxVersion)
1029     }
1030     if (getdownAltMultiJavaLocation != null && getdownAltMultiJavaLocation.length() > 0) {
1031       props.put("getdown_txt_multi_java_location", getdownAltMultiJavaLocation)
1032     }
1033
1034     props.put("getdown_txt_appbase", getdownAppBase)
1035     props.each{ prop, val ->
1036       if (prop.startsWith("getdown_txt_") && val != null) {
1037         if (prop.startsWith("getdown_txt_multi_")) {
1038           def key = prop.substring(18)
1039           val.split(",").each{ v ->
1040             def line = "${key} = ${v}\n"
1041             getdownTextString += line
1042           }
1043         } else {
1044           // file values rationalised
1045           if (val.indexOf('/') > -1 || prop.startsWith("getdown_txt_resource")) {
1046             def r = null
1047             if (val.indexOf('/') == 0) {
1048               // absolute path
1049               r = file(val)
1050             } else if (val.indexOf('/') > 0) {
1051               // relative path (relative to jalviewDir)
1052               r = file( "${jalviewDir}/${val}" )
1053             }
1054             if (r.exists()) {
1055               val = "${getdown_resource_dir}/" + r.getName()
1056               getdownWebsiteResourceFilenames += val
1057               getdownResourceFilenames += r.getPath()
1058             }
1059           }
1060           if (! prop.startsWith("getdown_txt_resource")) {
1061             def line = prop.substring(12) + " = ${val}\n"
1062             getdownTextString += line
1063           }
1064         }
1065       }
1066     }
1067
1068     getdownWebsiteResourceFilenames.each{ filename ->
1069       getdownTextString += "resource = ${filename}\n"
1070     }
1071     getdownResourceFilenames.each{ filename ->
1072       copy {
1073         from filename
1074         into getdownResourceDir
1075       }
1076     }
1077
1078     def codeFiles = []
1079     fileTree(file(packageDir)).each{ f ->
1080       if (f.isDirectory()) {
1081         def files = fileTree(dir: f, include: ["*"]).getFiles()
1082         codeFiles += files
1083       } else if (f.exists()) {
1084         codeFiles += f
1085       }
1086     }
1087     codeFiles.sort().each{f ->
1088       def name = f.getName()
1089       def line = "code = ${getdownAppDistDir}/${name}\n"
1090       getdownTextString += line
1091       copy {
1092         from f.getPath()
1093         into getdownAppDir
1094       }
1095     }
1096
1097     // NOT USING MODULES YET, EVERYTHING SHOULD BE IN dist
1098     /*
1099     if (JAVA_VERSION.equals("11")) {
1100     def j11libFiles = fileTree(dir: "${jalviewDir}/${j11libDir}", include: ["*.jar"]).getFiles()
1101     j11libFiles.sort().each{f ->
1102     def name = f.getName()
1103     def line = "code = ${getdown_j11lib_dir}/${name}\n"
1104     getdownTextString += line
1105     copy {
1106     from f.getPath()
1107     into getdownJ11libDir
1108     }
1109     }
1110     }
1111      */
1112
1113     // getdown-launcher.jar should not be in main application class path so the main application can move it when updated.  Listed as a resource so it gets updated.
1114     //getdownTextString += "class = " + file(getdownLauncher).getName() + "\n"
1115     getdownTextString += "resource = ${getdown_launcher_new}\n"
1116     getdownTextString += "class = ${mainClass}\n"
1117
1118     def getdown_txt = file("${getdownWebsiteDir}/getdown.txt")
1119     getdown_txt.write(getdownTextString)
1120
1121     def getdownLaunchJvl = getdown_launch_jvl_name + ( (jvlChannelName != null && jvlChannelName.length() > 0)?"-${jvlChannelName}":"" ) + ".jvl"
1122     def launchJvl = file("${getdownWebsiteDir}/${getdownLaunchJvl}")
1123     launchJvl.write("appbase="+props.get("getdown_txt_appbase"))
1124
1125     copy {
1126       from getdownLauncher
1127       rename(file(getdownLauncher).getName(), getdown_launcher_new)
1128       into getdownWebsiteDir
1129     }
1130
1131     copy {
1132       from getdownLauncher
1133       if (file(getdownLauncher).getName() != getdown_launcher) {
1134         rename(file(getdownLauncher).getName(), getdown_launcher)
1135       }
1136       into getdownWebsiteDir
1137     }
1138
1139     if (! (CHANNEL.startsWith("ARCHIVE") || CHANNEL.startsWith("DEVELOP"))) {
1140       copy {
1141         from getdown_txt
1142         from getdownLauncher
1143         from "${getdownWebsiteDir}/${getdown_build_properties}"
1144         if (file(getdownLauncher).getName() != getdown_launcher) {
1145           rename(file(getdownLauncher).getName(), getdown_launcher)
1146         }
1147         into getdownInstallDir
1148       }
1149
1150       copy {
1151         from getdownInstallDir
1152         into getdownFilesInstallDir
1153       }
1154     }
1155
1156     copy {
1157       from getdown_txt
1158       from launchJvl
1159       from getdownLauncher
1160       from "${getdownWebsiteDir}/${getdown_build_properties}"
1161       if (file(getdownLauncher).getName() != getdown_launcher) {
1162         rename(file(getdownLauncher).getName(), getdown_launcher)
1163       }
1164       into getdownFilesDir
1165     }
1166
1167     copy {
1168       from getdownResourceDir
1169       into "${getdownFilesDir}/${getdown_resource_dir}"
1170     }
1171   }
1172
1173   if (buildDist) {
1174     inputs.dir("${jalviewDir}/${packageDir}")
1175   }
1176   outputs.dir(getdownWebsiteDir)
1177   outputs.dir(getdownFilesDir)
1178 }
1179
1180
1181 // a helper task to allow getdown digest of any dir: `gradle getdownDigestDir -PDIGESTDIR=/path/to/my/random/getdown/dir
1182 task getdownDigestDir(type: JavaExec) {
1183   def digestDirPropertyName = "DIGESTDIR"
1184   description = "Digest a local dir (-P${digestDirPropertyName}=...) for getdown"
1185   doFirst {
1186     classpath = files(getdownLauncher)
1187     def digestDir = findProperty(digestDirPropertyName)
1188     if (digestDir == null) {
1189       throw new GradleException("Must provide a DIGESTDIR value to produce an alternative getdown digest")
1190     }
1191     args digestDir
1192   }
1193   main = "com.threerings.getdown.tools.Digester"
1194 }
1195
1196
1197 task getdownDigest(type: JavaExec) {
1198   group = "distribution"
1199   description = "Digest the getdown website folder"
1200   dependsOn getdownWebsite
1201   doFirst {
1202     classpath = files(getdownLauncher)
1203   }
1204   main = "com.threerings.getdown.tools.Digester"
1205   args getdownWebsiteDir
1206   inputs.dir(getdownWebsiteDir)
1207   outputs.file("${getdownWebsiteDir}/digest2.txt")
1208 }
1209
1210
1211 task getdown() {
1212   group = "distribution"
1213   description = "Create the minimal and full getdown app folder for installers and website and create digest file"
1214   dependsOn getdownDigest
1215   doLast {
1216     if (reportRsyncCommand) {
1217       def fromDir = getdownWebsiteDir + (getdownWebsiteDir.endsWith('/')?'':'/')
1218       def toDir = "${getdown_rsync_dest}/${getdownDir}" + (getdownDir.endsWith('/')?'':'/')
1219       println "LIKELY RSYNC COMMAND:"
1220       println "mkdir -p '$toDir'\nrsync -avh --delete '$fromDir' '$toDir'"
1221       if (RUNRSYNC == "true") {
1222         exec {
1223           commandLine "mkdir", "-p", toDir
1224         }
1225         exec {
1226           commandLine "rsync", "-avh", "--delete", fromDir, toDir
1227         }
1228       }
1229     }
1230   }
1231 }
1232
1233
1234 clean {
1235   doFirst {
1236     delete getdownWebsiteDir
1237     delete getdownFilesDir
1238   }
1239 }
1240
1241
1242 install4j {
1243   if (file(install4jHomeDir).exists()) {
1244     // good to go!
1245   } else if (file(System.getProperty("user.home")+"/buildtools/install4j").exists()) {
1246     install4jHomeDir = System.getProperty("user.home")+"/buildtools/install4j"
1247   } else if (file("/Applications/install4j.app/Contents/Resources/app").exists()) {
1248     install4jHomeDir = "/Applications/install4j.app/Contents/Resources/app"
1249   }
1250   installDir(file(install4jHomeDir))
1251
1252   mediaTypes = Arrays.asList(install4j_media_types.split(","))
1253 }
1254
1255
1256 task copyInstall4jTemplate {
1257   def install4jTemplateFile = file("${install4jDir}/${install4j_template}")
1258   def install4jFileAssociationsFile = file("${install4jDir}/${install4j_installer_file_associations}")
1259   inputs.file(install4jTemplateFile)
1260   inputs.file(install4jFileAssociationsFile)
1261   outputs.file(install4jConfFile)
1262
1263   doLast {
1264     def install4jConfigXml = new XmlParser().parse(install4jTemplateFile)
1265
1266     // turn off code signing if no OSX_KEYPASS
1267     if (OSX_KEYPASS == "") {
1268       install4jConfigXml.'**'.codeSigning.each { codeSigning ->
1269         codeSigning.'@macEnabled' = "false"
1270       }
1271       install4jConfigXml.'**'.windows.each { windows ->
1272         windows.'@runPostProcessor' = "false"
1273       }
1274     }
1275
1276     // turn off checksum creation for LOCAL channel
1277     def e = install4jConfigXml.application[0]
1278     if (CHANNEL == "LOCAL") {
1279       e.'@createChecksums' = "false"
1280     } else {
1281       e.'@createChecksums' = "true"
1282     }
1283
1284     // put file association actions where placeholder action is
1285     def install4jFileAssociationsText = install4jFileAssociationsFile.text
1286     def fileAssociationActions = new XmlParser().parseText("<actions>${install4jFileAssociationsText}</actions>")
1287     install4jConfigXml.'**'.action.any { a ->
1288       if (a.'@name' == 'EXTENSIONS_REPLACED_BY_GRADLE') {
1289         def parent = a.parent()
1290         parent.remove(a)
1291         fileAssociationActions.each { faa ->
1292             parent.append(faa)
1293         }
1294         // don't need to continue in .any loop once replacements have been made
1295         return true
1296       }
1297     }
1298
1299     // write install4j file
1300     install4jConfFile.text = XmlUtil.serialize(install4jConfigXml)
1301   }
1302 }
1303
1304
1305 clean {
1306   doFirst {
1307     delete install4jConfFile
1308   }
1309 }
1310
1311
1312 task installers(type: com.install4j.gradle.Install4jTask) {
1313   group = "distribution"
1314   description = "Create the install4j installers"
1315   dependsOn setGitVals
1316   dependsOn getdown
1317   dependsOn copyInstall4jTemplate
1318
1319   projectFile = install4jConfFile
1320
1321   // create an md5 for the input files to use as version for install4j conf file
1322   def digest = MessageDigest.getInstance("MD5")
1323   digest.update(
1324     (file("${install4jDir}/${install4j_template}").text + 
1325     file("${install4jDir}/${install4j_info_plist_file_associations}").text +
1326     file("${install4jDir}/${install4j_installer_file_associations}").text).bytes)
1327   def filesMd5 = new BigInteger(1, digest.digest()).toString(16)
1328   if (filesMd5.length() >= 8) {
1329     filesMd5 = filesMd5.substring(0,8)
1330   }
1331   def install4jTemplateVersion = "${JALVIEW_VERSION}_F${filesMd5}_C${gitHash}"
1332   // make install4jBuildDir relative to jalviewDir
1333   def install4jBuildDir = "${install4j_build_dir}/${JAVA_VERSION}"
1334
1335   variables = [
1336     'JALVIEW_NAME': getdown_txt_title,
1337     'JALVIEW_DIR': "../..",
1338     'OSX_KEYSTORE': OSX_KEYSTORE,
1339     'JSIGN_SH': JSIGN_SH,
1340     'JRE_DIR': getdown_app_dir_java,
1341     'INSTALLER_TEMPLATE_VERSION': install4jTemplateVersion,
1342     'JALVIEW_VERSION': JALVIEW_VERSION,
1343     'JAVA_MIN_VERSION': JAVA_MIN_VERSION,
1344     'JAVA_MAX_VERSION': JAVA_MAX_VERSION,
1345     'JAVA_VERSION': JAVA_VERSION,
1346     'JAVA_INTEGER_VERSION': JAVA_INTEGER_VERSION,
1347     'VERSION': JALVIEW_VERSION,
1348     'MACOS_JAVA_VM_DIR': macosJavaVMDir,
1349     'WINDOWS_JAVA_VM_DIR': windowsJavaVMDir,
1350     'LINUX_JAVA_VM_DIR': linuxJavaVMDir,
1351     'MACOS_JAVA_VM_TGZ': macosJavaVMTgz,
1352     'WINDOWS_JAVA_VM_TGZ': windowsJavaVMTgz,
1353     'LINUX_JAVA_VM_TGZ': linuxJavaVMTgz,
1354     'COPYRIGHT_MESSAGE': install4j_copyright_message,
1355     'MACOS_BUNDLE_ID': install4j_macOS_bundle_id,
1356     'INSTALLER_NAME': install4j_installer_name,
1357     'INSTALL4J_UTILS_DIR': install4j_utils_dir,
1358     'GETDOWN_WEBSITE_DIR': getdown_website_dir,
1359     'GETDOWN_FILES_DIR': getdown_files_dir,
1360     'GETDOWN_RESOURCE_DIR': getdown_resource_dir,
1361     'GETDOWN_DIST_DIR': getdownAppDistDir,
1362     'GETDOWN_ALT_DIR': getdown_app_dir_alt,
1363     'GETDOWN_INSTALL_DIR': getdown_install_dir,
1364     'INFO_PLIST_FILE_ASSOCIATIONS_FILE': install4j_info_plist_file_associations,
1365     'BUILD_DIR': install4jBuildDir,
1366   ]
1367
1368   destination = "${jalviewDir}/${install4jBuildDir}"
1369   buildSelected = true
1370
1371   if (install4j_faster.equals("true") || CHANNEL.startsWith("LOCAL")) {
1372     faster = true
1373     disableSigning = true
1374   }
1375
1376   if (OSX_KEYPASS) {
1377     macKeystorePassword = OSX_KEYPASS
1378   }
1379
1380   doFirst {
1381     println("Using projectFile "+projectFile)
1382   }
1383
1384   inputs.dir(getdownWebsiteDir)
1385   inputs.file(install4jConfFile)
1386   inputs.file("${install4jDir}/${install4j_info_plist_file_associations}")
1387   inputs.dir(macosJavaVMDir)
1388   inputs.dir(windowsJavaVMDir)
1389   outputs.dir("${jalviewDir}/${install4j_build_dir}/${JAVA_VERSION}")
1390 }
1391
1392
1393 task sourceDist(type: Tar) {
1394   
1395   def VERSION_UNDERSCORES = JALVIEW_VERSION.replaceAll("\\.", "_")
1396   def outputFileName = "${project.name}_${VERSION_UNDERSCORES}.tar.gz"
1397   // cater for buildship < 3.1 [3.0.1 is max version in eclipse 2018-09]
1398   try {
1399     archiveFileName = outputFileName
1400   } catch (Exception e) {
1401     archiveName = outputFileName
1402   }
1403   
1404   compression Compression.GZIP
1405   
1406   into project.name
1407
1408   def EXCLUDE_FILES=[
1409     "build/*",
1410     "bin/*",
1411     "test-output/",
1412     "test-reports",
1413     "tests",
1414     "clover*/*",
1415     ".*",
1416     "benchmarking/*",
1417     "**/.*",
1418     "*.class",
1419     "**/*.class","$j11modDir/**/*.jar","appletlib","**/*locales",
1420     "*locales/**",
1421     "utils/InstallAnywhere",
1422     "**/*.log",
1423   ] 
1424   def PROCESS_FILES=[
1425     "AUTHORS",
1426     "CITATION",
1427     "FEATURETODO",
1428     "JAVA-11-README",
1429     "FEATURETODO",
1430     "LICENSE",
1431     "**/README",
1432     "RELEASE",
1433     "THIRDPARTYLIBS",
1434     "TESTNG",
1435     "build.gradle",
1436     "gradle.properties",
1437     "**/*.java",
1438     "**/*.html",
1439     "**/*.xml",
1440     "**/*.gradle",
1441     "**/*.groovy",
1442     "**/*.properties",
1443     "**/*.perl",
1444     "**/*.sh",
1445   ]
1446   def INCLUDE_FILES=[
1447     ".settings/org.eclipse.jdt.core.jalview.prefs",
1448   ]
1449
1450   from(jalviewDir) {
1451     exclude (EXCLUDE_FILES)
1452     include (PROCESS_FILES)
1453     filter(ReplaceTokens,
1454       beginToken: '$$',
1455       endToken: '$$',
1456       tokens: [
1457         'Version-Rel': JALVIEW_VERSION,
1458         'Year-Rel': getDate("yyyy")
1459       ]
1460     )
1461   }
1462   from(jalviewDir) {
1463     exclude (EXCLUDE_FILES)
1464     exclude (PROCESS_FILES)
1465     exclude ("appletlib")
1466     exclude ("**/*locales")
1467     exclude ("*locales/**")
1468     exclude ("utils/InstallAnywhere")
1469
1470     exclude (getdown_files_dir)
1471     exclude (getdown_website_dir)
1472
1473     // exluding these as not using jars as modules yet
1474     exclude ("$j11modDir/**/*.jar")
1475   }
1476   from(jalviewDir) {
1477     include(INCLUDE_FILES)
1478   }
1479 //  from (jalviewDir) {
1480 //    // explicit includes for stuff that seemed to not get included
1481 //    include(fileTree("test/**/*."))
1482 //    exclude(EXCLUDE_FILES)
1483 //    exclude(PROCESS_FILES)
1484 //  }
1485 }
1486
1487
1488 task helppages {
1489   dependsOn copyHelp
1490   dependsOn pubhtmlhelp
1491   
1492   inputs.dir("${classesDir}/${help_dir}")
1493   outputs.dir("${buildDir}/distributions/${help_dir}")
1494 }
1495
1496 // LARGE AMOUNT OF JALVIEWJS STUFF DELETED HERE
1497 task eclipseAutoBuildTask {}
1498 task eclipseSynchronizationTask {}