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