JAL-3210 project name explicitly set. updated README_GRADLE_JALVIEWJS...md file....
[jalview.git] / build.gradle
1 import org.apache.tools.ant.filters.ReplaceTokens
2 import org.gradle.internal.os.OperatingSystem
3 import org.gradle.plugins.ide.eclipse.model.Output
4 import org.gradle.plugins.ide.eclipse.model.Library
5
6 import groovy.transform.ExternalizeMethods
7
8 buildscript {
9   dependencies {
10     classpath 'org.openclover:clover:4.3.1'
11   }
12 }
13
14 plugins {
15   id 'java'
16   id 'application'
17   id 'eclipse'
18   id 'com.github.johnrengelman.shadow' version '4.0.3'
19   id 'com.install4j.gradle' version '7.0.9'
20 }
21
22 repositories {
23   jcenter()
24   mavenCentral()
25   mavenLocal()
26   flatDir {
27     dirs gradlePluginsDir
28   }
29 }
30
31 dependencies {
32   compile 'org.apache.commons:commons-compress:1.18'
33 }
34
35 mainClassName = launcherClass
36 def cloverInstrDir = file("$buildDir/$cloverSourcesInstrDir")
37 def classes = "$jalviewDir/$classesDir"
38
39 if (clover.equals("true")) {
40   use_clover = true
41   classes = "$buildDir/$cloverClassesDir"
42 } else {
43   use_clover = false
44   classes = "$jalviewDir/$classesDir"
45 }
46
47 // configure classpath/args for j8/j11 compilation
48
49 def jalviewDirAbsolutePath = file(jalviewDir).getAbsolutePath()
50 def libDir
51 def libDistDir
52 def compile_source_compatibility
53 def compile_target_compatibility
54
55 ext {
56   getdownWebsiteDir = jalviewDir + '/' + getdown_website_dir + '/' + JAVA_VERSION
57   getdownDir = ""
58   reportRsyncCmd = false
59   buildDist = true
60   buildProperties = buildPropertiesFile
61   getdownLauncher = jalviewDir + '/' + getdown_lib_dir + '/' + getdown_launcher
62   switch (CHANNEL) {
63
64     case "BUILD":
65     // TODO: get bamboo build artifact URL for getdown artifacts
66     getdown_channel_base = bamboo_channelbase
67     getdown_channel_name = bamboo_planKey + '/'+JAVA_VERSION
68     getdown_app_base = bamboo_channelbase + '/'+ bamboo_planKey + bamboo_getdown_channel_suffix + '/'+JAVA_VERSION
69     getdown_app_dir = getdown_app_dir_alt
70     buildProperties = jalviewDir + "/" + classesDir +"/" + buildPropertiesFile
71     break
72
73     case "RELEASE":
74     getdown_channel_name = CHANNEL.toLowerCase()
75     getdownDir = getdown_channel_name + "/" + JAVA_VERSION
76     getdown_app_base = getdown_channel_base + "/" + getdownDir
77     getdown_app_dir = getdown_app_dir_release
78     buildProperties = jalviewDir + "/" + classesDir +"/" + buildPropertiesFile
79     reportRsyncCommand = true
80     break
81
82     case "ARCHIVE":
83     getdown_channel_name = CHANNEL.toLowerCase()+"/"+JALVIEW_VERSION
84     getdownDir = getdown_channel_name + "/" + JAVA_VERSION
85     getdown_app_base = getdown_channel_base + "/" + getdownDir
86     getdown_app_dir = getdown_app_dir_alt
87     if (!file(ARCHIVEDIR+"/"+packageDir).exists()) {
88       print "Must provide an ARCHIVEDIR value to produce an archive distribution"
89       exit
90     } else {
91       packageDir = ARCHIVEDIR + "/" + packageDir
92       buildProperties = ARCHIVEDIR +"/" + classesDir + "/" + buildPropertiesFile
93       buildDist = false
94     }
95     reportRsyncCommand = true
96     break
97
98     case "ARCHIVELOCAL":
99     getdown_channel_name = "archive" + "/" + JALVIEW_VERSION
100     getdownDir = getdown_channel_name + "/" + JAVA_VERSION
101     getdown_app_base = file(getdownWebsiteDir).toURI().toString()
102     getdown_app_dir = getdown_app_dir_alt
103     if (!file(ARCHIVEDIR+"/"+packageDir).exists()) {
104       print "Must provide an ARCHIVEDIR value to produce an archive distribution"
105       exit
106     } else {
107       packageDir = ARCHIVEDIR + "/" + packageDir
108       buildProperties = ARCHIVEDIR +"/" + classesDir + "/" + buildPropertiesFile
109       buildDist = false
110     }
111     reportRsyncCommand = true
112     getdownLauncher = jalviewDir + '/' + getdown_lib_dir + '/' + getdown_launcher_local
113     break
114
115     case "DEVELOP":
116     getdown_channel_name = CHANNEL.toLowerCase()
117     getdownDir = getdown_channel_name + "/" + JAVA_VERSION
118     getdown_app_base = getdown_channel_base + "/" + getdownDir
119     getdown_app_dir = getdown_app_dir_alt
120     buildProperties = jalviewDir + "/" + classesDir +"/" + buildPropertiesFile
121     reportRsyncCommand = true
122     break
123
124     case "TEST-RELEASE":
125     getdown_channel_name = CHANNEL.toLowerCase()
126     getdownDir = getdown_channel_name + "/" + JAVA_VERSION
127     getdown_app_base = getdown_channel_base + "/" + getdownDir
128     getdown_app_dir = getdown_app_dir_alt
129     buildProperties = jalviewDir + "/" + classesDir +"/" + buildPropertiesFile
130     reportRsyncCommand = true
131     break
132
133     case ~/^SCRATCH(|-[-\w]*)$/:
134     getdown_channel_name = CHANNEL
135     getdownDir = getdown_channel_name + "/" + JAVA_VERSION
136     getdown_app_base = getdown_channel_base + "/" + getdownDir
137     getdown_app_dir = getdown_app_dir_alt
138     buildProperties = jalviewDir + "/" + classesDir +"/" + buildPropertiesFile
139     reportRsyncCommand = true
140     break
141
142     case "LOCAL":
143     getdown_app_base = file(getdownWebsiteDir).toURI().toString()
144     getdown_app_dir = getdown_app_dir_alt
145     buildProperties = jalviewDir + "/" + classesDir +"/" + buildPropertiesFile
146     getdownLauncher = jalviewDir + '/' + getdown_lib_dir + '/' + getdown_launcher_local
147     break
148
149     default: // something wrong specified
150     print("CHANNEL must be one of BUILD, RELEASE, ARCHIVE, DEVELOP, TEST-RELEASE, SCRATCH-..., LOCAL [default]")
151     exit
152     break
153
154   }
155
156   println("Using a "+CHANNEL+" profile. appbase="+getdown_app_base)
157   getdownAppDir = getdownWebsiteDir + '/' + getdown_app_dir
158   //getdownJ11libDir = getdownWebsiteDir + '/' + getdown_j11lib_dir
159   getdownResourceDir = getdownWebsiteDir + '/' + getdown_resource_dir
160   getdownInstallDir = getdownWebsiteDir + '/' + getdown_install_dir
161   getdownFilesDir = jalviewDir + '/' + getdown_files_dir + '/' + JAVA_VERSION + '/'
162   getdownFilesInstallDir = getdownFilesDir+"/"+getdown_install_dir
163   /* compile without modules -- using classpath libraries
164   modules_compileClasspath = fileTree(dir: "$jalviewDir/$j11modDir", include: ["*.jar"])
165   modules_runtimeClasspath = modules_compileClasspath
166   */
167   gitHash = ""
168   gitBranch = ""
169
170   jalviewjsServer = ""
171 }
172
173 def JAVA_INTEGER_VERSION
174 def additional_compiler_args = []
175 // these are getdown.txt properties defined dependent on the JAVA_VERSION
176 def getdown_alt_java_min_version
177 def getdown_alt_java_max_version
178 // this property is assigned below and expanded to multiple lines in the getdown task
179 def getdown_alt_multi_java_location
180 // this property is for the Java library used in eclipse
181 def eclipse_java_runtime_name
182 if (JAVA_VERSION.equals("1.8")) {
183   JAVA_INTEGER_VERSION = "8"
184   //libDir = j8libDir
185   libDir = j11libDir
186   libDistDir = j8libDir
187   compile_source_compatibility = 1.8
188   compile_target_compatibility = 1.8
189   getdown_alt_java_min_version = getdown_alt_java8_min_version
190   getdown_alt_java_max_version = getdown_alt_java8_max_version
191   getdown_alt_multi_java_location = getdown_alt_java8_txt_multi_java_location
192   eclipse_java_runtime_name = "JavaSE-1.8"
193 } else if (JAVA_VERSION.equals("11")) {
194   JAVA_INTEGER_VERSION = "11"
195   libDir = j11libDir
196   libDistDir = j11libDir
197   compile_source_compatibility = 11
198   compile_target_compatibility = 11
199   getdown_alt_java_min_version = getdown_alt_java11_min_version
200   getdown_alt_java_max_version = getdown_alt_java11_max_version
201   getdown_alt_multi_java_location = getdown_alt_java11_txt_multi_java_location
202   eclipse_java_runtime_name = "JavaSE-11"
203   /* compile without modules -- using classpath libraries
204   additional_compiler_args += [
205   '--module-path', ext.modules_compileClasspath.asPath,
206   '--add-modules', j11modules
207   ]
208   */
209 } else if (JAVA_VERSION.equals("12") || JAVA_VERSION.equals("13")) {
210   JAVA_INTEGER_VERSION = JAVA_VERSION
211   libDir = j11libDir
212   libDistDir = j11libDir
213   compile_source_compatibility = JAVA_VERSION
214   compile_target_compatibility = JAVA_VERSION
215   getdown_alt_java_min_version = getdown_alt_java11_min_version
216   getdown_alt_java_max_version = getdown_alt_java11_max_version
217   getdown_alt_multi_java_location = getdown_alt_java11_txt_multi_java_location
218   eclipse_java_runtime_name = "JavaSE-11"
219   /* compile without modules -- using classpath libraries
220   additional_compiler_args += [
221   '--module-path', ext.modules_compileClasspath.asPath,
222   '--add-modules', j11modules
223   ]
224   */
225 } else {
226   throw new GradleException("JAVA_VERSION=$JAVA_VERSION not currently supported by Jalview")
227 }
228
229 sourceSets {
230
231   main {
232     java {
233       srcDirs "$jalviewDir/$sourceDir"
234       outputDir = file("$classes")
235     }
236
237     resources {
238       srcDirs "$jalviewDir/$resourceDir"
239     }
240
241     jar.destinationDir = file("$jalviewDir/$packageDir")
242
243     compileClasspath = files(sourceSets.main.java.outputDir)
244     compileClasspath += fileTree(dir: "$jalviewDir/$libDir", include: ["*.jar"])
245
246     runtimeClasspath = compileClasspath
247   }
248
249   clover {
250     java {
251       srcDirs = [ cloverInstrDir ]
252       outputDir = file("${buildDir}/${cloverClassesDir}")
253     }
254
255     resources {
256       srcDirs = sourceSets.main.resources.srcDirs
257     }
258     compileClasspath = configurations.cloverRuntime + files( sourceSets.clover.java.outputDir )
259     compileClasspath += files(sourceSets.main.java.outputDir)
260     compileClasspath += sourceSets.main.compileClasspath
261     compileClasspath += fileTree(dir: "$jalviewDir/$utilsDir", include: ["**/*.jar"])
262     compileClasspath += fileTree(dir: "$jalviewDir/$libDir", include: ["*.jar"])
263
264     runtimeClasspath = compileClasspath
265   }
266
267   test {
268     java {
269       srcDirs "$jalviewDir/$testSourceDir"
270       outputDir = file("$jalviewDir/$testOutputDir")
271     }
272
273     resources {
274       srcDirs = sourceSets.main.resources.srcDirs
275     }
276
277     compileClasspath = files( sourceSets.test.java.outputDir )
278
279     if (use_clover) {
280       compileClasspath += sourceSets.clover.compileClasspath
281     } else {
282       compileClasspath += files(sourceSets.main.java.outputDir)
283     }
284
285     compileClasspath += fileTree(dir: "$jalviewDir/$libDir", include: ["*.jar"])
286     compileClasspath += fileTree(dir: "$jalviewDir/$utilsDir/testnglibs", include: ["**/*.jar"])
287     compileClasspath += fileTree(dir: "$jalviewDir/$utilsDir/testlibs", include: ["**/*.jar"])
288
289     runtimeClasspath = compileClasspath
290   }
291 }
292
293 // clover bits
294 dependencies {
295   if (use_clover) {
296     cloverCompile 'org.openclover:clover:4.3.1'
297     testCompile 'org.openclover:clover:4.3.1'
298   }
299 }
300
301 configurations {
302   cloverRuntime
303   cloverRuntime.extendsFrom cloverCompile
304 }
305
306 eclipse {
307   project {
308     name = eclipse_project_name
309
310     natures 'org.eclipse.jdt.core.javanature',
311     'org.eclipse.jdt.groovy.core.groovyNature',
312     'org.eclipse.buildship.core.gradleprojectnature'
313
314     buildCommand 'org.eclipse.jdt.core.javabuilder'
315     buildCommand 'org.eclipse.buildship.core.gradleprojectbuilder'
316   }
317
318   classpath {
319     //defaultOutputDir = sourceSets.main.java.outputDir
320     def removeThese = []
321     configurations.each{
322       if (it.isCanBeResolved()) {
323         removeThese += it
324       }
325     }
326
327     minusConfigurations += removeThese
328     plusConfigurations = [ ]
329     file {
330
331       whenMerged { cp ->
332         def removeTheseToo = []
333         HashMap<String, Boolean> alreadyAddedSrcPath = new HashMap<>();
334         cp.entries.each { entry ->
335           if (entry.kind == 'src') {
336             if (alreadyAddedSrcPath.getAt(entry.path) || !(entry.path == "src" || entry.path == "test")) {
337               removeTheseToo += entry
338             } else {
339               alreadyAddedSrcPath.putAt(entry.path, true)
340             }
341           }
342         }
343         cp.entries.removeAll(removeTheseToo)
344
345         if (file(eclipse_bin_dir+"/main").isDirectory()) {
346           cp.entries += new Output(eclipse_bin_dir+"/main")
347         }
348         if (file(helpParentDir).isDirectory()) {
349           cp.entries += new Library(fileReference(helpParentDir))
350         }
351         if (file(resourceDir).isDirectory()) {
352           cp.entries += new Library(fileReference(resourceDir))
353         }
354
355         HashMap<String, Boolean> alreadyAddedLibPath = new HashMap<>();
356
357         sourceSets.main.compileClasspath.findAll { it.name.endsWith(".jar") }.each {
358           //don't want to add outputDir as eclipse is using its own output dir in bin/main
359           if (it.isDirectory() || ! it.exists()) {
360             // don't add dirs to classpath
361             return
362           }
363           def itPath = it.toString()
364           if (itPath.startsWith(jalviewDirAbsolutePath+"/")) {
365             // make relative path
366             itPath = itPath.substring(jalviewDirAbsolutePath.length()+1)
367           }
368           if (alreadyAddedLibPath.get(itPath)) {
369             //println("Not adding duplicate entry "+itPath)
370           } else {
371             //println("Adding entry "+itPath)
372             cp.entries += new Library(fileReference(itPath))
373             alreadyAddedLibPath.put(itPath, true)
374           }
375         }
376
377         //fileTree(dir: "$jalviewDir/$utilsDir", include: ["test*/*.jar"]).each {
378         sourceSets.test.compileClasspath.findAll { it.name.endsWith(".jar") }.each {
379           //no longer want to add outputDir as eclipse is using its own output dir in bin/main
380           if (it.isDirectory() || ! it.exists()) {
381             // don't add dirs to classpath
382             return false // groovy "break" in .each closure
383           }
384           def itPath = it.toString()
385           if (itPath.startsWith(jalviewDirAbsolutePath+"/")) {
386             itPath = itPath.substring(jalviewDirAbsolutePath.length()+1)
387           }
388           if (alreadyAddedLibPath.get(itPath)) {
389             // don't duplicate
390           } else {
391             def lib = new Library(fileReference(itPath))
392             /* this doesn't work... yet.  Adding test=true attribute using withXml below
393             def attrs = new Node(null, 'attributes')
394             attrs.appendNode('attribute', ["name":"test","value":"true"])
395             lib.appendNode(attrs)
396             /**/
397             cp.entries += lib
398             alreadyAddedLibPath.put(itPath, true)
399           }
400         }
401
402       } // whenMerged
403
404       // withXml changes ignored by buildship, these add the "test=true" attribute
405       withXml {
406         def node = it.asNode()
407
408         def srcTestAttributes
409         node.children().each{ cpe ->
410           def attributes = cpe.attributes()
411           if (attributes.get("kind") == "src" && attributes.get("path") == "test") {
412             srcTestAttributes = cpe.find { a -> a.name() == "attributes" }
413             return
414           }
415         }
416         def addTestAttribute = true
417         srcTestAttributes.each{a ->
418           if (a.name() == "attribute" && a.attributes().getAt("name") == "test") {
419             addTestAttribute = false
420           }
421         }
422         if (addTestAttribute) {
423           srcTestAttributes.append(new Node(null, "attribute", [name:"test", value:"true"]))
424         }
425
426         node.children().each{ cpe ->
427           def attributes = cpe.attributes()
428           if (attributes.get("kind") == "lib" && attributes.get("path").startsWith("utils/")) {
429             cpe.appendNode('attributes')
430             .appendNode('attribute', [name:"test", value:"true"])
431           }
432         }
433       } // withXML
434
435
436     } // file
437
438     containers 'org.eclipse.buildship.core.gradleclasspathcontainer'
439
440   } // classpath
441
442   jdt {
443     // for the IDE, use java 11 compatibility
444     sourceCompatibility = compile_source_compatibility
445     targetCompatibility = compile_target_compatibility
446     javaRuntimeName = eclipse_java_runtime_name
447
448     // add in jalview project specific properties/preferences into eclipse core preferences
449     file {
450       withProperties { props ->
451         def jalview_prefs = new Properties()
452         def ins = new FileInputStream(jalviewDirAbsolutePath+"/"+eclipse_extra_jdt_prefs_file)
453         jalview_prefs.load(ins)
454         ins.close()
455         jalview_prefs.forEach { t, v ->
456           if (props.getAt(t) == null) {
457             props.putAt(t, v)
458           }
459         }
460       }
461     }
462
463   } // jdt
464
465 }
466
467 task cloverInstr() {
468   // only instrument source, we build test classes as normal
469   inputs.files files (sourceSets.main.allJava) // , fileTree(dir:"$jalviewDir/$testSourceDir", include: ["**/*.java"]))
470   outputs.dir cloverInstrDir
471
472   doFirst {
473     delete cloverInstrDir
474     def argsList = ["--initstring", "${buildDir}/clover/clover.db",
475     "-d", "${buildDir}/${cloverSourcesInstrDir}"]
476     argsList.addAll(inputs.files.files.collect({ file ->
477       file.absolutePath
478     }))
479     String[] args = argsList.toArray()
480     println("About to instrument "+args.length +" files")
481     com.atlassian.clover.CloverInstr.mainImpl(args)
482   }
483 }
484
485
486 task cloverReport {
487   group = "Verification"
488     description = "Createst the Clover report"
489     inputs.dir "${buildDir}/clover"
490     outputs.dir "${reportsDir}/clover"
491     onlyIf {
492       file("${buildDir}/clover/clover.db").exists()
493     }
494   doFirst {
495     def argsList = ["--initstring", "${buildDir}/clover/clover.db",
496     "-o", "${reportsDir}/clover"]
497     String[] args = argsList.toArray()
498     com.atlassian.clover.reporters.html.HtmlReporter.runReport(args)
499
500     // and generate ${reportsDir}/clover/clover.xml
501     args = ["--initstring", "${buildDir}/clover/clover.db",
502     "-o", "${reportsDir}/clover/clover.xml"].toArray()
503     com.atlassian.clover.reporters.xml.XMLReporter.runReport(args)
504   }
505 }
506
507 // end clover bits
508
509
510 compileJava {
511
512   doFirst {
513     sourceCompatibility = compile_source_compatibility
514     targetCompatibility = compile_target_compatibility
515     options.compilerArgs = additional_compiler_args
516     print ("Setting target compatibility to "+targetCompatibility+"\n")
517   }
518
519 }
520
521 compileTestJava {
522   if (use_clover) {
523     dependsOn compileCloverJava
524     classpath += configurations.cloverRuntime
525   } else {
526     classpath += sourceSets.main.runtimeClasspath
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 }
535
536
537 compileCloverJava {
538
539   doFirst {
540     sourceCompatibility = compile_source_compatibility
541     targetCompatibility = compile_target_compatibility
542     options.compilerArgs += additional_compiler_args
543     print ("Setting target compatibility to "+targetCompatibility+"\n")
544   }
545   classpath += configurations.cloverRuntime
546 }
547
548 clean {
549   delete sourceSets.main.java.outputDir
550 }
551
552 cleanTest {
553   delete sourceSets.test.java.outputDir
554   delete cloverInstrDir
555 }
556
557 // format is a string like date.format("dd MMMM yyyy")
558 def getDate(format) {
559   def date = new Date()
560   return date.format(format)
561 }
562
563 task setGitVals {
564   def hashStdOut = new ByteArrayOutputStream()
565   exec {
566     commandLine "git", "rev-parse", "--short", "HEAD"
567     standardOutput = hashStdOut
568     ignoreExitValue true
569   }
570
571   def branchStdOut = new ByteArrayOutputStream()
572   exec {
573     commandLine "git", "rev-parse", "--abbrev-ref", "HEAD"
574     standardOutput = branchStdOut
575     ignoreExitValue true
576   }
577
578   project.ext.gitHash = hashStdOut.toString().trim()
579   project.ext.gitBranch = branchStdOut.toString().trim()
580
581   outputs.upToDateWhen { false }
582 }
583
584 task createBuildProperties(type: WriteProperties) {
585   dependsOn setGitVals
586   inputs.dir("$jalviewDir/$sourceDir")
587   inputs.dir("$classes")
588   inputs.dir("$jalviewDir/$resourceDir")
589   outputFile (buildProperties)
590   // taking time specific comment out to allow better incremental builds
591   comment "--Jalview Build Details--\n"+getDate("yyyy-MM-dd HH:mm:ss")
592   //comment "--Jalview Build Details--\n"+getDate("yyyy-MM-dd")
593   property "BUILD_DATE", getDate("HH:mm:ss dd MMMM yyyy")
594   property "VERSION", JALVIEW_VERSION
595   property "INSTALLATION", INSTALLATION+" git-commit:"+project.ext.gitHash+" ["+project.ext.gitBranch+"]"
596   outputs.file(outputFile)
597 }
598
599 def buildingHTML = "$jalviewDir/$docDir/building.html"
600 task deleteBuildingHTML(type: Delete) {
601   delete buildingHTML
602 }
603
604 task convertBuildingMD(type: Exec) {
605   dependsOn deleteBuildingHTML
606   def buildingMD = "$jalviewDir/$docDir/building.md"
607   def css = "$jalviewDir/$docDir/github.css"
608
609   def pandoc = null
610   pandoc_exec.split(",").each {
611     if (file(it.trim()).exists()) {
612       pandoc = it.trim()
613       return true
614     }
615   }
616
617   def hostname = "hostname".execute().text.trim()
618   if ((pandoc == null || ! file(pandoc).exists()) && hostname.equals("jv-bamboo")) {
619     pandoc = System.getProperty("user.home")+"/buildtools/pandoc/bin/pandoc"
620   }
621
622   doFirst {
623     if (pandoc != null && file(pandoc).exists()) {
624         commandLine pandoc, '-s', '-o', buildingHTML, '--metadata', 'pagetitle="Building Jalview from Source"', '--toc', '-H', css, buildingMD
625     } else {
626         println("Cannot find pandoc. Skipping convert building.md to HTML")
627         throw new StopExecutionException()
628     }
629   }
630
631   ignoreExitValue true
632
633   inputs.file(buildingMD)
634   inputs.file(css)
635   outputs.file(buildingHTML)
636 }
637 clean {
638   delete buildingHTML
639 }
640
641 task syncDocs(type: Sync) {
642   dependsOn convertBuildingMD
643   def syncDir = "$classes/$docDir"
644   from fileTree("$jalviewDir/$docDir")
645   into syncDir
646
647 }
648
649 def helpFile = "$classes/$helpDir/help.jhm"
650
651 task copyHelp(type: Copy) {
652   def inputDir = "$jalviewDir/$helpParentDir/$helpDir"
653   def outputDir = "$classes/$helpDir"
654   from(inputDir) {
655     exclude '**/*.gif'
656       exclude '**/*.jpg'
657       exclude '**/*.png'
658       filter(ReplaceTokens, beginToken: '$$', endToken: '$$', tokens: ['Version-Rel': JALVIEW_VERSION,'Year-Rel': getDate("yyyy")])
659   }
660   from(inputDir) {
661     include '**/*.gif'
662       include '**/*.jpg'
663       include '**/*.png'
664   }
665   into outputDir
666
667   inputs.dir(inputDir)
668   outputs.files(helpFile)
669   outputs.dir(outputDir)
670 }
671
672 task syncLib(type: Sync) {
673   def syncDir = "$classes/$libDistDir"
674   from fileTree("$jalviewDir/$libDistDir")
675   into syncDir
676 }
677
678 task syncResources(type: Sync) {
679   from "$jalviewDir/$resourceDir"
680   include "**/*.*"
681   exclude "install4j"
682   into "$classes"
683   preserve {
684     include "**"
685   }
686 }
687
688 task prepare {
689   dependsOn syncResources
690   dependsOn syncDocs
691   dependsOn copyHelp
692 }
693
694
695 //testReportDirName = "test-reports" // note that test workingDir will be $jalviewDir
696 test {
697   dependsOn prepare
698   dependsOn compileJava
699   if (use_clover) {
700     dependsOn cloverInstr
701   }
702
703   if (use_clover) {
704     print("Running tests " + (use_clover?"WITH":"WITHOUT") + " clover [clover="+use_clover+"]\n")
705   }
706
707   useTestNG() {
708     includeGroups testngGroups
709     preserveOrder true
710     useDefaultListeners=true
711   }
712
713   workingDir = jalviewDir
714   //systemProperties 'clover.jar' System.properties.clover.jar
715   sourceCompatibility = compile_source_compatibility
716   targetCompatibility = compile_target_compatibility
717   jvmArgs += additional_compiler_args
718   print ("Setting target compatibility to "+targetCompatibility+"\n")
719 }
720
721 task buildIndices(type: JavaExec) {
722   dependsOn copyHelp
723   classpath = sourceSets.main.compileClasspath
724   main = "com.sun.java.help.search.Indexer"
725   workingDir = "$classes/$helpDir"
726   def argDir = "html"
727   args = [ argDir ]
728   inputs.dir("$workingDir/$argDir")
729
730   outputs.dir("$classes/doc")
731   outputs.dir("$classes/help")
732   outputs.file("$workingDir/JavaHelpSearch/DOCS")
733   outputs.file("$workingDir/JavaHelpSearch/DOCS.TAB")
734   outputs.file("$workingDir/JavaHelpSearch/OFFSETS")
735   outputs.file("$workingDir/JavaHelpSearch/POSITIONS")
736   outputs.file("$workingDir/JavaHelpSearch/SCHEMA")
737   outputs.file("$workingDir/JavaHelpSearch/TMAP")
738 }
739
740 task compileLinkCheck(type: JavaCompile) {
741   options.fork = true
742   classpath = files("$jalviewDir/$utilsDir")
743   destinationDir = file("$jalviewDir/$utilsDir")
744   source = fileTree(dir: "$jalviewDir/$utilsDir", include: ["HelpLinksChecker.java", "BufferedLineReader.java"])
745
746   inputs.file("$jalviewDir/$utilsDir/HelpLinksChecker.java")
747   inputs.file("$jalviewDir/$utilsDir/HelpLinksChecker.java")
748   outputs.file("$jalviewDir/$utilsDir/HelpLinksChecker.class")
749   outputs.file("$jalviewDir/$utilsDir/BufferedLineReader.class")
750 }
751
752 def helplinkscheckertouchfile = file("$jalviewDir/$utilsDir/HelpLinksChecker.touch")
753 task linkCheck(type: JavaExec) {
754   dependsOn prepare, compileLinkCheck
755   classpath = files("$jalviewDir/$utilsDir")
756   main = "HelpLinksChecker"
757   workingDir = jalviewDir
758   def help = "$classes/$helpDir"
759   args = [ "$classes/$helpDir", "-nointernet" ]
760
761   doLast {
762     helplinkscheckertouchfile.createNewFile()
763   }
764
765   inputs.dir("$classes/$helpDir")
766   outputs.file(helplinkscheckertouchfile)
767 }
768
769 // import the pubhtmlhelp target
770 ant.properties.basedir = "$jalviewDir"
771 ant.properties.helpBuildDir = jalviewDirAbsolutePath+"/$classes/$helpDir"
772 ant.importBuild "$utilsDir/publishHelp.xml"
773
774
775 task cleanPackageDir(type: Delete) {
776   delete fileTree("$jalviewDir/$packageDir").include("*.jar")
777 }
778
779 jar {
780   dependsOn linkCheck
781   dependsOn buildIndices
782   dependsOn createBuildProperties
783
784   manifest {
785     attributes "Main-Class": mainClass,
786     "Permissions": "all-permissions",
787     "Application-Name": "Jalview Desktop",
788     "Codebase": application_codebase
789   }
790
791   destinationDir = file("$jalviewDir/$packageDir")
792   archiveName = rootProject.name+".jar"
793
794   exclude "cache*/**"
795   exclude "*.jar"
796   exclude "*.jar.*"
797   exclude "**/*.jar"
798   exclude "**/*.jar.*"
799
800   inputs.dir("$classes")
801   outputs.file("$jalviewDir/$packageDir/$archiveName")
802 }
803
804 task copyJars(type: Copy) {
805   from fileTree("$classes").include("**/*.jar").include("*.jar").files
806   into "$jalviewDir/$packageDir"
807 }
808
809 // doing a Sync instead of Copy as Copy doesn't deal with "outputs" very well
810 task syncJars(type: Sync) {
811   from fileTree("$jalviewDir/$libDistDir").include("**/*.jar").include("*.jar").files
812   into "$jalviewDir/$packageDir"
813   preserve {
814     include jar.archiveName
815   }
816 }
817
818 task makeDist {
819   group = "build"
820   description = "Put all required libraries in dist"
821   // order of "cleanPackageDir", "copyJars", "jar" important!
822   jar.mustRunAfter cleanPackageDir
823   syncJars.mustRunAfter cleanPackageDir
824   dependsOn cleanPackageDir
825   dependsOn syncJars
826   dependsOn jar
827   outputs.dir("$jalviewDir/$packageDir")
828 }
829
830 task cleanDist {
831   dependsOn cleanPackageDir
832   dependsOn cleanTest
833   dependsOn clean
834 }
835
836 shadowJar {
837   group = "distribution"
838   if (buildDist) {
839     dependsOn makeDist
840   }
841   from ("$jalviewDir/$libDistDir") {
842     include("*.jar")
843   }
844   manifest {
845     attributes 'Implementation-Version': JALVIEW_VERSION
846   }
847   mainClassName = shadowJarMainClass
848   mergeServiceFiles()
849   classifier = "all-"+JALVIEW_VERSION+"-j"+JAVA_VERSION
850   minimize()
851 }
852
853 task getdownWebsite() {
854   group = "distribution"
855   description = "Create the getdown minimal app folder, and website folder for this version of jalview. Website folder also used for offline app installer"
856   if (buildDist) {
857     dependsOn makeDist
858   }
859
860         // clean the getdown website and files dir before creating getdown folders
861         delete project.ext.getdownWebsiteDir
862         delete project.ext.getdownFilesDir
863
864   def getdownWebsiteResourceFilenames = []
865   def getdownTextString = ""
866   def getdownResourceDir = project.ext.getdownResourceDir
867   def getdownAppDir = project.ext.getdownAppDir
868   def getdownResourceFilenames = []
869
870   doFirst {
871     copy {
872       from buildProperties
873       rename(buildPropertiesFile, getdown_build_properties)
874       into project.ext.getdownAppDir
875     }
876     getdownWebsiteResourceFilenames += getdown_app_dir+"/"+getdown_build_properties
877
878     // go through properties looking for getdown_txt_...
879     def props = project.properties.sort { it.key }
880         if (getdown_alt_java_min_version.length() > 0) {
881                 props.put("getdown_txt_java_min_version", getdown_alt_java_min_version)
882         }
883         if (getdown_alt_java_max_version.length() > 0) {
884                 props.put("getdown_txt_java_max_version", getdown_alt_java_max_version)
885         }
886         props.put("getdown_txt_multi_java_location", getdown_alt_multi_java_location)
887
888     props.put("getdown_txt_appbase", getdown_app_base)
889     props.each{ prop, val ->
890       if (prop.startsWith("getdown_txt_") && val != null) {
891         if (prop.startsWith("getdown_txt_multi_")) {
892           def key = prop.substring(18)
893           val.split(",").each{ v ->
894             def line = key + " = " + v + "\n"
895             getdownTextString += line
896           }
897         } else {
898           // file values rationalised
899           if (val.indexOf('/') > -1 || prop.startsWith("getdown_txt_resource")) {
900             def r = null
901             if (val.indexOf('/') == 0) {
902               // absolute path
903               r = file(val)
904             } else if (val.indexOf('/') > 0) {
905               // relative path (relative to jalviewDir)
906               r = file( jalviewDir + '/' + val )
907             }
908             if (r.exists()) {
909               val = getdown_resource_dir + '/' + r.getName()
910               getdownWebsiteResourceFilenames += val
911               getdownResourceFilenames += r.getPath()
912             }
913           }
914           if (! prop.startsWith("getdown_txt_resource")) {
915             def line = prop.substring(12) + " = " + val + "\n"
916             getdownTextString += line
917           }
918         }
919       }
920     }
921
922     getdownWebsiteResourceFilenames.each{ filename ->
923       getdownTextString += "resource = "+filename+"\n"
924     }
925     getdownResourceFilenames.each{ filename ->
926       copy {
927         from filename
928         into project.ext.getdownResourceDir
929       }
930     }
931
932     def codeFiles = []
933     fileTree(file(packageDir)).each{ f ->
934       if (f.isDirectory()) {
935         def files = fileTree(dir: f, include: ["*"]).getFiles()
936         codeFiles += files
937       } else if (f.exists()) {
938         codeFiles += f
939       }
940     }
941     codeFiles.sort().each{f ->
942       def line = "code = " + getdown_app_dir + '/' + f.getName() + "\n"
943       getdownTextString += line
944       copy {
945         from f.getPath()
946         into project.ext.getdownAppDir
947       }
948     }
949
950     // NOT USING MODULES YET, EVERYTHING SHOULD BE IN dist
951     /*
952     if (JAVA_VERSION.equals("11")) {
953     def j11libFiles = fileTree(dir: "$jalviewDir/$j11libDir", include: ["*.jar"]).getFiles()
954     j11libFiles.sort().each{f ->
955     def line = "code = " + getdown_j11lib_dir + '/' + f.getName() + "\n"
956     getdownTextString += line
957     copy {
958     from f.getPath()
959     into project.ext.getdownJ11libDir
960     }
961     }
962     }
963      */
964
965     // 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.
966     //getdownTextString += "class = " + file(getdownLauncher).getName() + "\n"
967     getdownTextString += "resource = " + getdown_launcher_new + "\n"
968     getdownTextString += "class = " + mainClass + "\n"
969
970     def getdown_txt = file(project.ext.getdownWebsiteDir + "/getdown.txt")
971     getdown_txt.write(getdownTextString)
972
973     def launch_jvl = file(project.ext.getdownWebsiteDir + "/" + getdown_launch_jvl)
974     launch_jvl.write("appbase="+props.get("getdown_txt_appbase"))
975
976     copy {
977       from getdownLauncher
978       rename(file(getdownLauncher).getName(), getdown_launcher_new)
979       into project.ext.getdownWebsiteDir
980     }
981
982     copy {
983       from getdownLauncher
984       if (file(getdownLauncher).getName() != getdown_launcher) {
985         rename(file(getdownLauncher).getName(), getdown_launcher)
986       }
987       into project.ext.getdownWebsiteDir
988     }
989
990     if (! (CHANNEL.startsWith("ARCHIVE") || CHANNEL.startsWith("DEVELOP"))) {
991       copy {
992         from getdown_txt
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 getdownInstallDir
999       }
1000
1001       copy {
1002         from getdownInstallDir
1003         into getdownFilesInstallDir
1004       }
1005     }
1006
1007     copy {
1008       from getdown_txt
1009       from launch_jvl
1010       from getdownLauncher
1011       from getdownWebsiteDir+"/"+getdown_build_properties
1012       if (file(getdownLauncher).getName() != getdown_launcher) {
1013         rename(file(getdownLauncher).getName(), getdown_launcher)
1014       }
1015       into getdownFilesDir
1016     }
1017
1018     copy {
1019           from getdownResourceDir
1020       into project.ext.getdownFilesDir + '/' + getdown_resource_dir
1021     }
1022   }
1023
1024   if (buildDist) {
1025     inputs.dir(jalviewDir + '/' + packageDir)
1026   }
1027   outputs.dir(project.ext.getdownWebsiteDir)
1028   outputs.dir(project.ext.getdownFilesDir)
1029 }
1030
1031 task getdownDigest(type: JavaExec) {
1032   group = "distribution"
1033   description = "Digest the getdown website folder"
1034   dependsOn getdownWebsite
1035   doFirst {
1036     classpath = files(getdownWebsiteDir + '/' + getdown_launcher)
1037   }
1038   main = "com.threerings.getdown.tools.Digester"
1039   args project.ext.getdownWebsiteDir
1040   inputs.dir(project.ext.getdownWebsiteDir)
1041   outputs.file(project.ext.getdownWebsiteDir + '/' + "digest2.txt")
1042 }
1043
1044 task getdown() {
1045   group = "distribution"
1046   description = "Create the minimal and full getdown app folder for installers and website and create digest file"
1047   dependsOn getdownDigest
1048   doLast {
1049     if (reportRsyncCommand) {
1050       def fromDir = getdownWebsiteDir + (getdownWebsiteDir.endsWith("/")?"":"/")
1051       def toDir = getdown_rsync_dest + "/" + getdownDir + (getdownDir.endsWith("/")?"":"/")
1052       println "LIKELY RSYNC COMMAND:"
1053       println "mkdir -p '$toDir'\nrsync -avh --delete '$fromDir' '$toDir'"
1054       if (RUNRSYNC == "true") {
1055         exec {
1056           commandLine "mkdir", "-p", toDir
1057         }
1058         exec {
1059           commandLine "rsync", "-avh", "--delete", fromDir, toDir
1060         }
1061       }
1062     }
1063   }
1064 }
1065
1066 clean {
1067   delete project.ext.getdownWebsiteDir
1068   delete project.ext.getdownFilesDir
1069 }
1070
1071 install4j {
1072   def install4jHomeDir = "/opt/install4j"
1073   def hostname = "hostname".execute().text.trim()
1074   if (hostname.equals("jv-bamboo")) {
1075     install4jHomeDir = System.getProperty("user.home")+"/buildtools/install4j"
1076   } else if (OperatingSystem.current().isMacOsX()) {
1077     install4jHomeDir = '/Applications/install4j.app/Contents/Resources/app'
1078     if (! file(install4jHomeDir).exists()) {
1079       install4jHomeDir = System.getProperty("user.home")+install4jHomeDir
1080     }
1081   } else if (OperatingSystem.current().isLinux()) {
1082     install4jHomeDir = System.getProperty("user.home")+"/buildtools/install4j"
1083   }
1084   installDir = file(install4jHomeDir)
1085   mediaTypes = Arrays.asList(install4jMediaTypes.split(","))
1086   if (install4jFaster.equals("true")) {
1087     faster = true
1088   }
1089 }
1090
1091 def install4jConf
1092 def macosJavaVMDir
1093 def macosJavaVMTgz
1094 def windowsJavaVMDir
1095 def windowsJavaVMTgz
1096 def install4jDir = "$jalviewDir/$install4jResourceDir"
1097 def install4jConfFile = "jalview-installers-java"+JAVA_VERSION+".install4j"
1098 install4jConf = "$install4jDir/$install4jConfFile"
1099
1100 task copyInstall4jTemplate(type: Copy) {
1101   macosJavaVMDir = System.env.HOME+"/buildtools/jre/openjdk-java_vm/getdown/macos-jre"+JAVA_VERSION+"/jre"
1102   macosJavaVMTgz = System.env.HOME+"/buildtools/jre/openjdk-java_vm/install4j/tgz/macos-jre"+JAVA_VERSION+".tar.gz"
1103   windowsJavaVMDir = System.env.HOME+"/buildtools/jre/openjdk-java_vm/getdown/windows-jre"+JAVA_VERSION+"/jre"
1104   windowsJavaVMTgz = System.env.HOME+"/buildtools/jre/openjdk-java_vm/install4j/tgz/windows-jre"+JAVA_VERSION+".tar.gz"
1105   from (install4jDir) {
1106     include install4jTemplate
1107     rename (install4jTemplate, install4jConfFile)
1108     filter(ReplaceTokens, beginToken: '', endToken: '', tokens: ['9999999999': JAVA_VERSION])
1109     filter(ReplaceTokens, beginToken: '$$', endToken: '$$',
1110     tokens: [
1111     'JAVA_VERSION': JAVA_VERSION,
1112     'JAVA_INTEGER_VERSION': JAVA_INTEGER_VERSION,
1113     'VERSION': JALVIEW_VERSION,
1114     'MACOS_JAVA_VM_DIR': macosJavaVMDir,
1115     'MACOS_JAVA_VM_TGZ': macosJavaVMTgz,
1116     'WINDOWS_JAVA_VM_DIR': windowsJavaVMDir,
1117     'WINDOWS_JAVA_VM_TGZ': windowsJavaVMTgz,
1118     'INSTALL4JINFOPLISTFILEASSOCIATIONS': install4jInfoPlistFileAssociations,
1119     'COPYRIGHT_MESSAGE': install4jCopyrightMessage,
1120     'MACOS_BUNDLE_ID': install4jMacOSBundleId,
1121     'GETDOWN_RESOURCE_DIR': getdown_resource_dir,
1122     'GETDOWN_DIST_DIR': getdown_app_dir,
1123     'GETDOWN_ALT_DIR': getdown_app_dir_alt,
1124     'GETDOWN_INSTALL_DIR': getdown_install_dir
1125     ]
1126     )
1127     if (OSX_KEYPASS=="") {
1128       filter(ReplaceTokens, beginToken: 'codeSigning macEnabled="', endToken: '"', tokens: ['true':'codeSigning macEnabled="false"'])
1129       filter(ReplaceTokens, beginToken: 'runPostProcessor="true" ',endToken: 'Processor', tokens: ['post':'runPostProcessor="false" postProcessor'])
1130     }
1131   }
1132   into install4jDir
1133   outputs.files(install4jConf)
1134
1135   doLast {
1136     // include file associations in installer
1137     def installerFileAssociationsXml = file("$install4jDir/$install4jInstallerFileAssociations").text
1138     ant.replaceregexp(
1139       byline: false,
1140       flags: "s",
1141       match: '<action name="EXTENSIONS_REPLACED_BY_GRADLE".*?</action>',
1142       replace: installerFileAssociationsXml,
1143       file: install4jConf
1144     )
1145     /*
1146     // include uninstaller applescript app files in dmg
1147     def installerDMGUninstallerXml = file("$install4jDir/$install4jDMGUninstallerAppFiles").text
1148     ant.replaceregexp(
1149     byline: false,
1150     flags: "s",
1151     match: '<file name="UNINSTALL_OLD_JALVIEW_APP_REPLACED_IN_GRADLE" file=.*?>',
1152     replace: installerDMGUninstallerXml,
1153     file: install4jConf
1154     )
1155      */
1156   }
1157 }
1158
1159 task installers(type: com.install4j.gradle.Install4jTask) {
1160   group = "distribution"
1161   description = "Create the install4j installers"
1162   dependsOn getdown
1163   dependsOn copyInstall4jTemplate
1164   projectFile = file(install4jConf)
1165   println("Using projectFile "+projectFile)
1166   variables = [majorVersion: version.substring(2, 11), build: 001, OSX_KEYSTORE: OSX_KEYSTORE, JSIGN_SH: JSIGN_SH]
1167   destination = "$jalviewDir/$install4jBuildDir/$JAVA_VERSION"
1168   buildSelected = true
1169
1170   if (OSX_KEYPASS) {
1171     macKeystorePassword=OSX_KEYPASS
1172
1173   }
1174
1175   inputs.dir(project.ext.getdownWebsiteDir)
1176   inputs.file(install4jConf)
1177   inputs.dir(macosJavaVMDir)
1178   inputs.dir(windowsJavaVMDir)
1179   outputs.dir("$jalviewDir/$install4jBuildDir/$JAVA_VERSION")
1180
1181 }
1182
1183 clean {
1184   delete install4jConf
1185 }
1186
1187 task sourceDist (type: Tar) {
1188   
1189   def VERSION_UNDERSCORES = JALVIEW_VERSION.replaceAll("\\.", "_")
1190   def outputFileName = project.name + "_" + VERSION_UNDERSCORES + ".tar.gz"
1191   // cater for buildship < 3.1 [3.0.1 is max version in eclipse 2018-09]
1192   try {
1193     archiveFileName = outputFileName
1194   } catch (Exception e) {
1195     archiveName = outputFileName
1196   }
1197   
1198   compression Compression.GZIP
1199   
1200   into project.name
1201
1202   def EXCLUDE_FILES=["build/*","bin/*","test-output/","test-reports","tests","clover*/*"
1203   ,".*"
1204   ,"benchmarking/*"
1205   ,"**/.*"
1206   ,"*.class"
1207   ,"**/*.class","$j11modDir/**/*.jar","appletlib","**/*locales"
1208   ,"*locales/**",
1209   ,"utils/InstallAnywhere"] 
1210   def PROCESS_FILES=[   "AUTHORS",
1211   "CITATION",
1212   "FEATURETODO",
1213   "JAVA-11-README",
1214   "FEATURETODO",
1215   "LICENSE",
1216   "**/README",
1217   "RELEASE",
1218   "THIRDPARTYLIBS","TESTNG",
1219   "build.gradle",
1220   "gradle.properties",
1221   "**/*.java",
1222   "**/*.html",
1223   "**/*.xml",
1224   "**/*.gradle",
1225   "**/*.groovy",
1226   "**/*.properties",
1227   "**/*.perl",
1228   "**/*.sh"]
1229
1230   from(jalviewDir) {
1231     exclude (EXCLUDE_FILES)
1232     include (PROCESS_FILES)
1233     filter(ReplaceTokens, beginToken: '$$', endToken: '$$', tokens: ['Version-Rel': JALVIEW_VERSION,'Year-Rel': getDate("yyyy")])
1234   }
1235   from(jalviewDir) {
1236     exclude (EXCLUDE_FILES)
1237     exclude (PROCESS_FILES)
1238   exclude ("appletlib")
1239   exclude ("**/*locales")
1240   exclude ("*locales/**")
1241   exclude ("utils/InstallAnywhere")
1242
1243     exclude (getdown_files_dir)
1244   exclude (getdown_website_dir)
1245
1246   // exluding these as not using jars as modules yet
1247   exclude ("$j11modDir/**/*.jar")
1248 }
1249 //  from (jalviewDir) {
1250 //    // explicit includes for stuff that seemed to not get included
1251 //    include(fileTree("test/**/*."))
1252 //    exclude(EXCLUDE_FILES)
1253 //    exclude(PROCESS_FILES)
1254 //  }
1255 }
1256
1257 task helppages  {
1258   dependsOn copyHelp
1259   dependsOn pubhtmlhelp
1260   
1261   inputs.dir("$classes/$helpDir")
1262   outputs.dir("$helpOutputDir")
1263 }
1264
1265 def jalviewjsBuildDir
1266 def jalviewjsSiteDir
1267 def jalviewjsTransferSiteDir
1268 task jalviewjsSitePath {
1269   if (jalviewjs_site_dir.startsWith("/")) {
1270     jalviewjsSiteDir = jalviewjs_site_dir
1271   } else {
1272     def relativeBuildDir = file(jalviewDirAbsolutePath).toPath().relativize(buildDir.toPath())
1273     jalviewjsBuildDir = "${relativeBuildDir}/jalviewjs"
1274     jalviewjsSiteDir = jalviewjsBuildDir + "/" + jalviewjs_site_dir
1275   }
1276   jalviewjsTransferSiteDir = jalviewjsBuildDir + "/tmp/site"
1277 }
1278
1279 def eclipseWorkspace
1280 task jalviewjsSetEclipseWorkspace {
1281   def propKey = "jalviewjs_eclipse_workspace"
1282   def propsFileName = "${jalviewjsBuildDir}/${jalviewjs_eclipse_workspace_location_file}"
1283   def props = new Properties()
1284   def eclipseWsDir
1285   def propVal = null
1286   if (project.hasProperty(propKey)) {
1287     propVal = project.getProperty(propKey)
1288     eclipseWsDir = propVal
1289   }
1290   if (( eclipseWsDir == null || !file(eclipseWsDir).exists() ) && file(propsFileName).exists()) {
1291     def ins = new FileInputStream(propsFileName)
1292     props.load(ins)
1293     ins.close()
1294     if (props.getProperty(propKey, null) != null) {
1295       eclipseWsDir = props.getProperty(propKey)
1296     }
1297   }
1298
1299   if (eclipseWsDir == null || !file(eclipseWsDir).exists()) {
1300     def tempDir = File.createTempDir()
1301     eclipseWsDir = tempDir.getAbsolutePath()
1302     props.setProperty(propKey, eclipseWsDir)
1303     def propsFile = file(propsFileName)
1304     propsFile.parentFile.mkdirs()
1305     propsFile.createNewFile() // doesn't affect existing file
1306     def outs = new FileOutputStream(propsFile, false)
1307     props.store(outs, null)
1308     outs.close()
1309   }
1310
1311   eclipseWorkspace = file(eclipseWsDir)
1312     
1313   println("ECLIPSE WORKSPACE: "+eclipseWorkspace.getPath())
1314
1315   inputs.property(propKey, propVal)
1316   outputs.file(propsFileName)
1317 }
1318
1319
1320 task jalviewjsUnzipFiles {
1321   dependsOn jalviewjsSitePath
1322
1323   def zipFiles = fileTree(dir: jalviewjs_utils_dir+"/"+jalviewjs_libjs_dir).include("*.zip")
1324   zipFiles += jalviewjs_utils_dir+"/"+jalviewjs_swingjs_zip
1325
1326   doLast {
1327     zipFiles.each { file_zip -> 
1328       copy {
1329         from zipTree(file_zip)
1330         into jalviewjsSiteDir
1331       }
1332     }
1333   }
1334
1335   inputs.files zipFiles
1336   outputs.dir jalviewjsSiteDir
1337 }
1338
1339 def eclipseDropinsDir
1340 def eclipseBinary
1341 def eclipseVersion
1342 def fromDropinsDir
1343 task jalviewjsEclipsePaths {
1344   def eclipseRoot
1345   def eclipseProduct
1346   eclipseRoot = jalviewjs_eclipse_root
1347   if (eclipseRoot.startsWith("~")) {
1348     eclipseRoot = System.getProperty("user.home") + eclipseRoot.substring(1)
1349   }
1350   if (OperatingSystem.current().isMacOsX()) {
1351     eclipseRoot += "/Eclipse.app"
1352     eclipseDropinsDir = eclipseRoot+"/Contents/Eclipse/dropins"
1353     eclipseBinary = eclipseRoot+"/Contents/MacOS/eclipse"
1354     eclipseProduct = eclipseRoot+"/Contents/Eclipse/.eclipseproduct"
1355   } else if (OperatingSystem.current().isWindows()) { // check these paths!!
1356     if (file(eclipseRoot+"/eclipse").isDirectory() && file(eclipseRoot+"/eclipse/.eclipseproduct").exists()) {
1357       eclipseRoot += "/eclipse"
1358     }
1359     eclipseDropinsDir = eclipseRoot+"/dropins"
1360     eclipseBinary = eclipseRoot+"/eclipse"
1361     eclipseProduct = eclipseRoot+"/.eclipseproduct"
1362   } else { // linux or unix
1363     if (file(eclipseRoot+"/eclipse").isDirectory() && file(eclipseRoot+"/eclipse/.eclipseproduct").exists()) {
1364       eclipseRoot += "/eclipse"
1365     }
1366     eclipseDropinsDir = eclipseRoot+"/dropins"
1367     eclipseBinary = eclipseRoot+"/eclipse"
1368     eclipseProduct = eclipseRoot+"/.eclipseproduct"
1369   }
1370
1371   def fis = new FileInputStream(eclipseProduct)
1372   def props = new Properties()
1373   props.load(fis)
1374   eclipseVersion = props.getProperty("version")
1375   fis.close()
1376   println("ECLIPSE_VERSION=${eclipseVersion}")
1377   String[] v = eclipseVersion.split("\\.")
1378   def v0 = Integer.valueOf(v[0])
1379   def v1 = Integer.valueOf(v[1])
1380   if (v0 < 4 || ( v0 == 4 && v1 < 13 )) {
1381     fromDropinsDir = "eclipse/dropins_4.12"
1382   } else {
1383     fromDropinsDir = "eclipse/dropins_4.13"
1384   } 
1385 }
1386
1387 task jalviewjsEclipseCopyDropins {
1388   dependsOn jalviewjsEclipsePaths
1389   def inputFiles = fileTree(dir: jalviewjs_utils_dir+"/"+fromDropinsDir, include: "*.jar")
1390   def outputDir = eclipseDropinsDir
1391
1392   inputs.files inputFiles
1393   inputFiles.each { file ->
1394     outputs.file(outputDir+"/"+file.name)
1395   }
1396
1397   doLast {
1398     def outputFiles = []
1399     inputFiles.each { file ->
1400       copy {
1401         from file
1402         into outputDir
1403       }
1404     }
1405   }
1406 }
1407
1408 task jalviewjsCreateJ2sSettings(type: WriteProperties) {
1409   dependsOn jalviewjsSitePath
1410   outputFile (jalviewDir+"/"+jalviewjs_j2s_settings)
1411   def props = project.properties.sort { it.key }
1412   def siteDirProperty = "j2s.site.directory"
1413   def setSiteDir = false
1414   props.each { prop, val ->
1415     if (prop.startsWith("j2s.") && val != null) {
1416       if (prop == siteDirProperty) {
1417         if (!(val.startsWith("/") || val.startsWith("file://") )) {
1418           val = jalviewjsTransferSiteDir+"/"+val
1419         }
1420         setSiteDir = true
1421       }
1422       property(prop,val)
1423     }
1424     if (!setSiteDir) {
1425       property(siteDirProperty,jalviewjsTransferSiteDir)
1426     }
1427   }
1428   outputs.file(outputFile)
1429 }
1430
1431 task jalviewjsEclipseSetup {
1432   dependsOn jalviewjsEclipseCopyDropins
1433   dependsOn jalviewjsSetEclipseWorkspace
1434   dependsOn jalviewjsCreateJ2sSettings
1435 }
1436
1437 task jalviewjsCopyResources (type: Copy) {
1438   dependsOn jalviewjsSitePath
1439   def inputFiles = fileTree(dir: jalviewjs_resource_dir)
1440   def outputDir = jalviewjsSiteDir+"/"+jalviewjs_j2s_subdir
1441
1442   from inputFiles
1443   into outputDir
1444   def outputFiles = []
1445   rename { filename ->
1446     outputFiles += outputDir+"/"+filename
1447     null
1448   }
1449   outputs.files outputFiles
1450   inputs.files inputFiles
1451 }
1452
1453 task jalviewjsCopySiteResources (type: Copy) {
1454   dependsOn jalviewjsSitePath
1455   def inputFiles = fileTree(dir: jalviewjs_utils_dir+"/"+jalviewjs_site_resource_dir)
1456   def outputDir = jalviewjsSiteDir
1457
1458   from inputFiles
1459   into outputDir
1460   def outputFiles = []
1461   rename { filename ->
1462     outputFiles += outputDir+"/"+filename
1463     null
1464   }
1465   outputs.files outputFiles
1466   inputs.files inputFiles
1467 }
1468
1469 task cleanJalviewjs {
1470   //delete jalviewjsBuildDir
1471   //delete jalviewDir+"/"+eclipse_bin_dir
1472   //delete file(eclipseWorkspace.getAbsolutePath()+"/.metadata")
1473   //delete jalviewDir+"/"+jalviewjs_j2s_settings
1474 }
1475
1476 task jalviewjsProjectImport(type: Exec) {
1477   // work out how to do this!
1478   dependsOn eclipseProject
1479   dependsOn eclipseClasspath
1480   dependsOn eclipseJdt
1481   dependsOn jalviewjsEclipsePaths
1482   dependsOn jalviewjsEclipseSetup
1483   executable(eclipseBinary)
1484   args(["-nosplash", "--launcher.suppressErrors", "-application", "com.seeq.eclipse.importprojects.headlessimport", "-data", eclipseWorkspace.getPath(), "-import", jalviewDirAbsolutePath])
1485
1486   def projdir = eclipseWorkspace.getPath()+"/.metadata/.plugins/org.eclipse.core.resources/.projects/jalview/org.eclipse.jdt.core"
1487   inputs.file(jalviewDir+"/.project")
1488   outputs.dir(projdir)
1489   outputs.upToDateWhen { file(projdir).exists() }
1490 }
1491
1492 task jalviewjsTranspile(type: Exec) {
1493   dependsOn jalviewjsEclipseSetup 
1494   dependsOn jalviewjsProjectImport
1495   dependsOn jalviewjsEclipsePaths
1496   executable(eclipseBinary)
1497   args(["-nosplash", "--launcher.suppressErrors", "-application", "org.eclipse.jdt.apt.core.aptBuild", "-data", eclipseWorkspace, "-"+jalviewjs_eclipseBuildArg, eclipse_project_name ])
1498
1499   def stdout
1500   def stderr
1501   doFirst {
1502     stdout = new ByteArrayOutputStream()
1503     stderr = new ByteArrayOutputStream()
1504
1505     def logOutFileName = "${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_j2s_stdout}"
1506     def logOutFile = file(logOutFileName)
1507     logOutFile.createNewFile()
1508     def logOutFOS = new FileOutputStream(logOutFile, false)
1509     //def logErrFileName = "${jalviewjsBuildDir}/${jalviewjs_j2s_stderr}"
1510     //def logErrFile = file(logFileName)
1511     //logErrFile.createNewFile()
1512     //def logErrFOS = new FileErrputStream(logErrFile, false)
1513     // combine stdout and stderr
1514     def logErrFOS = logOutFOS
1515     if (jalviewjs_j2s_to_console.equals("true")) {
1516       standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
1517         new org.apache.tools.ant.util.TeeOutputStream(
1518           logOutFOS,
1519           stdout),
1520         standardOutput)
1521       errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
1522         new org.apache.tools.ant.util.TeeOutputStream(
1523           logErrFOS,
1524           stderr),
1525         errorOutput)
1526     } else {
1527       standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
1528         logOutFOS,
1529         stdout)
1530       errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
1531         logErrFOS,
1532         stderr)
1533     }
1534   }
1535   doLast {
1536     if (stdout.toString().contains("Error processing ")) {
1537       // j2s did not complete transpile
1538       throw new GradleException("Error during transpilation:\n${stderr}\nSee eclipse transpile log file '${jalviewjsBuildDir}/${jalviewjs_j2s_stdout}'")
1539     }
1540   }
1541
1542   inputs.dir(sourceDir)
1543   outputs.dir(eclipse_bin_dir+"/main")
1544   outputs.dir(jalviewjsTransferSiteDir)
1545
1546 }
1547
1548 task jalviewjsCopyTransferSite(type: Copy) {
1549   dependsOn jalviewjsTranspile
1550   from jalviewjsTransferSiteDir
1551   into jalviewjsSiteDir
1552 }
1553
1554 jalviewjsUnzipFiles.mustRunAfter jalviewjsCopyTransferSite
1555 jalviewjsCopyResources.mustRunAfter jalviewjsCopyTransferSite
1556 jalviewjsCopySiteResources.mustRunAfter jalviewjsCopyTransferSite
1557
1558 task jalviewjsPrepareSite {
1559   group "JalviewJS"
1560   description "Prepares the website folder including unzipping files and copying resources"
1561   dependsOn jalviewjsSitePath
1562   dependsOn jalviewjsUnzipFiles
1563   dependsOn jalviewjsCopyResources
1564   dependsOn jalviewjsCopySiteResources
1565 }
1566
1567 task jalviewjsBuildSite {
1568   group "JalviewJS"
1569   description "Builds the whole website including transpiled code"
1570   dependsOn jalviewjsCopyTransferSite
1571   dependsOn jalviewjsPrepareSite
1572 }
1573
1574 task jalviewjsSiteTar(type: Tar) {
1575   group "JalviewJS"
1576   description "Creates a tar.gz file for the website"
1577   dependsOn jalviewjsBuildSite
1578   def outputFilename = "jalviewjs-site-${JALVIEW_VERSION}.tar.gz"
1579   try {
1580     archiveFileName = outputFilename
1581   } catch (Exception e) {
1582     archiveName = outputFilename
1583   }
1584
1585   compression Compression.GZIP
1586
1587   from jalviewjsSiteDir
1588   into jalviewjs_site_dir // this is inside the tar file
1589
1590   inputs.dir(jalviewjsSiteDir)
1591 }
1592
1593 task jalviewjsServer {
1594   group "JalviewJS"
1595   description "Starts a webserver on localhost to test the website"
1596   dependsOn jalviewjsSitePath
1597   doLast {
1598
1599     SimpleHttpFileServerFactory factory = new SimpleHttpFileServerFactory()
1600     def port = Integer.valueOf(jalviewjs_server_port)
1601     def start = port
1602     def running = false
1603     while(port < start+1000 && !running) {
1604       try {
1605         def doc_root = new File(jalviewDirAbsolutePath +"/"+ jalviewjsSiteDir)
1606         jalviewjsServer = factory.start(doc_root, port)
1607         running = true
1608         println("SERVER STARTED with document root ${doc_root}.")
1609         println("Go to "+jalviewjsServer.getResourceUrl(jalviewjs_server_resource)+" . Run  gradle --stop  to stop (kills all gradle daemons).")
1610         println("For debug: "+jalviewjsServer.getResourceUrl(jalviewjs_server_resource)+"?j2sdebug")
1611       } catch (Exception e) {
1612         port++;
1613       }
1614     }
1615
1616   }
1617
1618 }
1619
1620 task jalviewjs {
1621   group "JalviewJS"
1622   description "Build the site"
1623   dependsOn jalviewjsBuildSite
1624 }
1625
1626