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