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