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