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