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