JAL-3130 add JAVA_VERSION to shadowJar classifier so artifacts are distinct
[jalview.git] / build.gradle
1 import org.apache.tools.ant.filters.ReplaceTokens
2 import org.gradle.internal.os.OperatingSystem
3
4 buildscript {
5   dependencies {
6         classpath 'org.openclover:clover:4.3.1'
7         classpath 'org.apache.commons:commons-compress:1.18'
8   }
9 }
10
11 plugins {
12   id 'java'
13   id 'application'
14   id 'com.github.johnrengelman.shadow' version '4.0.3'
15   id 'com.install4j.gradle' version '7.0.9'
16 }
17
18 repositories {
19   jcenter()
20   mavenCentral()
21   mavenLocal()
22   flatDir {
23     dirs gradlePluginsDir
24   }
25 }
26
27 mainClassName = launcherClass
28 def cloverInstrDir = file("$buildDir/$cloverSourcesInstrDir")
29 def classes = "$jalviewDir/$classesDir"
30 if (clover.equals("true")) {
31   use_clover = true
32   classes = "$buildDir/$cloverClassesDir"
33 } else {
34   use_clover = false
35   classes = "$jalviewDir/$classesDir"
36 }
37
38 // configure classpath/args for j8/j11 compilation
39
40 def libDir
41 def libDistDir
42 def compile_source_compatibility
43 def compile_target_compatibility
44 def additional_compiler_args = []
45 def getdown_alt_java_min_version
46 if (JAVA_VERSION.equals("1.8")) {
47   libDir = j11libDir
48   libDistDir = j8libDir
49   compile_source_compatibility = 1.8
50   compile_target_compatibility = 1.8
51   getdown_alt_java_min_version = getdown_alt_java8_min_version
52 } else if (JAVA_VERSION.equals("11")) {
53   libDir = j11libDir
54   libDistDir = j11libDir
55   compile_source_compatibility = 11
56   compile_target_compatibility = 11
57   getdown_alt_java_min_version = getdown_alt_java11_min_version
58   additional_compiler_args += [
59     '--module-path', file("$jalviewDir/$j11modDir").getAbsolutePath(),
60     '--add-modules', j11modules
61   ]
62 } else {
63   throw new GradleException("JAVA_VERSION=$JAVA_VERSION not currently supported by Jalview")
64 }
65
66 sourceSets {
67
68   main {
69     java {
70       srcDirs "$jalviewDir/$sourceDir"
71       outputDir = file("$classes")
72     }
73
74     resources {
75       srcDirs "$jalviewDir/$resourceDir"
76       srcDirs "$jalviewDir/$libDistDir"
77     }
78
79     jar.destinationDir = file("$jalviewDir/$packageDir")
80
81     compileClasspath = files(sourceSets.main.java.outputDir)
82     compileClasspath += fileTree(dir: "$jalviewDir/$libDir", include: ["*.jar"])
83
84     runtimeClasspath = compileClasspath
85   }
86   
87   clover {
88     java {
89         srcDirs = [ cloverInstrDir ]
90         outputDir = file("${buildDir}/${cloverClassesDir}")
91     }
92     
93     resources {
94       srcDirs = sourceSets.main.resources.srcDirs
95     }
96     compileClasspath = configurations.cloverRuntime + files( sourceSets.clover.java.outputDir )
97     compileClasspath += fileTree(dir: "$jalviewDir/$utilsDir", include: ["**/*.jar"])
98     compileClasspath += fileTree(dir: "$jalviewDir/$libDir", include: ["*.jar"])
99
100     runtimeClasspath = compileClasspath
101   }
102   
103   test {
104     java {
105       srcDirs "$jalviewDir/$testSourceDir"
106       outputDir = file("$jalviewDir/$testOutputDir")
107     }
108
109     resources {
110       srcDirs = sourceSets.main.resources.srcDirs
111     }
112
113     compileClasspath = files( sourceSets.test.java.outputDir ) 
114     if (use_clover) {
115       compileClasspath += sourceSets.clover.compileClasspath
116     } else {
117       compileClasspath += sourceSets.main.compileClasspath
118       compileClasspath += files(sourceSets.main.java.outputDir)
119     }
120     compileClasspath += files( sourceSets.main.resources.srcDirs)
121     compileClasspath += fileTree(dir: "$jalviewDir/$utilsDir", include: ["**/*.jar"])
122     compileClasspath += fileTree(dir: "$jalviewDir/$libDir", include: ["*.jar"])
123
124     runtimeClasspath = compileClasspath
125   }
126 }
127
128 // clover bits
129 dependencies {
130   if (use_clover) {
131     cloverCompile 'org.openclover:clover:4.3.1'
132     testCompile 'org.openclover:clover:4.3.1'
133   }
134 }
135
136 configurations {
137     cloverRuntime
138     cloverRuntime.extendsFrom cloverCompile
139 }
140  
141 task cloverInstr() {
142   // only instrument source, we build test classes as normal
143     inputs.files files (sourceSets.main.allJava) // , fileTree(dir:"$jalviewDir/$testSourceDir", include: ["**/*.java"]))
144     outputs.dir cloverInstrDir
145
146     doFirst {
147         delete cloverInstrDir
148         def argsList = ["--initstring", "${buildDir}/clover/clover.db",
149                         "-d", "${buildDir}/${cloverSourcesInstrDir}"]
150         argsList.addAll(inputs.files.files.collect({ file ->
151             file.absolutePath
152         }))
153         String[] args = argsList.toArray()
154         println("About to instrument "+args.length +" files")
155         com.atlassian.clover.CloverInstr.mainImpl(args)
156     }
157 }
158
159  
160 task cloverReport {
161     inputs.dir "${buildDir}/clover"
162     outputs.dir "${reportsDir}/clover"
163     onlyIf {
164         file("${buildDir}/clover/clover.db").exists()
165     }
166     doFirst {
167         def argsList = ["--initstring", "${buildDir}/clover/clover.db",
168                         "-o", "${reportsDir}/clover"]
169         String[] args = argsList.toArray()
170         com.atlassian.clover.reporters.html.HtmlReporter.runReport(args)
171         
172         // and generate ${reportsDir}/clover/clover.xml
173         args = ["--initstring", "${buildDir}/clover/clover.db",
174                         "-o", "${reportsDir}/clover/clover.xml"].toArray()
175         com.atlassian.clover.reporters.xml.XMLReporter.runReport(args)
176     }
177 }
178
179 // end clover bits
180
181
182 compileJava {
183
184   doFirst {
185     sourceCompatibility = compile_source_compatibility
186     targetCompatibility = compile_target_compatibility
187     options.compilerArgs = additional_compiler_args
188     print ("Setting target compatibility to "+targetCompatibility+"\n")
189   }
190
191 }
192
193 compileTestJava {
194
195   if (use_clover) {
196     dependsOn compileCloverJava
197     classpath += configurations.cloverRuntime
198   } else {
199     classpath += sourceSets.main.runtimeClasspath
200   }
201   doFirst {
202     sourceCompatibility = compile_source_compatibility
203     targetCompatibility = compile_target_compatibility
204     options.compilerArgs = additional_compiler_args
205     print ("Setting target compatibility to "+targetCompatibility+"\n")
206   }
207 }
208
209
210 compileCloverJava {
211
212   doFirst {
213     sourceCompatibility = compile_source_compatibility
214     targetCompatibility = compile_target_compatibility
215     options.compilerArgs += additional_compiler_args
216     print ("Setting target compatibility to "+targetCompatibility+"\n")
217   }
218   classpath += configurations.cloverRuntime
219 }
220
221 clean {
222   delete sourceSets.main.java.outputDir
223 }
224
225 cleanTest {
226   delete sourceSets.test.java.outputDir
227   delete cloverInstrDir
228 }
229
230 def getDate(format) {
231   def date = new Date()
232   //return date.format("dd MMMM yyyy")
233   return date.format(format)
234 }
235
236 def getGitHash() {
237   def stdout = new ByteArrayOutputStream()
238   exec {
239     commandLine "git", "rev-parse", "--short", "HEAD"
240     standardOutput = stdout
241     workingDir = jalviewDir
242   }
243   return stdout.toString().trim()
244 }
245
246 def getGitBranch() {
247   def stdout = new ByteArrayOutputStream()
248   exec {
249     commandLine "git", "rev-parse", "--abbrev-ref", "HEAD"
250     standardOutput = stdout
251     workingDir = jalviewDir
252   }
253   return stdout.toString().trim()
254 }
255
256 task createBuildProperties(type: WriteProperties) {
257   inputs.dir("$jalviewDir/$sourceDir")
258   inputs.dir("$jalviewDir/$resourceDir")
259   outputFile "$classes/$buildPropertiesFile"
260   /* taking time/date specific comment out to allow better incremental builds */
261   //comment "--Jalview Build Details--\n"+getDate("yyyy-MM-dd HH:mm:ss")
262   comment "--Jalview Build Details--\n"+getDate("yyyy-MM-dd")
263   property "BUILD_DATE", getDate("dd MMMM yyyy")
264   property "VERSION", JALVIEW_VERSION
265   property "INSTALLATION", INSTALLATION+" git-commit:"+getGitHash()+" ["+getGitBranch()+"]"
266   outputs.file(outputFile)
267   outputs.dir("$classes")
268 }
269
270 task syncDocs(type: Sync) {
271   def syncDir = "$classes/$docDir"
272   from fileTree("$jalviewDir/$docDir")
273   into syncDir
274
275 }
276
277 def helpFile = "$classes/$helpDir/help.jhm"
278 task syncHelp(type: Sync) {
279   inputs.files("$jalviewDir/$helpDir")
280   outputs.files(helpFile)
281
282   def syncDir = "$classes/$helpDir"
283   from fileTree("$jalviewDir/$helpDir")
284   into syncDir
285 }
286
287 task copyHelp(type: Copy) {
288   def inputDir = "$jalviewDir/$helpDir"
289   def outputDir = "$classes/$helpDir"
290   from inputDir
291   into outputDir
292   filter(ReplaceTokens, beginToken: '$$', endToken: '$$', tokens: ['Version-Rel': "USING_FILTER"])
293   inputs.dir(inputDir)
294   outputs.files(helpFile)
295   outputs.dir(outputDir)
296 }
297
298 task syncLib(type: Sync) {
299   def syncDir = "$classes/$libDistDir"
300   from fileTree("$jalviewDir/$libDistDir")
301   into syncDir
302 }
303
304 task syncResources(type: Sync) {
305   from "$jalviewDir/$resourceDir"
306   include "**/*.*"
307   exclude "install4j"
308   into "$classes"
309   preserve {
310     include "**"
311   }
312 }
313
314 task prepare {
315   dependsOn syncResources
316   dependsOn syncDocs
317   dependsOn copyHelp
318 }
319
320
321 //testReportDirName = "test-reports" // note that test workingDir will be $jalviewDir
322 test {
323   dependsOn prepare
324   dependsOn compileJava
325   if (use_clover) {
326     dependsOn cloverInstr
327   }
328   print("Running tests " + (use_clover?"WITH":"WITHOUT") + " clover [clover="+use_clover+"]\n") 
329   
330   useTestNG() {
331     includeGroups testngGroups
332     preserveOrder true
333     useDefaultListeners=true
334   }
335   
336   workingDir = jalviewDir
337   //systemProperties 'clover.jar' System.properties.clover.jar
338   sourceCompatibility = compile_source_compatibility
339   targetCompatibility = compile_target_compatibility
340   jvmArgs += additional_compiler_args
341   print ("Setting target compatibility to "+targetCompatibility+"\n")
342 }
343
344 task buildIndices(type: JavaExec) {
345   dependsOn copyHelp
346   classpath = sourceSets.main.compileClasspath
347   main = "com.sun.java.help.search.Indexer"
348   workingDir = "$classes/$helpDir"
349   def argDir = "html"
350   args = [ argDir ]
351   inputs.dir("$workingDir/$argDir")
352
353   outputs.dir("$classes/doc")
354   outputs.dir("$classes/help")
355   outputs.file("$workingDir/JavaHelpSearch/DOCS")
356   outputs.file("$workingDir/JavaHelpSearch/DOCS.TAB")
357   outputs.file("$workingDir/JavaHelpSearch/OFFSETS")
358   outputs.file("$workingDir/JavaHelpSearch/POSITIONS")
359   outputs.file("$workingDir/JavaHelpSearch/SCHEMA")
360   outputs.file("$workingDir/JavaHelpSearch/TMAP")
361 }
362
363 task compileLinkCheck(type: JavaCompile) {
364   options.fork = true
365   classpath = files("$jalviewDir/$utilsDir")
366   destinationDir = file("$jalviewDir/$utilsDir")
367   source = fileTree(dir: "$jalviewDir/$utilsDir", include: ["HelpLinksChecker.java", "BufferedLineReader.java"])
368
369   outputs.file("$jalviewDir/$utilsDir/HelpLinksChecker.class")
370   outputs.file("$jalviewDir/$utilsDir/BufferedLineReader.class")
371 }
372
373 task linkCheck(type: JavaExec) {
374   dependsOn prepare, compileLinkCheck
375   classpath = files("$jalviewDir/$utilsDir")
376   main = "HelpLinksChecker"
377   workingDir = jalviewDir
378   def help = "$classes/$helpDir"
379   args = [ "$classes/$helpDir", "-nointernet" ]
380   //args = [ "$classesDir/$helpDir", "-nointernet" ]
381
382   doFirst {
383     standardOutput new FileOutputStream("$jalviewDir/$utilsDir/HelpLinksChecker.out")
384   }
385
386   outputs.file("$jalviewDir/$utilsDir/HelpLinksChecker.out")
387 }
388
389 task cleanPackageDir(type: Delete) {
390   delete fileTree("$jalviewDir/$packageDir").include("*.jar")
391 }
392
393 jar {
394   dependsOn linkCheck
395   dependsOn buildIndices
396   dependsOn createBuildProperties
397
398   manifest {
399     attributes "Main-Class": mainClass,
400     "Permissions": "all-permissions",
401     "Application-Name": "Jalview Desktop",
402     "Codebase": application_codebase
403   }
404
405   destinationDir = file("$jalviewDir/$packageDir")
406   archiveName = rootProject.name+".jar"
407
408   exclude "cache*/**"
409   exclude "*.jar"
410   exclude "*.jar.*"
411   exclude "**/*.jar"
412   exclude "**/*.jar.*"
413
414   inputs.dir("$classes")
415   outputs.file("$jalviewDir/$packageDir/$archiveName")
416 }
417
418 task copyJars(type: Copy) {
419   from fileTree("$classes").include("**/*.jar").include("*.jar").files
420   into "$jalviewDir/$packageDir"
421 }
422
423 // doing a Sync instead of Copy as Copy doesn't deal with "outputs" very well
424 task syncJars(type: Sync) {
425   from fileTree("$jalviewDir/$libDistDir").include("**/*.jar").include("*.jar").files
426   into "$jalviewDir/$packageDir"
427   preserve {
428     include jar.archiveName
429   }
430 }
431
432 task makeDist {
433   // order of "cleanPackageDir", "copyJars", "jar" important!
434   jar.mustRunAfter cleanPackageDir
435   syncJars.mustRunAfter cleanPackageDir
436   dependsOn cleanPackageDir
437   dependsOn syncJars
438   dependsOn jar
439   outputs.dir("$jalviewDir/$packageDir")
440 }
441
442 task cleanDist {
443   dependsOn cleanPackageDir
444   dependsOn cleanTest
445   dependsOn clean
446 }
447
448 shadowJar {
449   dependsOn makeDist
450   from ("$jalviewDir/$libDistDir") {
451       include("*.jar")
452   }
453   mainClassName = shadowJarMainClass
454   mergeServiceFiles()
455   classifier = "all-"+JAVA_VERSION
456   minimize()
457 }
458
459 ext {
460   // where the getdown channel will be built. 
461   // TODO: consider allowing this expression to  be overrriden by -P arg
462   getdownWebsiteDir = jalviewDir + '/' + getdown_website_dir + '/' + JAVA_VERSION + '/'
463   getdownAppDir = getdownWebsiteDir + '/' + getdown_app_dir
464   getdownJ11libDir = getdownWebsiteDir + '/' + getdown_j11lib_dir
465   getdownResourceDir = getdownWebsiteDir + '/' + getdown_resource_dir
466   getdownLauncher = jalviewDir + '/' + getdown_launcher
467   getdownFilesDir = jalviewDir + '/' + getdown_files_dir
468   getdownLib1 = jalviewDir + '/' + getdown_lib1
469   def getdownChannel = getdown_channel_name
470   if (getdown_channel_name.equals("COMMIT")) {
471     getdownChannel = getGitHash()
472   }
473   getdown_app_base = getdown_channel_base+"/"+getdownChannel+"/"+JAVA_VERSION+"/"
474 }
475
476 task getdownWebsite() {
477   dependsOn makeDist
478   def getdownWebsiteResourceFilenames = []
479   def getdownTextString = ""
480   def getdownResourceDir = project.ext.getdownResourceDir
481   def getdownAppDir = project.ext.getdownAppDir
482   def getdownResourceFilenames = []
483   doFirst {
484     // go through properties looking for getdown_txt_...
485     def props = project.properties.sort { it.key }
486     props.put("getdown_txt_java_min_version", getdown_alt_java_min_version)
487     props.put("getdown_txt_appbase", getdown_app_base)
488     props.each{ prop, val ->
489       if (prop.startsWith("getdown_txt_") && val != null) {
490         if (prop.startsWith("getdown_txt_multi_")) {
491           def key = prop.substring(18)
492           val.split(",").each{ v ->
493             def line = key + " = " + v + "\n"
494             getdownTextString += line
495           }
496         } else {
497           // file values rationalised
498           if (val.indexOf('/') > -1) {
499             def r = null
500             if (val.indexOf('/') == 0) {
501               // absolute path
502               r = file(val)
503             } else if (val.indexOf('/') > 0) {
504               // relative path (relative to jalviewDir)
505               r = file( jalviewDir + '/' + val )
506             }
507             if (r.exists()) {
508               val = getdown_resource_dir + '/' + r.getName()
509               getdownWebsiteResourceFilenames += val
510               getdownResourceFilenames += r.getPath()
511             }
512           }
513           def line = prop.substring(12) + " = " + val + "\n"
514           getdownTextString += line
515         }
516       }
517     }
518
519     getdownWebsiteResourceFilenames.each{ filename ->
520       getdownTextString += "resource = "+filename+"\n"
521     }
522     getdownResourceFilenames.each{ filename ->
523       copy {
524         from filename
525         into project.ext.getdownResourceDir
526       }
527     }
528
529     def codeFiles = []
530     makeDist.outputs.files.each{ f ->
531       if (f.isDirectory()) {
532         def files = fileTree(dir: f, include: ["*"]).getFiles()
533         codeFiles += files
534       } else if (f.exists()) {
535         codeFiles += f
536       }
537     }
538     codeFiles.sort().each{f ->
539       def line = "code = " + getdown_app_dir + '/' + f.getName() + "\n"
540       getdownTextString += line
541       copy {
542         from f.getPath()
543         into project.ext.getdownAppDir
544       }
545     }
546
547     if (JAVA_VERSION.equals("11")) {
548       def j11libFiles = fileTree(dir: "$jalviewDir/$j11libDir", include: ["*.jar"]).getFiles()
549       j11libFiles.sort().each{f ->
550         def line = "code = " + getdown_j11lib_dir + '/' + f.getName() + "\n"
551         getdownTextString += line
552         copy {
553           from f.getPath()
554           into project.ext.getdownJ11libDir
555         }
556       }
557     }
558
559     getdownTextString += "code = " + file(getdownLauncher).getName() + "\n"
560     getdownTextString += "class = " + mainClass + "\n"
561
562     def getdown_txt = file(project.ext.getdownWebsiteDir + "/getdown.txt")
563     getdown_txt.write(getdownTextString)
564
565     copy {
566       from getdown_txt
567       into project.ext.getdownFilesDir
568     }
569
570     copy {
571       from getdownLauncher
572       into project.ext.getdownWebsiteDir
573     }
574
575     copy {
576       from getdownLauncher
577       into project.ext.getdownFilesDir
578     }
579
580     copy {
581       from getdownLib1
582       into project.ext.getdownFilesDir
583     }
584
585     copy {
586       from getdownLib1
587       into project.ext.getdownWebsiteDir
588     }
589
590     copy {
591       from jalviewDir + '/' + project.getProperty('getdown_txt_ui.background_image')
592       from jalviewDir + '/' + project.getProperty('getdown_txt_ui.error_background')
593       from jalviewDir + '/' + project.getProperty('getdown_txt_ui.progress_image')
594       from jalviewDir + '/' + project.getProperty('getdown_txt_ui.icon')
595       from jalviewDir + '/' + project.getProperty('getdown_txt_ui.mac_dock_icon')
596       into project.ext.getdownFilesDir + '/' + getdown_resource_dir 
597     }
598   }
599
600   inputs.dir(jalviewDir + '/' + packageDir)
601   outputs.dir(project.ext.getdownWebsiteDir)
602   outputs.dir(project.ext.getdownFilesDir)
603 }
604
605 task getdownDigest(type: JavaExec) {
606   dependsOn getdownWebsite
607   classpath = files(jalviewDir + '/' + getdown_core)
608   classpath file(jalviewDir + '/' + getdown_lib1)
609   main = "com.threerings.getdown.tools.Digester"
610   args project.ext.getdownWebsiteDir
611   outputs.file(project.ext.getdownWebsiteDir + '/' + "digest2.txt")
612 }
613
614 task getdown() {
615   dependsOn getdownDigest
616 }
617
618 clean {
619   delete project.ext.getdownWebsiteDir
620   delete project.ext.getdownFilesDir
621 }
622
623 install4j {
624   def install4jHomeDir = "/opt/install4j"
625   def hostname = "hostname".execute().text.trim()
626   if (hostname.equals("jv-bamboo")) {
627     install4jHomeDir = System.getProperty("user.home")+"/buildtools/install4j"
628   } else if (OperatingSystem.current().isMacOsX()) {
629     install4jHomeDir = '/Applications/install4j.app/Contents/Resources/app'
630     if (! file(install4jHomeDir).exists()) {
631       install4jHomeDir = System.getProperty("user.home")+install4jHomeDir
632     }
633   } else if (OperatingSystem.current().isLinux()) {
634     install4jHomeDir = System.getProperty("user.home")+"/buildtools/install4j"
635   }
636   installDir = file(install4jHomeDir)
637   mediaTypes = Arrays.asList(install4jMediaTypes.split(","))
638 }
639
640 def install4jConf
641 def macosJavaVMDir
642 def windowsJavaVMDir
643 def install4jDir = "$jalviewDir/$install4jResourceDir"
644 def install4jConfFile = "jalview-installers-java"+JAVA_VERSION+".install4j"
645 install4jConf = "$install4jDir/$install4jConfFile"
646   
647 task copyInstall4jTemplate(type: Copy) {
648   macosJavaVMDir = System.env.HOME+"/buildtools/jre/openjdk-java_vm/macos-jre"+JAVA_VERSION+"/java_vm"
649   windowsJavaVMDir = System.env.HOME+"/buildtools/jre/openjdk-java_vm/windows-jre"+JAVA_VERSION+"/java_vm"
650   from (install4jDir) {
651     include install4jTemplate
652     rename (install4jTemplate, install4jConfFile)
653     filter(ReplaceTokens, beginToken: '', endToken: '', tokens: ['9999999999': JAVA_VERSION])
654     filter(ReplaceTokens, beginToken: '$$', endToken: '$$', tokens: ['VERSION': JALVIEW_VERSION, 'MACOS_JAVA_VM_DIR': macosJavaVMDir, 'WINDOWS_JAVA_VM_DIR': windowsJavaVMDir])
655   }
656   into install4jDir
657   inputs.files("$install4jDir/$install4jTemplate")
658   outputs.files(install4jConf)
659 }
660
661 task installers(type: com.install4j.gradle.Install4jTask) {
662   dependsOn getdown
663   dependsOn copyInstall4jTemplate
664   projectFile = file(install4jConf)
665   println("Using projectFile "+projectFile)
666   variables = [majorVersion: version.substring(2, 11), build: 001]
667   destination = "$jalviewDir/$install4jBuildDir"
668   buildSelected = true
669   inputs.dir(project.ext.getdownWebsiteDir)
670   inputs.file(install4jConf)
671   inputs.dir(macosJavaVMDir)
672   inputs.dir(windowsJavaVMDir)
673   outputs.dir("$jalviewDir/$install4jBuildDir")
674 }
675
676 clean {
677   delete install4jConf
678 }