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