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