Merge branch 'develop' into improvement/JAL-3449_add_install4j_installer_getdown_vers...
[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 cloverReport {
573   group = "Verification"
574     description = "Createst the Clover report"
575     inputs.dir "${buildDir}/clover"
576     outputs.dir "${reportsDir}/clover"
577     onlyIf {
578       file("${buildDir}/clover/clover.db").exists()
579     }
580   doFirst {
581     def argsList = ["--initstring", "${buildDir}/clover/clover.db",
582     "-o", "${reportsDir}/clover"]
583     String[] args = argsList.toArray()
584     com.atlassian.clover.reporters.html.HtmlReporter.runReport(args)
585
586     // and generate ${reportsDir}/clover/clover.xml
587     args = ["--initstring", "${buildDir}/clover/clover.db",
588     "-o", "${reportsDir}/clover/clover.xml"].toArray()
589     com.atlassian.clover.reporters.xml.XMLReporter.runReport(args)
590   }
591 }
592 // end clover bits
593
594
595 compileJava {
596
597   doFirst {
598     sourceCompatibility = compile_source_compatibility
599     targetCompatibility = compile_target_compatibility
600     options.compilerArgs = additional_compiler_args
601     print ("Setting target compatibility to "+targetCompatibility+"\n")
602   }
603
604 }
605
606
607 compileTestJava {
608   if (use_clover) {
609     dependsOn compileCloverJava
610     classpath += configurations.cloverRuntime
611   } else {
612     classpath += sourceSets.main.runtimeClasspath
613   }
614   doFirst {
615     sourceCompatibility = compile_source_compatibility
616     targetCompatibility = compile_target_compatibility
617     options.compilerArgs = additional_compiler_args
618     print ("Setting target compatibility to "+targetCompatibility+"\n")
619   }
620 }
621
622
623 compileCloverJava {
624
625   doFirst {
626     sourceCompatibility = compile_source_compatibility
627     targetCompatibility = compile_target_compatibility
628     options.compilerArgs += additional_compiler_args
629     print ("Setting target compatibility to "+targetCompatibility+"\n")
630   }
631   classpath += configurations.cloverRuntime
632 }
633
634
635 clean {
636   doFirst {
637     delete sourceSets.main.java.outputDir
638   }
639 }
640
641
642 cleanTest {
643   doFirst {
644     delete sourceSets.test.java.outputDir
645     delete cloverInstrDir
646   }
647 }
648
649
650 // format is a string like date.format("dd MMMM yyyy")
651 def getDate(format) {
652   def date = new Date()
653   return date.format(format)
654 }
655
656
657 task setGitVals {
658   def hashStdOut = new ByteArrayOutputStream()
659   exec {
660     commandLine "git", "rev-parse", "--short", "HEAD"
661     standardOutput = hashStdOut
662     ignoreExitValue true
663   }
664
665   def branchStdOut = new ByteArrayOutputStream()
666   exec {
667     commandLine "git", "rev-parse", "--abbrev-ref", "HEAD"
668     standardOutput = branchStdOut
669     ignoreExitValue true
670   }
671
672   gitHash = hashStdOut.toString().trim()
673   gitBranch = branchStdOut.toString().trim()
674
675   outputs.upToDateWhen { false }
676 }
677
678
679 task createBuildProperties(type: WriteProperties) {
680   dependsOn setGitVals
681   inputs.dir(sourceDir)
682   inputs.dir(resourceDir)
683   file(buildProperties).getParentFile().mkdirs()
684   outputFile (buildProperties)
685   // taking time specific comment out to allow better incremental builds
686   comment "--Jalview Build Details--\n"+getDate("yyyy-MM-dd HH:mm:ss")
687   //comment "--Jalview Build Details--\n"+getDate("yyyy-MM-dd")
688   property "BUILD_DATE", getDate("HH:mm:ss dd MMMM yyyy")
689   property "VERSION", JALVIEW_VERSION
690   property "INSTALLATION", INSTALLATION+" git-commit:"+gitHash+" ["+gitBranch+"]"
691   outputs.file(outputFile)
692 }
693
694
695 task cleanBuildingHTML(type: Delete) {
696   doFirst {
697     delete buildingHTML
698   }
699 }
700
701
702 task convertBuildingMD(type: Exec) {
703   dependsOn cleanBuildingHTML
704   def buildingMD = "${jalviewDir}/${docDir}/building.md"
705   def css = "${jalviewDir}/${docDir}/github.css"
706
707   def pandoc = null
708   pandoc_exec.split(",").each {
709     if (file(it.trim()).exists()) {
710       pandoc = it.trim()
711       return true
712     }
713   }
714
715   def hostname = "hostname".execute().text.trim()
716   def buildtoolsPandoc = System.getProperty("user.home")+"/buildtools/pandoc/bin/pandoc"
717   if ((pandoc == null || ! file(pandoc).exists()) && file(buildtoolsPandoc).exists()) {
718     pandoc = System.getProperty("user.home")+"/buildtools/pandoc/bin/pandoc"
719   }
720
721   doFirst {
722     if (pandoc != null && file(pandoc).exists()) {
723         commandLine pandoc, '-s', '-o', buildingHTML, '--metadata', 'pagetitle="Building Jalview from Source"', '--toc', '-H', css, buildingMD
724     } else {
725         println("Cannot find pandoc. Skipping convert building.md to HTML")
726         throw new StopExecutionException("Cannot find pandoc. Skipping convert building.md to HTML")
727     }
728   }
729
730   ignoreExitValue true
731
732   inputs.file(buildingMD)
733   inputs.file(css)
734   outputs.file(buildingHTML)
735 }
736
737
738 clean {
739   doFirst {
740     delete buildingHTML
741   }
742 }
743
744
745 task syncDocs(type: Sync) {
746   dependsOn convertBuildingMD
747   def syncDir = "${classesDir}/${docDir}"
748   from fileTree("${jalviewDir}/${docDir}")
749   into syncDir
750
751 }
752
753
754 task copyHelp(type: Copy) {
755   def inputDir = helpSourceDir
756   def outputDir = "${classesDir}/${help_dir}"
757   from(inputDir) {
758     exclude '**/*.gif'
759     exclude '**/*.jpg'
760     exclude '**/*.png'
761     filter(ReplaceTokens,
762       beginToken: '$$',
763       endToken: '$$',
764       tokens: [
765         'Version-Rel': JALVIEW_VERSION,
766         'Year-Rel': getDate("yyyy")
767       ]
768     )
769   }
770   from(inputDir) {
771     include '**/*.gif'
772     include '**/*.jpg'
773     include '**/*.png'
774   }
775   into outputDir
776
777   inputs.dir(inputDir)
778   outputs.files(helpFile)
779   outputs.dir(outputDir)
780 }
781
782
783 task syncLib(type: Sync) {
784   def syncDir = "${classesDir}/${libDistDir}"
785   from fileTree("${jalviewDir}/${libDistDir}")
786   into syncDir
787 }
788
789
790 task syncResources(type: Sync) {
791   from resourceDir
792   include "**/*.*"
793   into "${classesDir}"
794   preserve {
795     include "**"
796   }
797 }
798
799
800 task prepare {
801   dependsOn syncResources
802   dependsOn syncDocs
803   dependsOn copyHelp
804 }
805
806
807 //testReportDirName = "test-reports" // note that test workingDir will be $jalviewDir
808 test {
809   dependsOn prepare
810   dependsOn compileJava
811   if (use_clover) {
812     dependsOn cloverInstr
813   }
814
815   if (use_clover) {
816     print("Running tests " + (use_clover?"WITH":"WITHOUT") + " clover [clover="+use_clover+"]\n")
817   }
818
819   useTestNG() {
820     includeGroups testngGroups
821     preserveOrder true
822     useDefaultListeners=true
823   }
824
825   workingDir = jalviewDir
826   //systemProperties 'clover.jar' System.properties.clover.jar
827   sourceCompatibility = compile_source_compatibility
828   targetCompatibility = compile_target_compatibility
829   jvmArgs += additional_compiler_args
830
831 }
832
833
834 task buildIndices(type: JavaExec) {
835   dependsOn copyHelp
836   classpath = sourceSets.main.compileClasspath
837   main = "com.sun.java.help.search.Indexer"
838   workingDir = "${classesDir}/${help_dir}"
839   def argDir = "html"
840   args = [ argDir ]
841   inputs.dir("${workingDir}/${argDir}")
842
843   outputs.dir("${classesDir}/doc")
844   outputs.dir("${classesDir}/help")
845   outputs.file("${workingDir}/JavaHelpSearch/DOCS")
846   outputs.file("${workingDir}/JavaHelpSearch/DOCS.TAB")
847   outputs.file("${workingDir}/JavaHelpSearch/OFFSETS")
848   outputs.file("${workingDir}/JavaHelpSearch/POSITIONS")
849   outputs.file("${workingDir}/JavaHelpSearch/SCHEMA")
850   outputs.file("${workingDir}/JavaHelpSearch/TMAP")
851 }
852
853
854 task compileLinkCheck(type: JavaCompile) {
855   options.fork = true
856   classpath = files("${jalviewDir}/${utilsDir}")
857   destinationDir = file("${jalviewDir}/${utilsDir}")
858   source = fileTree(dir: "${jalviewDir}/${utilsDir}", include: ["HelpLinksChecker.java", "BufferedLineReader.java"])
859
860   inputs.file("${jalviewDir}/${utilsDir}/HelpLinksChecker.java")
861   inputs.file("${jalviewDir}/${utilsDir}/HelpLinksChecker.java")
862   outputs.file("${jalviewDir}/${utilsDir}/HelpLinksChecker.class")
863   outputs.file("${jalviewDir}/${utilsDir}/BufferedLineReader.class")
864 }
865
866
867 task linkCheck(type: JavaExec) {
868   dependsOn prepare, compileLinkCheck
869
870   def helpLinksCheckerOutFile = file("${jalviewDir}/${utilsDir}/HelpLinksChecker.out")
871   classpath = files("${jalviewDir}/${utilsDir}")
872   main = "HelpLinksChecker"
873   workingDir = jalviewDir
874   args = [ "${classesDir}/${help_dir}", "-nointernet" ]
875
876   def outFOS = new FileOutputStream(helpLinksCheckerOutFile, false) // false == don't append
877   def errFOS = outFOS
878   standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
879     outFOS,
880     standardOutput)
881   errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
882     outFOS,
883     errorOutput)
884
885   inputs.dir("${classesDir}/${help_dir}")
886   outputs.file(helpLinksCheckerOutFile)
887 }
888
889 // import the pubhtmlhelp target
890 ant.properties.basedir = "${jalviewDir}"
891 ant.properties.helpBuildDir = "${jalviewDirAbsolutePath}/${classes_dir}/${help_dir}"
892 ant.importBuild "${utilsDir}/publishHelp.xml"
893
894
895 task cleanPackageDir(type: Delete) {
896   doFirst {
897     delete fileTree(dir: "${jalviewDir}/${packageDir}", include: "*.jar")
898   }
899 }
900
901 jar {
902   dependsOn linkCheck
903   dependsOn buildIndices
904   dependsOn createBuildProperties
905
906   manifest {
907     attributes "Main-Class": mainClass,
908     "Permissions": "all-permissions",
909     "Application-Name": "Jalview Desktop",
910     "Codebase": application_codebase
911   }
912
913   destinationDir = file("${jalviewDir}/${packageDir}")
914   archiveName = rootProject.name+".jar"
915
916   exclude "cache*/**"
917   exclude "*.jar"
918   exclude "*.jar.*"
919   exclude "**/*.jar"
920   exclude "**/*.jar.*"
921
922   inputs.dir(classesDir)
923   outputs.file("${jalviewDir}/${packageDir}/${archiveName}")
924 }
925
926
927 task copyJars(type: Copy) {
928   from fileTree(dir: classesDir, include: "**/*.jar").files
929   into "${jalviewDir}/${packageDir}"
930 }
931
932
933 // doing a Sync instead of Copy as Copy doesn't deal with "outputs" very well
934 task syncJars(type: Sync) {
935   from fileTree(dir: "${jalviewDir}/${libDistDir}", include: "**/*.jar").files
936   into "${jalviewDir}/${packageDir}"
937   preserve {
938     include jar.archiveName
939   }
940 }
941
942
943 task makeDist {
944   group = "build"
945   description = "Put all required libraries in dist"
946   // order of "cleanPackageDir", "copyJars", "jar" important!
947   jar.mustRunAfter cleanPackageDir
948   syncJars.mustRunAfter cleanPackageDir
949   dependsOn cleanPackageDir
950   dependsOn syncJars
951   dependsOn jar
952   outputs.dir("${jalviewDir}/${packageDir}")
953 }
954
955
956 task cleanDist {
957   dependsOn cleanPackageDir
958   dependsOn cleanTest
959   dependsOn clean
960 }
961
962 shadowJar {
963   group = "distribution"
964   if (buildDist) {
965     dependsOn makeDist
966   }
967   from ("${jalviewDir}/${libDistDir}") {
968     include("*.jar")
969   }
970   manifest {
971     attributes 'Implementation-Version': JALVIEW_VERSION
972   }
973   mainClassName = shadowJarMainClass
974   mergeServiceFiles()
975   classifier = "all-"+JALVIEW_VERSION+"-j"+JAVA_VERSION
976   minimize()
977 }
978
979
980 task getdownWebsite() {
981   group = "distribution"
982   description = "Create the getdown minimal app folder, and website folder for this version of jalview. Website folder also used for offline app installer"
983   if (buildDist) {
984     dependsOn makeDist
985   }
986
987   def getdownWebsiteResourceFilenames = []
988   def getdownTextString = ""
989   def getdownResourceDir = getdownResourceDir
990   def getdownResourceFilenames = []
991
992   doFirst {
993     // clean the getdown website and files dir before creating getdown folders
994     delete getdownWebsiteDir
995     delete getdownFilesDir
996
997     copy {
998       from buildProperties
999       rename(build_properties_file, getdown_build_properties)
1000       into getdownAppDir
1001     }
1002     getdownWebsiteResourceFilenames += "${getdownAppDistDir}/${getdown_build_properties}"
1003
1004     // go through properties looking for getdown_txt_...
1005     def props = project.properties.sort { it.key }
1006     if (getdownAltJavaMinVersion != null && getdownAltJavaMinVersion.length() > 0) {
1007       props.put("getdown_txt_java_min_version", getdownAltJavaMinVersion)
1008     }
1009     if (getdownAltJavaMaxVersion != null && getdownAltJavaMaxVersion.length() > 0) {
1010       props.put("getdown_txt_java_max_version", getdownAltJavaMaxVersion)
1011     }
1012     if (getdownAltMultiJavaLocation != null && getdownAltMultiJavaLocation.length() > 0) {
1013       props.put("getdown_txt_multi_java_location", getdownAltMultiJavaLocation)
1014     }
1015
1016     props.put("getdown_txt_appbase", getdownAppBase)
1017     props.each{ prop, val ->
1018       if (prop.startsWith("getdown_txt_") && val != null) {
1019         if (prop.startsWith("getdown_txt_multi_")) {
1020           def key = prop.substring(18)
1021           val.split(",").each{ v ->
1022             def line = "${key} = ${v}\n"
1023             getdownTextString += line
1024           }
1025         } else {
1026           // file values rationalised
1027           if (val.indexOf('/') > -1 || prop.startsWith("getdown_txt_resource")) {
1028             def r = null
1029             if (val.indexOf('/') == 0) {
1030               // absolute path
1031               r = file(val)
1032             } else if (val.indexOf('/') > 0) {
1033               // relative path (relative to jalviewDir)
1034               r = file( "${jalviewDir}/${val}" )
1035             }
1036             if (r.exists()) {
1037               val = "${getdown_resource_dir}/" + r.getName()
1038               getdownWebsiteResourceFilenames += val
1039               getdownResourceFilenames += r.getPath()
1040             }
1041           }
1042           if (! prop.startsWith("getdown_txt_resource")) {
1043             def line = prop.substring(12) + " = ${val}\n"
1044             getdownTextString += line
1045           }
1046         }
1047       }
1048     }
1049
1050     getdownWebsiteResourceFilenames.each{ filename ->
1051       getdownTextString += "resource = ${filename}\n"
1052     }
1053     getdownResourceFilenames.each{ filename ->
1054       copy {
1055         from filename
1056         into getdownResourceDir
1057       }
1058     }
1059
1060     def codeFiles = []
1061     fileTree(file(packageDir)).each{ f ->
1062       if (f.isDirectory()) {
1063         def files = fileTree(dir: f, include: ["*"]).getFiles()
1064         codeFiles += files
1065       } else if (f.exists()) {
1066         codeFiles += f
1067       }
1068     }
1069     codeFiles.sort().each{f ->
1070       def name = f.getName()
1071       def line = "code = ${getdownAppDistDir}/${name}\n"
1072       getdownTextString += line
1073       copy {
1074         from f.getPath()
1075         into getdownAppDir
1076       }
1077     }
1078
1079     // NOT USING MODULES YET, EVERYTHING SHOULD BE IN dist
1080     /*
1081     if (JAVA_VERSION.equals("11")) {
1082     def j11libFiles = fileTree(dir: "${jalviewDir}/${j11libDir}", include: ["*.jar"]).getFiles()
1083     j11libFiles.sort().each{f ->
1084     def name = f.getName()
1085     def line = "code = ${getdown_j11lib_dir}/${name}\n"
1086     getdownTextString += line
1087     copy {
1088     from f.getPath()
1089     into getdownJ11libDir
1090     }
1091     }
1092     }
1093      */
1094
1095     // 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.
1096     //getdownTextString += "class = " + file(getdownLauncher).getName() + "\n"
1097     getdownTextString += "resource = ${getdown_launcher_new}\n"
1098     getdownTextString += "class = ${mainClass}\n"
1099
1100     def getdown_txt = file("${getdownWebsiteDir}/getdown.txt")
1101     getdown_txt.write(getdownTextString)
1102
1103     def getdownLaunchJvl = getdown_launch_jvl_name + ( (jvlChannelName != null && jvlChannelName.length() > 0)?"-${jvlChannelName}":"" ) + ".jvl"
1104     def launchJvl = file("${getdownWebsiteDir}/${getdownLaunchJvl}")
1105     launchJvl.write("appbase="+props.get("getdown_txt_appbase"))
1106
1107     copy {
1108       from getdownLauncher
1109       rename(file(getdownLauncher).getName(), getdown_launcher_new)
1110       into getdownWebsiteDir
1111     }
1112
1113     copy {
1114       from getdownLauncher
1115       if (file(getdownLauncher).getName() != getdown_launcher) {
1116         rename(file(getdownLauncher).getName(), getdown_launcher)
1117       }
1118       into getdownWebsiteDir
1119     }
1120
1121     if (! (CHANNEL.startsWith("ARCHIVE") || CHANNEL.startsWith("DEVELOP"))) {
1122       copy {
1123         from getdown_txt
1124         from getdownLauncher
1125         from "${getdownWebsiteDir}/${getdown_build_properties}"
1126         if (file(getdownLauncher).getName() != getdown_launcher) {
1127           rename(file(getdownLauncher).getName(), getdown_launcher)
1128         }
1129         into getdownInstallDir
1130       }
1131
1132       copy {
1133         from getdownInstallDir
1134         into getdownFilesInstallDir
1135       }
1136     }
1137
1138     copy {
1139       from getdown_txt
1140       from launchJvl
1141       from getdownLauncher
1142       from "${getdownWebsiteDir}/${getdown_build_properties}"
1143       if (file(getdownLauncher).getName() != getdown_launcher) {
1144         rename(file(getdownLauncher).getName(), getdown_launcher)
1145       }
1146       into getdownFilesDir
1147     }
1148
1149     copy {
1150       from getdownResourceDir
1151       into "${getdownFilesDir}/${getdown_resource_dir}"
1152     }
1153   }
1154
1155   if (buildDist) {
1156     inputs.dir("${jalviewDir}/${packageDir}")
1157   }
1158   outputs.dir(getdownWebsiteDir)
1159   outputs.dir(getdownFilesDir)
1160 }
1161
1162
1163 // a helper task to allow getdown digest of any dir: `gradle getdownDigestDir -PDIGESTDIR=/path/to/my/random/getdown/dir
1164 task getdownDigestDir(type: JavaExec) {
1165   def digestDirPropertyName = "DIGESTDIR"
1166   description = "Digest a local dir (-P${digestDirPropertyName}=...) for getdown"
1167   doFirst {
1168     classpath = files(getdownLauncher)
1169     def digestDir = findProperty(digestDirPropertyName)
1170     if (digestDir == null) {
1171       throw new GradleException("Must provide a DIGESTDIR value to produce an alternative getdown digest")
1172     }
1173     args digestDir
1174   }
1175   main = "com.threerings.getdown.tools.Digester"
1176 }
1177
1178
1179 task getdownDigest(type: JavaExec) {
1180   group = "distribution"
1181   description = "Digest the getdown website folder"
1182   dependsOn getdownWebsite
1183   doFirst {
1184     classpath = files(getdownLauncher)
1185   }
1186   main = "com.threerings.getdown.tools.Digester"
1187   args getdownWebsiteDir
1188   inputs.dir(getdownWebsiteDir)
1189   outputs.file("${getdownWebsiteDir}/digest2.txt")
1190 }
1191
1192
1193 task getdown() {
1194   group = "distribution"
1195   description = "Create the minimal and full getdown app folder for installers and website and create digest file"
1196   dependsOn getdownDigest
1197   doLast {
1198     if (reportRsyncCommand) {
1199       def fromDir = getdownWebsiteDir + (getdownWebsiteDir.endsWith('/')?'':'/')
1200       def toDir = "${getdown_rsync_dest}/${getdownDir}" + (getdownDir.endsWith('/')?'':'/')
1201       println "LIKELY RSYNC COMMAND:"
1202       println "mkdir -p '$toDir'\nrsync -avh --delete '$fromDir' '$toDir'"
1203       if (RUNRSYNC == "true") {
1204         exec {
1205           commandLine "mkdir", "-p", toDir
1206         }
1207         exec {
1208           commandLine "rsync", "-avh", "--delete", fromDir, toDir
1209         }
1210       }
1211     }
1212   }
1213 }
1214
1215
1216 clean {
1217   doFirst {
1218     delete getdownWebsiteDir
1219     delete getdownFilesDir
1220   }
1221 }
1222
1223
1224 install4j {
1225   if (file(install4jHomeDir).exists()) {
1226     // good to go!
1227   } else if (file(System.getProperty("user.home")+"/buildtools/install4j").exists()) {
1228     install4jHomeDir = System.getProperty("user.home")+"/buildtools/install4j"
1229   } else if (file("/Applications/install4j.app/Contents/Resources/app").exists()) {
1230     install4jHomeDir = "/Applications/install4j.app/Contents/Resources/app"
1231   }
1232   installDir(file(install4jHomeDir))
1233
1234   mediaTypes = Arrays.asList(install4j_media_types.split(","))
1235 }
1236
1237
1238 task copyInstall4jTemplate {
1239   def install4jTemplateFile = file("${install4jDir}/${install4j_template}")
1240   def install4jFileAssociationsFile = file("${install4jDir}/${install4j_installer_file_associations}")
1241   inputs.file(install4jTemplateFile)
1242   inputs.file(install4jFileAssociationsFile)
1243   outputs.file(install4jConfFile)
1244
1245   doLast {
1246     def install4jConfigXml = new XmlParser().parse(install4jTemplateFile)
1247
1248     // turn off code signing if no OSX_KEYPASS
1249     if (OSX_KEYPASS == "") {
1250       install4jConfigXml.'**'.codeSigning.each { codeSigning ->
1251         codeSigning.'@macEnabled' = "false"
1252       }
1253       install4jConfigXml.'**'.windows.each { windows ->
1254         windows.'@runPostProcessor' = "false"
1255       }
1256     }
1257
1258     // turn off checksum creation for LOCAL channel
1259     def e = install4jConfigXml.application[0]
1260     if (CHANNEL == "LOCAL") {
1261       e.'@createChecksums' = "false"
1262     } else {
1263       e.'@createChecksums' = "true"
1264     }
1265
1266     // put file association actions where placeholder action is
1267     def install4jFileAssociationsText = install4jFileAssociationsFile.text
1268     def fileAssociationActions = new XmlParser().parseText("<actions>${install4jFileAssociationsText}</actions>")
1269     install4jConfigXml.'**'.action.any { a ->
1270       if (a.'@name' == 'EXTENSIONS_REPLACED_BY_GRADLE') {
1271         def parent = a.parent()
1272         parent.remove(a)
1273         fileAssociationActions.each { faa ->
1274             parent.append(faa)
1275         }
1276         // don't need to continue in .any loop once replacements have been made
1277         return true
1278       }
1279     }
1280
1281     // write install4j file
1282     install4jConfFile.text = XmlUtil.serialize(install4jConfigXml)
1283   }
1284 }
1285
1286
1287 clean {
1288   doFirst {
1289     delete install4jConfFile
1290   }
1291 }
1292
1293
1294 task installers(type: com.install4j.gradle.Install4jTask) {
1295   group = "distribution"
1296   description = "Create the install4j installers"
1297   dependsOn setGitVals
1298   dependsOn getdown
1299   dependsOn copyInstall4jTemplate
1300
1301   projectFile = install4jConfFile
1302
1303   // create an md5 for the input files to use as version for install4j conf file
1304   def digest = MessageDigest.getInstance("MD5")
1305   digest.update(
1306     (file("${install4jDir}/${install4j_template}").text + 
1307     file("${install4jDir}/${install4j_info_plist_file_associations}").text +
1308     file("${install4jDir}/${install4j_installer_file_associations}").text).bytes)
1309   def filesMd5 = new BigInteger(1, digest.digest()).toString(16)
1310   if (filesMd5.length() >= 8) {
1311     filesMd5 = filesMd5.substring(0,8)
1312   }
1313   def install4jTemplateVersion = "${JALVIEW_VERSION}_F${filesMd5}_C${gitHash}"
1314   // make install4jBuildDir relative to jalviewDir
1315   def install4jBuildDir = "${install4j_build_dir}/${JAVA_VERSION}"
1316
1317   variables = [
1318     'JALVIEW_NAME': getdown_txt_title,
1319     'JALVIEW_DIR': "../..",
1320     'OSX_KEYSTORE': OSX_KEYSTORE,
1321     'JSIGN_SH': JSIGN_SH,
1322     'JRE_DIR': getdown_app_dir_java,
1323     'INSTALLER_TEMPLATE_VERSION': install4jTemplateVersion,
1324     'JALVIEW_VERSION': JALVIEW_VERSION,
1325     'JAVA_MIN_VERSION': JAVA_MIN_VERSION,
1326     'JAVA_MAX_VERSION': JAVA_MAX_VERSION,
1327     'JAVA_VERSION': JAVA_VERSION,
1328     'JAVA_INTEGER_VERSION': JAVA_INTEGER_VERSION,
1329     'VERSION': JALVIEW_VERSION,
1330     'MACOS_JAVA_VM_DIR': macosJavaVMDir,
1331     'WINDOWS_JAVA_VM_DIR': windowsJavaVMDir,
1332     'LINUX_JAVA_VM_DIR': linuxJavaVMDir,
1333     'MACOS_JAVA_VM_TGZ': macosJavaVMTgz,
1334     'WINDOWS_JAVA_VM_TGZ': windowsJavaVMTgz,
1335     'LINUX_JAVA_VM_TGZ': linuxJavaVMTgz,
1336     'COPYRIGHT_MESSAGE': install4j_copyright_message,
1337     'MACOS_BUNDLE_ID': install4j_macOS_bundle_id,
1338     'INSTALLER_NAME': install4j_installer_name,
1339     'INSTALL4J_UTILS_DIR': install4j_utils_dir,
1340     'GETDOWN_WEBSITE_DIR': getdown_website_dir,
1341     'GETDOWN_FILES_DIR': getdown_files_dir,
1342     'GETDOWN_RESOURCE_DIR': getdown_resource_dir,
1343     'GETDOWN_DIST_DIR': getdownAppDistDir,
1344     'GETDOWN_ALT_DIR': getdown_app_dir_alt,
1345     'GETDOWN_INSTALL_DIR': getdown_install_dir,
1346     'INFO_PLIST_FILE_ASSOCIATIONS_FILE': install4j_info_plist_file_associations,
1347     'BUILD_DIR': install4jBuildDir,
1348   ]
1349
1350   destination = "${jalviewDir}/${install4jBuildDir}"
1351   buildSelected = true
1352
1353   if (install4j_faster.equals("true") || CHANNEL.startsWith("LOCAL")) {
1354     faster = true
1355     disableSigning = true
1356   }
1357
1358   if (OSX_KEYPASS) {
1359     macKeystorePassword = OSX_KEYPASS
1360   }
1361
1362   doFirst {
1363     println("Using projectFile "+projectFile)
1364   }
1365
1366   inputs.dir(getdownWebsiteDir)
1367   inputs.file(install4jConfFile)
1368   inputs.file("${install4jDir}/${install4j_info_plist_file_associations}")
1369   inputs.dir(macosJavaVMDir)
1370   inputs.dir(windowsJavaVMDir)
1371   outputs.dir("${jalviewDir}/${install4j_build_dir}/${JAVA_VERSION}")
1372 }
1373
1374
1375 task sourceDist(type: Tar) {
1376   
1377   def VERSION_UNDERSCORES = JALVIEW_VERSION.replaceAll("\\.", "_")
1378   def outputFileName = "${project.name}_${VERSION_UNDERSCORES}.tar.gz"
1379   // cater for buildship < 3.1 [3.0.1 is max version in eclipse 2018-09]
1380   try {
1381     archiveFileName = outputFileName
1382   } catch (Exception e) {
1383     archiveName = outputFileName
1384   }
1385   
1386   compression Compression.GZIP
1387   
1388   into project.name
1389
1390   def EXCLUDE_FILES=[
1391     "build/*",
1392     "bin/*",
1393     "test-output/",
1394     "test-reports",
1395     "tests",
1396     "clover*/*",
1397     ".*",
1398     "benchmarking/*",
1399     "**/.*",
1400     "*.class",
1401     "**/*.class","$j11modDir/**/*.jar","appletlib","**/*locales",
1402     "*locales/**",
1403     "utils/InstallAnywhere",
1404     "**/*.log",
1405   ] 
1406   def PROCESS_FILES=[
1407     "AUTHORS",
1408     "CITATION",
1409     "FEATURETODO",
1410     "JAVA-11-README",
1411     "FEATURETODO",
1412     "LICENSE",
1413     "**/README",
1414     "RELEASE",
1415     "THIRDPARTYLIBS",
1416     "TESTNG",
1417     "build.gradle",
1418     "gradle.properties",
1419     "**/*.java",
1420     "**/*.html",
1421     "**/*.xml",
1422     "**/*.gradle",
1423     "**/*.groovy",
1424     "**/*.properties",
1425     "**/*.perl",
1426     "**/*.sh",
1427   ]
1428   def INCLUDE_FILES=[
1429     ".settings/org.eclipse.jdt.core.jalview.prefs",
1430   ]
1431
1432   from(jalviewDir) {
1433     exclude (EXCLUDE_FILES)
1434     include (PROCESS_FILES)
1435     filter(ReplaceTokens,
1436       beginToken: '$$',
1437       endToken: '$$',
1438       tokens: [
1439         'Version-Rel': JALVIEW_VERSION,
1440         'Year-Rel': getDate("yyyy")
1441       ]
1442     )
1443   }
1444   from(jalviewDir) {
1445     exclude (EXCLUDE_FILES)
1446     exclude (PROCESS_FILES)
1447     exclude ("appletlib")
1448     exclude ("**/*locales")
1449     exclude ("*locales/**")
1450     exclude ("utils/InstallAnywhere")
1451
1452     exclude (getdown_files_dir)
1453     exclude (getdown_website_dir)
1454
1455     // exluding these as not using jars as modules yet
1456     exclude ("$j11modDir/**/*.jar")
1457   }
1458   from(jalviewDir) {
1459     include(INCLUDE_FILES)
1460   }
1461 //  from (jalviewDir) {
1462 //    // explicit includes for stuff that seemed to not get included
1463 //    include(fileTree("test/**/*."))
1464 //    exclude(EXCLUDE_FILES)
1465 //    exclude(PROCESS_FILES)
1466 //  }
1467 }
1468
1469
1470 task helppages {
1471   dependsOn copyHelp
1472   dependsOn pubhtmlhelp
1473   
1474   inputs.dir("${classesDir}/${help_dir}")
1475   outputs.dir("${buildDir}/distributions/${help_dir}")
1476 }
1477
1478 // LARGE AMOUNT OF JALVIEWJS STUFF DELETED HERE
1479 task eclipseAutoBuildTask {}
1480 task eclipseSynchronizationTask {}