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