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