JAL-3473 Checked value of def and min. Set def to min if lower than min.
[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
6 import groovy.transform.ExternalizeMethods
7
8 buildscript {
9   dependencies {
10     classpath 'org.openclover:clover:4.3.1'
11   }
12 }
13
14 plugins {
15   id 'java'
16   id 'application'
17   id 'eclipse'
18   id 'com.github.johnrengelman.shadow' version '4.0.3'
19   id 'com.install4j.gradle' version '7.0.9'
20 }
21
22 // local build environment properties
23 def localProps = "${jalviewDir}/local.properties"
24 if (file(localProps).exists()) {
25   try {
26     def p = new Properties()
27     def localPropsFIS = new FileInputStream(localProps)
28     p.load(localPropsFIS)
29     localPropsFIS.close()
30     p.each {
31       key, val -> 
32         def over = getProperty(key) != null
33         setProperty(key, val)
34         if (over) {
35           println("Overriding property '${key}' with local.properties value '${val}'")
36         }
37     }
38   } catch (Exception e) {
39     System.out.println("Exception reading local.properties")
40   }
41 }
42
43 repositories {
44   jcenter()
45   mavenCentral()
46   mavenLocal()
47   flatDir {
48     dirs gradlePluginsDir
49   }
50 }
51
52 dependencies {
53   compile 'org.apache.commons:commons-compress:1.18'
54 }
55
56 mainClassName = launcherClass
57 def cloverInstrDir = file("${buildDir}/${cloverSourcesInstrDir}")
58 def classes = "${jalviewDir}/${classesDir}"
59
60 if (clover.equals("true")) {
61   use_clover = true
62   classes = "${buildDir}/${cloverClassesDir}"
63 } else {
64   use_clover = false
65   classes = "${jalviewDir}/${classesDir}"
66 }
67
68 // configure classpath/args for j8/j11 compilation
69
70 def jalviewDirAbsolutePath = file(jalviewDir).getAbsolutePath()
71 def libDir
72 def libDistDir
73 def compile_source_compatibility
74 def compile_target_compatibility
75
76 ext {
77   getdownWebsiteDir = "${jalviewDir}/${getdown_website_dir}/${JAVA_VERSION}"
78   getdownDir = ""
79   reportRsyncCmd = false
80   buildDist = true
81   buildProperties = buildPropertiesFile
82   getdownLauncher = "${jalviewDir}/${getdown_lib_dir}/${getdown_launcher}"
83   switch (CHANNEL) {
84
85     case "BUILD":
86     // TODO: get bamboo build artifact URL for getdown artifacts
87     getdown_channel_base = bamboo_channelbase
88     getdown_channel_name = "${bamboo_planKey}/${JAVA_VERSION}"
89     getdown_app_base = "${bamboo_channelbase}/${bamboo_planKey}${bamboo_getdown_channel_suffix}/${JAVA_VERSION}"
90     getdown_app_dir = getdown_app_dir_alt
91     buildProperties = "${jalviewDir}/${classesDir}/${buildPropertiesFile}"
92     break
93
94     case "RELEASE":
95     getdown_channel_name = CHANNEL.toLowerCase()
96     getdownDir = "${getdown_channel_name}/${JAVA_VERSION}"
97     getdown_app_base = "${getdown_channel_base}/${getdownDir}"
98     getdown_app_dir = getdown_app_dir_release
99     buildProperties = "${jalviewDir}/${classesDir}/${buildPropertiesFile}"
100     reportRsyncCommand = true
101     break
102
103     case "ARCHIVE":
104     getdown_channel_name = CHANNEL.toLowerCase()+"/${JALVIEW_VERSION}"
105     getdownDir = "${getdown_channel_name}/${JAVA_VERSION}"
106     getdown_app_base = "${getdown_channel_base}/${getdownDir}"
107     getdown_app_dir = getdown_app_dir_alt
108     if (!file("${ARCHIVEDIR}/${packageDir}").exists()) {
109       print "Must provide an ARCHIVEDIR value to produce an archive distribution"
110       exit
111     } else {
112       packageDir = "${ARCHIVEDIR}/${packageDir}"
113       buildProperties = "${ARCHIVEDIR}/${classesDir}/${buildPropertiesFile}"
114       buildDist = false
115     }
116     reportRsyncCommand = true
117     break
118
119     case "ARCHIVELOCAL":
120     getdown_channel_name = "archive/${JALVIEW_VERSION}"
121     getdownDir = "${getdown_channel_name}/${JAVA_VERSION}"
122     getdown_app_base = file(getdownWebsiteDir).toURI().toString()
123     getdown_app_dir = getdown_app_dir_alt
124     if (!file("${ARCHIVEDIR}/${packageDir}").exists()) {
125       print "Must provide an ARCHIVEDIR value to produce an archive distribution"
126       exit
127     } else {
128       packageDir = "${ARCHIVEDIR}/${packageDir}"
129       buildProperties = "${ARCHIVEDIR}/${classesDir}/${buildPropertiesFile}"
130       buildDist = false
131     }
132     reportRsyncCommand = true
133     getdownLauncher = "${jalviewDir}/${getdown_lib_dir}/${getdown_launcher_local}"
134     break
135
136     case "DEVELOP":
137     getdown_channel_name = CHANNEL.toLowerCase()
138     getdownDir = "${getdown_channel_name}/${JAVA_VERSION}"
139     getdown_app_base = "${getdown_channel_base}/${getdownDir}"
140     getdown_app_dir = getdown_app_dir_alt
141     buildProperties = "${jalviewDir}/${classesDir}/${buildPropertiesFile}"
142     reportRsyncCommand = true
143     break
144
145     case "TEST-RELEASE":
146     getdown_channel_name = CHANNEL.toLowerCase()
147     getdownDir = "${getdown_channel_name}/${JAVA_VERSION}"
148     getdown_app_base = "${getdown_channel_base}/${getdownDir}"
149     getdown_app_dir = getdown_app_dir_alt
150     buildProperties = "${jalviewDir}/${classesDir}/${buildPropertiesFile}"
151     reportRsyncCommand = true
152     break
153
154     case ~/^SCRATCH(|-[-\w]*)$/:
155     getdown_channel_name = CHANNEL
156     getdownDir = "${getdown_channel_name}/${JAVA_VERSION}"
157     getdown_app_base = "${getdown_channel_base}/${getdownDir}"
158     getdown_app_dir = getdown_app_dir_alt
159     buildProperties = "${jalviewDir}/${classesDir}/${buildPropertiesFile}"
160     reportRsyncCommand = true
161     break
162
163     case "LOCAL":
164     getdown_app_base = file(getdownWebsiteDir).toURI().toString()
165     getdown_app_dir = getdown_app_dir_alt
166     buildProperties = "${jalviewDir}/${classesDir}/${buildPropertiesFile}"
167     getdownLauncher = "${jalviewDir}/${getdown_lib_dir}/${getdown_launcher_local}"
168     break
169
170     default: // something wrong specified
171     print("CHANNEL must be one of BUILD, RELEASE, ARCHIVE, DEVELOP, TEST-RELEASE, SCRATCH-..., LOCAL [default]")
172     exit
173     break
174
175   }
176
177   getdownAppDir = "${getdownWebsiteDir}/${getdown_app_dir}"
178   //getdownJ11libDir = "${getdownWebsiteDir}/${getdown_j11lib_dir}"
179   getdownResourceDir = "${getdownWebsiteDir}/${getdown_resource_dir}"
180   getdownInstallDir = "${getdownWebsiteDir}/${getdown_install_dir}"
181   getdownFilesDir = "${jalviewDir}/${getdown_files_dir}/${JAVA_VERSION}/"
182   getdownFilesInstallDir = "${getdownFilesDir}/${getdown_install_dir}"
183   /* compile without modules -- using classpath libraries
184   modules_compileClasspath = fileTree(dir: "${jalviewDir}/${j11modDir}", include: ["*.jar"])
185   modules_runtimeClasspath = modules_compileClasspath
186   */
187   gitHash = ""
188   gitBranch = ""
189
190   println("Using a ${CHANNEL} profile.")
191 }
192
193 def JAVA_INTEGER_VERSION
194 def additional_compiler_args = []
195 // these are getdown.txt properties defined dependent on the JAVA_VERSION
196 def getdown_alt_java_min_version
197 def getdown_alt_java_max_version
198 // this property is assigned below and expanded to multiple lines in the getdown task
199 def getdown_alt_multi_java_location
200 // this property is for the Java library used in eclipse
201 def eclipse_java_runtime_name
202 if (JAVA_VERSION.equals("1.8")) {
203   JAVA_INTEGER_VERSION = "8"
204   //libDir = j8libDir
205   libDir = j11libDir
206   libDistDir = j8libDir
207   compile_source_compatibility = 1.8
208   compile_target_compatibility = 1.8
209   getdown_alt_java_min_version = getdown_alt_java8_min_version
210   getdown_alt_java_max_version = getdown_alt_java8_max_version
211   getdown_alt_multi_java_location = getdown_alt_java8_txt_multi_java_location
212   eclipse_java_runtime_name = "JavaSE-1.8"
213 } else if (JAVA_VERSION.equals("11")) {
214   JAVA_INTEGER_VERSION = "11"
215   libDir = j11libDir
216   libDistDir = j11libDir
217   compile_source_compatibility = 11
218   compile_target_compatibility = 11
219   getdown_alt_java_min_version = getdown_alt_java11_min_version
220   getdown_alt_java_max_version = getdown_alt_java11_max_version
221   getdown_alt_multi_java_location = getdown_alt_java11_txt_multi_java_location
222   eclipse_java_runtime_name = "JavaSE-11"
223   /* compile without modules -- using classpath libraries
224   additional_compiler_args += [
225   '--module-path', ext.modules_compileClasspath.asPath,
226   '--add-modules', j11modules
227   ]
228   */
229 } else if (JAVA_VERSION.equals("12") || JAVA_VERSION.equals("13")) {
230   JAVA_INTEGER_VERSION = JAVA_VERSION
231   libDir = j11libDir
232   libDistDir = j11libDir
233   compile_source_compatibility = JAVA_VERSION
234   compile_target_compatibility = JAVA_VERSION
235   getdown_alt_java_min_version = getdown_alt_java11_min_version
236   getdown_alt_java_max_version = getdown_alt_java11_max_version
237   getdown_alt_multi_java_location = getdown_alt_java11_txt_multi_java_location
238   eclipse_java_runtime_name = "JavaSE-11"
239   /* compile without modules -- using classpath libraries
240   additional_compiler_args += [
241   '--module-path', ext.modules_compileClasspath.asPath,
242   '--add-modules', j11modules
243   ]
244   */
245 } else {
246   throw new GradleException("JAVA_VERSION=${JAVA_VERSION} not currently supported by Jalview")
247 }
248
249 sourceSets {
250
251   main {
252     java {
253       srcDirs "${jalviewDir}/${sourceDir}"
254       outputDir = file("${classes}")
255     }
256
257     resources {
258       srcDirs "${jalviewDir}/${resourceDir}"
259     }
260
261     jar.destinationDir = file("${jalviewDir}/${packageDir}")
262
263     compileClasspath = files(sourceSets.main.java.outputDir)
264     compileClasspath += fileTree(dir: "${jalviewDir}/${libDir}", include: ["*.jar"])
265
266     runtimeClasspath = compileClasspath
267   }
268
269   clover {
270     java {
271       srcDirs = [ cloverInstrDir ]
272       outputDir = file("${buildDir}/${cloverClassesDir}")
273     }
274
275     resources {
276       srcDirs = sourceSets.main.resources.srcDirs
277     }
278     compileClasspath = configurations.cloverRuntime + files( sourceSets.clover.java.outputDir )
279     compileClasspath += files(sourceSets.main.java.outputDir)
280     compileClasspath += sourceSets.main.compileClasspath
281     compileClasspath += fileTree(dir: "${jalviewDir}/${utilsDir}", include: ["**/*.jar"])
282     compileClasspath += fileTree(dir: "${jalviewDir}/${libDir}", include: ["*.jar"])
283
284     runtimeClasspath = compileClasspath
285   }
286
287   test {
288     java {
289       srcDirs "${jalviewDir}/${testSourceDir}"
290       outputDir = file("${jalviewDir}/${testOutputDir}")
291     }
292
293     resources {
294       srcDirs = sourceSets.main.resources.srcDirs
295     }
296
297     compileClasspath = files( sourceSets.test.java.outputDir )
298
299     if (use_clover) {
300       compileClasspath += sourceSets.clover.compileClasspath
301     } else {
302       compileClasspath += files(sourceSets.main.java.outputDir)
303     }
304
305     compileClasspath += fileTree(dir: "${jalviewDir}/${libDir}", include: ["*.jar"])
306     compileClasspath += fileTree(dir: "${jalviewDir}/${utilsDir}/testnglibs", include: ["**/*.jar"])
307     compileClasspath += fileTree(dir: "${jalviewDir}/${utilsDir}/testlibs", include: ["**/*.jar"])
308
309     runtimeClasspath = compileClasspath
310   }
311 }
312
313 // clover bits
314 dependencies {
315   if (use_clover) {
316     cloverCompile 'org.openclover:clover:4.3.1'
317     testCompile 'org.openclover:clover:4.3.1'
318   }
319 }
320
321 configurations {
322   cloverRuntime
323   cloverRuntime.extendsFrom cloverCompile
324 }
325
326 eclipse {
327   project {
328     name = eclipse_project_name
329
330     natures 'org.eclipse.jdt.core.javanature',
331     'org.eclipse.jdt.groovy.core.groovyNature',
332     'org.eclipse.buildship.core.gradleprojectnature'
333
334     buildCommand 'org.eclipse.jdt.core.javabuilder'
335     buildCommand 'org.eclipse.buildship.core.gradleprojectbuilder'
336   }
337
338   classpath {
339     //defaultOutputDir = sourceSets.main.java.outputDir
340     def removeThese = []
341     configurations.each{
342       if (it.isCanBeResolved()) {
343         removeThese += it
344       }
345     }
346
347     minusConfigurations += removeThese
348     plusConfigurations = [ ]
349     file {
350
351       whenMerged { cp ->
352         def removeTheseToo = []
353         HashMap<String, Boolean> alreadyAddedSrcPath = new HashMap<>();
354         cp.entries.each { entry ->
355           if (entry.kind == 'src') {
356             if (alreadyAddedSrcPath.getAt(entry.path) || !(entry.path == sourceDir || entry.path == testSourceDir)) {
357               removeTheseToo += entry
358             } else {
359               alreadyAddedSrcPath.putAt(entry.path, true)
360             }
361           }
362         }
363         cp.entries.removeAll(removeTheseToo)
364
365         if (file("${jalviewDir}/${eclipse_bin_dir}/main").isDirectory()) {
366           cp.entries += new Output("${eclipse_bin_dir}/main")
367         }
368         if (file(helpParentDir).isDirectory()) {
369           cp.entries += new Library(fileReference(helpParentDir))
370         }
371         if (file(resourceDir).isDirectory()) {
372           cp.entries += new Library(fileReference(resourceDir))
373         }
374
375         HashMap<String, Boolean> alreadyAddedLibPath = new HashMap<>();
376
377         sourceSets.main.compileClasspath.findAll { it.name.endsWith(".jar") }.each {
378           //don't want to add outputDir as eclipse is using its own output dir in bin/main
379           if (it.isDirectory() || ! it.exists()) {
380             // don't add dirs to classpath
381             return
382           }
383           def itPath = it.toString()
384           if (itPath.startsWith("${jalviewDirAbsolutePath}/")) {
385             // make relative path
386             itPath = itPath.substring(jalviewDirAbsolutePath.length()+1)
387           }
388           if (alreadyAddedLibPath.get(itPath)) {
389             //println("Not adding duplicate entry "+itPath)
390           } else {
391             //println("Adding entry "+itPath)
392             cp.entries += new Library(fileReference(itPath))
393             alreadyAddedLibPath.put(itPath, true)
394           }
395         }
396
397         //fileTree(dir: "$jalviewDir/$utilsDir", include: ["test*/*.jar"]).each {
398         sourceSets.test.compileClasspath.findAll { it.name.endsWith(".jar") }.each {
399           //no longer want to add outputDir as eclipse is using its own output dir in bin/main
400           if (it.isDirectory() || ! it.exists()) {
401             // don't add dirs to classpath
402             return false // groovy "break" in .each closure
403           }
404           def itPath = it.toString()
405           if (itPath.startsWith("${jalviewDirAbsolutePath}/")) {
406             itPath = itPath.substring(jalviewDirAbsolutePath.length()+1)
407           }
408           if (alreadyAddedLibPath.get(itPath)) {
409             // don't duplicate
410           } else {
411             def lib = new Library(fileReference(itPath))
412             lib.entryAttributes["test"] = "true"
413             cp.entries += lib
414             alreadyAddedLibPath.put(itPath, true)
415           }
416         }
417
418       } // whenMerged
419
420     } // file
421
422     containers 'org.eclipse.buildship.core.gradleclasspathcontainer'
423
424   } // classpath
425
426   jdt {
427     // for the IDE, use java 11 compatibility
428     sourceCompatibility = compile_source_compatibility
429     targetCompatibility = compile_target_compatibility
430     javaRuntimeName = eclipse_java_runtime_name
431
432     // add in jalview project specific properties/preferences into eclipse core preferences
433     file {
434       withProperties { props ->
435         def jalview_prefs = new Properties()
436         def ins = new FileInputStream("${jalviewDirAbsolutePath}/${eclipse_extra_jdt_prefs_file}")
437         jalview_prefs.load(ins)
438         ins.close()
439         jalview_prefs.forEach { t, v ->
440           if (props.getAt(t) == null) {
441             props.putAt(t, v)
442           }
443         }
444       }
445     }
446
447   } // jdt
448
449 }
450
451 task cloverInstr() {
452   // only instrument source, we build test classes as normal
453   inputs.files files (sourceSets.main.allJava) // , fileTree(dir:"$jalviewDir/$testSourceDir", include: ["**/*.java"]))
454   outputs.dir cloverInstrDir
455
456   doFirst {
457     delete cloverInstrDir
458     def argsList = ["--initstring", "${buildDir}/clover/clover.db",
459     "-d", "${buildDir}/${cloverSourcesInstrDir}"]
460     argsList.addAll(inputs.files.files.collect({ file ->
461       file.absolutePath
462     }))
463     String[] args = argsList.toArray()
464     println("About to instrument "+args.length +" files")
465     com.atlassian.clover.CloverInstr.mainImpl(args)
466   }
467 }
468
469
470 task cloverReport {
471   group = "Verification"
472     description = "Createst the Clover report"
473     inputs.dir "${buildDir}/clover"
474     outputs.dir "${reportsDir}/clover"
475     onlyIf {
476       file("${buildDir}/clover/clover.db").exists()
477     }
478   doFirst {
479     def argsList = ["--initstring", "${buildDir}/clover/clover.db",
480     "-o", "${reportsDir}/clover"]
481     String[] args = argsList.toArray()
482     com.atlassian.clover.reporters.html.HtmlReporter.runReport(args)
483
484     // and generate ${reportsDir}/clover/clover.xml
485     args = ["--initstring", "${buildDir}/clover/clover.db",
486     "-o", "${reportsDir}/clover/clover.xml"].toArray()
487     com.atlassian.clover.reporters.xml.XMLReporter.runReport(args)
488   }
489 }
490
491 // end clover bits
492
493
494 compileJava {
495
496   doFirst {
497     sourceCompatibility = compile_source_compatibility
498     targetCompatibility = compile_target_compatibility
499     options.compilerArgs = additional_compiler_args
500     print ("Setting target compatibility to "+targetCompatibility+"\n")
501   }
502
503 }
504
505 compileTestJava {
506   if (use_clover) {
507     dependsOn compileCloverJava
508     classpath += configurations.cloverRuntime
509   } else {
510     classpath += sourceSets.main.runtimeClasspath
511   }
512   doFirst {
513     sourceCompatibility = compile_source_compatibility
514     targetCompatibility = compile_target_compatibility
515     options.compilerArgs = additional_compiler_args
516     print ("Setting target compatibility to "+targetCompatibility+"\n")
517   }
518 }
519
520
521 compileCloverJava {
522
523   doFirst {
524     sourceCompatibility = compile_source_compatibility
525     targetCompatibility = compile_target_compatibility
526     options.compilerArgs += additional_compiler_args
527     print ("Setting target compatibility to "+targetCompatibility+"\n")
528   }
529   classpath += configurations.cloverRuntime
530 }
531
532 clean {
533   doFirst {
534     delete sourceSets.main.java.outputDir
535   }
536 }
537
538 cleanTest {
539   doFirst {
540     delete sourceSets.test.java.outputDir
541     delete cloverInstrDir
542   }
543 }
544
545 // format is a string like date.format("dd MMMM yyyy")
546 def getDate(format) {
547   def date = new Date()
548   return date.format(format)
549 }
550
551 task setGitVals {
552   def hashStdOut = new ByteArrayOutputStream()
553   exec {
554     commandLine "git", "rev-parse", "--short", "HEAD"
555     standardOutput = hashStdOut
556     ignoreExitValue true
557   }
558
559   def branchStdOut = new ByteArrayOutputStream()
560   exec {
561     commandLine "git", "rev-parse", "--abbrev-ref", "HEAD"
562     standardOutput = branchStdOut
563     ignoreExitValue true
564   }
565
566   project.ext.gitHash = hashStdOut.toString().trim()
567   project.ext.gitBranch = branchStdOut.toString().trim()
568
569   outputs.upToDateWhen { false }
570 }
571
572 task createBuildProperties(type: WriteProperties) {
573   dependsOn setGitVals
574   inputs.dir("${jalviewDir}/${sourceDir}")
575   inputs.dir("${classes}")
576   inputs.dir("${jalviewDir}/${resourceDir}")
577   outputFile (buildProperties)
578   // taking time specific comment out to allow better incremental builds
579   comment "--Jalview Build Details--\n"+getDate("yyyy-MM-dd HH:mm:ss")
580   //comment "--Jalview Build Details--\n"+getDate("yyyy-MM-dd")
581   property "BUILD_DATE", getDate("HH:mm:ss dd MMMM yyyy")
582   property "VERSION", JALVIEW_VERSION
583   property "INSTALLATION", INSTALLATION+" git-commit:"+project.ext.gitHash+" ["+project.ext.gitBranch+"]"
584   outputs.file(outputFile)
585 }
586
587 def buildingHTML = "${jalviewDir}/${docDir}/building.html"
588 task cleanBuildingHTML(type: Delete) {
589   doFirst {
590     delete buildingHTML
591   }
592 }
593
594 task convertBuildingMD(type: Exec) {
595   dependsOn cleanBuildingHTML
596   def buildingMD = "${jalviewDir}/${docDir}/building.md"
597   def css = "${jalviewDir}/${docDir}/github.css"
598
599   def pandoc = null
600   pandoc_exec.split(",").each {
601     if (file(it.trim()).exists()) {
602       pandoc = it.trim()
603       return true
604     }
605   }
606
607   def hostname = "hostname".execute().text.trim()
608   if ((pandoc == null || ! file(pandoc).exists()) && hostname.equals("jv-bamboo")) {
609     pandoc = System.getProperty("user.home")+"/buildtools/pandoc/bin/pandoc"
610   }
611
612   doFirst {
613     if (pandoc != null && file(pandoc).exists()) {
614         commandLine pandoc, '-s', '-o', buildingHTML, '--metadata', 'pagetitle="Building Jalview from Source"', '--toc', '-H', css, buildingMD
615     } else {
616         println("Cannot find pandoc. Skipping convert building.md to HTML")
617         throw new StopExecutionException()
618     }
619   }
620
621   ignoreExitValue true
622
623   inputs.file(buildingMD)
624   inputs.file(css)
625   outputs.file(buildingHTML)
626 }
627
628 clean {
629   doFirst {
630     delete buildingHTML
631   }
632 }
633
634 task syncDocs(type: Sync) {
635   dependsOn convertBuildingMD
636   def syncDir = "${classes}/${docDir}"
637   from fileTree("${jalviewDir}/${docDir}")
638   into syncDir
639
640 }
641
642 def helpFile = "${classes}/${helpDir}/help.jhm"
643
644 task copyHelp(type: Copy) {
645   def inputDir = "${jalviewDir}/${helpParentDir}/${helpDir}"
646   def outputDir = "${classes}/${helpDir}"
647   from(inputDir) {
648     exclude '**/*.gif'
649     exclude '**/*.jpg'
650     exclude '**/*.png'
651     filter(ReplaceTokens, beginToken: '$$', endToken: '$$', tokens: ['Version-Rel': JALVIEW_VERSION,'Year-Rel': getDate("yyyy")])
652   }
653   from(inputDir) {
654     include '**/*.gif'
655     include '**/*.jpg'
656     include '**/*.png'
657   }
658   into outputDir
659
660   inputs.dir(inputDir)
661   outputs.files(helpFile)
662   outputs.dir(outputDir)
663 }
664
665 task syncLib(type: Sync) {
666   def syncDir = "${classes}/${libDistDir}"
667   from fileTree("${jalviewDir}/${libDistDir}")
668   into syncDir
669 }
670
671 task syncResources(type: Sync) {
672   from "${jalviewDir}/${resourceDir}"
673   include "**/*.*"
674   into "${classes}"
675   preserve {
676     include "**"
677   }
678 }
679
680 task prepare {
681   dependsOn syncResources
682   dependsOn syncDocs
683   dependsOn copyHelp
684 }
685
686
687 //testReportDirName = "test-reports" // note that test workingDir will be $jalviewDir
688 test {
689   dependsOn prepare
690   dependsOn compileJava
691   if (use_clover) {
692     dependsOn cloverInstr
693   }
694
695   if (use_clover) {
696     print("Running tests " + (use_clover?"WITH":"WITHOUT") + " clover [clover="+use_clover+"]\n")
697   }
698
699   useTestNG() {
700     includeGroups testngGroups
701     preserveOrder true
702     useDefaultListeners=true
703   }
704
705   workingDir = jalviewDir
706   //systemProperties 'clover.jar' System.properties.clover.jar
707   sourceCompatibility = compile_source_compatibility
708   targetCompatibility = compile_target_compatibility
709   jvmArgs += additional_compiler_args
710
711 }
712
713 task buildIndices(type: JavaExec) {
714   dependsOn copyHelp
715   classpath = sourceSets.main.compileClasspath
716   main = "com.sun.java.help.search.Indexer"
717   workingDir = "${classes}/${helpDir}"
718   def argDir = "html"
719   args = [ argDir ]
720   inputs.dir("${workingDir}/${argDir}")
721
722   outputs.dir("${classes}/doc")
723   outputs.dir("${classes}/help")
724   outputs.file("${workingDir}/JavaHelpSearch/DOCS")
725   outputs.file("${workingDir}/JavaHelpSearch/DOCS.TAB")
726   outputs.file("${workingDir}/JavaHelpSearch/OFFSETS")
727   outputs.file("${workingDir}/JavaHelpSearch/POSITIONS")
728   outputs.file("${workingDir}/JavaHelpSearch/SCHEMA")
729   outputs.file("${workingDir}/JavaHelpSearch/TMAP")
730 }
731
732 task compileLinkCheck(type: JavaCompile) {
733   options.fork = true
734   classpath = files("${jalviewDir}/${utilsDir}")
735   destinationDir = file("${jalviewDir}/${utilsDir}")
736   source = fileTree(dir: "${jalviewDir}/${utilsDir}", include: ["HelpLinksChecker.java", "BufferedLineReader.java"])
737
738   inputs.file("${jalviewDir}/${utilsDir}/HelpLinksChecker.java")
739   inputs.file("${jalviewDir}/${utilsDir}/HelpLinksChecker.java")
740   outputs.file("${jalviewDir}/${utilsDir}/HelpLinksChecker.class")
741   outputs.file("${jalviewDir}/${utilsDir}/BufferedLineReader.class")
742 }
743
744 task linkCheck(type: JavaExec) {
745   dependsOn prepare, compileLinkCheck
746
747   def helpLinksCheckerOutFile = file("${jalviewDir}/${utilsDir}/HelpLinksChecker.out")
748   classpath = files("${jalviewDir}/${utilsDir}")
749   main = "HelpLinksChecker"
750   workingDir = jalviewDir
751   def help = "${classes}/${helpDir}"
752   args = [ "${classes}/${helpDir}", "-nointernet" ]
753
754   def outFOS = new FileOutputStream(helpLinksCheckerOutFile, false) // false == don't append
755   def errFOS = outFOS
756   standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
757     outFOS,
758     standardOutput)
759   errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
760     outFOS,
761     errorOutput)
762
763   inputs.dir("${classes}/${helpDir}")
764   outputs.file(helpLinksCheckerOutFile)
765 }
766
767 // import the pubhtmlhelp target
768 ant.properties.basedir = "${jalviewDir}"
769 ant.properties.helpBuildDir = "${jalviewDirAbsolutePath}/${classes}/${helpDir}"
770 ant.importBuild "${utilsDir}/publishHelp.xml"
771
772
773 task cleanPackageDir(type: Delete) {
774   doFirst {
775     delete fileTree(dir: "${jalviewDir}/${packageDir}", include: "*.jar")
776   }
777 }
778
779 jar {
780   dependsOn linkCheck
781   dependsOn buildIndices
782   dependsOn createBuildProperties
783
784   manifest {
785     attributes "Main-Class": mainClass,
786     "Permissions": "all-permissions",
787     "Application-Name": "Jalview Desktop",
788     "Codebase": application_codebase
789   }
790
791   destinationDir = file("${jalviewDir}/${packageDir}")
792   archiveName = rootProject.name+".jar"
793
794   exclude "cache*/**"
795   exclude "*.jar"
796   exclude "*.jar.*"
797   exclude "**/*.jar"
798   exclude "**/*.jar.*"
799
800   inputs.dir("${classes}")
801   outputs.file("${jalviewDir}/${packageDir}/${archiveName}")
802 }
803
804 task copyJars(type: Copy) {
805   from fileTree(dir: "${classes}", include: "**/*.jar").files
806   into "${jalviewDir}/${packageDir}"
807 }
808
809 // doing a Sync instead of Copy as Copy doesn't deal with "outputs" very well
810 task syncJars(type: Sync) {
811   from fileTree(dir: "${jalviewDir}/${libDistDir}", include: "**/*.jar").files
812   into "${jalviewDir}/${packageDir}"
813   preserve {
814     include jar.archiveName
815   }
816 }
817
818 task makeDist {
819   group = "build"
820   description = "Put all required libraries in dist"
821   // order of "cleanPackageDir", "copyJars", "jar" important!
822   jar.mustRunAfter cleanPackageDir
823   syncJars.mustRunAfter cleanPackageDir
824   dependsOn cleanPackageDir
825   dependsOn syncJars
826   dependsOn jar
827   outputs.dir("${jalviewDir}/${packageDir}")
828 }
829
830 task cleanDist {
831   dependsOn cleanPackageDir
832   dependsOn cleanTest
833   dependsOn clean
834 }
835
836 shadowJar {
837   group = "distribution"
838   if (buildDist) {
839     dependsOn makeDist
840   }
841   from ("${jalviewDir}/${libDistDir}") {
842     include("*.jar")
843   }
844   manifest {
845     attributes 'Implementation-Version': JALVIEW_VERSION
846   }
847   mainClassName = shadowJarMainClass
848   mergeServiceFiles()
849   classifier = "all-"+JALVIEW_VERSION+"-j"+JAVA_VERSION
850   minimize()
851 }
852
853 task getdownWebsite() {
854   group = "distribution"
855   description = "Create the getdown minimal app folder, and website folder for this version of jalview. Website folder also used for offline app installer"
856   if (buildDist) {
857     dependsOn makeDist
858   }
859
860   def getdownWebsiteResourceFilenames = []
861   def getdownTextString = ""
862   def getdownResourceDir = project.ext.getdownResourceDir
863   def getdownAppDir = project.ext.getdownAppDir
864   def getdownResourceFilenames = []
865
866   doFirst {
867     // clean the getdown website and files dir before creating getdown folders
868     delete project.ext.getdownWebsiteDir
869     delete project.ext.getdownFilesDir
870
871     copy {
872       from buildProperties
873       rename(buildPropertiesFile, getdown_build_properties)
874       into project.ext.getdownAppDir
875     }
876     getdownWebsiteResourceFilenames += "${getdown_app_dir}/${getdown_build_properties}"
877
878     // go through properties looking for getdown_txt_...
879     def props = project.properties.sort { it.key }
880     if (getdown_alt_java_min_version.length() > 0) {
881       props.put("getdown_txt_java_min_version", getdown_alt_java_min_version)
882     }
883     if (getdown_alt_java_max_version.length() > 0) {
884       props.put("getdown_txt_java_max_version", getdown_alt_java_max_version)
885     }
886     props.put("getdown_txt_multi_java_location", getdown_alt_multi_java_location)
887
888     props.put("getdown_txt_appbase", getdown_app_base)
889     props.each{ prop, val ->
890       if (prop.startsWith("getdown_txt_") && val != null) {
891         if (prop.startsWith("getdown_txt_multi_")) {
892           def key = prop.substring(18)
893           val.split(",").each{ v ->
894             def line = "${key} = ${v}\n"
895             getdownTextString += line
896           }
897         } else {
898           // file values rationalised
899           if (val.indexOf('/') > -1 || prop.startsWith("getdown_txt_resource")) {
900             def r = null
901             if (val.indexOf('/') == 0) {
902               // absolute path
903               r = file(val)
904             } else if (val.indexOf('/') > 0) {
905               // relative path (relative to jalviewDir)
906               r = file( "${jalviewDir}/${val}" )
907             }
908             if (r.exists()) {
909               val = "${getdown_resource_dir}/" + r.getName()
910               getdownWebsiteResourceFilenames += val
911               getdownResourceFilenames += r.getPath()
912             }
913           }
914           if (! prop.startsWith("getdown_txt_resource")) {
915             def line = prop.substring(12) + " = ${val}\n"
916             getdownTextString += line
917           }
918         }
919       }
920     }
921
922     getdownWebsiteResourceFilenames.each{ filename ->
923       getdownTextString += "resource = ${filename}\n"
924     }
925     getdownResourceFilenames.each{ filename ->
926       copy {
927         from filename
928         into project.ext.getdownResourceDir
929       }
930     }
931
932     def codeFiles = []
933     fileTree(file(packageDir)).each{ f ->
934       if (f.isDirectory()) {
935         def files = fileTree(dir: f, include: ["*"]).getFiles()
936         codeFiles += files
937       } else if (f.exists()) {
938         codeFiles += f
939       }
940     }
941     codeFiles.sort().each{f ->
942       def name = f.getName()
943       def line = "code = ${getdown_app_dir}/${name}\n"
944       getdownTextString += line
945       copy {
946         from f.getPath()
947         into project.ext.getdownAppDir
948       }
949     }
950
951     // NOT USING MODULES YET, EVERYTHING SHOULD BE IN dist
952     /*
953     if (JAVA_VERSION.equals("11")) {
954     def j11libFiles = fileTree(dir: "${jalviewDir}/${j11libDir}", include: ["*.jar"]).getFiles()
955     j11libFiles.sort().each{f ->
956     def name = f.getName()
957     def line = "code = ${getdown_j11lib_dir}/${name}\n"
958     getdownTextString += line
959     copy {
960     from f.getPath()
961     into project.ext.getdownJ11libDir
962     }
963     }
964     }
965      */
966
967     // 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.
968     //getdownTextString += "class = " + file(getdownLauncher).getName() + "\n"
969     getdownTextString += "resource = ${getdown_launcher_new}\n"
970     getdownTextString += "class = ${mainClass}\n"
971
972     def getdown_txt = file("${project.ext.getdownWebsiteDir}/getdown.txt")
973     getdown_txt.write(getdownTextString)
974
975     def launch_jvl = file("${project.ext.getdownWebsiteDir}/${getdown_launch_jvl}")
976     launch_jvl.write("appbase="+props.get("getdown_txt_appbase"))
977
978     copy {
979       from getdownLauncher
980       rename(file(getdownLauncher).getName(), getdown_launcher_new)
981       into project.ext.getdownWebsiteDir
982     }
983
984     copy {
985       from getdownLauncher
986       if (file(getdownLauncher).getName() != getdown_launcher) {
987         rename(file(getdownLauncher).getName(), getdown_launcher)
988       }
989       into project.ext.getdownWebsiteDir
990     }
991
992     if (! (CHANNEL.startsWith("ARCHIVE") || CHANNEL.startsWith("DEVELOP"))) {
993       copy {
994         from getdown_txt
995         from getdownLauncher
996         from "${getdownWebsiteDir}/${getdown_build_properties}"
997         if (file(getdownLauncher).getName() != getdown_launcher) {
998           rename(file(getdownLauncher).getName(), getdown_launcher)
999         }
1000         into getdownInstallDir
1001       }
1002
1003       copy {
1004         from getdownInstallDir
1005         into getdownFilesInstallDir
1006       }
1007     }
1008
1009     copy {
1010       from getdown_txt
1011       from launch_jvl
1012       from getdownLauncher
1013       from "${getdownWebsiteDir}/${getdown_build_properties}"
1014       if (file(getdownLauncher).getName() != getdown_launcher) {
1015         rename(file(getdownLauncher).getName(), getdown_launcher)
1016       }
1017       into getdownFilesDir
1018     }
1019
1020     copy {
1021       from getdownResourceDir
1022       into "${project.ext.getdownFilesDir}/${getdown_resource_dir}"
1023     }
1024   }
1025
1026   if (buildDist) {
1027     inputs.dir("${jalviewDir}/${packageDir}")
1028   }
1029   outputs.dir(project.ext.getdownWebsiteDir)
1030   outputs.dir(project.ext.getdownFilesDir)
1031 }
1032
1033 task getdownDigest(type: JavaExec) {
1034   group = "distribution"
1035   description = "Digest the getdown website folder"
1036   dependsOn getdownWebsite
1037   doFirst {
1038     classpath = files("${getdownWebsiteDir}/${getdown_launcher}")
1039   }
1040   main = "com.threerings.getdown.tools.Digester"
1041   args project.ext.getdownWebsiteDir
1042   inputs.dir(project.ext.getdownWebsiteDir)
1043   outputs.file("${project.ext.getdownWebsiteDir}/digest2.txt")
1044 }
1045
1046 task getdown() {
1047   group = "distribution"
1048   description = "Create the minimal and full getdown app folder for installers and website and create digest file"
1049   dependsOn getdownDigest
1050   doLast {
1051     if (reportRsyncCommand) {
1052       def fromDir = getdownWebsiteDir + (getdownWebsiteDir.endsWith('/')?'':'/')
1053       def toDir = "${getdown_rsync_dest}/${getdownDir}" + (getdownDir.endsWith('/')?'':'/')
1054       println "LIKELY RSYNC COMMAND:"
1055       println "mkdir -p '$toDir'\nrsync -avh --delete '$fromDir' '$toDir'"
1056       if (RUNRSYNC == "true") {
1057         exec {
1058           commandLine "mkdir", "-p", toDir
1059         }
1060         exec {
1061           commandLine "rsync", "-avh", "--delete", fromDir, toDir
1062         }
1063       }
1064     }
1065   }
1066 }
1067
1068 clean {
1069   doFirst {
1070     delete project.ext.getdownWebsiteDir
1071     delete project.ext.getdownFilesDir
1072   }
1073 }
1074
1075 install4j {
1076   def install4jHomeDir = "/opt/install4j"
1077   def hostname = "hostname".execute().text.trim()
1078   if (hostname.equals("jv-bamboo")) {
1079     install4jHomeDir = System.getProperty("user.home")+"/buildtools/install4j"
1080   } else if (OperatingSystem.current().isMacOsX()) {
1081     install4jHomeDir = '/Applications/install4j.app/Contents/Resources/app'
1082     if (! file(install4jHomeDir).exists()) {
1083       install4jHomeDir = System.getProperty("user.home")+install4jHomeDir
1084     }
1085   } else if (OperatingSystem.current().isLinux()) {
1086     install4jHomeDir = System.getProperty("user.home")+"/buildtools/install4j"
1087   }
1088   installDir = file(install4jHomeDir)
1089   mediaTypes = Arrays.asList(install4jMediaTypes.split(","))
1090   if (install4jFaster.equals("true")) {
1091     faster = true
1092   }
1093 }
1094
1095 def install4jConf
1096 def macosJavaVMDir
1097 def macosJavaVMTgz
1098 def windowsJavaVMDir
1099 def windowsJavaVMTgz
1100 def install4jDir = "${jalviewDir}/${install4jResourceDir}"
1101 def install4jConfFile = "jalview-installers-java${JAVA_VERSION}.install4j"
1102 install4jConf = "${install4jDir}/${install4jConfFile}"
1103
1104 task copyInstall4jTemplate(type: Copy) {
1105   macosJavaVMDir = "${System.env.HOME}/buildtools/jre/openjdk-java_vm/getdown/macos-jre${JAVA_VERSION}/jre"
1106   macosJavaVMTgz = "${System.env.HOME}/buildtools/jre/openjdk-java_vm/install4j/tgz/macos-jre${JAVA_VERSION}.tar.gz"
1107   windowsJavaVMDir = "${System.env.HOME}/buildtools/jre/openjdk-java_vm/getdown/windows-jre${JAVA_VERSION}/jre"
1108   windowsJavaVMTgz = "${System.env.HOME}/buildtools/jre/openjdk-java_vm/install4j/tgz/windows-jre${JAVA_VERSION}.tar.gz"
1109   from (install4jDir) {
1110     include install4jTemplate
1111     rename (install4jTemplate, install4jConfFile)
1112     filter(ReplaceTokens, beginToken: '', endToken: '', tokens: ['9999999999': JAVA_VERSION])
1113     filter(ReplaceTokens, beginToken: '$$', endToken: '$$',
1114     tokens: [
1115     'JAVA_VERSION': JAVA_VERSION,
1116     'JAVA_INTEGER_VERSION': JAVA_INTEGER_VERSION,
1117     'VERSION': JALVIEW_VERSION,
1118     'MACOS_JAVA_VM_DIR': macosJavaVMDir,
1119     'MACOS_JAVA_VM_TGZ': macosJavaVMTgz,
1120     'WINDOWS_JAVA_VM_DIR': windowsJavaVMDir,
1121     'WINDOWS_JAVA_VM_TGZ': windowsJavaVMTgz,
1122     'INSTALL4JINFOPLISTFILEASSOCIATIONS': install4jInfoPlistFileAssociations,
1123     'COPYRIGHT_MESSAGE': install4jCopyrightMessage,
1124     'MACOS_BUNDLE_ID': install4jMacOSBundleId,
1125     'GETDOWN_RESOURCE_DIR': getdown_resource_dir,
1126     'GETDOWN_DIST_DIR': getdown_app_dir,
1127     'GETDOWN_ALT_DIR': getdown_app_dir_alt,
1128     'GETDOWN_INSTALL_DIR': getdown_install_dir
1129     ]
1130     )
1131     if (OSX_KEYPASS=="") {
1132       filter(ReplaceTokens, beginToken: 'codeSigning macEnabled="', endToken: '"', tokens: ['true':'codeSigning macEnabled="false"'])
1133       filter(ReplaceTokens, beginToken: 'runPostProcessor="true" ',endToken: 'Processor', tokens: ['post':'runPostProcessor="false" postProcessor'])
1134     }
1135   }
1136   into install4jDir
1137   outputs.files(install4jConf)
1138
1139   doLast {
1140     // include file associations in installer
1141     def installerFileAssociationsXml = file("${install4jDir}/${install4jInstallerFileAssociations}").text
1142     ant.replaceregexp(
1143       byline: false,
1144       flags: "s",
1145       match: '<action name="EXTENSIONS_REPLACED_BY_GRADLE".*?</action>',
1146       replace: installerFileAssociationsXml,
1147       file: install4jConf
1148     )
1149     /*
1150     // include uninstaller applescript app files in dmg
1151     def installerDMGUninstallerXml = file("$install4jDir/$install4jDMGUninstallerAppFiles").text
1152     ant.replaceregexp(
1153     byline: false,
1154     flags: "s",
1155     match: '<file name="UNINSTALL_OLD_JALVIEW_APP_REPLACED_IN_GRADLE" file=.*?>',
1156     replace: installerDMGUninstallerXml,
1157     file: install4jConf
1158     )
1159      */
1160   }
1161 }
1162
1163 task installers(type: com.install4j.gradle.Install4jTask) {
1164   group = "distribution"
1165   description = "Create the install4j installers"
1166   dependsOn getdown
1167   dependsOn copyInstall4jTemplate
1168   projectFile = file(install4jConf)
1169   variables = [majorVersion: version.substring(2, 11), build: 001, OSX_KEYSTORE: OSX_KEYSTORE, JSIGN_SH: JSIGN_SH]
1170   destination = "${jalviewDir}/${install4jBuildDir}/${JAVA_VERSION}"
1171   buildSelected = true
1172
1173   if (OSX_KEYPASS) {
1174     macKeystorePassword=OSX_KEYPASS
1175   }
1176
1177   doFirst {
1178     println("Using projectFile "+projectFile)
1179   }
1180
1181   inputs.dir(project.ext.getdownWebsiteDir)
1182   inputs.file(install4jConf)
1183   inputs.dir(macosJavaVMDir)
1184   inputs.dir(windowsJavaVMDir)
1185   outputs.dir("${jalviewDir}/${install4jBuildDir}/${JAVA_VERSION}")
1186 }
1187
1188 clean {
1189   doFirst {
1190     delete install4jConf
1191   }
1192 }
1193
1194 task sourceDist (type: Tar) {
1195   
1196   def VERSION_UNDERSCORES = JALVIEW_VERSION.replaceAll("\\.", "_")
1197   def outputFileName = "${project.name}_${VERSION_UNDERSCORES}.tar.gz"
1198   // cater for buildship < 3.1 [3.0.1 is max version in eclipse 2018-09]
1199   try {
1200     archiveFileName = outputFileName
1201   } catch (Exception e) {
1202     archiveName = outputFileName
1203   }
1204   
1205   compression Compression.GZIP
1206   
1207   into project.name
1208
1209   def EXCLUDE_FILES=["build/*","bin/*","test-output/","test-reports","tests","clover*/*"
1210   ,".*"
1211   ,"benchmarking/*"
1212   ,"**/.*"
1213   ,"*.class"
1214   ,"**/*.class","${j11modDir}/**/*.jar","appletlib","**/*locales"
1215   ,"*locales/**",
1216   ,"utils/InstallAnywhere"] 
1217   def PROCESS_FILES=[   "AUTHORS",
1218   "CITATION",
1219   "FEATURETODO",
1220   "JAVA-11-README",
1221   "FEATURETODO",
1222   "LICENSE",
1223   "**/README",
1224   "RELEASE",
1225   "THIRDPARTYLIBS","TESTNG",
1226   "build.gradle",
1227   "gradle.properties",
1228   "**/*.java",
1229   "**/*.html",
1230   "**/*.xml",
1231   "**/*.gradle",
1232   "**/*.groovy",
1233   "**/*.properties",
1234   "**/*.perl",
1235   "**/*.sh"]
1236
1237   from(jalviewDir) {
1238     exclude (EXCLUDE_FILES)
1239     include (PROCESS_FILES)
1240     filter(ReplaceTokens, beginToken: '$$', endToken: '$$', tokens: ['Version-Rel': JALVIEW_VERSION,'Year-Rel': getDate("yyyy")])
1241   }
1242   from(jalviewDir) {
1243     exclude (EXCLUDE_FILES)
1244     exclude (PROCESS_FILES)
1245   exclude ("appletlib")
1246   exclude ("**/*locales")
1247   exclude ("*locales/**")
1248   exclude ("utils/InstallAnywhere")
1249
1250     exclude (getdown_files_dir)
1251   exclude (getdown_website_dir)
1252
1253   // exluding these as not using jars as modules yet
1254   exclude ("${j11modDir}/**/*.jar")
1255 }
1256 //  from (jalviewDir) {
1257 //    // explicit includes for stuff that seemed to not get included
1258 //    include(fileTree("test/**/*."))
1259 //    exclude(EXCLUDE_FILES)
1260 //    exclude(PROCESS_FILES)
1261 //  }
1262 }
1263
1264 task helppages  {
1265   dependsOn copyHelp
1266   dependsOn pubhtmlhelp
1267   
1268   inputs.dir("${classes}/${helpDir}")
1269   outputs.dir("${helpOutputDir}")
1270 }
1271
1272 def jalviewjsBuildDir
1273 def jalviewjsSiteDir
1274 def jalviewjsTransferSiteDir
1275 task jalviewjsSitePath {
1276   def relativeBuildDir = file(jalviewDirAbsolutePath).toPath().relativize(buildDir.toPath())
1277   jalviewjsBuildDir = "${relativeBuildDir}/jalviewjs"
1278   jalviewjsSiteDir = "${jalviewjsBuildDir}/${jalviewjs_site_dir}"
1279   jalviewjsTransferSiteDir = "${jalviewjsBuildDir}/tmp/site"
1280 }
1281
1282 def eclipseWorkspace
1283 task jalviewjsSetEclipseWorkspace {
1284   def propKey = "jalviewjs_eclipse_workspace"
1285   def propVal = null
1286   if (project.hasProperty(propKey)) {
1287     propVal = project.getProperty(propKey)
1288     if (propVal.startsWith("~/")) {
1289       propVal = System.getProperty("user.home") + propVal.substring(1)
1290     }
1291   }
1292   def propsFileName = "${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_eclipse_workspace_location_file}"
1293   def propsFile = file(propsFileName)
1294   def eclipseWsDir = propVal
1295   def props = new Properties()
1296
1297   if (( eclipseWsDir == null || !file(eclipseWsDir).exists() ) && propsFile.exists()) {
1298     def ins = new FileInputStream(propsFileName)
1299     props.load(ins)
1300     ins.close()
1301     if (props.getProperty(propKey, null) != null) {
1302       eclipseWsDir = props.getProperty(propKey)
1303     }
1304   }
1305
1306   def writeProps = false
1307   if (eclipseWsDir == null || !file(eclipseWsDir).exists()) {
1308     def tempDir = File.createTempDir()
1309     eclipseWsDir = tempDir.getAbsolutePath()
1310     writeProps = true
1311   }
1312   eclipseWorkspace = file(eclipseWsDir)
1313
1314   doFirst {
1315     if (writeProps) {
1316       props.setProperty(propKey, eclipseWsDir)
1317       propsFile.parentFile.mkdirs()
1318       def bytes = new ByteArrayOutputStream()
1319       props.store(bytes, null)
1320       def propertiesString = bytes.toString()
1321       propsFile.text = propertiesString
1322     }
1323
1324     println("ECLIPSE WORKSPACE: "+eclipseWorkspace.getPath())
1325   }
1326
1327   inputs.property(propKey, eclipseWsDir)
1328   outputs.file(propsFileName)
1329 }
1330
1331
1332 def eclipseBinary
1333 def eclipseVersion
1334 def eclipseDebug = false
1335 def eclipseVersionSuffix = ""
1336 task jalviewjsEclipsePaths {
1337   def eclipseProduct
1338
1339   def eclipseRoot = jalviewjs_eclipse_root
1340   if (eclipseRoot.startsWith("~/")) {
1341     eclipseRoot = System.getProperty("user.home") + eclipseRoot.substring(1)
1342   }
1343   if (OperatingSystem.current().isMacOsX()) {
1344     eclipseRoot += "/Eclipse.app"
1345     eclipseBinary = "${eclipseRoot}/Contents/MacOS/eclipse"
1346     eclipseProduct = "${eclipseRoot}/Contents/Eclipse/.eclipseproduct"
1347   } else if (OperatingSystem.current().isWindows()) { // check these paths!!
1348     if (file("${eclipseRoot}/eclipse").isDirectory() && file("${eclipseRoot}/eclipse/.eclipseproduct").exists()) {
1349       eclipseRoot += "/eclipse"
1350     }
1351     eclipseBinary = "${eclipseRoot}/eclipse"
1352     eclipseProduct = "${eclipseRoot}/.eclipseproduct"
1353   } else { // linux or unix
1354     if (file("${eclipseRoot}/eclipse").isDirectory() && file("${eclipseRoot}/eclipse/.eclipseproduct").exists()) {
1355       eclipseRoot += "/eclipse"
1356     }
1357     eclipseBinary = "${eclipseRoot}/eclipse"
1358     eclipseProduct = "${eclipseRoot}/.eclipseproduct"
1359   }
1360
1361   eclipseVersion = "4.12" // default
1362   def assumedVersion = true
1363   if (file(eclipseProduct).exists()) {
1364     def fis = new FileInputStream(eclipseProduct)
1365     def props = new Properties()
1366     props.load(fis)
1367     eclipseVersion = props.getProperty("version")
1368     fis.close()
1369     assumedVersion = false
1370   }
1371   /*
1372   String[] v = eclipseVersion.split("\\.")
1373   def v0 = Integer.valueOf(v[0])
1374   def v1 = Integer.valueOf(v[1])
1375   if (v0 < 4 || ( v0 == 4 && v1 < 13 )) {
1376     eclipseVersionSuffix = "_4.12"
1377   } else {
1378     eclipseVersionSuffix = "_4.13"
1379   }
1380   */
1381
1382   
1383   def propKey = "eclipse_debug"
1384   eclipseDebug = (project.hasProperty(propKey) && project.getProperty(propKey).equals("true"))
1385
1386   doFirst {
1387     if (!assumedVersion) {
1388       println("ECLIPSE VERSION=${eclipseVersion}")
1389     }
1390   }
1391 }
1392
1393 task eclipseSetup {
1394   dependsOn eclipseProject
1395   dependsOn eclipseClasspath
1396   dependsOn eclipseJdt
1397 }
1398
1399 /* using the Copy task below
1400 task OLDjalviewjsEclipseCopyDropins {
1401   dependsOn jalviewjsEclipsePaths
1402   dependsOn jalviewjsCleanEclipse
1403   def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjs_eclipse_dropins_dir}", include: "*.jar")
1404   inputFiles += file(jalviewjs_j2s_plugin)
1405   def outputDir = "${buildDir}/jalviewjs
1406
1407   inputs.files inputFiles
1408   inputFiles.each { file ->
1409     outputs.file("${outputDir}/${file.name}")
1410   }
1411
1412   doLast {
1413     inputFiles.each { file ->
1414       copy {
1415         from file
1416         into outputDir
1417       }
1418     }
1419   }
1420 }
1421 */
1422
1423 // this version (type: Copy) will delete anything in the eclipse dropins folder that isn't in fromDropinsDir
1424 task jalviewjsEclipseCopyDropins(type: Copy) {
1425   dependsOn jalviewjsEclipsePaths
1426
1427   def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjs_eclipse_dropins_dir}", include: "*.jar")
1428   inputFiles += file("${jalviewDir}/${jalviewjs_j2s_plugin}")
1429   def outputDir = "${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_eclipse_tmp_dropins_dir}"
1430
1431   from inputFiles
1432   into outputDir
1433 }
1434
1435 // this eclipse -clean doesn't actually work
1436 task jalviewjsCleanEclipse(type: Exec) {
1437   dependsOn eclipseSetup
1438   dependsOn jalviewjsEclipsePaths
1439   dependsOn jalviewjsEclipseCopyDropins
1440
1441   executable(eclipseBinary)
1442   args(["-nosplash", "--launcher.suppressErrors", "-data", eclipseWorkspace.getPath(), "-clean", "-console", "-consoleLog"])
1443   if (eclipseDebug) {
1444     args += "-debug"
1445   }
1446   args += "-l"
1447
1448   def inputString = """exit
1449 y
1450 """
1451   def inputByteStream = new ByteArrayInputStream(inputString.getBytes())
1452   standardInput = inputByteStream
1453 }
1454 /* not really working yet
1455 jalviewjsEclipseCopyDropins.finalizedBy jalviewjsCleanEclipse
1456 */
1457
1458 task jalviewjsUnzipFiles {
1459   dependsOn jalviewjsSitePath
1460
1461   def zipFiles = fileTree(dir: "${jalviewDir}/${jalviewjs_libjs_dir}", include: "*.zip")
1462   zipFiles += "${jalviewDir}/${jalviewjs_swingjs_zip}"
1463
1464   doLast {
1465     zipFiles.each { file_zip -> 
1466       copy {
1467         from zipTree(file_zip)
1468         into "${jalviewDir}/${jalviewjsSiteDir}"
1469       }
1470     }
1471   }
1472
1473   inputs.files zipFiles
1474   outputs.dir "${jalviewDir}/${jalviewjsSiteDir}"
1475 }
1476
1477 task jalviewjsCreateJ2sSettings(type: WriteProperties) {
1478   group "JalviewJS"
1479   description "Create the .j2s file from the j2s.* properties"
1480
1481   dependsOn jalviewjsSitePath
1482
1483   outputFile ("${jalviewDir}/${jalviewjs_j2s_settings}")
1484   def j2s_props = project.properties.findAll { it.key.startsWith("j2s.") }.sort { it.key }
1485   def siteDirProperty = "j2s.site.directory"
1486   def setSiteDir = false
1487   j2s_props.each { prop, val ->
1488     if (val != null) {
1489       if (prop == siteDirProperty) {
1490         if (!(val.startsWith('/') || val.startsWith("file://") )) {
1491           val = "${jalviewDir}/${jalviewjsTransferSiteDir}/${val}"
1492         }
1493         setSiteDir = true
1494       }
1495       property(prop,val)
1496     }
1497     if (!setSiteDir) { // default site location, don't override specifically set property
1498       property(siteDirProperty,"${jalviewDir}/${jalviewjsTransferSiteDir}")
1499     }
1500   }
1501   inputs.properties(j2s_props)
1502   outputs.file(outputFile)
1503 }
1504
1505 task jalviewjsEclipseSetup {
1506   dependsOn jalviewjsEclipseCopyDropins
1507   dependsOn jalviewjsSetEclipseWorkspace
1508   dependsOn jalviewjsCreateJ2sSettings
1509 }
1510
1511 task jalviewjsCopyResources (type: Sync) {
1512   dependsOn jalviewjsSitePath
1513   def inputFiles = fileTree(dir: "${jalviewDir}/${resourceDir}")
1514   def outputDir = "${jalviewDir}/${jalviewjsSiteDir}/${jalviewjs_j2s_subdir}"
1515
1516   from inputFiles
1517   into outputDir
1518   def outputFiles = []
1519   rename { filename ->
1520     outputFiles += "${outputDir}/${filename}"
1521     null
1522   }
1523   preserve {
1524     include "**"
1525   }
1526   outputs.files outputFiles
1527   inputs.files inputFiles
1528 }
1529
1530 task jalviewjsCopySiteResources (type: Sync) {
1531   dependsOn jalviewjsSitePath
1532   def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjs_site_resource_dir}")
1533   def outputDir = "${jalviewDir}/${jalviewjsSiteDir}"
1534
1535   from inputFiles
1536   into outputDir
1537   def outputFiles = []
1538   rename { filename ->
1539     outputFiles += "${outputDir}/${filename}"
1540     null
1541   }
1542   preserve {
1543     include "**"
1544   }
1545   outputs.files outputFiles
1546   inputs.files inputFiles
1547 }
1548
1549 task jalviewjsProjectImport(type: Exec) {
1550   dependsOn eclipseSetup
1551   dependsOn jalviewjsEclipsePaths
1552   dependsOn jalviewjsEclipseSetup
1553
1554   def projdir = eclipseWorkspace.getPath()+"/.metadata/.plugins/org.eclipse.core.resources/.projects/jalview/org.eclipse.jdt.core"
1555   executable(eclipseBinary)
1556   args(["-nosplash", "--launcher.suppressErrors", "-application", "com.seeq.eclipse.importprojects.headlessimport", "-data", eclipseWorkspace.getPath(), "-import", jalviewDirAbsolutePath])
1557   if (eclipseDebug) {
1558     args += "-debug"
1559   }
1560   args += [ "--launcher.appendVmargs", "-vmargs", "-Dorg.eclipse.equinox.p2.reconciler.dropins.directory=${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_eclipse_tmp_dropins_dir}" ]
1561
1562   inputs.file("${jalviewDir}/.project")
1563   outputs.upToDateWhen { file(projdir).exists() }
1564 }
1565
1566 task jalviewjsTranspile(type: Exec) {
1567   dependsOn jalviewjsEclipseSetup 
1568   dependsOn jalviewjsProjectImport
1569   dependsOn jalviewjsEclipsePaths
1570
1571   executable(eclipseBinary)
1572   args(["-nosplash", "--launcher.suppressErrors", "-application", "org.eclipse.jdt.apt.core.aptBuild", "-data", eclipseWorkspace, "-${jalviewjs_eclipse_build_arg}", eclipse_project_name ])
1573   if (eclipseDebug) {
1574     args += "-debug"
1575   }
1576   args += [ "--launcher.appendVmargs", "-vmargs", "-Dorg.eclipse.equinox.p2.reconciler.dropins.directory=${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_eclipse_tmp_dropins_dir}" ]
1577
1578   def stdout
1579   def stderr
1580   doFirst {
1581     stdout = new ByteArrayOutputStream()
1582     stderr = new ByteArrayOutputStream()
1583
1584     def logOutFileName = "${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_j2s_stdout}"
1585     def logOutFile = file(logOutFileName)
1586     logOutFile.createNewFile()
1587     logOutFile.text = """ROOT: ${jalviewjs_eclipse_root}
1588 BINARY: ${eclipseBinary}
1589 VERSION: ${eclipseVersion}
1590 WORKSPACE: ${eclipseWorkspace}
1591 DEBUG: ${eclipseDebug}
1592 ----
1593 """
1594     def logOutFOS = new FileOutputStream(logOutFile, true) // true == append
1595     //def logErrFileName = "${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_j2s_stderr}"
1596     //def logErrFile = file(logFileName)
1597     //logErrFile.createNewFile()
1598     //def logErrFOS = new FileErrputStream(logErrFile, false)
1599     // combine stdout and stderr
1600     def logErrFOS = logOutFOS
1601
1602     if (jalviewjs_j2s_to_console.equals("true")) {
1603       standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
1604         new org.apache.tools.ant.util.TeeOutputStream(
1605           logOutFOS,
1606           stdout),
1607         standardOutput)
1608       errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
1609         new org.apache.tools.ant.util.TeeOutputStream(
1610           logErrFOS,
1611           stderr),
1612         errorOutput)
1613     } else {
1614       standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
1615         logOutFOS,
1616         stdout)
1617       errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
1618         logErrFOS,
1619         stderr)
1620     }
1621   }
1622
1623   doLast {
1624     if (stdout.toString().contains("Error processing ")) {
1625       // j2s did not complete transpile
1626       throw new GradleException("Error during transpilation:\n${stderr}\nSee eclipse transpile log file '${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_j2s_stdout}'")
1627     }
1628   }
1629
1630   inputs.dir("${jalviewDir}/${sourceDir}")
1631   outputs.dir("${jalviewDir}/${jalviewjsTransferSiteDir}")
1632   outputs.upToDateWhen( { file("${jalviewDir}/${jalviewjsTransferSiteDir}${jalviewjs_server_resource}").exists() } )
1633 }
1634
1635 task jalviewjsCopyTransferSite(type: Copy) {
1636   dependsOn jalviewjsTranspile
1637   from "${jalviewDir}/${jalviewjsTransferSiteDir}"
1638   into "${jalviewDir}/${jalviewjsSiteDir}"
1639 }
1640
1641 jalviewjsUnzipFiles.mustRunAfter jalviewjsCopyTransferSite
1642 jalviewjsCopyResources.mustRunAfter jalviewjsCopyTransferSite
1643 jalviewjsCopySiteResources.mustRunAfter jalviewjsCopyTransferSite
1644
1645 task jalviewjsPrepareSite {
1646   group "JalviewJS"
1647   description "Prepares the website folder including unzipping files and copying resources"
1648   dependsOn jalviewjsSitePath
1649   dependsOn jalviewjsUnzipFiles
1650   dependsOn jalviewjsCopyResources
1651   dependsOn jalviewjsCopySiteResources
1652 }
1653
1654 task jalviewjsBuildSite {
1655   group "JalviewJS"
1656   description "Builds the whole website including transpiled code"
1657   dependsOn jalviewjsCopyTransferSite
1658   dependsOn jalviewjsPrepareSite
1659 }
1660
1661 task cleanJalviewjsSite {
1662   doFirst {
1663     delete "${jalviewDir}/${jalviewjsTransferSiteDir}"
1664     delete "${jalviewDir}/${jalviewjsSiteDir}"
1665   }
1666 }
1667
1668 task jalviewjsSiteTar(type: Tar) {
1669   group "JalviewJS"
1670   description "Creates a tar.gz file for the website"
1671   dependsOn jalviewjsBuildSite
1672   def outputFilename = "jalviewjs-site-${JALVIEW_VERSION}.tar.gz"
1673   try {
1674     archiveFileName = outputFilename
1675   } catch (Exception e) {
1676     archiveName = outputFilename
1677   }
1678
1679   compression Compression.GZIP
1680
1681   from "${jalviewDir}/${jalviewjsSiteDir}"
1682   into jalviewjs_site_dir // this is inside the tar file
1683
1684   inputs.dir("${jalviewDir}/${jalviewjsSiteDir}")
1685 }
1686
1687 task jalviewjsServer {
1688   group "JalviewJS"
1689   description "Starts a webserver on localhost to test the website"
1690   dependsOn jalviewjsSitePath
1691   def htmlFile = "${jalviewDirAbsolutePath}/jalviewjsTest.html"
1692   doLast {
1693
1694     SimpleHttpFileServerFactory factory = new SimpleHttpFileServerFactory()
1695     def port = Integer.valueOf(jalviewjs_server_port)
1696     def start = port
1697     def running = false
1698     def url
1699     while(port < start+1000 && !running) {
1700       try {
1701         def doc_root = new File("${jalviewDirAbsolutePath}/${jalviewjsSiteDir}")
1702         def jalviewjsServer = factory.start(doc_root, port)
1703         running = true
1704         url = jalviewjsServer.getResourceUrl(jalviewjs_server_resource)
1705         println("SERVER STARTED with document root ${doc_root}.")
1706         println("Go to "+url+" . Run  gradle --stop  to stop (kills all gradle daemons).")
1707         println("For debug: "+url+"?j2sdebug")
1708
1709         file(htmlFile).text = """
1710         <p><a href="${url}">Jalview JS Test. &lt;${url}&gt;</a></p>
1711         <p><a href="${url}?j2sdebug">Jalview JS Test with debug. &lt;${url}?j2sdebug&lt;</a></p>
1712         """
1713
1714       } catch (Exception e) {
1715         port++;
1716       }
1717     }
1718
1719   }
1720
1721   outputs.file(htmlFile)
1722   outputs.upToDateWhen({false})
1723 }
1724
1725 task cleanJalviewjsAll {
1726   group "JalviewJS"
1727   description "Delete all configuration and build artifacts to do with JalviewJS build"
1728   dependsOn cleanJalviewjsSite
1729   dependsOn jalviewjsEclipsePaths
1730   
1731   doFirst {
1732     delete "${jalviewDir}/${jalviewjsBuildDir}"
1733     delete "${jalviewDir}/${eclipse_bin_dir}"
1734     if (eclipseWorkspace != null && file(eclipseWorkspace.getAbsolutePath()+"/.metadata").exists()) {
1735       delete file(eclipseWorkspace.getAbsolutePath()+"/.metadata")
1736     }
1737     delete "${jalviewDir}/${jalviewjs_j2s_settings}"
1738   }
1739
1740   outputs.upToDateWhen( { false } )
1741 }
1742
1743 task jalviewjs {
1744   group "JalviewJS"
1745   description "Build the site"
1746   dependsOn jalviewjsBuildSite
1747 }
1748
1749
1750 task jalviewjsIDECopyTransferSite(type: Copy) {
1751   from "${jalviewDir}/${jalviewjsTransferSiteDir}"
1752   into "${jalviewDir}/${jalviewjsSiteDir}"
1753 }
1754
1755 task jalviewjsIDEj2s {
1756   group "JalviewJS in Eclipse"
1757   description "Creates the .j2s file"
1758   dependsOn jalviewjsCreateJ2sSettings
1759 }
1760
1761 task jalviewjsIDEBuildSite {
1762   group "JalviewJS in Eclipse"
1763   description "Copies the Eclipse transpiled site and unzips supporting zipfiles"
1764   dependsOn jalviewjsIDECopyTransferSite
1765   dependsOn jalviewjsPrepareSite
1766 }
1767
1768 task jalviewjsIDESiteClean {
1769   group "JalviewJS in Eclipse"
1770   description "Deletes the Eclipse transpiled site"
1771   dependsOn cleanJalviewjsSite
1772 }
1773
1774 task jalviewjsIDEServer {
1775   group "JalviewJS in Eclipse"
1776   description "Starts a webserver on localhost to test the website"
1777   dependsOn jalviewjsServer
1778 }
1779