JAL-3210 minor fix
[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   id 'com.dorongold.task-tree' version '1.4' // only needed to display task dependency tree with  gradle task1 [task2 ...] taskTree
21 }
22
23 repositories {
24   jcenter()
25   mavenCentral()
26   mavenLocal()
27   flatDir {
28     dirs gradlePluginsDir
29   }
30 }
31
32 dependencies {
33   compile 'org.apache.commons:commons-compress:1.18'
34 }
35
36
37 // in ext the values are cast to Object. Ensure string values are cast as String (and not GStringImpl) for later use
38 def string(Object o) {
39   return o.toString()
40 }
41
42
43 ext {
44   jalviewDirAbsolutePath = file(jalviewDir).getAbsolutePath()
45
46   // local build environment properties
47   def localProps = "${jalviewDirAbsolutePath}/local.properties"
48   if (file(localProps).exists()) {
49     try {
50       def p = new Properties()
51       def localPropsFIS = new FileInputStream(localProps)
52       p.load(localPropsFIS)
53       localPropsFIS.close()
54       p.each {
55         key, val -> 
56           def over = getProperty(key) != null
57           setProperty(key, val)
58           if (over) {
59             println("Overriding property '${key}' with local.properties value '${val}'")
60           }
61       }
62     } catch (Exception e) {
63       System.out.println("Exception reading local.properties")
64     }
65   }
66
67
68   // this property set when running Eclipse headlessly
69   j2sHeadlessBuildProperty = string("net.sf.j2s.core.headlessbuild")
70   // this property set by Eclipse
71   eclipseApplicationProperty = string("eclipse.application")
72   // CHECK IF RUNNING FROM WITHIN ECLIPSE
73   def eclipseApplicationPropertyVal = System.properties[eclipseApplicationProperty]
74   IN_ECLIPSE = eclipseApplicationPropertyVal != null && eclipseApplicationPropertyVal.startsWith("org.eclipse.ui.")
75   // BUT WITHOUT THE HEADLESS BUILD PROPERTY SET
76   if (System.properties[j2sHeadlessBuildProperty].equals("true")) {
77     println("Setting IN_ECLIPSE to ${IN_ECLIPSE} as System.properties['${j2sHeadlessBuildProperty}'] == '${System.properties[j2sHeadlessBuildProperty]}'")
78     IN_ECLIPSE = false
79   }
80   if (IN_ECLIPSE) {
81     println("WITHIN ECLIPSE IDE")
82   } else {
83     println("HEADLESS BUILD")
84   }
85   /*
86   System.properties.sort { it.key }.each {
87     key, val -> println("SYSTEM PROPERTY ${key}='${val}'")
88   }
89   */
90
91   cloverInstrDir = file("${buildDir}/${cloverSourcesInstrDir}")
92   classes = string("${jalviewDir}/${classesDir}")
93   if (clover.equals("true")) {
94     use_clover = true
95     classes = string("${buildDir}/${cloverClassesDir}")
96   } else {
97     use_clover = false
98     classes = string("${jalviewDir}/${classesDir}")
99   }
100
101   getdownWebsiteDir = string("${jalviewDir}/${getdown_website_dir}/${JAVA_VERSION}")
102   getdownDir = string("")
103   reportRsyncCmd = false
104   buildDist = true
105   buildProperties = build_properties_file
106   getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher}")
107   switch (CHANNEL) {
108
109     case "BUILD":
110     // TODO: get bamboo build artifact URL for getdown artifacts
111     getdown_channel_base = bamboo_channelbase
112     getdown_channel_name = string("${bamboo_planKey}/${JAVA_VERSION}")
113     getdown_app_base = string("${bamboo_channelbase}/${bamboo_planKey}${bamboo_getdown_channel_suffix}/${JAVA_VERSION}")
114     getdown_app_dir = getdown_app_dir_alt
115     buildProperties = string("${jalviewDir}/${classesDir}/${build_properties_file}")
116     break
117
118     case "RELEASE":
119     getdown_channel_name = CHANNEL.toLowerCase()
120     getdownDir = string("${getdown_channel_name}/${JAVA_VERSION}")
121     getdown_app_base = string("${getdown_channel_base}/${getdownDir}")
122     getdown_app_dir = getdown_app_dir_release
123     buildProperties = string("${jalviewDir}/${classesDir}/${build_properties_file}")
124     reportRsyncCommand = true
125     break
126
127     case "ARCHIVE":
128     getdown_channel_name = CHANNEL.toLowerCase()+"/${JALVIEW_VERSION}"
129     getdownDir = string("${getdown_channel_name}/${JAVA_VERSION}")
130     getdown_app_base = string("${getdown_channel_base}/${getdownDir}")
131     getdown_app_dir = getdown_app_dir_alt
132     if (!file("${ARCHIVEDIR}/${packageDir}").exists()) {
133       print "Must provide an ARCHIVEDIR value to produce an archive distribution"
134       exit
135     } else {
136       packageDir = string("${ARCHIVEDIR}/${packageDir}")
137       buildProperties = string("${ARCHIVEDIR}/${classesDir}/${build_properties_file}")
138       buildDist = false
139     }
140     reportRsyncCommand = true
141     break
142
143     case "ARCHIVELOCAL":
144     getdown_channel_name = string("archive/${JALVIEW_VERSION}")
145     getdownDir = string("${getdown_channel_name}/${JAVA_VERSION}")
146     getdown_app_base = file(getdownWebsiteDir).toURI().toString()
147     getdown_app_dir = getdown_app_dir_alt
148     if (!file("${ARCHIVEDIR}/${packageDir}").exists()) {
149       print "Must provide an ARCHIVEDIR value to produce an archive distribution"
150       exit
151     } else {
152       packageDir = string("${ARCHIVEDIR}/${packageDir}")
153       buildProperties = string("${ARCHIVEDIR}/${classesDir}/${build_properties_file}")
154       buildDist = false
155     }
156     reportRsyncCommand = true
157     getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher_local}")
158     break
159
160     case "DEVELOP":
161     getdown_channel_name = CHANNEL.toLowerCase()
162     getdownDir = string("${getdown_channel_name}/${JAVA_VERSION}")
163     getdown_app_base = string("${getdown_channel_base}/${getdownDir}")
164     getdown_app_dir = getdown_app_dir_alt
165     buildProperties = string("${jalviewDir}/${classesDir}/${build_properties_file}")
166     reportRsyncCommand = true
167     break
168
169     case "TEST-RELEASE":
170     getdown_channel_name = CHANNEL.toLowerCase()
171     getdownDir = string("${getdown_channel_name}/${JAVA_VERSION}")
172     getdown_app_base = string("${getdown_channel_base}/${getdownDir}")
173     getdown_app_dir = getdown_app_dir_alt
174     buildProperties = string("${jalviewDir}/${classesDir}/${build_properties_file}")
175     reportRsyncCommand = true
176     break
177
178     case ~/^SCRATCH(|-[-\w]*)$/:
179     getdown_channel_name = CHANNEL
180     getdownDir = string("${getdown_channel_name}/${JAVA_VERSION}")
181     getdown_app_base = string("${getdown_channel_base}/${getdownDir}")
182     getdown_app_dir = getdown_app_dir_alt
183     buildProperties = string("${jalviewDir}/${classesDir}/${build_properties_file}")
184     reportRsyncCommand = true
185     break
186
187     case "LOCAL":
188     getdown_app_base = file(getdownWebsiteDir).toURI().toString()
189     getdown_app_dir = getdown_app_dir_alt
190     buildProperties = string("${jalviewDir}/${classesDir}/${build_properties_file}")
191     getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher_local}")
192     break
193
194     default: // something wrong specified
195     print("CHANNEL must be one of BUILD, RELEASE, ARCHIVE, DEVELOP, TEST-RELEASE, SCRATCH-..., LOCAL [default]")
196     exit
197     break
198
199   }
200
201   getdownAppDir = string("${getdownWebsiteDir}/${getdown_app_dir}")
202   //getdownJ11libDir = "${getdownWebsiteDir}/${getdown_j11lib_dir}"
203   getdownResourceDir = string("${getdownWebsiteDir}/${getdown_resource_dir}")
204   getdownInstallDir = string("${getdownWebsiteDir}/${getdown_install_dir}")
205   getdownFilesDir = string("${jalviewDir}/${getdown_files_dir}/${JAVA_VERSION}/")
206   getdownFilesInstallDir = string("${getdownFilesDir}/${getdown_install_dir}")
207   /* compile without modules -- using classpath libraries
208   modules_compileClasspath = fileTree(dir: "${jalviewDir}/${j11modDir}", include: ["*.jar"])
209   modules_runtimeClasspath = modules_compileClasspath
210   */
211   gitHash = string("")
212   gitBranch = string("")
213
214   println("Using a ${CHANNEL} profile.")
215
216   additional_compiler_args = []
217   // configure classpath/args for j8/j11 compilation
218   if (JAVA_VERSION.equals("1.8")) {
219     JAVA_INTEGER_VERSION = string("8")
220     //libDir = j8libDir
221     libDir = j11libDir
222     libDistDir = j8libDir
223     compile_source_compatibility = 1.8
224     compile_target_compatibility = 1.8
225     // these are getdown.txt properties defined dependent on the JAVA_VERSION
226     getdown_alt_java_min_version = getdown_alt_java8_min_version
227     getdown_alt_java_max_version = getdown_alt_java8_max_version
228     // this property is assigned below and expanded to multiple lines in the getdown task
229     getdown_alt_multi_java_location = getdown_alt_java8_txt_multi_java_location
230     // this property is for the Java library used in eclipse
231     eclipse_java_runtime_name = string("JavaSE-1.8")
232   } else if (JAVA_VERSION.equals("11")) {
233     JAVA_INTEGER_VERSION = string("11")
234     libDir = j11libDir
235     libDistDir = j11libDir
236     compile_source_compatibility = 11
237     compile_target_compatibility = 11
238     getdown_alt_java_min_version = getdown_alt_java11_min_version
239     getdown_alt_java_max_version = getdown_alt_java11_max_version
240     getdown_alt_multi_java_location = getdown_alt_java11_txt_multi_java_location
241     eclipse_java_runtime_name = string("JavaSE-11")
242     /* compile without modules -- using classpath libraries
243     additional_compiler_args += [
244     '--module-path', modules_compileClasspath.asPath,
245     '--add-modules', j11modules
246     ]
247      */
248   } else if (JAVA_VERSION.equals("12") || JAVA_VERSION.equals("13")) {
249     JAVA_INTEGER_VERSION = JAVA_VERSION
250     libDir = j11libDir
251     libDistDir = j11libDir
252     compile_source_compatibility = JAVA_VERSION
253     compile_target_compatibility = JAVA_VERSION
254     getdown_alt_java_min_version = getdown_alt_java11_min_version
255     getdown_alt_java_max_version = getdown_alt_java11_max_version
256     getdown_alt_multi_java_location = getdown_alt_java11_txt_multi_java_location
257     eclipse_java_runtime_name = string("JavaSE-11")
258     /* compile without modules -- using classpath libraries
259     additional_compiler_args += [
260     '--module-path', modules_compileClasspath.asPath,
261     '--add-modules', j11modules
262     ]
263      */
264   } else {
265     throw new GradleException("JAVA_VERSION=${JAVA_VERSION} not currently supported by Jalview")
266   }
267
268
269   // for install4j
270   macosJavaVMDir = string("${System.env.HOME}/buildtools/jre/openjdk-java_vm/getdown/macos-jre${JAVA_VERSION}/jre")
271   macosJavaVMTgz = string("${System.env.HOME}/buildtools/jre/openjdk-java_vm/install4j/tgz/macos-jre${JAVA_VERSION}.tar.gz")
272   windowsJavaVMDir = string("${System.env.HOME}/buildtools/jre/openjdk-java_vm/getdown/windows-jre${JAVA_VERSION}/jre")
273   windowsJavaVMTgz = string("${System.env.HOME}/buildtools/jre/openjdk-java_vm/install4j/tgz/windows-jre${JAVA_VERSION}.tar.gz")
274   install4jDir = string("${jalviewDir}/${install4jResourceDir}")
275   install4jConfFileName = string("jalview-installers-java${JAVA_VERSION}.install4j")
276   install4jConfFile = string("${install4jDir}/${install4jConfFileName}")
277
278
279   buildingHTML = string("${jalviewDir}/${docDir}/building.html")
280   helpFile = string("${classes}/${helpDir}/help.jhm")
281
282
283   relativeBuildDir = file(jalviewDirAbsolutePath).toPath().relativize(buildDir.toPath())
284   jalviewjsBuildDir = string("${relativeBuildDir}/jalviewjs")
285   jalviewjsSiteDir = string("${jalviewjsBuildDir}/${jalviewjs_site_dir}")
286   if (IN_ECLIPSE) {
287     jalviewjsTransferSiteJsDir = string(jalviewjsSiteDir)
288   } else {
289     jalviewjsTransferSiteJsDir = string("${jalviewjsBuildDir}/tmp/${jalviewjs_site_dir}_js")
290   }
291   jalviewjsTransferSiteLibDir = string("${jalviewjsBuildDir}/tmp/${jalviewjs_site_dir}_lib")
292   jalviewjsTransferSiteSwingJsDir = string("${jalviewjsBuildDir}/tmp/${jalviewjs_site_dir}_swingjs")
293   jalviewjsTransferSiteCoreDir = string("${jalviewjsBuildDir}/tmp/${jalviewjs_site_dir}_core")
294   jalviewjsJalviewCoreHtmlFile = string("")
295   jalviewjsJalviewCoreName = string(jalviewjs_core_name)
296   jalviewjsJalviewTemplateName = string(jalviewjs_name)
297
298   eclipseWorkspace = null
299   eclipseBinary = string("")
300   eclipseVersion = string("")
301   eclipseDebug = false
302   // ENDEXT
303 }
304
305
306 sourceSets {
307   main {
308     java {
309       srcDirs "${jalviewDir}/${sourceDir}"
310       outputDir = file(project.classes)
311     }
312
313     resources {
314       srcDirs "${jalviewDir}/${resourceDir}"
315     }
316
317     jar.destinationDir = file("${jalviewDir}/${packageDir}")
318
319     compileClasspath = files(sourceSets.main.java.outputDir)
320     compileClasspath += fileTree(dir: "${jalviewDir}/${libDir}", include: ["*.jar"])
321
322     runtimeClasspath = compileClasspath
323   }
324
325   clover {
326     java {
327       srcDirs = [ cloverInstrDir ]
328       outputDir = file("${buildDir}/${cloverClassesDir}")
329     }
330
331     resources {
332       srcDirs = sourceSets.main.resources.srcDirs
333     }
334     compileClasspath = configurations.cloverRuntime + files( sourceSets.clover.java.outputDir )
335     compileClasspath += files(sourceSets.main.java.outputDir)
336     compileClasspath += sourceSets.main.compileClasspath
337     compileClasspath += fileTree(dir: "${jalviewDir}/${utilsDir}", include: ["**/*.jar"])
338     compileClasspath += fileTree(dir: "${jalviewDir}/${libDir}", include: ["*.jar"])
339
340     runtimeClasspath = compileClasspath
341   }
342
343   test {
344     java {
345       srcDirs "${jalviewDir}/${testSourceDir}"
346       outputDir = file("${jalviewDir}/${testOutputDir}")
347     }
348
349     resources {
350       srcDirs = sourceSets.main.resources.srcDirs
351     }
352
353     compileClasspath = files( sourceSets.test.java.outputDir )
354
355     if (use_clover) {
356       compileClasspath += sourceSets.clover.compileClasspath
357     } else {
358       compileClasspath += files(sourceSets.main.java.outputDir)
359     }
360
361     compileClasspath += fileTree(dir: "${jalviewDir}/${libDir}", include: ["*.jar"])
362     compileClasspath += fileTree(dir: "${jalviewDir}/${utilsDir}/testnglibs", include: ["**/*.jar"])
363     compileClasspath += fileTree(dir: "${jalviewDir}/${utilsDir}/testlibs", include: ["**/*.jar"])
364
365     runtimeClasspath = compileClasspath
366   }
367 }
368
369
370 // clover bits
371 dependencies {
372   if (use_clover) {
373     cloverCompile 'org.openclover:clover:4.3.1'
374     testCompile 'org.openclover:clover:4.3.1'
375   }
376 }
377
378
379 configurations {
380   cloverRuntime
381   cloverRuntime.extendsFrom cloverCompile
382 }
383
384 eclipse {
385   project {
386     name = eclipse_project_name
387
388     natures 'org.eclipse.jdt.core.javanature',
389     'org.eclipse.jdt.groovy.core.groovyNature',
390     'org.eclipse.buildship.core.gradleprojectnature'
391
392     buildCommand 'org.eclipse.jdt.core.javabuilder'
393     buildCommand 'org.eclipse.buildship.core.gradleprojectbuilder'
394   }
395
396   classpath {
397     //defaultOutputDir = sourceSets.main.java.outputDir
398     def removeThese = []
399     configurations.each{
400       if (it.isCanBeResolved()) {
401         removeThese += it
402       }
403     }
404
405     minusConfigurations += removeThese
406     plusConfigurations = [ ]
407     file {
408
409       whenMerged { cp ->
410         def removeTheseToo = []
411         HashMap<String, Boolean> alreadyAddedSrcPath = new HashMap<>();
412         cp.entries.each { entry ->
413           if (entry.kind == 'src') {
414             if (alreadyAddedSrcPath.getAt(entry.path) || !(entry.path == sourceDir || entry.path == testSourceDir)) {
415               removeTheseToo += entry
416             } else {
417               alreadyAddedSrcPath.putAt(entry.path, true)
418             }
419           }
420         }
421         cp.entries.removeAll(removeTheseToo)
422
423         if (file("${jalviewDir}/${eclipse_bin_dir}/main").isDirectory()) {
424           cp.entries += new Output("${eclipse_bin_dir}/main")
425         }
426         if (file(helpParentDir).isDirectory()) {
427           cp.entries += new Library(fileReference(helpParentDir))
428         }
429         if (file(resourceDir).isDirectory()) {
430           cp.entries += new Library(fileReference(resourceDir))
431         }
432
433         HashMap<String, Boolean> alreadyAddedLibPath = new HashMap<>();
434
435         sourceSets.main.compileClasspath.findAll { it.name.endsWith(".jar") }.each {
436           //don't want to add outputDir as eclipse is using its own output dir in bin/main
437           if (it.isDirectory() || ! it.exists()) {
438             // don't add dirs to classpath
439             return
440           }
441           def itPath = it.toString()
442           if (itPath.startsWith("${jalviewDirAbsolutePath}/")) {
443             // make relative path
444             itPath = itPath.substring(jalviewDirAbsolutePath.length()+1)
445           }
446           if (alreadyAddedLibPath.get(itPath)) {
447             //println("Not adding duplicate entry "+itPath)
448           } else {
449             //println("Adding entry "+itPath)
450             cp.entries += new Library(fileReference(itPath))
451             alreadyAddedLibPath.put(itPath, true)
452           }
453         }
454
455         //fileTree(dir: "$jalviewDir/$utilsDir", include: ["test*/*.jar"]).each {
456         sourceSets.test.compileClasspath.findAll { it.name.endsWith(".jar") }.any {
457           //no longer want to add outputDir as eclipse is using its own output dir in bin/main
458           if (it.isDirectory() || ! it.exists()) {
459             // don't add dirs to classpath
460             return false // groovy "continue" in .any closure
461           }
462
463           def itPath = it.toString()
464           if (itPath.startsWith("${jalviewDirAbsolutePath}/")) {
465             itPath = itPath.substring(jalviewDirAbsolutePath.length()+1)
466           }
467           if (alreadyAddedLibPath.get(itPath)) {
468             // don't duplicate
469           } else {
470             def lib = new Library(fileReference(itPath))
471             lib.entryAttributes["test"] = "true"
472             cp.entries += lib
473             alreadyAddedLibPath.put(itPath, true)
474           }
475         }
476
477       } // whenMerged
478
479     } // file
480
481     containers 'org.eclipse.buildship.core.gradleclasspathcontainer'
482
483   } // classpath
484
485   jdt {
486     // for the IDE, use java 11 compatibility
487     sourceCompatibility = compile_source_compatibility
488     targetCompatibility = compile_target_compatibility
489     javaRuntimeName = eclipse_java_runtime_name
490
491     // add in jalview project specific properties/preferences into eclipse core preferences
492     file {
493       withProperties { props ->
494         def jalview_prefs = new Properties()
495         def ins = new FileInputStream("${jalviewDirAbsolutePath}/${eclipse_extra_jdt_prefs_file}")
496         jalview_prefs.load(ins)
497         ins.close()
498         jalview_prefs.forEach { t, v ->
499           if (props.getAt(t) == null) {
500             props.putAt(t, v)
501           }
502         }
503       }
504     }
505
506   } // jdt
507
508   if (IN_ECLIPSE) {
509     // Don't want these to be activated if in headless build
510     synchronizationTasks "eclipseSynchronizationTask"
511     autoBuildTasks "eclipseAutoBuildTask"
512   }
513 }
514
515
516 task cloverInstr() {
517   // only instrument source, we build test classes as normal
518   inputs.files files (sourceSets.main.allJava) // , fileTree(dir:"$jalviewDir/$testSourceDir", include: ["**/*.java"]))
519   outputs.dir cloverInstrDir
520
521   doFirst {
522     delete cloverInstrDir
523     def argsList = ["--initstring", "${buildDir}/clover/clover.db",
524     "-d", "${buildDir}/${cloverSourcesInstrDir}"]
525     argsList.addAll(inputs.files.files.collect({ file ->
526       file.absolutePath
527     }))
528     String[] args = argsList.toArray()
529     println("About to instrument "+args.length +" files")
530     com.atlassian.clover.CloverInstr.mainImpl(args)
531   }
532 }
533
534
535 task cloverReport {
536   group = "Verification"
537     description = "Createst the Clover report"
538     inputs.dir "${buildDir}/clover"
539     outputs.dir "${reportsDir}/clover"
540     onlyIf {
541       file("${buildDir}/clover/clover.db").exists()
542     }
543   doFirst {
544     def argsList = ["--initstring", "${buildDir}/clover/clover.db",
545     "-o", "${reportsDir}/clover"]
546     String[] args = argsList.toArray()
547     com.atlassian.clover.reporters.html.HtmlReporter.runReport(args)
548
549     // and generate ${reportsDir}/clover/clover.xml
550     args = ["--initstring", "${buildDir}/clover/clover.db",
551     "-o", "${reportsDir}/clover/clover.xml"].toArray()
552     com.atlassian.clover.reporters.xml.XMLReporter.runReport(args)
553   }
554 }
555 // end clover bits
556
557
558 compileJava {
559
560   doFirst {
561     sourceCompatibility = compile_source_compatibility
562     targetCompatibility = compile_target_compatibility
563     options.compilerArgs = additional_compiler_args
564     print ("Setting target compatibility to "+targetCompatibility+"\n")
565   }
566
567 }
568
569
570 compileTestJava {
571   if (use_clover) {
572     dependsOn compileCloverJava
573     classpath += configurations.cloverRuntime
574   } else {
575     classpath += sourceSets.main.runtimeClasspath
576   }
577   doFirst {
578     sourceCompatibility = compile_source_compatibility
579     targetCompatibility = compile_target_compatibility
580     options.compilerArgs = additional_compiler_args
581     print ("Setting target compatibility to "+targetCompatibility+"\n")
582   }
583 }
584
585
586 compileCloverJava {
587
588   doFirst {
589     sourceCompatibility = compile_source_compatibility
590     targetCompatibility = compile_target_compatibility
591     options.compilerArgs += additional_compiler_args
592     print ("Setting target compatibility to "+targetCompatibility+"\n")
593   }
594   classpath += configurations.cloverRuntime
595 }
596
597
598 clean {
599   doFirst {
600     delete sourceSets.main.java.outputDir
601   }
602 }
603
604
605 cleanTest {
606   doFirst {
607     delete sourceSets.test.java.outputDir
608     delete cloverInstrDir
609   }
610 }
611
612
613 // format is a string like date.format("dd MMMM yyyy")
614 def getDate(format) {
615   def date = new Date()
616   return date.format(format)
617 }
618
619
620 task setGitVals {
621   def hashStdOut = new ByteArrayOutputStream()
622   exec {
623     commandLine "git", "rev-parse", "--short", "HEAD"
624     standardOutput = hashStdOut
625     ignoreExitValue true
626   }
627
628   def branchStdOut = new ByteArrayOutputStream()
629   exec {
630     commandLine "git", "rev-parse", "--abbrev-ref", "HEAD"
631     standardOutput = branchStdOut
632     ignoreExitValue true
633   }
634
635   gitHash = hashStdOut.toString().trim()
636   gitBranch = branchStdOut.toString().trim()
637
638   outputs.upToDateWhen { false }
639 }
640
641
642 task createBuildProperties(type: WriteProperties) {
643   dependsOn setGitVals
644   inputs.dir("${jalviewDir}/${sourceDir}")
645   inputs.dir("${jalviewDir}/${resourceDir}")
646   file(buildProperties).getParentFile().mkdirs()
647   outputFile (buildProperties)
648   // taking time specific comment out to allow better incremental builds
649   comment "--Jalview Build Details--\n"+getDate("yyyy-MM-dd HH:mm:ss")
650   //comment "--Jalview Build Details--\n"+getDate("yyyy-MM-dd")
651   property "BUILD_DATE", getDate("HH:mm:ss dd MMMM yyyy")
652   property "VERSION", JALVIEW_VERSION
653   property "INSTALLATION", INSTALLATION+" git-commit:"+gitHash+" ["+gitBranch+"]"
654   outputs.file(outputFile)
655 }
656
657
658 task cleanBuildingHTML(type: Delete) {
659   doFirst {
660     delete buildingHTML
661   }
662 }
663
664
665 task convertBuildingMD(type: Exec) {
666   dependsOn cleanBuildingHTML
667   def buildingMD = "${jalviewDir}/${docDir}/building.md"
668   def css = "${jalviewDir}/${docDir}/github.css"
669
670   def pandoc = null
671   pandoc_exec.split(",").each {
672     if (file(it.trim()).exists()) {
673       pandoc = it.trim()
674       return true
675     }
676   }
677
678   def hostname = "hostname".execute().text.trim()
679   if ((pandoc == null || ! file(pandoc).exists()) && hostname.equals("jv-bamboo")) {
680     pandoc = System.getProperty("user.home")+"/buildtools/pandoc/bin/pandoc"
681   }
682
683   doFirst {
684     if (pandoc != null && file(pandoc).exists()) {
685         commandLine pandoc, '-s', '-o', buildingHTML, '--metadata', 'pagetitle="Building Jalview from Source"', '--toc', '-H', css, buildingMD
686     } else {
687         println("Cannot find pandoc. Skipping convert building.md to HTML")
688         throw new StopExecutionException()
689     }
690   }
691
692   ignoreExitValue true
693
694   inputs.file(buildingMD)
695   inputs.file(css)
696   outputs.file(buildingHTML)
697 }
698
699
700 clean {
701   doFirst {
702     delete buildingHTML
703   }
704 }
705
706
707 task syncDocs(type: Sync) {
708   dependsOn convertBuildingMD
709   def syncDir = "${classes}/${docDir}"
710   from fileTree("${jalviewDir}/${docDir}")
711   into syncDir
712
713 }
714
715
716 task copyHelp(type: Copy) {
717   def inputDir = "${jalviewDir}/${helpParentDir}/${helpDir}"
718   def outputDir = "${classes}/${helpDir}"
719   from(inputDir) {
720     exclude '**/*.gif'
721     exclude '**/*.jpg'
722     exclude '**/*.png'
723     filter(ReplaceTokens,
724       beginToken: '$$',
725       endToken: '$$',
726       tokens: [
727         'Version-Rel': JALVIEW_VERSION,
728         'Year-Rel': getDate("yyyy")
729       ]
730     )
731   }
732   from(inputDir) {
733     include '**/*.gif'
734     include '**/*.jpg'
735     include '**/*.png'
736   }
737   into outputDir
738
739   inputs.dir(inputDir)
740   outputs.files(helpFile)
741   outputs.dir(outputDir)
742 }
743
744
745 task syncLib(type: Sync) {
746   def syncDir = "${classes}/${libDistDir}"
747   from fileTree("${jalviewDir}/${libDistDir}")
748   into syncDir
749 }
750
751
752 task syncResources(type: Sync) {
753   from "${jalviewDir}/${resourceDir}"
754   include "**/*.*"
755   into "${classes}"
756   preserve {
757     include "**"
758   }
759 }
760
761
762 task prepare {
763   dependsOn syncResources
764   dependsOn syncDocs
765   dependsOn copyHelp
766 }
767
768
769 //testReportDirName = "test-reports" // note that test workingDir will be $jalviewDir
770 test {
771   dependsOn prepare
772   dependsOn compileJava
773   if (use_clover) {
774     dependsOn cloverInstr
775   }
776
777   if (use_clover) {
778     print("Running tests " + (use_clover?"WITH":"WITHOUT") + " clover [clover="+use_clover+"]\n")
779   }
780
781   useTestNG() {
782     includeGroups testngGroups
783     preserveOrder true
784     useDefaultListeners=true
785   }
786
787   workingDir = jalviewDir
788   //systemProperties 'clover.jar' System.properties.clover.jar
789   sourceCompatibility = compile_source_compatibility
790   targetCompatibility = compile_target_compatibility
791   jvmArgs += additional_compiler_args
792
793 }
794
795
796 task buildIndices(type: JavaExec) {
797   dependsOn copyHelp
798   classpath = sourceSets.main.compileClasspath
799   main = "com.sun.java.help.search.Indexer"
800   workingDir = "${classes}/${helpDir}"
801   def argDir = "html"
802   args = [ argDir ]
803   inputs.dir("${workingDir}/${argDir}")
804
805   outputs.dir("${classes}/doc")
806   outputs.dir("${classes}/help")
807   outputs.file("${workingDir}/JavaHelpSearch/DOCS")
808   outputs.file("${workingDir}/JavaHelpSearch/DOCS.TAB")
809   outputs.file("${workingDir}/JavaHelpSearch/OFFSETS")
810   outputs.file("${workingDir}/JavaHelpSearch/POSITIONS")
811   outputs.file("${workingDir}/JavaHelpSearch/SCHEMA")
812   outputs.file("${workingDir}/JavaHelpSearch/TMAP")
813 }
814
815
816 task compileLinkCheck(type: JavaCompile) {
817   options.fork = true
818   classpath = files("${jalviewDir}/${utilsDir}")
819   destinationDir = file("${jalviewDir}/${utilsDir}")
820   source = fileTree(dir: "${jalviewDir}/${utilsDir}", include: ["HelpLinksChecker.java", "BufferedLineReader.java"])
821
822   inputs.file("${jalviewDir}/${utilsDir}/HelpLinksChecker.java")
823   inputs.file("${jalviewDir}/${utilsDir}/HelpLinksChecker.java")
824   outputs.file("${jalviewDir}/${utilsDir}/HelpLinksChecker.class")
825   outputs.file("${jalviewDir}/${utilsDir}/BufferedLineReader.class")
826 }
827
828
829 task linkCheck(type: JavaExec) {
830   dependsOn prepare, compileLinkCheck
831
832   def helpLinksCheckerOutFile = file("${jalviewDir}/${utilsDir}/HelpLinksChecker.out")
833   classpath = files("${jalviewDir}/${utilsDir}")
834   main = "HelpLinksChecker"
835   workingDir = jalviewDir
836   def help = "${classes}/${helpDir}"
837   args = [ "${classes}/${helpDir}", "-nointernet" ]
838
839   def outFOS = new FileOutputStream(helpLinksCheckerOutFile, false) // false == don't append
840   def errFOS = outFOS
841   standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
842     outFOS,
843     standardOutput)
844   errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
845     outFOS,
846     errorOutput)
847
848   inputs.dir("${classes}/${helpDir}")
849   outputs.file(helpLinksCheckerOutFile)
850 }
851
852 // import the pubhtmlhelp target
853 ant.properties.basedir = "${jalviewDir}"
854 ant.properties.helpBuildDir = "${jalviewDirAbsolutePath}/${classes}/${helpDir}"
855 ant.importBuild "${utilsDir}/publishHelp.xml"
856
857
858 task cleanPackageDir(type: Delete) {
859   doFirst {
860     delete fileTree(dir: "${jalviewDir}/${packageDir}", include: "*.jar")
861   }
862 }
863
864 jar {
865   dependsOn linkCheck
866   dependsOn buildIndices
867   dependsOn createBuildProperties
868
869   manifest {
870     attributes "Main-Class": mainClass,
871     "Permissions": "all-permissions",
872     "Application-Name": "Jalview Desktop",
873     "Codebase": application_codebase
874   }
875
876   destinationDir = file("${jalviewDir}/${packageDir}")
877   archiveName = rootProject.name+".jar"
878
879   exclude "cache*/**"
880   exclude "*.jar"
881   exclude "*.jar.*"
882   exclude "**/*.jar"
883   exclude "**/*.jar.*"
884
885   inputs.dir("${classes}")
886   outputs.file("${jalviewDir}/${packageDir}/${archiveName}")
887 }
888
889
890 task copyJars(type: Copy) {
891   from fileTree(dir: "${classes}", include: "**/*.jar").files
892   into "${jalviewDir}/${packageDir}"
893 }
894
895
896 // doing a Sync instead of Copy as Copy doesn't deal with "outputs" very well
897 task syncJars(type: Sync) {
898   from fileTree(dir: "${jalviewDir}/${libDistDir}", include: "**/*.jar").files
899   into "${jalviewDir}/${packageDir}"
900   preserve {
901     include jar.archiveName
902   }
903 }
904
905
906 task makeDist {
907   group = "build"
908   description = "Put all required libraries in dist"
909   // order of "cleanPackageDir", "copyJars", "jar" important!
910   jar.mustRunAfter cleanPackageDir
911   syncJars.mustRunAfter cleanPackageDir
912   dependsOn cleanPackageDir
913   dependsOn syncJars
914   dependsOn jar
915   outputs.dir("${jalviewDir}/${packageDir}")
916 }
917
918
919 task cleanDist {
920   dependsOn cleanPackageDir
921   dependsOn cleanTest
922   dependsOn clean
923 }
924
925 shadowJar {
926   group = "distribution"
927   if (buildDist) {
928     dependsOn makeDist
929   }
930   from ("${jalviewDir}/${libDistDir}") {
931     include("*.jar")
932   }
933   manifest {
934     attributes 'Implementation-Version': JALVIEW_VERSION
935   }
936   mainClassName = shadowJarMainClass
937   mergeServiceFiles()
938   classifier = "all-"+JALVIEW_VERSION+"-j"+JAVA_VERSION
939   minimize()
940 }
941
942
943 task getdownWebsite() {
944   group = "distribution"
945   description = "Create the getdown minimal app folder, and website folder for this version of jalview. Website folder also used for offline app installer"
946   if (buildDist) {
947     dependsOn makeDist
948   }
949
950   def getdownWebsiteResourceFilenames = []
951   def getdownTextString = ""
952   def getdownResourceDir = getdownResourceDir
953   def getdownAppDir = getdownAppDir
954   def getdownResourceFilenames = []
955
956   doFirst {
957     // clean the getdown website and files dir before creating getdown folders
958     delete getdownWebsiteDir
959     delete getdownFilesDir
960
961     copy {
962       from buildProperties
963       rename(build_properties_file, getdown_build_properties)
964       into getdownAppDir
965     }
966     getdownWebsiteResourceFilenames += "${getdown_app_dir}/${getdown_build_properties}"
967
968     // go through properties looking for getdown_txt_...
969     def props = project.properties.sort { it.key }
970     if (getdown_alt_java_min_version.length() > 0) {
971       props.put("getdown_txt_java_min_version", getdown_alt_java_min_version)
972     }
973     if (getdown_alt_java_max_version.length() > 0) {
974       props.put("getdown_txt_java_max_version", getdown_alt_java_max_version)
975     }
976     props.put("getdown_txt_multi_java_location", getdown_alt_multi_java_location)
977
978     props.put("getdown_txt_appbase", getdown_app_base)
979     props.each{ prop, val ->
980       if (prop.startsWith("getdown_txt_") && val != null) {
981         if (prop.startsWith("getdown_txt_multi_")) {
982           def key = prop.substring(18)
983           val.split(",").each{ v ->
984             def line = "${key} = ${v}\n"
985             getdownTextString += line
986           }
987         } else {
988           // file values rationalised
989           if (val.indexOf('/') > -1 || prop.startsWith("getdown_txt_resource")) {
990             def r = null
991             if (val.indexOf('/') == 0) {
992               // absolute path
993               r = file(val)
994             } else if (val.indexOf('/') > 0) {
995               // relative path (relative to jalviewDir)
996               r = file( "${jalviewDir}/${val}" )
997             }
998             if (r.exists()) {
999               val = "${getdown_resource_dir}/" + r.getName()
1000               getdownWebsiteResourceFilenames += val
1001               getdownResourceFilenames += r.getPath()
1002             }
1003           }
1004           if (! prop.startsWith("getdown_txt_resource")) {
1005             def line = prop.substring(12) + " = ${val}\n"
1006             getdownTextString += line
1007           }
1008         }
1009       }
1010     }
1011
1012     getdownWebsiteResourceFilenames.each{ filename ->
1013       getdownTextString += "resource = ${filename}\n"
1014     }
1015     getdownResourceFilenames.each{ filename ->
1016       copy {
1017         from filename
1018         into getdownResourceDir
1019       }
1020     }
1021
1022     def codeFiles = []
1023     fileTree(file(packageDir)).each{ f ->
1024       if (f.isDirectory()) {
1025         def files = fileTree(dir: f, include: ["*"]).getFiles()
1026         codeFiles += files
1027       } else if (f.exists()) {
1028         codeFiles += f
1029       }
1030     }
1031     codeFiles.sort().each{f ->
1032       def name = f.getName()
1033       def line = "code = ${getdown_app_dir}/${name}\n"
1034       getdownTextString += line
1035       copy {
1036         from f.getPath()
1037         into getdownAppDir
1038       }
1039     }
1040
1041     // NOT USING MODULES YET, EVERYTHING SHOULD BE IN dist
1042     /*
1043     if (JAVA_VERSION.equals("11")) {
1044     def j11libFiles = fileTree(dir: "${jalviewDir}/${j11libDir}", include: ["*.jar"]).getFiles()
1045     j11libFiles.sort().each{f ->
1046     def name = f.getName()
1047     def line = "code = ${getdown_j11lib_dir}/${name}\n"
1048     getdownTextString += line
1049     copy {
1050     from f.getPath()
1051     into getdownJ11libDir
1052     }
1053     }
1054     }
1055      */
1056
1057     // 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.
1058     //getdownTextString += "class = " + file(getdownLauncher).getName() + "\n"
1059     getdownTextString += "resource = ${getdown_launcher_new}\n"
1060     getdownTextString += "class = ${mainClass}\n"
1061
1062     def getdown_txt = file("${getdownWebsiteDir}/getdown.txt")
1063     getdown_txt.write(getdownTextString)
1064
1065     def launch_jvl = file("${getdownWebsiteDir}/${getdown_launch_jvl}")
1066     launch_jvl.write("appbase="+props.get("getdown_txt_appbase"))
1067
1068     copy {
1069       from getdownLauncher
1070       rename(file(getdownLauncher).getName(), getdown_launcher_new)
1071       into getdownWebsiteDir
1072     }
1073
1074     copy {
1075       from getdownLauncher
1076       if (file(getdownLauncher).getName() != getdown_launcher) {
1077         rename(file(getdownLauncher).getName(), getdown_launcher)
1078       }
1079       into getdownWebsiteDir
1080     }
1081
1082     if (! (CHANNEL.startsWith("ARCHIVE") || CHANNEL.startsWith("DEVELOP"))) {
1083       copy {
1084         from getdown_txt
1085         from getdownLauncher
1086         from "${getdownWebsiteDir}/${getdown_build_properties}"
1087         if (file(getdownLauncher).getName() != getdown_launcher) {
1088           rename(file(getdownLauncher).getName(), getdown_launcher)
1089         }
1090         into getdownInstallDir
1091       }
1092
1093       copy {
1094         from getdownInstallDir
1095         into getdownFilesInstallDir
1096       }
1097     }
1098
1099     copy {
1100       from getdown_txt
1101       from launch_jvl
1102       from getdownLauncher
1103       from "${getdownWebsiteDir}/${getdown_build_properties}"
1104       if (file(getdownLauncher).getName() != getdown_launcher) {
1105         rename(file(getdownLauncher).getName(), getdown_launcher)
1106       }
1107       into getdownFilesDir
1108     }
1109
1110     copy {
1111       from getdownResourceDir
1112       into "${getdownFilesDir}/${getdown_resource_dir}"
1113     }
1114   }
1115
1116   if (buildDist) {
1117     inputs.dir("${jalviewDir}/${packageDir}")
1118   }
1119   outputs.dir(getdownWebsiteDir)
1120   outputs.dir(getdownFilesDir)
1121 }
1122
1123
1124 task getdownDigest(type: JavaExec) {
1125   group = "distribution"
1126   description = "Digest the getdown website folder"
1127   dependsOn getdownWebsite
1128   doFirst {
1129     classpath = files("${getdownWebsiteDir}/${getdown_launcher}")
1130   }
1131   main = "com.threerings.getdown.tools.Digester"
1132   args getdownWebsiteDir
1133   inputs.dir(getdownWebsiteDir)
1134   outputs.file("${getdownWebsiteDir}/digest2.txt")
1135 }
1136
1137
1138 task getdown() {
1139   group = "distribution"
1140   description = "Create the minimal and full getdown app folder for installers and website and create digest file"
1141   dependsOn getdownDigest
1142   doLast {
1143     if (reportRsyncCommand) {
1144       def fromDir = getdownWebsiteDir + (getdownWebsiteDir.endsWith('/')?'':'/')
1145       def toDir = "${getdown_rsync_dest}/${getdownDir}" + (getdownDir.endsWith('/')?'':'/')
1146       println "LIKELY RSYNC COMMAND:"
1147       println "mkdir -p '$toDir'\nrsync -avh --delete '$fromDir' '$toDir'"
1148       if (RUNRSYNC == "true") {
1149         exec {
1150           commandLine "mkdir", "-p", toDir
1151         }
1152         exec {
1153           commandLine "rsync", "-avh", "--delete", fromDir, toDir
1154         }
1155       }
1156     }
1157   }
1158 }
1159
1160
1161 clean {
1162   doFirst {
1163     delete getdownWebsiteDir
1164     delete getdownFilesDir
1165   }
1166 }
1167
1168
1169 install4j {
1170   def install4jHomeDir = "/opt/install4j"
1171   def hostname = "hostname".execute().text.trim()
1172   if (hostname.equals("jv-bamboo")) {
1173     install4jHomeDir = System.getProperty("user.home")+"/buildtools/install4j"
1174   } else if (OperatingSystem.current().isMacOsX()) {
1175     install4jHomeDir = '/Applications/install4j.app/Contents/Resources/app'
1176     if (! file(install4jHomeDir).exists()) {
1177       install4jHomeDir = System.getProperty("user.home")+install4jHomeDir
1178     }
1179   } else if (OperatingSystem.current().isLinux()) {
1180     install4jHomeDir = System.getProperty("user.home")+"/buildtools/install4j"
1181   }
1182   installDir = file(install4jHomeDir)
1183   mediaTypes = Arrays.asList(install4jMediaTypes.split(","))
1184   if (install4jFaster.equals("true")) {
1185     faster = true
1186   }
1187 }
1188
1189
1190 task copyInstall4jTemplate(type: Copy) {
1191   from (install4jDir) {
1192     include install4jTemplate
1193     rename (install4jTemplate, install4jConfFileName)
1194     filter(ReplaceTokens,
1195       beginToken: '',
1196       endToken: '',
1197       tokens: [
1198         '9999999999': JAVA_VERSION
1199       ]
1200     )
1201     filter(ReplaceTokens,
1202       beginToken: '$$',
1203       endToken: '$$',
1204       tokens: [
1205         'JAVA_VERSION': JAVA_VERSION,
1206         'JAVA_INTEGER_VERSION': JAVA_INTEGER_VERSION,
1207         'VERSION': JALVIEW_VERSION,
1208         'MACOS_JAVA_VM_DIR': macosJavaVMDir,
1209         'MACOS_JAVA_VM_TGZ': macosJavaVMTgz,
1210         'WINDOWS_JAVA_VM_DIR': windowsJavaVMDir,
1211         'WINDOWS_JAVA_VM_TGZ': windowsJavaVMTgz,
1212         'INSTALL4JINFOPLISTFILEASSOCIATIONS': install4jInfoPlistFileAssociations,
1213         'COPYRIGHT_MESSAGE': install4jCopyrightMessage,
1214         'MACOS_BUNDLE_ID': install4jMacOSBundleId,
1215         'GETDOWN_RESOURCE_DIR': getdown_resource_dir,
1216         'GETDOWN_DIST_DIR': getdown_app_dir,
1217         'GETDOWN_ALT_DIR': getdown_app_dir_alt,
1218         'GETDOWN_INSTALL_DIR': getdown_install_dir
1219       ]
1220     )
1221     if (OSX_KEYPASS == "") {
1222       filter(ReplaceTokens,
1223         beginToken: 'codeSigning macEnabled="',
1224         endToken: '"',
1225         tokens: [
1226           'true': 'codeSigning macEnabled="false"'
1227         ]
1228       )
1229       filter(ReplaceTokens,
1230         beginToken: 'runPostProcessor="true" ',
1231         endToken: 'Processor',
1232         tokens: [
1233           'post': 'runPostProcessor="false" postProcessor'
1234         ]
1235       )
1236     }
1237   }
1238   into install4jDir
1239   outputs.files(install4jConfFile)
1240
1241   doLast {
1242     // include file associations in installer
1243     def installerFileAssociationsXml = file("${install4jDir}/${install4jInstallerFileAssociations}").text
1244     ant.replaceregexp(
1245       byline: false,
1246       flags: "s",
1247       match: '<action name="EXTENSIONS_REPLACED_BY_GRADLE".*?</action>',
1248       replace: installerFileAssociationsXml,
1249       file: install4jConfFile
1250     )
1251     /*
1252     // include uninstaller applescript app files in dmg
1253     def installerDMGUninstallerXml = file("$install4jDir/$install4jDMGUninstallerAppFiles").text
1254     ant.replaceregexp(
1255     byline: false,
1256     flags: "s",
1257     match: '<file name="UNINSTALL_OLD_JALVIEW_APP_REPLACED_IN_GRADLE" file=.*?>',
1258     replace: installerDMGUninstallerXml,
1259     file: install4jConfFile
1260     )
1261      */
1262   }
1263 }
1264
1265
1266 clean {
1267   doFirst {
1268     delete install4jConfFile
1269   }
1270 }
1271
1272
1273 task installers(type: com.install4j.gradle.Install4jTask) {
1274   group = "distribution"
1275   description = "Create the install4j installers"
1276   dependsOn getdown
1277   dependsOn copyInstall4jTemplate
1278   projectFile = file(install4jConfFile)
1279   variables = [majorVersion: version.substring(2, 11), build: 001, OSX_KEYSTORE: OSX_KEYSTORE, JSIGN_SH: JSIGN_SH]
1280   destination = "${jalviewDir}/${install4jBuildDir}/${JAVA_VERSION}"
1281   buildSelected = true
1282
1283   if (OSX_KEYPASS) {
1284     macKeystorePassword=OSX_KEYPASS
1285   }
1286
1287   doFirst {
1288     println("Using projectFile "+projectFile)
1289   }
1290
1291   inputs.dir(getdownWebsiteDir)
1292   inputs.file(install4jConfFile)
1293   inputs.dir(macosJavaVMDir)
1294   inputs.dir(windowsJavaVMDir)
1295   outputs.dir("${jalviewDir}/${install4jBuildDir}/${JAVA_VERSION}")
1296 }
1297
1298
1299 clean {
1300   doFirst {
1301     delete install4jConfFile
1302   }
1303 }
1304
1305
1306 task sourceDist (type: Tar) {
1307   
1308   def VERSION_UNDERSCORES = JALVIEW_VERSION.replaceAll("\\.", "_")
1309   def outputFileName = "${project.name}_${VERSION_UNDERSCORES}.tar.gz"
1310   // cater for buildship < 3.1 [3.0.1 is max version in eclipse 2018-09]
1311   try {
1312     archiveFileName = outputFileName
1313   } catch (Exception e) {
1314     archiveName = outputFileName
1315   }
1316   
1317   compression Compression.GZIP
1318   
1319   into project.name
1320
1321   def EXCLUDE_FILES=["build/*","bin/*","test-output/","test-reports","tests","clover*/*"
1322   ,".*"
1323   ,"benchmarking/*"
1324   ,"**/.*"
1325   ,"*.class"
1326   ,"**/*.class","${j11modDir}/**/*.jar","appletlib","**/*locales"
1327   ,"*locales/**",
1328   ,"utils/InstallAnywhere"] 
1329   def PROCESS_FILES=[   "AUTHORS",
1330   "CITATION",
1331   "FEATURETODO",
1332   "JAVA-11-README",
1333   "FEATURETODO",
1334   "LICENSE",
1335   "**/README",
1336   "RELEASE",
1337   "THIRDPARTYLIBS","TESTNG",
1338   "build.gradle",
1339   "gradle.properties",
1340   "**/*.java",
1341   "**/*.html",
1342   "**/*.xml",
1343   "**/*.gradle",
1344   "**/*.groovy",
1345   "**/*.properties",
1346   "**/*.perl",
1347   "**/*.sh"]
1348
1349   from(jalviewDir) {
1350     exclude (EXCLUDE_FILES)
1351     include (PROCESS_FILES)
1352     filter(ReplaceTokens,
1353       beginToken: '$$',
1354       endToken: '$$',
1355       tokens: [
1356         'Version-Rel': JALVIEW_VERSION,
1357         'Year-Rel': getDate("yyyy")
1358       ]
1359     )
1360   }
1361   from(jalviewDir) {
1362     exclude (EXCLUDE_FILES)
1363     exclude (PROCESS_FILES)
1364     exclude ("appletlib")
1365     exclude ("**/*locales")
1366     exclude ("*locales/**")
1367     exclude ("utils/InstallAnywhere")
1368
1369     exclude (getdown_files_dir)
1370     exclude (getdown_website_dir)
1371
1372     // exluding these as not using jars as modules yet
1373     exclude ("${j11modDir}/**/*.jar")
1374   }
1375   //  from (jalviewDir) {
1376   //    // explicit includes for stuff that seemed to not get included
1377   //    include(fileTree("test/**/*."))
1378   //    exclude(EXCLUDE_FILES)
1379   //    exclude(PROCESS_FILES)
1380   //  }
1381 }
1382
1383
1384 task helppages  {
1385   dependsOn copyHelp
1386   dependsOn pubhtmlhelp
1387   
1388   inputs.dir("${classes}/${helpDir}")
1389   outputs.dir("${helpOutputDir}")
1390 }
1391
1392
1393 task j2sSetHeadlessBuild {
1394   doFirst {
1395     IN_ECLIPSE = false
1396   }
1397 }
1398
1399
1400 task jalviewjsSetEclipseWorkspace {
1401   def propKey = "jalviewjs_eclipse_workspace"
1402   def propVal = null
1403   if (project.hasProperty(propKey)) {
1404     propVal = project.getProperty(propKey)
1405     if (propVal.startsWith("~/")) {
1406       propVal = System.getProperty("user.home") + propVal.substring(1)
1407     }
1408   }
1409   def propsFileName = "${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_eclipse_workspace_location_file}"
1410   def propsFile = file(propsFileName)
1411   def eclipseWsDir = propVal
1412   def props = new Properties()
1413
1414   if (( eclipseWsDir == null || !file(eclipseWsDir).exists() ) && propsFile.exists()) {
1415     def ins = new FileInputStream(propsFileName)
1416     props.load(ins)
1417     ins.close()
1418     if (props.getProperty(propKey, null) != null) {
1419       eclipseWsDir = props.getProperty(propKey)
1420     }
1421   }
1422
1423   def writeProps = false
1424   if (eclipseWsDir == null || !file(eclipseWsDir).exists()) {
1425     def tempDir = File.createTempDir()
1426     eclipseWsDir = tempDir.getAbsolutePath()
1427     writeProps = true
1428   }
1429   eclipseWorkspace = file(eclipseWsDir)
1430
1431   doFirst {
1432     // do not run a headless transpile when we claim to be in Eclipse
1433     if (IN_ECLIPSE) {
1434       println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
1435       throw new StopExecutionException("Not running headless transpile whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
1436     } else {
1437       println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
1438     }
1439
1440     if (writeProps) {
1441       props.setProperty(propKey, eclipseWsDir)
1442       propsFile.parentFile.mkdirs()
1443       def bytes = new ByteArrayOutputStream()
1444       props.store(bytes, null)
1445       def propertiesString = bytes.toString()
1446       propsFile.text = propertiesString
1447     }
1448
1449     println("ECLIPSE WORKSPACE: "+eclipseWorkspace.getPath())
1450   }
1451
1452   //inputs.property(propKey, eclipseWsDir) // eclipseWsDir only gets set once this task runs, so will be out-of-date
1453   outputs.file(propsFileName)
1454   outputs.upToDateWhen { eclipseWorkspace.exists() }
1455 }
1456
1457
1458 task jalviewjsEclipsePaths {
1459   def eclipseProduct
1460
1461   def eclipseRoot = jalviewjs_eclipse_root
1462   if (eclipseRoot.startsWith("~/")) {
1463     eclipseRoot = System.getProperty("user.home") + eclipseRoot.substring(1)
1464   }
1465   if (OperatingSystem.current().isMacOsX()) {
1466     eclipseRoot += "/Eclipse.app"
1467     eclipseBinary = "${eclipseRoot}/Contents/MacOS/eclipse"
1468     eclipseProduct = "${eclipseRoot}/Contents/Eclipse/.eclipseproduct"
1469   } else if (OperatingSystem.current().isWindows()) { // check these paths!!
1470     if (file("${eclipseRoot}/eclipse").isDirectory() && file("${eclipseRoot}/eclipse/.eclipseproduct").exists()) {
1471       eclipseRoot += "/eclipse.exe"
1472     }
1473     eclipseBinary = "${eclipseRoot}/eclipse"
1474     eclipseProduct = "${eclipseRoot}/.eclipseproduct"
1475   } else { // linux or unix
1476     if (file("${eclipseRoot}/eclipse").isDirectory() && file("${eclipseRoot}/eclipse/.eclipseproduct").exists()) {
1477       eclipseRoot += "/eclipse"
1478     }
1479     eclipseBinary = "${eclipseRoot}/eclipse"
1480     eclipseProduct = "${eclipseRoot}/.eclipseproduct"
1481   }
1482
1483   eclipseVersion = "4.13" // default
1484   def assumedVersion = true
1485   if (file(eclipseProduct).exists()) {
1486     def fis = new FileInputStream(eclipseProduct)
1487     def props = new Properties()
1488     props.load(fis)
1489     eclipseVersion = props.getProperty("version")
1490     fis.close()
1491     assumedVersion = false
1492   }
1493   
1494   def propKey = "eclipse_debug"
1495   eclipseDebug = (project.hasProperty(propKey) && project.getProperty(propKey).equals("true"))
1496
1497   doFirst {
1498     // do not run a headless transpile when we claim to be in Eclipse
1499     if (IN_ECLIPSE) {
1500       println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
1501       throw new StopExecutionException("Not running headless transpile whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
1502     } else {
1503       println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
1504     }
1505
1506     if (!assumedVersion) {
1507       println("ECLIPSE VERSION=${eclipseVersion}")
1508     }
1509   }
1510 }
1511
1512
1513 task eclipseSetup {
1514   dependsOn eclipseProject
1515   dependsOn eclipseClasspath
1516   dependsOn eclipseJdt
1517 }
1518
1519
1520 // this version (type: Copy) will delete anything in the eclipse dropins folder that isn't in fromDropinsDir
1521 task jalviewjsEclipseCopyDropins(type: Copy) {
1522   dependsOn jalviewjsEclipsePaths
1523
1524   def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjs_eclipse_dropins_dir}", include: "*.jar")
1525   inputFiles += file("${jalviewDir}/${jalviewjs_j2s_plugin}")
1526   def outputDir = "${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_eclipse_tmp_dropins_dir}"
1527
1528   from inputFiles
1529   into outputDir
1530 }
1531
1532
1533 // this eclipse -clean doesn't actually work
1534 task jalviewjsCleanEclipse(type: Exec) {
1535   dependsOn eclipseSetup
1536   dependsOn jalviewjsEclipsePaths
1537   dependsOn jalviewjsEclipseCopyDropins
1538
1539   executable(eclipseBinary)
1540   args(["-nosplash", "--launcher.suppressErrors", "-data", eclipseWorkspace.getPath(), "-clean", "-console", "-consoleLog"])
1541   if (eclipseDebug) {
1542     args += "-debug"
1543   }
1544   args += "-l"
1545
1546   def inputString = """exit
1547 y
1548 """
1549   def inputByteStream = new ByteArrayInputStream(inputString.getBytes())
1550   standardInput = inputByteStream
1551 }
1552
1553 /* not really working yet
1554 jalviewjsEclipseCopyDropins.finalizedBy jalviewjsCleanEclipse
1555 */
1556
1557
1558 task jalviewjsTransferUnzipSwingJs {
1559   def file_zip = "${jalviewDir}/${jalviewjs_swingjs_zip}"
1560
1561   doLast {
1562     copy {
1563       from zipTree(file_zip)
1564       into "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}"
1565     }
1566   }
1567
1568   inputs.file file_zip
1569   outputs.dir "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}"
1570 }
1571
1572
1573 task jalviewjsTransferUnzipLib {
1574   def zipFiles = fileTree(dir: "${jalviewDir}/${jalviewjs_libjs_dir}", include: "*.zip")
1575
1576   doLast {
1577     zipFiles.each { file_zip -> 
1578       copy {
1579         from zipTree(file_zip)
1580         into "${jalviewDir}/${jalviewjsTransferSiteLibDir}"
1581       }
1582     }
1583   }
1584
1585   inputs.files zipFiles
1586   outputs.dir "${jalviewDir}/${jalviewjsTransferSiteLibDir}"
1587 }
1588
1589
1590 task jalviewjsTransferUnzipAllLibs {
1591   dependsOn jalviewjsTransferUnzipSwingJs
1592   dependsOn jalviewjsTransferUnzipLib
1593 }
1594
1595
1596 task jalviewjsCreateJ2sSettings(type: WriteProperties) {
1597   group "JalviewJS"
1598   description "Create the .j2s file from the j2s.* properties"
1599
1600   outputFile ("${jalviewDir}/${jalviewjs_j2s_settings}")
1601   def j2s_props = project.properties.findAll { it.key.startsWith("j2s.") }.sort { it.key }
1602   def siteDirProperty = "j2s.site.directory"
1603   def setSiteDir = false
1604   j2s_props.each { prop, val ->
1605     if (val != null) {
1606       if (prop == siteDirProperty) {
1607         if (!(val.startsWith('/') || val.startsWith("file://") )) {
1608           val = "${jalviewDir}/${jalviewjsTransferSiteJsDir}/${val}"
1609         }
1610         setSiteDir = true
1611       }
1612       property(prop,val)
1613     }
1614     if (!setSiteDir) { // default site location, don't override specifically set property
1615       property(siteDirProperty,"${jalviewDir}/${jalviewjsTransferSiteJsDir}")
1616     }
1617   }
1618   inputs.properties(j2s_props)
1619   outputs.file(outputFile)
1620 }
1621
1622
1623 task jalviewjsEclipseSetup {
1624   dependsOn jalviewjsEclipseCopyDropins
1625   dependsOn jalviewjsSetEclipseWorkspace
1626   dependsOn jalviewjsCreateJ2sSettings
1627 }
1628
1629
1630 task jalviewjsSyncAllLibs (type: Sync) {
1631   dependsOn jalviewjsTransferUnzipAllLibs
1632   def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjsTransferSiteLibDir}")
1633   inputFiles += fileTree(dir: "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}")
1634   def outputDir = "${jalviewDir}/${jalviewjsSiteDir}"
1635
1636   from inputFiles
1637   into outputDir
1638   def outputFiles = []
1639   rename { filename ->
1640     outputFiles += "${outputDir}/${filename}"
1641     null
1642   }
1643   preserve {
1644     include "**"
1645   }
1646   outputs.files outputFiles
1647   inputs.files inputFiles
1648 }
1649
1650
1651 task jalviewjsSyncResources (type: Sync) {
1652   def inputFiles = fileTree(dir: "${jalviewDir}/${resourceDir}")
1653   def outputDir = "${jalviewDir}/${jalviewjsSiteDir}/${jalviewjs_j2s_subdir}"
1654
1655   from inputFiles
1656   into outputDir
1657   def outputFiles = []
1658   rename { filename ->
1659     outputFiles += "${outputDir}/${filename}"
1660     null
1661   }
1662   preserve {
1663     include "**"
1664   }
1665   outputs.files outputFiles
1666   inputs.files inputFiles
1667 }
1668
1669
1670 task jalviewjsSyncSiteResources (type: Sync) {
1671   def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjs_site_resource_dir}")
1672   def outputDir = "${jalviewDir}/${jalviewjsSiteDir}"
1673
1674   from inputFiles
1675   into outputDir
1676   def outputFiles = []
1677   rename { filename ->
1678     outputFiles += "${outputDir}/${filename}"
1679     null
1680   }
1681   preserve {
1682     include "**"
1683   }
1684   outputs.files outputFiles
1685   inputs.files inputFiles
1686 }
1687
1688
1689 task jalviewjsSyncBuildProperties (type: Sync) {
1690   dependsOn createBuildProperties
1691   def inputFiles = [file(buildProperties)]
1692   def outputDir = "${jalviewDir}/${jalviewjsSiteDir}/${jalviewjs_j2s_subdir}"
1693
1694   from inputFiles
1695   into outputDir
1696   def outputFiles = []
1697   rename { filename ->
1698     outputFiles += "${outputDir}/${filename}"
1699     null
1700   }
1701   preserve {
1702     include "**"
1703   }
1704   outputs.files outputFiles
1705   inputs.files inputFiles
1706 }
1707
1708
1709 task jalviewjsProjectImport(type: Exec) {
1710   dependsOn eclipseSetup
1711   dependsOn jalviewjsEclipsePaths
1712   dependsOn jalviewjsEclipseSetup
1713
1714   doFirst {
1715     // do not run a headless import when we claim to be in Eclipse
1716     if (IN_ECLIPSE) {
1717       println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
1718       throw new StopExecutionException("Not running headless import whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
1719     } else {
1720       println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
1721     }
1722   }
1723
1724   //def projdir = eclipseWorkspace.getPath()+"/.metadata/.plugins/org.eclipse.core.resources/.projects/jalview/org.eclipse.jdt.core"
1725   def projdir = eclipseWorkspace.getPath()+"/.metadata/.plugins/org.eclipse.core.resources/.projects/jalview"
1726   executable(eclipseBinary)
1727   args(["-nosplash", "--launcher.suppressErrors", "-application", "com.seeq.eclipse.importprojects.headlessimport", "-data", eclipseWorkspace.getPath(), "-import", jalviewDirAbsolutePath])
1728   if (eclipseDebug) {
1729     args += "-debug"
1730   }
1731   args += [ "--launcher.appendVmargs", "-vmargs", "-Dorg.eclipse.equinox.p2.reconciler.dropins.directory=${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_eclipse_tmp_dropins_dir}" ]
1732   if (!IN_ECLIPSE) {
1733     args += [ "-D${j2sHeadlessBuildProperty}=true" ]
1734   }
1735
1736   inputs.file("${jalviewDir}/.project")
1737   outputs.upToDateWhen { 
1738     file(projdir).exists()
1739   }
1740 }
1741
1742
1743 task jalviewjsTranspile(type: Exec) {
1744   dependsOn jalviewjsEclipseSetup 
1745   dependsOn jalviewjsProjectImport
1746   dependsOn jalviewjsEclipsePaths
1747
1748   doFirst {
1749     // do not run a headless transpile when we claim to be in Eclipse
1750     if (IN_ECLIPSE) {
1751       println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
1752       throw new StopExecutionException("Not running headless transpile whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
1753     } else {
1754       println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
1755     }
1756   }
1757
1758   executable(eclipseBinary)
1759   args(["-nosplash", "--launcher.suppressErrors", "-application", "org.eclipse.jdt.apt.core.aptBuild", "-data", eclipseWorkspace, "-${jalviewjs_eclipse_build_arg}", eclipse_project_name ])
1760   if (eclipseDebug) {
1761     args += "-debug"
1762   }
1763   args += [ "--launcher.appendVmargs", "-vmargs", "-Dorg.eclipse.equinox.p2.reconciler.dropins.directory=${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_eclipse_tmp_dropins_dir}" ]
1764   if (!IN_ECLIPSE) {
1765     args += [ "-D${j2sHeadlessBuildProperty}=true" ]
1766   }
1767
1768   def stdout
1769   def stderr
1770   doFirst {
1771     stdout = new ByteArrayOutputStream()
1772     stderr = new ByteArrayOutputStream()
1773
1774     def logOutFileName = "${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}"
1775     def logOutFile = file(logOutFileName)
1776     logOutFile.createNewFile()
1777     logOutFile.text = """ROOT: ${jalviewjs_eclipse_root}
1778 BINARY: ${eclipseBinary}
1779 VERSION: ${eclipseVersion}
1780 WORKSPACE: ${eclipseWorkspace}
1781 DEBUG: ${eclipseDebug}
1782 ----
1783 """
1784     def logOutFOS = new FileOutputStream(logOutFile, true) // true == append
1785     // combine stdout and stderr
1786     def logErrFOS = logOutFOS
1787
1788     if (jalviewjs_j2s_to_console.equals("true")) {
1789       standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
1790         new org.apache.tools.ant.util.TeeOutputStream(
1791           logOutFOS,
1792           stdout),
1793         standardOutput)
1794       errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
1795         new org.apache.tools.ant.util.TeeOutputStream(
1796           logErrFOS,
1797           stderr),
1798         errorOutput)
1799     } else {
1800       standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
1801         logOutFOS,
1802         stdout)
1803       errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
1804         logErrFOS,
1805         stderr)
1806     }
1807   }
1808
1809   doLast {
1810     if (stdout.toString().contains("Error processing ")) {
1811       // j2s did not complete transpile
1812       //throw new TaskExecutionException("Error during transpilation:\n${stderr}\nSee eclipse transpile log file '${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}'")
1813       throw new GradleException("Error during transpilation:\n${stderr}\nSee eclipse transpile log file '${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}'")
1814     }
1815   }
1816
1817   inputs.dir("${jalviewDir}/${sourceDir}")
1818   outputs.dir("${jalviewDir}/${jalviewjsTransferSiteJsDir}")
1819   outputs.upToDateWhen( { file("${jalviewDir}/${jalviewjsTransferSiteJsDir}${jalviewjs_server_resource}").exists() } )
1820 }
1821
1822
1823 def jalviewjsCallCore(FileCollection list, String prefixFile, String suffixFile, String jsfile, String zjsfile, File logOutFile, Boolean logOutConsole) {
1824
1825   def stdout = new ByteArrayOutputStream()
1826   def stderr = new ByteArrayOutputStream()
1827
1828   def coreFile = file(jsfile)
1829   def msg = ""
1830   msg = "Generating ${jsfile}"
1831   println(msg)
1832   logOutFile.createNewFile()
1833   logOutFile.append(msg+"\n")
1834
1835   def coreTop = file(prefixFile)
1836   def coreBottom = file(suffixFile)
1837   coreFile.getParentFile().mkdirs()
1838   coreFile.createNewFile()
1839   coreFile.write( coreTop.text )
1840   list.each {
1841     f ->
1842     if (f.exists()) {
1843       def t = f.text
1844       t.replaceAll("Clazz\\.","Clazz_")
1845       t.replaceAll("Class__","Clazz._")
1846       coreFile.append( t )
1847     } else {
1848       msg = "...file '"+f.getPath()+"' does not exist, skipping"
1849       println(msg)
1850       logOutFile.append(msg+"\n")
1851     }
1852   }
1853   coreFile.append( coreBottom.text )
1854
1855   msg = "Generating ${zjsfile}"
1856   println(msg)
1857   logOutFile.append(msg+"\n")
1858   def logOutFOS = new FileOutputStream(logOutFile, true) // true == append
1859   def logErrFOS = logOutFOS
1860
1861   javaexec {
1862     classpath = files(["${jalviewDir}/tools/closure_compiler.jar"])
1863     args = [ "--js", jsfile, "--js_output_file", zjsfile ]
1864
1865     msg = "\nRunning '"+commandLine.join(' ')+"'\n"
1866     println(msg)
1867     logOutFile.append(msg+"\n")
1868
1869     if (logOutConsole) {
1870       standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
1871         new org.apache.tools.ant.util.TeeOutputStream(
1872           logOutFOS,
1873           stdout),
1874         standardOutput)
1875         errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
1876           new org.apache.tools.ant.util.TeeOutputStream(
1877             logErrFOS,
1878             stderr),
1879           errorOutput)
1880     } else {
1881       standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
1882         logOutFOS,
1883         stdout)
1884         errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
1885           logErrFOS,
1886           stderr)
1887     }
1888   }
1889   msg = "--"
1890   println(msg)
1891   logOutFile.append(msg+"\n")
1892 }
1893
1894
1895 task jalviewjsBuildAllCores {
1896   group "JalviewJS"
1897   description "Build the core js lib closures listed in the classlists dir"
1898   dependsOn jalviewjsTranspile
1899   dependsOn jalviewjsTransferUnzipSwingJs
1900
1901   def j2sDir = "${jalviewDir}/${jalviewjsTransferSiteJsDir}/${jalviewjs_j2s_subdir}"
1902   def jsDir = "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}/${jalviewjs_js_subdir}"
1903   def outputDir = "${jalviewDir}/${jalviewjsTransferSiteCoreDir}/${jalviewjs_j2s_subdir}/core"
1904   def prefixFile = "${jsDir}/core/coretop2.js"
1905   def suffixFile = "${jsDir}/core/corebottom2.js"
1906
1907   inputs.file prefixFile
1908   inputs.file suffixFile
1909
1910   def classlistFiles = []
1911   // add the classlists found int the jalviewjs_classlists_dir
1912   fileTree(dir: "${jalviewDir}/${jalviewjs_classlists_dir}", include: "*.txt").each {
1913     file ->
1914     def name = file.getName() - ".txt"
1915     classlistFiles += [
1916       'file': file,
1917       'name': name
1918     ]
1919   }
1920
1921   // _jmol and _jalview cores. Add any other peculiar classlist.txt files here
1922   classlistFiles += [ 'file': file("${jalviewDir}/${jalviewjs_classlist_jmol}"), 'name': "_jvjmol" ]
1923   classlistFiles += [ 'file': file("${jalviewDir}/${jalviewjs_classlist_jalview}"), 'name': jalviewjsJalviewCoreName ]
1924
1925   def classlists = []
1926
1927   classlistFiles.each {
1928     hash ->
1929
1930     def file = hash['file']
1931     if (! file.exists()) {
1932       println("...classlist file '"+file.getPath()+"' does not exist, skipping")
1933       return false // this is a "continue" in groovy .each closure
1934     }
1935     def name = hash['name']
1936     if (name == null) {
1937       name = file.getName() - ".txt"
1938     }
1939
1940     def filelist = []
1941     file.eachLine {
1942       line ->
1943         filelist += line
1944     }
1945     def list = fileTree(dir: j2sDir, includes: filelist)
1946
1947     def jsfile = "${outputDir}/core${name}.js"
1948     def zjsfile = "${outputDir}/core${name}.z.js"
1949
1950     classlists += [
1951     'jsfile': jsfile,
1952     'zjsfile': zjsfile,
1953     'list': list
1954     ]
1955
1956     inputs.file(file)
1957     inputs.files(list)
1958     outputs.file(jsfile)
1959     outputs.file(zjsfile)
1960   }
1961   
1962   // _stevesoft core. add any cores without a classlist here (and the inputs and outputs)
1963   def stevesoftClasslist = [
1964     'jsfile': "${outputDir}/core_stevesoft.js",
1965     'zjsfile': "${outputDir}/core_stevesoft.z.js",
1966     'list': fileTree(dir: j2sDir, include: "com/stevesoft/pat/**/*.js")
1967   ]
1968   classlists += stevesoftClasslist
1969   inputs.files(stevesoftClasslist['list'])
1970   outputs.file(stevesoftClasslist['jsfile'])
1971   outputs.file(stevesoftClasslist['zjsfile'])
1972
1973   doFirst {
1974     def logOutFile = file("${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_j2s_closure_stdout}")
1975     logOutFile.getParentFile().mkdirs()
1976     logOutFile.createNewFile()
1977     logOutFile.write(getDate("yyyy-MM-dd HH:mm:ss")+" jalviewjsBuildAllCores\n----\n")
1978
1979     classlists.each {
1980       jalviewjsCallCore(it.list, prefixFile, suffixFile, it.jsfile, it.zjsfile, logOutFile, jalviewjs_j2s_to_console.equals("true"))
1981     }
1982   }
1983
1984 }
1985
1986
1987 task jalviewjsPublishCoreTemplate(type: Sync) {
1988   dependsOn jalviewjsBuildAllCores
1989
1990   def inputFile = file("${jalviewDir}/${j2s_template_html}")
1991   def outputDir = "${jalviewDir}/${jalviewjsTransferSiteCoreDir}"
1992
1993   from inputFile
1994   into outputDir
1995   def outputFiles = []
1996   jalviewjsJalviewCoreHtmlFile = "${jalviewjsJalviewTemplateName}_${jalviewjsJalviewCoreName}.html"
1997   rename { filename ->
1998     outputFiles += "${outputDir}/${filename}"
1999     if (filename.equals(inputFile.getName())) {
2000       return jalviewjsJalviewCoreHtmlFile 
2001     }
2002     return null
2003   }
2004   filter(ReplaceTokens,
2005     beginToken: '_',
2006     endToken: '_',
2007     tokens: [
2008       'MAIN': '"'+mainClass+'"',
2009       'CODE': "null",
2010       'NAME': jalviewjsJalviewTemplateName
2011     ]
2012   )
2013   filter(ReplaceTokens,
2014     beginToken: '',
2015     endToken: '',
2016     tokens: [
2017       'NONE': jalviewjsJalviewCoreName
2018     ]
2019   )
2020   preserve {
2021     include "**"
2022   }
2023   outputs.files outputFiles
2024   inputs.files inputFile
2025 }
2026
2027
2028 task jalviewjsSyncCore (type: Sync) {
2029   dependsOn jalviewjsBuildAllCores
2030   dependsOn jalviewjsPublishCoreTemplate
2031   def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjsTransferSiteCoreDir}")
2032   def outputDir = "${jalviewDir}/${jalviewjsSiteDir}"
2033
2034   from inputFiles
2035   into outputDir
2036   def outputFiles = []
2037   rename { filename ->
2038     outputFiles += "${outputDir}/${filename}"
2039     null
2040   }
2041   preserve {
2042     include "**"
2043   }
2044   outputs.files outputFiles
2045   inputs.files inputFiles
2046 }
2047
2048
2049 // this Copy version of TransferSiteJs will delete anything else in the target dir
2050 task jalviewjsCopyTransferSiteJs(type: Copy) {
2051   dependsOn jalviewjsTranspile
2052   from "${jalviewDir}/${jalviewjsTransferSiteJsDir}"
2053   into "${jalviewDir}/${jalviewjsSiteDir}"
2054 }
2055
2056
2057 // this Sync version of TransferSite is used by buildship to keep the website automatically up to date when a file changes
2058 task jalviewjsSyncTransferSiteJs(type: Sync) {
2059   from "${jalviewDir}/${jalviewjsTransferSiteJsDir}"
2060   include "**/*.*"
2061   into "${jalviewDir}/${jalviewjsSiteDir}"
2062   preserve {
2063     include "**"
2064   }
2065 }
2066
2067
2068 jalviewjsSyncAllLibs.mustRunAfter jalviewjsCopyTransferSiteJs
2069 jalviewjsSyncResources.mustRunAfter jalviewjsCopyTransferSiteJs
2070 jalviewjsSyncSiteResources.mustRunAfter jalviewjsCopyTransferSiteJs
2071 jalviewjsSyncBuildProperties.mustRunAfter jalviewjsCopyTransferSiteJs
2072
2073 jalviewjsSyncAllLibs.mustRunAfter jalviewjsSyncTransferSiteJs
2074 jalviewjsSyncResources.mustRunAfter jalviewjsSyncTransferSiteJs
2075 jalviewjsSyncSiteResources.mustRunAfter jalviewjsSyncTransferSiteJs
2076 jalviewjsSyncBuildProperties.mustRunAfter jalviewjsSyncTransferSiteJs
2077
2078
2079 task jalviewjsPrepareSite {
2080   group "JalviewJS"
2081   description "Prepares the website folder including unzipping files and copying resources"
2082   dependsOn jalviewjsSyncAllLibs
2083   dependsOn jalviewjsSyncResources
2084   dependsOn jalviewjsSyncSiteResources
2085   dependsOn jalviewjsSyncBuildProperties
2086   dependsOn jalviewjsSyncCore
2087 }
2088
2089
2090 task jalviewjsBuildSite {
2091   group "JalviewJS"
2092   description "Builds the whole website including transpiled code"
2093   dependsOn jalviewjsCopyTransferSiteJs
2094   dependsOn jalviewjsPrepareSite
2095 }
2096
2097
2098 task cleanJalviewjsSite {
2099   doFirst {
2100     delete "${jalviewDir}/${jalviewjsTransferSiteJsDir}"
2101     delete "${jalviewDir}/${jalviewjsTransferSiteLibDir}"
2102     delete "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}"
2103     delete "${jalviewDir}/${jalviewjsTransferSiteCoreDir}"
2104     delete "${jalviewDir}/${jalviewjsSiteDir}"
2105   }
2106 }
2107
2108
2109 task jalviewjsSiteTar(type: Tar) {
2110   group "JalviewJS"
2111   description "Creates a tar.gz file for the website"
2112   dependsOn jalviewjsBuildSite
2113   def outputFilename = "jalviewjs-site-${JALVIEW_VERSION}.tar.gz"
2114   try {
2115     archiveFileName = outputFilename
2116   } catch (Exception e) {
2117     archiveName = outputFilename
2118   }
2119
2120   compression Compression.GZIP
2121
2122   from "${jalviewDir}/${jalviewjsSiteDir}"
2123   into jalviewjs_site_dir // this is inside the tar file
2124
2125   inputs.dir("${jalviewDir}/${jalviewjsSiteDir}")
2126 }
2127
2128
2129 task jalviewjsServer {
2130   group "JalviewJS"
2131   def filename = "jalviewjsTest.html"
2132   description "Starts a webserver on localhost to test the website. See ${filename} to access local site on most recently used port."
2133   def htmlFile = "${jalviewDirAbsolutePath}/${filename}"
2134   doLast {
2135
2136     SimpleHttpFileServerFactory factory = new SimpleHttpFileServerFactory()
2137     def port = Integer.valueOf(jalviewjs_server_port)
2138     def start = port
2139     def running = false
2140     def url
2141     def urlcore
2142     while(port < start+1000 && !running) {
2143       try {
2144         def doc_root = new File("${jalviewDirAbsolutePath}/${jalviewjsSiteDir}")
2145         def jalviewjsServer = factory.start(doc_root, port)
2146         running = true
2147         url = jalviewjsServer.getResourceUrl(jalviewjs_server_resource)
2148         urlcore = jalviewjsServer.getResourceUrl(jalviewjsJalviewCoreHtmlFile)
2149         println("SERVER STARTED with document root ${doc_root}.")
2150         println("Go to "+url+" . Run  gradle --stop  to stop (kills all gradle daemons).")
2151         println("For debug: "+url+"?j2sdebug")
2152         println("For core: "+urlcore)
2153
2154         file(htmlFile).text = """
2155         <p><a href="${url}">JalviewJS Test. &lt;${url}&gt;</a></p>
2156         <p><a href="${url}?j2sdebug">JalviewJS Test with debug. &lt;${url}?j2sdebug&lt;</a></p>
2157         <p><a href="${urlcore}">${jalviewjsJalviewTemplateName} Core Test. &lt;${urlcore}&gt;</a></p>
2158         """
2159
2160       } catch (Exception e) {
2161         port++;
2162       }
2163     }
2164
2165   }
2166
2167   outputs.file(htmlFile)
2168   outputs.upToDateWhen({false})
2169 }
2170
2171
2172 task cleanJalviewjsAll {
2173   group "JalviewJS"
2174   description "Delete all configuration and build artifacts to do with JalviewJS build"
2175   dependsOn cleanJalviewjsSite
2176   dependsOn jalviewjsEclipsePaths
2177   
2178   doFirst {
2179     delete "${jalviewDir}/${jalviewjsBuildDir}"
2180     delete "${jalviewDir}/${eclipse_bin_dir}"
2181     if (eclipseWorkspace != null && file(eclipseWorkspace.getAbsolutePath()+"/.metadata").exists()) {
2182       delete file(eclipseWorkspace.getAbsolutePath()+"/.metadata")
2183     }
2184     delete "${jalviewDir}/${jalviewjs_j2s_settings}"
2185   }
2186
2187   outputs.upToDateWhen( { false } )
2188 }
2189
2190
2191
2192 task jalviewjsIDE_CopyTransferSiteJs(type: Copy) {
2193   from "${jalviewDir}/${jalviewjsTransferSiteJsDir}"
2194   into "${jalviewDir}/${jalviewjsSiteDir}"
2195 }
2196
2197
2198 task jalviewjsIDE_j2sFile {
2199   group "00 JalviewJS in Eclipse"
2200   description "Creates the .j2s file"
2201   dependsOn jalviewjsCreateJ2sSettings
2202 }
2203
2204
2205 task jalviewjsIDE_SyncCore {
2206   group "00 JalviewJS in Eclipse"
2207   description "Build the core js lib closures listed in the classlists dir and publish core html from template"
2208   dependsOn jalviewjsSyncCore
2209 }
2210
2211
2212 task jalviewjsIDE_PrepareSite {
2213   group "00 JalviewJS in Eclipse"
2214   description "Sync libs and resources to site dir, but not closure cores"
2215   dependsOn jalviewjsSyncAllLibs
2216   dependsOn jalviewjsSyncResources
2217   dependsOn jalviewjsSyncSiteResources
2218   dependsOn jalviewjsSyncBuildProperties
2219 }
2220
2221
2222 task jalviewjsIDE_AssembleSite {
2223   group "00 JalviewJS in Eclipse"
2224   description "Assembles the Eclipse transpiled site and unzips supporting zipfiles"
2225   dependsOn jalviewjsIDE_CopyTransferSiteJs
2226   dependsOn jalviewjsPrepareSite
2227 }
2228
2229
2230 task jalviewjsIDE_SiteClean {
2231   group "00 JalviewJS in Eclipse"
2232   description "Deletes the Eclipse transpiled site"
2233   dependsOn cleanJalviewjsSite
2234 }
2235
2236
2237 task jalviewjsIDE_Server {
2238   group "00 JalviewJS in Eclipse"
2239   description "Starts a webserver on localhost to test the website"
2240   dependsOn jalviewjsServer
2241 }
2242
2243
2244 // buildship runs this at import
2245 task eclipseSynchronizationTask {
2246   dependsOn eclipseSetup
2247   dependsOn jalviewjsIDE_j2sFile
2248 }
2249
2250
2251 // buildship runs this at build time
2252 task eclipseAutoBuildTask {
2253   dependsOn jalviewjsIDE_PrepareSite
2254 }
2255
2256
2257
2258
2259
2260
2261
2262
2263 task jalviewjs {
2264   group "JalviewJS"
2265   description "Build the site"
2266   dependsOn jalviewjsBuildSite
2267 }