JAL-3332 Sensible default timeout values for network connections (8s connect_timeout...
[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   doFirst {
598     if (pandoc != null && file(pandoc).exists()) {
599         commandLine pandoc, '-s', '-o', buildingHTML, '--metadata', 'pagetitle="Building Jalview from Source"', '--toc', '-H', css, buildingMD
600     } else {
601         println("Cannot find pandoc. Skipping convert building.md to HTML")
602         throw new StopExecutionException()
603     }
604   }
605
606   ignoreExitValue true
607
608   inputs.file(buildingMD)
609   inputs.file(css)
610   outputs.file(buildingHTML)
611 }
612 clean {
613   delete buildingHTML
614 }
615
616 task syncDocs(type: Sync) {
617   dependsOn convertBuildingMD
618   def syncDir = "$classes/$docDir"
619   from fileTree("$jalviewDir/$docDir")
620   into syncDir
621
622 }
623
624 def helpFile = "$classes/$helpDir/help.jhm"
625
626 task copyHelp(type: Copy) {
627   def inputDir = "$jalviewDir/$helpParentDir/$helpDir"
628   def outputDir = "$classes/$helpDir"
629   from(inputDir) {
630     exclude '**/*.gif'
631       exclude '**/*.jpg'
632       exclude '**/*.png'
633       filter(ReplaceTokens, beginToken: '$$', endToken: '$$', tokens: ['Version-Rel': JALVIEW_VERSION])
634   }
635   from(inputDir) {
636     include '**/*.gif'
637       include '**/*.jpg'
638       include '**/*.png'
639   }
640   into outputDir
641
642   inputs.dir(inputDir)
643   outputs.files(helpFile)
644   outputs.dir(outputDir)
645 }
646
647 task syncLib(type: Sync) {
648   def syncDir = "$classes/$libDistDir"
649   from fileTree("$jalviewDir/$libDistDir")
650   into syncDir
651 }
652
653 task syncResources(type: Sync) {
654   from "$jalviewDir/$resourceDir"
655   include "**/*.*"
656   exclude "install4j"
657   into "$classes"
658   preserve {
659     include "**"
660   }
661 }
662
663 task prepare {
664   dependsOn syncResources
665   dependsOn syncDocs
666   dependsOn copyHelp
667 }
668
669
670 //testReportDirName = "test-reports" // note that test workingDir will be $jalviewDir
671 test {
672   dependsOn prepare
673   dependsOn compileJava
674   if (use_clover) {
675     dependsOn cloverInstr
676   }
677
678   if (use_clover) {
679     print("Running tests " + (use_clover?"WITH":"WITHOUT") + " clover [clover="+use_clover+"]\n")
680   }
681
682   useTestNG() {
683     includeGroups testngGroups
684     preserveOrder true
685     useDefaultListeners=true
686   }
687
688   workingDir = jalviewDir
689   //systemProperties 'clover.jar' System.properties.clover.jar
690   sourceCompatibility = compile_source_compatibility
691   targetCompatibility = compile_target_compatibility
692   jvmArgs += additional_compiler_args
693   print ("Setting target compatibility to "+targetCompatibility+"\n")
694 }
695
696 task buildIndices(type: JavaExec) {
697   dependsOn copyHelp
698   classpath = sourceSets.main.compileClasspath
699   main = "com.sun.java.help.search.Indexer"
700   workingDir = "$classes/$helpDir"
701   def argDir = "html"
702   args = [ argDir ]
703   inputs.dir("$workingDir/$argDir")
704
705   outputs.dir("$classes/doc")
706   outputs.dir("$classes/help")
707   outputs.file("$workingDir/JavaHelpSearch/DOCS")
708   outputs.file("$workingDir/JavaHelpSearch/DOCS.TAB")
709   outputs.file("$workingDir/JavaHelpSearch/OFFSETS")
710   outputs.file("$workingDir/JavaHelpSearch/POSITIONS")
711   outputs.file("$workingDir/JavaHelpSearch/SCHEMA")
712   outputs.file("$workingDir/JavaHelpSearch/TMAP")
713 }
714
715 task compileLinkCheck(type: JavaCompile) {
716   options.fork = true
717   classpath = files("$jalviewDir/$utilsDir")
718   destinationDir = file("$jalviewDir/$utilsDir")
719   source = fileTree(dir: "$jalviewDir/$utilsDir", include: ["HelpLinksChecker.java", "BufferedLineReader.java"])
720
721   inputs.file("$jalviewDir/$utilsDir/HelpLinksChecker.java")
722   inputs.file("$jalviewDir/$utilsDir/HelpLinksChecker.java")
723   outputs.file("$jalviewDir/$utilsDir/HelpLinksChecker.class")
724   outputs.file("$jalviewDir/$utilsDir/BufferedLineReader.class")
725 }
726
727 def helplinkscheckertouchfile = file("$jalviewDir/$utilsDir/HelpLinksChecker.touch")
728 task linkCheck(type: JavaExec) {
729   dependsOn prepare, compileLinkCheck
730   classpath = files("$jalviewDir/$utilsDir")
731   main = "HelpLinksChecker"
732   workingDir = jalviewDir
733   def help = "$classes/$helpDir"
734   args = [ "$classes/$helpDir", "-nointernet" ]
735
736   doLast {
737     helplinkscheckertouchfile.createNewFile()
738   }
739
740   inputs.dir("$classes/$helpDir")
741   outputs.file(helplinkscheckertouchfile)
742 }
743
744 task cleanPackageDir(type: Delete) {
745   delete fileTree("$jalviewDir/$packageDir").include("*.jar")
746 }
747
748 jar {
749   dependsOn linkCheck
750   dependsOn buildIndices
751   dependsOn createBuildProperties
752
753   manifest {
754     attributes "Main-Class": mainClass,
755     "Permissions": "all-permissions",
756     "Application-Name": "Jalview Desktop",
757     "Codebase": application_codebase
758   }
759
760   destinationDir = file("$jalviewDir/$packageDir")
761   archiveName = rootProject.name+".jar"
762
763   exclude "cache*/**"
764   exclude "*.jar"
765   exclude "*.jar.*"
766   exclude "**/*.jar"
767   exclude "**/*.jar.*"
768
769   inputs.dir("$classes")
770   outputs.file("$jalviewDir/$packageDir/$archiveName")
771 }
772
773 task copyJars(type: Copy) {
774   from fileTree("$classes").include("**/*.jar").include("*.jar").files
775   into "$jalviewDir/$packageDir"
776 }
777
778 // doing a Sync instead of Copy as Copy doesn't deal with "outputs" very well
779 task syncJars(type: Sync) {
780   from fileTree("$jalviewDir/$libDistDir").include("**/*.jar").include("*.jar").files
781   into "$jalviewDir/$packageDir"
782   preserve {
783     include jar.archiveName
784   }
785 }
786
787 task makeDist {
788   group = "build"
789   description = "Put all required libraries in dist"
790   // order of "cleanPackageDir", "copyJars", "jar" important!
791   jar.mustRunAfter cleanPackageDir
792   syncJars.mustRunAfter cleanPackageDir
793   dependsOn cleanPackageDir
794   dependsOn syncJars
795   dependsOn jar
796   outputs.dir("$jalviewDir/$packageDir")
797 }
798
799 task cleanDist {
800   dependsOn cleanPackageDir
801   dependsOn cleanTest
802   dependsOn clean
803 }
804
805 shadowJar {
806   group = "distribution"
807   if (buildDist) {
808     dependsOn makeDist
809   }
810   from ("$jalviewDir/$libDistDir") {
811     include("*.jar")
812   }
813   manifest {
814     attributes 'Implementation-Version': JALVIEW_VERSION
815   }
816   mainClassName = shadowJarMainClass
817   mergeServiceFiles()
818   classifier = "all-"+JALVIEW_VERSION+"-j"+JAVA_VERSION
819   minimize()
820 }
821
822 task getdownWebsite() {
823   group = "distribution"
824   description = "Create the getdown minimal app folder, and website folder for this version of jalview. Website folder also used for offline app installer"
825   if (buildDist) {
826     dependsOn makeDist
827   }
828
829         // clean the getdown website and files dir before creating getdown folders
830         delete project.ext.getdownWebsiteDir
831         delete project.ext.getdownFilesDir
832
833   def getdownWebsiteResourceFilenames = []
834   def getdownTextString = ""
835   def getdownResourceDir = project.ext.getdownResourceDir
836   def getdownAppDir = project.ext.getdownAppDir
837   def getdownResourceFilenames = []
838
839   doFirst {
840     copy {
841       from buildProperties
842       rename(buildPropertiesFile, getdown_build_properties)
843       into project.ext.getdownAppDir
844     }
845     getdownWebsiteResourceFilenames += getdown_app_dir+"/"+getdown_build_properties
846
847     // go through properties looking for getdown_txt_...
848     def props = project.properties.sort { it.key }
849         if (getdown_alt_java_min_version.length() > 0) {
850                 props.put("getdown_txt_java_min_version", getdown_alt_java_min_version)
851         }
852         if (getdown_alt_java_max_version.length() > 0) {
853                 props.put("getdown_txt_java_max_version", getdown_alt_java_max_version)
854         }
855         props.put("getdown_txt_multi_java_location", getdown_alt_multi_java_location)
856
857     props.put("getdown_txt_appbase", getdown_app_base)
858     props.each{ prop, val ->
859       if (prop.startsWith("getdown_txt_") && val != null) {
860         if (prop.startsWith("getdown_txt_multi_")) {
861           def key = prop.substring(18)
862           val.split(",").each{ v ->
863             def line = key + " = " + v + "\n"
864             getdownTextString += line
865           }
866         } else {
867           // file values rationalised
868           if (val.indexOf('/') > -1 || prop.startsWith("getdown_txt_resource")) {
869             def r = null
870             if (val.indexOf('/') == 0) {
871               // absolute path
872               r = file(val)
873             } else if (val.indexOf('/') > 0) {
874               // relative path (relative to jalviewDir)
875               r = file( jalviewDir + '/' + val )
876             }
877             if (r.exists()) {
878               val = getdown_resource_dir + '/' + r.getName()
879               getdownWebsiteResourceFilenames += val
880               getdownResourceFilenames += r.getPath()
881             }
882           }
883           if (! prop.startsWith("getdown_txt_resource")) {
884             def line = prop.substring(12) + " = " + val + "\n"
885             getdownTextString += line
886           }
887         }
888       }
889     }
890
891     getdownWebsiteResourceFilenames.each{ filename ->
892       getdownTextString += "resource = "+filename+"\n"
893     }
894     getdownResourceFilenames.each{ filename ->
895       copy {
896         from filename
897         into project.ext.getdownResourceDir
898       }
899     }
900
901     def codeFiles = []
902     fileTree(file(packageDir)).each{ f ->
903       if (f.isDirectory()) {
904         def files = fileTree(dir: f, include: ["*"]).getFiles()
905         codeFiles += files
906       } else if (f.exists()) {
907         codeFiles += f
908       }
909     }
910     codeFiles.sort().each{f ->
911       def line = "code = " + getdown_app_dir + '/' + f.getName() + "\n"
912       getdownTextString += line
913       copy {
914         from f.getPath()
915         into project.ext.getdownAppDir
916       }
917     }
918
919     // NOT USING MODULES YET, EVERYTHING SHOULD BE IN dist
920     /*
921     if (JAVA_VERSION.equals("11")) {
922     def j11libFiles = fileTree(dir: "$jalviewDir/$j11libDir", include: ["*.jar"]).getFiles()
923     j11libFiles.sort().each{f ->
924     def line = "code = " + getdown_j11lib_dir + '/' + f.getName() + "\n"
925     getdownTextString += line
926     copy {
927     from f.getPath()
928     into project.ext.getdownJ11libDir
929     }
930     }
931     }
932      */
933
934     // 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.
935     //getdownTextString += "class = " + file(getdownLauncher).getName() + "\n"
936     getdownTextString += "resource = " + getdown_launcher_new + "\n"
937     getdownTextString += "class = " + mainClass + "\n"
938
939     def getdown_txt = file(project.ext.getdownWebsiteDir + "/getdown.txt")
940     getdown_txt.write(getdownTextString)
941
942     def launch_jvl = file(project.ext.getdownWebsiteDir + "/" + getdown_launch_jvl)
943     launch_jvl.write("appbase="+props.get("getdown_txt_appbase"))
944
945     copy {
946       from getdownLauncher
947       rename(file(getdownLauncher).getName(), getdown_launcher_new)
948       into project.ext.getdownWebsiteDir
949     }
950
951     copy {
952       from getdownLauncher
953       into project.ext.getdownWebsiteDir
954     }
955
956     if (! (CHANNEL.startsWith("ARCHIVE") || CHANNEL.startsWith("DEVELOP"))) {
957       copy {
958         from getdown_txt
959         from getdownLauncher
960         from getdownWebsiteDir+"/"+getdown_build_properties
961         into getdownInstallDir
962       }
963
964       copy {
965         from getdownInstallDir
966         into getdownFilesInstallDir
967       }
968     }
969
970     copy {
971       from getdown_txt
972       from launch_jvl
973       from getdownLauncher
974       from getdownWebsiteDir+"/"+getdown_build_properties
975       into getdownFilesDir
976     }
977
978     copy {
979           from getdownResourceDir
980       into project.ext.getdownFilesDir + '/' + getdown_resource_dir
981     }
982   }
983
984   if (buildDist) {
985     inputs.dir(jalviewDir + '/' + packageDir)
986   }
987   outputs.dir(project.ext.getdownWebsiteDir)
988   outputs.dir(project.ext.getdownFilesDir)
989 }
990
991 task getdownDigest(type: JavaExec) {
992   group = "distribution"
993   description = "Digest the getdown website folder"
994   dependsOn getdownWebsite
995   classpath = files(jalviewDir + '/' + getdown_core, jalviewDir+'/'+getdown_launcher)
996   main = "com.threerings.getdown.tools.Digester"
997   args project.ext.getdownWebsiteDir
998   inputs.dir(project.ext.getdownWebsiteDir)
999   outputs.file(project.ext.getdownWebsiteDir + '/' + "digest2.txt")
1000 }
1001
1002 task getdown() {
1003   group = "distribution"
1004   description = "Create the minimal and full getdown app folder for installers and website and create digest file"
1005   dependsOn getdownDigest
1006   doLast {
1007     if (reportRsyncCommand) {
1008       def fromDir = getdownWebsiteDir + (getdownWebsiteDir.endsWith("/")?"":"/")
1009       def toDir = getdown_rsync_dest + "/" + getdownDir + (getdownDir.endsWith("/")?"":"/")
1010       println "LIKELY RSYNC COMMAND:"
1011       println "mkdir -p '$toDir'\nrsync -avh --delete '$fromDir' '$toDir'"
1012       if (RUNRSYNC == "true") {
1013         exec {
1014           commandLine "mkdir", "-p", toDir
1015         }
1016         exec {
1017           commandLine "rsync", "-avh", "--delete", fromDir, toDir
1018         }
1019       }
1020     }
1021   }
1022 }
1023
1024 clean {
1025   delete project.ext.getdownWebsiteDir
1026   delete project.ext.getdownFilesDir
1027 }
1028
1029 install4j {
1030   def install4jHomeDir = "/opt/install4j"
1031   def hostname = "hostname".execute().text.trim()
1032   if (hostname.equals("jv-bamboo")) {
1033     install4jHomeDir = System.getProperty("user.home")+"/buildtools/install4j"
1034   } else if (OperatingSystem.current().isMacOsX()) {
1035     install4jHomeDir = '/Applications/install4j.app/Contents/Resources/app'
1036     if (! file(install4jHomeDir).exists()) {
1037       install4jHomeDir = System.getProperty("user.home")+install4jHomeDir
1038     }
1039   } else if (OperatingSystem.current().isLinux()) {
1040     install4jHomeDir = System.getProperty("user.home")+"/buildtools/install4j"
1041   }
1042   installDir = file(install4jHomeDir)
1043   mediaTypes = Arrays.asList(install4jMediaTypes.split(","))
1044   if (install4jFaster.equals("true")) {
1045     faster = true
1046   }
1047 }
1048
1049 def install4jConf
1050 def macosJavaVMDir
1051 def macosJavaVMTgz
1052 def windowsJavaVMDir
1053 def windowsJavaVMTgz
1054 def install4jDir = "$jalviewDir/$install4jResourceDir"
1055 def install4jConfFile = "jalview-installers-java"+JAVA_VERSION+".install4j"
1056 install4jConf = "$install4jDir/$install4jConfFile"
1057
1058 task copyInstall4jTemplate(type: Copy) {
1059   macosJavaVMDir = System.env.HOME+"/buildtools/jre/openjdk-java_vm/getdown/macos-jre"+JAVA_VERSION+"/jre"
1060   macosJavaVMTgz = System.env.HOME+"/buildtools/jre/openjdk-java_vm/install4j/tgz/macos-jre"+JAVA_VERSION+".tar.gz"
1061   windowsJavaVMDir = System.env.HOME+"/buildtools/jre/openjdk-java_vm/getdown/windows-jre"+JAVA_VERSION+"/jre"
1062   windowsJavaVMTgz = System.env.HOME+"/buildtools/jre/openjdk-java_vm/install4j/tgz/windows-jre"+JAVA_VERSION+".tar.gz"
1063   from (install4jDir) {
1064     include install4jTemplate
1065     rename (install4jTemplate, install4jConfFile)
1066     filter(ReplaceTokens, beginToken: '', endToken: '', tokens: ['9999999999': JAVA_VERSION])
1067     filter(ReplaceTokens, beginToken: '$$', endToken: '$$',
1068     tokens: [
1069     'JAVA_VERSION': JAVA_VERSION,
1070     'JAVA_INTEGER_VERSION': JAVA_INTEGER_VERSION,
1071     'VERSION': JALVIEW_VERSION,
1072     'MACOS_JAVA_VM_DIR': macosJavaVMDir,
1073     'MACOS_JAVA_VM_TGZ': macosJavaVMTgz,
1074     'WINDOWS_JAVA_VM_DIR': windowsJavaVMDir,
1075     'WINDOWS_JAVA_VM_TGZ': windowsJavaVMTgz,
1076     'INSTALL4JINFOPLISTFILEASSOCIATIONS': install4jInfoPlistFileAssociations,
1077     'COPYRIGHT_MESSAGE': install4jCopyrightMessage,
1078     'MACOS_BUNDLE_ID': install4jMacOSBundleId,
1079     'GETDOWN_RESOURCE_DIR': getdown_resource_dir,
1080     'GETDOWN_DIST_DIR': getdown_app_dir,
1081     'GETDOWN_ALT_DIR': getdown_app_dir_alt,
1082     'GETDOWN_INSTALL_DIR': getdown_install_dir
1083     ]
1084     )
1085     if (OSX_KEYPASS=="") {
1086       filter(ReplaceTokens, beginToken: 'codeSigning macEnabled="', endToken: '"', tokens: ['true':'codeSigning macEnabled="false"'])
1087       filter(ReplaceTokens, beginToken: 'runPostProcessor="true" ',endToken: 'Processor', tokens: ['post':'runPostProcessor="false" postProcessor'])
1088     }
1089   }
1090   into install4jDir
1091   outputs.files(install4jConf)
1092
1093   doLast {
1094     // include file associations in installer
1095     def installerFileAssociationsXml = file("$install4jDir/$install4jInstallerFileAssociations").text
1096     ant.replaceregexp(
1097       byline: false,
1098       flags: "s",
1099       match: '<action name="EXTENSIONS_REPLACED_BY_GRADLE".*?</action>',
1100       replace: installerFileAssociationsXml,
1101       file: install4jConf
1102     )
1103     /*
1104     // include uninstaller applescript app files in dmg
1105     def installerDMGUninstallerXml = file("$install4jDir/$install4jDMGUninstallerAppFiles").text
1106     ant.replaceregexp(
1107     byline: false,
1108     flags: "s",
1109     match: '<file name="UNINSTALL_OLD_JALVIEW_APP_REPLACED_IN_GRADLE" file=.*?>',
1110     replace: installerDMGUninstallerXml,
1111     file: install4jConf
1112     )
1113      */
1114   }
1115 }
1116
1117 task installers(type: com.install4j.gradle.Install4jTask) {
1118   group = "distribution"
1119   description = "Create the install4j installers"
1120   dependsOn getdown
1121   dependsOn copyInstall4jTemplate
1122   projectFile = file(install4jConf)
1123   println("Using projectFile "+projectFile)
1124   variables = [majorVersion: version.substring(2, 11), build: 001, OSX_KEYSTORE: OSX_KEYSTORE, JSIGN_SH: JSIGN_SH]
1125   destination = "$jalviewDir/$install4jBuildDir/$JAVA_VERSION"
1126   buildSelected = true
1127
1128   if (OSX_KEYPASS) {
1129     macKeystorePassword=OSX_KEYPASS
1130
1131   }
1132
1133   inputs.dir(project.ext.getdownWebsiteDir)
1134   inputs.file(install4jConf)
1135   inputs.dir(macosJavaVMDir)
1136   inputs.dir(windowsJavaVMDir)
1137   outputs.dir("$jalviewDir/$install4jBuildDir/$JAVA_VERSION")
1138
1139 }
1140
1141 clean {
1142   delete install4jConf
1143 }
1144