0c2448ced91f3ed75807dddb831f1f81634b0725
[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 repositories {
23   jcenter()
24   mavenCentral()
25   mavenLocal()
26   flatDir {
27     dirs gradlePluginsDir
28   }
29 }
30
31 dependencies {
32   compile 'org.apache.commons:commons-compress:1.18'
33 }
34
35 mainClassName = launcherClass
36 def cloverInstrDir = file("$buildDir/$cloverSourcesInstrDir")
37 def classes = "$jalviewDir/$classesDir"
38
39 if (clover.equals("true")) {
40   use_clover = true
41   classes = "$buildDir/$cloverClassesDir"
42 } else {
43   use_clover = false
44   classes = "$jalviewDir/$classesDir"
45 }
46
47 // configure classpath/args for j8/j11 compilation
48
49 def jalviewDirAbsolutePath = file(jalviewDir).getAbsolutePath()
50 def libDir
51 def libDistDir
52 def compile_source_compatibility
53 def compile_target_compatibility
54
55 ext {
56   getdownWebsiteDir = jalviewDir + '/' + getdown_website_dir + '/' + JAVA_VERSION
57   getdownDir = ""
58   reportRsyncCmd = false
59   buildDist = true
60   buildProperties = buildPropertiesFile
61   getdownLauncher = jalviewDir + '/' + getdown_lib_dir + '/' + getdown_launcher
62   switch (CHANNEL) {
63
64     case "BUILD":
65     // TODO: get bamboo build artifact URL for getdown artifacts
66     getdown_channel_base = bamboo_channelbase
67     getdown_channel_name = bamboo_planKey + '/'+JAVA_VERSION
68     getdown_app_base = bamboo_channelbase + '/'+ bamboo_planKey + bamboo_getdown_channel_suffix + '/'+JAVA_VERSION
69     getdown_app_dir = getdown_app_dir_alt
70     buildProperties = jalviewDir + "/" + classesDir +"/" + buildPropertiesFile
71     break
72
73     case "RELEASE":
74     getdown_channel_name = CHANNEL.toLowerCase()
75     getdownDir = getdown_channel_name + "/" + JAVA_VERSION
76     getdown_app_base = getdown_channel_base + "/" + getdownDir
77     getdown_app_dir = getdown_app_dir_release
78     buildProperties = jalviewDir + "/" + classesDir +"/" + buildPropertiesFile
79     reportRsyncCommand = true
80     break
81
82     case "ARCHIVE":
83     getdown_channel_name = CHANNEL.toLowerCase()+"/"+JALVIEW_VERSION
84     getdownDir = getdown_channel_name + "/" + JAVA_VERSION
85     getdown_app_base = getdown_channel_base + "/" + getdownDir
86     getdown_app_dir = getdown_app_dir_alt
87     if (!file(ARCHIVEDIR+"/"+packageDir).exists()) {
88       print "Must provide an ARCHIVEDIR value to produce an archive distribution"
89       exit
90     } else {
91       packageDir = ARCHIVEDIR + "/" + packageDir
92       buildProperties = ARCHIVEDIR +"/" + classesDir + "/" + buildPropertiesFile
93       buildDist = false
94     }
95     reportRsyncCommand = true
96     break
97
98     case "ARCHIVELOCAL":
99     getdown_channel_name = "archive" + "/" + JALVIEW_VERSION
100     getdownDir = getdown_channel_name + "/" + JAVA_VERSION
101     getdown_app_base = file(getdownWebsiteDir).toURI().toString()
102     getdown_app_dir = getdown_app_dir_alt
103     if (!file(ARCHIVEDIR+"/"+packageDir).exists()) {
104       print "Must provide an ARCHIVEDIR value to produce an archive distribution"
105       exit
106     } else {
107       packageDir = ARCHIVEDIR + "/" + packageDir
108       buildProperties = ARCHIVEDIR +"/" + classesDir + "/" + buildPropertiesFile
109       buildDist = false
110     }
111     reportRsyncCommand = true
112     getdownLauncher = jalviewDir + '/' + getdown_lib_dir + '/' + getdown_launcher_local
113     break
114
115     case "DEVELOP":
116     getdown_channel_name = CHANNEL.toLowerCase()
117     getdownDir = getdown_channel_name + "/" + JAVA_VERSION
118     getdown_app_base = getdown_channel_base + "/" + getdownDir
119     getdown_app_dir = getdown_app_dir_alt
120     buildProperties = jalviewDir + "/" + classesDir +"/" + buildPropertiesFile
121     reportRsyncCommand = true
122     break
123
124     case "TEST-RELEASE":
125     getdown_channel_name = CHANNEL.toLowerCase()
126     getdownDir = getdown_channel_name + "/" + JAVA_VERSION
127     getdown_app_base = getdown_channel_base + "/" + getdownDir
128     getdown_app_dir = getdown_app_dir_alt
129     buildProperties = jalviewDir + "/" + classesDir +"/" + buildPropertiesFile
130     reportRsyncCommand = true
131     break
132
133     case ~/^SCRATCH(|-[-\w]*)$/:
134     getdown_channel_name = CHANNEL
135     getdownDir = getdown_channel_name + "/" + JAVA_VERSION
136     getdown_app_base = getdown_channel_base + "/" + getdownDir
137     getdown_app_dir = getdown_app_dir_alt
138     buildProperties = jalviewDir + "/" + classesDir +"/" + buildPropertiesFile
139     reportRsyncCommand = true
140     break
141
142     case "LOCAL":
143     getdown_app_base = file(getdownWebsiteDir).toURI().toString()
144     getdown_app_dir = getdown_app_dir_alt
145     buildProperties = jalviewDir + "/" + classesDir +"/" + buildPropertiesFile
146     getdownLauncher = jalviewDir + '/' + getdown_lib_dir + '/' + getdown_launcher_local
147     break
148
149     default: // something wrong specified
150     print("CHANNEL must be one of BUILD, RELEASE, ARCHIVE, DEVELOP, TEST-RELEASE, SCRATCH-..., LOCAL [default]")
151     exit
152     break
153
154   }
155
156   println("Using a "+CHANNEL+" profile. appbase="+getdown_app_base)
157   getdownAppDir = getdownWebsiteDir + '/' + getdown_app_dir
158   //getdownJ11libDir = getdownWebsiteDir + '/' + getdown_j11lib_dir
159   getdownResourceDir = getdownWebsiteDir + '/' + getdown_resource_dir
160   getdownInstallDir = getdownWebsiteDir + '/' + getdown_install_dir
161   getdownFilesDir = jalviewDir + '/' + getdown_files_dir + '/' + JAVA_VERSION + '/'
162   getdownFilesInstallDir = getdownFilesDir+"/"+getdown_install_dir
163   /* compile without modules -- using classpath libraries
164   modules_compileClasspath = fileTree(dir: "$jalviewDir/$j11modDir", include: ["*.jar"])
165   modules_runtimeClasspath = modules_compileClasspath
166   */
167   gitHash = ""
168   gitBranch = ""
169
170   jalviewjsServer = ""
171 }
172
173 def JAVA_INTEGER_VERSION
174 def additional_compiler_args = []
175 // these are getdown.txt properties defined dependent on the JAVA_VERSION
176 def getdown_alt_java_min_version
177 def getdown_alt_java_max_version
178 // this property is assigned below and expanded to multiple lines in the getdown task
179 def getdown_alt_multi_java_location
180 // this property is for the Java library used in eclipse
181 def eclipse_java_runtime_name
182 if (JAVA_VERSION.equals("1.8")) {
183   JAVA_INTEGER_VERSION = "8"
184   //libDir = j8libDir
185   libDir = j11libDir
186   libDistDir = j8libDir
187   compile_source_compatibility = 1.8
188   compile_target_compatibility = 1.8
189   getdown_alt_java_min_version = getdown_alt_java8_min_version
190   getdown_alt_java_max_version = getdown_alt_java8_max_version
191   getdown_alt_multi_java_location = getdown_alt_java8_txt_multi_java_location
192   eclipse_java_runtime_name = "JavaSE-1.8"
193 } else if (JAVA_VERSION.equals("11")) {
194   JAVA_INTEGER_VERSION = "11"
195   libDir = j11libDir
196   libDistDir = j11libDir
197   compile_source_compatibility = 11
198   compile_target_compatibility = 11
199   getdown_alt_java_min_version = getdown_alt_java11_min_version
200   getdown_alt_java_max_version = getdown_alt_java11_max_version
201   getdown_alt_multi_java_location = getdown_alt_java11_txt_multi_java_location
202   eclipse_java_runtime_name = "JavaSE-11"
203   /* compile without modules -- using classpath libraries
204   additional_compiler_args += [
205   '--module-path', ext.modules_compileClasspath.asPath,
206   '--add-modules', j11modules
207   ]
208   */
209 } else if (JAVA_VERSION.equals("12") || JAVA_VERSION.equals("13")) {
210   JAVA_INTEGER_VERSION = JAVA_VERSION
211   libDir = j11libDir
212   libDistDir = j11libDir
213   compile_source_compatibility = JAVA_VERSION
214   compile_target_compatibility = JAVA_VERSION
215   getdown_alt_java_min_version = getdown_alt_java11_min_version
216   getdown_alt_java_max_version = getdown_alt_java11_max_version
217   getdown_alt_multi_java_location = getdown_alt_java11_txt_multi_java_location
218   eclipse_java_runtime_name = "JavaSE-11"
219   /* compile without modules -- using classpath libraries
220   additional_compiler_args += [
221   '--module-path', ext.modules_compileClasspath.asPath,
222   '--add-modules', j11modules
223   ]
224   */
225 } else {
226   throw new GradleException("JAVA_VERSION=$JAVA_VERSION not currently supported by Jalview")
227 }
228
229 sourceSets {
230
231   main {
232     java {
233       srcDirs "$jalviewDir/$sourceDir"
234       outputDir = file("$classes")
235     }
236
237     resources {
238       srcDirs "$jalviewDir/$resourceDir"
239     }
240
241     jar.destinationDir = file("$jalviewDir/$packageDir")
242
243     compileClasspath = files(sourceSets.main.java.outputDir)
244     compileClasspath += fileTree(dir: "$jalviewDir/$libDir", include: ["*.jar"])
245
246     runtimeClasspath = compileClasspath
247   }
248
249   clover {
250     java {
251       srcDirs = [ cloverInstrDir ]
252       outputDir = file("${buildDir}/${cloverClassesDir}")
253     }
254
255     resources {
256       srcDirs = sourceSets.main.resources.srcDirs
257     }
258     compileClasspath = configurations.cloverRuntime + files( sourceSets.clover.java.outputDir )
259     compileClasspath += files(sourceSets.main.java.outputDir)
260     compileClasspath += sourceSets.main.compileClasspath
261     compileClasspath += fileTree(dir: "$jalviewDir/$utilsDir", include: ["**/*.jar"])
262     compileClasspath += fileTree(dir: "$jalviewDir/$libDir", include: ["*.jar"])
263
264     runtimeClasspath = compileClasspath
265   }
266
267   test {
268     java {
269       srcDirs "$jalviewDir/$testSourceDir"
270       outputDir = file("$jalviewDir/$testOutputDir")
271     }
272
273     resources {
274       srcDirs = sourceSets.main.resources.srcDirs
275     }
276
277     compileClasspath = files( sourceSets.test.java.outputDir )
278
279     if (use_clover) {
280       compileClasspath += sourceSets.clover.compileClasspath
281     } else {
282       compileClasspath += files(sourceSets.main.java.outputDir)
283     }
284
285     compileClasspath += fileTree(dir: "$jalviewDir/$libDir", include: ["*.jar"])
286     compileClasspath += fileTree(dir: "$jalviewDir/$utilsDir/testnglibs", include: ["**/*.jar"])
287     compileClasspath += fileTree(dir: "$jalviewDir/$utilsDir/testlibs", include: ["**/*.jar"])
288
289     runtimeClasspath = compileClasspath
290   }
291 }
292
293 // clover bits
294 dependencies {
295   if (use_clover) {
296     cloverCompile 'org.openclover:clover:4.3.1'
297     testCompile 'org.openclover:clover:4.3.1'
298   }
299 }
300
301 configurations {
302   cloverRuntime
303   cloverRuntime.extendsFrom cloverCompile
304 }
305
306 eclipse {
307   project {
308     name = eclipse_project_name
309
310     natures 'org.eclipse.jdt.core.javanature',
311     'org.eclipse.jdt.groovy.core.groovyNature',
312     'org.eclipse.buildship.core.gradleprojectnature'
313
314     buildCommand 'org.eclipse.jdt.core.javabuilder'
315     buildCommand 'org.eclipse.buildship.core.gradleprojectbuilder'
316   }
317
318   classpath {
319     //defaultOutputDir = sourceSets.main.java.outputDir
320     def removeThese = []
321     configurations.each{
322       if (it.isCanBeResolved()) {
323         removeThese += it
324       }
325     }
326
327     minusConfigurations += removeThese
328     plusConfigurations = [ ]
329     file {
330
331       whenMerged { cp ->
332         def removeTheseToo = []
333         HashMap<String, Boolean> alreadyAddedSrcPath = new HashMap<>();
334         cp.entries.each { entry ->
335           if (entry.kind == 'src') {
336             if (alreadyAddedSrcPath.getAt(entry.path) || !(entry.path == "src" || entry.path == "test")) {
337               removeTheseToo += entry
338             } else {
339               alreadyAddedSrcPath.putAt(entry.path, true)
340             }
341           }
342         }
343         cp.entries.removeAll(removeTheseToo)
344
345         if (file(eclipse_bin_dir+"/main").isDirectory()) {
346           cp.entries += new Output(eclipse_bin_dir+"/main")
347         }
348         if (file(helpParentDir).isDirectory()) {
349           cp.entries += new Library(fileReference(helpParentDir))
350         }
351         if (file(resourceDir).isDirectory()) {
352           cp.entries += new Library(fileReference(resourceDir))
353         }
354
355         HashMap<String, Boolean> alreadyAddedLibPath = new HashMap<>();
356
357         sourceSets.main.compileClasspath.findAll { it.name.endsWith(".jar") }.each {
358           //don't want to add outputDir as eclipse is using its own output dir in bin/main
359           if (it.isDirectory() || ! it.exists()) {
360             // don't add dirs to classpath
361             return
362           }
363           def itPath = it.toString()
364           if (itPath.startsWith(jalviewDirAbsolutePath+"/")) {
365             // make relative path
366             itPath = itPath.substring(jalviewDirAbsolutePath.length()+1)
367           }
368           if (alreadyAddedLibPath.get(itPath)) {
369             //println("Not adding duplicate entry "+itPath)
370           } else {
371             //println("Adding entry "+itPath)
372             cp.entries += new Library(fileReference(itPath))
373             alreadyAddedLibPath.put(itPath, true)
374           }
375         }
376
377         //fileTree(dir: "$jalviewDir/$utilsDir", include: ["test*/*.jar"]).each {
378         sourceSets.test.compileClasspath.findAll { it.name.endsWith(".jar") }.each {
379           //no longer want to add outputDir as eclipse is using its own output dir in bin/main
380           if (it.isDirectory() || ! it.exists()) {
381             // don't add dirs to classpath
382             return false // groovy "break" in .each closure
383           }
384           def itPath = it.toString()
385           if (itPath.startsWith(jalviewDirAbsolutePath+"/")) {
386             itPath = itPath.substring(jalviewDirAbsolutePath.length()+1)
387           }
388           if (alreadyAddedLibPath.get(itPath)) {
389             // don't duplicate
390           } else {
391             def lib = new Library(fileReference(itPath))
392             lib.entryAttributes["test"] = "true"
393             cp.entries += lib
394             alreadyAddedLibPath.put(itPath, true)
395           }
396         }
397
398       } // whenMerged
399
400     } // file
401
402     containers 'org.eclipse.buildship.core.gradleclasspathcontainer'
403
404   } // classpath
405
406   jdt {
407     // for the IDE, use java 11 compatibility
408     sourceCompatibility = compile_source_compatibility
409     targetCompatibility = compile_target_compatibility
410     javaRuntimeName = eclipse_java_runtime_name
411
412     // add in jalview project specific properties/preferences into eclipse core preferences
413     file {
414       withProperties { props ->
415         def jalview_prefs = new Properties()
416         def ins = new FileInputStream(jalviewDirAbsolutePath+"/"+eclipse_extra_jdt_prefs_file)
417         jalview_prefs.load(ins)
418         ins.close()
419         jalview_prefs.forEach { t, v ->
420           if (props.getAt(t) == null) {
421             props.putAt(t, v)
422           }
423         }
424       }
425     }
426
427   } // jdt
428
429 }
430
431 task cloverInstr() {
432   // only instrument source, we build test classes as normal
433   inputs.files files (sourceSets.main.allJava) // , fileTree(dir:"$jalviewDir/$testSourceDir", include: ["**/*.java"]))
434   outputs.dir cloverInstrDir
435
436   doFirst {
437     delete cloverInstrDir
438     def argsList = ["--initstring", "${buildDir}/clover/clover.db",
439     "-d", "${buildDir}/${cloverSourcesInstrDir}"]
440     argsList.addAll(inputs.files.files.collect({ file ->
441       file.absolutePath
442     }))
443     String[] args = argsList.toArray()
444     println("About to instrument "+args.length +" files")
445     com.atlassian.clover.CloverInstr.mainImpl(args)
446   }
447 }
448
449
450 task cloverReport {
451   group = "Verification"
452     description = "Createst the Clover report"
453     inputs.dir "${buildDir}/clover"
454     outputs.dir "${reportsDir}/clover"
455     onlyIf {
456       file("${buildDir}/clover/clover.db").exists()
457     }
458   doFirst {
459     def argsList = ["--initstring", "${buildDir}/clover/clover.db",
460     "-o", "${reportsDir}/clover"]
461     String[] args = argsList.toArray()
462     com.atlassian.clover.reporters.html.HtmlReporter.runReport(args)
463
464     // and generate ${reportsDir}/clover/clover.xml
465     args = ["--initstring", "${buildDir}/clover/clover.db",
466     "-o", "${reportsDir}/clover/clover.xml"].toArray()
467     com.atlassian.clover.reporters.xml.XMLReporter.runReport(args)
468   }
469 }
470
471 // end clover bits
472
473
474 compileJava {
475
476   doFirst {
477     sourceCompatibility = compile_source_compatibility
478     targetCompatibility = compile_target_compatibility
479     options.compilerArgs = additional_compiler_args
480     print ("Setting target compatibility to "+targetCompatibility+"\n")
481   }
482
483 }
484
485 compileTestJava {
486   if (use_clover) {
487     dependsOn compileCloverJava
488     classpath += configurations.cloverRuntime
489   } else {
490     classpath += sourceSets.main.runtimeClasspath
491   }
492   doFirst {
493     sourceCompatibility = compile_source_compatibility
494     targetCompatibility = compile_target_compatibility
495     options.compilerArgs = additional_compiler_args
496     print ("Setting target compatibility to "+targetCompatibility+"\n")
497   }
498 }
499
500
501 compileCloverJava {
502
503   doFirst {
504     sourceCompatibility = compile_source_compatibility
505     targetCompatibility = compile_target_compatibility
506     options.compilerArgs += additional_compiler_args
507     print ("Setting target compatibility to "+targetCompatibility+"\n")
508   }
509   classpath += configurations.cloverRuntime
510 }
511
512 clean {
513   delete sourceSets.main.java.outputDir
514 }
515
516 cleanTest {
517   delete sourceSets.test.java.outputDir
518   delete cloverInstrDir
519 }
520
521 // format is a string like date.format("dd MMMM yyyy")
522 def getDate(format) {
523   def date = new Date()
524   return date.format(format)
525 }
526
527 task setGitVals {
528   def hashStdOut = new ByteArrayOutputStream()
529   exec {
530     commandLine "git", "rev-parse", "--short", "HEAD"
531     standardOutput = hashStdOut
532     ignoreExitValue true
533   }
534
535   def branchStdOut = new ByteArrayOutputStream()
536   exec {
537     commandLine "git", "rev-parse", "--abbrev-ref", "HEAD"
538     standardOutput = branchStdOut
539     ignoreExitValue true
540   }
541
542   project.ext.gitHash = hashStdOut.toString().trim()
543   project.ext.gitBranch = branchStdOut.toString().trim()
544
545   outputs.upToDateWhen { false }
546 }
547
548 task createBuildProperties(type: WriteProperties) {
549   dependsOn setGitVals
550   inputs.dir("$jalviewDir/$sourceDir")
551   inputs.dir("$classes")
552   inputs.dir("$jalviewDir/$resourceDir")
553   outputFile (buildProperties)
554   // taking time specific comment out to allow better incremental builds
555   comment "--Jalview Build Details--\n"+getDate("yyyy-MM-dd HH:mm:ss")
556   //comment "--Jalview Build Details--\n"+getDate("yyyy-MM-dd")
557   property "BUILD_DATE", getDate("HH:mm:ss dd MMMM yyyy")
558   property "VERSION", JALVIEW_VERSION
559   property "INSTALLATION", INSTALLATION+" git-commit:"+project.ext.gitHash+" ["+project.ext.gitBranch+"]"
560   outputs.file(outputFile)
561 }
562
563 def buildingHTML = "$jalviewDir/$docDir/building.html"
564 task deleteBuildingHTML(type: Delete) {
565   delete buildingHTML
566 }
567
568 task convertBuildingMD(type: Exec) {
569   dependsOn deleteBuildingHTML
570   def buildingMD = "$jalviewDir/$docDir/building.md"
571   def css = "$jalviewDir/$docDir/github.css"
572
573   def pandoc = null
574   pandoc_exec.split(",").each {
575     if (file(it.trim()).exists()) {
576       pandoc = it.trim()
577       return true
578     }
579   }
580
581   def hostname = "hostname".execute().text.trim()
582   if ((pandoc == null || ! file(pandoc).exists()) && hostname.equals("jv-bamboo")) {
583     pandoc = System.getProperty("user.home")+"/buildtools/pandoc/bin/pandoc"
584   }
585
586   doFirst {
587     if (pandoc != null && file(pandoc).exists()) {
588         commandLine pandoc, '-s', '-o', buildingHTML, '--metadata', 'pagetitle="Building Jalview from Source"', '--toc', '-H', css, buildingMD
589     } else {
590         println("Cannot find pandoc. Skipping convert building.md to HTML")
591         throw new StopExecutionException()
592     }
593   }
594
595   ignoreExitValue true
596
597   inputs.file(buildingMD)
598   inputs.file(css)
599   outputs.file(buildingHTML)
600 }
601 clean {
602   delete buildingHTML
603 }
604
605 task syncDocs(type: Sync) {
606   dependsOn convertBuildingMD
607   def syncDir = "$classes/$docDir"
608   from fileTree("$jalviewDir/$docDir")
609   into syncDir
610
611 }
612
613 def helpFile = "$classes/$helpDir/help.jhm"
614
615 task copyHelp(type: Copy) {
616   def inputDir = "$jalviewDir/$helpParentDir/$helpDir"
617   def outputDir = "$classes/$helpDir"
618   from(inputDir) {
619     exclude '**/*.gif'
620       exclude '**/*.jpg'
621       exclude '**/*.png'
622       filter(ReplaceTokens, beginToken: '$$', endToken: '$$', tokens: ['Version-Rel': JALVIEW_VERSION,'Year-Rel': getDate("yyyy")])
623   }
624   from(inputDir) {
625     include '**/*.gif'
626       include '**/*.jpg'
627       include '**/*.png'
628   }
629   into outputDir
630
631   inputs.dir(inputDir)
632   outputs.files(helpFile)
633   outputs.dir(outputDir)
634 }
635
636 task syncLib(type: Sync) {
637   def syncDir = "$classes/$libDistDir"
638   from fileTree("$jalviewDir/$libDistDir")
639   into syncDir
640 }
641
642 task syncResources(type: Sync) {
643   from "$jalviewDir/$resourceDir"
644   include "**/*.*"
645   exclude "install4j"
646   into "$classes"
647   preserve {
648     include "**"
649   }
650 }
651
652 task prepare {
653   dependsOn syncResources
654   dependsOn syncDocs
655   dependsOn copyHelp
656 }
657
658
659 //testReportDirName = "test-reports" // note that test workingDir will be $jalviewDir
660 test {
661   dependsOn prepare
662   dependsOn compileJava
663   if (use_clover) {
664     dependsOn cloverInstr
665   }
666
667   if (use_clover) {
668     print("Running tests " + (use_clover?"WITH":"WITHOUT") + " clover [clover="+use_clover+"]\n")
669   }
670
671   useTestNG() {
672     includeGroups testngGroups
673     preserveOrder true
674     useDefaultListeners=true
675   }
676
677   workingDir = jalviewDir
678   //systemProperties 'clover.jar' System.properties.clover.jar
679   sourceCompatibility = compile_source_compatibility
680   targetCompatibility = compile_target_compatibility
681   jvmArgs += additional_compiler_args
682   print ("Setting target compatibility to "+targetCompatibility+"\n")
683 }
684
685 task buildIndices(type: JavaExec) {
686   dependsOn copyHelp
687   classpath = sourceSets.main.compileClasspath
688   main = "com.sun.java.help.search.Indexer"
689   workingDir = "$classes/$helpDir"
690   def argDir = "html"
691   args = [ argDir ]
692   inputs.dir("$workingDir/$argDir")
693
694   outputs.dir("$classes/doc")
695   outputs.dir("$classes/help")
696   outputs.file("$workingDir/JavaHelpSearch/DOCS")
697   outputs.file("$workingDir/JavaHelpSearch/DOCS.TAB")
698   outputs.file("$workingDir/JavaHelpSearch/OFFSETS")
699   outputs.file("$workingDir/JavaHelpSearch/POSITIONS")
700   outputs.file("$workingDir/JavaHelpSearch/SCHEMA")
701   outputs.file("$workingDir/JavaHelpSearch/TMAP")
702 }
703
704 task compileLinkCheck(type: JavaCompile) {
705   options.fork = true
706   classpath = files("$jalviewDir/$utilsDir")
707   destinationDir = file("$jalviewDir/$utilsDir")
708   source = fileTree(dir: "$jalviewDir/$utilsDir", include: ["HelpLinksChecker.java", "BufferedLineReader.java"])
709
710   inputs.file("$jalviewDir/$utilsDir/HelpLinksChecker.java")
711   inputs.file("$jalviewDir/$utilsDir/HelpLinksChecker.java")
712   outputs.file("$jalviewDir/$utilsDir/HelpLinksChecker.class")
713   outputs.file("$jalviewDir/$utilsDir/BufferedLineReader.class")
714 }
715
716 def helplinkscheckertouchfile = file("$jalviewDir/$utilsDir/HelpLinksChecker.touch")
717 task linkCheck(type: JavaExec) {
718   dependsOn prepare, compileLinkCheck
719   classpath = files("$jalviewDir/$utilsDir")
720   main = "HelpLinksChecker"
721   workingDir = jalviewDir
722   def help = "$classes/$helpDir"
723   args = [ "$classes/$helpDir", "-nointernet" ]
724
725   doLast {
726     helplinkscheckertouchfile.createNewFile()
727   }
728
729   inputs.dir("$classes/$helpDir")
730   outputs.file(helplinkscheckertouchfile)
731 }
732
733 // import the pubhtmlhelp target
734 ant.properties.basedir = "$jalviewDir"
735 ant.properties.helpBuildDir = jalviewDirAbsolutePath+"/$classes/$helpDir"
736 ant.importBuild "$utilsDir/publishHelp.xml"
737
738
739 task cleanPackageDir(type: Delete) {
740   delete fileTree("$jalviewDir/$packageDir").include("*.jar")
741 }
742
743 jar {
744   dependsOn linkCheck
745   dependsOn buildIndices
746   dependsOn createBuildProperties
747
748   manifest {
749     attributes "Main-Class": mainClass,
750     "Permissions": "all-permissions",
751     "Application-Name": "Jalview Desktop",
752     "Codebase": application_codebase
753   }
754
755   destinationDir = file("$jalviewDir/$packageDir")
756   archiveName = rootProject.name+".jar"
757
758   exclude "cache*/**"
759   exclude "*.jar"
760   exclude "*.jar.*"
761   exclude "**/*.jar"
762   exclude "**/*.jar.*"
763
764   inputs.dir("$classes")
765   outputs.file("$jalviewDir/$packageDir/$archiveName")
766 }
767
768 task copyJars(type: Copy) {
769   from fileTree("$classes").include("**/*.jar").include("*.jar").files
770   into "$jalviewDir/$packageDir"
771 }
772
773 // doing a Sync instead of Copy as Copy doesn't deal with "outputs" very well
774 task syncJars(type: Sync) {
775   from fileTree("$jalviewDir/$libDistDir").include("**/*.jar").include("*.jar").files
776   into "$jalviewDir/$packageDir"
777   preserve {
778     include jar.archiveName
779   }
780 }
781
782 task makeDist {
783   group = "build"
784   description = "Put all required libraries in dist"
785   // order of "cleanPackageDir", "copyJars", "jar" important!
786   jar.mustRunAfter cleanPackageDir
787   syncJars.mustRunAfter cleanPackageDir
788   dependsOn cleanPackageDir
789   dependsOn syncJars
790   dependsOn jar
791   outputs.dir("$jalviewDir/$packageDir")
792 }
793
794 task cleanDist {
795   dependsOn cleanPackageDir
796   dependsOn cleanTest
797   dependsOn clean
798 }
799
800 shadowJar {
801   group = "distribution"
802   if (buildDist) {
803     dependsOn makeDist
804   }
805   from ("$jalviewDir/$libDistDir") {
806     include("*.jar")
807   }
808   manifest {
809     attributes 'Implementation-Version': JALVIEW_VERSION
810   }
811   mainClassName = shadowJarMainClass
812   mergeServiceFiles()
813   classifier = "all-"+JALVIEW_VERSION+"-j"+JAVA_VERSION
814   minimize()
815 }
816
817 task getdownWebsite() {
818   group = "distribution"
819   description = "Create the getdown minimal app folder, and website folder for this version of jalview. Website folder also used for offline app installer"
820   if (buildDist) {
821     dependsOn makeDist
822   }
823
824         // clean the getdown website and files dir before creating getdown folders
825         delete project.ext.getdownWebsiteDir
826         delete project.ext.getdownFilesDir
827
828   def getdownWebsiteResourceFilenames = []
829   def getdownTextString = ""
830   def getdownResourceDir = project.ext.getdownResourceDir
831   def getdownAppDir = project.ext.getdownAppDir
832   def getdownResourceFilenames = []
833
834   doFirst {
835     copy {
836       from buildProperties
837       rename(buildPropertiesFile, getdown_build_properties)
838       into project.ext.getdownAppDir
839     }
840     getdownWebsiteResourceFilenames += getdown_app_dir+"/"+getdown_build_properties
841
842     // go through properties looking for getdown_txt_...
843     def props = project.properties.sort { it.key }
844         if (getdown_alt_java_min_version.length() > 0) {
845                 props.put("getdown_txt_java_min_version", getdown_alt_java_min_version)
846         }
847         if (getdown_alt_java_max_version.length() > 0) {
848                 props.put("getdown_txt_java_max_version", getdown_alt_java_max_version)
849         }
850         props.put("getdown_txt_multi_java_location", getdown_alt_multi_java_location)
851
852     props.put("getdown_txt_appbase", getdown_app_base)
853     props.each{ prop, val ->
854       if (prop.startsWith("getdown_txt_") && val != null) {
855         if (prop.startsWith("getdown_txt_multi_")) {
856           def key = prop.substring(18)
857           val.split(",").each{ v ->
858             def line = key + " = " + v + "\n"
859             getdownTextString += line
860           }
861         } else {
862           // file values rationalised
863           if (val.indexOf('/') > -1 || prop.startsWith("getdown_txt_resource")) {
864             def r = null
865             if (val.indexOf('/') == 0) {
866               // absolute path
867               r = file(val)
868             } else if (val.indexOf('/') > 0) {
869               // relative path (relative to jalviewDir)
870               r = file( jalviewDir + '/' + val )
871             }
872             if (r.exists()) {
873               val = getdown_resource_dir + '/' + r.getName()
874               getdownWebsiteResourceFilenames += val
875               getdownResourceFilenames += r.getPath()
876             }
877           }
878           if (! prop.startsWith("getdown_txt_resource")) {
879             def line = prop.substring(12) + " = " + val + "\n"
880             getdownTextString += line
881           }
882         }
883       }
884     }
885
886     getdownWebsiteResourceFilenames.each{ filename ->
887       getdownTextString += "resource = "+filename+"\n"
888     }
889     getdownResourceFilenames.each{ filename ->
890       copy {
891         from filename
892         into project.ext.getdownResourceDir
893       }
894     }
895
896     def codeFiles = []
897     fileTree(file(packageDir)).each{ f ->
898       if (f.isDirectory()) {
899         def files = fileTree(dir: f, include: ["*"]).getFiles()
900         codeFiles += files
901       } else if (f.exists()) {
902         codeFiles += f
903       }
904     }
905     codeFiles.sort().each{f ->
906       def line = "code = " + getdown_app_dir + '/' + f.getName() + "\n"
907       getdownTextString += line
908       copy {
909         from f.getPath()
910         into project.ext.getdownAppDir
911       }
912     }
913
914     // NOT USING MODULES YET, EVERYTHING SHOULD BE IN dist
915     /*
916     if (JAVA_VERSION.equals("11")) {
917     def j11libFiles = fileTree(dir: "$jalviewDir/$j11libDir", include: ["*.jar"]).getFiles()
918     j11libFiles.sort().each{f ->
919     def line = "code = " + getdown_j11lib_dir + '/' + f.getName() + "\n"
920     getdownTextString += line
921     copy {
922     from f.getPath()
923     into project.ext.getdownJ11libDir
924     }
925     }
926     }
927      */
928
929     // 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.
930     //getdownTextString += "class = " + file(getdownLauncher).getName() + "\n"
931     getdownTextString += "resource = " + getdown_launcher_new + "\n"
932     getdownTextString += "class = " + mainClass + "\n"
933
934     def getdown_txt = file(project.ext.getdownWebsiteDir + "/getdown.txt")
935     getdown_txt.write(getdownTextString)
936
937     def launch_jvl = file(project.ext.getdownWebsiteDir + "/" + getdown_launch_jvl)
938     launch_jvl.write("appbase="+props.get("getdown_txt_appbase"))
939
940     copy {
941       from getdownLauncher
942       rename(file(getdownLauncher).getName(), getdown_launcher_new)
943       into project.ext.getdownWebsiteDir
944     }
945
946     copy {
947       from getdownLauncher
948       if (file(getdownLauncher).getName() != getdown_launcher) {
949         rename(file(getdownLauncher).getName(), getdown_launcher)
950       }
951       into project.ext.getdownWebsiteDir
952     }
953
954     if (! (CHANNEL.startsWith("ARCHIVE") || CHANNEL.startsWith("DEVELOP"))) {
955       copy {
956         from getdown_txt
957         from getdownLauncher
958         from getdownWebsiteDir+"/"+getdown_build_properties
959         if (file(getdownLauncher).getName() != getdown_launcher) {
960           rename(file(getdownLauncher).getName(), getdown_launcher)
961         }
962         into getdownInstallDir
963       }
964
965       copy {
966         from getdownInstallDir
967         into getdownFilesInstallDir
968       }
969     }
970
971     copy {
972       from getdown_txt
973       from launch_jvl
974       from getdownLauncher
975       from getdownWebsiteDir+"/"+getdown_build_properties
976       if (file(getdownLauncher).getName() != getdown_launcher) {
977         rename(file(getdownLauncher).getName(), getdown_launcher)
978       }
979       into getdownFilesDir
980     }
981
982     copy {
983           from getdownResourceDir
984       into project.ext.getdownFilesDir + '/' + getdown_resource_dir
985     }
986   }
987
988   if (buildDist) {
989     inputs.dir(jalviewDir + '/' + packageDir)
990   }
991   outputs.dir(project.ext.getdownWebsiteDir)
992   outputs.dir(project.ext.getdownFilesDir)
993 }
994
995 task getdownDigest(type: JavaExec) {
996   group = "distribution"
997   description = "Digest the getdown website folder"
998   dependsOn getdownWebsite
999   doFirst {
1000     classpath = files(getdownWebsiteDir + '/' + getdown_launcher)
1001   }
1002   main = "com.threerings.getdown.tools.Digester"
1003   args project.ext.getdownWebsiteDir
1004   inputs.dir(project.ext.getdownWebsiteDir)
1005   outputs.file(project.ext.getdownWebsiteDir + '/' + "digest2.txt")
1006 }
1007
1008 task getdown() {
1009   group = "distribution"
1010   description = "Create the minimal and full getdown app folder for installers and website and create digest file"
1011   dependsOn getdownDigest
1012   doLast {
1013     if (reportRsyncCommand) {
1014       def fromDir = getdownWebsiteDir + (getdownWebsiteDir.endsWith("/")?"":"/")
1015       def toDir = getdown_rsync_dest + "/" + getdownDir + (getdownDir.endsWith("/")?"":"/")
1016       println "LIKELY RSYNC COMMAND:"
1017       println "mkdir -p '$toDir'\nrsync -avh --delete '$fromDir' '$toDir'"
1018       if (RUNRSYNC == "true") {
1019         exec {
1020           commandLine "mkdir", "-p", toDir
1021         }
1022         exec {
1023           commandLine "rsync", "-avh", "--delete", fromDir, toDir
1024         }
1025       }
1026     }
1027   }
1028 }
1029
1030 clean {
1031   delete project.ext.getdownWebsiteDir
1032   delete project.ext.getdownFilesDir
1033 }
1034
1035 install4j {
1036   def install4jHomeDir = "/opt/install4j"
1037   def hostname = "hostname".execute().text.trim()
1038   if (hostname.equals("jv-bamboo")) {
1039     install4jHomeDir = System.getProperty("user.home")+"/buildtools/install4j"
1040   } else if (OperatingSystem.current().isMacOsX()) {
1041     install4jHomeDir = '/Applications/install4j.app/Contents/Resources/app'
1042     if (! file(install4jHomeDir).exists()) {
1043       install4jHomeDir = System.getProperty("user.home")+install4jHomeDir
1044     }
1045   } else if (OperatingSystem.current().isLinux()) {
1046     install4jHomeDir = System.getProperty("user.home")+"/buildtools/install4j"
1047   }
1048   installDir = file(install4jHomeDir)
1049   mediaTypes = Arrays.asList(install4jMediaTypes.split(","))
1050   if (install4jFaster.equals("true")) {
1051     faster = true
1052   }
1053 }
1054
1055 def install4jConf
1056 def macosJavaVMDir
1057 def macosJavaVMTgz
1058 def windowsJavaVMDir
1059 def windowsJavaVMTgz
1060 def install4jDir = "$jalviewDir/$install4jResourceDir"
1061 def install4jConfFile = "jalview-installers-java"+JAVA_VERSION+".install4j"
1062 install4jConf = "$install4jDir/$install4jConfFile"
1063
1064 task copyInstall4jTemplate(type: Copy) {
1065   macosJavaVMDir = System.env.HOME+"/buildtools/jre/openjdk-java_vm/getdown/macos-jre"+JAVA_VERSION+"/jre"
1066   macosJavaVMTgz = System.env.HOME+"/buildtools/jre/openjdk-java_vm/install4j/tgz/macos-jre"+JAVA_VERSION+".tar.gz"
1067   windowsJavaVMDir = System.env.HOME+"/buildtools/jre/openjdk-java_vm/getdown/windows-jre"+JAVA_VERSION+"/jre"
1068   windowsJavaVMTgz = System.env.HOME+"/buildtools/jre/openjdk-java_vm/install4j/tgz/windows-jre"+JAVA_VERSION+".tar.gz"
1069   from (install4jDir) {
1070     include install4jTemplate
1071     rename (install4jTemplate, install4jConfFile)
1072     filter(ReplaceTokens, beginToken: '', endToken: '', tokens: ['9999999999': JAVA_VERSION])
1073     filter(ReplaceTokens, beginToken: '$$', endToken: '$$',
1074     tokens: [
1075     'JAVA_VERSION': JAVA_VERSION,
1076     'JAVA_INTEGER_VERSION': JAVA_INTEGER_VERSION,
1077     'VERSION': JALVIEW_VERSION,
1078     'MACOS_JAVA_VM_DIR': macosJavaVMDir,
1079     'MACOS_JAVA_VM_TGZ': macosJavaVMTgz,
1080     'WINDOWS_JAVA_VM_DIR': windowsJavaVMDir,
1081     'WINDOWS_JAVA_VM_TGZ': windowsJavaVMTgz,
1082     'INSTALL4JINFOPLISTFILEASSOCIATIONS': install4jInfoPlistFileAssociations,
1083     'COPYRIGHT_MESSAGE': install4jCopyrightMessage,
1084     'MACOS_BUNDLE_ID': install4jMacOSBundleId,
1085     'GETDOWN_RESOURCE_DIR': getdown_resource_dir,
1086     'GETDOWN_DIST_DIR': getdown_app_dir,
1087     'GETDOWN_ALT_DIR': getdown_app_dir_alt,
1088     'GETDOWN_INSTALL_DIR': getdown_install_dir
1089     ]
1090     )
1091     if (OSX_KEYPASS=="") {
1092       filter(ReplaceTokens, beginToken: 'codeSigning macEnabled="', endToken: '"', tokens: ['true':'codeSigning macEnabled="false"'])
1093       filter(ReplaceTokens, beginToken: 'runPostProcessor="true" ',endToken: 'Processor', tokens: ['post':'runPostProcessor="false" postProcessor'])
1094     }
1095   }
1096   into install4jDir
1097   outputs.files(install4jConf)
1098
1099   doLast {
1100     // include file associations in installer
1101     def installerFileAssociationsXml = file("$install4jDir/$install4jInstallerFileAssociations").text
1102     ant.replaceregexp(
1103       byline: false,
1104       flags: "s",
1105       match: '<action name="EXTENSIONS_REPLACED_BY_GRADLE".*?</action>',
1106       replace: installerFileAssociationsXml,
1107       file: install4jConf
1108     )
1109     /*
1110     // include uninstaller applescript app files in dmg
1111     def installerDMGUninstallerXml = file("$install4jDir/$install4jDMGUninstallerAppFiles").text
1112     ant.replaceregexp(
1113     byline: false,
1114     flags: "s",
1115     match: '<file name="UNINSTALL_OLD_JALVIEW_APP_REPLACED_IN_GRADLE" file=.*?>',
1116     replace: installerDMGUninstallerXml,
1117     file: install4jConf
1118     )
1119      */
1120   }
1121 }
1122
1123 task installers(type: com.install4j.gradle.Install4jTask) {
1124   group = "distribution"
1125   description = "Create the install4j installers"
1126   dependsOn getdown
1127   dependsOn copyInstall4jTemplate
1128   projectFile = file(install4jConf)
1129   println("Using projectFile "+projectFile)
1130   variables = [majorVersion: version.substring(2, 11), build: 001, OSX_KEYSTORE: OSX_KEYSTORE, JSIGN_SH: JSIGN_SH]
1131   destination = "$jalviewDir/$install4jBuildDir/$JAVA_VERSION"
1132   buildSelected = true
1133
1134   if (OSX_KEYPASS) {
1135     macKeystorePassword=OSX_KEYPASS
1136
1137   }
1138
1139   inputs.dir(project.ext.getdownWebsiteDir)
1140   inputs.file(install4jConf)
1141   inputs.dir(macosJavaVMDir)
1142   inputs.dir(windowsJavaVMDir)
1143   outputs.dir("$jalviewDir/$install4jBuildDir/$JAVA_VERSION")
1144
1145 }
1146
1147 clean {
1148   delete install4jConf
1149 }
1150
1151 task sourceDist (type: Tar) {
1152   
1153   def VERSION_UNDERSCORES = JALVIEW_VERSION.replaceAll("\\.", "_")
1154   def outputFileName = project.name + "_" + VERSION_UNDERSCORES + ".tar.gz"
1155   // cater for buildship < 3.1 [3.0.1 is max version in eclipse 2018-09]
1156   try {
1157     archiveFileName = outputFileName
1158   } catch (Exception e) {
1159     archiveName = outputFileName
1160   }
1161   
1162   compression Compression.GZIP
1163   
1164   into project.name
1165
1166   def EXCLUDE_FILES=["build/*","bin/*","test-output/","test-reports","tests","clover*/*"
1167   ,".*"
1168   ,"benchmarking/*"
1169   ,"**/.*"
1170   ,"*.class"
1171   ,"**/*.class","$j11modDir/**/*.jar","appletlib","**/*locales"
1172   ,"*locales/**",
1173   ,"utils/InstallAnywhere"] 
1174   def PROCESS_FILES=[   "AUTHORS",
1175   "CITATION",
1176   "FEATURETODO",
1177   "JAVA-11-README",
1178   "FEATURETODO",
1179   "LICENSE",
1180   "**/README",
1181   "RELEASE",
1182   "THIRDPARTYLIBS","TESTNG",
1183   "build.gradle",
1184   "gradle.properties",
1185   "**/*.java",
1186   "**/*.html",
1187   "**/*.xml",
1188   "**/*.gradle",
1189   "**/*.groovy",
1190   "**/*.properties",
1191   "**/*.perl",
1192   "**/*.sh"]
1193
1194   from(jalviewDir) {
1195     exclude (EXCLUDE_FILES)
1196     include (PROCESS_FILES)
1197     filter(ReplaceTokens, beginToken: '$$', endToken: '$$', tokens: ['Version-Rel': JALVIEW_VERSION,'Year-Rel': getDate("yyyy")])
1198   }
1199   from(jalviewDir) {
1200     exclude (EXCLUDE_FILES)
1201     exclude (PROCESS_FILES)
1202   exclude ("appletlib")
1203   exclude ("**/*locales")
1204   exclude ("*locales/**")
1205   exclude ("utils/InstallAnywhere")
1206
1207     exclude (getdown_files_dir)
1208   exclude (getdown_website_dir)
1209
1210   // exluding these as not using jars as modules yet
1211   exclude ("$j11modDir/**/*.jar")
1212 }
1213 //  from (jalviewDir) {
1214 //    // explicit includes for stuff that seemed to not get included
1215 //    include(fileTree("test/**/*."))
1216 //    exclude(EXCLUDE_FILES)
1217 //    exclude(PROCESS_FILES)
1218 //  }
1219 }
1220
1221 task helppages  {
1222   dependsOn copyHelp
1223   dependsOn pubhtmlhelp
1224   
1225   inputs.dir("$classes/$helpDir")
1226   outputs.dir("$helpOutputDir")
1227 }
1228
1229 def jalviewjsBuildDir
1230 def jalviewjsSiteDir
1231 def jalviewjsTransferSiteDir
1232 task jalviewjsSitePath {
1233   def relativeBuildDir = file(jalviewDirAbsolutePath).toPath().relativize(buildDir.toPath())
1234   jalviewjsBuildDir = "${relativeBuildDir}/jalviewjs"
1235   if (jalviewjs_site_dir.startsWith("/")) {
1236     jalviewjsSiteDir = jalviewjs_site_dir
1237   } else {
1238     jalviewjsSiteDir = jalviewjsBuildDir + "/" + jalviewjs_site_dir
1239   }
1240   jalviewjsTransferSiteDir = jalviewjsBuildDir + "/tmp/site"
1241 }
1242
1243 def eclipseWorkspace
1244 task jalviewjsSetEclipseWorkspace {
1245   def propKey = "jalviewjs_eclipse_workspace"
1246   def propsFileName = "${jalviewjsBuildDir}/${jalviewjs_eclipse_workspace_location_file}"
1247   def props = new Properties()
1248   def eclipseWsDir
1249   def propVal = null
1250   if (project.hasProperty(propKey)) {
1251     propVal = project.getProperty(propKey)
1252     eclipseWsDir = propVal
1253   }
1254   if (( eclipseWsDir == null || !file(eclipseWsDir).exists() ) && file(propsFileName).exists()) {
1255     def ins = new FileInputStream("${jalviewDirAbsolutePath}/${propsFileName}")
1256     props.load(ins)
1257     ins.close()
1258     if (props.getProperty(propKey, null) != null) {
1259       eclipseWsDir = props.getProperty(propKey)
1260     }
1261   }
1262
1263   if (eclipseWsDir == null || !file(eclipseWsDir).exists()) {
1264     def tempDir = File.createTempDir()
1265     eclipseWsDir = tempDir.getAbsolutePath()
1266     props.setProperty(propKey, eclipseWsDir)
1267     def propsFile = file(propsFileName)
1268     propsFile.parentFile.mkdirs()
1269     propsFile.createNewFile() // doesn't affect existing file
1270     def outs = new FileOutputStream(propsFile, false)
1271     props.store(outs, null)
1272     outs.close()
1273   }
1274
1275   eclipseWorkspace = file(eclipseWsDir)
1276     
1277   println("ECLIPSE WORKSPACE: "+eclipseWorkspace.getPath())
1278
1279   inputs.property(propKey, propVal)
1280   outputs.file(propsFileName)
1281 }
1282
1283
1284 task jalviewjsUnzipFiles {
1285   dependsOn jalviewjsSitePath
1286
1287   def zipFiles = fileTree(dir: jalviewjs_utils_dir+"/"+jalviewjs_libjs_dir).include("*.zip")
1288   zipFiles += jalviewjs_utils_dir+"/"+jalviewjs_swingjs_zip
1289
1290   doLast {
1291     zipFiles.each { file_zip -> 
1292       copy {
1293         from zipTree(file_zip)
1294         into jalviewjsSiteDir
1295       }
1296     }
1297   }
1298
1299   inputs.files zipFiles
1300   outputs.dir jalviewjsSiteDir
1301 }
1302
1303 def eclipseDropinsDir
1304 def eclipseBinary
1305 def eclipseVersion
1306 def fromDropinsDir
1307 task jalviewjsEclipsePaths {
1308   def eclipseRoot
1309   def eclipseProduct
1310   eclipseRoot = jalviewjs_eclipse_root
1311   if (eclipseRoot.startsWith("~")) {
1312     eclipseRoot = System.getProperty("user.home") + eclipseRoot.substring(1)
1313   }
1314   if (OperatingSystem.current().isMacOsX()) {
1315     eclipseRoot += "/Eclipse.app"
1316     eclipseDropinsDir = eclipseRoot+"/Contents/Eclipse/dropins"
1317     eclipseBinary = eclipseRoot+"/Contents/MacOS/eclipse"
1318     eclipseProduct = eclipseRoot+"/Contents/Eclipse/.eclipseproduct"
1319   } else if (OperatingSystem.current().isWindows()) { // check these paths!!
1320     if (file(eclipseRoot+"/eclipse").isDirectory() && file(eclipseRoot+"/eclipse/.eclipseproduct").exists()) {
1321       eclipseRoot += "/eclipse"
1322     }
1323     eclipseDropinsDir = eclipseRoot+"/dropins"
1324     eclipseBinary = eclipseRoot+"/eclipse"
1325     eclipseProduct = eclipseRoot+"/.eclipseproduct"
1326   } else { // linux or unix
1327     if (file(eclipseRoot+"/eclipse").isDirectory() && file(eclipseRoot+"/eclipse/.eclipseproduct").exists()) {
1328       eclipseRoot += "/eclipse"
1329     }
1330     eclipseDropinsDir = eclipseRoot+"/dropins"
1331     eclipseBinary = eclipseRoot+"/eclipse"
1332     eclipseProduct = eclipseRoot+"/.eclipseproduct"
1333   }
1334
1335   def fis = new FileInputStream(eclipseProduct)
1336   def props = new Properties()
1337   props.load(fis)
1338   eclipseVersion = props.getProperty("version")
1339   fis.close()
1340   println("ECLIPSE_VERSION=${eclipseVersion}")
1341   String[] v = eclipseVersion.split("\\.")
1342   def v0 = Integer.valueOf(v[0])
1343   def v1 = Integer.valueOf(v[1])
1344   if (v0 < 4 || ( v0 == 4 && v1 < 13 )) {
1345     fromDropinsDir = "eclipse/dropins_4.12"
1346   } else {
1347     fromDropinsDir = "eclipse/dropins_4.13"
1348   } 
1349 }
1350
1351 task jalviewjsEclipseCopyDropins {
1352   dependsOn jalviewjsEclipsePaths
1353   def inputFiles = fileTree(dir: jalviewjs_utils_dir+"/"+fromDropinsDir, include: "*.jar")
1354   def outputDir = eclipseDropinsDir
1355
1356   inputs.files inputFiles
1357   inputFiles.each { file ->
1358     outputs.file(outputDir+"/"+file.name)
1359   }
1360
1361   doLast {
1362     def outputFiles = []
1363     inputFiles.each { file ->
1364       copy {
1365         from file
1366         into outputDir
1367       }
1368     }
1369   }
1370 }
1371
1372 task jalviewjsCreateJ2sSettings(type: WriteProperties) {
1373   dependsOn jalviewjsSitePath
1374   outputFile (jalviewDir+"/"+jalviewjs_j2s_settings)
1375   def props = project.properties.sort { it.key }
1376   def siteDirProperty = "j2s.site.directory"
1377   def setSiteDir = false
1378   props.each { prop, val ->
1379     if (prop.startsWith("j2s.") && val != null) {
1380       if (prop == siteDirProperty) {
1381         if (!(val.startsWith("/") || val.startsWith("file://") )) {
1382           val = jalviewjsTransferSiteDir+"/"+val
1383         }
1384         setSiteDir = true
1385       }
1386       property(prop,val)
1387     }
1388     if (!setSiteDir) {
1389       property(siteDirProperty,jalviewjsTransferSiteDir)
1390     }
1391   }
1392   outputs.file(outputFile)
1393 }
1394
1395 task jalviewjsEclipseSetup {
1396   dependsOn jalviewjsEclipseCopyDropins
1397   dependsOn jalviewjsSetEclipseWorkspace
1398   dependsOn jalviewjsCreateJ2sSettings
1399 }
1400
1401 task jalviewjsCopyResources (type: Copy) {
1402   dependsOn jalviewjsSitePath
1403   def inputFiles = fileTree(dir: jalviewjs_resource_dir)
1404   def outputDir = jalviewjsSiteDir+"/"+jalviewjs_j2s_subdir
1405
1406   from inputFiles
1407   into outputDir
1408   def outputFiles = []
1409   rename { filename ->
1410     outputFiles += outputDir+"/"+filename
1411     null
1412   }
1413   outputs.files outputFiles
1414   inputs.files inputFiles
1415 }
1416
1417 task jalviewjsCopySiteResources (type: Copy) {
1418   dependsOn jalviewjsSitePath
1419   def inputFiles = fileTree(dir: jalviewjs_utils_dir+"/"+jalviewjs_site_resource_dir)
1420   def outputDir = jalviewjsSiteDir
1421
1422   from inputFiles
1423   into outputDir
1424   def outputFiles = []
1425   rename { filename ->
1426     outputFiles += outputDir+"/"+filename
1427     null
1428   }
1429   outputs.files outputFiles
1430   inputs.files inputFiles
1431 }
1432
1433 task cleanJalviewjs {
1434   //delete jalviewjsBuildDir
1435   //delete jalviewDir+"/"+eclipse_bin_dir
1436   //delete file(eclipseWorkspace.getAbsolutePath()+"/.metadata")
1437   //delete jalviewDir+"/"+jalviewjs_j2s_settings
1438 }
1439
1440 task jalviewjsProjectImport(type: Exec) {
1441   // work out how to do this!
1442   dependsOn eclipseProject
1443   dependsOn eclipseClasspath
1444   dependsOn eclipseJdt
1445   dependsOn jalviewjsEclipsePaths
1446   dependsOn jalviewjsEclipseSetup
1447   executable(eclipseBinary)
1448   args(["-nosplash", "--launcher.suppressErrors", "-application", "com.seeq.eclipse.importprojects.headlessimport", "-data", eclipseWorkspace.getPath(), "-import", jalviewDirAbsolutePath])
1449
1450   def projdir = eclipseWorkspace.getPath()+"/.metadata/.plugins/org.eclipse.core.resources/.projects/jalview/org.eclipse.jdt.core"
1451   inputs.file(jalviewDir+"/.project")
1452   outputs.dir(projdir)
1453   outputs.upToDateWhen { file(projdir).exists() }
1454 }
1455
1456 task jalviewjsTranspile(type: Exec) {
1457   dependsOn jalviewjsEclipseSetup 
1458   dependsOn jalviewjsProjectImport
1459   dependsOn jalviewjsEclipsePaths
1460   executable(eclipseBinary)
1461   args(["-nosplash", "--launcher.suppressErrors", "-application", "org.eclipse.jdt.apt.core.aptBuild", "-data", eclipseWorkspace, "-"+jalviewjs_eclipseBuildArg, eclipse_project_name ])
1462
1463   def stdout
1464   def stderr
1465   doFirst {
1466     stdout = new ByteArrayOutputStream()
1467     stderr = new ByteArrayOutputStream()
1468
1469     def logOutFileName = "${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_j2s_stdout}"
1470     def logOutFile = file(logOutFileName)
1471     logOutFile.createNewFile()
1472     def logOutFOS = new FileOutputStream(logOutFile, false)
1473     //def logErrFileName = "${jalviewjsBuildDir}/${jalviewjs_j2s_stderr}"
1474     //def logErrFile = file(logFileName)
1475     //logErrFile.createNewFile()
1476     //def logErrFOS = new FileErrputStream(logErrFile, false)
1477     // combine stdout and stderr
1478     def logErrFOS = logOutFOS
1479     if (jalviewjs_j2s_to_console.equals("true")) {
1480       standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
1481         new org.apache.tools.ant.util.TeeOutputStream(
1482           logOutFOS,
1483           stdout),
1484         standardOutput)
1485       errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
1486         new org.apache.tools.ant.util.TeeOutputStream(
1487           logErrFOS,
1488           stderr),
1489         errorOutput)
1490     } else {
1491       standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
1492         logOutFOS,
1493         stdout)
1494       errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
1495         logErrFOS,
1496         stderr)
1497     }
1498   }
1499   doLast {
1500     if (stdout.toString().contains("Error processing ")) {
1501       // j2s did not complete transpile
1502       throw new GradleException("Error during transpilation:\n${stderr}\nSee eclipse transpile log file '${jalviewjsBuildDir}/${jalviewjs_j2s_stdout}'")
1503     }
1504   }
1505
1506   inputs.dir(sourceDir)
1507   outputs.dir(eclipse_bin_dir+"/main")
1508   outputs.dir(jalviewjsTransferSiteDir)
1509
1510 }
1511
1512 task jalviewjsCopyTransferSite(type: Copy) {
1513   dependsOn jalviewjsTranspile
1514   from jalviewjsTransferSiteDir
1515   into jalviewjsSiteDir
1516 }
1517
1518 jalviewjsUnzipFiles.mustRunAfter jalviewjsCopyTransferSite
1519 jalviewjsCopyResources.mustRunAfter jalviewjsCopyTransferSite
1520 jalviewjsCopySiteResources.mustRunAfter jalviewjsCopyTransferSite
1521
1522 task jalviewjsPrepareSite {
1523   group "JalviewJS"
1524   description "Prepares the website folder including unzipping files and copying resources"
1525   dependsOn jalviewjsSitePath
1526   dependsOn jalviewjsUnzipFiles
1527   dependsOn jalviewjsCopyResources
1528   dependsOn jalviewjsCopySiteResources
1529 }
1530
1531 task jalviewjsBuildSite {
1532   group "JalviewJS"
1533   description "Builds the whole website including transpiled code"
1534   dependsOn jalviewjsCopyTransferSite
1535   dependsOn jalviewjsPrepareSite
1536 }
1537
1538 task cleanJalviewjsSite {
1539   delete jalviewjsTransferSiteDir
1540   delete jalviewjsSiteDir
1541 }
1542
1543 task jalviewjsSiteTar(type: Tar) {
1544   group "JalviewJS"
1545   description "Creates a tar.gz file for the website"
1546   dependsOn jalviewjsBuildSite
1547   def outputFilename = "jalviewjs-site-${JALVIEW_VERSION}.tar.gz"
1548   try {
1549     archiveFileName = outputFilename
1550   } catch (Exception e) {
1551     archiveName = outputFilename
1552   }
1553
1554   compression Compression.GZIP
1555
1556   from jalviewjsSiteDir
1557   into jalviewjs_site_dir // this is inside the tar file
1558
1559   inputs.dir(jalviewjsSiteDir)
1560 }
1561
1562 task jalviewjsServer {
1563   group "JalviewJS"
1564   description "Starts a webserver on localhost to test the website"
1565   dependsOn jalviewjsSitePath
1566   def htmlFile = "${jalviewDirAbsolutePath}/jalviewjsTest.html"
1567   doLast {
1568
1569     SimpleHttpFileServerFactory factory = new SimpleHttpFileServerFactory()
1570     def port = Integer.valueOf(jalviewjs_server_port)
1571     def start = port
1572     def running = false
1573     def url
1574     while(port < start+1000 && !running) {
1575       try {
1576         def doc_root = new File(jalviewDirAbsolutePath +"/"+ jalviewjsSiteDir)
1577         jalviewjsServer = factory.start(doc_root, port)
1578         running = true
1579         url = jalviewjsServer.getResourceUrl(jalviewjs_server_resource)
1580         println("SERVER STARTED with document root ${doc_root}.")
1581         println("Go to "+url+" . Run  gradle --stop  to stop (kills all gradle daemons).")
1582         println("For debug: "+url+"?j2sdebug")
1583
1584         file(htmlFile).text = """
1585         <p><a href="${url}">Jalview JS Test. &lt;${url}&gt;</a></p>
1586         <p><a href="${url}?j2sdebug">Jalview JS Test with debug. &lt;${url}?j2sdebug&lt;</a></p>
1587         """
1588
1589       } catch (Exception e) {
1590         port++;
1591       }
1592     }
1593
1594   }
1595
1596   outputs.file(htmlFile)
1597 }
1598
1599 task jalviewjs {
1600   group "JalviewJS"
1601   description "Build the site"
1602   dependsOn jalviewjsBuildSite
1603 }
1604
1605
1606 task jalviewjsIDECopyTransferSite(type: Copy) {
1607   from jalviewjsTransferSiteDir
1608   into jalviewjsSiteDir
1609 }
1610
1611 task jalviewjsIDEBuildSite {
1612   group "JalviewJS in Eclipse"
1613   description "Copies the Eclipse transpiled site and unzips supporting zipfiles"
1614   dependsOn jalviewjsIDECopyTransferSite
1615   dependsOn jalviewjsPrepareSite
1616 }
1617
1618 task cleanJalviewjsIDESite {
1619   group "JalviewJS in Eclipse"
1620   description "Deletes the Eclipse transpiled site"
1621   dependsOn cleanJalviewjsSite
1622 }
1623
1624 task jalviewjsIDEServer {
1625   group "JalviewJS in Eclipse"
1626   description "Starts a webserver on localhost to test the website"
1627   dependsOn jalviewjsServer
1628 }
1629