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