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