JAL-3633 Help documentation updated
[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   destinationDirectory = file("${jalviewDir}/${package_dir}")
1367   archiveFileName = rootProject.name+".jar"
1368
1369   exclude "cache*/**"
1370   exclude "*.jar"
1371   exclude "*.jar.*"
1372   exclude "**/*.jar"
1373   exclude "**/*.jar.*"
1374
1375   inputs.dir(sourceSets.main.java.outputDir)
1376   sourceSets.main.resources.srcDirs.each{ dir ->
1377     inputs.dir(dir)
1378   }
1379   outputs.file("${destinationDirectory}/${archiveFileName}")
1380 }
1381
1382
1383 task copyJars(type: Copy) {
1384   from fileTree(dir: classesDir, include: "**/*.jar").files
1385   into "${jalviewDir}/${package_dir}"
1386 }
1387
1388
1389 // doing a Sync instead of Copy as Copy doesn't deal with "outputs" very well
1390 task syncJars(type: Sync) {
1391   dependsOn jar
1392   from fileTree(dir: "${jalviewDir}/${libDistDir}", include: "**/*.jar").files
1393   into "${jalviewDir}/${package_dir}"
1394   preserve {
1395     include jar.archiveFileName.getOrNull()
1396   }
1397 }
1398
1399
1400 task makeDist {
1401   group = "build"
1402   description = "Put all required libraries in dist"
1403   // order of "cleanPackageDir", "copyJars", "jar" important!
1404   jar.mustRunAfter cleanPackageDir
1405   syncJars.mustRunAfter cleanPackageDir
1406   dependsOn cleanPackageDir
1407   dependsOn syncJars
1408   dependsOn jar
1409   outputs.dir("${jalviewDir}/${package_dir}")
1410 }
1411
1412
1413 task cleanDist {
1414   dependsOn cleanPackageDir
1415   dependsOn cleanTest
1416   dependsOn clean
1417 }
1418
1419
1420 shadowJar {
1421   group = "distribution"
1422   description = "Create a single jar file with all dependency libraries merged. Can be run with java -jar"
1423   if (buildDist) {
1424     dependsOn makeDist
1425   }
1426   from ("${jalviewDir}/${libDistDir}") {
1427     include("*.jar")
1428   }
1429   manifest {
1430     attributes "Implementation-Version": JALVIEW_VERSION,
1431     "Application-Name": install4jApplicationName
1432   }
1433   mainClassName = shadow_jar_main_class
1434   mergeServiceFiles()
1435   classifier = "all-"+JALVIEW_VERSION+"-j"+JAVA_VERSION
1436   minimize()
1437 }
1438
1439
1440 task getdownWebsite() {
1441   group = "distribution"
1442   description = "Create the getdown minimal app folder, and website folder for this version of jalview. Website folder also used for offline app installer"
1443   if (buildDist) {
1444     dependsOn makeDist
1445   }
1446
1447   def getdownWebsiteResourceFilenames = []
1448   def getdownTextString = ""
1449   def getdownResourceDir = getdownResourceDir
1450   def getdownResourceFilenames = []
1451
1452   doFirst {
1453     // clean the getdown website and files dir before creating getdown folders
1454     delete getdownWebsiteDir
1455     delete getdownFilesDir
1456
1457     copy {
1458       from buildProperties
1459       rename(build_properties_file, getdown_build_properties)
1460       into getdownAppDir
1461     }
1462     getdownWebsiteResourceFilenames += "${getdownAppDistDir}/${getdown_build_properties}"
1463
1464     // set some getdown_txt_ properties then go through all properties looking for getdown_txt_...
1465     def props = project.properties.sort { it.key }
1466     if (getdownAltJavaMinVersion != null && getdownAltJavaMinVersion.length() > 0) {
1467       props.put("getdown_txt_java_min_version", getdownAltJavaMinVersion)
1468     }
1469     if (getdownAltJavaMaxVersion != null && getdownAltJavaMaxVersion.length() > 0) {
1470       props.put("getdown_txt_java_max_version", getdownAltJavaMaxVersion)
1471     }
1472     if (getdownAltMultiJavaLocation != null && getdownAltMultiJavaLocation.length() > 0) {
1473       props.put("getdown_txt_multi_java_location", getdownAltMultiJavaLocation)
1474     }
1475
1476     props.put("getdown_txt_title", jalview_name)
1477     props.put("getdown_txt_ui.name", install4jApplicationName)
1478
1479     // start with appbase
1480     getdownTextString += "appbase = ${getdownAppBase}\n"
1481     props.each{ prop, val ->
1482       if (prop.startsWith("getdown_txt_") && val != null) {
1483         if (prop.startsWith("getdown_txt_multi_")) {
1484           def key = prop.substring(18)
1485           val.split(",").each{ v ->
1486             def line = "${key} = ${v}\n"
1487             getdownTextString += line
1488           }
1489         } else {
1490           // file values rationalised
1491           if (val.indexOf('/') > -1 || prop.startsWith("getdown_txt_resource")) {
1492             def r = null
1493             if (val.indexOf('/') == 0) {
1494               // absolute path
1495               r = file(val)
1496             } else if (val.indexOf('/') > 0) {
1497               // relative path (relative to jalviewDir)
1498               r = file( "${jalviewDir}/${val}" )
1499             }
1500             if (r.exists()) {
1501               val = "${getdown_resource_dir}/" + r.getName()
1502               getdownWebsiteResourceFilenames += val
1503               getdownResourceFilenames += r.getPath()
1504             }
1505           }
1506           if (! prop.startsWith("getdown_txt_resource")) {
1507             def line = prop.substring(12) + " = ${val}\n"
1508             getdownTextString += line
1509           }
1510         }
1511       }
1512     }
1513
1514     getdownWebsiteResourceFilenames.each{ filename ->
1515       getdownTextString += "resource = ${filename}\n"
1516     }
1517     getdownResourceFilenames.each{ filename ->
1518       copy {
1519         from filename
1520         into getdownResourceDir
1521       }
1522     }
1523
1524     def codeFiles = []
1525     fileTree(file(package_dir)).each{ f ->
1526       if (f.isDirectory()) {
1527         def files = fileTree(dir: f, include: ["*"]).getFiles()
1528         codeFiles += files
1529       } else if (f.exists()) {
1530         codeFiles += f
1531       }
1532     }
1533     codeFiles.sort().each{f ->
1534       def name = f.getName()
1535       def line = "code = ${getdownAppDistDir}/${name}\n"
1536       getdownTextString += line
1537       copy {
1538         from f.getPath()
1539         into getdownAppDir
1540       }
1541     }
1542
1543     // NOT USING MODULES YET, EVERYTHING SHOULD BE IN dist
1544     /*
1545     if (JAVA_VERSION.equals("11")) {
1546     def j11libFiles = fileTree(dir: "${jalviewDir}/${j11libDir}", include: ["*.jar"]).getFiles()
1547     j11libFiles.sort().each{f ->
1548     def name = f.getName()
1549     def line = "code = ${getdown_j11lib_dir}/${name}\n"
1550     getdownTextString += line
1551     copy {
1552     from f.getPath()
1553     into getdownJ11libDir
1554     }
1555     }
1556     }
1557      */
1558
1559     // 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.
1560     //getdownTextString += "class = " + file(getdownLauncher).getName() + "\n"
1561     getdownTextString += "resource = ${getdown_launcher_new}\n"
1562     getdownTextString += "class = ${main_class}\n"
1563
1564     def getdown_txt = file("${getdownWebsiteDir}/getdown.txt")
1565     getdown_txt.write(getdownTextString)
1566
1567     def getdownLaunchJvl = getdown_launch_jvl_name + ( (jvlChannelName != null && jvlChannelName.length() > 0)?"-${jvlChannelName}":"" ) + ".jvl"
1568     def launchJvl = file("${getdownWebsiteDir}/${getdownLaunchJvl}")
1569     launchJvl.write("appbase=${getdownAppBase}")
1570
1571     copy {
1572       from getdownLauncher
1573       rename(file(getdownLauncher).getName(), getdown_launcher_new)
1574       into getdownWebsiteDir
1575     }
1576
1577     copy {
1578       from getdownLauncher
1579       if (file(getdownLauncher).getName() != getdown_launcher) {
1580         rename(file(getdownLauncher).getName(), getdown_launcher)
1581       }
1582       into getdownWebsiteDir
1583     }
1584
1585     if (! (CHANNEL.startsWith("ARCHIVE") || CHANNEL.startsWith("DEVELOP"))) {
1586       copy {
1587         from getdown_txt
1588         from getdownLauncher
1589         from "${getdownWebsiteDir}/${getdown_build_properties}"
1590         if (file(getdownLauncher).getName() != getdown_launcher) {
1591           rename(file(getdownLauncher).getName(), getdown_launcher)
1592         }
1593         into getdownInstallDir
1594       }
1595
1596       copy {
1597         from getdownInstallDir
1598         into getdownFilesInstallDir
1599       }
1600     }
1601
1602     copy {
1603       from getdown_txt
1604       from launchJvl
1605       from getdownLauncher
1606       from "${getdownWebsiteDir}/${getdown_build_properties}"
1607       if (file(getdownLauncher).getName() != getdown_launcher) {
1608         rename(file(getdownLauncher).getName(), getdown_launcher)
1609       }
1610       into getdownFilesDir
1611     }
1612
1613     copy {
1614       from getdownResourceDir
1615       into "${getdownFilesDir}/${getdown_resource_dir}"
1616     }
1617   }
1618
1619   if (buildDist) {
1620     inputs.dir("${jalviewDir}/${package_dir}")
1621   }
1622   outputs.dir(getdownWebsiteDir)
1623   outputs.dir(getdownFilesDir)
1624 }
1625
1626
1627 // a helper task to allow getdown digest of any dir: `gradle getdownDigestDir -PDIGESTDIR=/path/to/my/random/getdown/dir
1628 task getdownDigestDir(type: JavaExec) {
1629   group "Help"
1630   description "A task to run a getdown Digest on a dir with getdown.txt. Provide a DIGESTDIR property via -PDIGESTDIR=..."
1631
1632   def digestDirPropertyName = "DIGESTDIR"
1633   doFirst {
1634     classpath = files(getdownLauncher)
1635     def digestDir = findProperty(digestDirPropertyName)
1636     if (digestDir == null) {
1637       throw new GradleException("Must provide a DIGESTDIR value to produce an alternative getdown digest")
1638     }
1639     args digestDir
1640   }
1641   main = "com.threerings.getdown.tools.Digester"
1642 }
1643
1644
1645 task getdownDigest(type: JavaExec) {
1646   group = "distribution"
1647   description = "Digest the getdown website folder"
1648   dependsOn getdownWebsite
1649   doFirst {
1650     classpath = files(getdownLauncher)
1651   }
1652   main = "com.threerings.getdown.tools.Digester"
1653   args getdownWebsiteDir
1654   inputs.dir(getdownWebsiteDir)
1655   outputs.file("${getdownWebsiteDir}/digest2.txt")
1656 }
1657
1658
1659 task getdown() {
1660   group = "distribution"
1661   description = "Create the minimal and full getdown app folder for installers and website and create digest file"
1662   dependsOn getdownDigest
1663   doLast {
1664     if (reportRsyncCommand) {
1665       def fromDir = getdownWebsiteDir + (getdownWebsiteDir.endsWith('/')?'':'/')
1666       def toDir = "${getdown_rsync_dest}/${getdownDir}" + (getdownDir.endsWith('/')?'':'/')
1667       println "LIKELY RSYNC COMMAND:"
1668       println "mkdir -p '$toDir'\nrsync -avh --delete '$fromDir' '$toDir'"
1669       if (RUNRSYNC == "true") {
1670         exec {
1671           commandLine "mkdir", "-p", toDir
1672         }
1673         exec {
1674           commandLine "rsync", "-avh", "--delete", fromDir, toDir
1675         }
1676       }
1677     }
1678   }
1679 }
1680
1681
1682 tasks.withType(JavaCompile) {
1683         options.encoding = 'UTF-8'
1684 }
1685
1686
1687 clean {
1688   doFirst {
1689     delete getdownWebsiteDir
1690     delete getdownFilesDir
1691   }
1692 }
1693
1694
1695 install4j {
1696   if (file(install4jHomeDir).exists()) {
1697     // good to go!
1698   } else if (file(System.getProperty("user.home")+"/buildtools/install4j").exists()) {
1699     install4jHomeDir = System.getProperty("user.home")+"/buildtools/install4j"
1700   } else if (file("/Applications/install4j.app/Contents/Resources/app").exists()) {
1701     install4jHomeDir = "/Applications/install4j.app/Contents/Resources/app"
1702   }
1703   installDir(file(install4jHomeDir))
1704
1705   mediaTypes = Arrays.asList(install4j_media_types.split(","))
1706 }
1707
1708
1709 task copyInstall4jTemplate {
1710   def install4jTemplateFile = file("${install4jDir}/${install4j_template}")
1711   def install4jFileAssociationsFile = file("${install4jDir}/${install4j_installer_file_associations}")
1712   inputs.file(install4jTemplateFile)
1713   inputs.file(install4jFileAssociationsFile)
1714   inputs.property("CHANNEL", { CHANNEL })
1715   outputs.file(install4jConfFile)
1716
1717   doLast {
1718     def install4jConfigXml = new XmlParser().parse(install4jTemplateFile)
1719
1720     // turn off code signing if no OSX_KEYPASS
1721     if (OSX_KEYPASS == "") {
1722       install4jConfigXml.'**'.codeSigning.each { codeSigning ->
1723         codeSigning.'@macEnabled' = "false"
1724       }
1725       install4jConfigXml.'**'.windows.each { windows ->
1726         windows.'@runPostProcessor' = "false"
1727       }
1728     }
1729
1730     // turn off checksum creation for LOCAL channel
1731     def e = install4jConfigXml.application[0]
1732     if (CHANNEL == "LOCAL") {
1733       e.'@createChecksums' = "false"
1734     } else {
1735       e.'@createChecksums' = "true"
1736     }
1737
1738     // put file association actions where placeholder action is
1739     def install4jFileAssociationsText = install4jFileAssociationsFile.text
1740     def fileAssociationActions = new XmlParser().parseText("<actions>${install4jFileAssociationsText}</actions>")
1741     install4jConfigXml.'**'.action.any { a -> // .any{} stops after the first one that returns true
1742       if (a.'@name' == 'EXTENSIONS_REPLACED_BY_GRADLE') {
1743         def parent = a.parent()
1744         parent.remove(a)
1745         fileAssociationActions.each { faa ->
1746             parent.append(faa)
1747         }
1748         // don't need to continue in .any loop once replacements have been made
1749         return true
1750       }
1751     }
1752
1753     // use Windows Program Group with Examples folder for RELEASE, and Program Group without Examples for everything else
1754     // NB we're deleting the /other/ one!
1755     // Also remove the examples subdir from non-release versions
1756     def customizedIdToDelete = "PROGRAM_GROUP_RELEASE"
1757     // 2.11.1.0 NOT releasing with the Examples folder in the Program Group
1758     if (false && CHANNEL=="RELEASE") { // remove 'false && ' to include Examples folder in RELEASE channel
1759       customizedIdToDelete = "PROGRAM_GROUP_NON_RELEASE"
1760     } else {
1761       // remove the examples subdir from Full File Set
1762       def files = install4jConfigXml.files[0]
1763       def fileset = files.filesets.fileset.find { fs -> fs.'@customizedId' == "FULL_FILE_SET" }
1764       def root = files.roots.root.find { r -> r.'@fileset' == fileset.'@id' }
1765       def mountPoint = files.mountPoints.mountPoint.find { mp -> mp.'@root' == root.'@id' }
1766       def dirEntry = files.entries.dirEntry.find { de -> de.'@mountPoint' == mountPoint.'@id' && de.'@subDirectory' == "examples" }
1767       dirEntry.parent().remove(dirEntry)
1768     }
1769     install4jConfigXml.'**'.action.any { a ->
1770       if (a.'@customizedId' == customizedIdToDelete) {
1771         def parent = a.parent()
1772         parent.remove(a)
1773         return true
1774       }
1775     }
1776
1777     // remove the "Uninstall Old Jalview (optional)" symlink from DMG for non-release DS_Stores
1778     if (! (CHANNEL == "RELEASE" || CHANNEL == "TEST-RELEASE" ) ) {
1779       def symlink = install4jConfigXml.'**'.topLevelFiles.symlink.find { sl -> sl.'@name' == "Uninstall Old Jalview (optional).app" }
1780       symlink.parent().remove(symlink)
1781     }
1782
1783     // write install4j file
1784     install4jConfFile.text = XmlUtil.serialize(install4jConfigXml)
1785   }
1786 }
1787
1788
1789 clean {
1790   doFirst {
1791     delete install4jConfFile
1792   }
1793 }
1794
1795
1796 task installers(type: com.install4j.gradle.Install4jTask) {
1797   group = "distribution"
1798   description = "Create the install4j installers"
1799   dependsOn getdown
1800   dependsOn copyInstall4jTemplate
1801
1802   projectFile = install4jConfFile
1803
1804   // create an md5 for the input files to use as version for install4j conf file
1805   def digest = MessageDigest.getInstance("MD5")
1806   digest.update(
1807     (file("${install4jDir}/${install4j_template}").text + 
1808     file("${install4jDir}/${install4j_info_plist_file_associations}").text +
1809     file("${install4jDir}/${install4j_installer_file_associations}").text).bytes)
1810   def filesMd5 = new BigInteger(1, digest.digest()).toString(16)
1811   if (filesMd5.length() >= 8) {
1812     filesMd5 = filesMd5.substring(0,8)
1813   }
1814   def install4jTemplateVersion = "${JALVIEW_VERSION}_F${filesMd5}_C${gitHash}"
1815   // make install4jBuildDir relative to jalviewDir
1816   def install4jBuildDir = "${install4j_build_dir}/${JAVA_VERSION}"
1817
1818   variables = [
1819     'JALVIEW_NAME': jalview_name,
1820     'JALVIEW_APPLICATION_NAME': install4jApplicationName,
1821     'JALVIEW_DIR': "../..",
1822     'OSX_KEYSTORE': OSX_KEYSTORE,
1823     'JSIGN_SH': JSIGN_SH,
1824     'JRE_DIR': getdown_app_dir_java,
1825     'INSTALLER_TEMPLATE_VERSION': install4jTemplateVersion,
1826     'JALVIEW_VERSION': JALVIEW_VERSION,
1827     'JAVA_MIN_VERSION': JAVA_MIN_VERSION,
1828     'JAVA_MAX_VERSION': JAVA_MAX_VERSION,
1829     'JAVA_VERSION': JAVA_VERSION,
1830     'JAVA_INTEGER_VERSION': JAVA_INTEGER_VERSION,
1831     'VERSION': JALVIEW_VERSION,
1832     'MACOS_JAVA_VM_DIR': macosJavaVMDir,
1833     'WINDOWS_JAVA_VM_DIR': windowsJavaVMDir,
1834     'LINUX_JAVA_VM_DIR': linuxJavaVMDir,
1835     'MACOS_JAVA_VM_TGZ': macosJavaVMTgz,
1836     'WINDOWS_JAVA_VM_TGZ': windowsJavaVMTgz,
1837     'LINUX_JAVA_VM_TGZ': linuxJavaVMTgz,
1838     'COPYRIGHT_MESSAGE': install4j_copyright_message,
1839     'BUNDLE_ID': install4jBundleId,
1840     'INTERNAL_ID': install4jInternalId,
1841     'WINDOWS_APPLICATION_ID': install4jWinApplicationId,
1842     'MACOS_DS_STORE': install4jDSStore,
1843     'MACOS_DMG_BG_IMAGE': install4jDMGBackgroundImage,
1844     'INSTALLER_NAME': install4jInstallerName,
1845     'INSTALL4J_UTILS_DIR': install4j_utils_dir,
1846     'GETDOWN_WEBSITE_DIR': getdown_website_dir,
1847     'GETDOWN_FILES_DIR': getdown_files_dir,
1848     'GETDOWN_RESOURCE_DIR': getdown_resource_dir,
1849     'GETDOWN_DIST_DIR': getdownAppDistDir,
1850     'GETDOWN_ALT_DIR': getdown_app_dir_alt,
1851     'GETDOWN_INSTALL_DIR': getdown_install_dir,
1852     'INFO_PLIST_FILE_ASSOCIATIONS_FILE': install4j_info_plist_file_associations,
1853     'BUILD_DIR': install4jBuildDir,
1854     'APPLICATION_CATEGORIES': install4j_application_categories,
1855     'APPLICATION_FOLDER': install4jApplicationFolder,
1856     'UNIX_APPLICATION_FOLDER': install4jUnixApplicationFolder,
1857     'EXECUTABLE_NAME': install4jExecutableName,
1858     'EXTRA_SCHEME': install4jExtraScheme,
1859   ]
1860
1861   //println("INSTALL4J VARIABLES:")
1862   //variables.each{k,v->println("${k}=${v}")}
1863
1864   destination = "${jalviewDir}/${install4jBuildDir}"
1865   buildSelected = true
1866
1867   if (install4j_faster.equals("true") || CHANNEL.startsWith("LOCAL")) {
1868     faster = true
1869     disableSigning = true
1870   }
1871
1872   if (OSX_KEYPASS) {
1873     macKeystorePassword = OSX_KEYPASS
1874   }
1875
1876   doFirst {
1877     println("Using projectFile "+projectFile)
1878   }
1879
1880   inputs.dir(getdownWebsiteDir)
1881   inputs.file(install4jConfFile)
1882   inputs.file("${install4jDir}/${install4j_info_plist_file_associations}")
1883   inputs.dir(macosJavaVMDir)
1884   inputs.dir(windowsJavaVMDir)
1885   outputs.dir("${jalviewDir}/${install4j_build_dir}/${JAVA_VERSION}")
1886 }
1887
1888
1889 spotless {
1890   java {
1891     eclipse().configFile(eclipse_codestyle_file)
1892   }
1893 }
1894
1895
1896 task sourceDist(type: Tar) {
1897   group "distribution"
1898   description "Create a source .tar.gz file for distribution"
1899   
1900   dependsOn convertMdFiles
1901
1902   def VERSION_UNDERSCORES = JALVIEW_VERSION.replaceAll("\\.", "_")
1903   def outputFileName = "${project.name}_${VERSION_UNDERSCORES}.tar.gz"
1904   archiveFileName = outputFileName
1905   
1906   compression Compression.GZIP
1907   
1908   into project.name
1909
1910   def EXCLUDE_FILES=[
1911     "build/*",
1912     "bin/*",
1913     "test-output/",
1914     "test-reports",
1915     "tests",
1916     "clover*/*",
1917     ".*",
1918     "benchmarking/*",
1919     "**/.*",
1920     "*.class",
1921     "**/*.class","$j11modDir/**/*.jar","appletlib","**/*locales",
1922     "*locales/**",
1923     "utils/InstallAnywhere",
1924     "**/*.log",
1925   ] 
1926   def PROCESS_FILES=[
1927     "AUTHORS",
1928     "CITATION",
1929     "FEATURETODO",
1930     "JAVA-11-README",
1931     "FEATURETODO",
1932     "LICENSE",
1933     "**/README",
1934     "RELEASE",
1935     "THIRDPARTYLIBS",
1936     "TESTNG",
1937     "build.gradle",
1938     "gradle.properties",
1939     "**/*.java",
1940     "**/*.html",
1941     "**/*.xml",
1942     "**/*.gradle",
1943     "**/*.groovy",
1944     "**/*.properties",
1945     "**/*.perl",
1946     "**/*.sh",
1947   ]
1948   def INCLUDE_FILES=[
1949     ".settings/org.eclipse.jdt.core.jalview.prefs",
1950   ]
1951
1952   from(jalviewDir) {
1953     exclude (EXCLUDE_FILES)
1954     include (PROCESS_FILES)
1955     filter(ReplaceTokens,
1956       beginToken: '$$',
1957       endToken: '$$',
1958       tokens: [
1959         'Version-Rel': JALVIEW_VERSION,
1960         'Year-Rel': getDate("yyyy")
1961       ]
1962     )
1963   }
1964   from(jalviewDir) {
1965     exclude (EXCLUDE_FILES)
1966     exclude (PROCESS_FILES)
1967     exclude ("appletlib")
1968     exclude ("**/*locales")
1969     exclude ("*locales/**")
1970     exclude ("utils/InstallAnywhere")
1971
1972     exclude (getdown_files_dir)
1973     exclude (getdown_website_dir)
1974
1975     // exluding these as not using jars as modules yet
1976     exclude ("${j11modDir}/**/*.jar")
1977   }
1978   from(jalviewDir) {
1979     include(INCLUDE_FILES)
1980   }
1981 //  from (jalviewDir) {
1982 //    // explicit includes for stuff that seemed to not get included
1983 //    include(fileTree("test/**/*."))
1984 //    exclude(EXCLUDE_FILES)
1985 //    exclude(PROCESS_FILES)
1986 //  }
1987 }
1988
1989
1990 task helppages {
1991   dependsOn copyHelp
1992   dependsOn pubhtmlhelp
1993   
1994   inputs.dir("${helpBuildDir}/${help_dir}")
1995   outputs.dir("${buildDir}/distributions/${help_dir}")
1996 }
1997
1998
1999 task j2sSetHeadlessBuild {
2000   doFirst {
2001     IN_ECLIPSE = false
2002   }
2003 }
2004
2005
2006 task jalviewjsSetEclipseWorkspace {
2007   def propKey = "jalviewjs_eclipse_workspace"
2008   def propVal = null
2009   if (project.hasProperty(propKey)) {
2010     propVal = project.getProperty(propKey)
2011     if (propVal.startsWith("~/")) {
2012       propVal = System.getProperty("user.home") + propVal.substring(1)
2013     }
2014   }
2015   def propsFileName = "${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_eclipse_workspace_location_file}"
2016   def propsFile = file(propsFileName)
2017   def eclipseWsDir = propVal
2018   def props = new Properties()
2019
2020   def writeProps = true
2021   if (( eclipseWsDir == null || !file(eclipseWsDir).exists() ) && propsFile.exists()) {
2022     def ins = new FileInputStream(propsFileName)
2023     props.load(ins)
2024     ins.close()
2025     if (props.getProperty(propKey, null) != null) {
2026       eclipseWsDir = props.getProperty(propKey)
2027       writeProps = false
2028     }
2029   }
2030
2031   if (eclipseWsDir == null || !file(eclipseWsDir).exists()) {
2032     def tempDir = File.createTempDir()
2033     eclipseWsDir = tempDir.getAbsolutePath()
2034     writeProps = true
2035   }
2036   eclipseWorkspace = file(eclipseWsDir)
2037
2038   doFirst {
2039     // do not run a headless transpile when we claim to be in Eclipse
2040     if (IN_ECLIPSE) {
2041       println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
2042       throw new StopExecutionException("Not running headless transpile whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
2043     } else {
2044       println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
2045     }
2046
2047     if (writeProps) {
2048       props.setProperty(propKey, eclipseWsDir)
2049       propsFile.parentFile.mkdirs()
2050       def bytes = new ByteArrayOutputStream()
2051       props.store(bytes, null)
2052       def propertiesString = bytes.toString()
2053       propsFile.text = propertiesString
2054       print("NEW ")
2055     } else {
2056       print("EXISTING ")
2057     }
2058
2059     println("ECLIPSE WORKSPACE: "+eclipseWorkspace.getPath())
2060   }
2061
2062   //inputs.property(propKey, eclipseWsDir) // eclipseWsDir only gets set once this task runs, so will be out-of-date
2063   outputs.file(propsFileName)
2064   outputs.upToDateWhen { eclipseWorkspace.exists() && propsFile.exists() }
2065 }
2066
2067
2068 task jalviewjsEclipsePaths {
2069   def eclipseProduct
2070
2071   def eclipseRoot = jalviewjs_eclipse_root
2072   if (eclipseRoot.startsWith("~/")) {
2073     eclipseRoot = System.getProperty("user.home") + eclipseRoot.substring(1)
2074   }
2075   if (OperatingSystem.current().isMacOsX()) {
2076     eclipseRoot += "/Eclipse.app"
2077     eclipseBinary = "${eclipseRoot}/Contents/MacOS/eclipse"
2078     eclipseProduct = "${eclipseRoot}/Contents/Eclipse/.eclipseproduct"
2079   } else if (OperatingSystem.current().isWindows()) { // check these paths!!
2080     if (file("${eclipseRoot}/eclipse").isDirectory() && file("${eclipseRoot}/eclipse/.eclipseproduct").exists()) {
2081       eclipseRoot += "/eclipse"
2082     }
2083     eclipseBinary = "${eclipseRoot}/eclipse.exe"
2084     eclipseProduct = "${eclipseRoot}/.eclipseproduct"
2085   } else { // linux or unix
2086     if (file("${eclipseRoot}/eclipse").isDirectory() && file("${eclipseRoot}/eclipse/.eclipseproduct").exists()) {
2087       eclipseRoot += "/eclipse"
2088 println("eclipseDir exists")
2089     }
2090     eclipseBinary = "${eclipseRoot}/eclipse"
2091     eclipseProduct = "${eclipseRoot}/.eclipseproduct"
2092   }
2093
2094   eclipseVersion = "4.13" // default
2095   def assumedVersion = true
2096   if (file(eclipseProduct).exists()) {
2097     def fis = new FileInputStream(eclipseProduct)
2098     def props = new Properties()
2099     props.load(fis)
2100     eclipseVersion = props.getProperty("version")
2101     fis.close()
2102     assumedVersion = false
2103   }
2104   
2105   def propKey = "eclipse_debug"
2106   eclipseDebug = (project.hasProperty(propKey) && project.getProperty(propKey).equals("true"))
2107
2108   doFirst {
2109     // do not run a headless transpile when we claim to be in Eclipse
2110     if (IN_ECLIPSE) {
2111       println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
2112       throw new StopExecutionException("Not running headless transpile whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
2113     } else {
2114       println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
2115     }
2116
2117     if (!assumedVersion) {
2118       println("ECLIPSE VERSION=${eclipseVersion}")
2119     }
2120   }
2121 }
2122
2123
2124 task printProperties {
2125   group "Debug"
2126   description "Output to console all System.properties"
2127   doFirst {
2128     System.properties.each { key, val -> System.out.println("Property: ${key}=${val}") }
2129   }
2130 }
2131
2132
2133 task eclipseSetup {
2134   dependsOn eclipseProject
2135   dependsOn eclipseClasspath
2136   dependsOn eclipseJdt
2137 }
2138
2139
2140 // this version (type: Copy) will delete anything in the eclipse dropins folder that isn't in fromDropinsDir
2141 task jalviewjsEclipseCopyDropins(type: Copy) {
2142   dependsOn jalviewjsEclipsePaths
2143
2144   def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjs_eclipse_dropins_dir}", include: "*.jar")
2145   inputFiles += file("${jalviewDir}/${jalviewjsJ2sPlugin}")
2146   def outputDir = "${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_eclipse_tmp_dropins_dir}"
2147
2148   from inputFiles
2149   into outputDir
2150 }
2151
2152
2153 // this eclipse -clean doesn't actually work
2154 task jalviewjsCleanEclipse(type: Exec) {
2155   dependsOn eclipseSetup
2156   dependsOn jalviewjsEclipsePaths
2157   dependsOn jalviewjsEclipseCopyDropins
2158
2159   executable(eclipseBinary)
2160   args(["-nosplash", "--launcher.suppressErrors", "-data", eclipseWorkspace.getPath(), "-clean", "-console", "-consoleLog"])
2161   if (eclipseDebug) {
2162     args += "-debug"
2163   }
2164   args += "-l"
2165
2166   def inputString = """exit
2167 y
2168 """
2169   def inputByteStream = new ByteArrayInputStream(inputString.getBytes())
2170   standardInput = inputByteStream
2171 }
2172
2173 /* not really working yet
2174 jalviewjsEclipseCopyDropins.finalizedBy jalviewjsCleanEclipse
2175 */
2176
2177
2178 task jalviewjsTransferUnzipSwingJs {
2179   def file_zip = "${jalviewDir}/${jalviewjs_swingjs_zip}"
2180
2181   doLast {
2182     copy {
2183       from zipTree(file_zip)
2184       into "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}"
2185     }
2186   }
2187
2188   inputs.file file_zip
2189   outputs.dir "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}"
2190 }
2191
2192
2193 task jalviewjsTransferUnzipLib {
2194   def zipFiles = fileTree(dir: "${jalviewDir}/${jalviewjs_libjs_dir}", include: "*.zip")
2195
2196   doLast {
2197     zipFiles.each { file_zip -> 
2198       copy {
2199         from zipTree(file_zip)
2200         into "${jalviewDir}/${jalviewjsTransferSiteLibDir}"
2201       }
2202     }
2203   }
2204
2205   inputs.files zipFiles
2206   outputs.dir "${jalviewDir}/${jalviewjsTransferSiteLibDir}"
2207 }
2208
2209
2210 task jalviewjsTransferUnzipAllLibs {
2211   dependsOn jalviewjsTransferUnzipSwingJs
2212   dependsOn jalviewjsTransferUnzipLib
2213 }
2214
2215
2216 task jalviewjsCreateJ2sSettings(type: WriteProperties) {
2217   group "JalviewJS"
2218   description "Create the .j2s file from the j2s.* properties"
2219
2220   jalviewjsJ2sProps = project.properties.findAll { it.key.startsWith("j2s.") }.sort { it.key }
2221   def siteDirProperty = "j2s.site.directory"
2222   def setSiteDir = false
2223   jalviewjsJ2sProps.each { prop, val ->
2224     if (val != null) {
2225       if (prop == siteDirProperty) {
2226         if (!(val.startsWith('/') || val.startsWith("file://") )) {
2227           val = "${jalviewDir}/${jalviewjsTransferSiteJsDir}/${val}"
2228         }
2229         setSiteDir = true
2230       }
2231       property(prop,val)
2232     }
2233     if (!setSiteDir) { // default site location, don't override specifically set property
2234       property(siteDirProperty,"${jalviewDirRelativePath}/${jalviewjsTransferSiteJsDir}")
2235     }
2236   }
2237   outputFile = jalviewjsJ2sSettingsFileName
2238
2239   if (! IN_ECLIPSE) {
2240     inputs.properties(jalviewjsJ2sProps)
2241     outputs.file(jalviewjsJ2sSettingsFileName)
2242   }
2243 }
2244
2245
2246 task jalviewjsEclipseSetup {
2247   dependsOn jalviewjsEclipseCopyDropins
2248   dependsOn jalviewjsSetEclipseWorkspace
2249   dependsOn jalviewjsCreateJ2sSettings
2250 }
2251
2252
2253 task jalviewjsSyncAllLibs (type: Sync) {
2254   dependsOn jalviewjsTransferUnzipAllLibs
2255   def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjsTransferSiteLibDir}")
2256   inputFiles += fileTree(dir: "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}")
2257   def outputDir = "${jalviewDir}/${jalviewjsSiteDir}"
2258
2259   from inputFiles
2260   into outputDir
2261   def outputFiles = []
2262   rename { filename ->
2263     outputFiles += "${outputDir}/${filename}"
2264     null
2265   }
2266   preserve {
2267     include "**"
2268   }
2269   outputs.files outputFiles
2270   inputs.files inputFiles
2271 }
2272
2273
2274 task jalviewjsSyncResources (type: Sync) {
2275   def inputFiles = fileTree(dir: resourceDir)
2276   def outputDir = "${jalviewDir}/${jalviewjsSiteDir}/${jalviewjs_j2s_subdir}"
2277
2278   from inputFiles
2279   into outputDir
2280   def outputFiles = []
2281   rename { filename ->
2282     outputFiles += "${outputDir}/${filename}"
2283     null
2284   }
2285   preserve {
2286     include "**"
2287   }
2288   outputs.files outputFiles
2289   inputs.files inputFiles
2290 }
2291
2292
2293 task jalviewjsSyncSiteResources (type: Sync) {
2294   def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjs_site_resource_dir}")
2295   def outputDir = "${jalviewDir}/${jalviewjsSiteDir}"
2296
2297   from inputFiles
2298   into outputDir
2299   def outputFiles = []
2300   rename { filename ->
2301     outputFiles += "${outputDir}/${filename}"
2302     null
2303   }
2304   preserve {
2305     include "**"
2306   }
2307   outputs.files outputFiles
2308   inputs.files inputFiles
2309 }
2310
2311
2312 task jalviewjsSyncBuildProperties (type: Sync) {
2313   dependsOn createBuildProperties
2314   def inputFiles = [file(buildProperties)]
2315   def outputDir = "${jalviewDir}/${jalviewjsSiteDir}/${jalviewjs_j2s_subdir}"
2316
2317   from inputFiles
2318   into outputDir
2319   def outputFiles = []
2320   rename { filename ->
2321     outputFiles += "${outputDir}/${filename}"
2322     null
2323   }
2324   preserve {
2325     include "**"
2326   }
2327   outputs.files outputFiles
2328   inputs.files inputFiles
2329 }
2330
2331
2332 task jalviewjsProjectImport(type: Exec) {
2333   dependsOn eclipseSetup
2334   dependsOn jalviewjsEclipsePaths
2335   dependsOn jalviewjsEclipseSetup
2336
2337   doFirst {
2338     // do not run a headless import when we claim to be in Eclipse
2339     if (IN_ECLIPSE) {
2340       println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
2341       throw new StopExecutionException("Not running headless import whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
2342     } else {
2343       println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
2344     }
2345   }
2346
2347   //def projdir = eclipseWorkspace.getPath()+"/.metadata/.plugins/org.eclipse.core.resources/.projects/jalview/org.eclipse.jdt.core"
2348   def projdir = eclipseWorkspace.getPath()+"/.metadata/.plugins/org.eclipse.core.resources/.projects/jalview"
2349   executable(eclipseBinary)
2350   args(["-nosplash", "--launcher.suppressErrors", "-application", "com.seeq.eclipse.importprojects.headlessimport", "-data", eclipseWorkspace.getPath(), "-import", jalviewDirAbsolutePath])
2351   if (eclipseDebug) {
2352     args += "-debug"
2353   }
2354   args += [ "--launcher.appendVmargs", "-vmargs", "-Dorg.eclipse.equinox.p2.reconciler.dropins.directory=${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_eclipse_tmp_dropins_dir}" ]
2355   if (!IN_ECLIPSE) {
2356     args += [ "-D${j2sHeadlessBuildProperty}=true" ]
2357   }
2358
2359   inputs.file("${jalviewDir}/.project")
2360   outputs.upToDateWhen { 
2361     file(projdir).exists()
2362   }
2363 }
2364
2365
2366 task jalviewjsTranspile(type: Exec) {
2367   dependsOn jalviewjsEclipseSetup 
2368   dependsOn jalviewjsProjectImport
2369   dependsOn jalviewjsEclipsePaths
2370
2371   doFirst {
2372     // do not run a headless transpile when we claim to be in Eclipse
2373     if (IN_ECLIPSE) {
2374       println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
2375       throw new StopExecutionException("Not running headless transpile whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
2376     } else {
2377       println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
2378     }
2379   }
2380
2381   executable(eclipseBinary)
2382   args(["-nosplash", "--launcher.suppressErrors", "-application", "org.eclipse.jdt.apt.core.aptBuild", "-data", eclipseWorkspace, "-${jalviewjs_eclipse_build_arg}", eclipse_project_name ])
2383   if (eclipseDebug) {
2384     args += "-debug"
2385   }
2386   args += [ "--launcher.appendVmargs", "-vmargs", "-Dorg.eclipse.equinox.p2.reconciler.dropins.directory=${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_eclipse_tmp_dropins_dir}" ]
2387   if (!IN_ECLIPSE) {
2388     args += [ "-D${j2sHeadlessBuildProperty}=true" ]
2389   }
2390
2391   def stdout
2392   def stderr
2393   doFirst {
2394     stdout = new ByteArrayOutputStream()
2395     stderr = new ByteArrayOutputStream()
2396
2397     def logOutFileName = "${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}"
2398     def logOutFile = file(logOutFileName)
2399     logOutFile.createNewFile()
2400     logOutFile.text = """ROOT: ${jalviewjs_eclipse_root}
2401 BINARY: ${eclipseBinary}
2402 VERSION: ${eclipseVersion}
2403 WORKSPACE: ${eclipseWorkspace}
2404 DEBUG: ${eclipseDebug}
2405 ----
2406 """
2407     def logOutFOS = new FileOutputStream(logOutFile, true) // true == append
2408     // combine stdout and stderr
2409     def logErrFOS = logOutFOS
2410
2411     if (jalviewjs_j2s_to_console.equals("true")) {
2412       standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
2413         new org.apache.tools.ant.util.TeeOutputStream(
2414           logOutFOS,
2415           stdout),
2416         standardOutput)
2417       errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
2418         new org.apache.tools.ant.util.TeeOutputStream(
2419           logErrFOS,
2420           stderr),
2421         errorOutput)
2422     } else {
2423       standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
2424         logOutFOS,
2425         stdout)
2426       errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
2427         logErrFOS,
2428         stderr)
2429     }
2430   }
2431
2432   doLast {
2433     if (stdout.toString().contains("Error processing ")) {
2434       // j2s did not complete transpile
2435       //throw new TaskExecutionException("Error during transpilation:\n${stderr}\nSee eclipse transpile log file '${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}'")
2436       if (jalviewjs_ignore_transpile_errors.equals("true")) {
2437         println("IGNORING TRANSPILE ERRORS")
2438         println("See eclipse transpile log file '${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}'")
2439       } else {
2440         throw new GradleException("Error during transpilation:\n${stderr}\nSee eclipse transpile log file '${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}'")
2441       }
2442     }
2443   }
2444
2445   inputs.dir("${jalviewDir}/${sourceDir}")
2446   outputs.dir("${jalviewDir}/${jalviewjsTransferSiteJsDir}")
2447   outputs.upToDateWhen( { file("${jalviewDir}/${jalviewjsTransferSiteJsDir}${jalviewjs_server_resource}").exists() } )
2448 }
2449
2450
2451 def jalviewjsCallCore(String name, FileCollection list, String prefixFile, String suffixFile, String jsfile, String zjsfile, File logOutFile, Boolean logOutConsole) {
2452
2453   def stdout = new ByteArrayOutputStream()
2454   def stderr = new ByteArrayOutputStream()
2455
2456   def coreFile = file(jsfile)
2457   def msg = ""
2458   msg = "Creating core for ${name}...\nGenerating ${jsfile}"
2459   println(msg)
2460   logOutFile.createNewFile()
2461   logOutFile.append(msg+"\n")
2462
2463   def coreTop = file(prefixFile)
2464   def coreBottom = file(suffixFile)
2465   coreFile.getParentFile().mkdirs()
2466   coreFile.createNewFile()
2467   coreFile.write( coreTop.getText("UTF-8") )
2468   list.each {
2469     f ->
2470     if (f.exists()) {
2471       def t = f.getText("UTF-8")
2472       t.replaceAll("Clazz\\.([^_])","Clazz_${1}")
2473       coreFile.append( t )
2474     } else {
2475       msg = "...file '"+f.getPath()+"' does not exist, skipping"
2476       println(msg)
2477       logOutFile.append(msg+"\n")
2478     }
2479   }
2480   coreFile.append( coreBottom.getText("UTF-8") )
2481
2482   msg = "Generating ${zjsfile}"
2483   println(msg)
2484   logOutFile.append(msg+"\n")
2485   def logOutFOS = new FileOutputStream(logOutFile, true) // true == append
2486   def logErrFOS = logOutFOS
2487
2488   javaexec {
2489     classpath = files(["${jalviewDir}/${jalviewjs_closure_compiler}"])
2490     main = "com.google.javascript.jscomp.CommandLineRunner"
2491     jvmArgs = [ "-Dfile.encoding=UTF-8" ]
2492     args = [ "--compilation_level", "SIMPLE_OPTIMIZATIONS", "--warning_level", "QUIET", "--charset", "UTF-8", "--js", jsfile, "--js_output_file", zjsfile ]
2493     maxHeapSize = "2g"
2494
2495     msg = "\nRunning '"+commandLine.join(' ')+"'\n"
2496     println(msg)
2497     logOutFile.append(msg+"\n")
2498
2499     if (logOutConsole) {
2500       standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
2501         new org.apache.tools.ant.util.TeeOutputStream(
2502           logOutFOS,
2503           stdout),
2504         standardOutput)
2505         errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
2506           new org.apache.tools.ant.util.TeeOutputStream(
2507             logErrFOS,
2508             stderr),
2509           errorOutput)
2510     } else {
2511       standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
2512         logOutFOS,
2513         stdout)
2514         errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
2515           logErrFOS,
2516           stderr)
2517     }
2518   }
2519   msg = "--"
2520   println(msg)
2521   logOutFile.append(msg+"\n")
2522 }
2523
2524
2525 task jalviewjsBuildAllCores {
2526   group "JalviewJS"
2527   description "Build the core js lib closures listed in the classlists dir"
2528   dependsOn jalviewjsTranspile
2529   dependsOn jalviewjsTransferUnzipSwingJs
2530
2531   def j2sDir = "${jalviewDir}/${jalviewjsTransferSiteJsDir}/${jalviewjs_j2s_subdir}"
2532   def swingJ2sDir = "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}/${jalviewjs_j2s_subdir}"
2533   def libJ2sDir = "${jalviewDir}/${jalviewjsTransferSiteLibDir}/${jalviewjs_j2s_subdir}"
2534   def jsDir = "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}/${jalviewjs_js_subdir}"
2535   def outputDir = "${jalviewDir}/${jalviewjsTransferSiteCoreDir}/${jalviewjs_j2s_subdir}/core"
2536   def prefixFile = "${jsDir}/core/coretop2.js"
2537   def suffixFile = "${jsDir}/core/corebottom2.js"
2538
2539   inputs.file prefixFile
2540   inputs.file suffixFile
2541
2542   def classlistFiles = []
2543   // add the classlists found int the jalviewjs_classlists_dir
2544   fileTree(dir: "${jalviewDir}/${jalviewjs_classlists_dir}", include: "*.txt").each {
2545     file ->
2546     def name = file.getName() - ".txt"
2547     classlistFiles += [
2548       'file': file,
2549       'name': name
2550     ]
2551   }
2552
2553   // _jmol and _jalview cores. Add any other peculiar classlist.txt files here
2554   //classlistFiles += [ 'file': file("${jalviewDir}/${jalviewjs_classlist_jmol}"), 'name': "_jvjmol" ]
2555   classlistFiles += [ 'file': file("${jalviewDir}/${jalviewjs_classlist_jalview}"), 'name': jalviewjsJalviewCoreName ]
2556
2557   jalviewjsCoreClasslists = []
2558
2559   classlistFiles.each {
2560     hash ->
2561
2562     def file = hash['file']
2563     if (! file.exists()) {
2564       //println("...classlist file '"+file.getPath()+"' does not exist, skipping")
2565       return false // this is a "continue" in groovy .each closure
2566     }
2567     def name = hash['name']
2568     if (name == null) {
2569       name = file.getName() - ".txt"
2570     }
2571
2572     def filelist = []
2573     file.eachLine {
2574       line ->
2575         filelist += line
2576     }
2577     def list = fileTree(dir: j2sDir, includes: filelist)
2578
2579     def jsfile = "${outputDir}/core${name}.js"
2580     def zjsfile = "${outputDir}/core${name}.z.js"
2581
2582     jalviewjsCoreClasslists += [
2583       'jsfile': jsfile,
2584       'zjsfile': zjsfile,
2585       'list': list,
2586       'name': name
2587     ]
2588
2589     inputs.file(file)
2590     inputs.files(list)
2591     outputs.file(jsfile)
2592     outputs.file(zjsfile)
2593   }
2594   
2595   // _stevesoft core. add any cores without a classlist here (and the inputs and outputs)
2596   def stevesoftClasslistName = "_stevesoft"
2597   def stevesoftClasslist = [
2598     'jsfile': "${outputDir}/core${stevesoftClasslistName}.js",
2599     'zjsfile': "${outputDir}/core${stevesoftClasslistName}.z.js",
2600     'list': fileTree(dir: j2sDir, include: "com/stevesoft/pat/**/*.js"),
2601     'name': stevesoftClasslistName
2602   ]
2603   jalviewjsCoreClasslists += stevesoftClasslist
2604   inputs.files(stevesoftClasslist['list'])
2605   outputs.file(stevesoftClasslist['jsfile'])
2606   outputs.file(stevesoftClasslist['zjsfile'])
2607
2608   // _all core
2609   def allClasslistName = "_all"
2610   def allJsFiles = fileTree(dir: j2sDir, include: "**/*.js")
2611   allJsFiles += fileTree(
2612     dir: libJ2sDir,
2613     include: "**/*.js",
2614     excludes: [
2615       // these exlusions are files that the closure-compiler produces errors for. Should fix them
2616       "**/org/jmol/jvxl/readers/IsoIntersectFileReader.js",
2617       "**/org/jmol/export/JSExporter.js"
2618     ]
2619   )
2620   allJsFiles += fileTree(
2621     dir: swingJ2sDir,
2622     include: "**/*.js",
2623     excludes: [
2624       // these exlusions are files that the closure-compiler produces errors for. Should fix them
2625       "**/sun/misc/Unsafe.js",
2626       "**/swingjs/jquery/jquery-editable-select.js",
2627       "**/swingjs/jquery/j2sComboBox.js",
2628       "**/sun/misc/FloatingDecimal.js"
2629     ]
2630   )
2631   def allClasslist = [
2632     'jsfile': "${outputDir}/core${allClasslistName}.js",
2633     'zjsfile': "${outputDir}/core${allClasslistName}.z.js",
2634     'list': allJsFiles,
2635     'name': allClasslistName
2636   ]
2637   // not including this version of "all" core at the moment
2638   //jalviewjsCoreClasslists += allClasslist
2639   inputs.files(allClasslist['list'])
2640   outputs.file(allClasslist['jsfile'])
2641   outputs.file(allClasslist['zjsfile'])
2642
2643   doFirst {
2644     def logOutFile = file("${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_j2s_closure_stdout}")
2645     logOutFile.getParentFile().mkdirs()
2646     logOutFile.createNewFile()
2647     logOutFile.write(getDate("yyyy-MM-dd HH:mm:ss")+" jalviewjsBuildAllCores\n----\n")
2648
2649     jalviewjsCoreClasslists.each {
2650       jalviewjsCallCore(it.name, it.list, prefixFile, suffixFile, it.jsfile, it.zjsfile, logOutFile, jalviewjs_j2s_to_console.equals("true"))
2651     }
2652   }
2653
2654 }
2655
2656
2657 def jalviewjsPublishCoreTemplate(String coreName, String templateName, File inputFile, String outputFile) {
2658   copy {
2659     from inputFile
2660     into file(outputFile).getParentFile()
2661     rename { filename ->
2662       if (filename.equals(inputFile.getName())) {
2663         return file(outputFile).getName()
2664       }
2665       return null
2666     }
2667     filter(ReplaceTokens,
2668       beginToken: '_',
2669       endToken: '_',
2670       tokens: [
2671         'MAIN': '"'+main_class+'"',
2672         'CODE': "null",
2673         'NAME': jalviewjsJalviewTemplateName+" [core ${coreName}]",
2674         'COREKEY': jalviewjs_core_key,
2675         'CORENAME': coreName
2676       ]
2677     )
2678   }
2679 }
2680
2681
2682 task jalviewjsPublishCoreTemplates {
2683   dependsOn jalviewjsBuildAllCores
2684   def inputFileName = "${jalviewDir}/${j2s_coretemplate_html}"
2685   def inputFile = file(inputFileName)
2686   def outputDir = "${jalviewDir}/${jalviewjsTransferSiteCoreDir}"
2687
2688   def outputFiles = []
2689   jalviewjsCoreClasslists.each { cl ->
2690     def outputFile = "${outputDir}/${jalviewjsJalviewTemplateName}_${cl.name}.html"
2691     cl['outputfile'] = outputFile
2692     outputFiles += outputFile
2693   }
2694
2695   doFirst {
2696     jalviewjsCoreClasslists.each { cl ->
2697       jalviewjsPublishCoreTemplate(cl.name, jalviewjsJalviewTemplateName, inputFile, cl.outputfile)
2698     }
2699   }
2700   inputs.file(inputFile)
2701   outputs.files(outputFiles)
2702 }
2703
2704
2705 task jalviewjsSyncCore (type: Sync) {
2706   dependsOn jalviewjsBuildAllCores
2707   dependsOn jalviewjsPublishCoreTemplates
2708   def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjsTransferSiteCoreDir}")
2709   def outputDir = "${jalviewDir}/${jalviewjsSiteDir}"
2710
2711   from inputFiles
2712   into outputDir
2713   def outputFiles = []
2714   rename { filename ->
2715     outputFiles += "${outputDir}/${filename}"
2716     null
2717   }
2718   preserve {
2719     include "**"
2720   }
2721   outputs.files outputFiles
2722   inputs.files inputFiles
2723 }
2724
2725
2726 // this Copy version of TransferSiteJs will delete anything else in the target dir
2727 task jalviewjsCopyTransferSiteJs(type: Copy) {
2728   dependsOn jalviewjsTranspile
2729   from "${jalviewDir}/${jalviewjsTransferSiteJsDir}"
2730   into "${jalviewDir}/${jalviewjsSiteDir}"
2731 }
2732
2733
2734 // this Sync version of TransferSite is used by buildship to keep the website automatically up to date when a file changes
2735 task jalviewjsSyncTransferSiteJs(type: Sync) {
2736   from "${jalviewDir}/${jalviewjsTransferSiteJsDir}"
2737   include "**/*.*"
2738   into "${jalviewDir}/${jalviewjsSiteDir}"
2739   preserve {
2740     include "**"
2741   }
2742 }
2743
2744
2745 jalviewjsSyncAllLibs.mustRunAfter jalviewjsCopyTransferSiteJs
2746 jalviewjsSyncResources.mustRunAfter jalviewjsCopyTransferSiteJs
2747 jalviewjsSyncSiteResources.mustRunAfter jalviewjsCopyTransferSiteJs
2748 jalviewjsSyncBuildProperties.mustRunAfter jalviewjsCopyTransferSiteJs
2749
2750 jalviewjsSyncAllLibs.mustRunAfter jalviewjsSyncTransferSiteJs
2751 jalviewjsSyncResources.mustRunAfter jalviewjsSyncTransferSiteJs
2752 jalviewjsSyncSiteResources.mustRunAfter jalviewjsSyncTransferSiteJs
2753 jalviewjsSyncBuildProperties.mustRunAfter jalviewjsSyncTransferSiteJs
2754
2755
2756 task jalviewjsPrepareSite {
2757   group "JalviewJS"
2758   description "Prepares the website folder including unzipping files and copying resources"
2759   dependsOn jalviewjsSyncAllLibs
2760   dependsOn jalviewjsSyncResources
2761   dependsOn jalviewjsSyncSiteResources
2762   dependsOn jalviewjsSyncBuildProperties
2763   dependsOn jalviewjsSyncCore
2764 }
2765
2766
2767 task jalviewjsBuildSite {
2768   group "JalviewJS"
2769   description "Builds the whole website including transpiled code"
2770   dependsOn jalviewjsCopyTransferSiteJs
2771   dependsOn jalviewjsPrepareSite
2772 }
2773
2774
2775 task cleanJalviewjsTransferSite {
2776   doFirst {
2777     delete "${jalviewDir}/${jalviewjsTransferSiteJsDir}"
2778     delete "${jalviewDir}/${jalviewjsTransferSiteLibDir}"
2779     delete "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}"
2780     delete "${jalviewDir}/${jalviewjsTransferSiteCoreDir}"
2781   }
2782 }
2783
2784
2785 task cleanJalviewjsSite {
2786   dependsOn cleanJalviewjsTransferSite
2787   doFirst {
2788     delete "${jalviewDir}/${jalviewjsSiteDir}"
2789   }
2790 }
2791
2792
2793 task jalviewjsSiteTar(type: Tar) {
2794   group "JalviewJS"
2795   description "Creates a tar.gz file for the website"
2796   dependsOn jalviewjsBuildSite
2797   def outputFilename = "jalviewjs-site-${JALVIEW_VERSION}.tar.gz"
2798   archiveFileName = outputFilename
2799
2800   compression Compression.GZIP
2801
2802   from "${jalviewDir}/${jalviewjsSiteDir}"
2803   into jalviewjs_site_dir // this is inside the tar file
2804
2805   inputs.dir("${jalviewDir}/${jalviewjsSiteDir}")
2806 }
2807
2808
2809 task jalviewjsServer {
2810   group "JalviewJS"
2811   def filename = "jalviewjsTest.html"
2812   description "Starts a webserver on localhost to test the website. See ${filename} to access local site on most recently used port."
2813   def htmlFile = "${jalviewDirAbsolutePath}/${filename}"
2814   doLast {
2815
2816     SimpleHttpFileServerFactory factory = new SimpleHttpFileServerFactory()
2817     def port = Integer.valueOf(jalviewjs_server_port)
2818     def start = port
2819     def running = false
2820     def url
2821     def jalviewjsServer
2822     while(port < start+1000 && !running) {
2823       try {
2824         def doc_root = new File("${jalviewDirAbsolutePath}/${jalviewjsSiteDir}")
2825         jalviewjsServer = factory.start(doc_root, port)
2826         running = true
2827         url = jalviewjsServer.getResourceUrl(jalviewjs_server_resource)
2828         println("SERVER STARTED with document root ${doc_root}.")
2829         println("Go to "+url+" . Run  gradle --stop  to stop (kills all gradle daemons).")
2830         println("For debug: "+url+"?j2sdebug")
2831         println("For verbose: "+url+"?j2sverbose")
2832       } catch (Exception e) {
2833         port++;
2834       }
2835     }
2836     def htmlText = """
2837       <p><a href="${url}">JalviewJS Test. &lt;${url}&gt;</a></p>
2838       <p><a href="${url}?j2sdebug">JalviewJS Test with debug. &lt;${url}?j2sdebug&gt;</a></p>
2839       <p><a href="${url}?j2sverbose">JalviewJS Test with verbose. &lt;${url}?j2sdebug&gt;</a></p>
2840       """
2841     jalviewjsCoreClasslists.each { cl ->
2842       def urlcore = jalviewjsServer.getResourceUrl(file(cl.outputfile).getName())
2843       htmlText += """
2844       <p><a href="${urlcore}">${jalviewjsJalviewTemplateName} [core ${cl.name}]. &lt;${urlcore}&gt;</a></p>
2845       """
2846       println("For core ${cl.name}: "+urlcore)
2847     }
2848
2849     file(htmlFile).text = htmlText
2850   }
2851
2852   outputs.file(htmlFile)
2853   outputs.upToDateWhen({false})
2854 }
2855
2856
2857 task cleanJalviewjsAll {
2858   group "JalviewJS"
2859   description "Delete all configuration and build artifacts to do with JalviewJS build"
2860   dependsOn cleanJalviewjsSite
2861   dependsOn jalviewjsEclipsePaths
2862   
2863   doFirst {
2864     delete "${jalviewDir}/${jalviewjsBuildDir}"
2865     delete "${jalviewDir}/${eclipse_bin_dir}"
2866     if (eclipseWorkspace != null && file(eclipseWorkspace.getAbsolutePath()+"/.metadata").exists()) {
2867       delete file(eclipseWorkspace.getAbsolutePath()+"/.metadata")
2868     }
2869     delete "${jalviewDir}/${jalviewjs_j2s_settings}"
2870   }
2871
2872   outputs.upToDateWhen( { false } )
2873 }
2874
2875
2876 task jalviewjsIDE_checkJ2sPlugin {
2877   group "00 JalviewJS in Eclipse"
2878   description "Compare the swingjs/net.sf.j2s.core(-j11)?.jar file with the Eclipse IDE's plugin version (found in the 'dropins' dir)"
2879
2880   doFirst {
2881     def j2sPlugin = string("${jalviewDir}/${jalviewjsJ2sPlugin}")
2882     def j2sPluginFile = file(j2sPlugin)
2883     def eclipseHome = System.properties["eclipse.home.location"]
2884     if (eclipseHome == null || ! IN_ECLIPSE) {
2885       throw new StopExecutionException("Cannot find running Eclipse home from System.properties['eclipse.home.location']. Skipping J2S Plugin Check.")
2886     }
2887     def eclipseJ2sPluginDirs = [ "${eclipseHome}/dropins" ]
2888     def altPluginsDir = System.properties["org.eclipse.equinox.p2.reconciler.dropins.directory"]
2889     if (altPluginsDir != null && file(altPluginsDir).exists()) {
2890       eclipseJ2sPluginDirs += altPluginsDir
2891     }
2892     def foundPlugin = false
2893     def j2sPluginFileName = j2sPluginFile.getName()
2894     def eclipseJ2sPlugin
2895     def eclipseJ2sPluginFile
2896     eclipseJ2sPluginDirs.any { dir ->
2897       eclipseJ2sPlugin = "${dir}/${j2sPluginFileName}"
2898       eclipseJ2sPluginFile = file(eclipseJ2sPlugin)
2899       if (eclipseJ2sPluginFile.exists()) {
2900         foundPlugin = true
2901         return true
2902       }
2903     }
2904     if (!foundPlugin) {
2905       def msg = "Eclipse J2S Plugin is not installed (could not find '${j2sPluginFileName}' in\n"+eclipseJ2sPluginDirs.join("\n")+"\n)\nTry running task jalviewjsIDE_copyJ2sPlugin"
2906       System.err.println(msg)
2907       throw new StopExecutionException(msg)
2908     }
2909
2910     def digest = MessageDigest.getInstance("MD5")
2911
2912     digest.update(j2sPluginFile.text.bytes)
2913     def j2sPluginMd5 = new BigInteger(1, digest.digest()).toString(16).padLeft(32, '0')
2914
2915     digest.update(eclipseJ2sPluginFile.text.bytes)
2916     def eclipseJ2sPluginMd5 = new BigInteger(1, digest.digest()).toString(16).padLeft(32, '0')
2917      
2918     if (j2sPluginMd5 != eclipseJ2sPluginMd5) {
2919       def msg = "WARNING! Eclipse J2S Plugin '${eclipseJ2sPlugin}' is different to this commit's version '${j2sPlugin}'"
2920       System.err.println(msg)
2921       throw new StopExecutionException(msg)
2922     } else {
2923       def msg = "Eclipse J2S Plugin '${eclipseJ2sPlugin}' is the same as '${j2sPlugin}' (this is good)"
2924       println(msg)
2925     }
2926   }
2927 }
2928
2929 task jalviewjsIDE_copyJ2sPlugin {
2930   group "00 JalviewJS in Eclipse"
2931   description "Copy the swingjs/net.sf.j2s.core(-j11)?.jar file into the Eclipse IDE's 'dropins' dir"
2932
2933   doFirst {
2934     def j2sPlugin = string("${jalviewDir}/${jalviewjsJ2sPlugin}")
2935     def j2sPluginFile = file(j2sPlugin)
2936     def eclipseHome = System.properties["eclipse.home.location"]
2937     if (eclipseHome == null || ! IN_ECLIPSE) {
2938       throw new StopExecutionException("Cannot find running Eclipse home from System.properties['eclipse.home.location']. NOT copying J2S Plugin.")
2939     }
2940     def eclipseJ2sPlugin = "${eclipseHome}/dropins/${j2sPluginFile.getName()}"
2941     def eclipseJ2sPluginFile = file(eclipseJ2sPlugin)
2942     def msg = "WARNING! Copying this commit's j2s plugin '${j2sPlugin}' to Eclipse J2S Plugin '${eclipseJ2sPlugin}'\n* May require an Eclipse restart"
2943     System.err.println(msg)
2944     copy {
2945       from j2sPlugin
2946       eclipseJ2sPluginFile.getParentFile().mkdirs()
2947       into eclipseJ2sPluginFile.getParent()
2948     }
2949   }
2950 }
2951
2952
2953 task jalviewjsIDE_j2sFile {
2954   group "00 JalviewJS in Eclipse"
2955   description "Creates the .j2s file"
2956   dependsOn jalviewjsCreateJ2sSettings
2957 }
2958
2959
2960 task jalviewjsIDE_SyncCore {
2961   group "00 JalviewJS in Eclipse"
2962   description "Build the core js lib closures listed in the classlists dir and publish core html from template"
2963   dependsOn jalviewjsSyncCore
2964 }
2965
2966
2967 task jalviewjsIDE_SyncSiteAll {
2968   dependsOn jalviewjsSyncAllLibs
2969   dependsOn jalviewjsSyncResources
2970   dependsOn jalviewjsSyncSiteResources
2971   dependsOn jalviewjsSyncBuildProperties
2972 }
2973
2974
2975 cleanJalviewjsTransferSite.mustRunAfter jalviewjsIDE_SyncSiteAll
2976
2977
2978 task jalviewjsIDE_PrepareSite {
2979   group "00 JalviewJS in Eclipse"
2980   description "Sync libs and resources to site dir, but not closure cores"
2981
2982   dependsOn jalviewjsIDE_SyncSiteAll
2983   //dependsOn cleanJalviewjsTransferSite // not sure why this clean is here -- will slow down a re-run of this task
2984 }
2985
2986
2987 task jalviewjsIDE_AssembleSite {
2988   group "00 JalviewJS in Eclipse"
2989   description "Assembles unzipped supporting zipfiles, resources, site resources and closure cores into the Eclipse transpiled site"
2990   dependsOn jalviewjsPrepareSite
2991 }
2992
2993
2994 task jalviewjsIDE_SiteClean {
2995   group "00 JalviewJS in Eclipse"
2996   description "Deletes the Eclipse transpiled site"
2997   dependsOn cleanJalviewjsSite
2998 }
2999
3000
3001 task jalviewjsIDE_Server {
3002   group "00 JalviewJS in Eclipse"
3003   description "Starts a webserver on localhost to test the website"
3004   dependsOn jalviewjsServer
3005 }
3006
3007
3008 // buildship runs this at import or gradle refresh
3009 task eclipseSynchronizationTask {
3010   //dependsOn eclipseSetup
3011   dependsOn createBuildProperties
3012   if (J2S_ENABLED) {
3013     dependsOn jalviewjsIDE_j2sFile
3014     dependsOn jalviewjsIDE_checkJ2sPlugin
3015     dependsOn jalviewjsIDE_PrepareSite
3016   }
3017 }
3018
3019
3020 // buildship runs this at build time or project refresh
3021 task eclipseAutoBuildTask {
3022   //dependsOn jalviewjsIDE_checkJ2sPlugin
3023   //dependsOn jalviewjsIDE_PrepareSite
3024 }
3025
3026
3027 task jalviewjs {
3028   group "JalviewJS"
3029   description "Build the site"
3030   dependsOn jalviewjsBuildSite
3031 }