merge from develop: the fixy bit
[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   doFirst {
809     sourceCompatibility = compile_source_compatibility
810     targetCompatibility = compile_target_compatibility
811     options.compilerArgs = additional_compiler_args
812     print ("Setting target compatibility to "+targetCompatibility+"\n")
813   }
814
815 }
816
817
818 compileTestJava {
819   if (use_clover) {
820     dependsOn compileCloverJava
821     classpath += configurations.cloverRuntime
822   } else {
823     classpath += sourceSets.main.runtimeClasspath
824   }
825   doFirst {
826     sourceCompatibility = compile_source_compatibility
827     targetCompatibility = compile_target_compatibility
828     options.compilerArgs = additional_compiler_args
829     print ("Setting target compatibility to "+targetCompatibility+"\n")
830   }
831 }
832
833
834 clean {
835   doFirst {
836     delete sourceSets.main.java.outputDir
837   }
838 }
839
840
841 cleanTest {
842   dependsOn cleanClover
843   doFirst {
844     delete sourceSets.test.java.outputDir
845   }
846 }
847
848
849 // format is a string like date.format("dd MMMM yyyy")
850 def getDate(format) {
851   def date = new Date()
852   return date.format(format)
853 }
854
855
856 task setGitVals {
857   def hashStdOut = new ByteArrayOutputStream()
858   exec {
859     commandLine "git", "rev-parse", "--short", "HEAD"
860     standardOutput = hashStdOut
861     ignoreExitValue true
862   }
863
864   def branchStdOut = new ByteArrayOutputStream()
865   exec {
866     commandLine "git", "rev-parse", "--abbrev-ref", "HEAD"
867     standardOutput = branchStdOut
868     ignoreExitValue true
869   }
870
871   gitHash = hashStdOut.toString().trim()
872   gitBranch = branchStdOut.toString().trim()
873
874   outputs.upToDateWhen { false }
875 }
876
877
878 task createBuildProperties(type: WriteProperties) {
879   group = "build"
880   description = "Create the ${buildProperties} file"
881   
882   dependsOn setGitVals
883   inputs.dir(sourceDir)
884   inputs.dir(resourceDir)
885   file(buildProperties).getParentFile().mkdirs()
886   outputFile (buildProperties)
887   // taking time specific comment out to allow better incremental builds
888   comment "--Jalview Build Details--\n"+getDate("yyyy-MM-dd HH:mm:ss")
889   //comment "--Jalview Build Details--\n"+getDate("yyyy-MM-dd")
890   property "BUILD_DATE", getDate("HH:mm:ss dd MMMM yyyy")
891   property "VERSION", JALVIEW_VERSION
892   property "INSTALLATION", INSTALLATION+" git-commit:"+gitHash+" ["+gitBranch+"]"
893   outputs.file(outputFile)
894 }
895
896
897 clean {
898   doFirst {
899     delete buildProperties
900   }
901 }
902
903
904 task cleanBuildingHTML(type: Delete) {
905   doFirst {
906     delete buildingHTML
907   }
908 }
909
910
911 task convertBuildingMD(type: Exec) {
912   dependsOn cleanBuildingHTML
913   def buildingMD = "${jalviewDir}/${docDir}/building.md"
914   def css = "${jalviewDir}/${docDir}/github.css"
915
916   def pandoc = null
917   pandoc_exec.split(",").each {
918     if (file(it.trim()).exists()) {
919       pandoc = it.trim()
920       return true
921     }
922   }
923
924   def buildtoolsPandoc = System.getProperty("user.home")+"/buildtools/pandoc/bin/pandoc"
925   if ((pandoc == null || ! file(pandoc).exists()) && file(buildtoolsPandoc).exists()) {
926     pandoc = System.getProperty("user.home")+"/buildtools/pandoc/bin/pandoc"
927   }
928
929   doFirst {
930     if (pandoc != null && file(pandoc).exists()) {
931         commandLine pandoc, '-s', '-o', buildingHTML, '--metadata', 'pagetitle="Building Jalview from Source"', '--toc', '-H', css, buildingMD
932     } else {
933         println("Cannot find pandoc. Skipping convert building.md to HTML")
934         throw new StopExecutionException("Cannot find pandoc. Skipping convert building.md to HTML")
935     }
936   }
937
938   ignoreExitValue true
939
940   inputs.file(buildingMD)
941   inputs.file(css)
942   outputs.file(buildingHTML)
943 }
944
945
946 task syncDocs(type: Sync) {
947   dependsOn convertBuildingMD
948   def syncDir = "${classesDir}/${docDir}"
949   from fileTree("${jalviewDir}/${docDir}")
950   into syncDir
951
952 }
953
954
955 task copyHelp(type: Copy) {
956   def inputDir = helpSourceDir
957   def outputDir = "${classesDir}/${help_dir}"
958   from(inputDir) {
959     exclude '**/*.gif'
960     exclude '**/*.jpg'
961     exclude '**/*.png'
962     filter(ReplaceTokens,
963       beginToken: '$$',
964       endToken: '$$',
965       tokens: [
966         'Version-Rel': JALVIEW_VERSION,
967         'Year-Rel': getDate("yyyy")
968       ]
969     )
970   }
971   from(inputDir) {
972     include '**/*.gif'
973     include '**/*.jpg'
974     include '**/*.png'
975   }
976   into outputDir
977
978   inputs.dir(inputDir)
979   outputs.files(helpFile)
980   outputs.dir(outputDir)
981 }
982
983
984 task syncLib(type: Sync) {
985   def syncDir = "${classesDir}/${libDistDir}"
986   from fileTree("${jalviewDir}/${libDistDir}")
987   into syncDir
988 }
989
990
991 task syncResources(type: Sync) {
992   dependsOn createBuildProperties
993   from resourceDir
994   include "**/*.*"
995   into "${classesDir}"
996   preserve {
997     include "**"
998   }
999 }
1000
1001
1002 task prepare {
1003   dependsOn syncResources
1004   dependsOn syncDocs
1005   dependsOn copyHelp
1006 }
1007
1008
1009 //testReportDirName = "test-reports" // note that test workingDir will be $jalviewDir
1010 test {
1011   dependsOn prepare
1012   dependsOn compileJava
1013   if (use_clover) {
1014     dependsOn cloverInstr
1015   }
1016
1017   if (use_clover) {
1018     print("Running tests " + (use_clover?"WITH":"WITHOUT") + " clover [clover="+use_clover+"]\n")
1019   }
1020
1021   useTestNG() {
1022     includeGroups testngGroups
1023     excludeGroups testngExcludedGroups
1024     preserveOrder true
1025     useDefaultListeners=true
1026   }
1027
1028   maxHeapSize = "1024m"
1029
1030   workingDir = jalviewDir
1031   //systemProperties 'clover.jar' System.properties.clover.jar
1032   sourceCompatibility = compile_source_compatibility
1033   targetCompatibility = compile_target_compatibility
1034   jvmArgs += additional_compiler_args
1035
1036 }
1037
1038
1039 task buildIndices(type: JavaExec) {
1040   dependsOn copyHelp
1041   classpath = sourceSets.main.compileClasspath
1042   main = "com.sun.java.help.search.Indexer"
1043   workingDir = "${classesDir}/${help_dir}"
1044   def argDir = "html"
1045   args = [ argDir ]
1046   inputs.dir("${workingDir}/${argDir}")
1047
1048   outputs.dir("${classesDir}/doc")
1049   outputs.dir("${classesDir}/help")
1050   outputs.file("${workingDir}/JavaHelpSearch/DOCS")
1051   outputs.file("${workingDir}/JavaHelpSearch/DOCS.TAB")
1052   outputs.file("${workingDir}/JavaHelpSearch/OFFSETS")
1053   outputs.file("${workingDir}/JavaHelpSearch/POSITIONS")
1054   outputs.file("${workingDir}/JavaHelpSearch/SCHEMA")
1055   outputs.file("${workingDir}/JavaHelpSearch/TMAP")
1056 }
1057
1058
1059 task compileLinkCheck(type: JavaCompile) {
1060   options.fork = true
1061   classpath = files("${jalviewDir}/${utilsDir}")
1062   destinationDir = file("${jalviewDir}/${utilsDir}")
1063   source = fileTree(dir: "${jalviewDir}/${utilsDir}", include: ["HelpLinksChecker.java", "BufferedLineReader.java"])
1064
1065   inputs.file("${jalviewDir}/${utilsDir}/HelpLinksChecker.java")
1066   inputs.file("${jalviewDir}/${utilsDir}/HelpLinksChecker.java")
1067   outputs.file("${jalviewDir}/${utilsDir}/HelpLinksChecker.class")
1068   outputs.file("${jalviewDir}/${utilsDir}/BufferedLineReader.class")
1069 }
1070
1071
1072 task linkCheck(type: JavaExec) {
1073   dependsOn prepare, compileLinkCheck
1074
1075   def helpLinksCheckerOutFile = file("${jalviewDir}/${utilsDir}/HelpLinksChecker.out")
1076   classpath = files("${jalviewDir}/${utilsDir}")
1077   main = "HelpLinksChecker"
1078   workingDir = jalviewDir
1079   args = [ "${classesDir}/${help_dir}", "-nointernet" ]
1080
1081   def outFOS = new FileOutputStream(helpLinksCheckerOutFile, false) // false == don't append
1082   def errFOS = outFOS
1083   standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
1084     outFOS,
1085     standardOutput)
1086   errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
1087     outFOS,
1088     errorOutput)
1089
1090   inputs.dir("${classesDir}/${help_dir}")
1091   outputs.file(helpLinksCheckerOutFile)
1092 }
1093
1094 // import the pubhtmlhelp target
1095 ant.properties.basedir = "${jalviewDir}"
1096 ant.properties.helpBuildDir = "${jalviewDirAbsolutePath}/${classes_dir}/${help_dir}"
1097 ant.importBuild "${utilsDir}/publishHelp.xml"
1098
1099
1100 task cleanPackageDir(type: Delete) {
1101   doFirst {
1102     delete fileTree(dir: "${jalviewDir}/${packageDir}", include: "*.jar")
1103   }
1104 }
1105
1106
1107 jar {
1108   dependsOn linkCheck
1109   dependsOn buildIndices
1110   dependsOn createBuildProperties
1111
1112   manifest {
1113     attributes "Main-Class": mainClass,
1114     "Permissions": "all-permissions",
1115     "Application-Name": "Jalview Desktop",
1116     "Codebase": application_codebase
1117   }
1118
1119   destinationDir = file("${jalviewDir}/${packageDir}")
1120   archiveName = rootProject.name+".jar"
1121
1122   exclude "cache*/**"
1123   exclude "*.jar"
1124   exclude "*.jar.*"
1125   exclude "**/*.jar"
1126   exclude "**/*.jar.*"
1127
1128   inputs.dir(classesDir)
1129   outputs.file("${jalviewDir}/${packageDir}/${archiveName}")
1130 }
1131
1132
1133 task copyJars(type: Copy) {
1134   from fileTree(dir: classesDir, include: "**/*.jar").files
1135   into "${jalviewDir}/${packageDir}"
1136 }
1137
1138
1139 // doing a Sync instead of Copy as Copy doesn't deal with "outputs" very well
1140 task syncJars(type: Sync) {
1141   from fileTree(dir: "${jalviewDir}/${libDistDir}", include: "**/*.jar").files
1142   into "${jalviewDir}/${packageDir}"
1143   preserve {
1144     include jar.archiveName
1145   }
1146 }
1147
1148
1149 task makeDist {
1150   group = "build"
1151   description = "Put all required libraries in dist"
1152   // order of "cleanPackageDir", "copyJars", "jar" important!
1153   jar.mustRunAfter cleanPackageDir
1154   syncJars.mustRunAfter cleanPackageDir
1155   dependsOn cleanPackageDir
1156   dependsOn syncJars
1157   dependsOn jar
1158   outputs.dir("${jalviewDir}/${packageDir}")
1159 }
1160
1161
1162 task cleanDist {
1163   dependsOn cleanPackageDir
1164   dependsOn cleanTest
1165   dependsOn clean
1166 }
1167
1168 shadowJar {
1169   group = "distribution"
1170   if (buildDist) {
1171     dependsOn makeDist
1172   }
1173   from ("${jalviewDir}/${libDistDir}") {
1174     include("*.jar")
1175   }
1176   manifest {
1177     attributes 'Implementation-Version': JALVIEW_VERSION
1178   }
1179   mainClassName = shadowJarMainClass
1180   mergeServiceFiles()
1181   classifier = "all-"+JALVIEW_VERSION+"-j"+JAVA_VERSION
1182   minimize()
1183 }
1184
1185
1186 task getdownWebsite() {
1187   group = "distribution"
1188   description = "Create the getdown minimal app folder, and website folder for this version of jalview. Website folder also used for offline app installer"
1189   if (buildDist) {
1190     dependsOn makeDist
1191   }
1192
1193   def getdownWebsiteResourceFilenames = []
1194   def getdownTextString = ""
1195   def getdownResourceDir = getdownResourceDir
1196   def getdownResourceFilenames = []
1197
1198   doFirst {
1199     // clean the getdown website and files dir before creating getdown folders
1200     delete getdownWebsiteDir
1201     delete getdownFilesDir
1202
1203     copy {
1204       from buildProperties
1205       rename(build_properties_file, getdown_build_properties)
1206       into getdownAppDir
1207     }
1208     getdownWebsiteResourceFilenames += "${getdownAppDistDir}/${getdown_build_properties}"
1209
1210     // set some getdown_txt_ properties then go through all properties looking for getdown_txt_...
1211     def props = project.properties.sort { it.key }
1212     if (getdownAltJavaMinVersion != null && getdownAltJavaMinVersion.length() > 0) {
1213       props.put("getdown_txt_java_min_version", getdownAltJavaMinVersion)
1214     }
1215     if (getdownAltJavaMaxVersion != null && getdownAltJavaMaxVersion.length() > 0) {
1216       props.put("getdown_txt_java_max_version", getdownAltJavaMaxVersion)
1217     }
1218     if (getdownAltMultiJavaLocation != null && getdownAltMultiJavaLocation.length() > 0) {
1219       props.put("getdown_txt_multi_java_location", getdownAltMultiJavaLocation)
1220     }
1221
1222     props.put("getdown_txt_title", jalview_name)
1223     props.put("getdown_txt_ui.name", install4jApplicationName)
1224
1225     // start with appbase
1226     getdownTextString += "appbase = ${getdownAppBase}\n"
1227     props.each{ prop, val ->
1228       if (prop.startsWith("getdown_txt_") && val != null) {
1229         if (prop.startsWith("getdown_txt_multi_")) {
1230           def key = prop.substring(18)
1231           val.split(",").each{ v ->
1232             def line = "${key} = ${v}\n"
1233             getdownTextString += line
1234           }
1235         } else {
1236           // file values rationalised
1237           if (val.indexOf('/') > -1 || prop.startsWith("getdown_txt_resource")) {
1238             def r = null
1239             if (val.indexOf('/') == 0) {
1240               // absolute path
1241               r = file(val)
1242             } else if (val.indexOf('/') > 0) {
1243               // relative path (relative to jalviewDir)
1244               r = file( "${jalviewDir}/${val}" )
1245             }
1246             if (r.exists()) {
1247               val = "${getdown_resource_dir}/" + r.getName()
1248               getdownWebsiteResourceFilenames += val
1249               getdownResourceFilenames += r.getPath()
1250             }
1251           }
1252           if (! prop.startsWith("getdown_txt_resource")) {
1253             def line = prop.substring(12) + " = ${val}\n"
1254             getdownTextString += line
1255           }
1256         }
1257       }
1258     }
1259
1260     getdownWebsiteResourceFilenames.each{ filename ->
1261       getdownTextString += "resource = ${filename}\n"
1262     }
1263     getdownResourceFilenames.each{ filename ->
1264       copy {
1265         from filename
1266         into getdownResourceDir
1267       }
1268     }
1269
1270     def codeFiles = []
1271     fileTree(file(packageDir)).each{ f ->
1272       if (f.isDirectory()) {
1273         def files = fileTree(dir: f, include: ["*"]).getFiles()
1274         codeFiles += files
1275       } else if (f.exists()) {
1276         codeFiles += f
1277       }
1278     }
1279     codeFiles.sort().each{f ->
1280       def name = f.getName()
1281       def line = "code = ${getdownAppDistDir}/${name}\n"
1282       getdownTextString += line
1283       copy {
1284         from f.getPath()
1285         into getdownAppDir
1286       }
1287     }
1288
1289     // NOT USING MODULES YET, EVERYTHING SHOULD BE IN dist
1290     /*
1291     if (JAVA_VERSION.equals("11")) {
1292     def j11libFiles = fileTree(dir: "${jalviewDir}/${j11libDir}", include: ["*.jar"]).getFiles()
1293     j11libFiles.sort().each{f ->
1294     def name = f.getName()
1295     def line = "code = ${getdown_j11lib_dir}/${name}\n"
1296     getdownTextString += line
1297     copy {
1298     from f.getPath()
1299     into getdownJ11libDir
1300     }
1301     }
1302     }
1303      */
1304
1305     // 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.
1306     //getdownTextString += "class = " + file(getdownLauncher).getName() + "\n"
1307     getdownTextString += "resource = ${getdown_launcher_new}\n"
1308     getdownTextString += "class = ${mainClass}\n"
1309
1310     def getdown_txt = file("${getdownWebsiteDir}/getdown.txt")
1311     getdown_txt.write(getdownTextString)
1312
1313     def getdownLaunchJvl = getdown_launch_jvl_name + ( (jvlChannelName != null && jvlChannelName.length() > 0)?"-${jvlChannelName}":"" ) + ".jvl"
1314     def launchJvl = file("${getdownWebsiteDir}/${getdownLaunchJvl}")
1315     launchJvl.write("appbase=${getdownAppBase}")
1316
1317     copy {
1318       from getdownLauncher
1319       rename(file(getdownLauncher).getName(), getdown_launcher_new)
1320       into getdownWebsiteDir
1321     }
1322
1323     copy {
1324       from getdownLauncher
1325       if (file(getdownLauncher).getName() != getdown_launcher) {
1326         rename(file(getdownLauncher).getName(), getdown_launcher)
1327       }
1328       into getdownWebsiteDir
1329     }
1330
1331     if (! (CHANNEL.startsWith("ARCHIVE") || CHANNEL.startsWith("DEVELOP"))) {
1332       copy {
1333         from getdown_txt
1334         from getdownLauncher
1335         from "${getdownWebsiteDir}/${getdown_build_properties}"
1336         if (file(getdownLauncher).getName() != getdown_launcher) {
1337           rename(file(getdownLauncher).getName(), getdown_launcher)
1338         }
1339         into getdownInstallDir
1340       }
1341
1342       copy {
1343         from getdownInstallDir
1344         into getdownFilesInstallDir
1345       }
1346     }
1347
1348     copy {
1349       from getdown_txt
1350       from launchJvl
1351       from getdownLauncher
1352       from "${getdownWebsiteDir}/${getdown_build_properties}"
1353       if (file(getdownLauncher).getName() != getdown_launcher) {
1354         rename(file(getdownLauncher).getName(), getdown_launcher)
1355       }
1356       into getdownFilesDir
1357     }
1358
1359     copy {
1360       from getdownResourceDir
1361       into "${getdownFilesDir}/${getdown_resource_dir}"
1362     }
1363   }
1364
1365   if (buildDist) {
1366     inputs.dir("${jalviewDir}/${packageDir}")
1367   }
1368   outputs.dir(getdownWebsiteDir)
1369   outputs.dir(getdownFilesDir)
1370 }
1371
1372
1373 // a helper task to allow getdown digest of any dir: `gradle getdownDigestDir -PDIGESTDIR=/path/to/my/random/getdown/dir
1374 task getdownDigestDir(type: JavaExec) {
1375   def digestDirPropertyName = "DIGESTDIR"
1376   description = "Digest a local dir (-P${digestDirPropertyName}=...) for getdown"
1377   doFirst {
1378     classpath = files(getdownLauncher)
1379     def digestDir = findProperty(digestDirPropertyName)
1380     if (digestDir == null) {
1381       throw new GradleException("Must provide a DIGESTDIR value to produce an alternative getdown digest")
1382     }
1383     args digestDir
1384   }
1385   main = "com.threerings.getdown.tools.Digester"
1386 }
1387
1388
1389 task getdownDigest(type: JavaExec) {
1390   group = "distribution"
1391   description = "Digest the getdown website folder"
1392   dependsOn getdownWebsite
1393   doFirst {
1394     classpath = files(getdownLauncher)
1395   }
1396   main = "com.threerings.getdown.tools.Digester"
1397   args getdownWebsiteDir
1398   inputs.dir(getdownWebsiteDir)
1399   outputs.file("${getdownWebsiteDir}/digest2.txt")
1400 }
1401
1402
1403 task getdown() {
1404   group = "distribution"
1405   description = "Create the minimal and full getdown app folder for installers and website and create digest file"
1406   dependsOn getdownDigest
1407   doLast {
1408     if (reportRsyncCommand) {
1409       def fromDir = getdownWebsiteDir + (getdownWebsiteDir.endsWith('/')?'':'/')
1410       def toDir = "${getdown_rsync_dest}/${getdownDir}" + (getdownDir.endsWith('/')?'':'/')
1411       println "LIKELY RSYNC COMMAND:"
1412       println "mkdir -p '$toDir'\nrsync -avh --delete '$fromDir' '$toDir'"
1413       if (RUNRSYNC == "true") {
1414         exec {
1415           commandLine "mkdir", "-p", toDir
1416         }
1417         exec {
1418           commandLine "rsync", "-avh", "--delete", fromDir, toDir
1419         }
1420       }
1421     }
1422   }
1423 }
1424
1425
1426 clean {
1427   doFirst {
1428     delete getdownWebsiteDir
1429     delete getdownFilesDir
1430   }
1431 }
1432
1433
1434 install4j {
1435   if (file(install4jHomeDir).exists()) {
1436     // good to go!
1437   } else if (file(System.getProperty("user.home")+"/buildtools/install4j").exists()) {
1438     install4jHomeDir = System.getProperty("user.home")+"/buildtools/install4j"
1439   } else if (file("/Applications/install4j.app/Contents/Resources/app").exists()) {
1440     install4jHomeDir = "/Applications/install4j.app/Contents/Resources/app"
1441   }
1442   installDir(file(install4jHomeDir))
1443
1444   mediaTypes = Arrays.asList(install4j_media_types.split(","))
1445 }
1446
1447
1448 task copyInstall4jTemplate {
1449   def install4jTemplateFile = file("${install4jDir}/${install4j_template}")
1450   def install4jFileAssociationsFile = file("${install4jDir}/${install4j_installer_file_associations}")
1451   inputs.file(install4jTemplateFile)
1452   inputs.file(install4jFileAssociationsFile)
1453   inputs.property("CHANNEL", { CHANNEL })
1454   outputs.file(install4jConfFile)
1455
1456   doLast {
1457     def install4jConfigXml = new XmlParser().parse(install4jTemplateFile)
1458
1459     // turn off code signing if no OSX_KEYPASS
1460     if (OSX_KEYPASS == "") {
1461       install4jConfigXml.'**'.codeSigning.each { codeSigning ->
1462         codeSigning.'@macEnabled' = "false"
1463       }
1464       install4jConfigXml.'**'.windows.each { windows ->
1465         windows.'@runPostProcessor' = "false"
1466       }
1467     }
1468
1469     // turn off checksum creation for LOCAL channel
1470     def e = install4jConfigXml.application[0]
1471     if (CHANNEL == "LOCAL") {
1472       e.'@createChecksums' = "false"
1473     } else {
1474       e.'@createChecksums' = "true"
1475     }
1476
1477     // put file association actions where placeholder action is
1478     def install4jFileAssociationsText = install4jFileAssociationsFile.text
1479     def fileAssociationActions = new XmlParser().parseText("<actions>${install4jFileAssociationsText}</actions>")
1480     install4jConfigXml.'**'.action.any { a -> // .any{} stops after the first one that returns true
1481       if (a.'@name' == 'EXTENSIONS_REPLACED_BY_GRADLE') {
1482         def parent = a.parent()
1483         parent.remove(a)
1484         fileAssociationActions.each { faa ->
1485             parent.append(faa)
1486         }
1487         // don't need to continue in .any loop once replacements have been made
1488         return true
1489       }
1490     }
1491
1492     // use Windows Program Group with Examples folder for RELEASE, and Program Group without Examples for everything else
1493     // NB we're deleting the /other/ one!
1494     // Also remove the examples subdir from non-release versions
1495     def customizedIdToDelete = "PROGRAM_GROUP_RELEASE"
1496     if (CHANNEL=="RELEASE") {
1497       customizedIdToDelete = "PROGRAM_GROUP_NON_RELEASE"
1498     } else {
1499       // remove the examples subdir from Full File Set
1500       def files = install4jConfigXml.files[0]
1501       def fileset = files.filesets.fileset.find { fs -> fs.'@customizedId' == "FULL_FILE_SET" }
1502       def root = files.roots.root.find { r -> r.'@fileset' == fileset.'@id' }
1503       def mountPoint = files.mountPoints.mountPoint.find { mp -> mp.'@root' == root.'@id' }
1504       def dirEntry = files.entries.dirEntry.find { de -> de.'@mountPoint' == mountPoint.'@id' && de.'@subDirectory' == "examples" }
1505       dirEntry.parent().remove(dirEntry)
1506     }
1507     install4jConfigXml.'**'.action.any { a ->
1508       if (a.'@customizedId' == customizedIdToDelete) {
1509         def parent = a.parent()
1510         parent.remove(a)
1511         return true
1512       }
1513     }
1514
1515     // remove the "Uninstall Old Jalview (optional)" symlink from DMG for non-release DS_Stores
1516     if (! (CHANNEL == "RELEASE" || CHANNEL == "TEST-RELEASE" ) ) {
1517       def symlink = install4jConfigXml.'**'.topLevelFiles.symlink.find { sl -> sl.'@name' == "Uninstall Old Jalview (optional).app" }
1518       symlink.parent().remove(symlink)
1519     }
1520
1521     // write install4j file
1522     install4jConfFile.text = XmlUtil.serialize(install4jConfigXml)
1523   }
1524 }
1525
1526
1527 clean {
1528   doFirst {
1529     delete install4jConfFile
1530   }
1531 }
1532
1533
1534 task installers(type: com.install4j.gradle.Install4jTask) {
1535   group = "distribution"
1536   description = "Create the install4j installers"
1537   dependsOn setGitVals
1538   dependsOn getdown
1539   dependsOn copyInstall4jTemplate
1540
1541   projectFile = install4jConfFile
1542
1543   // create an md5 for the input files to use as version for install4j conf file
1544   def digest = MessageDigest.getInstance("MD5")
1545   digest.update(
1546     (file("${install4jDir}/${install4j_template}").text + 
1547     file("${install4jDir}/${install4j_info_plist_file_associations}").text +
1548     file("${install4jDir}/${install4j_installer_file_associations}").text).bytes)
1549   def filesMd5 = new BigInteger(1, digest.digest()).toString(16)
1550   if (filesMd5.length() >= 8) {
1551     filesMd5 = filesMd5.substring(0,8)
1552   }
1553   def install4jTemplateVersion = "${JALVIEW_VERSION}_F${filesMd5}_C${gitHash}"
1554   // make install4jBuildDir relative to jalviewDir
1555   def install4jBuildDir = "${install4j_build_dir}/${JAVA_VERSION}"
1556
1557   variables = [
1558     'JALVIEW_NAME': jalview_name,
1559     'JALVIEW_APPLICATION_NAME': install4jApplicationName,
1560     'JALVIEW_DIR': "../..",
1561     'OSX_KEYSTORE': OSX_KEYSTORE,
1562     'JSIGN_SH': JSIGN_SH,
1563     'JRE_DIR': getdown_app_dir_java,
1564     'INSTALLER_TEMPLATE_VERSION': install4jTemplateVersion,
1565     'JALVIEW_VERSION': JALVIEW_VERSION,
1566     'JAVA_MIN_VERSION': JAVA_MIN_VERSION,
1567     'JAVA_MAX_VERSION': JAVA_MAX_VERSION,
1568     'JAVA_VERSION': JAVA_VERSION,
1569     'JAVA_INTEGER_VERSION': JAVA_INTEGER_VERSION,
1570     'VERSION': JALVIEW_VERSION,
1571     'MACOS_JAVA_VM_DIR': macosJavaVMDir,
1572     'WINDOWS_JAVA_VM_DIR': windowsJavaVMDir,
1573     'LINUX_JAVA_VM_DIR': linuxJavaVMDir,
1574     'MACOS_JAVA_VM_TGZ': macosJavaVMTgz,
1575     'WINDOWS_JAVA_VM_TGZ': windowsJavaVMTgz,
1576     'LINUX_JAVA_VM_TGZ': linuxJavaVMTgz,
1577     'COPYRIGHT_MESSAGE': install4j_copyright_message,
1578     'BUNDLE_ID': install4jBundleId,
1579     'INTERNAL_ID': install4jInternalId,
1580     'WINDOWS_APPLICATION_ID': install4jWinApplicationId,
1581     'MACOS_DS_STORE': install4jDSStore,
1582     'MACOS_DMG_BG_IMAGE': install4jDMGBackgroundImage,
1583     'INSTALLER_NAME': install4jInstallerName,
1584     'INSTALL4J_UTILS_DIR': install4j_utils_dir,
1585     'GETDOWN_WEBSITE_DIR': getdown_website_dir,
1586     'GETDOWN_FILES_DIR': getdown_files_dir,
1587     'GETDOWN_RESOURCE_DIR': getdown_resource_dir,
1588     'GETDOWN_DIST_DIR': getdownAppDistDir,
1589     'GETDOWN_ALT_DIR': getdown_app_dir_alt,
1590     'GETDOWN_INSTALL_DIR': getdown_install_dir,
1591     'INFO_PLIST_FILE_ASSOCIATIONS_FILE': install4j_info_plist_file_associations,
1592     'BUILD_DIR': install4jBuildDir,
1593     'APPLICATION_CATEGORIES': install4j_application_categories,
1594     'APPLICATION_FOLDER': install4jApplicationFolder,
1595     'UNIX_APPLICATION_FOLDER': install4jUnixApplicationFolder,
1596     'EXECUTABLE_NAME': install4jExecutableName,
1597     'EXTRA_SCHEME': install4jExtraScheme,
1598   ]
1599
1600   //println("INSTALL4J VARIABLES:")
1601   //variables.each{k,v->println("${k}=${v}")}
1602
1603   destination = "${jalviewDir}/${install4jBuildDir}"
1604   buildSelected = true
1605
1606   if (install4j_faster.equals("true") || CHANNEL.startsWith("LOCAL")) {
1607     faster = true
1608     disableSigning = true
1609   }
1610
1611   if (OSX_KEYPASS) {
1612     macKeystorePassword = OSX_KEYPASS
1613   }
1614
1615   doFirst {
1616     println("Using projectFile "+projectFile)
1617   }
1618
1619   inputs.dir(getdownWebsiteDir)
1620   inputs.file(install4jConfFile)
1621   inputs.file("${install4jDir}/${install4j_info_plist_file_associations}")
1622   inputs.dir(macosJavaVMDir)
1623   inputs.dir(windowsJavaVMDir)
1624   outputs.dir("${jalviewDir}/${install4j_build_dir}/${JAVA_VERSION}")
1625 }
1626
1627
1628 spotless {
1629   java {
1630     eclipse().configFile(eclipse_codestyle_file)
1631   }
1632 }
1633
1634
1635 task sourceDist(type: Tar) {
1636   
1637   def VERSION_UNDERSCORES = JALVIEW_VERSION.replaceAll("\\.", "_")
1638   def outputFileName = "${project.name}_${VERSION_UNDERSCORES}.tar.gz"
1639   // cater for buildship < 3.1 [3.0.1 is max version in eclipse 2018-09]
1640   try {
1641     archiveFileName = outputFileName
1642   } catch (Exception e) {
1643     archiveName = outputFileName
1644   }
1645   
1646   compression Compression.GZIP
1647   
1648   into project.name
1649
1650   def EXCLUDE_FILES=[
1651     "build/*",
1652     "bin/*",
1653     "test-output/",
1654     "test-reports",
1655     "tests",
1656     "clover*/*",
1657     ".*",
1658     "benchmarking/*",
1659     "**/.*",
1660     "*.class",
1661     "**/*.class","$j11modDir/**/*.jar","appletlib","**/*locales",
1662     "*locales/**",
1663     "utils/InstallAnywhere",
1664     "**/*.log",
1665   ] 
1666   def PROCESS_FILES=[
1667     "AUTHORS",
1668     "CITATION",
1669     "FEATURETODO",
1670     "JAVA-11-README",
1671     "FEATURETODO",
1672     "LICENSE",
1673     "**/README",
1674     "RELEASE",
1675     "THIRDPARTYLIBS",
1676     "TESTNG",
1677     "build.gradle",
1678     "gradle.properties",
1679     "**/*.java",
1680     "**/*.html",
1681     "**/*.xml",
1682     "**/*.gradle",
1683     "**/*.groovy",
1684     "**/*.properties",
1685     "**/*.perl",
1686     "**/*.sh",
1687   ]
1688   def INCLUDE_FILES=[
1689     ".settings/org.eclipse.jdt.core.jalview.prefs",
1690   ]
1691
1692   from(jalviewDir) {
1693     exclude (EXCLUDE_FILES)
1694     include (PROCESS_FILES)
1695     filter(ReplaceTokens,
1696       beginToken: '$$',
1697       endToken: '$$',
1698       tokens: [
1699         'Version-Rel': JALVIEW_VERSION,
1700         'Year-Rel': getDate("yyyy")
1701       ]
1702     )
1703   }
1704   from(jalviewDir) {
1705     exclude (EXCLUDE_FILES)
1706     exclude (PROCESS_FILES)
1707     exclude ("appletlib")
1708     exclude ("**/*locales")
1709     exclude ("*locales/**")
1710     exclude ("utils/InstallAnywhere")
1711
1712     exclude (getdown_files_dir)
1713     exclude (getdown_website_dir)
1714
1715     // exluding these as not using jars as modules yet
1716     exclude ("${j11modDir}/**/*.jar")
1717   }
1718   from(jalviewDir) {
1719     include(INCLUDE_FILES)
1720   }
1721 //  from (jalviewDir) {
1722 //    // explicit includes for stuff that seemed to not get included
1723 //    include(fileTree("test/**/*."))
1724 //    exclude(EXCLUDE_FILES)
1725 //    exclude(PROCESS_FILES)
1726 //  }
1727 }
1728
1729
1730 task helppages {
1731   dependsOn copyHelp
1732   dependsOn pubhtmlhelp
1733   
1734   inputs.dir("${classesDir}/${help_dir}")
1735   outputs.dir("${buildDir}/distributions/${help_dir}")
1736 }
1737
1738
1739 task j2sSetHeadlessBuild {
1740   doFirst {
1741     IN_ECLIPSE = false
1742   }
1743 }
1744
1745
1746 task jalviewjsSetEclipseWorkspace {
1747   def propKey = "jalviewjs_eclipse_workspace"
1748   def propVal = null
1749   if (project.hasProperty(propKey)) {
1750     propVal = project.getProperty(propKey)
1751     if (propVal.startsWith("~/")) {
1752       propVal = System.getProperty("user.home") + propVal.substring(1)
1753     }
1754   }
1755   def propsFileName = "${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_eclipse_workspace_location_file}"
1756   def propsFile = file(propsFileName)
1757   def eclipseWsDir = propVal
1758   def props = new Properties()
1759
1760   def writeProps = true
1761   if (( eclipseWsDir == null || !file(eclipseWsDir).exists() ) && propsFile.exists()) {
1762     def ins = new FileInputStream(propsFileName)
1763     props.load(ins)
1764     ins.close()
1765     if (props.getProperty(propKey, null) != null) {
1766       eclipseWsDir = props.getProperty(propKey)
1767       writeProps = false
1768     }
1769   }
1770
1771   if (eclipseWsDir == null || !file(eclipseWsDir).exists()) {
1772     def tempDir = File.createTempDir()
1773     eclipseWsDir = tempDir.getAbsolutePath()
1774     writeProps = true
1775   }
1776   eclipseWorkspace = file(eclipseWsDir)
1777
1778   doFirst {
1779     // do not run a headless transpile when we claim to be in Eclipse
1780     if (IN_ECLIPSE) {
1781       println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
1782       throw new StopExecutionException("Not running headless transpile whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
1783     } else {
1784       println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
1785     }
1786
1787     if (writeProps) {
1788       props.setProperty(propKey, eclipseWsDir)
1789       propsFile.parentFile.mkdirs()
1790       def bytes = new ByteArrayOutputStream()
1791       props.store(bytes, null)
1792       def propertiesString = bytes.toString()
1793       propsFile.text = propertiesString
1794       print("NEW ")
1795     } else {
1796       print("EXISTING ")
1797     }
1798
1799     println("ECLIPSE WORKSPACE: "+eclipseWorkspace.getPath())
1800   }
1801
1802   //inputs.property(propKey, eclipseWsDir) // eclipseWsDir only gets set once this task runs, so will be out-of-date
1803   outputs.file(propsFileName)
1804   outputs.upToDateWhen { eclipseWorkspace.exists() && propsFile.exists() }
1805 }
1806
1807
1808 task jalviewjsEclipsePaths {
1809   def eclipseProduct
1810
1811   def eclipseRoot = jalviewjs_eclipse_root
1812   if (eclipseRoot.startsWith("~/")) {
1813     eclipseRoot = System.getProperty("user.home") + eclipseRoot.substring(1)
1814   }
1815   if (OperatingSystem.current().isMacOsX()) {
1816     eclipseRoot += "/Eclipse.app"
1817     eclipseBinary = "${eclipseRoot}/Contents/MacOS/eclipse"
1818     eclipseProduct = "${eclipseRoot}/Contents/Eclipse/.eclipseproduct"
1819   } else if (OperatingSystem.current().isWindows()) { // check these paths!!
1820     if (file("${eclipseRoot}/eclipse").isDirectory() && file("${eclipseRoot}/eclipse/.eclipseproduct").exists()) {
1821       eclipseRoot += "/eclipse.exe"
1822     }
1823     eclipseBinary = "${eclipseRoot}/eclipse"
1824     eclipseProduct = "${eclipseRoot}/.eclipseproduct"
1825   } else { // linux or unix
1826     if (file("${eclipseRoot}/eclipse").isDirectory() && file("${eclipseRoot}/eclipse/.eclipseproduct").exists()) {
1827       eclipseRoot += "/eclipse"
1828     }
1829     eclipseBinary = "${eclipseRoot}/eclipse"
1830     eclipseProduct = "${eclipseRoot}/.eclipseproduct"
1831   }
1832
1833   eclipseVersion = "4.13" // default
1834   def assumedVersion = true
1835   if (file(eclipseProduct).exists()) {
1836     def fis = new FileInputStream(eclipseProduct)
1837     def props = new Properties()
1838     props.load(fis)
1839     eclipseVersion = props.getProperty("version")
1840     fis.close()
1841     assumedVersion = false
1842   }
1843   
1844   def propKey = "eclipse_debug"
1845   eclipseDebug = (project.hasProperty(propKey) && project.getProperty(propKey).equals("true"))
1846
1847   doFirst {
1848     // do not run a headless transpile when we claim to be in Eclipse
1849     if (IN_ECLIPSE) {
1850       println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
1851       throw new StopExecutionException("Not running headless transpile whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
1852     } else {
1853       println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
1854     }
1855
1856     if (!assumedVersion) {
1857       println("ECLIPSE VERSION=${eclipseVersion}")
1858     }
1859   }
1860 }
1861
1862
1863 task printProperties {
1864   group "Debug"
1865   description "Output to console all System.properties"
1866   doFirst {
1867     System.properties.each { key, val -> System.out.println("Property: ${key}=${val}") }
1868   }
1869 }
1870
1871
1872 task eclipseSetup {
1873   dependsOn eclipseProject
1874   dependsOn eclipseClasspath
1875   dependsOn eclipseJdt
1876 }
1877
1878
1879 // this version (type: Copy) will delete anything in the eclipse dropins folder that isn't in fromDropinsDir
1880 task jalviewjsEclipseCopyDropins(type: Copy) {
1881   dependsOn jalviewjsEclipsePaths
1882
1883   def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjs_eclipse_dropins_dir}", include: "*.jar")
1884   inputFiles += file("${jalviewDir}/${jalviewjsJ2sPlugin}")
1885   def outputDir = "${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_eclipse_tmp_dropins_dir}"
1886
1887   from inputFiles
1888   into outputDir
1889 }
1890
1891
1892 // this eclipse -clean doesn't actually work
1893 task jalviewjsCleanEclipse(type: Exec) {
1894   dependsOn eclipseSetup
1895   dependsOn jalviewjsEclipsePaths
1896   dependsOn jalviewjsEclipseCopyDropins
1897
1898   executable(eclipseBinary)
1899   args(["-nosplash", "--launcher.suppressErrors", "-data", eclipseWorkspace.getPath(), "-clean", "-console", "-consoleLog"])
1900   if (eclipseDebug) {
1901     args += "-debug"
1902   }
1903   args += "-l"
1904
1905   def inputString = """exit
1906 y
1907 """
1908   def inputByteStream = new ByteArrayInputStream(inputString.getBytes())
1909   standardInput = inputByteStream
1910 }
1911
1912 /* not really working yet
1913 jalviewjsEclipseCopyDropins.finalizedBy jalviewjsCleanEclipse
1914 */
1915
1916
1917 task jalviewjsTransferUnzipSwingJs {
1918   def file_zip = "${jalviewDir}/${jalviewjs_swingjs_zip}"
1919
1920   doLast {
1921     copy {
1922       from zipTree(file_zip)
1923       into "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}"
1924     }
1925   }
1926
1927   inputs.file file_zip
1928   outputs.dir "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}"
1929 }
1930
1931
1932 task jalviewjsTransferUnzipLib {
1933   def zipFiles = fileTree(dir: "${jalviewDir}/${jalviewjs_libjs_dir}", include: "*.zip")
1934
1935   doLast {
1936     zipFiles.each { file_zip -> 
1937       copy {
1938         from zipTree(file_zip)
1939         into "${jalviewDir}/${jalviewjsTransferSiteLibDir}"
1940       }
1941     }
1942   }
1943
1944   inputs.files zipFiles
1945   outputs.dir "${jalviewDir}/${jalviewjsTransferSiteLibDir}"
1946 }
1947
1948
1949 task jalviewjsTransferUnzipAllLibs {
1950   dependsOn jalviewjsTransferUnzipSwingJs
1951   dependsOn jalviewjsTransferUnzipLib
1952 }
1953
1954
1955 task jalviewjsCreateJ2sSettings(type: WriteProperties) {
1956   group "JalviewJS"
1957   description "Create the .j2s file from the j2s.* properties"
1958
1959   jalviewjsJ2sProps = project.properties.findAll { it.key.startsWith("j2s.") }.sort { it.key }
1960   def siteDirProperty = "j2s.site.directory"
1961   def setSiteDir = false
1962   jalviewjsJ2sProps.each { prop, val ->
1963     if (val != null) {
1964       if (prop == siteDirProperty) {
1965         if (!(val.startsWith('/') || val.startsWith("file://") )) {
1966           val = "${jalviewDir}/${jalviewjsTransferSiteJsDir}/${val}"
1967         }
1968         setSiteDir = true
1969       }
1970       property(prop,val)
1971     }
1972     if (!setSiteDir) { // default site location, don't override specifically set property
1973       property(siteDirProperty,"${jalviewDirRelativePath}/${jalviewjsTransferSiteJsDir}")
1974     }
1975   }
1976   outputFile = jalviewjsJ2sSettingsFileName
1977
1978   if (! IN_ECLIPSE) {
1979     inputs.properties(jalviewjsJ2sProps)
1980     outputs.file(jalviewjsJ2sSettingsFileName)
1981   }
1982 }
1983
1984
1985 task jalviewjsEclipseSetup {
1986   dependsOn jalviewjsEclipseCopyDropins
1987   dependsOn jalviewjsSetEclipseWorkspace
1988   dependsOn jalviewjsCreateJ2sSettings
1989 }
1990
1991
1992 task jalviewjsSyncAllLibs (type: Sync) {
1993   dependsOn jalviewjsTransferUnzipAllLibs
1994   def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjsTransferSiteLibDir}")
1995   inputFiles += fileTree(dir: "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}")
1996   def outputDir = "${jalviewDir}/${jalviewjsSiteDir}"
1997
1998   from inputFiles
1999   into outputDir
2000   def outputFiles = []
2001   rename { filename ->
2002     outputFiles += "${outputDir}/${filename}"
2003     null
2004   }
2005   preserve {
2006     include "**"
2007   }
2008   outputs.files outputFiles
2009   inputs.files inputFiles
2010 }
2011
2012
2013 task jalviewjsSyncResources (type: Sync) {
2014   def inputFiles = fileTree(dir: resourceDir)
2015   def outputDir = "${jalviewDir}/${jalviewjsSiteDir}/${jalviewjs_j2s_subdir}"
2016
2017   from inputFiles
2018   into outputDir
2019   def outputFiles = []
2020   rename { filename ->
2021     outputFiles += "${outputDir}/${filename}"
2022     null
2023   }
2024   preserve {
2025     include "**"
2026   }
2027   outputs.files outputFiles
2028   inputs.files inputFiles
2029 }
2030
2031
2032 task jalviewjsSyncSiteResources (type: Sync) {
2033   def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjs_site_resource_dir}")
2034   def outputDir = "${jalviewDir}/${jalviewjsSiteDir}"
2035
2036   from inputFiles
2037   into outputDir
2038   def outputFiles = []
2039   rename { filename ->
2040     outputFiles += "${outputDir}/${filename}"
2041     null
2042   }
2043   preserve {
2044     include "**"
2045   }
2046   outputs.files outputFiles
2047   inputs.files inputFiles
2048 }
2049
2050
2051 task jalviewjsSyncBuildProperties (type: Sync) {
2052   dependsOn createBuildProperties
2053   def inputFiles = [file(buildProperties)]
2054   def outputDir = "${jalviewDir}/${jalviewjsSiteDir}/${jalviewjs_j2s_subdir}"
2055
2056   from inputFiles
2057   into outputDir
2058   def outputFiles = []
2059   rename { filename ->
2060     outputFiles += "${outputDir}/${filename}"
2061     null
2062   }
2063   preserve {
2064     include "**"
2065   }
2066   outputs.files outputFiles
2067   inputs.files inputFiles
2068 }
2069
2070
2071 task jalviewjsProjectImport(type: Exec) {
2072   dependsOn eclipseSetup
2073   dependsOn jalviewjsEclipsePaths
2074   dependsOn jalviewjsEclipseSetup
2075
2076   doFirst {
2077     // do not run a headless import when we claim to be in Eclipse
2078     if (IN_ECLIPSE) {
2079       println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
2080       throw new StopExecutionException("Not running headless import whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
2081     } else {
2082       println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
2083     }
2084   }
2085
2086   //def projdir = eclipseWorkspace.getPath()+"/.metadata/.plugins/org.eclipse.core.resources/.projects/jalview/org.eclipse.jdt.core"
2087   def projdir = eclipseWorkspace.getPath()+"/.metadata/.plugins/org.eclipse.core.resources/.projects/jalview"
2088   executable(eclipseBinary)
2089   args(["-nosplash", "--launcher.suppressErrors", "-application", "com.seeq.eclipse.importprojects.headlessimport", "-data", eclipseWorkspace.getPath(), "-import", jalviewDirAbsolutePath])
2090   if (eclipseDebug) {
2091     args += "-debug"
2092   }
2093   args += [ "--launcher.appendVmargs", "-vmargs", "-Dorg.eclipse.equinox.p2.reconciler.dropins.directory=${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_eclipse_tmp_dropins_dir}" ]
2094   if (!IN_ECLIPSE) {
2095     args += [ "-D${j2sHeadlessBuildProperty}=true" ]
2096   }
2097
2098   inputs.file("${jalviewDir}/.project")
2099   outputs.upToDateWhen { 
2100     file(projdir).exists()
2101   }
2102 }
2103
2104
2105 task jalviewjsTranspile(type: Exec) {
2106   dependsOn jalviewjsEclipseSetup 
2107   dependsOn jalviewjsProjectImport
2108   dependsOn jalviewjsEclipsePaths
2109
2110   doFirst {
2111     // do not run a headless transpile when we claim to be in Eclipse
2112     if (IN_ECLIPSE) {
2113       println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
2114       throw new StopExecutionException("Not running headless transpile whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
2115     } else {
2116       println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
2117     }
2118   }
2119
2120   executable(eclipseBinary)
2121   args(["-nosplash", "--launcher.suppressErrors", "-application", "org.eclipse.jdt.apt.core.aptBuild", "-data", eclipseWorkspace, "-${jalviewjs_eclipse_build_arg}", eclipse_project_name ])
2122   if (eclipseDebug) {
2123     args += "-debug"
2124   }
2125   args += [ "--launcher.appendVmargs", "-vmargs", "-Dorg.eclipse.equinox.p2.reconciler.dropins.directory=${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_eclipse_tmp_dropins_dir}" ]
2126   if (!IN_ECLIPSE) {
2127     args += [ "-D${j2sHeadlessBuildProperty}=true" ]
2128   }
2129
2130   def stdout
2131   def stderr
2132   doFirst {
2133     stdout = new ByteArrayOutputStream()
2134     stderr = new ByteArrayOutputStream()
2135
2136     def logOutFileName = "${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}"
2137     def logOutFile = file(logOutFileName)
2138     logOutFile.createNewFile()
2139     logOutFile.text = """ROOT: ${jalviewjs_eclipse_root}
2140 BINARY: ${eclipseBinary}
2141 VERSION: ${eclipseVersion}
2142 WORKSPACE: ${eclipseWorkspace}
2143 DEBUG: ${eclipseDebug}
2144 ----
2145 """
2146     def logOutFOS = new FileOutputStream(logOutFile, true) // true == append
2147     // combine stdout and stderr
2148     def logErrFOS = logOutFOS
2149
2150     if (jalviewjs_j2s_to_console.equals("true")) {
2151       standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
2152         new org.apache.tools.ant.util.TeeOutputStream(
2153           logOutFOS,
2154           stdout),
2155         standardOutput)
2156       errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
2157         new org.apache.tools.ant.util.TeeOutputStream(
2158           logErrFOS,
2159           stderr),
2160         errorOutput)
2161     } else {
2162       standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
2163         logOutFOS,
2164         stdout)
2165       errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
2166         logErrFOS,
2167         stderr)
2168     }
2169   }
2170
2171   doLast {
2172     if (stdout.toString().contains("Error processing ")) {
2173       // j2s did not complete transpile
2174       //throw new TaskExecutionException("Error during transpilation:\n${stderr}\nSee eclipse transpile log file '${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}'")
2175       if (jalviewjs_ignore_transpile_errors.equals("true")) {
2176         println("IGNORING TRANSPILE ERRORS")
2177         println("See eclipse transpile log file '${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}'")
2178       } else {
2179         throw new GradleException("Error during transpilation:\n${stderr}\nSee eclipse transpile log file '${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}'")
2180       }
2181     }
2182   }
2183
2184   inputs.dir("${jalviewDir}/${sourceDir}")
2185   outputs.dir("${jalviewDir}/${jalviewjsTransferSiteJsDir}")
2186   outputs.upToDateWhen( { file("${jalviewDir}/${jalviewjsTransferSiteJsDir}${jalviewjs_server_resource}").exists() } )
2187 }
2188
2189
2190 def jalviewjsCallCore(String name, FileCollection list, String prefixFile, String suffixFile, String jsfile, String zjsfile, File logOutFile, Boolean logOutConsole) {
2191
2192   def stdout = new ByteArrayOutputStream()
2193   def stderr = new ByteArrayOutputStream()
2194
2195   def coreFile = file(jsfile)
2196   def msg = ""
2197   msg = "Creating core for ${name}...\nGenerating ${jsfile}"
2198   println(msg)
2199   logOutFile.createNewFile()
2200   logOutFile.append(msg+"\n")
2201
2202   def coreTop = file(prefixFile)
2203   def coreBottom = file(suffixFile)
2204   coreFile.getParentFile().mkdirs()
2205   coreFile.createNewFile()
2206   coreFile.write( coreTop.text )
2207   list.each {
2208     f ->
2209     if (f.exists()) {
2210       def t = f.text
2211       t.replaceAll("Clazz\\.([^_])","Clazz_${1}")
2212       coreFile.append( t )
2213     } else {
2214       msg = "...file '"+f.getPath()+"' does not exist, skipping"
2215       println(msg)
2216       logOutFile.append(msg+"\n")
2217     }
2218   }
2219   coreFile.append( coreBottom.text )
2220
2221   msg = "Generating ${zjsfile}"
2222   println(msg)
2223   logOutFile.append(msg+"\n")
2224   def logOutFOS = new FileOutputStream(logOutFile, true) // true == append
2225   def logErrFOS = logOutFOS
2226
2227   javaexec {
2228     classpath = files(["${jalviewDir}/tools/closure_compiler.jar"])
2229     args = [ "--js", jsfile, "--js_output_file", zjsfile ]
2230     maxHeapSize = "2g"
2231
2232     msg = "\nRunning '"+commandLine.join(' ')+"'\n"
2233     println(msg)
2234     logOutFile.append(msg+"\n")
2235
2236     if (logOutConsole) {
2237       standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
2238         new org.apache.tools.ant.util.TeeOutputStream(
2239           logOutFOS,
2240           stdout),
2241         standardOutput)
2242         errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
2243           new org.apache.tools.ant.util.TeeOutputStream(
2244             logErrFOS,
2245             stderr),
2246           errorOutput)
2247     } else {
2248       standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
2249         logOutFOS,
2250         stdout)
2251         errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
2252           logErrFOS,
2253           stderr)
2254     }
2255   }
2256   msg = "--"
2257   println(msg)
2258   logOutFile.append(msg+"\n")
2259 }
2260
2261
2262 task jalviewjsBuildAllCores {
2263   group "JalviewJS"
2264   description "Build the core js lib closures listed in the classlists dir"
2265   dependsOn jalviewjsTranspile
2266   dependsOn jalviewjsTransferUnzipSwingJs
2267
2268   def j2sDir = "${jalviewDir}/${jalviewjsTransferSiteJsDir}/${jalviewjs_j2s_subdir}"
2269   def swingJ2sDir = "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}/${jalviewjs_j2s_subdir}"
2270   def libJ2sDir = "${jalviewDir}/${jalviewjsTransferSiteLibDir}/${jalviewjs_j2s_subdir}"
2271   def jsDir = "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}/${jalviewjs_js_subdir}"
2272   def outputDir = "${jalviewDir}/${jalviewjsTransferSiteCoreDir}/${jalviewjs_j2s_subdir}/core"
2273   def prefixFile = "${jsDir}/core/coretop2.js"
2274   def suffixFile = "${jsDir}/core/corebottom2.js"
2275
2276   inputs.file prefixFile
2277   inputs.file suffixFile
2278
2279   def classlistFiles = []
2280   // add the classlists found int the jalviewjs_classlists_dir
2281   fileTree(dir: "${jalviewDir}/${jalviewjs_classlists_dir}", include: "*.txt").each {
2282     file ->
2283     def name = file.getName() - ".txt"
2284     classlistFiles += [
2285       'file': file,
2286       'name': name
2287     ]
2288   }
2289
2290   // _jmol and _jalview cores. Add any other peculiar classlist.txt files here
2291   //classlistFiles += [ 'file': file("${jalviewDir}/${jalviewjs_classlist_jmol}"), 'name': "_jvjmol" ]
2292   classlistFiles += [ 'file': file("${jalviewDir}/${jalviewjs_classlist_jalview}"), 'name': jalviewjsJalviewCoreName ]
2293
2294   jalviewjsCoreClasslists = []
2295
2296   classlistFiles.each {
2297     hash ->
2298
2299     def file = hash['file']
2300     if (! file.exists()) {
2301       //println("...classlist file '"+file.getPath()+"' does not exist, skipping")
2302       return false // this is a "continue" in groovy .each closure
2303     }
2304     def name = hash['name']
2305     if (name == null) {
2306       name = file.getName() - ".txt"
2307     }
2308
2309     def filelist = []
2310     file.eachLine {
2311       line ->
2312         filelist += line
2313     }
2314     def list = fileTree(dir: j2sDir, includes: filelist)
2315
2316     def jsfile = "${outputDir}/core${name}.js"
2317     def zjsfile = "${outputDir}/core${name}.z.js"
2318
2319     jalviewjsCoreClasslists += [
2320       'jsfile': jsfile,
2321       'zjsfile': zjsfile,
2322       'list': list,
2323       'name': name
2324     ]
2325
2326     inputs.file(file)
2327     inputs.files(list)
2328     outputs.file(jsfile)
2329     outputs.file(zjsfile)
2330   }
2331   
2332   // _stevesoft core. add any cores without a classlist here (and the inputs and outputs)
2333   def stevesoftClasslistName = "_stevesoft"
2334   def stevesoftClasslist = [
2335     'jsfile': "${outputDir}/core${stevesoftClasslistName}.js",
2336     'zjsfile': "${outputDir}/core${stevesoftClasslistName}.z.js",
2337     'list': fileTree(dir: j2sDir, include: "com/stevesoft/pat/**/*.js"),
2338     'name': stevesoftClasslistName
2339   ]
2340   jalviewjsCoreClasslists += stevesoftClasslist
2341   inputs.files(stevesoftClasslist['list'])
2342   outputs.file(stevesoftClasslist['jsfile'])
2343   outputs.file(stevesoftClasslist['zjsfile'])
2344
2345   // _all core
2346   def allClasslistName = "_all"
2347   def allJsFiles = fileTree(dir: j2sDir, include: "**/*.js")
2348   allJsFiles += fileTree(
2349     dir: libJ2sDir,
2350     include: "**/*.js",
2351     excludes: [
2352       // these exlusions are files that the closure-compiler produces errors for. Should fix them
2353       "**/org/jmol/jvxl/readers/IsoIntersectFileReader.js",
2354       "**/org/jmol/export/JSExporter.js"
2355     ]
2356   )
2357   allJsFiles += fileTree(
2358     dir: swingJ2sDir,
2359     include: "**/*.js",
2360     excludes: [
2361       // these exlusions are files that the closure-compiler produces errors for. Should fix them
2362       "**/sun/misc/Unsafe.js",
2363       "**/swingjs/jquery/jquery-editable-select.js",
2364       "**/swingjs/jquery/j2sComboBox.js",
2365       "**/sun/misc/FloatingDecimal.js"
2366     ]
2367   )
2368   def allClasslist = [
2369     'jsfile': "${outputDir}/core${allClasslistName}.js",
2370     'zjsfile': "${outputDir}/core${allClasslistName}.z.js",
2371     'list': allJsFiles,
2372     'name': allClasslistName
2373   ]
2374   // not including this version of "all" core at the moment
2375   //jalviewjsCoreClasslists += allClasslist
2376   inputs.files(allClasslist['list'])
2377   outputs.file(allClasslist['jsfile'])
2378   outputs.file(allClasslist['zjsfile'])
2379
2380   doFirst {
2381     def logOutFile = file("${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_j2s_closure_stdout}")
2382     logOutFile.getParentFile().mkdirs()
2383     logOutFile.createNewFile()
2384     logOutFile.write(getDate("yyyy-MM-dd HH:mm:ss")+" jalviewjsBuildAllCores\n----\n")
2385
2386     jalviewjsCoreClasslists.each {
2387       jalviewjsCallCore(it.name, it.list, prefixFile, suffixFile, it.jsfile, it.zjsfile, logOutFile, jalviewjs_j2s_to_console.equals("true"))
2388     }
2389   }
2390
2391 }
2392
2393
2394 def jalviewjsPublishCoreTemplate(String coreName, String templateName, File inputFile, String outputFile) {
2395   copy {
2396     from inputFile
2397     into file(outputFile).getParentFile()
2398     rename { filename ->
2399       if (filename.equals(inputFile.getName())) {
2400         return file(outputFile).getName()
2401       }
2402       return null
2403     }
2404     filter(ReplaceTokens,
2405       beginToken: '_',
2406       endToken: '_',
2407       tokens: [
2408         'MAIN': '"'+mainClass+'"',
2409         'CODE': "null",
2410         'NAME': jalviewjsJalviewTemplateName+" [core ${coreName}]",
2411         'COREKEY': jalviewjs_core_key,
2412         'CORENAME': coreName
2413       ]
2414     )
2415   }
2416 }
2417
2418
2419 task jalviewjsPublishCoreTemplates {
2420   dependsOn jalviewjsBuildAllCores
2421   def inputFileName = "${jalviewDir}/${j2s_coretemplate_html}"
2422   def inputFile = file(inputFileName)
2423   def outputDir = "${jalviewDir}/${jalviewjsTransferSiteCoreDir}"
2424
2425   def outputFiles = []
2426   jalviewjsCoreClasslists.each { cl ->
2427     def outputFile = "${outputDir}/${jalviewjsJalviewTemplateName}_${cl.name}.html"
2428     cl['outputfile'] = outputFile
2429     outputFiles += outputFile
2430   }
2431
2432   doFirst {
2433     jalviewjsCoreClasslists.each { cl ->
2434       jalviewjsPublishCoreTemplate(cl.name, jalviewjsJalviewTemplateName, inputFile, cl.outputfile)
2435     }
2436   }
2437   inputs.file(inputFile)
2438   outputs.files(outputFiles)
2439 }
2440
2441
2442 task jalviewjsSyncCore (type: Sync) {
2443   dependsOn jalviewjsBuildAllCores
2444   dependsOn jalviewjsPublishCoreTemplates
2445   def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjsTransferSiteCoreDir}")
2446   def outputDir = "${jalviewDir}/${jalviewjsSiteDir}"
2447
2448   from inputFiles
2449   into outputDir
2450   def outputFiles = []
2451   rename { filename ->
2452     outputFiles += "${outputDir}/${filename}"
2453     null
2454   }
2455   preserve {
2456     include "**"
2457   }
2458   outputs.files outputFiles
2459   inputs.files inputFiles
2460 }
2461
2462
2463 // this Copy version of TransferSiteJs will delete anything else in the target dir
2464 task jalviewjsCopyTransferSiteJs(type: Copy) {
2465   dependsOn jalviewjsTranspile
2466   from "${jalviewDir}/${jalviewjsTransferSiteJsDir}"
2467   into "${jalviewDir}/${jalviewjsSiteDir}"
2468 }
2469
2470
2471 // this Sync version of TransferSite is used by buildship to keep the website automatically up to date when a file changes
2472 task jalviewjsSyncTransferSiteJs(type: Sync) {
2473   from "${jalviewDir}/${jalviewjsTransferSiteJsDir}"
2474   include "**/*.*"
2475   into "${jalviewDir}/${jalviewjsSiteDir}"
2476   preserve {
2477     include "**"
2478   }
2479 }
2480
2481
2482 jalviewjsSyncAllLibs.mustRunAfter jalviewjsCopyTransferSiteJs
2483 jalviewjsSyncResources.mustRunAfter jalviewjsCopyTransferSiteJs
2484 jalviewjsSyncSiteResources.mustRunAfter jalviewjsCopyTransferSiteJs
2485 jalviewjsSyncBuildProperties.mustRunAfter jalviewjsCopyTransferSiteJs
2486
2487 jalviewjsSyncAllLibs.mustRunAfter jalviewjsSyncTransferSiteJs
2488 jalviewjsSyncResources.mustRunAfter jalviewjsSyncTransferSiteJs
2489 jalviewjsSyncSiteResources.mustRunAfter jalviewjsSyncTransferSiteJs
2490 jalviewjsSyncBuildProperties.mustRunAfter jalviewjsSyncTransferSiteJs
2491
2492
2493 task jalviewjsPrepareSite {
2494   group "JalviewJS"
2495   description "Prepares the website folder including unzipping files and copying resources"
2496   dependsOn jalviewjsSyncAllLibs
2497   dependsOn jalviewjsSyncResources
2498   dependsOn jalviewjsSyncSiteResources
2499   dependsOn jalviewjsSyncBuildProperties
2500   dependsOn jalviewjsSyncCore
2501 }
2502
2503
2504 task jalviewjsBuildSite {
2505   group "JalviewJS"
2506   description "Builds the whole website including transpiled code"
2507   dependsOn jalviewjsCopyTransferSiteJs
2508   dependsOn jalviewjsPrepareSite
2509 }
2510
2511
2512 task cleanJalviewjsTransferSite {
2513   doFirst {
2514     delete "${jalviewDir}/${jalviewjsTransferSiteJsDir}"
2515     delete "${jalviewDir}/${jalviewjsTransferSiteLibDir}"
2516     delete "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}"
2517     delete "${jalviewDir}/${jalviewjsTransferSiteCoreDir}"
2518   }
2519 }
2520
2521
2522 task cleanJalviewjsSite {
2523   dependsOn cleanJalviewjsTransferSite
2524   doFirst {
2525     delete "${jalviewDir}/${jalviewjsSiteDir}"
2526   }
2527 }
2528
2529
2530 task jalviewjsSiteTar(type: Tar) {
2531   group "JalviewJS"
2532   description "Creates a tar.gz file for the website"
2533   dependsOn jalviewjsBuildSite
2534   def outputFilename = "jalviewjs-site-${JALVIEW_VERSION}.tar.gz"
2535   try {
2536     archiveFileName = outputFilename
2537   } catch (Exception e) {
2538     archiveName = outputFilename
2539   }
2540
2541   compression Compression.GZIP
2542
2543   from "${jalviewDir}/${jalviewjsSiteDir}"
2544   into jalviewjs_site_dir // this is inside the tar file
2545
2546   inputs.dir("${jalviewDir}/${jalviewjsSiteDir}")
2547 }
2548
2549
2550 task jalviewjsServer {
2551   group "JalviewJS"
2552   def filename = "jalviewjsTest.html"
2553   description "Starts a webserver on localhost to test the website. See ${filename} to access local site on most recently used port."
2554   def htmlFile = "${jalviewDirAbsolutePath}/${filename}"
2555   doLast {
2556
2557     SimpleHttpFileServerFactory factory = new SimpleHttpFileServerFactory()
2558     def port = Integer.valueOf(jalviewjs_server_port)
2559     def start = port
2560     def running = false
2561     def url
2562     def jalviewjsServer
2563     while(port < start+1000 && !running) {
2564       try {
2565         def doc_root = new File("${jalviewDirAbsolutePath}/${jalviewjsSiteDir}")
2566         jalviewjsServer = factory.start(doc_root, port)
2567         running = true
2568         url = jalviewjsServer.getResourceUrl(jalviewjs_server_resource)
2569         println("SERVER STARTED with document root ${doc_root}.")
2570         println("Go to "+url+" . Run  gradle --stop  to stop (kills all gradle daemons).")
2571         println("For debug: "+url+"?j2sdebug")
2572         println("For verbose: "+url+"?j2sverbose")
2573       } catch (Exception e) {
2574         port++;
2575       }
2576     }
2577     def htmlText = """
2578       <p><a href="${url}">JalviewJS Test. &lt;${url}&gt;</a></p>
2579       <p><a href="${url}?j2sdebug">JalviewJS Test with debug. &lt;${url}?j2sdebug&gt;</a></p>
2580       <p><a href="${url}?j2sverbose">JalviewJS Test with verbose. &lt;${url}?j2sdebug&gt;</a></p>
2581       """
2582     jalviewjsCoreClasslists.each { cl ->
2583       def urlcore = jalviewjsServer.getResourceUrl(file(cl.outputfile).getName())
2584       htmlText += """
2585       <p><a href="${urlcore}">${jalviewjsJalviewTemplateName} [core ${cl.name}]. &lt;${urlcore}&gt;</a></p>
2586       """
2587       println("For core ${cl.name}: "+urlcore)
2588     }
2589
2590     file(htmlFile).text = htmlText
2591   }
2592
2593   outputs.file(htmlFile)
2594   outputs.upToDateWhen({false})
2595 }
2596
2597
2598 task cleanJalviewjsAll {
2599   group "JalviewJS"
2600   description "Delete all configuration and build artifacts to do with JalviewJS build"
2601   dependsOn cleanJalviewjsSite
2602   dependsOn jalviewjsEclipsePaths
2603   
2604   doFirst {
2605     delete "${jalviewDir}/${jalviewjsBuildDir}"
2606     delete "${jalviewDir}/${eclipse_bin_dir}"
2607     if (eclipseWorkspace != null && file(eclipseWorkspace.getAbsolutePath()+"/.metadata").exists()) {
2608       delete file(eclipseWorkspace.getAbsolutePath()+"/.metadata")
2609     }
2610     delete "${jalviewDir}/${jalviewjs_j2s_settings}"
2611   }
2612
2613   outputs.upToDateWhen( { false } )
2614 }
2615
2616
2617 task jalviewjsIDE_checkJ2sPlugin {
2618   group "00 JalviewJS in Eclipse"
2619   description "Compare the swingjs/net.sf.j2s.core(-j11)?.jar file with the Eclipse IDE's plugin version (found in the 'dropins' dir)"
2620
2621   doFirst {
2622     def j2sPlugin = string("${jalviewDir}/${jalviewjsJ2sPlugin}")
2623     def j2sPluginFile = file(j2sPlugin)
2624     def eclipseHome = System.properties["eclipse.home.location"]
2625     if (eclipseHome == null || ! IN_ECLIPSE) {
2626       throw new StopExecutionException("Cannot find running Eclipse home from System.properties['eclipse.home.location']. Skipping J2S Plugin Check.")
2627     }
2628     def eclipseJ2sPlugin = "${eclipseHome}/dropins/${j2sPluginFile.getName()}"
2629     def eclipseJ2sPluginFile = file(eclipseJ2sPlugin)
2630     if (!eclipseJ2sPluginFile.exists()) {
2631       def msg = "Eclipse J2S Plugin is not installed (could not find '${eclipseJ2sPlugin}')\nTry running task jalviewjsIDE_copyJ2sPlugin"
2632       System.err.println(msg)
2633       throw new StopExecutionException(msg)
2634     }
2635
2636     def digest = MessageDigest.getInstance("MD5")
2637
2638     digest.update(j2sPluginFile.text.bytes)
2639     def j2sPluginMd5 = new BigInteger(1, digest.digest()).toString(16).padLeft(32, '0')
2640
2641     digest.update(eclipseJ2sPluginFile.text.bytes)
2642     def eclipseJ2sPluginMd5 = new BigInteger(1, digest.digest()).toString(16).padLeft(32, '0')
2643      
2644     if (j2sPluginMd5 != eclipseJ2sPluginMd5) {
2645       def msg = "WARNING! Eclipse J2S Plugin '${eclipseJ2sPlugin}' is different to this commit's version '${j2sPlugin}'"
2646       System.err.println(msg)
2647       throw new StopExecutionException(msg)
2648     } else {
2649       def msg = "Eclipse J2S Plugin is the same as '${j2sPlugin}' (this is good)"
2650       println(msg)
2651     }
2652   }
2653 }
2654
2655 task jalviewjsIDE_copyJ2sPlugin {
2656   group "00 JalviewJS in Eclipse"
2657   description "Copy the swingjs/net.sf.j2s.core(-j11)?.jar file into the Eclipse IDE's 'dropins' dir"
2658
2659   doFirst {
2660     def j2sPlugin = string("${jalviewDir}/${jalviewjsJ2sPlugin}")
2661     def j2sPluginFile = file(j2sPlugin)
2662     def eclipseHome = System.properties["eclipse.home.location"]
2663     if (eclipseHome == null || ! IN_ECLIPSE) {
2664       throw new StopExecutionException("Cannot find running Eclipse home from System.properties['eclipse.home.location']. NOT copying J2S Plugin.")
2665     }
2666     def eclipseJ2sPlugin = "${eclipseHome}/dropins/${j2sPluginFile.getName()}"
2667     def eclipseJ2sPluginFile = file(eclipseJ2sPlugin)
2668     def msg = "WARNING! Copying this commit's j2s plugin '${j2sPlugin}' to Eclipse J2S Plugin '${eclipseJ2sPlugin}'\n* May require an Eclipse restart"
2669     System.err.println(msg)
2670     copy {
2671       from j2sPlugin
2672       eclipseJ2sPluginFile.getParentFile().mkdirs()
2673       into eclipseJ2sPluginFile.getParent()
2674     }
2675   }
2676 }
2677
2678
2679 task jalviewjsIDE_j2sFile {
2680   group "00 JalviewJS in Eclipse"
2681   description "Creates the .j2s file"
2682   dependsOn jalviewjsCreateJ2sSettings
2683 }
2684
2685
2686 task jalviewjsIDE_SyncCore {
2687   group "00 JalviewJS in Eclipse"
2688   description "Build the core js lib closures listed in the classlists dir and publish core html from template"
2689   dependsOn jalviewjsSyncCore
2690 }
2691
2692
2693 task jalviewjsIDE_SyncSiteAll {
2694   dependsOn jalviewjsSyncAllLibs
2695   dependsOn jalviewjsSyncResources
2696   dependsOn jalviewjsSyncSiteResources
2697   dependsOn jalviewjsSyncBuildProperties
2698 }
2699
2700
2701 cleanJalviewjsTransferSite.mustRunAfter jalviewjsIDE_SyncSiteAll
2702
2703
2704 task jalviewjsIDE_PrepareSite {
2705   group "00 JalviewJS in Eclipse"
2706   description "Sync libs and resources to site dir, but not closure cores"
2707
2708   dependsOn jalviewjsIDE_SyncSiteAll
2709   dependsOn cleanJalviewjsTransferSite
2710 }
2711
2712
2713 task jalviewjsIDE_AssembleSite {
2714   group "00 JalviewJS in Eclipse"
2715   description "Assembles unzipped supporting zipfiles, resources, site resources and closure cores into the Eclipse transpiled site"
2716   dependsOn jalviewjsPrepareSite
2717 }
2718
2719
2720 task jalviewjsIDE_SiteClean {
2721   group "00 JalviewJS in Eclipse"
2722   description "Deletes the Eclipse transpiled site"
2723   dependsOn cleanJalviewjsSite
2724 }
2725
2726
2727 task jalviewjsIDE_Server {
2728   group "00 JalviewJS in Eclipse"
2729   description "Starts a webserver on localhost to test the website"
2730   dependsOn jalviewjsServer
2731 }
2732
2733
2734 // buildship runs this at import or gradle refresh
2735 task eclipseSynchronizationTask {
2736   //dependsOn eclipseSetup
2737   dependsOn createBuildProperties
2738   if (J2S_ENABLED) {
2739     dependsOn jalviewjsIDE_j2sFile
2740     dependsOn jalviewjsIDE_checkJ2sPlugin
2741     dependsOn jalviewjsIDE_PrepareSite
2742   }
2743 }
2744
2745
2746 // buildship runs this at build time or project refresh
2747 task eclipseAutoBuildTask {
2748   //dependsOn jalviewjsIDE_checkJ2sPlugin
2749   //dependsOn jalviewjsIDE_PrepareSite
2750 }
2751
2752
2753 task jalviewjs {
2754   group "JalviewJS"
2755   description "Build the site"
2756   dependsOn jalviewjsBuildSite
2757 }