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