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