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