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