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