JAL-3322 linksCheck task output.
[jalview.git] / build.gradle
1 import org.apache.tools.ant.filters.ReplaceTokens
2 //import org.apache.tools.ant.filters.ReplaceRegexp
3 import org.gradle.internal.os.OperatingSystem
4 import org.gradle.plugins.ide.eclipse.model.*
5
6
7 import groovy.transform.ExternalizeMethods
8
9 buildscript {
10   dependencies {
11     classpath 'org.openclover:clover:4.3.1'
12     classpath 'org.apache.commons:commons-compress:1.18'
13   }
14 }
15
16 plugins {
17   id 'java'
18   id 'application'
19   id 'eclipse'
20   id 'com.github.johnrengelman.shadow' version '4.0.3'
21   id 'com.install4j.gradle' version '7.0.9'
22 }
23
24 repositories {
25   jcenter()
26   mavenCentral()
27   mavenLocal()
28   flatDir {
29     dirs gradlePluginsDir
30   }
31 }
32
33 mainClassName = launcherClass
34 def cloverInstrDir = file("$buildDir/$cloverSourcesInstrDir")
35 def classes = "$jalviewDir/$classesDir"
36
37 if (clover.equals("true")) {
38   use_clover = true
39   classes = "$buildDir/$cloverClassesDir"
40 } else {
41   use_clover = false
42   classes = "$jalviewDir/$classesDir"
43 }
44
45 // configure classpath/args for j8/j11 compilation
46
47 def jalviewDirAbsolutePath = file(jalviewDir).getAbsolutePath()
48 def libDir
49 def libDistDir
50 def compile_source_compatibility
51 def compile_target_compatibility
52
53 ext {
54   getdownWebsiteDir = jalviewDir + '/' + getdown_website_dir + '/' + JAVA_VERSION
55   getdownDir = ""
56   reportRsyncCmd = false
57   buildDist = true
58   buildProperties = buildPropertiesFile
59   switch (CHANNEL) {
60
61     case "BUILD":
62     // TODO: get bamboo build artifact URL for getdown artifacts
63     getdown_app_dir = getdown_app_dir_alt
64     buildProperties = jalviewDir + "/" + classesDir +"/" + buildPropertiesFile
65     break
66
67     case "RELEASE":
68     getdown_channel_name = CHANNEL.toLowerCase()
69     getdownDir = getdown_channel_name + "/" + JAVA_VERSION
70     getdown_app_base = getdown_channel_base + "/" + getdownDir
71     getdown_app_dir = getdown_app_dir_release
72     buildProperties = jalviewDir + "/" + classesDir +"/" + buildPropertiesFile
73     reportRsyncCommand = true
74     break
75
76     case "ARCHIVE":
77     getdown_channel_name = CHANNEL.toLowerCase()+"/"+JALVIEW_VERSION
78     getdownDir = getdown_channel_name + "/" + JAVA_VERSION
79     getdown_app_base = getdown_channel_base + "/" + getdownDir
80     getdown_app_dir = getdown_app_dir_alt
81     if (!file(ARCHIVEDIR+"/"+packageDir).exists()) {
82       print "Must provide an ARCHIVEDIR value to produce an archive distribution"
83       exit
84     } else {
85       packageDir = ARCHIVEDIR + "/" + packageDir
86       buildProperties = ARCHIVEDIR +"/" + classesDir + "/" + buildPropertiesFile
87       buildDist = false
88     }
89     reportRsyncCommand = true
90     break
91
92     case "ARCHIVELOCAL":
93     getdown_channel_name = "archive" + "/" + JALVIEW_VERSION
94     getdownDir = getdown_channel_name + "/" + JAVA_VERSION
95     getdown_app_base = file(getdownWebsiteDir).toURI().toString()
96     getdown_app_dir = getdown_app_dir_alt
97     if (!file(ARCHIVEDIR+"/"+packageDir).exists()) {
98       print "Must provide an ARCHIVEDIR value to produce an archive distribution"
99       exit
100     } else {
101       packageDir = ARCHIVEDIR + "/" + packageDir
102       buildProperties = ARCHIVEDIR +"/" + classesDir + "/" + buildPropertiesFile
103       buildDist = false
104     }
105     reportRsyncCommand = true
106     break
107
108     case "DEVELOP":
109     getdown_channel_name = CHANNEL.toLowerCase()
110     getdownDir = getdown_channel_name + "/" + JAVA_VERSION
111     getdown_app_base = getdown_channel_base + "/" + getdownDir
112     getdown_app_dir = getdown_app_dir_alt
113     buildProperties = jalviewDir + "/" + classesDir +"/" + buildPropertiesFile
114     reportRsyncCommand = true
115     break
116
117     case "TEST-RELEASE":
118     getdown_channel_name = CHANNEL.toLowerCase()
119     getdownDir = getdown_channel_name + "/" + JAVA_VERSION
120     getdown_app_base = getdown_channel_base + "/" + getdownDir
121     getdown_app_dir = getdown_app_dir_alt
122     buildProperties = jalviewDir + "/" + classesDir +"/" + buildPropertiesFile
123     reportRsyncCommand = true
124     break
125
126     case ~/^SCRATCH(|-[-\w]*)$/:
127     getdown_channel_name = CHANNEL
128     getdownDir = getdown_channel_name + "/" + JAVA_VERSION
129     getdown_app_base = getdown_channel_base + "/" + getdownDir
130     getdown_app_dir = getdown_app_dir_alt
131     buildProperties = jalviewDir + "/" + classesDir +"/" + buildPropertiesFile
132     reportRsyncCommand = true
133     break
134
135     case "LOCAL":
136     getdown_app_base = file(getdownWebsiteDir).toURI().toString()
137     getdown_app_dir = getdown_app_dir_alt
138     buildProperties = jalviewDir + "/" + classesDir +"/" + buildPropertiesFile
139     break
140
141     default: // something wrong specified
142     print("CHANNEL must be one of BUILD, RELEASE, ARCHIVE, DEVELOP, TEST-RELEASE, SCRATCH-..., LOCAL [default]")
143     exit
144     break
145
146   }
147
148   println("Using a "+CHANNEL+" profile. appbase="+getdown_app_base)
149   getdownAppDir = getdownWebsiteDir + '/' + getdown_app_dir
150   //getdownJ11libDir = getdownWebsiteDir + '/' + getdown_j11lib_dir
151   getdownResourceDir = getdownWebsiteDir + '/' + getdown_resource_dir
152   getdownInstallDir = getdownWebsiteDir + '/' + getdown_install_dir
153   getdownLauncher = jalviewDir + '/' + getdown_launcher
154   getdownFilesDir = jalviewDir + '/' + getdown_files_dir + '/' + JAVA_VERSION + '/'
155   getdownFilesInstallDir = getdownFilesDir+"/"+getdown_install_dir
156   modules_compileClasspath = fileTree(dir: "$jalviewDir/$j11modDir", include: ["*.jar"])
157   modules_runtimeClasspath = modules_compileClasspath
158   gitHash = ""
159   gitBranch = ""
160 }
161
162 def JAVA_INTEGER_VERSION
163 def additional_compiler_args = []
164 // these are getdown.txt properties defined dependent on the JAVA_VERSION
165 def getdown_alt_java_min_version
166 def getdown_alt_java_max_version
167 // this property is assigned below and expanded to multiple lines in the getdown task
168 def getdown_alt_multi_java_location
169 // this property is for the Java library used in eclipse
170 def eclipse_java_runtime_name
171 if (JAVA_VERSION.equals("1.8")) {
172   JAVA_INTEGER_VERSION = "8"
173   //libDir = j8libDir
174   libDir = j11libDir
175   libDistDir = j8libDir
176   compile_source_compatibility = 1.8
177   compile_target_compatibility = 1.8
178   getdown_alt_java_min_version = getdown_alt_java8_min_version
179   getdown_alt_java_max_version = getdown_alt_java8_max_version
180   getdown_alt_multi_java_location = getdown_alt_java8_txt_multi_java_location
181   eclipse_java_runtime_name = "JavaSE-1.8"
182 } else if (JAVA_VERSION.equals("11")) {
183   JAVA_INTEGER_VERSION = "11"
184   libDir = j11libDir
185   libDistDir = j11libDir
186   compile_source_compatibility = 11
187   compile_target_compatibility = 11
188   getdown_alt_java_min_version = getdown_alt_java11_min_version
189   getdown_alt_java_max_version = getdown_alt_java11_max_version
190   getdown_alt_multi_java_location = getdown_alt_java11_txt_multi_java_location
191   eclipse_java_runtime_name = "JavaSE-11"
192   additional_compiler_args += [
193   '--module-path', ext.modules_compileClasspath.asPath,
194   '--add-modules', j11modules
195   ]
196 } else if (JAVA_VERSION.equals("12") || JAVA_VERSION.equals("13")) {
197   JAVA_INTEGER_VERSION = JAVA_VERSION
198   libDir = j11libDir
199   libDistDir = j11libDir
200   compile_source_compatibility = JAVA_VERSION
201   compile_target_compatibility = JAVA_VERSION
202   getdown_alt_java_min_version = getdown_alt_java11_min_version
203   getdown_alt_java_max_version = getdown_alt_java11_max_version
204   getdown_alt_multi_java_location = getdown_alt_java11_txt_multi_java_location
205   eclipse_java_runtime_name = "JavaSE-11"
206   additional_compiler_args += [
207   '--module-path', ext.modules_compileClasspath.asPath,
208   '--add-modules', j11modules
209   ]
210 } else {
211   throw new GradleException("JAVA_VERSION=$JAVA_VERSION not currently supported by Jalview")
212 }
213
214 sourceSets {
215
216   main {
217     java {
218       srcDirs "$jalviewDir/$sourceDir"
219       outputDir = file("$classes")
220     }
221
222     resources {
223       srcDirs "$jalviewDir/$resourceDir"
224     }
225
226     jar.destinationDir = file("$jalviewDir/$packageDir")
227
228     compileClasspath = files(sourceSets.main.java.outputDir)
229     compileClasspath += fileTree(dir: "$jalviewDir/$libDir", include: ["*.jar"])
230
231     runtimeClasspath = compileClasspath
232   }
233   clover {
234     java {
235       srcDirs = [ cloverInstrDir ]
236       outputDir = file("${buildDir}/${cloverClassesDir}")
237     }
238
239     resources {
240       srcDirs = sourceSets.main.resources.srcDirs
241     }
242     compileClasspath = configurations.cloverRuntime + files( sourceSets.clover.java.outputDir )
243     compileClasspath += files(sourceSets.main.java.outputDir)
244     compileClasspath += sourceSets.main.compileClasspath
245     compileClasspath += fileTree(dir: "$jalviewDir/$utilsDir", include: ["**/*.jar"])
246     compileClasspath += fileTree(dir: "$jalviewDir/$libDir", include: ["*.jar"])
247
248     runtimeClasspath = compileClasspath
249   }
250
251   test {
252     java {
253       srcDirs "$jalviewDir/$testSourceDir"
254       outputDir = file("$jalviewDir/$testOutputDir")
255     }
256
257     resources {
258       srcDirs = sourceSets.main.resources.srcDirs
259     }
260
261     compileClasspath = files( sourceSets.test.java.outputDir )
262
263     if (use_clover) {
264       compileClasspath += sourceSets.clover.compileClasspath
265     } else {
266       compileClasspath += files(sourceSets.main.java.outputDir)
267     }
268
269     compileClasspath += fileTree(dir: "$jalviewDir/$utilsDir", include: ["**/*.jar"])
270     compileClasspath += fileTree(dir: "$jalviewDir/$libDir", include: ["*.jar"])
271
272     runtimeClasspath = compileClasspath
273   }
274 }
275
276 // clover bits
277 dependencies {
278   if (use_clover) {
279     cloverCompile 'org.openclover:clover:4.3.1'
280     testCompile 'org.openclover:clover:4.3.1'
281   }
282 }
283
284 configurations {
285   cloverRuntime
286   cloverRuntime.extendsFrom cloverCompile
287 }
288
289 eclipse {
290   project {
291     name = "Jalview with gradle build"
292
293     natures 'org.eclipse.jdt.core.javanature',
294     'org.eclipse.jdt.groovy.core.groovyNature',
295     'org.eclipse.buildship.core.gradleprojectnature'
296
297     buildCommand 'org.eclipse.jdt.core.javabuilder'
298     buildCommand 'org.eclipse.buildship.core.gradleprojectbuilder'
299   }
300
301   classpath {
302     //defaultOutputDir = sourceSets.main.java.outputDir
303     def removeThese = []
304     configurations.each{ if (it.isCanBeResolved()) {
305       removeThese += it
306     }
307   }
308
309   minusConfigurations += removeThese
310   plusConfigurations = [ ]
311   file {
312
313     whenMerged { cp ->
314       def removeTheseToo = []
315       HashMap<String, Boolean> addedSrcPath = new HashMap<>();
316       cp.entries.each { entry ->
317         if (entry.kind == 'src') {
318           if (addedSrcPath.getAt(entry.path) || !(entry.path == "src" || entry.path == "test")) {
319             removeTheseToo += entry
320           } else {
321             addedSrcPath.putAt(entry.path, true)
322           }
323         }
324       }
325       cp.entries.removeAll(removeTheseToo)
326
327       print ("CP="+cp.inspect())
328
329       cp.entries += new Output("bin/main")
330       cp.entries += new Library(fileReference(helpParentDir))
331       cp.entries += new Library(fileReference(resourceDir))
332
333       HashMap<String, Boolean> addedLibPath = new HashMap<>();
334
335       // changing from sourcesets.main.classpath to specific Java version lib
336       //sourceSets.main.compileClasspath.each{
337       fileTree("$jalviewDir/$libDistDir").include("**/*.jar").include("*.jar").each {
338         //don't want to add outputDir as eclipse is using its own output dir in bin/main
339         if (it.isDirectory() || ! it.exists()) {
340           // don't add dirs to classpath
341           return
342         }
343         def itPath = it.toString()
344         if (itPath.startsWith(jalviewDirAbsolutePath+"/")) {
345           itPath = itPath.substring(jalviewDirAbsolutePath.length()+1)
346         }
347         if (addedLibPath.get(itPath)) {
348           //println("Not adding duplicate entry "+itPath)
349         } else {
350           //println("Adding entry "+itPath)
351           cp.entries += new Library(fileReference(itPath))
352           addedLibPath.put(itPath, true)
353         }
354       }
355
356       // changing from sourcesets.main.classpath to specific Java version lib
357       //sourceSets.test.compileClasspath.each{
358       fileTree(dir: "$jalviewDir/$utilsDir", include: ["**/*.jar"]).each {
359         //if ((it.isDirectory() || ! it.exists()) && ! (it.equals(sourceSets.main.java.outputDir))) {
360         //no longer want to add outputDir as eclipse is using its own output dir in bin/main
361         if (it.isDirectory() || ! it.exists()) {
362           // don't add dirs to classpath
363           return false // groovy "break" in .each loop
364         }
365         def itPath = it.toString()
366         if (itPath.startsWith(jalviewDirAbsolutePath+"/")) {
367           itPath = itPath.substring(jalviewDirAbsolutePath.length()+1)
368         }
369         if (addedLibPath.get(itPath)) {
370           // don't duplicate
371         } else {
372           def lib = new Library(fileReference(itPath))
373           // this doesn't work... yet.  Adding test=true attribute using withXml below
374           //def attrs = new Node(null, 'attributes', ["test":"true"])
375           //lib.appendNode(attrs) //
376           cp.entries += lib
377           addedLibPath.put(itPath, true)
378         }
379         }
380       }
381
382       // withXml changes ignored by buildship, these add the "test=true" attribute
383       withXml {
384         def node = it.asNode()
385
386         def srcTestAttributes
387         node.children().each{ cpe ->
388           def attributes = cpe.attributes()
389           if (attributes.get("kind") == "src" && attributes.get("path") == "test") {
390             srcTestAttributes = cpe.find { a -> a.name() == "attributes" }
391             return
392           }
393         }
394         def addTestAttribute = true
395         srcTestAttributes.each{a ->
396           if (a.name() == "attribute" && a.attributes().getAt("name") == "test") {
397             addTestAttribute = false
398           }
399         }
400         if (addTestAttribute) {
401           srcTestAttributes.append(new Node(null, "attribute", [name:"test", value:"true"]))
402         }
403
404         node.children().each{ cpe ->
405           def attributes = cpe.attributes()
406           if (attributes.get("kind") == "lib" && attributes.get("path").startsWith("utils/")) {
407             cpe.appendNode('attributes')
408             .appendNode('attribute', [name:"test", value:"true"])
409           }
410         }
411       } // withXML
412     } // file
413
414     containers 'org.eclipse.buildship.core.gradleclasspathcontainer'
415   } // classpath
416
417   jdt {
418     // for the IDE, use java 11 compatibility
419     sourceCompatibility = compile_source_compatibility
420     targetCompatibility = compile_target_compatibility
421     javaRuntimeName = eclipse_java_runtime_name
422
423     file {
424       withProperties { props ->
425         def jalview_prefs = new Properties()
426         def ins = new FileInputStream(jalviewDirAbsolutePath+"/"+eclipse_extra_jdt_prefs_file)
427         jalview_prefs.load(ins)
428         ins.close()
429         jalview_prefs.forEach { t, v ->
430           if (props.getAt(t) == null) {
431             props.putAt(t, v)
432           }
433         }
434       }
435     }
436   }
437
438   //synchronizationTasks eclipseClasspath
439   //autoBuildTasks eclipseClasspath
440 }
441
442 task cloverInstr() {
443   // only instrument source, we build test classes as normal
444   inputs.files files (sourceSets.main.allJava) // , fileTree(dir:"$jalviewDir/$testSourceDir", include: ["**/*.java"]))
445   outputs.dir cloverInstrDir
446
447   doFirst {
448     delete cloverInstrDir
449     def argsList = ["--initstring", "${buildDir}/clover/clover.db",
450     "-d", "${buildDir}/${cloverSourcesInstrDir}"]
451     argsList.addAll(inputs.files.files.collect({ file ->
452       file.absolutePath
453     }))
454     String[] args = argsList.toArray()
455     println("About to instrument "+args.length +" files")
456     com.atlassian.clover.CloverInstr.mainImpl(args)
457   }
458 }
459
460
461 task cloverReport {
462   group = "Verification"
463     description = "Createst the Clover report"
464     inputs.dir "${buildDir}/clover"
465     outputs.dir "${reportsDir}/clover"
466     onlyIf {
467       file("${buildDir}/clover/clover.db").exists()
468     }
469   doFirst {
470     def argsList = ["--initstring", "${buildDir}/clover/clover.db",
471     "-o", "${reportsDir}/clover"]
472     String[] args = argsList.toArray()
473     com.atlassian.clover.reporters.html.HtmlReporter.runReport(args)
474
475     // and generate ${reportsDir}/clover/clover.xml
476     args = ["--initstring", "${buildDir}/clover/clover.db",
477     "-o", "${reportsDir}/clover/clover.xml"].toArray()
478     com.atlassian.clover.reporters.xml.XMLReporter.runReport(args)
479   }
480 }
481
482 // end clover bits
483
484
485 compileJava {
486
487   doFirst {
488     sourceCompatibility = compile_source_compatibility
489     targetCompatibility = compile_target_compatibility
490     options.compilerArgs = additional_compiler_args
491     print ("Setting target compatibility to "+targetCompatibility+"\n")
492   }
493
494 }
495
496 compileTestJava {
497   if (use_clover) {
498     dependsOn compileCloverJava
499     classpath += configurations.cloverRuntime
500   } else {
501     classpath += sourceSets.main.runtimeClasspath
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 }
510
511
512 compileCloverJava {
513
514   doFirst {
515     sourceCompatibility = compile_source_compatibility
516     targetCompatibility = compile_target_compatibility
517     options.compilerArgs += additional_compiler_args
518     print ("Setting target compatibility to "+targetCompatibility+"\n")
519   }
520   classpath += configurations.cloverRuntime
521 }
522
523 clean {
524   delete sourceSets.main.java.outputDir
525 }
526
527 cleanTest {
528   delete sourceSets.test.java.outputDir
529   delete cloverInstrDir
530 }
531
532 // format is a string like date.format("dd MMMM yyyy")
533 def getDate(format) {
534   def date = new Date()
535   return date.format(format)
536 }
537
538 task setGitVals {
539   def hashStdOut = new ByteArrayOutputStream()
540   exec {
541     commandLine "git", "rev-parse", "--short", "HEAD"
542     standardOutput = hashStdOut
543     ignoreExitValue true
544   }
545
546   def branchStdOut = new ByteArrayOutputStream()
547   exec {
548     commandLine "git", "rev-parse", "--abbrev-ref", "HEAD"
549     standardOutput = branchStdOut
550     ignoreExitValue true
551   }
552
553   project.ext.gitHash = hashStdOut.toString().trim()
554   project.ext.gitBranch = branchStdOut.toString().trim()
555
556   outputs.upToDateWhen { false }
557 }
558
559 task createBuildProperties(type: WriteProperties) {
560   dependsOn setGitVals
561   inputs.dir("$jalviewDir/$sourceDir")
562   inputs.dir("$classes")
563   inputs.dir("$jalviewDir/$resourceDir")
564   outputFile (buildProperties)
565   // taking time specific comment out to allow better incremental builds
566   comment "--Jalview Build Details--\n"+getDate("yyyy-MM-dd HH:mm:ss")
567   //comment "--Jalview Build Details--\n"+getDate("yyyy-MM-dd")
568   property "BUILD_DATE", getDate("HH:mm:ss dd MMMM yyyy")
569   property "VERSION", JALVIEW_VERSION
570   property "INSTALLATION", INSTALLATION+" git-commit:"+project.ext.gitHash+" ["+project.ext.gitBranch+"]"
571   outputs.file(outputFile)
572 }
573
574 def buildingHTML = "$jalviewDir/$docDir/building.html"
575 task deleteBuildingHTML(type: Delete) {
576   delete buildingHTML
577 }
578
579 task convertBuildingMD(type: Exec) {
580   dependsOn deleteBuildingHTML
581   def buildingMD = "$jalviewDir/$docDir/building.md"
582   def css = "$jalviewDir/$docDir/github.css"
583
584   def pandoc = null
585   pandoc_exec.split(",").each {
586     if (file(it.trim()).exists()) {
587       pandoc = it.trim()
588       return true
589     }
590   }
591
592   def hostname = "hostname".execute().text.trim()
593   if ((pandoc == null || ! file(pandoc).exists()) && hostname.equals("jv-bamboo")) {
594     pandoc = System.getProperty("user.home")+"/buildtools/pandoc/bin/pandoc"
595   }
596
597   if (pandoc != null && file(pandoc).exists()) {
598     commandLine pandoc, '-s', '-o', buildingHTML, '--metadata', 'pagetitle="Building Jalview from Source"', '--toc', '-H', css, buildingMD
599   } else {
600     commandLine "true"
601   }
602
603   ignoreExitValue true
604
605   inputs.file(buildingMD)
606   inputs.file(css)
607   outputs.file(buildingHTML)
608 }
609 clean {
610   delete buildingHTML
611 }
612
613 task syncDocs(type: Sync) {
614   dependsOn convertBuildingMD
615   def syncDir = "$classes/$docDir"
616   from fileTree("$jalviewDir/$docDir")
617   into syncDir
618
619 }
620
621 def helpFile = "$classes/$helpDir/help.jhm"
622
623 task copyHelp(type: Copy) {
624   def inputDir = "$jalviewDir/$helpParentDir/$helpDir"
625   def outputDir = "$classes/$helpDir"
626   from(inputDir) {
627     exclude '**/*.gif'
628       exclude '**/*.jpg'
629       exclude '**/*.png'
630       filter(ReplaceTokens, beginToken: '$$', endToken: '$$', tokens: ['Version-Rel': JALVIEW_VERSION])
631   }
632   from(inputDir) {
633     include '**/*.gif'
634       include '**/*.jpg'
635       include '**/*.png'
636   }
637   into outputDir
638
639   inputs.dir(inputDir)
640   outputs.files(helpFile)
641   outputs.dir(outputDir)
642 }
643
644 task syncLib(type: Sync) {
645   def syncDir = "$classes/$libDistDir"
646   from fileTree("$jalviewDir/$libDistDir")
647   into syncDir
648 }
649
650 task syncResources(type: Sync) {
651   from "$jalviewDir/$resourceDir"
652   include "**/*.*"
653   exclude "install4j"
654   into "$classes"
655   preserve {
656     include "**"
657   }
658 }
659
660 task prepare {
661   dependsOn syncResources
662   dependsOn syncDocs
663   dependsOn copyHelp
664 }
665
666
667 //testReportDirName = "test-reports" // note that test workingDir will be $jalviewDir
668 test {
669   dependsOn prepare
670   dependsOn compileJava
671   if (use_clover) {
672     dependsOn cloverInstr
673   }
674
675   if (use_clover) {
676     print("Running tests " + (use_clover?"WITH":"WITHOUT") + " clover [clover="+use_clover+"]\n")
677   }
678
679   useTestNG() {
680     includeGroups testngGroups
681     preserveOrder true
682     useDefaultListeners=true
683   }
684
685   workingDir = jalviewDir
686   //systemProperties 'clover.jar' System.properties.clover.jar
687   sourceCompatibility = compile_source_compatibility
688   targetCompatibility = compile_target_compatibility
689   jvmArgs += additional_compiler_args
690   print ("Setting target compatibility to "+targetCompatibility+"\n")
691 }
692
693 task buildIndices(type: JavaExec) {
694   dependsOn copyHelp
695   classpath = sourceSets.main.compileClasspath
696   main = "com.sun.java.help.search.Indexer"
697   workingDir = "$classes/$helpDir"
698   def argDir = "html"
699   args = [ argDir ]
700   inputs.dir("$workingDir/$argDir")
701
702   outputs.dir("$classes/doc")
703   outputs.dir("$classes/help")
704   outputs.file("$workingDir/JavaHelpSearch/DOCS")
705   outputs.file("$workingDir/JavaHelpSearch/DOCS.TAB")
706   outputs.file("$workingDir/JavaHelpSearch/OFFSETS")
707   outputs.file("$workingDir/JavaHelpSearch/POSITIONS")
708   outputs.file("$workingDir/JavaHelpSearch/SCHEMA")
709   outputs.file("$workingDir/JavaHelpSearch/TMAP")
710 }
711
712 task compileLinkCheck(type: JavaCompile) {
713   options.fork = true
714   classpath = files("$jalviewDir/$utilsDir")
715   destinationDir = file("$jalviewDir/$utilsDir")
716   source = fileTree(dir: "$jalviewDir/$utilsDir", include: ["HelpLinksChecker.java", "BufferedLineReader.java"])
717
718   inputs.file("$jalviewDir/$utilsDir/HelpLinksChecker.java")
719   inputs.file("$jalviewDir/$utilsDir/HelpLinksChecker.java")
720   outputs.file("$jalviewDir/$utilsDir/HelpLinksChecker.class")
721   outputs.file("$jalviewDir/$utilsDir/BufferedLineReader.class")
722 }
723
724 def helplinkscheckertouchfile = file("$jalviewDir/$utilsDir/HelpLinksChecker.touch")
725 task linkCheck(type: JavaExec) {
726   dependsOn prepare, compileLinkCheck
727   classpath = files("$jalviewDir/$utilsDir")
728   main = "HelpLinksChecker"
729   workingDir = jalviewDir
730   def help = "$classes/$helpDir"
731   args = [ "$classes/$helpDir", "-nointernet" ]
732
733   doLast {
734     helplinkscheckertouchfile.createNewFile()
735   }
736
737   inputs.dir("$classes/$helpDir")
738   outputs.file(helplinkscheckertouchfile)
739 }
740
741 task cleanPackageDir(type: Delete) {
742   delete fileTree("$jalviewDir/$packageDir").include("*.jar")
743 }
744
745 jar {
746   dependsOn linkCheck
747   dependsOn buildIndices
748   dependsOn createBuildProperties
749
750   manifest {
751     attributes "Main-Class": mainClass,
752     "Permissions": "all-permissions",
753     "Application-Name": "Jalview Desktop",
754     "Codebase": application_codebase
755   }
756
757   destinationDir = file("$jalviewDir/$packageDir")
758   archiveName = rootProject.name+".jar"
759
760   exclude "cache*/**"
761   exclude "*.jar"
762   exclude "*.jar.*"
763   exclude "**/*.jar"
764   exclude "**/*.jar.*"
765
766   inputs.dir("$classes")
767   outputs.file("$jalviewDir/$packageDir/$archiveName")
768 }
769
770 task copyJars(type: Copy) {
771   from fileTree("$classes").include("**/*.jar").include("*.jar").files
772   into "$jalviewDir/$packageDir"
773 }
774
775 // doing a Sync instead of Copy as Copy doesn't deal with "outputs" very well
776 task syncJars(type: Sync) {
777   from fileTree("$jalviewDir/$libDistDir").include("**/*.jar").include("*.jar").files
778   into "$jalviewDir/$packageDir"
779   preserve {
780     include jar.archiveName
781   }
782 }
783
784 task makeDist {
785   group = "build"
786   description = "Put all required libraries in dist"
787   // order of "cleanPackageDir", "copyJars", "jar" important!
788   jar.mustRunAfter cleanPackageDir
789   syncJars.mustRunAfter cleanPackageDir
790   dependsOn cleanPackageDir
791   dependsOn syncJars
792   dependsOn jar
793   outputs.dir("$jalviewDir/$packageDir")
794 }
795
796 task cleanDist {
797   dependsOn cleanPackageDir
798   dependsOn cleanTest
799   dependsOn clean
800 }
801
802 shadowJar {
803   group = "distribution"
804   if (buildDist) {
805     dependsOn makeDist
806   }
807   from ("$jalviewDir/$libDistDir") {
808     include("*.jar")
809   }
810   manifest {
811     attributes 'Implementation-Version': JALVIEW_VERSION
812   }
813   mainClassName = shadowJarMainClass
814   mergeServiceFiles()
815   classifier = "all-"+JALVIEW_VERSION+"-j"+JAVA_VERSION
816   minimize()
817 }
818
819 task getdownWebsite() {
820   group = "distribution"
821   description = "Create the getdown minimal app folder, and website folder for this version of jalview. Website folder also used for offline app installer"
822   if (buildDist) {
823     dependsOn makeDist
824   }
825
826         // clean the getdown website and files dir before creating getdown folders
827         delete project.ext.getdownWebsiteDir
828         delete project.ext.getdownFilesDir
829
830   def getdownWebsiteResourceFilenames = []
831   def getdownTextString = ""
832   def getdownResourceDir = project.ext.getdownResourceDir
833   def getdownAppDir = project.ext.getdownAppDir
834   def getdownResourceFilenames = []
835
836   doFirst {
837     copy {
838       from buildProperties
839       rename(buildPropertiesFile, getdown_build_properties)
840       into project.ext.getdownAppDir
841     }
842     getdownWebsiteResourceFilenames += getdown_app_dir+"/"+getdown_build_properties
843
844     // go through properties looking for getdown_txt_...
845     def props = project.properties.sort { it.key }
846         if (getdown_alt_java_min_version.length() > 0) {
847                 props.put("getdown_txt_java_min_version", getdown_alt_java_min_version)
848         }
849         if (getdown_alt_java_max_version.length() > 0) {
850                 props.put("getdown_txt_java_max_version", getdown_alt_java_max_version)
851         }
852         props.put("getdown_txt_multi_java_location", getdown_alt_multi_java_location)
853
854     props.put("getdown_txt_appbase", getdown_app_base)
855     props.each{ prop, val ->
856       if (prop.startsWith("getdown_txt_") && val != null) {
857         if (prop.startsWith("getdown_txt_multi_")) {
858           def key = prop.substring(18)
859           val.split(",").each{ v ->
860             def line = key + " = " + v + "\n"
861             getdownTextString += line
862           }
863         } else {
864           // file values rationalised
865           if (val.indexOf('/') > -1 || prop.startsWith("getdown_txt_resource")) {
866             def r = null
867             if (val.indexOf('/') == 0) {
868               // absolute path
869               r = file(val)
870             } else if (val.indexOf('/') > 0) {
871               // relative path (relative to jalviewDir)
872               r = file( jalviewDir + '/' + val )
873             }
874             if (r.exists()) {
875               val = getdown_resource_dir + '/' + r.getName()
876               getdownWebsiteResourceFilenames += val
877               getdownResourceFilenames += r.getPath()
878             }
879           }
880           if (! prop.startsWith("getdown_txt_resource")) {
881             def line = prop.substring(12) + " = " + val + "\n"
882             getdownTextString += line
883           }
884         }
885       }
886     }
887
888     getdownWebsiteResourceFilenames.each{ filename ->
889       getdownTextString += "resource = "+filename+"\n"
890     }
891     getdownResourceFilenames.each{ filename ->
892       copy {
893         from filename
894         into project.ext.getdownResourceDir
895       }
896     }
897
898     def codeFiles = []
899     fileTree(file(packageDir)).each{ f ->
900       if (f.isDirectory()) {
901         def files = fileTree(dir: f, include: ["*"]).getFiles()
902         codeFiles += files
903       } else if (f.exists()) {
904         codeFiles += f
905       }
906     }
907     codeFiles.sort().each{f ->
908       def line = "code = " + getdown_app_dir + '/' + f.getName() + "\n"
909       getdownTextString += line
910       copy {
911         from f.getPath()
912         into project.ext.getdownAppDir
913       }
914     }
915
916     // NOT USING MODULES YET, EVERYTHING SHOULD BE IN dist
917     /*
918     if (JAVA_VERSION.equals("11")) {
919     def j11libFiles = fileTree(dir: "$jalviewDir/$j11libDir", include: ["*.jar"]).getFiles()
920     j11libFiles.sort().each{f ->
921     def line = "code = " + getdown_j11lib_dir + '/' + f.getName() + "\n"
922     getdownTextString += line
923     copy {
924     from f.getPath()
925     into project.ext.getdownJ11libDir
926     }
927     }
928     }
929      */
930
931     // 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.
932     //getdownTextString += "class = " + file(getdownLauncher).getName() + "\n"
933     getdownTextString += "resource = " + getdown_launcher_new + "\n"
934     getdownTextString += "class = " + mainClass + "\n"
935
936     def getdown_txt = file(project.ext.getdownWebsiteDir + "/getdown.txt")
937     getdown_txt.write(getdownTextString)
938
939     def launch_jvl = file(project.ext.getdownWebsiteDir + "/" + getdown_launch_jvl)
940     launch_jvl.write("appbase="+props.get("getdown_txt_appbase"))
941
942     copy {
943       from getdownLauncher
944       rename(file(getdownLauncher).getName(), getdown_launcher_new)
945       into project.ext.getdownWebsiteDir
946     }
947
948     copy {
949       from getdownLauncher
950       into project.ext.getdownWebsiteDir
951     }
952
953     if (! (CHANNEL.startsWith("ARCHIVE") || CHANNEL.startsWith("DEVELOP"))) {
954       copy {
955         from getdown_txt
956         from getdownLauncher
957         from getdownWebsiteDir+"/"+getdown_build_properties
958         into getdownInstallDir
959       }
960
961       copy {
962         from getdownInstallDir
963         into getdownFilesInstallDir
964       }
965     }
966
967     copy {
968       from getdown_txt
969       from launch_jvl
970       from getdownLauncher
971       from getdownWebsiteDir+"/"+getdown_build_properties
972       into getdownFilesDir
973     }
974
975     copy {
976           from getdownResourceDir
977       into project.ext.getdownFilesDir + '/' + getdown_resource_dir
978     }
979   }
980
981   if (buildDist) {
982     inputs.dir(jalviewDir + '/' + packageDir)
983   }
984   outputs.dir(project.ext.getdownWebsiteDir)
985   outputs.dir(project.ext.getdownFilesDir)
986 }
987
988 task getdownDigest(type: JavaExec) {
989   group = "distribution"
990   description = "Digest the getdown website folder"
991   dependsOn getdownWebsite
992   classpath = files(jalviewDir + '/' + getdown_core, jalviewDir+'/'+getdown_launcher)
993   main = "com.threerings.getdown.tools.Digester"
994   args project.ext.getdownWebsiteDir
995   inputs.dir(project.ext.getdownWebsiteDir)
996   outputs.file(project.ext.getdownWebsiteDir + '/' + "digest2.txt")
997 }
998
999 task getdown() {
1000   group = "distribution"
1001   description = "Create the minimal and full getdown app folder for installers and website and create digest file"
1002   dependsOn getdownDigest
1003   doLast {
1004     if (reportRsyncCommand) {
1005       def fromDir = getdownWebsiteDir + (getdownWebsiteDir.endsWith("/")?"":"/")
1006       def toDir = getdown_rsync_dest + "/" + getdownDir + (getdownDir.endsWith("/")?"":"/")
1007       println "LIKELY RSYNC COMMAND:"
1008       println "mkdir -p '$toDir'\nrsync -avh --delete '$fromDir' '$toDir'"
1009       if (RUNRSYNC == "true") {
1010         exec {
1011           commandLine "mkdir", "-p", toDir
1012         }
1013         exec {
1014           commandLine "rsync", "-avh", "--delete", fromDir, toDir
1015         }
1016       }
1017     }
1018   }
1019 }
1020
1021 clean {
1022   delete project.ext.getdownWebsiteDir
1023   delete project.ext.getdownFilesDir
1024 }
1025
1026 install4j {
1027   def install4jHomeDir = "/opt/install4j"
1028   def hostname = "hostname".execute().text.trim()
1029   if (hostname.equals("jv-bamboo")) {
1030     install4jHomeDir = System.getProperty("user.home")+"/buildtools/install4j"
1031   } else if (OperatingSystem.current().isMacOsX()) {
1032     install4jHomeDir = '/Applications/install4j.app/Contents/Resources/app'
1033     if (! file(install4jHomeDir).exists()) {
1034       install4jHomeDir = System.getProperty("user.home")+install4jHomeDir
1035     }
1036   } else if (OperatingSystem.current().isLinux()) {
1037     install4jHomeDir = System.getProperty("user.home")+"/buildtools/install4j"
1038   }
1039   installDir = file(install4jHomeDir)
1040   mediaTypes = Arrays.asList(install4jMediaTypes.split(","))
1041   if (install4jFaster.equals("true")) {
1042     faster = true
1043   }
1044 }
1045
1046 def install4jConf
1047 def macosJavaVMDir
1048 def macosJavaVMTgz
1049 def windowsJavaVMDir
1050 def windowsJavaVMTgz
1051 def install4jDir = "$jalviewDir/$install4jResourceDir"
1052 def install4jConfFile = "jalview-installers-java"+JAVA_VERSION+".install4j"
1053 install4jConf = "$install4jDir/$install4jConfFile"
1054
1055 task copyInstall4jTemplate(type: Copy) {
1056   macosJavaVMDir = System.env.HOME+"/buildtools/jre/openjdk-java_vm/getdown/macos-jre"+JAVA_VERSION+"/jre"
1057   macosJavaVMTgz = System.env.HOME+"/buildtools/jre/openjdk-java_vm/install4j/tgz/macos-jre"+JAVA_VERSION+".tar.gz"
1058   windowsJavaVMDir = System.env.HOME+"/buildtools/jre/openjdk-java_vm/getdown/windows-jre"+JAVA_VERSION+"/jre"
1059   windowsJavaVMTgz = System.env.HOME+"/buildtools/jre/openjdk-java_vm/install4j/tgz/windows-jre"+JAVA_VERSION+".tar.gz"
1060   from (install4jDir) {
1061     include install4jTemplate
1062     rename (install4jTemplate, install4jConfFile)
1063     filter(ReplaceTokens, beginToken: '', endToken: '', tokens: ['9999999999': JAVA_VERSION])
1064     filter(ReplaceTokens, beginToken: '$$', endToken: '$$',
1065     tokens: [
1066     'JAVA_VERSION': JAVA_VERSION,
1067     'JAVA_INTEGER_VERSION': JAVA_INTEGER_VERSION,
1068     'VERSION': JALVIEW_VERSION,
1069     'MACOS_JAVA_VM_DIR': macosJavaVMDir,
1070     'MACOS_JAVA_VM_TGZ': macosJavaVMTgz,
1071     'WINDOWS_JAVA_VM_DIR': windowsJavaVMDir,
1072     'WINDOWS_JAVA_VM_TGZ': windowsJavaVMTgz,
1073     'INSTALL4JINFOPLISTFILEASSOCIATIONS': install4jInfoPlistFileAssociations,
1074     'COPYRIGHT_MESSAGE': install4jCopyrightMessage,
1075     'MACOS_BUNDLE_ID': install4jMacOSBundleId,
1076     'GETDOWN_RESOURCE_DIR': getdown_resource_dir,
1077     'GETDOWN_DIST_DIR': getdown_app_dir,
1078     'GETDOWN_ALT_DIR': getdown_app_dir_alt,
1079     'GETDOWN_INSTALL_DIR': getdown_install_dir
1080     ]
1081     )
1082     if (OSX_KEYPASS=="") {
1083       filter(ReplaceTokens, beginToken: 'codeSigning macEnabled="', endToken: '"', tokens: ['true':'codeSigning macEnabled="false"'])
1084       filter(ReplaceTokens, beginToken: 'runPostProcessor="true" ',endToken: 'Processor', tokens: ['post':'runPostProcessor="false" postProcessor'])
1085     }
1086   }
1087   into install4jDir
1088   outputs.files(install4jConf)
1089
1090   doLast {
1091     // include file associations in installer
1092     def installerFileAssociationsXml = file("$install4jDir/$install4jInstallerFileAssociations").text
1093     ant.replaceregexp(
1094       byline: false,
1095       flags: "s",
1096       match: '<action name="EXTENSIONS_REPLACED_BY_GRADLE".*?</action>',
1097       replace: installerFileAssociationsXml,
1098       file: install4jConf
1099     )
1100     /*
1101     // include uninstaller applescript app files in dmg
1102     def installerDMGUninstallerXml = file("$install4jDir/$install4jDMGUninstallerAppFiles").text
1103     ant.replaceregexp(
1104     byline: false,
1105     flags: "s",
1106     match: '<file name="UNINSTALL_OLD_JALVIEW_APP_REPLACED_IN_GRADLE" file=.*?>',
1107     replace: installerDMGUninstallerXml,
1108     file: install4jConf
1109     )
1110      */
1111   }
1112 }
1113
1114 task installers(type: com.install4j.gradle.Install4jTask) {
1115   group = "distribution"
1116   description = "Create the install4j installers"
1117   dependsOn getdown
1118   dependsOn copyInstall4jTemplate
1119   projectFile = file(install4jConf)
1120   println("Using projectFile "+projectFile)
1121   variables = [majorVersion: version.substring(2, 11), build: 001, OSX_KEYSTORE: OSX_KEYSTORE, JSIGN_SH: JSIGN_SH]
1122   destination = "$jalviewDir/$install4jBuildDir/$JAVA_VERSION"
1123   buildSelected = true
1124
1125   if (OSX_KEYPASS) {
1126     macKeystorePassword=OSX_KEYPASS
1127
1128   }
1129
1130   inputs.dir(project.ext.getdownWebsiteDir)
1131   inputs.file(install4jConf)
1132   inputs.dir(macosJavaVMDir)
1133   inputs.dir(windowsJavaVMDir)
1134   outputs.dir("$jalviewDir/$install4jBuildDir/$JAVA_VERSION")
1135
1136 }
1137
1138 clean {
1139   delete install4jConf
1140 }
1141