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