JAL-3210 Possibly fixed eclipse_workspace_location disappearances, again
[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   def writeProps = true
1425   if (( eclipseWsDir == null || !file(eclipseWsDir).exists() ) && propsFile.exists()) {
1426     def ins = new FileInputStream(propsFileName)
1427     props.load(ins)
1428     ins.close()
1429     if (props.getProperty(propKey, null) != null) {
1430       eclipseWsDir = props.getProperty(propKey)
1431       writeProps = false
1432     }
1433   }
1434
1435   if (eclipseWsDir == null || !file(eclipseWsDir).exists()) {
1436     def tempDir = File.createTempDir()
1437     eclipseWsDir = tempDir.getAbsolutePath()
1438     writeProps = true
1439   }
1440   eclipseWorkspace = file(eclipseWsDir)
1441
1442   doFirst {
1443     // do not run a headless transpile when we claim to be in Eclipse
1444     if (IN_ECLIPSE) {
1445       println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
1446       throw new StopExecutionException("Not running headless transpile whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
1447     } else {
1448       println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
1449     }
1450
1451     if (writeProps) {
1452       props.setProperty(propKey, eclipseWsDir)
1453       propsFile.parentFile.mkdirs()
1454       def bytes = new ByteArrayOutputStream()
1455       props.store(bytes, null)
1456       def propertiesString = bytes.toString()
1457       propsFile.text = propertiesString
1458       print("NEW ")
1459     } else {
1460       print("EXISTING ")
1461     }
1462
1463     println("ECLIPSE WORKSPACE: "+eclipseWorkspace.getPath())
1464   }
1465
1466   //inputs.property(propKey, eclipseWsDir) // eclipseWsDir only gets set once this task runs, so will be out-of-date
1467   outputs.file(propsFileName)
1468   outputs.upToDateWhen { eclipseWorkspace.exists() && propsFile.exists() }
1469 }
1470
1471
1472 task jalviewjsEclipsePaths {
1473   def eclipseProduct
1474
1475   def eclipseRoot = jalviewjs_eclipse_root
1476   if (eclipseRoot.startsWith("~/")) {
1477     eclipseRoot = System.getProperty("user.home") + eclipseRoot.substring(1)
1478   }
1479   if (OperatingSystem.current().isMacOsX()) {
1480     eclipseRoot += "/Eclipse.app"
1481     eclipseBinary = "${eclipseRoot}/Contents/MacOS/eclipse"
1482     eclipseProduct = "${eclipseRoot}/Contents/Eclipse/.eclipseproduct"
1483   } else if (OperatingSystem.current().isWindows()) { // check these paths!!
1484     if (file("${eclipseRoot}/eclipse").isDirectory() && file("${eclipseRoot}/eclipse/.eclipseproduct").exists()) {
1485       eclipseRoot += "/eclipse.exe"
1486     }
1487     eclipseBinary = "${eclipseRoot}/eclipse"
1488     eclipseProduct = "${eclipseRoot}/.eclipseproduct"
1489   } else { // linux or unix
1490     if (file("${eclipseRoot}/eclipse").isDirectory() && file("${eclipseRoot}/eclipse/.eclipseproduct").exists()) {
1491       eclipseRoot += "/eclipse"
1492     }
1493     eclipseBinary = "${eclipseRoot}/eclipse"
1494     eclipseProduct = "${eclipseRoot}/.eclipseproduct"
1495   }
1496
1497   eclipseVersion = "4.13" // default
1498   def assumedVersion = true
1499   if (file(eclipseProduct).exists()) {
1500     def fis = new FileInputStream(eclipseProduct)
1501     def props = new Properties()
1502     props.load(fis)
1503     eclipseVersion = props.getProperty("version")
1504     fis.close()
1505     assumedVersion = false
1506   }
1507   
1508   def propKey = "eclipse_debug"
1509   eclipseDebug = (project.hasProperty(propKey) && project.getProperty(propKey).equals("true"))
1510
1511   doFirst {
1512     // do not run a headless transpile when we claim to be in Eclipse
1513     if (IN_ECLIPSE) {
1514       println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
1515       throw new StopExecutionException("Not running headless transpile whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
1516     } else {
1517       println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
1518     }
1519
1520     if (!assumedVersion) {
1521       println("ECLIPSE VERSION=${eclipseVersion}")
1522     }
1523   }
1524 }
1525
1526
1527 task eclipseSetup {
1528   dependsOn eclipseProject
1529   dependsOn eclipseClasspath
1530   dependsOn eclipseJdt
1531 }
1532
1533
1534 // this version (type: Copy) will delete anything in the eclipse dropins folder that isn't in fromDropinsDir
1535 task jalviewjsEclipseCopyDropins(type: Copy) {
1536   dependsOn jalviewjsEclipsePaths
1537
1538   def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjs_eclipse_dropins_dir}", include: "*.jar")
1539   inputFiles += file("${jalviewDir}/${jalviewjs_j2s_plugin}")
1540   def outputDir = "${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_eclipse_tmp_dropins_dir}"
1541
1542   from inputFiles
1543   into outputDir
1544 }
1545
1546
1547 // this eclipse -clean doesn't actually work
1548 task jalviewjsCleanEclipse(type: Exec) {
1549   dependsOn eclipseSetup
1550   dependsOn jalviewjsEclipsePaths
1551   dependsOn jalviewjsEclipseCopyDropins
1552
1553   executable(eclipseBinary)
1554   args(["-nosplash", "--launcher.suppressErrors", "-data", eclipseWorkspace.getPath(), "-clean", "-console", "-consoleLog"])
1555   if (eclipseDebug) {
1556     args += "-debug"
1557   }
1558   args += "-l"
1559
1560   def inputString = """exit
1561 y
1562 """
1563   def inputByteStream = new ByteArrayInputStream(inputString.getBytes())
1564   standardInput = inputByteStream
1565 }
1566
1567 /* not really working yet
1568 jalviewjsEclipseCopyDropins.finalizedBy jalviewjsCleanEclipse
1569 */
1570
1571
1572 task jalviewjsTransferUnzipSwingJs {
1573   def file_zip = "${jalviewDir}/${jalviewjs_swingjs_zip}"
1574
1575   doLast {
1576     copy {
1577       from zipTree(file_zip)
1578       into "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}"
1579     }
1580   }
1581
1582   inputs.file file_zip
1583   outputs.dir "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}"
1584 }
1585
1586
1587 task jalviewjsTransferUnzipLib {
1588   def zipFiles = fileTree(dir: "${jalviewDir}/${jalviewjs_libjs_dir}", include: "*.zip")
1589
1590   doLast {
1591     zipFiles.each { file_zip -> 
1592       copy {
1593         from zipTree(file_zip)
1594         into "${jalviewDir}/${jalviewjsTransferSiteLibDir}"
1595       }
1596     }
1597   }
1598
1599   inputs.files zipFiles
1600   outputs.dir "${jalviewDir}/${jalviewjsTransferSiteLibDir}"
1601 }
1602
1603
1604 task jalviewjsTransferUnzipAllLibs {
1605   dependsOn jalviewjsTransferUnzipSwingJs
1606   dependsOn jalviewjsTransferUnzipLib
1607 }
1608
1609
1610 task jalviewjsCreateJ2sSettings(type: WriteProperties) {
1611   group "JalviewJS"
1612   description "Create the .j2s file from the j2s.* properties"
1613
1614   jalviewjsJ2sProps = project.properties.findAll { it.key.startsWith("j2s.") }.sort { it.key }
1615   def siteDirProperty = "j2s.site.directory"
1616   def setSiteDir = false
1617   jalviewjsJ2sProps.each { prop, val ->
1618     if (val != null) {
1619       if (prop == siteDirProperty) {
1620         if (!(val.startsWith('/') || val.startsWith("file://") )) {
1621           val = "${jalviewDir}/${jalviewjsTransferSiteJsDir}/${val}"
1622         }
1623         setSiteDir = true
1624       }
1625       property(prop,val)
1626     }
1627     if (!setSiteDir) { // default site location, don't override specifically set property
1628       property(siteDirProperty,"${jalviewDirRelativePath}/${jalviewjsTransferSiteJsDir}")
1629     }
1630   }
1631   outputFile = jalviewjsJ2sSettingsFileName
1632
1633   if (! IN_ECLIPSE) {
1634     inputs.properties(jalviewjsJ2sProps)
1635     outputs.file(jalviewjsJ2sSettingsFileName)
1636   }
1637 }
1638
1639
1640 task jalviewjsEclipseSetup {
1641   dependsOn jalviewjsEclipseCopyDropins
1642   dependsOn jalviewjsSetEclipseWorkspace
1643   dependsOn jalviewjsCreateJ2sSettings
1644 }
1645
1646
1647 task jalviewjsSyncAllLibs (type: Sync) {
1648   dependsOn jalviewjsTransferUnzipAllLibs
1649   def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjsTransferSiteLibDir}")
1650   inputFiles += fileTree(dir: "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}")
1651   def outputDir = "${jalviewDir}/${jalviewjsSiteDir}"
1652
1653   from inputFiles
1654   into outputDir
1655   def outputFiles = []
1656   rename { filename ->
1657     outputFiles += "${outputDir}/${filename}"
1658     null
1659   }
1660   preserve {
1661     include "**"
1662   }
1663   outputs.files outputFiles
1664   inputs.files inputFiles
1665 }
1666
1667
1668 task jalviewjsSyncResources (type: Sync) {
1669   def inputFiles = fileTree(dir: resourceDir)
1670   def outputDir = "${jalviewDir}/${jalviewjsSiteDir}/${jalviewjs_j2s_subdir}"
1671
1672   from inputFiles
1673   into outputDir
1674   def outputFiles = []
1675   rename { filename ->
1676     outputFiles += "${outputDir}/${filename}"
1677     null
1678   }
1679   preserve {
1680     include "**"
1681   }
1682   outputs.files outputFiles
1683   inputs.files inputFiles
1684 }
1685
1686
1687 task jalviewjsSyncSiteResources (type: Sync) {
1688   def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjs_site_resource_dir}")
1689   def outputDir = "${jalviewDir}/${jalviewjsSiteDir}"
1690
1691   from inputFiles
1692   into outputDir
1693   def outputFiles = []
1694   rename { filename ->
1695     outputFiles += "${outputDir}/${filename}"
1696     null
1697   }
1698   preserve {
1699     include "**"
1700   }
1701   outputs.files outputFiles
1702   inputs.files inputFiles
1703 }
1704
1705
1706 task jalviewjsSyncBuildProperties (type: Sync) {
1707   dependsOn createBuildProperties
1708   def inputFiles = [file(buildProperties)]
1709   def outputDir = "${jalviewDir}/${jalviewjsSiteDir}/${jalviewjs_j2s_subdir}"
1710
1711   from inputFiles
1712   into outputDir
1713   def outputFiles = []
1714   rename { filename ->
1715     outputFiles += "${outputDir}/${filename}"
1716     null
1717   }
1718   preserve {
1719     include "**"
1720   }
1721   outputs.files outputFiles
1722   inputs.files inputFiles
1723 }
1724
1725
1726 task jalviewjsProjectImport(type: Exec) {
1727   dependsOn eclipseSetup
1728   dependsOn jalviewjsEclipsePaths
1729   dependsOn jalviewjsEclipseSetup
1730
1731   doFirst {
1732     // do not run a headless import when we claim to be in Eclipse
1733     if (IN_ECLIPSE) {
1734       println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
1735       throw new StopExecutionException("Not running headless import whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
1736     } else {
1737       println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
1738     }
1739   }
1740
1741   //def projdir = eclipseWorkspace.getPath()+"/.metadata/.plugins/org.eclipse.core.resources/.projects/jalview/org.eclipse.jdt.core"
1742   def projdir = eclipseWorkspace.getPath()+"/.metadata/.plugins/org.eclipse.core.resources/.projects/jalview"
1743   executable(eclipseBinary)
1744   args(["-nosplash", "--launcher.suppressErrors", "-application", "com.seeq.eclipse.importprojects.headlessimport", "-data", eclipseWorkspace.getPath(), "-import", jalviewDirAbsolutePath])
1745   if (eclipseDebug) {
1746     args += "-debug"
1747   }
1748   args += [ "--launcher.appendVmargs", "-vmargs", "-Dorg.eclipse.equinox.p2.reconciler.dropins.directory=${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_eclipse_tmp_dropins_dir}" ]
1749   if (!IN_ECLIPSE) {
1750     args += [ "-D${j2sHeadlessBuildProperty}=true" ]
1751   }
1752
1753   inputs.file("${jalviewDir}/.project")
1754   outputs.upToDateWhen { 
1755     file(projdir).exists()
1756   }
1757 }
1758
1759
1760 task jalviewjsTranspile(type: Exec) {
1761   dependsOn jalviewjsEclipseSetup 
1762   dependsOn jalviewjsProjectImport
1763   dependsOn jalviewjsEclipsePaths
1764
1765   doFirst {
1766     // do not run a headless transpile when we claim to be in Eclipse
1767     if (IN_ECLIPSE) {
1768       println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
1769       throw new StopExecutionException("Not running headless transpile whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
1770     } else {
1771       println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
1772     }
1773   }
1774
1775   executable(eclipseBinary)
1776   args(["-nosplash", "--launcher.suppressErrors", "-application", "org.eclipse.jdt.apt.core.aptBuild", "-data", eclipseWorkspace, "-${jalviewjs_eclipse_build_arg}", eclipse_project_name ])
1777   if (eclipseDebug) {
1778     args += "-debug"
1779   }
1780   args += [ "--launcher.appendVmargs", "-vmargs", "-Dorg.eclipse.equinox.p2.reconciler.dropins.directory=${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_eclipse_tmp_dropins_dir}" ]
1781   if (!IN_ECLIPSE) {
1782     args += [ "-D${j2sHeadlessBuildProperty}=true" ]
1783   }
1784
1785   def stdout
1786   def stderr
1787   doFirst {
1788     stdout = new ByteArrayOutputStream()
1789     stderr = new ByteArrayOutputStream()
1790
1791     def logOutFileName = "${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}"
1792     def logOutFile = file(logOutFileName)
1793     logOutFile.createNewFile()
1794     logOutFile.text = """ROOT: ${jalviewjs_eclipse_root}
1795 BINARY: ${eclipseBinary}
1796 VERSION: ${eclipseVersion}
1797 WORKSPACE: ${eclipseWorkspace}
1798 DEBUG: ${eclipseDebug}
1799 ----
1800 """
1801     def logOutFOS = new FileOutputStream(logOutFile, true) // true == append
1802     // combine stdout and stderr
1803     def logErrFOS = logOutFOS
1804
1805     if (jalviewjs_j2s_to_console.equals("true")) {
1806       standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
1807         new org.apache.tools.ant.util.TeeOutputStream(
1808           logOutFOS,
1809           stdout),
1810         standardOutput)
1811       errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
1812         new org.apache.tools.ant.util.TeeOutputStream(
1813           logErrFOS,
1814           stderr),
1815         errorOutput)
1816     } else {
1817       standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
1818         logOutFOS,
1819         stdout)
1820       errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
1821         logErrFOS,
1822         stderr)
1823     }
1824   }
1825
1826   doLast {
1827     if (stdout.toString().contains("Error processing ")) {
1828       // j2s did not complete transpile
1829       //throw new TaskExecutionException("Error during transpilation:\n${stderr}\nSee eclipse transpile log file '${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}'")
1830       throw new GradleException("Error during transpilation:\n${stderr}\nSee eclipse transpile log file '${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}'")
1831     }
1832   }
1833
1834   inputs.dir("${jalviewDir}/${sourceDir}")
1835   outputs.dir("${jalviewDir}/${jalviewjsTransferSiteJsDir}")
1836   outputs.upToDateWhen( { file("${jalviewDir}/${jalviewjsTransferSiteJsDir}${jalviewjs_server_resource}").exists() } )
1837 }
1838
1839
1840 def jalviewjsCallCore(String name, FileCollection list, String prefixFile, String suffixFile, String jsfile, String zjsfile, File logOutFile, Boolean logOutConsole) {
1841
1842   def stdout = new ByteArrayOutputStream()
1843   def stderr = new ByteArrayOutputStream()
1844
1845   def coreFile = file(jsfile)
1846   def msg = ""
1847   msg = "Creating core for ${name}...\nGenerating ${jsfile}"
1848   println(msg)
1849   logOutFile.createNewFile()
1850   logOutFile.append(msg+"\n")
1851
1852   def coreTop = file(prefixFile)
1853   def coreBottom = file(suffixFile)
1854   coreFile.getParentFile().mkdirs()
1855   coreFile.createNewFile()
1856   coreFile.write( coreTop.text )
1857   list.each {
1858     f ->
1859     if (f.exists()) {
1860       def t = f.text
1861       t.replaceAll("Clazz\\.([^_])","Clazz_${1}")
1862       coreFile.append( t )
1863     } else {
1864       msg = "...file '"+f.getPath()+"' does not exist, skipping"
1865       println(msg)
1866       logOutFile.append(msg+"\n")
1867     }
1868   }
1869   coreFile.append( coreBottom.text )
1870
1871   msg = "Generating ${zjsfile}"
1872   println(msg)
1873   logOutFile.append(msg+"\n")
1874   def logOutFOS = new FileOutputStream(logOutFile, true) // true == append
1875   def logErrFOS = logOutFOS
1876
1877   javaexec {
1878     classpath = files(["${jalviewDir}/tools/closure_compiler.jar"])
1879     args = [ "--js", jsfile, "--js_output_file", zjsfile ]
1880
1881     msg = "\nRunning '"+commandLine.join(' ')+"'\n"
1882     println(msg)
1883     logOutFile.append(msg+"\n")
1884
1885     if (logOutConsole) {
1886       standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
1887         new org.apache.tools.ant.util.TeeOutputStream(
1888           logOutFOS,
1889           stdout),
1890         standardOutput)
1891         errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
1892           new org.apache.tools.ant.util.TeeOutputStream(
1893             logErrFOS,
1894             stderr),
1895           errorOutput)
1896     } else {
1897       standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
1898         logOutFOS,
1899         stdout)
1900         errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
1901           logErrFOS,
1902           stderr)
1903     }
1904   }
1905   msg = "--"
1906   println(msg)
1907   logOutFile.append(msg+"\n")
1908 }
1909
1910
1911 task jalviewjsBuildAllCores {
1912   group "JalviewJS"
1913   description "Build the core js lib closures listed in the classlists dir"
1914   dependsOn jalviewjsTranspile
1915   dependsOn jalviewjsTransferUnzipSwingJs
1916
1917   def j2sDir = "${jalviewDir}/${jalviewjsTransferSiteJsDir}/${jalviewjs_j2s_subdir}"
1918   def swingJ2sDir = "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}/${jalviewjs_j2s_subdir}"
1919   def libJ2sDir = "${jalviewDir}/${jalviewjsTransferSiteLibDir}/${jalviewjs_j2s_subdir}"
1920   def jsDir = "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}/${jalviewjs_js_subdir}"
1921   def outputDir = "${jalviewDir}/${jalviewjsTransferSiteCoreDir}/${jalviewjs_j2s_subdir}/core"
1922   def prefixFile = "${jsDir}/core/coretop2.js"
1923   def suffixFile = "${jsDir}/core/corebottom2.js"
1924
1925   inputs.file prefixFile
1926   inputs.file suffixFile
1927
1928   def classlistFiles = []
1929   // add the classlists found int the jalviewjs_classlists_dir
1930   fileTree(dir: "${jalviewDir}/${jalviewjs_classlists_dir}", include: "*.txt").each {
1931     file ->
1932     def name = file.getName() - ".txt"
1933     classlistFiles += [
1934       'file': file,
1935       'name': name
1936     ]
1937   }
1938
1939   // _jmol and _jalview cores. Add any other peculiar classlist.txt files here
1940   //classlistFiles += [ 'file': file("${jalviewDir}/${jalviewjs_classlist_jmol}"), 'name': "_jvjmol" ]
1941   classlistFiles += [ 'file': file("${jalviewDir}/${jalviewjs_classlist_jalview}"), 'name': jalviewjsJalviewCoreName ]
1942
1943   jalviewjsCoreClasslists = []
1944
1945   classlistFiles.each {
1946     hash ->
1947
1948     def file = hash['file']
1949     if (! file.exists()) {
1950       println("...classlist file '"+file.getPath()+"' does not exist, skipping")
1951       return false // this is a "continue" in groovy .each closure
1952     }
1953     def name = hash['name']
1954     if (name == null) {
1955       name = file.getName() - ".txt"
1956     }
1957
1958     def filelist = []
1959     file.eachLine {
1960       line ->
1961         filelist += line
1962     }
1963     def list = fileTree(dir: j2sDir, includes: filelist)
1964
1965     def jsfile = "${outputDir}/core${name}.js"
1966     def zjsfile = "${outputDir}/core${name}.z.js"
1967
1968     jalviewjsCoreClasslists += [
1969       'jsfile': jsfile,
1970       'zjsfile': zjsfile,
1971       'list': list,
1972       'name': name
1973     ]
1974
1975     inputs.file(file)
1976     inputs.files(list)
1977     outputs.file(jsfile)
1978     outputs.file(zjsfile)
1979   }
1980   
1981   // _stevesoft core. add any cores without a classlist here (and the inputs and outputs)
1982   def stevesoftClasslistName = "_stevesoft"
1983   def stevesoftClasslist = [
1984     'jsfile': "${outputDir}/core${stevesoftClasslistName}.js",
1985     'zjsfile': "${outputDir}/core${stevesoftClasslistName}.z.js",
1986     'list': fileTree(dir: j2sDir, include: "com/stevesoft/pat/**/*.js"),
1987     'name': stevesoftClasslistName
1988   ]
1989   jalviewjsCoreClasslists += stevesoftClasslist
1990   inputs.files(stevesoftClasslist['list'])
1991   outputs.file(stevesoftClasslist['jsfile'])
1992   outputs.file(stevesoftClasslist['zjsfile'])
1993
1994   // _all core
1995   def allClasslistName = "_all"
1996   def allJsFiles = fileTree(dir: j2sDir, include: "**/*.js")
1997   allJsFiles += fileTree(
1998     dir: libJ2sDir,
1999     include: "**/*.js",
2000     excludes: [
2001       // these exlusions are files that the closure-compiler produces errors for. Should fix them
2002       "**/org/jmol/jvxl/readers/IsoIntersectFileReader.js",
2003       "**/org/jmol/export/JSExporter.js"
2004     ]
2005   )
2006   allJsFiles += fileTree(
2007     dir: swingJ2sDir,
2008     include: "**/*.js",
2009     excludes: [
2010       // these exlusions are files that the closure-compiler produces errors for. Should fix them
2011       "**/sun/misc/Unsafe.js",
2012       "**/swingjs/jquery/jquery-editable-select.js",
2013       "**/swingjs/jquery/j2sComboBox.js",
2014       "**/sun/misc/FloatingDecimal.js"
2015     ]
2016   )
2017   def allClasslist = [
2018     'jsfile': "${outputDir}/core${allClasslistName}.js",
2019     'zjsfile': "${outputDir}/core${allClasslistName}.z.js",
2020     'list': allJsFiles,
2021     'name': allClasslistName
2022   ]
2023   jalviewjsCoreClasslists += allClasslist
2024   inputs.files(allClasslist['list'])
2025   outputs.file(allClasslist['jsfile'])
2026   outputs.file(allClasslist['zjsfile'])
2027
2028   doFirst {
2029     def logOutFile = file("${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_j2s_closure_stdout}")
2030     logOutFile.getParentFile().mkdirs()
2031     logOutFile.createNewFile()
2032     logOutFile.write(getDate("yyyy-MM-dd HH:mm:ss")+" jalviewjsBuildAllCores\n----\n")
2033
2034     jalviewjsCoreClasslists.each {
2035       jalviewjsCallCore(it.name, it.list, prefixFile, suffixFile, it.jsfile, it.zjsfile, logOutFile, jalviewjs_j2s_to_console.equals("true"))
2036     }
2037   }
2038
2039 }
2040
2041
2042 def jalviewjsPublishCoreTemplate(String coreName, String templateName, File inputFile, String outputFile) {
2043   copy {
2044     from inputFile
2045     into file(outputFile).getParentFile()
2046     rename { filename ->
2047       if (filename.equals(inputFile.getName())) {
2048         return file(outputFile).getName()
2049       }
2050       return null
2051     }
2052     filter(ReplaceTokens,
2053       beginToken: '_',
2054       endToken: '_',
2055       tokens: [
2056         'MAIN': '"'+mainClass+'"',
2057         'CODE': "null",
2058         'NAME': jalviewjsJalviewTemplateName+" [core ${coreName}]",
2059         'COREKEY': jalviewjs_core_key,
2060         'CORENAME': coreName
2061       ]
2062     )
2063   }
2064 }
2065
2066
2067 task jalviewjsPublishCoreTemplates {
2068   dependsOn jalviewjsBuildAllCores
2069   def inputFileName = "${jalviewDir}/${j2s_coretemplate_html}"
2070   def inputFile = file(inputFileName)
2071   def outputDir = "${jalviewDir}/${jalviewjsTransferSiteCoreDir}"
2072
2073   def outputFiles = []
2074   jalviewjsCoreClasslists.each { cl ->
2075     def outputFile = "${outputDir}/${jalviewjsJalviewTemplateName}_${cl.name}.html"
2076     cl['outputfile'] = outputFile
2077     outputFiles += outputFile
2078   }
2079
2080   doFirst {
2081     jalviewjsCoreClasslists.each { cl ->
2082       jalviewjsPublishCoreTemplate(cl.name, jalviewjsJalviewTemplateName, inputFile, cl.outputfile)
2083     }
2084   }
2085   inputs.file(inputFile)
2086   outputs.files(outputFiles)
2087 }
2088
2089
2090 task jalviewjsSyncCore (type: Sync) {
2091   dependsOn jalviewjsBuildAllCores
2092   dependsOn jalviewjsPublishCoreTemplates
2093   def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjsTransferSiteCoreDir}")
2094   def outputDir = "${jalviewDir}/${jalviewjsSiteDir}"
2095
2096   from inputFiles
2097   into outputDir
2098   def outputFiles = []
2099   rename { filename ->
2100     outputFiles += "${outputDir}/${filename}"
2101     null
2102   }
2103   preserve {
2104     include "**"
2105   }
2106   outputs.files outputFiles
2107   inputs.files inputFiles
2108 }
2109
2110
2111 // this Copy version of TransferSiteJs will delete anything else in the target dir
2112 task jalviewjsCopyTransferSiteJs(type: Copy) {
2113   dependsOn jalviewjsTranspile
2114   from "${jalviewDir}/${jalviewjsTransferSiteJsDir}"
2115   into "${jalviewDir}/${jalviewjsSiteDir}"
2116 }
2117
2118
2119 // this Sync version of TransferSite is used by buildship to keep the website automatically up to date when a file changes
2120 task jalviewjsSyncTransferSiteJs(type: Sync) {
2121   from "${jalviewDir}/${jalviewjsTransferSiteJsDir}"
2122   include "**/*.*"
2123   into "${jalviewDir}/${jalviewjsSiteDir}"
2124   preserve {
2125     include "**"
2126   }
2127 }
2128
2129
2130 jalviewjsSyncAllLibs.mustRunAfter jalviewjsCopyTransferSiteJs
2131 jalviewjsSyncResources.mustRunAfter jalviewjsCopyTransferSiteJs
2132 jalviewjsSyncSiteResources.mustRunAfter jalviewjsCopyTransferSiteJs
2133 jalviewjsSyncBuildProperties.mustRunAfter jalviewjsCopyTransferSiteJs
2134
2135 jalviewjsSyncAllLibs.mustRunAfter jalviewjsSyncTransferSiteJs
2136 jalviewjsSyncResources.mustRunAfter jalviewjsSyncTransferSiteJs
2137 jalviewjsSyncSiteResources.mustRunAfter jalviewjsSyncTransferSiteJs
2138 jalviewjsSyncBuildProperties.mustRunAfter jalviewjsSyncTransferSiteJs
2139
2140
2141 task jalviewjsPrepareSite {
2142   group "JalviewJS"
2143   description "Prepares the website folder including unzipping files and copying resources"
2144   dependsOn jalviewjsSyncAllLibs
2145   dependsOn jalviewjsSyncResources
2146   dependsOn jalviewjsSyncSiteResources
2147   dependsOn jalviewjsSyncBuildProperties
2148   dependsOn jalviewjsSyncCore
2149 }
2150
2151
2152 task jalviewjsBuildSite {
2153   group "JalviewJS"
2154   description "Builds the whole website including transpiled code"
2155   dependsOn jalviewjsCopyTransferSiteJs
2156   dependsOn jalviewjsPrepareSite
2157 }
2158
2159
2160 task cleanJalviewjsSite {
2161   doFirst {
2162     delete "${jalviewDir}/${jalviewjsTransferSiteJsDir}"
2163     delete "${jalviewDir}/${jalviewjsTransferSiteLibDir}"
2164     delete "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}"
2165     delete "${jalviewDir}/${jalviewjsTransferSiteCoreDir}"
2166     delete "${jalviewDir}/${jalviewjsSiteDir}"
2167   }
2168 }
2169
2170
2171 task jalviewjsSiteTar(type: Tar) {
2172   group "JalviewJS"
2173   description "Creates a tar.gz file for the website"
2174   dependsOn jalviewjsBuildSite
2175   def outputFilename = "jalviewjs-site-${JALVIEW_VERSION}.tar.gz"
2176   try {
2177     archiveFileName = outputFilename
2178   } catch (Exception e) {
2179     archiveName = outputFilename
2180   }
2181
2182   compression Compression.GZIP
2183
2184   from "${jalviewDir}/${jalviewjsSiteDir}"
2185   into jalviewjs_site_dir // this is inside the tar file
2186
2187   inputs.dir("${jalviewDir}/${jalviewjsSiteDir}")
2188 }
2189
2190
2191 task jalviewjsServer {
2192   group "JalviewJS"
2193   def filename = "jalviewjsTest.html"
2194   description "Starts a webserver on localhost to test the website. See ${filename} to access local site on most recently used port."
2195   def htmlFile = "${jalviewDirAbsolutePath}/${filename}"
2196   doLast {
2197
2198     SimpleHttpFileServerFactory factory = new SimpleHttpFileServerFactory()
2199     def port = Integer.valueOf(jalviewjs_server_port)
2200     def start = port
2201     def running = false
2202     def url
2203     def jalviewjsServer
2204     while(port < start+1000 && !running) {
2205       try {
2206         def doc_root = new File("${jalviewDirAbsolutePath}/${jalviewjsSiteDir}")
2207         jalviewjsServer = factory.start(doc_root, port)
2208         running = true
2209         url = jalviewjsServer.getResourceUrl(jalviewjs_server_resource)
2210         println("SERVER STARTED with document root ${doc_root}.")
2211         println("Go to "+url+" . Run  gradle --stop  to stop (kills all gradle daemons).")
2212         println("For debug: "+url+"?j2sdebug")
2213         println("For verbose: "+url+"?j2sverbose")
2214       } catch (Exception e) {
2215         port++;
2216       }
2217     }
2218     def htmlText = """
2219       <p><a href="${url}">JalviewJS Test. &lt;${url}&gt;</a></p>
2220       <p><a href="${url}?j2sdebug">JalviewJS Test with debug. &lt;${url}?j2sdebug&gt;</a></p>
2221       <p><a href="${url}?j2sverbose">JalviewJS Test with verbose. &lt;${url}?j2sdebug&gt;</a></p>
2222       """
2223     jalviewjsCoreClasslists.each { cl ->
2224       def urlcore = jalviewjsServer.getResourceUrl(file(cl.outputfile).getName())
2225       htmlText += """
2226       <p><a href="${urlcore}">${jalviewjsJalviewTemplateName} [core ${cl.name}]. &lt;${urlcore}&gt;</a></p>
2227       """
2228       println("For core ${cl.name}: "+urlcore)
2229     }
2230
2231     file(htmlFile).text = htmlText
2232   }
2233
2234   outputs.file(htmlFile)
2235   outputs.upToDateWhen({false})
2236 }
2237
2238
2239 task cleanJalviewjsAll {
2240   group "JalviewJS"
2241   description "Delete all configuration and build artifacts to do with JalviewJS build"
2242   dependsOn cleanJalviewjsSite
2243   dependsOn jalviewjsEclipsePaths
2244   
2245   doFirst {
2246     delete "${jalviewDir}/${jalviewjsBuildDir}"
2247     delete "${jalviewDir}/${eclipse_bin_dir}"
2248     if (eclipseWorkspace != null && file(eclipseWorkspace.getAbsolutePath()+"/.metadata").exists()) {
2249       delete file(eclipseWorkspace.getAbsolutePath()+"/.metadata")
2250     }
2251     delete "${jalviewDir}/${jalviewjs_j2s_settings}"
2252   }
2253
2254   outputs.upToDateWhen( { false } )
2255 }
2256
2257
2258
2259 task jalviewjsIDE_j2sFile {
2260   group "00 JalviewJS in Eclipse"
2261   description "Creates the .j2s file"
2262   dependsOn jalviewjsCreateJ2sSettings
2263 }
2264
2265
2266 task jalviewjsIDE_SyncCore {
2267   group "00 JalviewJS in Eclipse"
2268   description "Build the core js lib closures listed in the classlists dir and publish core html from template"
2269   dependsOn jalviewjsSyncCore
2270 }
2271
2272
2273 task jalviewjsIDE_PrepareSite {
2274   group "00 JalviewJS in Eclipse"
2275   description "Sync libs and resources to site dir, but not closure cores"
2276   dependsOn jalviewjsSyncAllLibs
2277   dependsOn jalviewjsSyncResources
2278   dependsOn jalviewjsSyncSiteResources
2279   dependsOn jalviewjsSyncBuildProperties
2280 }
2281
2282
2283 task jalviewjsIDE_AssembleSite {
2284   group "00 JalviewJS in Eclipse"
2285   description "Assembles unzipped supporting zipfiles, resources, site resources and closure cores into the Eclipse transpiled site"
2286   dependsOn jalviewjsPrepareSite
2287 }
2288
2289
2290 task jalviewjsIDE_SiteClean {
2291   group "00 JalviewJS in Eclipse"
2292   description "Deletes the Eclipse transpiled site"
2293   dependsOn cleanJalviewjsSite
2294 }
2295
2296
2297 task jalviewjsIDE_Server {
2298   group "00 JalviewJS in Eclipse"
2299   description "Starts a webserver on localhost to test the website"
2300   dependsOn jalviewjsServer
2301 }
2302
2303
2304 // buildship runs this at import
2305 task eclipseSynchronizationTask {
2306   //dependsOn eclipseSetup
2307   dependsOn jalviewjsIDE_j2sFile
2308 }
2309
2310
2311 // buildship runs this at build time
2312 task eclipseAutoBuildTask {
2313   dependsOn jalviewjsIDE_PrepareSite
2314 }
2315
2316
2317
2318
2319
2320
2321
2322
2323 task jalviewjs {
2324   group "JalviewJS"
2325   description "Build the site"
2326   dependsOn jalviewjsBuildSite
2327 }