Merge branch 'Jalview-JS/develop' into merge/Ben_trying_out_JSdevelop_with_develop
[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 import java.security.MessageDigest
6
7 import groovy.transform.ExternalizeMethods
8
9 buildscript {
10   dependencies {
11     classpath 'org.openclover:clover:4.3.1'
12   }
13 }
14
15 plugins {
16   id 'java'
17   id 'application'
18   id 'eclipse'
19   id 'com.github.johnrengelman.shadow' version '4.0.3'
20   id 'com.install4j.gradle' version '7.0.9'
21   id 'com.dorongold.task-tree' version '1.4' // only needed to display task dependency tree with  gradle task1 [task2 ...] taskTree
22 }
23
24 repositories {
25   jcenter()
26   mavenCentral()
27   mavenLocal()
28   flatDir {
29     dirs gradlePluginsDir
30   }
31 }
32
33 dependencies {
34   compile 'org.apache.commons:commons-compress:1.18'
35 }
36
37
38 // in ext the values are cast to Object. Ensure string values are cast as String (and not GStringImpl) for later use
39 def string(Object o) {
40   return o.toString()
41 }
42
43
44 ext {
45   jalviewDirAbsolutePath = file(jalviewDir).getAbsolutePath()
46   jalviewDirRelativePath = jalviewDir
47
48   // local build environment properties
49   def localProps = "${jalviewDirAbsolutePath}/local.properties"
50   if (file(localProps).exists()) {
51     try {
52       def p = new Properties()
53       def localPropsFIS = new FileInputStream(localProps)
54       p.load(localPropsFIS)
55       localPropsFIS.close()
56       p.each {
57         key, val -> 
58           def over = getProperty(key) != null
59           setProperty(key, val)
60           if (over) {
61             println("Overriding property '${key}' with local.properties value '${val}'")
62           }
63       }
64     } catch (Exception e) {
65       System.out.println("Exception reading local.properties")
66     }
67   }
68
69   // this property set when running Eclipse headlessly
70   j2sHeadlessBuildProperty = string("net.sf.j2s.core.headlessbuild")
71   // this property set by Eclipse
72   eclipseApplicationProperty = string("eclipse.application")
73   // CHECK IF RUNNING FROM WITHIN ECLIPSE
74   def eclipseApplicationPropertyVal = System.properties[eclipseApplicationProperty]
75   IN_ECLIPSE = eclipseApplicationPropertyVal != null && eclipseApplicationPropertyVal.startsWith("org.eclipse.ui.")
76   // BUT WITHOUT THE HEADLESS BUILD PROPERTY SET
77   if (System.properties[j2sHeadlessBuildProperty].equals("true")) {
78     println("Setting IN_ECLIPSE to ${IN_ECLIPSE} as System.properties['${j2sHeadlessBuildProperty}'] == '${System.properties[j2sHeadlessBuildProperty]}'")
79     IN_ECLIPSE = false
80   }
81   if (IN_ECLIPSE) {
82     println("WITHIN ECLIPSE IDE")
83   } else {
84     println("HEADLESS BUILD")
85   }
86   /* *-/
87   System.properties.sort { it.key }.each {
88     key, val -> println("SYSTEM PROPERTY ${key}='${val}'")
89   }
90   /-* *-/
91   if (false && IN_ECLIPSE) {
92     jalviewDir = jalviewDirAbsolutePath
93   }
94   */
95
96   // essentials
97   bareSourceDir = string(source_dir)
98   sourceDir = string("${jalviewDir}/${bareSourceDir}")
99   resourceDir = string("${jalviewDir}/${resource_dir}")
100   bareTestSourceDir = string(test_source_dir)
101   testSourceDir = string("${jalviewDir}/${bareTestSourceDir}")
102
103   // clover
104   cloverInstrDir = file("${buildDir}/${cloverSourcesInstrDir}")
105   classesDir = string("${jalviewDir}/${classes_dir}")
106   if (clover.equals("true")) {
107     use_clover = true
108     classesDir = string("${buildDir}/${cloverClassesDir}")
109   } else {
110     use_clover = false
111     classesDir = string("${jalviewDir}/${classes_dir}")
112   }
113
114   classes = classesDir
115
116   getdownWebsiteDir = string("${jalviewDir}/${getdown_website_dir}/${JAVA_VERSION}")
117   getdownDir = string("")
118   reportRsyncCmd = false
119   buildDist = true
120   buildProperties = build_properties_file
121   getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher}")
122   switch (CHANNEL) {
123
124     case "BUILD":
125     // TODO: get bamboo build artifact URL for getdown artifacts
126     getdown_channel_base = bamboo_channelbase
127     getdown_channel_name = string("${bamboo_planKey}/${JAVA_VERSION}")
128     getdown_app_base = string("${bamboo_channelbase}/${bamboo_planKey}${bamboo_getdown_channel_suffix}/${JAVA_VERSION}")
129     getdown_app_dir = getdown_app_dir_alt
130     buildProperties = string("${classesDir}/${build_properties_file}")
131     break
132
133     case "RELEASE":
134     getdown_channel_name = CHANNEL.toLowerCase()
135     getdownDir = string("${getdown_channel_name}/${JAVA_VERSION}")
136     getdown_app_base = string("${getdown_channel_base}/${getdownDir}")
137     getdown_app_dir = getdown_app_dir_release
138     buildProperties = string("${classesDir}/${build_properties_file}")
139     reportRsyncCommand = true
140     break
141
142     case "ARCHIVE":
143     getdown_channel_name = CHANNEL.toLowerCase()+"/${JALVIEW_VERSION}"
144     getdownDir = string("${getdown_channel_name}/${JAVA_VERSION}")
145     getdown_app_base = string("${getdown_channel_base}/${getdownDir}")
146     getdown_app_dir = getdown_app_dir_alt
147     if (!file("${ARCHIVEDIR}/${packageDir}").exists()) {
148       print "Must provide an ARCHIVEDIR value to produce an archive distribution"
149       exit
150     } else {
151       packageDir = string("${ARCHIVEDIR}/${packageDir}")
152       buildProperties = string("${ARCHIVEDIR}/${classes_dir}/${build_properties_file}")
153       buildDist = false
154     }
155     reportRsyncCommand = true
156     break
157
158     case "ARCHIVELOCAL":
159     getdown_channel_name = string("archive/${JALVIEW_VERSION}")
160     getdownDir = string("${getdown_channel_name}/${JAVA_VERSION}")
161     getdown_app_base = file(getdownWebsiteDir).toURI().toString()
162     getdown_app_dir = getdown_app_dir_alt
163     if (!file("${ARCHIVEDIR}/${packageDir}").exists()) {
164       print "Must provide an ARCHIVEDIR value to produce an archive distribution"
165       exit
166     } else {
167       packageDir = string("${ARCHIVEDIR}/${packageDir}")
168       buildProperties = string("${ARCHIVEDIR}/${classes_dir}/${build_properties_file}")
169       buildDist = false
170     }
171     reportRsyncCommand = true
172     getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher_local}")
173     break
174
175     case "DEVELOP":
176     getdown_channel_name = CHANNEL.toLowerCase()
177     getdownDir = string("${getdown_channel_name}/${JAVA_VERSION}")
178     getdown_app_base = string("${getdown_channel_base}/${getdownDir}")
179     getdown_app_dir = getdown_app_dir_alt
180     buildProperties = string("${classesDir}/${build_properties_file}")
181     reportRsyncCommand = true
182     break
183
184     case "TEST-RELEASE":
185     getdown_channel_name = CHANNEL.toLowerCase()
186     getdownDir = string("${getdown_channel_name}/${JAVA_VERSION}")
187     getdown_app_base = string("${getdown_channel_base}/${getdownDir}")
188     getdown_app_dir = getdown_app_dir_alt
189     buildProperties = string("${classesDir}/${build_properties_file}")
190     reportRsyncCommand = true
191     break
192
193     case ~/^SCRATCH(|-[-\w]*)$/:
194     getdown_channel_name = CHANNEL
195     getdownDir = string("${getdown_channel_name}/${JAVA_VERSION}")
196     getdown_app_base = string("${getdown_channel_base}/${getdownDir}")
197     getdown_app_dir = getdown_app_dir_alt
198     buildProperties = string("${classesDir}/${build_properties_file}")
199     reportRsyncCommand = true
200     break
201
202     case "LOCAL":
203     getdown_app_base = file(getdownWebsiteDir).toURI().toString()
204     getdown_app_dir = getdown_app_dir_alt
205     buildProperties = string("${classesDir}/${build_properties_file}")
206     getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher_local}")
207     break
208
209     default: // something wrong specified
210     print("CHANNEL must be one of BUILD, RELEASE, ARCHIVE, DEVELOP, TEST-RELEASE, SCRATCH-..., LOCAL [default]")
211     exit
212     break
213
214   }
215
216   getdownAppDir = string("${getdownWebsiteDir}/${getdown_app_dir}")
217   //getdownJ11libDir = "${getdownWebsiteDir}/${getdown_j11lib_dir}"
218   getdownResourceDir = string("${getdownWebsiteDir}/${getdown_resource_dir}")
219   getdownInstallDir = string("${getdownWebsiteDir}/${getdown_install_dir}")
220   getdownFilesDir = string("${jalviewDir}/${getdown_files_dir}/${JAVA_VERSION}/")
221   getdownFilesInstallDir = string("${getdownFilesDir}/${getdown_install_dir}")
222   /* compile without modules -- using classpath libraries
223   modules_compileClasspath = fileTree(dir: "${jalviewDir}/${j11modDir}", include: ["*.jar"])
224   modules_runtimeClasspath = modules_compileClasspath
225   */
226   gitHash = string("")
227   gitBranch = string("")
228
229   println("Using a ${CHANNEL} profile.")
230
231   additional_compiler_args = []
232   // configure classpath/args for j8/j11 compilation
233   if (JAVA_VERSION.equals("1.8")) {
234     JAVA_INTEGER_VERSION = string("8")
235     //libDir = j8libDir
236     libDir = j11libDir
237     libDistDir = j8libDir
238     compile_source_compatibility = 1.8
239     compile_target_compatibility = 1.8
240     // these are getdown.txt properties defined dependent on the JAVA_VERSION
241     getdown_alt_java_min_version = getdown_alt_java8_min_version
242     getdown_alt_java_max_version = getdown_alt_java8_max_version
243     // this property is assigned below and expanded to multiple lines in the getdown task
244     getdown_alt_multi_java_location = getdown_alt_java8_txt_multi_java_location
245     // this property is for the Java library used in eclipse
246     eclipse_java_runtime_name = string("JavaSE-1.8")
247   } else if (JAVA_VERSION.equals("11")) {
248     JAVA_INTEGER_VERSION = string("11")
249     libDir = j11libDir
250     libDistDir = j11libDir
251     compile_source_compatibility = 11
252     compile_target_compatibility = 11
253     getdown_alt_java_min_version = getdown_alt_java11_min_version
254     getdown_alt_java_max_version = getdown_alt_java11_max_version
255     getdown_alt_multi_java_location = getdown_alt_java11_txt_multi_java_location
256     eclipse_java_runtime_name = string("JavaSE-11")
257     /* compile without modules -- using classpath libraries
258     additional_compiler_args += [
259     '--module-path', modules_compileClasspath.asPath,
260     '--add-modules', j11modules
261     ]
262      */
263   } else if (JAVA_VERSION.equals("12") || JAVA_VERSION.equals("13")) {
264     JAVA_INTEGER_VERSION = JAVA_VERSION
265     libDir = j11libDir
266     libDistDir = j11libDir
267     compile_source_compatibility = JAVA_VERSION
268     compile_target_compatibility = JAVA_VERSION
269     getdown_alt_java_min_version = getdown_alt_java11_min_version
270     getdown_alt_java_max_version = getdown_alt_java11_max_version
271     getdown_alt_multi_java_location = getdown_alt_java11_txt_multi_java_location
272     eclipse_java_runtime_name = string("JavaSE-11")
273     /* compile without modules -- using classpath libraries
274     additional_compiler_args += [
275     '--module-path', modules_compileClasspath.asPath,
276     '--add-modules', j11modules
277     ]
278      */
279   } else {
280     throw new GradleException("JAVA_VERSION=${JAVA_VERSION} not currently supported by Jalview")
281   }
282
283
284   // for install4j
285   macosJavaVMDir = string("${System.env.HOME}/buildtools/jre/openjdk-java_vm/getdown/macos-jre${JAVA_VERSION}/jre")
286   macosJavaVMTgz = string("${System.env.HOME}/buildtools/jre/openjdk-java_vm/install4j/tgz/macos-jre${JAVA_VERSION}.tar.gz")
287   windowsJavaVMDir = string("${System.env.HOME}/buildtools/jre/openjdk-java_vm/getdown/windows-jre${JAVA_VERSION}/jre")
288   windowsJavaVMTgz = string("${System.env.HOME}/buildtools/jre/openjdk-java_vm/install4j/tgz/windows-jre${JAVA_VERSION}.tar.gz")
289   install4jDir = string("${jalviewDir}/${install4jResourceDir}")
290   install4jConfFileName = string("jalview-installers-java${JAVA_VERSION}.install4j")
291   install4jConfFile = string("${install4jDir}/${install4jConfFileName}")
292
293
294   buildingHTML = string("${jalviewDir}/${docDir}/building.html")
295   helpFile = string("${classesDir}/${help_dir}/help.jhm")
296   helpParentDir = string("${jalviewDir}/${help_parent_dir}")
297   helpDir = string("${help_dir}")
298   helpSourceDir = string("${helpParentDir}/${helpDir}")
299
300
301   relativeBuildDir = file(jalviewDirAbsolutePath).toPath().relativize(buildDir.toPath())
302   jalviewjsBuildDir = string("${relativeBuildDir}/jalviewjs")
303   jalviewjsSiteDir = string("${jalviewjsBuildDir}/${jalviewjs_site_dir}")
304   if (IN_ECLIPSE) {
305     jalviewjsTransferSiteJsDir = string(jalviewjsSiteDir)
306   } else {
307     jalviewjsTransferSiteJsDir = string("${jalviewjsBuildDir}/tmp/${jalviewjs_site_dir}_js")
308   }
309   jalviewjsTransferSiteLibDir = string("${jalviewjsBuildDir}/tmp/${jalviewjs_site_dir}_lib")
310   jalviewjsTransferSiteSwingJsDir = string("${jalviewjsBuildDir}/tmp/${jalviewjs_site_dir}_swingjs")
311   jalviewjsTransferSiteCoreDir = string("${jalviewjsBuildDir}/tmp/${jalviewjs_site_dir}_core")
312   jalviewjsJalviewCoreHtmlFile = string("")
313   jalviewjsJalviewCoreName = string(jalviewjs_core_name)
314   jalviewjsCoreClasslists = []
315   jalviewjsJalviewTemplateName = string(jalviewjs_name)
316   jalviewjsJ2sSettingsFileName = string("${jalviewDir}/${jalviewjs_j2s_settings}")
317   jalviewjsJ2sProps = null
318
319   eclipseWorkspace = null
320   eclipseBinary = string("")
321   eclipseVersion = string("")
322   eclipseDebug = false
323   // ENDEXT
324 }
325
326
327 sourceSets {
328   main {
329     java {
330       srcDirs sourceDir
331       outputDir = file(classesDir)
332     }
333
334     resources {
335       srcDirs resourceDir
336     }
337
338     jar.destinationDir = file("${jalviewDir}/${packageDir}")
339
340     compileClasspath = files(sourceSets.main.java.outputDir)
341     compileClasspath += fileTree(dir: "${jalviewDir}/${libDir}", include: ["*.jar"])
342
343     runtimeClasspath = compileClasspath
344   }
345
346   clover {
347     java {
348       srcDirs = [ cloverInstrDir ]
349       outputDir = file("${buildDir}/${cloverClassesDir}")
350     }
351
352     resources {
353       srcDirs = sourceSets.main.resources.srcDirs
354     }
355     compileClasspath = configurations.cloverRuntime + files( sourceSets.clover.java.outputDir )
356     compileClasspath += files(sourceSets.main.java.outputDir)
357     compileClasspath += sourceSets.main.compileClasspath
358     compileClasspath += fileTree(dir: "${jalviewDir}/${utilsDir}", include: ["**/*.jar"])
359     compileClasspath += fileTree(dir: "${jalviewDir}/${libDir}", include: ["*.jar"])
360
361     runtimeClasspath = compileClasspath
362   }
363
364   test {
365     java {
366       srcDirs testSourceDir
367       outputDir = file("${jalviewDir}/${testOutputDir}")
368     }
369
370     resources {
371       srcDirs = sourceSets.main.resources.srcDirs
372     }
373
374     compileClasspath = files( sourceSets.test.java.outputDir )
375
376     if (use_clover) {
377       compileClasspath += sourceSets.clover.compileClasspath
378     } else {
379       compileClasspath += files(sourceSets.main.java.outputDir)
380     }
381
382     compileClasspath += fileTree(dir: "${jalviewDir}/${libDir}", include: ["*.jar"])
383     compileClasspath += fileTree(dir: "${jalviewDir}/${utilsDir}/testnglibs", include: ["**/*.jar"])
384     compileClasspath += fileTree(dir: "${jalviewDir}/${utilsDir}/testlibs", include: ["**/*.jar"])
385
386     runtimeClasspath = compileClasspath
387   }
388 }
389
390
391 // clover bits
392 dependencies {
393   if (use_clover) {
394     cloverCompile 'org.openclover:clover:4.3.1'
395     testCompile 'org.openclover:clover:4.3.1'
396   }
397 }
398
399
400 configurations {
401   cloverRuntime
402   cloverRuntime.extendsFrom cloverCompile
403 }
404
405 eclipse {
406   project {
407     name = eclipse_project_name
408
409     natures 'org.eclipse.jdt.core.javanature',
410     'org.eclipse.jdt.groovy.core.groovyNature',
411     'org.eclipse.buildship.core.gradleprojectnature'
412
413     buildCommand 'org.eclipse.jdt.core.javabuilder'
414     buildCommand 'org.eclipse.buildship.core.gradleprojectbuilder'
415   }
416
417   classpath {
418     //defaultOutputDir = sourceSets.main.java.outputDir
419     def removeThese = []
420     configurations.each{
421       if (it.isCanBeResolved()) {
422         removeThese += it
423       }
424     }
425
426     minusConfigurations += removeThese
427     plusConfigurations = [ ]
428     file {
429
430       whenMerged { cp ->
431         def removeTheseToo = []
432         HashMap<String, Boolean> alreadyAddedSrcPath = new HashMap<>();
433         cp.entries.each { entry ->
434           // This conditional removes all src classpathentries that a) have already been added or b) aren't "src" or "test".
435           // e.g. this removes the resources dir being copied into bin/main, bin/test AND bin/clover
436           // we add the resources and help/help dirs in as libs afterwards (see below)
437           if (entry.kind == 'src') {
438             if (alreadyAddedSrcPath.getAt(entry.path) || !(entry.path == bareSourceDir || entry.path == bareTestSourceDir)) {
439               removeTheseToo += entry
440             } else {
441               alreadyAddedSrcPath.putAt(entry.path, true)
442             }
443           }
444
445         }
446         cp.entries.removeAll(removeTheseToo)
447
448         //cp.entries += new Output("${eclipse_bin_dir}/main")
449         if (file(helpSourceDir).isDirectory()) {
450           cp.entries += new Library(fileReference(helpSourceDir))
451         }
452         if (file(resourceDir).isDirectory()) {
453           cp.entries += new Library(fileReference(resourceDir))
454         }
455
456         HashMap<String, Boolean> alreadyAddedLibPath = new HashMap<>();
457
458         sourceSets.main.compileClasspath.findAll { it.name.endsWith(".jar") }.each {
459           //don't want to add outputDir as eclipse is using its own output dir in bin/main
460           if (it.isDirectory() || ! it.exists()) {
461             // don't add dirs to classpath, especially if they don't exist
462             return false // groovy "continue" in .any closure
463           }
464           def itPath = it.toString()
465           if (itPath.startsWith("${jalviewDirAbsolutePath}/")) {
466             // make relative path
467             itPath = itPath.substring(jalviewDirAbsolutePath.length()+1)
468           }
469           if (alreadyAddedLibPath.get(itPath)) {
470             //println("Not adding duplicate entry "+itPath)
471           } else {
472             //println("Adding entry "+itPath)
473             cp.entries += new Library(fileReference(itPath))
474             alreadyAddedLibPath.put(itPath, true)
475           }
476         }
477
478         //fileTree(dir: "$jalviewDir/$utilsDir", include: ["test*/*.jar"]).each {
479         sourceSets.test.compileClasspath.findAll { it.name.endsWith(".jar") }.any {
480           //no longer want to add outputDir as eclipse is using its own output dir in bin/main
481           if (it.isDirectory() || ! it.exists()) {
482             // don't add dirs to classpath
483             return false // groovy "continue" in .any closure
484           }
485
486           def itPath = it.toString()
487           if (itPath.startsWith("${jalviewDirAbsolutePath}/")) {
488             itPath = itPath.substring(jalviewDirAbsolutePath.length()+1)
489           }
490           if (alreadyAddedLibPath.get(itPath)) {
491             // don't duplicate
492           } else {
493             def lib = new Library(fileReference(itPath))
494             lib.entryAttributes["test"] = "true"
495             cp.entries += lib
496             alreadyAddedLibPath.put(itPath, true)
497           }
498         }
499
500       } // whenMerged
501
502     } // file
503
504     containers 'org.eclipse.buildship.core.gradleclasspathcontainer'
505
506   } // classpath
507
508   jdt {
509     // for the IDE, use java 11 compatibility
510     sourceCompatibility = compile_source_compatibility
511     targetCompatibility = compile_target_compatibility
512     javaRuntimeName = eclipse_java_runtime_name
513
514     // add in jalview project specific properties/preferences into eclipse core preferences
515     file {
516       withProperties { props ->
517         def jalview_prefs = new Properties()
518         def ins = new FileInputStream("${jalviewDirAbsolutePath}/${eclipse_extra_jdt_prefs_file}")
519         jalview_prefs.load(ins)
520         ins.close()
521         jalview_prefs.forEach { t, v ->
522           if (props.getAt(t) == null) {
523             props.putAt(t, v)
524           }
525         }
526       }
527     }
528
529   } // jdt
530
531   if (IN_ECLIPSE) {
532     // Don't want these to be activated if in headless build
533     synchronizationTasks "eclipseSynchronizationTask"
534     autoBuildTasks "eclipseAutoBuildTask"
535
536   }
537 }
538
539
540 task cloverInstr() {
541   // only instrument source, we build test classes as normal
542   inputs.files files (sourceSets.main.allJava) // , fileTree(dir: testSourceDir, include: ["**/*.java"]))
543   outputs.dir cloverInstrDir
544
545   doFirst {
546     delete cloverInstrDir
547     def argsList = ["--initstring", "${buildDir}/clover/clover.db",
548     "-d", "${buildDir}/${cloverSourcesInstrDir}"]
549     argsList.addAll(inputs.files.files.collect({ file ->
550       file.absolutePath
551     }))
552     String[] args = argsList.toArray()
553     println("About to instrument "+args.length +" files")
554     com.atlassian.clover.CloverInstr.mainImpl(args)
555   }
556 }
557
558
559 task cloverReport {
560   group = "Verification"
561     description = "Createst the Clover report"
562     inputs.dir "${buildDir}/clover"
563     outputs.dir "${reportsDir}/clover"
564     onlyIf {
565       file("${buildDir}/clover/clover.db").exists()
566     }
567   doFirst {
568     def argsList = ["--initstring", "${buildDir}/clover/clover.db",
569     "-o", "${reportsDir}/clover"]
570     String[] args = argsList.toArray()
571     com.atlassian.clover.reporters.html.HtmlReporter.runReport(args)
572
573     // and generate ${reportsDir}/clover/clover.xml
574     args = ["--initstring", "${buildDir}/clover/clover.db",
575     "-o", "${reportsDir}/clover/clover.xml"].toArray()
576     com.atlassian.clover.reporters.xml.XMLReporter.runReport(args)
577   }
578 }
579 // end clover bits
580
581
582 compileJava {
583
584   doFirst {
585     sourceCompatibility = compile_source_compatibility
586     targetCompatibility = compile_target_compatibility
587     options.compilerArgs = additional_compiler_args
588     print ("Setting target compatibility to "+targetCompatibility+"\n")
589   }
590
591 }
592
593
594 compileTestJava {
595   if (use_clover) {
596     dependsOn compileCloverJava
597     classpath += configurations.cloverRuntime
598   } else {
599     classpath += sourceSets.main.runtimeClasspath
600   }
601   doFirst {
602     sourceCompatibility = compile_source_compatibility
603     targetCompatibility = compile_target_compatibility
604     options.compilerArgs = additional_compiler_args
605     print ("Setting target compatibility to "+targetCompatibility+"\n")
606   }
607 }
608
609
610 compileCloverJava {
611
612   doFirst {
613     sourceCompatibility = compile_source_compatibility
614     targetCompatibility = compile_target_compatibility
615     options.compilerArgs += additional_compiler_args
616     print ("Setting target compatibility to "+targetCompatibility+"\n")
617   }
618   classpath += configurations.cloverRuntime
619 }
620
621
622 clean {
623   doFirst {
624     delete sourceSets.main.java.outputDir
625   }
626 }
627
628
629 cleanTest {
630   doFirst {
631     delete sourceSets.test.java.outputDir
632     delete cloverInstrDir
633   }
634 }
635
636
637 // format is a string like date.format("dd MMMM yyyy")
638 def getDate(format) {
639   def date = new Date()
640   return date.format(format)
641 }
642
643
644 task setGitVals {
645   def hashStdOut = new ByteArrayOutputStream()
646   exec {
647     commandLine "git", "rev-parse", "--short", "HEAD"
648     standardOutput = hashStdOut
649     ignoreExitValue true
650   }
651
652   def branchStdOut = new ByteArrayOutputStream()
653   exec {
654     commandLine "git", "rev-parse", "--abbrev-ref", "HEAD"
655     standardOutput = branchStdOut
656     ignoreExitValue true
657   }
658
659   gitHash = hashStdOut.toString().trim()
660   gitBranch = branchStdOut.toString().trim()
661
662   outputs.upToDateWhen { false }
663 }
664
665
666 task createBuildProperties(type: WriteProperties) {
667   dependsOn setGitVals
668   inputs.dir(sourceDir)
669   inputs.dir(resourceDir)
670   file(buildProperties).getParentFile().mkdirs()
671   outputFile (buildProperties)
672   // taking time specific comment out to allow better incremental builds
673   comment "--Jalview Build Details--\n"+getDate("yyyy-MM-dd HH:mm:ss")
674   //comment "--Jalview Build Details--\n"+getDate("yyyy-MM-dd")
675   property "BUILD_DATE", getDate("HH:mm:ss dd MMMM yyyy")
676   property "VERSION", JALVIEW_VERSION
677   property "INSTALLATION", INSTALLATION+" git-commit:"+gitHash+" ["+gitBranch+"]"
678   outputs.file(outputFile)
679 }
680
681
682 task cleanBuildingHTML(type: Delete) {
683   doFirst {
684     delete buildingHTML
685   }
686 }
687
688
689 task convertBuildingMD(type: Exec) {
690   dependsOn cleanBuildingHTML
691   def buildingMD = "${jalviewDir}/${docDir}/building.md"
692   def css = "${jalviewDir}/${docDir}/github.css"
693
694   def pandoc = null
695   pandoc_exec.split(",").each {
696     if (file(it.trim()).exists()) {
697       pandoc = it.trim()
698       return true
699     }
700   }
701
702   def hostname = "hostname".execute().text.trim()
703   if ((pandoc == null || ! file(pandoc).exists()) && hostname.equals("jv-bamboo")) {
704     pandoc = System.getProperty("user.home")+"/buildtools/pandoc/bin/pandoc"
705   }
706
707   doFirst {
708     if (pandoc != null && file(pandoc).exists()) {
709         commandLine pandoc, '-s', '-o', buildingHTML, '--metadata', 'pagetitle="Building Jalview from Source"', '--toc', '-H', css, buildingMD
710     } else {
711         println("Cannot find pandoc. Skipping convert building.md to HTML")
712         throw new StopExecutionException("Cannot find pandoc. Skipping convert building.md to HTML")
713     }
714   }
715
716   ignoreExitValue true
717
718   inputs.file(buildingMD)
719   inputs.file(css)
720   outputs.file(buildingHTML)
721 }
722
723
724 clean {
725   doFirst {
726     delete buildingHTML
727   }
728 }
729
730
731 task syncDocs(type: Sync) {
732   dependsOn convertBuildingMD
733   def syncDir = "${classesDir}/${docDir}"
734   from fileTree("${jalviewDir}/${docDir}")
735   into syncDir
736
737 }
738
739
740 task copyHelp(type: Copy) {
741   def inputDir = helpSourceDir
742   def outputDir = "${classesDir}/${helpDir}"
743   from(inputDir) {
744     exclude '**/*.gif'
745     exclude '**/*.jpg'
746     exclude '**/*.png'
747     filter(ReplaceTokens,
748       beginToken: '$$',
749       endToken: '$$',
750       tokens: [
751         'Version-Rel': JALVIEW_VERSION,
752         'Year-Rel': getDate("yyyy")
753       ]
754     )
755   }
756   from(inputDir) {
757     include '**/*.gif'
758     include '**/*.jpg'
759     include '**/*.png'
760   }
761   into outputDir
762
763   inputs.dir(inputDir)
764   outputs.files(helpFile)
765   outputs.dir(outputDir)
766 }
767
768
769 task syncLib(type: Sync) {
770   def syncDir = "${classesDir}/${libDistDir}"
771   from fileTree("${jalviewDir}/${libDistDir}")
772   into syncDir
773 }
774
775
776 task syncResources(type: Sync) {
777   from resourceDir
778   include "**/*.*"
779   into "${classesDir}"
780   preserve {
781     include "**"
782   }
783 }
784
785
786 task prepare {
787   dependsOn syncResources
788   dependsOn syncDocs
789   dependsOn copyHelp
790 }
791
792
793 //testReportDirName = "test-reports" // note that test workingDir will be $jalviewDir
794 test {
795   dependsOn prepare
796   dependsOn compileJava
797   if (use_clover) {
798     dependsOn cloverInstr
799   }
800
801   if (use_clover) {
802     print("Running tests " + (use_clover?"WITH":"WITHOUT") + " clover [clover="+use_clover+"]\n")
803   }
804
805   useTestNG() {
806     includeGroups testngGroups
807     preserveOrder true
808     useDefaultListeners=true
809   }
810
811   workingDir = jalviewDir
812   //systemProperties 'clover.jar' System.properties.clover.jar
813   sourceCompatibility = compile_source_compatibility
814   targetCompatibility = compile_target_compatibility
815   jvmArgs += additional_compiler_args
816
817 }
818
819
820 task buildIndices(type: JavaExec) {
821   dependsOn copyHelp
822   classpath = sourceSets.main.compileClasspath
823   main = "com.sun.java.help.search.Indexer"
824   workingDir = "${classesDir}/${helpDir}"
825   def argDir = "html"
826   args = [ argDir ]
827   inputs.dir("${workingDir}/${argDir}")
828
829   outputs.dir("${classesDir}/doc")
830   outputs.dir("${classesDir}/help")
831   outputs.file("${workingDir}/JavaHelpSearch/DOCS")
832   outputs.file("${workingDir}/JavaHelpSearch/DOCS.TAB")
833   outputs.file("${workingDir}/JavaHelpSearch/OFFSETS")
834   outputs.file("${workingDir}/JavaHelpSearch/POSITIONS")
835   outputs.file("${workingDir}/JavaHelpSearch/SCHEMA")
836   outputs.file("${workingDir}/JavaHelpSearch/TMAP")
837 }
838
839
840 task compileLinkCheck(type: JavaCompile) {
841   options.fork = true
842   classpath = files("${jalviewDir}/${utilsDir}")
843   destinationDir = file("${jalviewDir}/${utilsDir}")
844   source = fileTree(dir: "${jalviewDir}/${utilsDir}", include: ["HelpLinksChecker.java", "BufferedLineReader.java"])
845
846   inputs.file("${jalviewDir}/${utilsDir}/HelpLinksChecker.java")
847   inputs.file("${jalviewDir}/${utilsDir}/HelpLinksChecker.java")
848   outputs.file("${jalviewDir}/${utilsDir}/HelpLinksChecker.class")
849   outputs.file("${jalviewDir}/${utilsDir}/BufferedLineReader.class")
850 }
851
852
853 task linkCheck(type: JavaExec) {
854   dependsOn prepare, compileLinkCheck
855
856   def helpLinksCheckerOutFile = file("${jalviewDir}/${utilsDir}/HelpLinksChecker.out")
857   classpath = files("${jalviewDir}/${utilsDir}")
858   main = "HelpLinksChecker"
859   workingDir = jalviewDir
860   def help = "${classesDir}/${helpDir}"
861   args = [ "${classesDir}/${helpDir}", "-nointernet" ]
862
863   def outFOS = new FileOutputStream(helpLinksCheckerOutFile, false) // false == don't append
864   def errFOS = outFOS
865   standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
866     outFOS,
867     standardOutput)
868   errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
869     outFOS,
870     errorOutput)
871
872   inputs.dir("${classesDir}/${helpDir}")
873   outputs.file(helpLinksCheckerOutFile)
874 }
875
876 // import the pubhtmlhelp target
877 ant.properties.basedir = "${jalviewDir}"
878 ant.properties.helpBuildDir = "${jalviewDirAbsolutePath}/${classes_dir}/${helpDir}"
879 ant.importBuild "${utilsDir}/publishHelp.xml"
880
881
882 task cleanPackageDir(type: Delete) {
883   doFirst {
884     delete fileTree(dir: "${jalviewDir}/${packageDir}", include: "*.jar")
885   }
886 }
887
888 jar {
889   dependsOn linkCheck
890   dependsOn buildIndices
891   dependsOn createBuildProperties
892
893   manifest {
894     attributes "Main-Class": mainClass,
895     "Permissions": "all-permissions",
896     "Application-Name": "Jalview Desktop",
897     "Codebase": application_codebase
898   }
899
900   destinationDir = file("${jalviewDir}/${packageDir}")
901   archiveName = rootProject.name+".jar"
902
903   exclude "cache*/**"
904   exclude "*.jar"
905   exclude "*.jar.*"
906   exclude "**/*.jar"
907   exclude "**/*.jar.*"
908
909   inputs.dir(classesDir)
910   outputs.file("${jalviewDir}/${packageDir}/${archiveName}")
911 }
912
913
914 task copyJars(type: Copy) {
915   from fileTree(dir: classesDir, include: "**/*.jar").files
916   into "${jalviewDir}/${packageDir}"
917 }
918
919
920 // doing a Sync instead of Copy as Copy doesn't deal with "outputs" very well
921 task syncJars(type: Sync) {
922   from fileTree(dir: "${jalviewDir}/${libDistDir}", include: "**/*.jar").files
923   into "${jalviewDir}/${packageDir}"
924   preserve {
925     include jar.archiveName
926   }
927 }
928
929
930 task makeDist {
931   group = "build"
932   description = "Put all required libraries in dist"
933   // order of "cleanPackageDir", "copyJars", "jar" important!
934   jar.mustRunAfter cleanPackageDir
935   syncJars.mustRunAfter cleanPackageDir
936   dependsOn cleanPackageDir
937   dependsOn syncJars
938   dependsOn jar
939   outputs.dir("${jalviewDir}/${packageDir}")
940 }
941
942
943 task cleanDist {
944   dependsOn cleanPackageDir
945   dependsOn cleanTest
946   dependsOn clean
947 }
948
949 shadowJar {
950   group = "distribution"
951   if (buildDist) {
952     dependsOn makeDist
953   }
954   from ("${jalviewDir}/${libDistDir}") {
955     include("*.jar")
956   }
957   manifest {
958     attributes 'Implementation-Version': JALVIEW_VERSION
959   }
960   mainClassName = shadowJarMainClass
961   mergeServiceFiles()
962   classifier = "all-"+JALVIEW_VERSION+"-j"+JAVA_VERSION
963   minimize()
964 }
965
966
967 task getdownWebsite() {
968   group = "distribution"
969   description = "Create the getdown minimal app folder, and website folder for this version of jalview. Website folder also used for offline app installer"
970   if (buildDist) {
971     dependsOn makeDist
972   }
973
974   def getdownWebsiteResourceFilenames = []
975   def getdownTextString = ""
976   def getdownResourceDir = getdownResourceDir
977   def getdownAppDir = getdownAppDir
978   def getdownResourceFilenames = []
979
980   doFirst {
981     // clean the getdown website and files dir before creating getdown folders
982     delete getdownWebsiteDir
983     delete getdownFilesDir
984
985     copy {
986       from buildProperties
987       rename(build_properties_file, getdown_build_properties)
988       into getdownAppDir
989     }
990     getdownWebsiteResourceFilenames += "${getdown_app_dir}/${getdown_build_properties}"
991
992     // go through properties looking for getdown_txt_...
993     def props = project.properties.sort { it.key }
994     if (getdown_alt_java_min_version.length() > 0) {
995       props.put("getdown_txt_java_min_version", getdown_alt_java_min_version)
996     }
997     if (getdown_alt_java_max_version.length() > 0) {
998       props.put("getdown_txt_java_max_version", getdown_alt_java_max_version)
999     }
1000     props.put("getdown_txt_multi_java_location", getdown_alt_multi_java_location)
1001
1002     props.put("getdown_txt_appbase", getdown_app_base)
1003     props.each{ prop, val ->
1004       if (prop.startsWith("getdown_txt_") && val != null) {
1005         if (prop.startsWith("getdown_txt_multi_")) {
1006           def key = prop.substring(18)
1007           val.split(",").each{ v ->
1008             def line = "${key} = ${v}\n"
1009             getdownTextString += line
1010           }
1011         } else {
1012           // file values rationalised
1013           if (val.indexOf('/') > -1 || prop.startsWith("getdown_txt_resource")) {
1014             def r = null
1015             if (val.indexOf('/') == 0) {
1016               // absolute path
1017               r = file(val)
1018             } else if (val.indexOf('/') > 0) {
1019               // relative path (relative to jalviewDir)
1020               r = file( "${jalviewDir}/${val}" )
1021             }
1022             if (r.exists()) {
1023               val = "${getdown_resource_dir}/" + r.getName()
1024               getdownWebsiteResourceFilenames += val
1025               getdownResourceFilenames += r.getPath()
1026             }
1027           }
1028           if (! prop.startsWith("getdown_txt_resource")) {
1029             def line = prop.substring(12) + " = ${val}\n"
1030             getdownTextString += line
1031           }
1032         }
1033       }
1034     }
1035
1036     getdownWebsiteResourceFilenames.each{ filename ->
1037       getdownTextString += "resource = ${filename}\n"
1038     }
1039     getdownResourceFilenames.each{ filename ->
1040       copy {
1041         from filename
1042         into getdownResourceDir
1043       }
1044     }
1045
1046     def codeFiles = []
1047     fileTree(file(packageDir)).each{ f ->
1048       if (f.isDirectory()) {
1049         def files = fileTree(dir: f, include: ["*"]).getFiles()
1050         codeFiles += files
1051       } else if (f.exists()) {
1052         codeFiles += f
1053       }
1054     }
1055     codeFiles.sort().each{f ->
1056       def name = f.getName()
1057       def line = "code = ${getdown_app_dir}/${name}\n"
1058       getdownTextString += line
1059       copy {
1060         from f.getPath()
1061         into getdownAppDir
1062       }
1063     }
1064
1065     // NOT USING MODULES YET, EVERYTHING SHOULD BE IN dist
1066     /*
1067     if (JAVA_VERSION.equals("11")) {
1068     def j11libFiles = fileTree(dir: "${jalviewDir}/${j11libDir}", include: ["*.jar"]).getFiles()
1069     j11libFiles.sort().each{f ->
1070     def name = f.getName()
1071     def line = "code = ${getdown_j11lib_dir}/${name}\n"
1072     getdownTextString += line
1073     copy {
1074     from f.getPath()
1075     into getdownJ11libDir
1076     }
1077     }
1078     }
1079      */
1080
1081     // 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.
1082     //getdownTextString += "class = " + file(getdownLauncher).getName() + "\n"
1083     getdownTextString += "resource = ${getdown_launcher_new}\n"
1084     getdownTextString += "class = ${mainClass}\n"
1085
1086     def getdown_txt = file("${getdownWebsiteDir}/getdown.txt")
1087     getdown_txt.write(getdownTextString)
1088
1089     def launch_jvl = file("${getdownWebsiteDir}/${getdown_launch_jvl}")
1090     launch_jvl.write("appbase="+props.get("getdown_txt_appbase"))
1091
1092     copy {
1093       from getdownLauncher
1094       rename(file(getdownLauncher).getName(), getdown_launcher_new)
1095       into getdownWebsiteDir
1096     }
1097
1098     copy {
1099       from getdownLauncher
1100       if (file(getdownLauncher).getName() != getdown_launcher) {
1101         rename(file(getdownLauncher).getName(), getdown_launcher)
1102       }
1103       into getdownWebsiteDir
1104     }
1105
1106     if (! (CHANNEL.startsWith("ARCHIVE") || CHANNEL.startsWith("DEVELOP"))) {
1107       copy {
1108         from getdown_txt
1109         from getdownLauncher
1110         from "${getdownWebsiteDir}/${getdown_build_properties}"
1111         if (file(getdownLauncher).getName() != getdown_launcher) {
1112           rename(file(getdownLauncher).getName(), getdown_launcher)
1113         }
1114         into getdownInstallDir
1115       }
1116
1117       copy {
1118         from getdownInstallDir
1119         into getdownFilesInstallDir
1120       }
1121     }
1122
1123     copy {
1124       from getdown_txt
1125       from launch_jvl
1126       from getdownLauncher
1127       from "${getdownWebsiteDir}/${getdown_build_properties}"
1128       if (file(getdownLauncher).getName() != getdown_launcher) {
1129         rename(file(getdownLauncher).getName(), getdown_launcher)
1130       }
1131       into getdownFilesDir
1132     }
1133
1134     copy {
1135       from getdownResourceDir
1136       into "${getdownFilesDir}/${getdown_resource_dir}"
1137     }
1138   }
1139
1140   if (buildDist) {
1141     inputs.dir("${jalviewDir}/${packageDir}")
1142   }
1143   outputs.dir(getdownWebsiteDir)
1144   outputs.dir(getdownFilesDir)
1145 }
1146
1147
1148 task getdownDigest(type: JavaExec) {
1149   group = "distribution"
1150   description = "Digest the getdown website folder"
1151   dependsOn getdownWebsite
1152   doFirst {
1153     classpath = files("${getdownWebsiteDir}/${getdown_launcher}")
1154   }
1155   main = "com.threerings.getdown.tools.Digester"
1156   args getdownWebsiteDir
1157   inputs.dir(getdownWebsiteDir)
1158   outputs.file("${getdownWebsiteDir}/digest2.txt")
1159 }
1160
1161
1162 task getdown() {
1163   group = "distribution"
1164   description = "Create the minimal and full getdown app folder for installers and website and create digest file"
1165   dependsOn getdownDigest
1166   doLast {
1167     if (reportRsyncCommand) {
1168       def fromDir = getdownWebsiteDir + (getdownWebsiteDir.endsWith('/')?'':'/')
1169       def toDir = "${getdown_rsync_dest}/${getdownDir}" + (getdownDir.endsWith('/')?'':'/')
1170       println "LIKELY RSYNC COMMAND:"
1171       println "mkdir -p '$toDir'\nrsync -avh --delete '$fromDir' '$toDir'"
1172       if (RUNRSYNC == "true") {
1173         exec {
1174           commandLine "mkdir", "-p", toDir
1175         }
1176         exec {
1177           commandLine "rsync", "-avh", "--delete", fromDir, toDir
1178         }
1179       }
1180     }
1181   }
1182 }
1183
1184
1185 clean {
1186   doFirst {
1187     delete getdownWebsiteDir
1188     delete getdownFilesDir
1189   }
1190 }
1191
1192
1193 install4j {
1194   def install4jHomeDir = "/opt/install4j"
1195   def hostname = "hostname".execute().text.trim()
1196   if (hostname.equals("jv-bamboo")) {
1197     install4jHomeDir = System.getProperty("user.home")+"/buildtools/install4j"
1198   } else if (OperatingSystem.current().isMacOsX()) {
1199     install4jHomeDir = '/Applications/install4j.app/Contents/Resources/app'
1200     if (! file(install4jHomeDir).exists()) {
1201       install4jHomeDir = System.getProperty("user.home")+install4jHomeDir
1202     }
1203   } else if (OperatingSystem.current().isLinux()) {
1204     install4jHomeDir = System.getProperty("user.home")+"/buildtools/install4j"
1205   }
1206   installDir = file(install4jHomeDir)
1207   mediaTypes = Arrays.asList(install4jMediaTypes.split(","))
1208   if (install4jFaster.equals("true")) {
1209     faster = true
1210   }
1211 }
1212
1213
1214 task copyInstall4jTemplate(type: Copy) {
1215   from (install4jDir) {
1216     include install4jTemplate
1217     rename (install4jTemplate, install4jConfFileName)
1218     filter(ReplaceTokens,
1219       beginToken: '',
1220       endToken: '',
1221       tokens: [
1222         '9999999999': JAVA_VERSION
1223       ]
1224     )
1225     filter(ReplaceTokens,
1226       beginToken: '$$',
1227       endToken: '$$',
1228       tokens: [
1229         'JAVA_VERSION': JAVA_VERSION,
1230         'JAVA_INTEGER_VERSION': JAVA_INTEGER_VERSION,
1231         'VERSION': JALVIEW_VERSION,
1232         'MACOS_JAVA_VM_DIR': macosJavaVMDir,
1233         'MACOS_JAVA_VM_TGZ': macosJavaVMTgz,
1234         'WINDOWS_JAVA_VM_DIR': windowsJavaVMDir,
1235         'WINDOWS_JAVA_VM_TGZ': windowsJavaVMTgz,
1236         'INSTALL4JINFOPLISTFILEASSOCIATIONS': install4jInfoPlistFileAssociations,
1237         'COPYRIGHT_MESSAGE': install4jCopyrightMessage,
1238         'MACOS_BUNDLE_ID': install4jMacOSBundleId,
1239         'GETDOWN_RESOURCE_DIR': getdown_resource_dir,
1240         'GETDOWN_DIST_DIR': getdown_app_dir,
1241         'GETDOWN_ALT_DIR': getdown_app_dir_alt,
1242         'GETDOWN_INSTALL_DIR': getdown_install_dir
1243       ]
1244     )
1245     if (OSX_KEYPASS == "") {
1246       filter(ReplaceTokens,
1247         beginToken: 'codeSigning macEnabled="',
1248         endToken: '"',
1249         tokens: [
1250           'true': 'codeSigning macEnabled="false"'
1251         ]
1252       )
1253       filter(ReplaceTokens,
1254         beginToken: 'runPostProcessor="true" ',
1255         endToken: 'Processor',
1256         tokens: [
1257           'post': 'runPostProcessor="false" postProcessor'
1258         ]
1259       )
1260     }
1261   }
1262   into install4jDir
1263   outputs.files(install4jConfFile)
1264
1265   doLast {
1266     // include file associations in installer
1267     def installerFileAssociationsXml = file("${install4jDir}/${install4jInstallerFileAssociations}").text
1268     ant.replaceregexp(
1269       byline: false,
1270       flags: "s",
1271       match: '<action name="EXTENSIONS_REPLACED_BY_GRADLE".*?</action>',
1272       replace: installerFileAssociationsXml,
1273       file: install4jConfFile
1274     )
1275     /*
1276     // include uninstaller applescript app files in dmg
1277     def installerDMGUninstallerXml = file("$install4jDir/$install4jDMGUninstallerAppFiles").text
1278     ant.replaceregexp(
1279     byline: false,
1280     flags: "s",
1281     match: '<file name="UNINSTALL_OLD_JALVIEW_APP_REPLACED_IN_GRADLE" file=.*?>',
1282     replace: installerDMGUninstallerXml,
1283     file: install4jConfFile
1284     )
1285      */
1286   }
1287 }
1288
1289
1290 clean {
1291   doFirst {
1292     delete install4jConfFile
1293   }
1294 }
1295
1296
1297 task installers(type: com.install4j.gradle.Install4jTask) {
1298   group = "distribution"
1299   description = "Create the install4j installers"
1300   dependsOn getdown
1301   dependsOn copyInstall4jTemplate
1302   projectFile = file(install4jConfFile)
1303   variables = [majorVersion: version.substring(2, 11), build: 001, OSX_KEYSTORE: OSX_KEYSTORE, JSIGN_SH: JSIGN_SH]
1304   destination = "${jalviewDir}/${install4jBuildDir}/${JAVA_VERSION}"
1305   buildSelected = true
1306
1307   if (OSX_KEYPASS) {
1308     macKeystorePassword=OSX_KEYPASS
1309   }
1310
1311   doFirst {
1312     println("Using projectFile "+projectFile)
1313   }
1314
1315   inputs.dir(getdownWebsiteDir)
1316   inputs.file(install4jConfFile)
1317   inputs.dir(macosJavaVMDir)
1318   inputs.dir(windowsJavaVMDir)
1319   outputs.dir("${jalviewDir}/${install4jBuildDir}/${JAVA_VERSION}")
1320 }
1321
1322
1323 task sourceDist (type: Tar) {
1324   
1325   def VERSION_UNDERSCORES = JALVIEW_VERSION.replaceAll("\\.", "_")
1326   def outputFileName = "${project.name}_${VERSION_UNDERSCORES}.tar.gz"
1327   // cater for buildship < 3.1 [3.0.1 is max version in eclipse 2018-09]
1328   try {
1329     archiveFileName = outputFileName
1330   } catch (Exception e) {
1331     archiveName = outputFileName
1332   }
1333   
1334   compression Compression.GZIP
1335   
1336   into project.name
1337
1338   def EXCLUDE_FILES=["build/*","bin/*","test-output/","test-reports","tests","clover*/*"
1339   ,".*"
1340   ,"benchmarking/*"
1341   ,"**/.*"
1342   ,"*.class"
1343   ,"**/*.class","${j11modDir}/**/*.jar","appletlib","**/*locales"
1344   ,"*locales/**",
1345   ,"utils/InstallAnywhere"] 
1346   def PROCESS_FILES=[   "AUTHORS",
1347   "CITATION",
1348   "FEATURETODO",
1349   "JAVA-11-README",
1350   "FEATURETODO",
1351   "LICENSE",
1352   "**/README",
1353   "RELEASE",
1354   "THIRDPARTYLIBS","TESTNG",
1355   "build.gradle",
1356   "gradle.properties",
1357   "**/*.java",
1358   "**/*.html",
1359   "**/*.xml",
1360   "**/*.gradle",
1361   "**/*.groovy",
1362   "**/*.properties",
1363   "**/*.perl",
1364   "**/*.sh"]
1365
1366   from(jalviewDir) {
1367     exclude (EXCLUDE_FILES)
1368     include (PROCESS_FILES)
1369     filter(ReplaceTokens,
1370       beginToken: '$$',
1371       endToken: '$$',
1372       tokens: [
1373         'Version-Rel': JALVIEW_VERSION,
1374         'Year-Rel': getDate("yyyy")
1375       ]
1376     )
1377   }
1378   from(jalviewDir) {
1379     exclude (EXCLUDE_FILES)
1380     exclude (PROCESS_FILES)
1381     exclude ("appletlib")
1382     exclude ("**/*locales")
1383     exclude ("*locales/**")
1384     exclude ("utils/InstallAnywhere")
1385
1386     exclude (getdown_files_dir)
1387     exclude (getdown_website_dir)
1388
1389     // exluding these as not using jars as modules yet
1390     exclude ("${j11modDir}/**/*.jar")
1391   }
1392   //  from (jalviewDir) {
1393   //    // explicit includes for stuff that seemed to not get included
1394   //    include(fileTree("test/**/*."))
1395   //    exclude(EXCLUDE_FILES)
1396   //    exclude(PROCESS_FILES)
1397   //  }
1398 }
1399
1400
1401 task helppages  {
1402   dependsOn copyHelp
1403   dependsOn pubhtmlhelp
1404   
1405   inputs.dir("${classesDir}/${helpDir}")
1406   outputs.dir("${buildDir}/distributions/${helpDir}")
1407 }
1408
1409
1410 task j2sSetHeadlessBuild {
1411   doFirst {
1412     IN_ECLIPSE = false
1413   }
1414 }
1415
1416
1417 task jalviewjsSetEclipseWorkspace {
1418   def propKey = "jalviewjs_eclipse_workspace"
1419   def propVal = null
1420   if (project.hasProperty(propKey)) {
1421     propVal = project.getProperty(propKey)
1422     if (propVal.startsWith("~/")) {
1423       propVal = System.getProperty("user.home") + propVal.substring(1)
1424     }
1425   }
1426   def propsFileName = "${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_eclipse_workspace_location_file}"
1427   def propsFile = file(propsFileName)
1428   def eclipseWsDir = propVal
1429   def props = new Properties()
1430
1431   def writeProps = true
1432   if (( eclipseWsDir == null || !file(eclipseWsDir).exists() ) && propsFile.exists()) {
1433     def ins = new FileInputStream(propsFileName)
1434     props.load(ins)
1435     ins.close()
1436     if (props.getProperty(propKey, null) != null) {
1437       eclipseWsDir = props.getProperty(propKey)
1438       writeProps = false
1439     }
1440   }
1441
1442   if (eclipseWsDir == null || !file(eclipseWsDir).exists()) {
1443     def tempDir = File.createTempDir()
1444     eclipseWsDir = tempDir.getAbsolutePath()
1445     writeProps = true
1446   }
1447   eclipseWorkspace = file(eclipseWsDir)
1448
1449   doFirst {
1450     // do not run a headless transpile when we claim to be in Eclipse
1451     if (IN_ECLIPSE) {
1452       println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
1453       throw new StopExecutionException("Not running headless transpile whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
1454     } else {
1455       println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
1456     }
1457
1458     if (writeProps) {
1459       props.setProperty(propKey, eclipseWsDir)
1460       propsFile.parentFile.mkdirs()
1461       def bytes = new ByteArrayOutputStream()
1462       props.store(bytes, null)
1463       def propertiesString = bytes.toString()
1464       propsFile.text = propertiesString
1465       print("NEW ")
1466     } else {
1467       print("EXISTING ")
1468     }
1469
1470     println("ECLIPSE WORKSPACE: "+eclipseWorkspace.getPath())
1471   }
1472
1473   //inputs.property(propKey, eclipseWsDir) // eclipseWsDir only gets set once this task runs, so will be out-of-date
1474   outputs.file(propsFileName)
1475   outputs.upToDateWhen { eclipseWorkspace.exists() && propsFile.exists() }
1476 }
1477
1478
1479 task jalviewjsEclipsePaths {
1480   def eclipseProduct
1481
1482   def eclipseRoot = jalviewjs_eclipse_root
1483   if (eclipseRoot.startsWith("~/")) {
1484     eclipseRoot = System.getProperty("user.home") + eclipseRoot.substring(1)
1485   }
1486   if (OperatingSystem.current().isMacOsX()) {
1487     eclipseRoot += "/Eclipse.app"
1488     eclipseBinary = "${eclipseRoot}/Contents/MacOS/eclipse"
1489     eclipseProduct = "${eclipseRoot}/Contents/Eclipse/.eclipseproduct"
1490   } else if (OperatingSystem.current().isWindows()) { // check these paths!!
1491     if (file("${eclipseRoot}/eclipse").isDirectory() && file("${eclipseRoot}/eclipse/.eclipseproduct").exists()) {
1492       eclipseRoot += "/eclipse.exe"
1493     }
1494     eclipseBinary = "${eclipseRoot}/eclipse"
1495     eclipseProduct = "${eclipseRoot}/.eclipseproduct"
1496   } else { // linux or unix
1497     if (file("${eclipseRoot}/eclipse").isDirectory() && file("${eclipseRoot}/eclipse/.eclipseproduct").exists()) {
1498       eclipseRoot += "/eclipse"
1499     }
1500     eclipseBinary = "${eclipseRoot}/eclipse"
1501     eclipseProduct = "${eclipseRoot}/.eclipseproduct"
1502   }
1503
1504   eclipseVersion = "4.13" // default
1505   def assumedVersion = true
1506   if (file(eclipseProduct).exists()) {
1507     def fis = new FileInputStream(eclipseProduct)
1508     def props = new Properties()
1509     props.load(fis)
1510     eclipseVersion = props.getProperty("version")
1511     fis.close()
1512     assumedVersion = false
1513   }
1514   
1515   def propKey = "eclipse_debug"
1516   eclipseDebug = (project.hasProperty(propKey) && project.getProperty(propKey).equals("true"))
1517
1518   doFirst {
1519     // do not run a headless transpile when we claim to be in Eclipse
1520     if (IN_ECLIPSE) {
1521       println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
1522       throw new StopExecutionException("Not running headless transpile whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
1523     } else {
1524       println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
1525     }
1526
1527     if (!assumedVersion) {
1528       println("ECLIPSE VERSION=${eclipseVersion}")
1529     }
1530   }
1531 }
1532
1533
1534 task eclipseSetup {
1535   dependsOn eclipseProject
1536   dependsOn eclipseClasspath
1537   dependsOn eclipseJdt
1538 }
1539
1540
1541 // this version (type: Copy) will delete anything in the eclipse dropins folder that isn't in fromDropinsDir
1542 task jalviewjsEclipseCopyDropins(type: Copy) {
1543   dependsOn jalviewjsEclipsePaths
1544
1545   def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjs_eclipse_dropins_dir}", include: "*.jar")
1546   inputFiles += file("${jalviewDir}/${jalviewjs_j2s_plugin}")
1547   def outputDir = "${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_eclipse_tmp_dropins_dir}"
1548
1549   from inputFiles
1550   into outputDir
1551 }
1552
1553
1554 // this eclipse -clean doesn't actually work
1555 task jalviewjsCleanEclipse(type: Exec) {
1556   dependsOn eclipseSetup
1557   dependsOn jalviewjsEclipsePaths
1558   dependsOn jalviewjsEclipseCopyDropins
1559
1560   executable(eclipseBinary)
1561   args(["-nosplash", "--launcher.suppressErrors", "-data", eclipseWorkspace.getPath(), "-clean", "-console", "-consoleLog"])
1562   if (eclipseDebug) {
1563     args += "-debug"
1564   }
1565   args += "-l"
1566
1567   def inputString = """exit
1568 y
1569 """
1570   def inputByteStream = new ByteArrayInputStream(inputString.getBytes())
1571   standardInput = inputByteStream
1572 }
1573
1574 /* not really working yet
1575 jalviewjsEclipseCopyDropins.finalizedBy jalviewjsCleanEclipse
1576 */
1577
1578
1579 task jalviewjsTransferUnzipSwingJs {
1580   def file_zip = "${jalviewDir}/${jalviewjs_swingjs_zip}"
1581
1582   doLast {
1583     copy {
1584       from zipTree(file_zip)
1585       into "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}"
1586     }
1587   }
1588
1589   inputs.file file_zip
1590   outputs.dir "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}"
1591 }
1592
1593
1594 task jalviewjsTransferUnzipLib {
1595   def zipFiles = fileTree(dir: "${jalviewDir}/${jalviewjs_libjs_dir}", include: "*.zip")
1596
1597   doLast {
1598     zipFiles.each { file_zip -> 
1599       copy {
1600         from zipTree(file_zip)
1601         into "${jalviewDir}/${jalviewjsTransferSiteLibDir}"
1602       }
1603     }
1604   }
1605
1606   inputs.files zipFiles
1607   outputs.dir "${jalviewDir}/${jalviewjsTransferSiteLibDir}"
1608 }
1609
1610
1611 task jalviewjsTransferUnzipAllLibs {
1612   dependsOn jalviewjsTransferUnzipSwingJs
1613   dependsOn jalviewjsTransferUnzipLib
1614 }
1615
1616
1617 task jalviewjsCreateJ2sSettings(type: WriteProperties) {
1618   group "JalviewJS"
1619   description "Create the .j2s file from the j2s.* properties"
1620
1621   jalviewjsJ2sProps = project.properties.findAll { it.key.startsWith("j2s.") }.sort { it.key }
1622   def siteDirProperty = "j2s.site.directory"
1623   def setSiteDir = false
1624   jalviewjsJ2sProps.each { prop, val ->
1625     if (val != null) {
1626       if (prop == siteDirProperty) {
1627         if (!(val.startsWith('/') || val.startsWith("file://") )) {
1628           val = "${jalviewDir}/${jalviewjsTransferSiteJsDir}/${val}"
1629         }
1630         setSiteDir = true
1631       }
1632       property(prop,val)
1633     }
1634     if (!setSiteDir) { // default site location, don't override specifically set property
1635       property(siteDirProperty,"${jalviewDirRelativePath}/${jalviewjsTransferSiteJsDir}")
1636     }
1637   }
1638   outputFile = jalviewjsJ2sSettingsFileName
1639
1640   if (! IN_ECLIPSE) {
1641     inputs.properties(jalviewjsJ2sProps)
1642     outputs.file(jalviewjsJ2sSettingsFileName)
1643   }
1644 }
1645
1646
1647 task jalviewjsEclipseSetup {
1648   dependsOn jalviewjsEclipseCopyDropins
1649   dependsOn jalviewjsSetEclipseWorkspace
1650   dependsOn jalviewjsCreateJ2sSettings
1651 }
1652
1653
1654 task jalviewjsSyncAllLibs (type: Sync) {
1655   dependsOn jalviewjsTransferUnzipAllLibs
1656   def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjsTransferSiteLibDir}")
1657   inputFiles += fileTree(dir: "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}")
1658   def outputDir = "${jalviewDir}/${jalviewjsSiteDir}"
1659
1660   from inputFiles
1661   into outputDir
1662   def outputFiles = []
1663   rename { filename ->
1664     outputFiles += "${outputDir}/${filename}"
1665     null
1666   }
1667   preserve {
1668     include "**"
1669   }
1670   outputs.files outputFiles
1671   inputs.files inputFiles
1672 }
1673
1674
1675 task jalviewjsSyncResources (type: Sync) {
1676   def inputFiles = fileTree(dir: resourceDir)
1677   def outputDir = "${jalviewDir}/${jalviewjsSiteDir}/${jalviewjs_j2s_subdir}"
1678
1679   from inputFiles
1680   into outputDir
1681   def outputFiles = []
1682   rename { filename ->
1683     outputFiles += "${outputDir}/${filename}"
1684     null
1685   }
1686   preserve {
1687     include "**"
1688   }
1689   outputs.files outputFiles
1690   inputs.files inputFiles
1691 }
1692
1693
1694 task jalviewjsSyncSiteResources (type: Sync) {
1695   def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjs_site_resource_dir}")
1696   def outputDir = "${jalviewDir}/${jalviewjsSiteDir}"
1697
1698   from inputFiles
1699   into outputDir
1700   def outputFiles = []
1701   rename { filename ->
1702     outputFiles += "${outputDir}/${filename}"
1703     null
1704   }
1705   preserve {
1706     include "**"
1707   }
1708   outputs.files outputFiles
1709   inputs.files inputFiles
1710 }
1711
1712
1713 task jalviewjsSyncBuildProperties (type: Sync) {
1714   dependsOn createBuildProperties
1715   def inputFiles = [file(buildProperties)]
1716   def outputDir = "${jalviewDir}/${jalviewjsSiteDir}/${jalviewjs_j2s_subdir}"
1717
1718   from inputFiles
1719   into outputDir
1720   def outputFiles = []
1721   rename { filename ->
1722     outputFiles += "${outputDir}/${filename}"
1723     null
1724   }
1725   preserve {
1726     include "**"
1727   }
1728   outputs.files outputFiles
1729   inputs.files inputFiles
1730 }
1731
1732
1733 task jalviewjsProjectImport(type: Exec) {
1734   dependsOn eclipseSetup
1735   dependsOn jalviewjsEclipsePaths
1736   dependsOn jalviewjsEclipseSetup
1737
1738   doFirst {
1739     // do not run a headless import when we claim to be in Eclipse
1740     if (IN_ECLIPSE) {
1741       println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
1742       throw new StopExecutionException("Not running headless import whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
1743     } else {
1744       println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
1745     }
1746   }
1747
1748   //def projdir = eclipseWorkspace.getPath()+"/.metadata/.plugins/org.eclipse.core.resources/.projects/jalview/org.eclipse.jdt.core"
1749   def projdir = eclipseWorkspace.getPath()+"/.metadata/.plugins/org.eclipse.core.resources/.projects/jalview"
1750   executable(eclipseBinary)
1751   args(["-nosplash", "--launcher.suppressErrors", "-application", "com.seeq.eclipse.importprojects.headlessimport", "-data", eclipseWorkspace.getPath(), "-import", jalviewDirAbsolutePath])
1752   if (eclipseDebug) {
1753     args += "-debug"
1754   }
1755   args += [ "--launcher.appendVmargs", "-vmargs", "-Dorg.eclipse.equinox.p2.reconciler.dropins.directory=${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_eclipse_tmp_dropins_dir}" ]
1756   if (!IN_ECLIPSE) {
1757     args += [ "-D${j2sHeadlessBuildProperty}=true" ]
1758   }
1759
1760   inputs.file("${jalviewDir}/.project")
1761   outputs.upToDateWhen { 
1762     file(projdir).exists()
1763   }
1764 }
1765
1766
1767 task jalviewjsTranspile(type: Exec) {
1768   dependsOn jalviewjsEclipseSetup 
1769   dependsOn jalviewjsProjectImport
1770   dependsOn jalviewjsEclipsePaths
1771
1772   doFirst {
1773     // do not run a headless transpile when we claim to be in Eclipse
1774     if (IN_ECLIPSE) {
1775       println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
1776       throw new StopExecutionException("Not running headless transpile whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
1777     } else {
1778       println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
1779     }
1780   }
1781
1782   executable(eclipseBinary)
1783   args(["-nosplash", "--launcher.suppressErrors", "-application", "org.eclipse.jdt.apt.core.aptBuild", "-data", eclipseWorkspace, "-${jalviewjs_eclipse_build_arg}", eclipse_project_name ])
1784   if (eclipseDebug) {
1785     args += "-debug"
1786   }
1787   args += [ "--launcher.appendVmargs", "-vmargs", "-Dorg.eclipse.equinox.p2.reconciler.dropins.directory=${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_eclipse_tmp_dropins_dir}" ]
1788   if (!IN_ECLIPSE) {
1789     args += [ "-D${j2sHeadlessBuildProperty}=true" ]
1790   }
1791
1792   def stdout
1793   def stderr
1794   doFirst {
1795     stdout = new ByteArrayOutputStream()
1796     stderr = new ByteArrayOutputStream()
1797
1798     def logOutFileName = "${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}"
1799     def logOutFile = file(logOutFileName)
1800     logOutFile.createNewFile()
1801     logOutFile.text = """ROOT: ${jalviewjs_eclipse_root}
1802 BINARY: ${eclipseBinary}
1803 VERSION: ${eclipseVersion}
1804 WORKSPACE: ${eclipseWorkspace}
1805 DEBUG: ${eclipseDebug}
1806 ----
1807 """
1808     def logOutFOS = new FileOutputStream(logOutFile, true) // true == append
1809     // combine stdout and stderr
1810     def logErrFOS = logOutFOS
1811
1812     if (jalviewjs_j2s_to_console.equals("true")) {
1813       standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
1814         new org.apache.tools.ant.util.TeeOutputStream(
1815           logOutFOS,
1816           stdout),
1817         standardOutput)
1818       errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
1819         new org.apache.tools.ant.util.TeeOutputStream(
1820           logErrFOS,
1821           stderr),
1822         errorOutput)
1823     } else {
1824       standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
1825         logOutFOS,
1826         stdout)
1827       errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
1828         logErrFOS,
1829         stderr)
1830     }
1831   }
1832
1833   doLast {
1834     if (stdout.toString().contains("Error processing ")) {
1835       // j2s did not complete transpile
1836       //throw new TaskExecutionException("Error during transpilation:\n${stderr}\nSee eclipse transpile log file '${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}'")
1837       throw new GradleException("Error during transpilation:\n${stderr}\nSee eclipse transpile log file '${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}'")
1838     }
1839   }
1840
1841   inputs.dir("${jalviewDir}/${sourceDir}")
1842   outputs.dir("${jalviewDir}/${jalviewjsTransferSiteJsDir}")
1843   outputs.upToDateWhen( { file("${jalviewDir}/${jalviewjsTransferSiteJsDir}${jalviewjs_server_resource}").exists() } )
1844 }
1845
1846
1847 def jalviewjsCallCore(String name, FileCollection list, String prefixFile, String suffixFile, String jsfile, String zjsfile, File logOutFile, Boolean logOutConsole) {
1848
1849   def stdout = new ByteArrayOutputStream()
1850   def stderr = new ByteArrayOutputStream()
1851
1852   def coreFile = file(jsfile)
1853   def msg = ""
1854   msg = "Creating core for ${name}...\nGenerating ${jsfile}"
1855   println(msg)
1856   logOutFile.createNewFile()
1857   logOutFile.append(msg+"\n")
1858
1859   def coreTop = file(prefixFile)
1860   def coreBottom = file(suffixFile)
1861   coreFile.getParentFile().mkdirs()
1862   coreFile.createNewFile()
1863   coreFile.write( coreTop.text )
1864   list.each {
1865     f ->
1866     if (f.exists()) {
1867       def t = f.text
1868       t.replaceAll("Clazz\\.([^_])","Clazz_${1}")
1869       coreFile.append( t )
1870     } else {
1871       msg = "...file '"+f.getPath()+"' does not exist, skipping"
1872       println(msg)
1873       logOutFile.append(msg+"\n")
1874     }
1875   }
1876   coreFile.append( coreBottom.text )
1877
1878   msg = "Generating ${zjsfile}"
1879   println(msg)
1880   logOutFile.append(msg+"\n")
1881   def logOutFOS = new FileOutputStream(logOutFile, true) // true == append
1882   def logErrFOS = logOutFOS
1883
1884   javaexec {
1885     classpath = files(["${jalviewDir}/tools/closure_compiler.jar"])
1886     args = [ "--js", jsfile, "--js_output_file", zjsfile ]
1887     maxHeapSize = "2g"
1888
1889     msg = "\nRunning '"+commandLine.join(' ')+"'\n"
1890     println(msg)
1891     logOutFile.append(msg+"\n")
1892
1893     if (logOutConsole) {
1894       standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
1895         new org.apache.tools.ant.util.TeeOutputStream(
1896           logOutFOS,
1897           stdout),
1898         standardOutput)
1899         errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
1900           new org.apache.tools.ant.util.TeeOutputStream(
1901             logErrFOS,
1902             stderr),
1903           errorOutput)
1904     } else {
1905       standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
1906         logOutFOS,
1907         stdout)
1908         errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
1909           logErrFOS,
1910           stderr)
1911     }
1912   }
1913   msg = "--"
1914   println(msg)
1915   logOutFile.append(msg+"\n")
1916 }
1917
1918
1919 task jalviewjsBuildAllCores {
1920   group "JalviewJS"
1921   description "Build the core js lib closures listed in the classlists dir"
1922   dependsOn jalviewjsTranspile
1923   dependsOn jalviewjsTransferUnzipSwingJs
1924
1925   def j2sDir = "${jalviewDir}/${jalviewjsTransferSiteJsDir}/${jalviewjs_j2s_subdir}"
1926   def swingJ2sDir = "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}/${jalviewjs_j2s_subdir}"
1927   def libJ2sDir = "${jalviewDir}/${jalviewjsTransferSiteLibDir}/${jalviewjs_j2s_subdir}"
1928   def jsDir = "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}/${jalviewjs_js_subdir}"
1929   def outputDir = "${jalviewDir}/${jalviewjsTransferSiteCoreDir}/${jalviewjs_j2s_subdir}/core"
1930   def prefixFile = "${jsDir}/core/coretop2.js"
1931   def suffixFile = "${jsDir}/core/corebottom2.js"
1932
1933   inputs.file prefixFile
1934   inputs.file suffixFile
1935
1936   def classlistFiles = []
1937   // add the classlists found int the jalviewjs_classlists_dir
1938   fileTree(dir: "${jalviewDir}/${jalviewjs_classlists_dir}", include: "*.txt").each {
1939     file ->
1940     def name = file.getName() - ".txt"
1941     classlistFiles += [
1942       'file': file,
1943       'name': name
1944     ]
1945   }
1946
1947   // _jmol and _jalview cores. Add any other peculiar classlist.txt files here
1948   //classlistFiles += [ 'file': file("${jalviewDir}/${jalviewjs_classlist_jmol}"), 'name': "_jvjmol" ]
1949   classlistFiles += [ 'file': file("${jalviewDir}/${jalviewjs_classlist_jalview}"), 'name': jalviewjsJalviewCoreName ]
1950
1951   jalviewjsCoreClasslists = []
1952
1953   classlistFiles.each {
1954     hash ->
1955
1956     def file = hash['file']
1957     if (! file.exists()) {
1958       println("...classlist file '"+file.getPath()+"' does not exist, skipping")
1959       return false // this is a "continue" in groovy .each closure
1960     }
1961     def name = hash['name']
1962     if (name == null) {
1963       name = file.getName() - ".txt"
1964     }
1965
1966     def filelist = []
1967     file.eachLine {
1968       line ->
1969         filelist += line
1970     }
1971     def list = fileTree(dir: j2sDir, includes: filelist)
1972
1973     def jsfile = "${outputDir}/core${name}.js"
1974     def zjsfile = "${outputDir}/core${name}.z.js"
1975
1976     jalviewjsCoreClasslists += [
1977       'jsfile': jsfile,
1978       'zjsfile': zjsfile,
1979       'list': list,
1980       'name': name
1981     ]
1982
1983     inputs.file(file)
1984     inputs.files(list)
1985     outputs.file(jsfile)
1986     outputs.file(zjsfile)
1987   }
1988   
1989   // _stevesoft core. add any cores without a classlist here (and the inputs and outputs)
1990   def stevesoftClasslistName = "_stevesoft"
1991   def stevesoftClasslist = [
1992     'jsfile': "${outputDir}/core${stevesoftClasslistName}.js",
1993     'zjsfile': "${outputDir}/core${stevesoftClasslistName}.z.js",
1994     'list': fileTree(dir: j2sDir, include: "com/stevesoft/pat/**/*.js"),
1995     'name': stevesoftClasslistName
1996   ]
1997   jalviewjsCoreClasslists += stevesoftClasslist
1998   inputs.files(stevesoftClasslist['list'])
1999   outputs.file(stevesoftClasslist['jsfile'])
2000   outputs.file(stevesoftClasslist['zjsfile'])
2001
2002   // _all core
2003   def allClasslistName = "_all"
2004   def allJsFiles = fileTree(dir: j2sDir, include: "**/*.js")
2005   allJsFiles += fileTree(
2006     dir: libJ2sDir,
2007     include: "**/*.js",
2008     excludes: [
2009       // these exlusions are files that the closure-compiler produces errors for. Should fix them
2010       "**/org/jmol/jvxl/readers/IsoIntersectFileReader.js",
2011       "**/org/jmol/export/JSExporter.js"
2012     ]
2013   )
2014   allJsFiles += fileTree(
2015     dir: swingJ2sDir,
2016     include: "**/*.js",
2017     excludes: [
2018       // these exlusions are files that the closure-compiler produces errors for. Should fix them
2019       "**/sun/misc/Unsafe.js",
2020       "**/swingjs/jquery/jquery-editable-select.js",
2021       "**/swingjs/jquery/j2sComboBox.js",
2022       "**/sun/misc/FloatingDecimal.js"
2023     ]
2024   )
2025   def allClasslist = [
2026     'jsfile': "${outputDir}/core${allClasslistName}.js",
2027     'zjsfile': "${outputDir}/core${allClasslistName}.z.js",
2028     'list': allJsFiles,
2029     'name': allClasslistName
2030   ]
2031   jalviewjsCoreClasslists += allClasslist
2032   inputs.files(allClasslist['list'])
2033   outputs.file(allClasslist['jsfile'])
2034   outputs.file(allClasslist['zjsfile'])
2035
2036   doFirst {
2037     def logOutFile = file("${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_j2s_closure_stdout}")
2038     logOutFile.getParentFile().mkdirs()
2039     logOutFile.createNewFile()
2040     logOutFile.write(getDate("yyyy-MM-dd HH:mm:ss")+" jalviewjsBuildAllCores\n----\n")
2041
2042     jalviewjsCoreClasslists.each {
2043       jalviewjsCallCore(it.name, it.list, prefixFile, suffixFile, it.jsfile, it.zjsfile, logOutFile, jalviewjs_j2s_to_console.equals("true"))
2044     }
2045   }
2046
2047 }
2048
2049
2050 def jalviewjsPublishCoreTemplate(String coreName, String templateName, File inputFile, String outputFile) {
2051   copy {
2052     from inputFile
2053     into file(outputFile).getParentFile()
2054     rename { filename ->
2055       if (filename.equals(inputFile.getName())) {
2056         return file(outputFile).getName()
2057       }
2058       return null
2059     }
2060     filter(ReplaceTokens,
2061       beginToken: '_',
2062       endToken: '_',
2063       tokens: [
2064         'MAIN': '"'+mainClass+'"',
2065         'CODE': "null",
2066         'NAME': jalviewjsJalviewTemplateName+" [core ${coreName}]",
2067         'COREKEY': jalviewjs_core_key,
2068         'CORENAME': coreName
2069       ]
2070     )
2071   }
2072 }
2073
2074
2075 task jalviewjsPublishCoreTemplates {
2076   dependsOn jalviewjsBuildAllCores
2077   def inputFileName = "${jalviewDir}/${j2s_coretemplate_html}"
2078   def inputFile = file(inputFileName)
2079   def outputDir = "${jalviewDir}/${jalviewjsTransferSiteCoreDir}"
2080
2081   def outputFiles = []
2082   jalviewjsCoreClasslists.each { cl ->
2083     def outputFile = "${outputDir}/${jalviewjsJalviewTemplateName}_${cl.name}.html"
2084     cl['outputfile'] = outputFile
2085     outputFiles += outputFile
2086   }
2087
2088   doFirst {
2089     jalviewjsCoreClasslists.each { cl ->
2090       jalviewjsPublishCoreTemplate(cl.name, jalviewjsJalviewTemplateName, inputFile, cl.outputfile)
2091     }
2092   }
2093   inputs.file(inputFile)
2094   outputs.files(outputFiles)
2095 }
2096
2097
2098 task jalviewjsSyncCore (type: Sync) {
2099   dependsOn jalviewjsBuildAllCores
2100   dependsOn jalviewjsPublishCoreTemplates
2101   def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjsTransferSiteCoreDir}")
2102   def outputDir = "${jalviewDir}/${jalviewjsSiteDir}"
2103
2104   from inputFiles
2105   into outputDir
2106   def outputFiles = []
2107   rename { filename ->
2108     outputFiles += "${outputDir}/${filename}"
2109     null
2110   }
2111   preserve {
2112     include "**"
2113   }
2114   outputs.files outputFiles
2115   inputs.files inputFiles
2116 }
2117
2118
2119 // this Copy version of TransferSiteJs will delete anything else in the target dir
2120 task jalviewjsCopyTransferSiteJs(type: Copy) {
2121   dependsOn jalviewjsTranspile
2122   from "${jalviewDir}/${jalviewjsTransferSiteJsDir}"
2123   into "${jalviewDir}/${jalviewjsSiteDir}"
2124 }
2125
2126
2127 // this Sync version of TransferSite is used by buildship to keep the website automatically up to date when a file changes
2128 task jalviewjsSyncTransferSiteJs(type: Sync) {
2129   from "${jalviewDir}/${jalviewjsTransferSiteJsDir}"
2130   include "**/*.*"
2131   into "${jalviewDir}/${jalviewjsSiteDir}"
2132   preserve {
2133     include "**"
2134   }
2135 }
2136
2137
2138 jalviewjsSyncAllLibs.mustRunAfter jalviewjsCopyTransferSiteJs
2139 jalviewjsSyncResources.mustRunAfter jalviewjsCopyTransferSiteJs
2140 jalviewjsSyncSiteResources.mustRunAfter jalviewjsCopyTransferSiteJs
2141 jalviewjsSyncBuildProperties.mustRunAfter jalviewjsCopyTransferSiteJs
2142
2143 jalviewjsSyncAllLibs.mustRunAfter jalviewjsSyncTransferSiteJs
2144 jalviewjsSyncResources.mustRunAfter jalviewjsSyncTransferSiteJs
2145 jalviewjsSyncSiteResources.mustRunAfter jalviewjsSyncTransferSiteJs
2146 jalviewjsSyncBuildProperties.mustRunAfter jalviewjsSyncTransferSiteJs
2147
2148
2149 task jalviewjsPrepareSite {
2150   group "JalviewJS"
2151   description "Prepares the website folder including unzipping files and copying resources"
2152   dependsOn jalviewjsSyncAllLibs
2153   dependsOn jalviewjsSyncResources
2154   dependsOn jalviewjsSyncSiteResources
2155   dependsOn jalviewjsSyncBuildProperties
2156   dependsOn jalviewjsSyncCore
2157 }
2158
2159
2160 task jalviewjsBuildSite {
2161   group "JalviewJS"
2162   description "Builds the whole website including transpiled code"
2163   dependsOn jalviewjsCopyTransferSiteJs
2164   dependsOn jalviewjsPrepareSite
2165 }
2166
2167
2168 task cleanJalviewjsSite {
2169   doFirst {
2170     delete "${jalviewDir}/${jalviewjsTransferSiteJsDir}"
2171     delete "${jalviewDir}/${jalviewjsTransferSiteLibDir}"
2172     delete "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}"
2173     delete "${jalviewDir}/${jalviewjsTransferSiteCoreDir}"
2174     delete "${jalviewDir}/${jalviewjsSiteDir}"
2175   }
2176 }
2177
2178
2179 task jalviewjsSiteTar(type: Tar) {
2180   group "JalviewJS"
2181   description "Creates a tar.gz file for the website"
2182   dependsOn jalviewjsBuildSite
2183   def outputFilename = "jalviewjs-site-${JALVIEW_VERSION}.tar.gz"
2184   try {
2185     archiveFileName = outputFilename
2186   } catch (Exception e) {
2187     archiveName = outputFilename
2188   }
2189
2190   compression Compression.GZIP
2191
2192   from "${jalviewDir}/${jalviewjsSiteDir}"
2193   into jalviewjs_site_dir // this is inside the tar file
2194
2195   inputs.dir("${jalviewDir}/${jalviewjsSiteDir}")
2196 }
2197
2198
2199 task jalviewjsServer {
2200   group "JalviewJS"
2201   def filename = "jalviewjsTest.html"
2202   description "Starts a webserver on localhost to test the website. See ${filename} to access local site on most recently used port."
2203   def htmlFile = "${jalviewDirAbsolutePath}/${filename}"
2204   doLast {
2205
2206     SimpleHttpFileServerFactory factory = new SimpleHttpFileServerFactory()
2207     def port = Integer.valueOf(jalviewjs_server_port)
2208     def start = port
2209     def running = false
2210     def url
2211     def jalviewjsServer
2212     while(port < start+1000 && !running) {
2213       try {
2214         def doc_root = new File("${jalviewDirAbsolutePath}/${jalviewjsSiteDir}")
2215         jalviewjsServer = factory.start(doc_root, port)
2216         running = true
2217         url = jalviewjsServer.getResourceUrl(jalviewjs_server_resource)
2218         println("SERVER STARTED with document root ${doc_root}.")
2219         println("Go to "+url+" . Run  gradle --stop  to stop (kills all gradle daemons).")
2220         println("For debug: "+url+"?j2sdebug")
2221         println("For verbose: "+url+"?j2sverbose")
2222       } catch (Exception e) {
2223         port++;
2224       }
2225     }
2226     def htmlText = """
2227       <p><a href="${url}">JalviewJS Test. &lt;${url}&gt;</a></p>
2228       <p><a href="${url}?j2sdebug">JalviewJS Test with debug. &lt;${url}?j2sdebug&gt;</a></p>
2229       <p><a href="${url}?j2sverbose">JalviewJS Test with verbose. &lt;${url}?j2sdebug&gt;</a></p>
2230       """
2231     jalviewjsCoreClasslists.each { cl ->
2232       def urlcore = jalviewjsServer.getResourceUrl(file(cl.outputfile).getName())
2233       htmlText += """
2234       <p><a href="${urlcore}">${jalviewjsJalviewTemplateName} [core ${cl.name}]. &lt;${urlcore}&gt;</a></p>
2235       """
2236       println("For core ${cl.name}: "+urlcore)
2237     }
2238
2239     file(htmlFile).text = htmlText
2240   }
2241
2242   outputs.file(htmlFile)
2243   outputs.upToDateWhen({false})
2244 }
2245
2246
2247 task cleanJalviewjsAll {
2248   group "JalviewJS"
2249   description "Delete all configuration and build artifacts to do with JalviewJS build"
2250   dependsOn cleanJalviewjsSite
2251   dependsOn jalviewjsEclipsePaths
2252   
2253   doFirst {
2254     delete "${jalviewDir}/${jalviewjsBuildDir}"
2255     delete "${jalviewDir}/${eclipse_bin_dir}"
2256     if (eclipseWorkspace != null && file(eclipseWorkspace.getAbsolutePath()+"/.metadata").exists()) {
2257       delete file(eclipseWorkspace.getAbsolutePath()+"/.metadata")
2258     }
2259     delete "${jalviewDir}/${jalviewjs_j2s_settings}"
2260   }
2261
2262   outputs.upToDateWhen( { false } )
2263 }
2264
2265
2266 task jalviewjsIDE_checkJ2sPlugin {
2267   group "00 JalviewJS in Eclipse"
2268   description "Compare the swingjs/net.sf.j2s.core.jar file with the Eclipse IDE's plugin version (found in the 'dropins' dir)"
2269
2270   doFirst {
2271     def j2sPlugin = string("${jalviewDir}/${jalviewjs_j2s_plugin}")
2272     def j2sPluginFile = file(j2sPlugin)
2273     def eclipseHome = System.properties["eclipse.home.location"]
2274     def copyPlugin = jalviewjs_eclipseIDE_auto_copy_j2s_plugin == "true"
2275     def doCopy = false
2276     if (eclipseHome == null || ! IN_ECLIPSE) {
2277       throw new StopExecutionException("Cannot find running Eclipse home from System.properties['eclipse.home.location']. Skipping J2S Plugin Check.")
2278     }
2279     def eclipseJ2sPlugin = "${eclipseHome}/dropins/${j2sPluginFile.getName()}"
2280     def eclipseJ2sPluginFile = file(eclipseJ2sPlugin)
2281     if (!eclipseJ2sPluginFile.exists()) {
2282       def msg = "Eclipse J2S Plugin is not installed"
2283       println(msg)
2284       if (! copyPlugin) {
2285         throw new GradleException(msg)
2286       }
2287       doCopy = true
2288     }
2289
2290     def digest = MessageDigest.getInstance("MD5")
2291
2292     digest.update(j2sPluginFile.text.bytes)
2293     def j2sPluginMd5 = new BigInteger(1, digest.digest()).toString(16).padLeft(32, '0')
2294
2295     digest.update(eclipseJ2sPluginFile.text.bytes)
2296     def eclipseJ2sPluginMd5 = new BigInteger(1, digest.digest()).toString(16).padLeft(32, '0')
2297      
2298     if (j2sPluginMd5 != eclipseJ2sPluginMd5) {
2299       def msg = "WARNING! Eclipse J2S Plugin '${eclipseJ2sPlugin}' is different to this commit's version '${j2sPlugin}'"
2300       println(msg)
2301       if (! copyPlugin) {
2302         throw new StopExecutionException(msg)
2303       }
2304       doCopy = true
2305     }
2306
2307     if (doCopy) {
2308       def msg = "WARNING! Auto-copying this commit's j2s plugin version '${j2sPlugin}' to Eclipse J2S Plugin '${eclipseJ2sPlugin}'\n         May require an Eclipse restart"
2309       println(msg)
2310       copy {
2311         from j2sPlugin
2312         eclipseJ2sPluginFile.getParentFile().mkdirs()
2313         into eclipseJ2sPluginFile.getParent()
2314       }
2315     } else {
2316       def msg = "Eclipse J2S Plugin is the same as '${j2sPlugin}'"
2317       println(msg)
2318     }
2319   }
2320 }
2321
2322
2323 task jalviewjsIDE_j2sFile {
2324   group "00 JalviewJS in Eclipse"
2325   description "Creates the .j2s file"
2326   dependsOn jalviewjsCreateJ2sSettings
2327 }
2328
2329
2330 task jalviewjsIDE_SyncCore {
2331   group "00 JalviewJS in Eclipse"
2332   description "Build the core js lib closures listed in the classlists dir and publish core html from template"
2333   dependsOn jalviewjsSyncCore
2334 }
2335
2336
2337 task jalviewjsIDE_PrepareSite {
2338   group "00 JalviewJS in Eclipse"
2339   description "Sync libs and resources to site dir, but not closure cores"
2340   dependsOn jalviewjsSyncAllLibs
2341   dependsOn jalviewjsSyncResources
2342   dependsOn jalviewjsSyncSiteResources
2343   dependsOn jalviewjsSyncBuildProperties
2344 }
2345
2346
2347 task jalviewjsIDE_AssembleSite {
2348   group "00 JalviewJS in Eclipse"
2349   description "Assembles unzipped supporting zipfiles, resources, site resources and closure cores into the Eclipse transpiled site"
2350   dependsOn jalviewjsPrepareSite
2351 }
2352
2353
2354 task jalviewjsIDE_SiteClean {
2355   group "00 JalviewJS in Eclipse"
2356   description "Deletes the Eclipse transpiled site"
2357   dependsOn cleanJalviewjsSite
2358 }
2359
2360
2361 task jalviewjsIDE_Server {
2362   group "00 JalviewJS in Eclipse"
2363   description "Starts a webserver on localhost to test the website"
2364   dependsOn jalviewjsServer
2365 }
2366
2367
2368 // buildship runs this at import or gradle refresh
2369 task eclipseSynchronizationTask {
2370   //dependsOn eclipseSetup
2371   dependsOn jalviewjsIDE_j2sFile
2372   dependsOn jalviewjsIDE_checkJ2sPlugin
2373 }
2374
2375
2376 // buildship runs this at build time or project refresh
2377 task eclipseAutoBuildTask {
2378   //dependsOn jalviewjsIDE_checkJ2sPlugin
2379   dependsOn jalviewjsIDE_PrepareSite
2380 }
2381
2382
2383
2384
2385
2386
2387
2388
2389 task jalviewjs {
2390   group "JalviewJS"
2391   description "Build the site"
2392   dependsOn jalviewjsBuildSite
2393 }