SwingJS update adds java.awt.Taskbar (untested)
[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 = build_properties_file
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}/${build_properties_file}"
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}/${build_properties_file}"
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}/${build_properties_file}"
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}/${build_properties_file}"
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}/${build_properties_file}"
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}/${build_properties_file}"
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}/${build_properties_file}"
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}/${build_properties_file}"
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   synchronizationTasks "eclipseSynchronizationTask"
450   autoBuildTasks "eclipseAutoBuildTask"
451
452 }
453
454 task cloverInstr() {
455   // only instrument source, we build test classes as normal
456   inputs.files files (sourceSets.main.allJava) // , fileTree(dir:"$jalviewDir/$testSourceDir", include: ["**/*.java"]))
457   outputs.dir cloverInstrDir
458
459   doFirst {
460     delete cloverInstrDir
461     def argsList = ["--initstring", "${buildDir}/clover/clover.db",
462     "-d", "${buildDir}/${cloverSourcesInstrDir}"]
463     argsList.addAll(inputs.files.files.collect({ file ->
464       file.absolutePath
465     }))
466     String[] args = argsList.toArray()
467     println("About to instrument "+args.length +" files")
468     com.atlassian.clover.CloverInstr.mainImpl(args)
469   }
470 }
471
472
473 task cloverReport {
474   group = "Verification"
475     description = "Createst the Clover report"
476     inputs.dir "${buildDir}/clover"
477     outputs.dir "${reportsDir}/clover"
478     onlyIf {
479       file("${buildDir}/clover/clover.db").exists()
480     }
481   doFirst {
482     def argsList = ["--initstring", "${buildDir}/clover/clover.db",
483     "-o", "${reportsDir}/clover"]
484     String[] args = argsList.toArray()
485     com.atlassian.clover.reporters.html.HtmlReporter.runReport(args)
486
487     // and generate ${reportsDir}/clover/clover.xml
488     args = ["--initstring", "${buildDir}/clover/clover.db",
489     "-o", "${reportsDir}/clover/clover.xml"].toArray()
490     com.atlassian.clover.reporters.xml.XMLReporter.runReport(args)
491   }
492 }
493
494 // end clover bits
495
496
497 compileJava {
498
499   doFirst {
500     sourceCompatibility = compile_source_compatibility
501     targetCompatibility = compile_target_compatibility
502     options.compilerArgs = additional_compiler_args
503     print ("Setting target compatibility to "+targetCompatibility+"\n")
504   }
505
506 }
507
508 compileTestJava {
509   if (use_clover) {
510     dependsOn compileCloverJava
511     classpath += configurations.cloverRuntime
512   } else {
513     classpath += sourceSets.main.runtimeClasspath
514   }
515   doFirst {
516     sourceCompatibility = compile_source_compatibility
517     targetCompatibility = compile_target_compatibility
518     options.compilerArgs = additional_compiler_args
519     print ("Setting target compatibility to "+targetCompatibility+"\n")
520   }
521 }
522
523
524 compileCloverJava {
525
526   doFirst {
527     sourceCompatibility = compile_source_compatibility
528     targetCompatibility = compile_target_compatibility
529     options.compilerArgs += additional_compiler_args
530     print ("Setting target compatibility to "+targetCompatibility+"\n")
531   }
532   classpath += configurations.cloverRuntime
533 }
534
535 clean {
536   doFirst {
537     delete sourceSets.main.java.outputDir
538   }
539 }
540
541 cleanTest {
542   doFirst {
543     delete sourceSets.test.java.outputDir
544     delete cloverInstrDir
545   }
546 }
547
548 // format is a string like date.format("dd MMMM yyyy")
549 def getDate(format) {
550   def date = new Date()
551   return date.format(format)
552 }
553
554 task setGitVals {
555   def hashStdOut = new ByteArrayOutputStream()
556   exec {
557     commandLine "git", "rev-parse", "--short", "HEAD"
558     standardOutput = hashStdOut
559     ignoreExitValue true
560   }
561
562   def branchStdOut = new ByteArrayOutputStream()
563   exec {
564     commandLine "git", "rev-parse", "--abbrev-ref", "HEAD"
565     standardOutput = branchStdOut
566     ignoreExitValue true
567   }
568
569   project.ext.gitHash = hashStdOut.toString().trim()
570   project.ext.gitBranch = branchStdOut.toString().trim()
571
572   outputs.upToDateWhen { false }
573 }
574
575 task createBuildProperties(type: WriteProperties) {
576   dependsOn setGitVals
577   inputs.dir("${jalviewDir}/${sourceDir}")
578   inputs.dir("${jalviewDir}/${resourceDir}")
579   file(buildProperties).getParentFile().mkdirs()
580   outputFile (buildProperties)
581   // taking time specific comment out to allow better incremental builds
582   comment "--Jalview Build Details--\n"+getDate("yyyy-MM-dd HH:mm:ss")
583   //comment "--Jalview Build Details--\n"+getDate("yyyy-MM-dd")
584   property "BUILD_DATE", getDate("HH:mm:ss dd MMMM yyyy")
585   property "VERSION", JALVIEW_VERSION
586   property "INSTALLATION", INSTALLATION+" git-commit:"+project.ext.gitHash+" ["+project.ext.gitBranch+"]"
587   outputs.file(outputFile)
588 }
589
590 def buildingHTML = "${jalviewDir}/${docDir}/building.html"
591 task cleanBuildingHTML(type: Delete) {
592   doFirst {
593     delete buildingHTML
594   }
595 }
596
597 task convertBuildingMD(type: Exec) {
598   dependsOn cleanBuildingHTML
599   def buildingMD = "${jalviewDir}/${docDir}/building.md"
600   def css = "${jalviewDir}/${docDir}/github.css"
601
602   def pandoc = null
603   pandoc_exec.split(",").each {
604     if (file(it.trim()).exists()) {
605       pandoc = it.trim()
606       return true
607     }
608   }
609
610   def hostname = "hostname".execute().text.trim()
611   if ((pandoc == null || ! file(pandoc).exists()) && hostname.equals("jv-bamboo")) {
612     pandoc = System.getProperty("user.home")+"/buildtools/pandoc/bin/pandoc"
613   }
614
615   doFirst {
616     if (pandoc != null && file(pandoc).exists()) {
617         commandLine pandoc, '-s', '-o', buildingHTML, '--metadata', 'pagetitle="Building Jalview from Source"', '--toc', '-H', css, buildingMD
618     } else {
619         println("Cannot find pandoc. Skipping convert building.md to HTML")
620         throw new StopExecutionException()
621     }
622   }
623
624   ignoreExitValue true
625
626   inputs.file(buildingMD)
627   inputs.file(css)
628   outputs.file(buildingHTML)
629 }
630
631 clean {
632   doFirst {
633     delete buildingHTML
634   }
635 }
636
637 task syncDocs(type: Sync) {
638   dependsOn convertBuildingMD
639   def syncDir = "${classes}/${docDir}"
640   from fileTree("${jalviewDir}/${docDir}")
641   into syncDir
642
643 }
644
645 def helpFile = "${classes}/${helpDir}/help.jhm"
646
647 task copyHelp(type: Copy) {
648   def inputDir = "${jalviewDir}/${helpParentDir}/${helpDir}"
649   def outputDir = "${classes}/${helpDir}"
650   from(inputDir) {
651     exclude '**/*.gif'
652     exclude '**/*.jpg'
653     exclude '**/*.png'
654     filter(ReplaceTokens, beginToken: '$$', endToken: '$$', tokens: ['Version-Rel': JALVIEW_VERSION,'Year-Rel': getDate("yyyy")])
655   }
656   from(inputDir) {
657     include '**/*.gif'
658     include '**/*.jpg'
659     include '**/*.png'
660   }
661   into outputDir
662
663   inputs.dir(inputDir)
664   outputs.files(helpFile)
665   outputs.dir(outputDir)
666 }
667
668 task syncLib(type: Sync) {
669   def syncDir = "${classes}/${libDistDir}"
670   from fileTree("${jalviewDir}/${libDistDir}")
671   into syncDir
672 }
673
674 task syncResources(type: Sync) {
675   from "${jalviewDir}/${resourceDir}"
676   include "**/*.*"
677   into "${classes}"
678   preserve {
679     include "**"
680   }
681 }
682
683 task prepare {
684   dependsOn syncResources
685   dependsOn syncDocs
686   dependsOn copyHelp
687 }
688
689
690 //testReportDirName = "test-reports" // note that test workingDir will be $jalviewDir
691 test {
692   dependsOn prepare
693   dependsOn compileJava
694   if (use_clover) {
695     dependsOn cloverInstr
696   }
697
698   if (use_clover) {
699     print("Running tests " + (use_clover?"WITH":"WITHOUT") + " clover [clover="+use_clover+"]\n")
700   }
701
702   useTestNG() {
703     includeGroups testngGroups
704     preserveOrder true
705     useDefaultListeners=true
706   }
707
708   workingDir = jalviewDir
709   //systemProperties 'clover.jar' System.properties.clover.jar
710   sourceCompatibility = compile_source_compatibility
711   targetCompatibility = compile_target_compatibility
712   jvmArgs += additional_compiler_args
713
714 }
715
716 task buildIndices(type: JavaExec) {
717   dependsOn copyHelp
718   classpath = sourceSets.main.compileClasspath
719   main = "com.sun.java.help.search.Indexer"
720   workingDir = "${classes}/${helpDir}"
721   def argDir = "html"
722   args = [ argDir ]
723   inputs.dir("${workingDir}/${argDir}")
724
725   outputs.dir("${classes}/doc")
726   outputs.dir("${classes}/help")
727   outputs.file("${workingDir}/JavaHelpSearch/DOCS")
728   outputs.file("${workingDir}/JavaHelpSearch/DOCS.TAB")
729   outputs.file("${workingDir}/JavaHelpSearch/OFFSETS")
730   outputs.file("${workingDir}/JavaHelpSearch/POSITIONS")
731   outputs.file("${workingDir}/JavaHelpSearch/SCHEMA")
732   outputs.file("${workingDir}/JavaHelpSearch/TMAP")
733 }
734
735 task compileLinkCheck(type: JavaCompile) {
736   options.fork = true
737   classpath = files("${jalviewDir}/${utilsDir}")
738   destinationDir = file("${jalviewDir}/${utilsDir}")
739   source = fileTree(dir: "${jalviewDir}/${utilsDir}", include: ["HelpLinksChecker.java", "BufferedLineReader.java"])
740
741   inputs.file("${jalviewDir}/${utilsDir}/HelpLinksChecker.java")
742   inputs.file("${jalviewDir}/${utilsDir}/HelpLinksChecker.java")
743   outputs.file("${jalviewDir}/${utilsDir}/HelpLinksChecker.class")
744   outputs.file("${jalviewDir}/${utilsDir}/BufferedLineReader.class")
745 }
746
747 task linkCheck(type: JavaExec) {
748   dependsOn prepare, compileLinkCheck
749
750   def helpLinksCheckerOutFile = file("${jalviewDir}/${utilsDir}/HelpLinksChecker.out")
751   classpath = files("${jalviewDir}/${utilsDir}")
752   main = "HelpLinksChecker"
753   workingDir = jalviewDir
754   def help = "${classes}/${helpDir}"
755   args = [ "${classes}/${helpDir}", "-nointernet" ]
756
757   def outFOS = new FileOutputStream(helpLinksCheckerOutFile, false) // false == don't append
758   def errFOS = outFOS
759   standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
760     outFOS,
761     standardOutput)
762   errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
763     outFOS,
764     errorOutput)
765
766   inputs.dir("${classes}/${helpDir}")
767   outputs.file(helpLinksCheckerOutFile)
768 }
769
770 // import the pubhtmlhelp target
771 ant.properties.basedir = "${jalviewDir}"
772 ant.properties.helpBuildDir = "${jalviewDirAbsolutePath}/${classes}/${helpDir}"
773 ant.importBuild "${utilsDir}/publishHelp.xml"
774
775
776 task cleanPackageDir(type: Delete) {
777   doFirst {
778     delete fileTree(dir: "${jalviewDir}/${packageDir}", include: "*.jar")
779   }
780 }
781
782 jar {
783   dependsOn linkCheck
784   dependsOn buildIndices
785   dependsOn createBuildProperties
786
787   manifest {
788     attributes "Main-Class": mainClass,
789     "Permissions": "all-permissions",
790     "Application-Name": "Jalview Desktop",
791     "Codebase": application_codebase
792   }
793
794   destinationDir = file("${jalviewDir}/${packageDir}")
795   archiveName = rootProject.name+".jar"
796
797   exclude "cache*/**"
798   exclude "*.jar"
799   exclude "*.jar.*"
800   exclude "**/*.jar"
801   exclude "**/*.jar.*"
802
803   inputs.dir("${classes}")
804   outputs.file("${jalviewDir}/${packageDir}/${archiveName}")
805 }
806
807 task copyJars(type: Copy) {
808   from fileTree(dir: "${classes}", include: "**/*.jar").files
809   into "${jalviewDir}/${packageDir}"
810 }
811
812 // doing a Sync instead of Copy as Copy doesn't deal with "outputs" very well
813 task syncJars(type: Sync) {
814   from fileTree(dir: "${jalviewDir}/${libDistDir}", include: "**/*.jar").files
815   into "${jalviewDir}/${packageDir}"
816   preserve {
817     include jar.archiveName
818   }
819 }
820
821 task makeDist {
822   group = "build"
823   description = "Put all required libraries in dist"
824   // order of "cleanPackageDir", "copyJars", "jar" important!
825   jar.mustRunAfter cleanPackageDir
826   syncJars.mustRunAfter cleanPackageDir
827   dependsOn cleanPackageDir
828   dependsOn syncJars
829   dependsOn jar
830   outputs.dir("${jalviewDir}/${packageDir}")
831 }
832
833 task cleanDist {
834   dependsOn cleanPackageDir
835   dependsOn cleanTest
836   dependsOn clean
837 }
838
839 shadowJar {
840   group = "distribution"
841   if (buildDist) {
842     dependsOn makeDist
843   }
844   from ("${jalviewDir}/${libDistDir}") {
845     include("*.jar")
846   }
847   manifest {
848     attributes 'Implementation-Version': JALVIEW_VERSION
849   }
850   mainClassName = shadowJarMainClass
851   mergeServiceFiles()
852   classifier = "all-"+JALVIEW_VERSION+"-j"+JAVA_VERSION
853   minimize()
854 }
855
856 task getdownWebsite() {
857   group = "distribution"
858   description = "Create the getdown minimal app folder, and website folder for this version of jalview. Website folder also used for offline app installer"
859   if (buildDist) {
860     dependsOn makeDist
861   }
862
863   def getdownWebsiteResourceFilenames = []
864   def getdownTextString = ""
865   def getdownResourceDir = project.ext.getdownResourceDir
866   def getdownAppDir = project.ext.getdownAppDir
867   def getdownResourceFilenames = []
868
869   doFirst {
870     // clean the getdown website and files dir before creating getdown folders
871     delete project.ext.getdownWebsiteDir
872     delete project.ext.getdownFilesDir
873
874     copy {
875       from buildProperties
876       rename(build_properties_file, getdown_build_properties)
877       into project.ext.getdownAppDir
878     }
879     getdownWebsiteResourceFilenames += "${getdown_app_dir}/${getdown_build_properties}"
880
881     // go through properties looking for getdown_txt_...
882     def props = project.properties.sort { it.key }
883     if (getdown_alt_java_min_version.length() > 0) {
884       props.put("getdown_txt_java_min_version", getdown_alt_java_min_version)
885     }
886     if (getdown_alt_java_max_version.length() > 0) {
887       props.put("getdown_txt_java_max_version", getdown_alt_java_max_version)
888     }
889     props.put("getdown_txt_multi_java_location", getdown_alt_multi_java_location)
890
891     props.put("getdown_txt_appbase", getdown_app_base)
892     props.each{ prop, val ->
893       if (prop.startsWith("getdown_txt_") && val != null) {
894         if (prop.startsWith("getdown_txt_multi_")) {
895           def key = prop.substring(18)
896           val.split(",").each{ v ->
897             def line = "${key} = ${v}\n"
898             getdownTextString += line
899           }
900         } else {
901           // file values rationalised
902           if (val.indexOf('/') > -1 || prop.startsWith("getdown_txt_resource")) {
903             def r = null
904             if (val.indexOf('/') == 0) {
905               // absolute path
906               r = file(val)
907             } else if (val.indexOf('/') > 0) {
908               // relative path (relative to jalviewDir)
909               r = file( "${jalviewDir}/${val}" )
910             }
911             if (r.exists()) {
912               val = "${getdown_resource_dir}/" + r.getName()
913               getdownWebsiteResourceFilenames += val
914               getdownResourceFilenames += r.getPath()
915             }
916           }
917           if (! prop.startsWith("getdown_txt_resource")) {
918             def line = prop.substring(12) + " = ${val}\n"
919             getdownTextString += line
920           }
921         }
922       }
923     }
924
925     getdownWebsiteResourceFilenames.each{ filename ->
926       getdownTextString += "resource = ${filename}\n"
927     }
928     getdownResourceFilenames.each{ filename ->
929       copy {
930         from filename
931         into project.ext.getdownResourceDir
932       }
933     }
934
935     def codeFiles = []
936     fileTree(file(packageDir)).each{ f ->
937       if (f.isDirectory()) {
938         def files = fileTree(dir: f, include: ["*"]).getFiles()
939         codeFiles += files
940       } else if (f.exists()) {
941         codeFiles += f
942       }
943     }
944     codeFiles.sort().each{f ->
945       def name = f.getName()
946       def line = "code = ${getdown_app_dir}/${name}\n"
947       getdownTextString += line
948       copy {
949         from f.getPath()
950         into project.ext.getdownAppDir
951       }
952     }
953
954     // NOT USING MODULES YET, EVERYTHING SHOULD BE IN dist
955     /*
956     if (JAVA_VERSION.equals("11")) {
957     def j11libFiles = fileTree(dir: "${jalviewDir}/${j11libDir}", include: ["*.jar"]).getFiles()
958     j11libFiles.sort().each{f ->
959     def name = f.getName()
960     def line = "code = ${getdown_j11lib_dir}/${name}\n"
961     getdownTextString += line
962     copy {
963     from f.getPath()
964     into project.ext.getdownJ11libDir
965     }
966     }
967     }
968      */
969
970     // 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.
971     //getdownTextString += "class = " + file(getdownLauncher).getName() + "\n"
972     getdownTextString += "resource = ${getdown_launcher_new}\n"
973     getdownTextString += "class = ${mainClass}\n"
974
975     def getdown_txt = file("${project.ext.getdownWebsiteDir}/getdown.txt")
976     getdown_txt.write(getdownTextString)
977
978     def launch_jvl = file("${project.ext.getdownWebsiteDir}/${getdown_launch_jvl}")
979     launch_jvl.write("appbase="+props.get("getdown_txt_appbase"))
980
981     copy {
982       from getdownLauncher
983       rename(file(getdownLauncher).getName(), getdown_launcher_new)
984       into project.ext.getdownWebsiteDir
985     }
986
987     copy {
988       from getdownLauncher
989       if (file(getdownLauncher).getName() != getdown_launcher) {
990         rename(file(getdownLauncher).getName(), getdown_launcher)
991       }
992       into project.ext.getdownWebsiteDir
993     }
994
995     if (! (CHANNEL.startsWith("ARCHIVE") || CHANNEL.startsWith("DEVELOP"))) {
996       copy {
997         from getdown_txt
998         from getdownLauncher
999         from "${getdownWebsiteDir}/${getdown_build_properties}"
1000         if (file(getdownLauncher).getName() != getdown_launcher) {
1001           rename(file(getdownLauncher).getName(), getdown_launcher)
1002         }
1003         into getdownInstallDir
1004       }
1005
1006       copy {
1007         from getdownInstallDir
1008         into getdownFilesInstallDir
1009       }
1010     }
1011
1012     copy {
1013       from getdown_txt
1014       from launch_jvl
1015       from getdownLauncher
1016       from "${getdownWebsiteDir}/${getdown_build_properties}"
1017       if (file(getdownLauncher).getName() != getdown_launcher) {
1018         rename(file(getdownLauncher).getName(), getdown_launcher)
1019       }
1020       into getdownFilesDir
1021     }
1022
1023     copy {
1024       from getdownResourceDir
1025       into "${project.ext.getdownFilesDir}/${getdown_resource_dir}"
1026     }
1027   }
1028
1029   if (buildDist) {
1030     inputs.dir("${jalviewDir}/${packageDir}")
1031   }
1032   outputs.dir(project.ext.getdownWebsiteDir)
1033   outputs.dir(project.ext.getdownFilesDir)
1034 }
1035
1036 task getdownDigest(type: JavaExec) {
1037   group = "distribution"
1038   description = "Digest the getdown website folder"
1039   dependsOn getdownWebsite
1040   doFirst {
1041     classpath = files("${getdownWebsiteDir}/${getdown_launcher}")
1042   }
1043   main = "com.threerings.getdown.tools.Digester"
1044   args project.ext.getdownWebsiteDir
1045   inputs.dir(project.ext.getdownWebsiteDir)
1046   outputs.file("${project.ext.getdownWebsiteDir}/digest2.txt")
1047 }
1048
1049 task getdown() {
1050   group = "distribution"
1051   description = "Create the minimal and full getdown app folder for installers and website and create digest file"
1052   dependsOn getdownDigest
1053   doLast {
1054     if (reportRsyncCommand) {
1055       def fromDir = getdownWebsiteDir + (getdownWebsiteDir.endsWith('/')?'':'/')
1056       def toDir = "${getdown_rsync_dest}/${getdownDir}" + (getdownDir.endsWith('/')?'':'/')
1057       println "LIKELY RSYNC COMMAND:"
1058       println "mkdir -p '$toDir'\nrsync -avh --delete '$fromDir' '$toDir'"
1059       if (RUNRSYNC == "true") {
1060         exec {
1061           commandLine "mkdir", "-p", toDir
1062         }
1063         exec {
1064           commandLine "rsync", "-avh", "--delete", fromDir, toDir
1065         }
1066       }
1067     }
1068   }
1069 }
1070
1071 clean {
1072   doFirst {
1073     delete project.ext.getdownWebsiteDir
1074     delete project.ext.getdownFilesDir
1075   }
1076 }
1077
1078 install4j {
1079   def install4jHomeDir = "/opt/install4j"
1080   def hostname = "hostname".execute().text.trim()
1081   if (hostname.equals("jv-bamboo")) {
1082     install4jHomeDir = System.getProperty("user.home")+"/buildtools/install4j"
1083   } else if (OperatingSystem.current().isMacOsX()) {
1084     install4jHomeDir = '/Applications/install4j.app/Contents/Resources/app'
1085     if (! file(install4jHomeDir).exists()) {
1086       install4jHomeDir = System.getProperty("user.home")+install4jHomeDir
1087     }
1088   } else if (OperatingSystem.current().isLinux()) {
1089     install4jHomeDir = System.getProperty("user.home")+"/buildtools/install4j"
1090   }
1091   installDir = file(install4jHomeDir)
1092   mediaTypes = Arrays.asList(install4jMediaTypes.split(","))
1093   if (install4jFaster.equals("true")) {
1094     faster = true
1095   }
1096 }
1097
1098 def install4jConf
1099 def macosJavaVMDir
1100 def macosJavaVMTgz
1101 def windowsJavaVMDir
1102 def windowsJavaVMTgz
1103 def install4jDir = "${jalviewDir}/${install4jResourceDir}"
1104 def install4jConfFile = "jalview-installers-java${JAVA_VERSION}.install4j"
1105 install4jConf = "${install4jDir}/${install4jConfFile}"
1106
1107 task copyInstall4jTemplate(type: Copy) {
1108   macosJavaVMDir = "${System.env.HOME}/buildtools/jre/openjdk-java_vm/getdown/macos-jre${JAVA_VERSION}/jre"
1109   macosJavaVMTgz = "${System.env.HOME}/buildtools/jre/openjdk-java_vm/install4j/tgz/macos-jre${JAVA_VERSION}.tar.gz"
1110   windowsJavaVMDir = "${System.env.HOME}/buildtools/jre/openjdk-java_vm/getdown/windows-jre${JAVA_VERSION}/jre"
1111   windowsJavaVMTgz = "${System.env.HOME}/buildtools/jre/openjdk-java_vm/install4j/tgz/windows-jre${JAVA_VERSION}.tar.gz"
1112   from (install4jDir) {
1113     include install4jTemplate
1114     rename (install4jTemplate, install4jConfFile)
1115     filter(ReplaceTokens, beginToken: '', endToken: '', tokens: ['9999999999': JAVA_VERSION])
1116     filter(ReplaceTokens, beginToken: '$$', endToken: '$$',
1117     tokens: [
1118     'JAVA_VERSION': JAVA_VERSION,
1119     'JAVA_INTEGER_VERSION': JAVA_INTEGER_VERSION,
1120     'VERSION': JALVIEW_VERSION,
1121     'MACOS_JAVA_VM_DIR': macosJavaVMDir,
1122     'MACOS_JAVA_VM_TGZ': macosJavaVMTgz,
1123     'WINDOWS_JAVA_VM_DIR': windowsJavaVMDir,
1124     'WINDOWS_JAVA_VM_TGZ': windowsJavaVMTgz,
1125     'INSTALL4JINFOPLISTFILEASSOCIATIONS': install4jInfoPlistFileAssociations,
1126     'COPYRIGHT_MESSAGE': install4jCopyrightMessage,
1127     'MACOS_BUNDLE_ID': install4jMacOSBundleId,
1128     'GETDOWN_RESOURCE_DIR': getdown_resource_dir,
1129     'GETDOWN_DIST_DIR': getdown_app_dir,
1130     'GETDOWN_ALT_DIR': getdown_app_dir_alt,
1131     'GETDOWN_INSTALL_DIR': getdown_install_dir
1132     ]
1133     )
1134     if (OSX_KEYPASS=="") {
1135       filter(ReplaceTokens, beginToken: 'codeSigning macEnabled="', endToken: '"', tokens: ['true':'codeSigning macEnabled="false"'])
1136       filter(ReplaceTokens, beginToken: 'runPostProcessor="true" ',endToken: 'Processor', tokens: ['post':'runPostProcessor="false" postProcessor'])
1137     }
1138   }
1139   into install4jDir
1140   outputs.files(install4jConf)
1141
1142   doLast {
1143     // include file associations in installer
1144     def installerFileAssociationsXml = file("${install4jDir}/${install4jInstallerFileAssociations}").text
1145     ant.replaceregexp(
1146       byline: false,
1147       flags: "s",
1148       match: '<action name="EXTENSIONS_REPLACED_BY_GRADLE".*?</action>',
1149       replace: installerFileAssociationsXml,
1150       file: install4jConf
1151     )
1152     /*
1153     // include uninstaller applescript app files in dmg
1154     def installerDMGUninstallerXml = file("$install4jDir/$install4jDMGUninstallerAppFiles").text
1155     ant.replaceregexp(
1156     byline: false,
1157     flags: "s",
1158     match: '<file name="UNINSTALL_OLD_JALVIEW_APP_REPLACED_IN_GRADLE" file=.*?>',
1159     replace: installerDMGUninstallerXml,
1160     file: install4jConf
1161     )
1162      */
1163   }
1164 }
1165
1166 task installers(type: com.install4j.gradle.Install4jTask) {
1167   group = "distribution"
1168   description = "Create the install4j installers"
1169   dependsOn getdown
1170   dependsOn copyInstall4jTemplate
1171   projectFile = file(install4jConf)
1172   variables = [majorVersion: version.substring(2, 11), build: 001, OSX_KEYSTORE: OSX_KEYSTORE, JSIGN_SH: JSIGN_SH]
1173   destination = "${jalviewDir}/${install4jBuildDir}/${JAVA_VERSION}"
1174   buildSelected = true
1175
1176   if (OSX_KEYPASS) {
1177     macKeystorePassword=OSX_KEYPASS
1178   }
1179
1180   doFirst {
1181     println("Using projectFile "+projectFile)
1182   }
1183
1184   inputs.dir(project.ext.getdownWebsiteDir)
1185   inputs.file(install4jConf)
1186   inputs.dir(macosJavaVMDir)
1187   inputs.dir(windowsJavaVMDir)
1188   outputs.dir("${jalviewDir}/${install4jBuildDir}/${JAVA_VERSION}")
1189 }
1190
1191 clean {
1192   doFirst {
1193     delete install4jConf
1194   }
1195 }
1196
1197 task sourceDist (type: Tar) {
1198   
1199   def VERSION_UNDERSCORES = JALVIEW_VERSION.replaceAll("\\.", "_")
1200   def outputFileName = "${project.name}_${VERSION_UNDERSCORES}.tar.gz"
1201   // cater for buildship < 3.1 [3.0.1 is max version in eclipse 2018-09]
1202   try {
1203     archiveFileName = outputFileName
1204   } catch (Exception e) {
1205     archiveName = outputFileName
1206   }
1207   
1208   compression Compression.GZIP
1209   
1210   into project.name
1211
1212   def EXCLUDE_FILES=["build/*","bin/*","test-output/","test-reports","tests","clover*/*"
1213   ,".*"
1214   ,"benchmarking/*"
1215   ,"**/.*"
1216   ,"*.class"
1217   ,"**/*.class","${j11modDir}/**/*.jar","appletlib","**/*locales"
1218   ,"*locales/**",
1219   ,"utils/InstallAnywhere"] 
1220   def PROCESS_FILES=[   "AUTHORS",
1221   "CITATION",
1222   "FEATURETODO",
1223   "JAVA-11-README",
1224   "FEATURETODO",
1225   "LICENSE",
1226   "**/README",
1227   "RELEASE",
1228   "THIRDPARTYLIBS","TESTNG",
1229   "build.gradle",
1230   "gradle.properties",
1231   "**/*.java",
1232   "**/*.html",
1233   "**/*.xml",
1234   "**/*.gradle",
1235   "**/*.groovy",
1236   "**/*.properties",
1237   "**/*.perl",
1238   "**/*.sh"]
1239
1240   from(jalviewDir) {
1241     exclude (EXCLUDE_FILES)
1242     include (PROCESS_FILES)
1243     filter(ReplaceTokens, beginToken: '$$', endToken: '$$', tokens: ['Version-Rel': JALVIEW_VERSION,'Year-Rel': getDate("yyyy")])
1244   }
1245   from(jalviewDir) {
1246     exclude (EXCLUDE_FILES)
1247     exclude (PROCESS_FILES)
1248   exclude ("appletlib")
1249   exclude ("**/*locales")
1250   exclude ("*locales/**")
1251   exclude ("utils/InstallAnywhere")
1252
1253     exclude (getdown_files_dir)
1254   exclude (getdown_website_dir)
1255
1256   // exluding these as not using jars as modules yet
1257   exclude ("${j11modDir}/**/*.jar")
1258 }
1259 //  from (jalviewDir) {
1260 //    // explicit includes for stuff that seemed to not get included
1261 //    include(fileTree("test/**/*."))
1262 //    exclude(EXCLUDE_FILES)
1263 //    exclude(PROCESS_FILES)
1264 //  }
1265 }
1266
1267 task helppages  {
1268   dependsOn copyHelp
1269   dependsOn pubhtmlhelp
1270   
1271   inputs.dir("${classes}/${helpDir}")
1272   outputs.dir("${helpOutputDir}")
1273 }
1274
1275 def jalviewjsBuildDir
1276 def jalviewjsSiteDir
1277 def jalviewjsTransferSiteJsDir
1278 def jalviewjsTransferSiteLibDir
1279 def jalviewjsTransferSiteCoreDir
1280 task jalviewjsSitePath {
1281   def relativeBuildDir = file(jalviewDirAbsolutePath).toPath().relativize(buildDir.toPath())
1282   jalviewjsBuildDir = "${relativeBuildDir}/jalviewjs"
1283   jalviewjsSiteDir = "${jalviewjsBuildDir}/${jalviewjs_site_dir}"
1284   jalviewjsTransferSiteJsDir = "${jalviewjsBuildDir}/tmp/${jalviewjs_site_dir}_js"
1285   jalviewjsTransferSiteLibDir = "${jalviewjsBuildDir}/tmp/${jalviewjs_site_dir}_lib"
1286   jalviewjsTransferSiteCoreDir = "${jalviewjsBuildDir}/tmp/${jalviewjs_site_dir}_core"
1287 }
1288
1289 def eclipseWorkspace
1290 task jalviewjsSetEclipseWorkspace {
1291   def propKey = "jalviewjs_eclipse_workspace"
1292   def propVal = null
1293   if (project.hasProperty(propKey)) {
1294     propVal = project.getProperty(propKey)
1295     if (propVal.startsWith("~/")) {
1296       propVal = System.getProperty("user.home") + propVal.substring(1)
1297     }
1298   }
1299   def propsFileName = "${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_eclipse_workspace_location_file}"
1300   def propsFile = file(propsFileName)
1301   def eclipseWsDir = propVal
1302   def props = new Properties()
1303
1304   if (( eclipseWsDir == null || !file(eclipseWsDir).exists() ) && propsFile.exists()) {
1305     def ins = new FileInputStream(propsFileName)
1306     props.load(ins)
1307     ins.close()
1308     if (props.getProperty(propKey, null) != null) {
1309       eclipseWsDir = props.getProperty(propKey)
1310     }
1311   }
1312
1313   def writeProps = false
1314   if (eclipseWsDir == null || !file(eclipseWsDir).exists()) {
1315     def tempDir = File.createTempDir()
1316     eclipseWsDir = tempDir.getAbsolutePath()
1317     writeProps = true
1318   }
1319   eclipseWorkspace = file(eclipseWsDir)
1320
1321   doFirst {
1322     if (writeProps) {
1323       props.setProperty(propKey, eclipseWsDir)
1324       propsFile.parentFile.mkdirs()
1325       def bytes = new ByteArrayOutputStream()
1326       props.store(bytes, null)
1327       def propertiesString = bytes.toString()
1328       propsFile.text = propertiesString
1329     }
1330
1331     println("ECLIPSE WORKSPACE: "+eclipseWorkspace.getPath())
1332   }
1333
1334   //inputs.property(propKey, eclipseWsDir) // eclipseWsDir only gets set once this task runs, so will be out-of-date
1335   outputs.file(propsFileName)
1336   outputs.upToDateWhen { eclipseWorkspace.exists() }
1337 }
1338
1339
1340 def eclipseBinary
1341 def eclipseVersion
1342 def eclipseDebug = false
1343 def eclipseVersionSuffix = ""
1344 task jalviewjsEclipsePaths {
1345   def eclipseProduct
1346
1347   def eclipseRoot = jalviewjs_eclipse_root
1348   if (eclipseRoot.startsWith("~/")) {
1349     eclipseRoot = System.getProperty("user.home") + eclipseRoot.substring(1)
1350   }
1351   if (OperatingSystem.current().isMacOsX()) {
1352     eclipseRoot += "/Eclipse.app"
1353     eclipseBinary = "${eclipseRoot}/Contents/MacOS/eclipse"
1354     eclipseProduct = "${eclipseRoot}/Contents/Eclipse/.eclipseproduct"
1355   } else if (OperatingSystem.current().isWindows()) { // check these paths!!
1356     if (file("${eclipseRoot}/eclipse").isDirectory() && file("${eclipseRoot}/eclipse/.eclipseproduct").exists()) {
1357       eclipseRoot += "/eclipse.exe"
1358     }
1359     eclipseBinary = "${eclipseRoot}/eclipse"
1360     eclipseProduct = "${eclipseRoot}/.eclipseproduct"
1361   } else { // linux or unix
1362     if (file("${eclipseRoot}/eclipse").isDirectory() && file("${eclipseRoot}/eclipse/.eclipseproduct").exists()) {
1363       eclipseRoot += "/eclipse"
1364     }
1365     eclipseBinary = "${eclipseRoot}/eclipse"
1366     eclipseProduct = "${eclipseRoot}/.eclipseproduct"
1367   }
1368
1369   eclipseVersion = "4.13" // default
1370   def assumedVersion = true
1371   if (file(eclipseProduct).exists()) {
1372     def fis = new FileInputStream(eclipseProduct)
1373     def props = new Properties()
1374     props.load(fis)
1375     eclipseVersion = props.getProperty("version")
1376     fis.close()
1377     assumedVersion = false
1378   }
1379   
1380   def propKey = "eclipse_debug"
1381   eclipseDebug = (project.hasProperty(propKey) && project.getProperty(propKey).equals("true"))
1382
1383   doFirst {
1384     if (!assumedVersion) {
1385       println("ECLIPSE VERSION=${eclipseVersion}")
1386     }
1387   }
1388 }
1389
1390 task eclipseSetup {
1391   dependsOn eclipseProject
1392   dependsOn eclipseClasspath
1393   dependsOn eclipseJdt
1394 }
1395
1396 // this version (type: Copy) will delete anything in the eclipse dropins folder that isn't in fromDropinsDir
1397 task jalviewjsEclipseCopyDropins(type: Copy) {
1398   dependsOn jalviewjsEclipsePaths
1399
1400   def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjs_eclipse_dropins_dir}", include: "*.jar")
1401   inputFiles += file("${jalviewDir}/${jalviewjs_j2s_plugin}")
1402   def outputDir = "${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_eclipse_tmp_dropins_dir}"
1403
1404   from inputFiles
1405   into outputDir
1406 }
1407
1408 // this eclipse -clean doesn't actually work
1409 task jalviewjsCleanEclipse(type: Exec) {
1410   dependsOn eclipseSetup
1411   dependsOn jalviewjsEclipsePaths
1412   dependsOn jalviewjsEclipseCopyDropins
1413
1414   executable(eclipseBinary)
1415   args(["-nosplash", "--launcher.suppressErrors", "-data", eclipseWorkspace.getPath(), "-clean", "-console", "-consoleLog"])
1416   if (eclipseDebug) {
1417     args += "-debug"
1418   }
1419   args += "-l"
1420
1421   def inputString = """exit
1422 y
1423 """
1424   def inputByteStream = new ByteArrayInputStream(inputString.getBytes())
1425   standardInput = inputByteStream
1426 }
1427 /* not really working yet
1428 jalviewjsEclipseCopyDropins.finalizedBy jalviewjsCleanEclipse
1429 */
1430
1431 def jalviewjsTransferSiteUnzipDir
1432 task jalviewjsTransferUnzipLib {
1433   dependsOn jalviewjsSitePath
1434
1435   def zipFiles = fileTree(dir: "${jalviewDir}/${jalviewjs_libjs_dir}", include: "*.zip")
1436   zipFiles += "${jalviewDir}/${jalviewjs_swingjs_zip}"
1437
1438   doLast {
1439     zipFiles.each { file_zip -> 
1440       copy {
1441         from zipTree(file_zip)
1442         into "${jalviewDir}/${jalviewjsTransferSiteLibDir}"
1443       }
1444     }
1445   }
1446
1447   inputs.files zipFiles
1448   outputs.dir "${jalviewDir}/${jalviewjsTransferSiteLibDir}"
1449 }
1450
1451 task jalviewjsCreateJ2sSettings(type: WriteProperties) {
1452   group "JalviewJS"
1453   description "Create the .j2s file from the j2s.* properties"
1454
1455   dependsOn jalviewjsSitePath
1456
1457   outputFile ("${jalviewDir}/${jalviewjs_j2s_settings}")
1458   def j2s_props = project.properties.findAll { it.key.startsWith("j2s.") }.sort { it.key }
1459   def siteDirProperty = "j2s.site.directory"
1460   def setSiteDir = false
1461   j2s_props.each { prop, val ->
1462     if (val != null) {
1463       if (prop == siteDirProperty) {
1464         if (!(val.startsWith('/') || val.startsWith("file://") )) {
1465           val = "${jalviewDir}/${jalviewjsTransferSiteJsDir}/${val}"
1466         }
1467         setSiteDir = true
1468       }
1469       property(prop,val)
1470     }
1471     if (!setSiteDir) { // default site location, don't override specifically set property
1472       property(siteDirProperty,"${jalviewDir}/${jalviewjsTransferSiteJsDir}")
1473     }
1474   }
1475   inputs.properties(j2s_props)
1476   outputs.file(outputFile)
1477 }
1478
1479 task jalviewjsEclipseSetup {
1480   dependsOn jalviewjsEclipseCopyDropins
1481   dependsOn jalviewjsSetEclipseWorkspace
1482   dependsOn jalviewjsCreateJ2sSettings
1483 }
1484
1485 task jalviewjsSyncLib (type: Sync) {
1486   dependsOn jalviewjsSitePath
1487   dependsOn jalviewjsTransferUnzipLib
1488   def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjsTransferSiteLibDir}")
1489   def outputDir = "${jalviewDir}/${jalviewjsSiteDir}"
1490
1491   from inputFiles
1492   into outputDir
1493   def outputFiles = []
1494   rename { filename ->
1495     outputFiles += "${outputDir}/${filename}"
1496     null
1497   }
1498   preserve {
1499     include "**"
1500   }
1501   outputs.files outputFiles
1502   inputs.files inputFiles
1503 }
1504
1505 task jalviewjsSyncCore (type: Sync) {
1506   dependsOn jalviewjsSitePath
1507   dependsOn "jalviewjsBuildAllCores"
1508   def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjsTransferSiteCoreDir}")
1509   def outputDir = "${jalviewDir}/${jalviewjsSiteDir}"
1510
1511   from inputFiles
1512   into outputDir
1513   def outputFiles = []
1514   rename { filename ->
1515     outputFiles += "${outputDir}/${filename}"
1516     null
1517   }
1518   preserve {
1519     include "**"
1520   }
1521   outputs.files outputFiles
1522   inputs.files inputFiles
1523 }
1524
1525 task jalviewjsSyncResources (type: Sync) {
1526   dependsOn jalviewjsSitePath
1527   def inputFiles = fileTree(dir: "${jalviewDir}/${resourceDir}")
1528   def outputDir = "${jalviewDir}/${jalviewjsSiteDir}/${jalviewjs_j2s_subdir}"
1529
1530   from inputFiles
1531   into outputDir
1532   def outputFiles = []
1533   rename { filename ->
1534     outputFiles += "${outputDir}/${filename}"
1535     null
1536   }
1537   preserve {
1538     include "**"
1539   }
1540   outputs.files outputFiles
1541   inputs.files inputFiles
1542 }
1543
1544 task jalviewjsSyncSiteResources (type: Sync) {
1545   dependsOn jalviewjsSitePath
1546   def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjs_site_resource_dir}")
1547   def outputDir = "${jalviewDir}/${jalviewjsSiteDir}"
1548
1549   from inputFiles
1550   into outputDir
1551   def outputFiles = []
1552   rename { filename ->
1553     outputFiles += "${outputDir}/${filename}"
1554     null
1555   }
1556   preserve {
1557     include "**"
1558   }
1559   outputs.files outputFiles
1560   inputs.files inputFiles
1561 }
1562
1563 task jalviewjsSyncBuildProperties (type: Sync) {
1564   dependsOn jalviewjsSitePath
1565   dependsOn createBuildProperties
1566   def inputFiles = [file(buildProperties)]
1567   def outputDir = "${jalviewDir}/${jalviewjsSiteDir}/${jalviewjs_j2s_subdir}"
1568
1569   from inputFiles
1570   into outputDir
1571   def outputFiles = []
1572   rename { filename ->
1573     outputFiles += "${outputDir}/${filename}"
1574     null
1575   }
1576   preserve {
1577     include "**"
1578   }
1579   outputs.files outputFiles
1580   inputs.files inputFiles
1581 }
1582
1583 task jalviewjsProjectImport(type: Exec) {
1584   dependsOn eclipseSetup
1585   dependsOn jalviewjsEclipsePaths
1586   dependsOn jalviewjsEclipseSetup
1587
1588   //def projdir = eclipseWorkspace.getPath()+"/.metadata/.plugins/org.eclipse.core.resources/.projects/jalview/org.eclipse.jdt.core"
1589   def projdir = eclipseWorkspace.getPath()+"/.metadata/.plugins/org.eclipse.core.resources/.projects/jalview"
1590   executable(eclipseBinary)
1591   args(["-nosplash", "--launcher.suppressErrors", "-application", "com.seeq.eclipse.importprojects.headlessimport", "-data", eclipseWorkspace.getPath(), "-import", jalviewDirAbsolutePath])
1592   if (eclipseDebug) {
1593     args += "-debug"
1594   }
1595   args += [ "--launcher.appendVmargs", "-vmargs", "-Dorg.eclipse.equinox.p2.reconciler.dropins.directory=${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_eclipse_tmp_dropins_dir}" ]
1596
1597   inputs.file("${jalviewDir}/.project")
1598   outputs.upToDateWhen { 
1599     file(projdir).exists()
1600   }
1601 }
1602
1603 task jalviewjsTranspile(type: Exec) {
1604   dependsOn jalviewjsEclipseSetup 
1605   dependsOn jalviewjsProjectImport
1606   dependsOn jalviewjsEclipsePaths
1607
1608   executable(eclipseBinary)
1609   args(["-nosplash", "--launcher.suppressErrors", "-application", "org.eclipse.jdt.apt.core.aptBuild", "-data", eclipseWorkspace, "-${jalviewjs_eclipse_build_arg}", eclipse_project_name ])
1610   if (eclipseDebug) {
1611     args += "-debug"
1612   }
1613   args += [ "--launcher.appendVmargs", "-vmargs", "-Dorg.eclipse.equinox.p2.reconciler.dropins.directory=${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_eclipse_tmp_dropins_dir}" ]
1614
1615   def stdout
1616   def stderr
1617   doFirst {
1618     stdout = new ByteArrayOutputStream()
1619     stderr = new ByteArrayOutputStream()
1620
1621     def logOutFileName = "${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}"
1622     def logOutFile = file(logOutFileName)
1623     logOutFile.createNewFile()
1624     logOutFile.text = """ROOT: ${jalviewjs_eclipse_root}
1625 BINARY: ${eclipseBinary}
1626 VERSION: ${eclipseVersion}
1627 WORKSPACE: ${eclipseWorkspace}
1628 DEBUG: ${eclipseDebug}
1629 ----
1630 """
1631     def logOutFOS = new FileOutputStream(logOutFile, true) // true == append
1632     //def logErrFileName = "${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_j2s_stderr}"
1633     //def logErrFile = file(logFileName)
1634     //logErrFile.createNewFile()
1635     //def logErrFOS = new FileErrputStream(logErrFile, false)
1636     // combine stdout and stderr
1637     def logErrFOS = logOutFOS
1638
1639     if (jalviewjs_j2s_to_console.equals("true")) {
1640       standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
1641         new org.apache.tools.ant.util.TeeOutputStream(
1642           logOutFOS,
1643           stdout),
1644         standardOutput)
1645       errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
1646         new org.apache.tools.ant.util.TeeOutputStream(
1647           logErrFOS,
1648           stderr),
1649         errorOutput)
1650     } else {
1651       standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
1652         logOutFOS,
1653         stdout)
1654       errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
1655         logErrFOS,
1656         stderr)
1657     }
1658   }
1659
1660   doLast {
1661     if (stdout.toString().contains("Error processing ")) {
1662       // j2s did not complete transpile
1663       throw new GradleException("Error during transpilation:\n${stderr}\nSee eclipse transpile log file '${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}'")
1664     }
1665   }
1666
1667   inputs.dir("${jalviewDir}/${sourceDir}")
1668   outputs.dir("${jalviewDir}/${jalviewjsTransferSiteJsDir}")
1669   outputs.upToDateWhen( { file("${jalviewDir}/${jalviewjsTransferSiteJsDir}${jalviewjs_server_resource}").exists() } )
1670 }
1671
1672 // this Copy version of TransferSiteJs will delete anything else in the target dir
1673 task jalviewjsCopyTransferSiteJs(type: Copy) {
1674   dependsOn jalviewjsTranspile
1675   from "${jalviewDir}/${jalviewjsTransferSiteJsDir}"
1676   into "${jalviewDir}/${jalviewjsSiteDir}"
1677 }
1678
1679 // this Sync version of TransferSite is used by buildship to keep the website automatically up to date when a file changes
1680 task jalviewjsSyncTransferSiteJs(type: Sync) {
1681   from "${jalviewDir}/${jalviewjsTransferSiteJsDir}"
1682   include "**/*.*"
1683   into "${jalviewDir}/${jalviewjsSiteDir}"
1684   preserve {
1685     include "**"
1686   }
1687 }
1688
1689 jalviewjsSyncLib.mustRunAfter jalviewjsCopyTransferSiteJs
1690 jalviewjsSyncResources.mustRunAfter jalviewjsCopyTransferSiteJs
1691 jalviewjsSyncSiteResources.mustRunAfter jalviewjsCopyTransferSiteJs
1692 jalviewjsSyncBuildProperties.mustRunAfter jalviewjsCopyTransferSiteJs
1693
1694 jalviewjsSyncLib.mustRunAfter jalviewjsSyncTransferSiteJs
1695 jalviewjsSyncResources.mustRunAfter jalviewjsSyncTransferSiteJs
1696 jalviewjsSyncSiteResources.mustRunAfter jalviewjsSyncTransferSiteJs
1697 jalviewjsSyncBuildProperties.mustRunAfter jalviewjsSyncTransferSiteJs
1698
1699 task jalviewjsPrepareSite {
1700   group "JalviewJS"
1701   description "Prepares the website folder including unzipping files and copying resources"
1702   dependsOn jalviewjsSyncLib
1703   dependsOn jalviewjsSyncResources
1704   dependsOn jalviewjsSyncSiteResources
1705   dependsOn jalviewjsSyncBuildProperties
1706   dependsOn jalviewjsSyncCore
1707 }
1708
1709 task jalviewjsBuildSite {
1710   group "JalviewJS"
1711   description "Builds the whole website including transpiled code"
1712   dependsOn jalviewjsCopyTransferSiteJs
1713   dependsOn jalviewjsPrepareSite
1714 }
1715
1716 task cleanJalviewjsSite {
1717   doFirst {
1718     delete "${jalviewDir}/${jalviewjsTransferSiteJsDir}"
1719     delete "${jalviewDir}/${jalviewjsTransferSiteLibDir}"
1720     delete "${jalviewDir}/${jalviewjsTransferSiteCoreDir}"
1721     delete "${jalviewDir}/${jalviewjsSiteDir}"
1722   }
1723 }
1724
1725 task jalviewjsSiteTar(type: Tar) {
1726   group "JalviewJS"
1727   description "Creates a tar.gz file for the website"
1728   dependsOn jalviewjsBuildSite
1729   def outputFilename = "jalviewjs-site-${JALVIEW_VERSION}.tar.gz"
1730   try {
1731     archiveFileName = outputFilename
1732   } catch (Exception e) {
1733     archiveName = outputFilename
1734   }
1735
1736   compression Compression.GZIP
1737
1738   from "${jalviewDir}/${jalviewjsSiteDir}"
1739   into jalviewjs_site_dir // this is inside the tar file
1740
1741   inputs.dir("${jalviewDir}/${jalviewjsSiteDir}")
1742 }
1743
1744 task jalviewjsServer {
1745   group "JalviewJS"
1746   def filename = "jalviewjsTest.html"
1747   description "Starts a webserver on localhost to test the website. See ${filename} to access local site on most recently used port."
1748   dependsOn jalviewjsSitePath
1749   def htmlFile = "${jalviewDirAbsolutePath}/${filename}"
1750   doLast {
1751
1752     SimpleHttpFileServerFactory factory = new SimpleHttpFileServerFactory()
1753     def port = Integer.valueOf(jalviewjs_server_port)
1754     def start = port
1755     def running = false
1756     def url
1757     while(port < start+1000 && !running) {
1758       try {
1759         def doc_root = new File("${jalviewDirAbsolutePath}/${jalviewjsSiteDir}")
1760         def jalviewjsServer = factory.start(doc_root, port)
1761         running = true
1762         url = jalviewjsServer.getResourceUrl(jalviewjs_server_resource)
1763         println("SERVER STARTED with document root ${doc_root}.")
1764         println("Go to "+url+" . Run  gradle --stop  to stop (kills all gradle daemons).")
1765         println("For debug: "+url+"?j2sdebug")
1766
1767         file(htmlFile).text = """
1768         <p><a href="${url}">Jalview JS Test. &lt;${url}&gt;</a></p>
1769         <p><a href="${url}?j2sdebug">Jalview JS Test with debug. &lt;${url}?j2sdebug&lt;</a></p>
1770         """
1771
1772       } catch (Exception e) {
1773         port++;
1774       }
1775     }
1776
1777   }
1778
1779   outputs.file(htmlFile)
1780   outputs.upToDateWhen({false})
1781 }
1782
1783 task cleanJalviewjsAll {
1784   group "JalviewJS"
1785   description "Delete all configuration and build artifacts to do with JalviewJS build"
1786   dependsOn cleanJalviewjsSite
1787   dependsOn jalviewjsEclipsePaths
1788   
1789   doFirst {
1790     delete "${jalviewDir}/${jalviewjsBuildDir}"
1791     delete "${jalviewDir}/${eclipse_bin_dir}"
1792     if (eclipseWorkspace != null && file(eclipseWorkspace.getAbsolutePath()+"/.metadata").exists()) {
1793       delete file(eclipseWorkspace.getAbsolutePath()+"/.metadata")
1794     }
1795     delete "${jalviewDir}/${jalviewjs_j2s_settings}"
1796   }
1797
1798   outputs.upToDateWhen( { false } )
1799 }
1800
1801 task jalviewjs {
1802   group "JalviewJS"
1803   description "Build the site"
1804   dependsOn jalviewjsBuildSite
1805 }
1806
1807
1808 task jalviewjsIDE_CopyTransferSiteJs(type: Copy) {
1809   from "${jalviewDir}/${jalviewjsTransferSiteJsDir}"
1810   into "${jalviewDir}/${jalviewjsSiteDir}"
1811 }
1812
1813 task jalviewjsIDE_j2sFile {
1814   group "00 JalviewJS in Eclipse"
1815   description "Creates the .j2s file"
1816   dependsOn jalviewjsCreateJ2sSettings
1817 }
1818
1819 task jalviewjsIDE_AssembleSite {
1820   group "00 JalviewJS in Eclipse"
1821   description "Assembles the Eclipse transpiled site and unzips supporting zipfiles"
1822   dependsOn jalviewjsIDE_CopyTransferSiteJs
1823   dependsOn jalviewjsPrepareSite
1824 }
1825
1826 task jalviewjsIDE_SiteClean {
1827   group "00 JalviewJS in Eclipse"
1828   description "Deletes the Eclipse transpiled site"
1829   dependsOn cleanJalviewjsSite
1830 }
1831
1832 task jalviewjsIDE_Server {
1833   group "00 JalviewJS in Eclipse"
1834   description "Starts a webserver on localhost to test the website"
1835   dependsOn jalviewjsServer
1836 }
1837
1838 // buildship runs this at import
1839 task eclipseSynchronizationTask {
1840   dependsOn eclipseSetup
1841   dependsOn jalviewjsIDE_j2sFile
1842 }
1843
1844 // buildship runs this at build time
1845 task eclipseAutoBuildTask {
1846   dependsOn jalviewjsSyncTransferSiteJs
1847   dependsOn jalviewjsPrepareSite
1848 }
1849
1850
1851
1852
1853
1854
1855
1856
1857 // closure
1858
1859 def jalviewjsCallCore(FileCollection list, String prefixFile, String suffixFile, String jsfile, String zjsfile, File logOutFile, Boolean logOutConsole) {
1860
1861   def stdout = new ByteArrayOutputStream()
1862   def stderr = new ByteArrayOutputStream()
1863
1864   def coreFile = file(jsfile)
1865   def msg = ""
1866   msg = "Generating ${jsfile}"
1867   println(msg)
1868   logOutFile.createNewFile()
1869   logOutFile.append(msg+"\n")
1870
1871   def coreTop = file(prefixFile)
1872   def coreBottom = file(suffixFile)
1873   coreFile.getParentFile().mkdirs()
1874   coreFile.createNewFile()
1875   coreFile.write( coreTop.text )
1876   list.each {
1877     f ->
1878     if (f.exists()) {
1879       def t = f.text
1880       t.replaceAll("Clazz\\.","Clazz_")
1881       t.replaceAll("Class__","Clazz._")
1882       coreFile.append( t )
1883     } else {
1884       msg = "...file "+f.getPath()+" does not exist, skipping"
1885       println(msg)
1886       logOutFile.append(msg+"\n")
1887     }
1888   }
1889   coreFile.append( coreBottom.text )
1890
1891   msg = "Generating ${zjsfile}"
1892   println(msg)
1893   logOutFile.append(msg+"\n")
1894   def logOutFOS = new FileOutputStream(logOutFile, true) // true == append
1895   def logErrFOS = logOutFOS
1896
1897   javaexec {
1898     classpath = files(["${jalviewDir}/tools/closure_compiler.jar"])
1899     args = [ "--js", jsfile, "--js_output_file", zjsfile ]
1900
1901     msg = "\nRunning '"+commandLine.join(' ')+"'\n"
1902     println(msg)
1903     logOutFile.append(msg+"\n")
1904
1905     if (logOutConsole) {
1906       standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
1907         new org.apache.tools.ant.util.TeeOutputStream(
1908           logOutFOS,
1909           stdout),
1910         standardOutput)
1911         errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
1912           new org.apache.tools.ant.util.TeeOutputStream(
1913             logErrFOS,
1914             stderr),
1915           errorOutput)
1916     } else {
1917       standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
1918         logOutFOS,
1919         stdout)
1920         errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
1921           logErrFOS,
1922           stderr)
1923     }
1924   }
1925   msg = "--"
1926   println(msg)
1927   logOutFile.append(msg+"\n")
1928 }
1929
1930
1931
1932 task jalviewjsBuildAllCores {
1933   group "JalviewJS"
1934   description "Build the core js lib closures"
1935
1936   dependsOn jalviewjsSitePath
1937   dependsOn jalviewjsTransferUnzipLib
1938   dependsOn jalviewjsTranspile
1939
1940   def j2sDir = "${jalviewDir}/${jalviewjsTransferSiteJsDir}/${jalviewjs_j2s_subdir}"
1941   def jsDir = "${jalviewDir}/${jalviewjsTransferSiteLibDir}/${jalviewjs_js_subdir}"
1942   def outputDir = "${jalviewDir}/${jalviewjsTransferSiteCoreDir}/${jalviewjs_j2s_subdir}/core"
1943   def prefixFile = "${jsDir}/core/coretop2.js"
1944   def suffixFile = "${jsDir}/core/corebottom2.js"
1945
1946   inputs.file prefixFile
1947   inputs.file suffixFile
1948
1949   def classlists = []
1950   fileTree(dir: "${jalviewDir}/${jalviewjs_classlists_dir}", include: "*.txt").each {
1951     file ->
1952     def name = file.getName() - ".txt"
1953
1954     def filelist = []
1955     file.eachLine {
1956       line ->
1957       filelist += line
1958     }
1959     def list = fileTree(dir: j2sDir, includes: filelist)
1960
1961     def coreFileName = "core${name}.js"
1962     def jsfile = "${outputDir}/${coreFileName}"
1963     def coreZFileName = "core${name}.z.js"
1964     def zjsfile = "${outputDir}/${coreZFileName}"
1965
1966     classlists += [
1967       'jsfile': jsfile,
1968       'zjsfile': zjsfile,
1969       'list': list
1970     ]
1971
1972     inputs.file(file)
1973     inputs.files(list)
1974     outputs.file(jsfile)
1975     outputs.file(zjsfile)
1976   } 
1977
1978
1979   doFirst {
1980     def logOutFile = file("${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_j2s_closure_stdout}")
1981     logOutFile.getParentFile().mkdirs()
1982     logOutFile.createNewFile()
1983     logOutFile.write(getDate("yyyy-MM-dd HH:mm:ss")+" jalviewjsBuildAllCores\n----\n")
1984
1985     classlists.each {
1986       jalviewjsCallCore(it.list, prefixFile, suffixFile, it.jsfile, it.zjsfile, logOutFile, jalviewjs_j2s_to_console.equals("true"))
1987     }
1988   }
1989
1990 }