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