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