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