JAL-3633 getdown reads jalview_properties for proxy settings
[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       from "${getdownWebsiteDir}/${channel_props}"
1677       if (file(getdownLauncher).getName() != getdown_launcher) {
1678         rename(file(getdownLauncher).getName(), getdown_launcher)
1679       }
1680       into getdownFilesDir
1681     }
1682
1683     // and ./resources (not all downloaded by getdown)
1684     copy {
1685       from getdownResourceDir
1686       into "${getdownFilesDir}/${getdown_resource_dir}"
1687     }
1688   }
1689
1690   if (buildDist) {
1691     inputs.dir("${jalviewDir}/${package_dir}")
1692   }
1693   outputs.dir(getdownWebsiteDir)
1694   outputs.dir(getdownFilesDir)
1695 }
1696
1697
1698 // a helper task to allow getdown digest of any dir: `gradle getdownDigestDir -PDIGESTDIR=/path/to/my/random/getdown/dir
1699 task getdownDigestDir(type: JavaExec) {
1700   group "Help"
1701   description "A task to run a getdown Digest on a dir with getdown.txt. Provide a DIGESTDIR property via -PDIGESTDIR=..."
1702
1703   def digestDirPropertyName = "DIGESTDIR"
1704   doFirst {
1705     classpath = files(getdownLauncher)
1706     def digestDir = findProperty(digestDirPropertyName)
1707     if (digestDir == null) {
1708       throw new GradleException("Must provide a DIGESTDIR value to produce an alternative getdown digest")
1709     }
1710     args digestDir
1711   }
1712   main = "com.threerings.getdown.tools.Digester"
1713 }
1714
1715
1716 task getdownDigest(type: JavaExec) {
1717   group = "distribution"
1718   description = "Digest the getdown website folder"
1719   dependsOn getdownWebsite
1720   doFirst {
1721     classpath = files(getdownLauncher)
1722   }
1723   main = "com.threerings.getdown.tools.Digester"
1724   args getdownWebsiteDir
1725   inputs.dir(getdownWebsiteDir)
1726   outputs.file("${getdownWebsiteDir}/digest2.txt")
1727 }
1728
1729
1730 task getdown() {
1731   group = "distribution"
1732   description = "Create the minimal and full getdown app folder for installers and website and create digest file"
1733   dependsOn getdownDigest
1734   doLast {
1735     if (reportRsyncCommand) {
1736       def fromDir = getdownWebsiteDir + (getdownWebsiteDir.endsWith('/')?'':'/')
1737       def toDir = "${getdown_rsync_dest}/${getdownDir}" + (getdownDir.endsWith('/')?'':'/')
1738       println "LIKELY RSYNC COMMAND:"
1739       println "mkdir -p '$toDir'\nrsync -avh --delete '$fromDir' '$toDir'"
1740       if (RUNRSYNC == "true") {
1741         exec {
1742           commandLine "mkdir", "-p", toDir
1743         }
1744         exec {
1745           commandLine "rsync", "-avh", "--delete", fromDir, toDir
1746         }
1747       }
1748     }
1749   }
1750 }
1751
1752
1753 tasks.withType(JavaCompile) {
1754         options.encoding = 'UTF-8'
1755 }
1756
1757
1758 clean {
1759   doFirst {
1760     delete getdownWebsiteDir
1761     delete getdownFilesDir
1762   }
1763 }
1764
1765
1766 install4j {
1767   if (file(install4jHomeDir).exists()) {
1768     // good to go!
1769   } else if (file(System.getProperty("user.home")+"/buildtools/install4j").exists()) {
1770     install4jHomeDir = System.getProperty("user.home")+"/buildtools/install4j"
1771   } else if (file("/Applications/install4j.app/Contents/Resources/app").exists()) {
1772     install4jHomeDir = "/Applications/install4j.app/Contents/Resources/app"
1773   }
1774   installDir(file(install4jHomeDir))
1775
1776   mediaTypes = Arrays.asList(install4j_media_types.split(","))
1777 }
1778
1779
1780 task copyInstall4jTemplate {
1781   def install4jTemplateFile = file("${install4jDir}/${install4j_template}")
1782   def install4jFileAssociationsFile = file("${install4jDir}/${install4j_installer_file_associations}")
1783   inputs.file(install4jTemplateFile)
1784   inputs.file(install4jFileAssociationsFile)
1785   inputs.property("CHANNEL", { CHANNEL })
1786   outputs.file(install4jConfFile)
1787
1788   doLast {
1789     def install4jConfigXml = new XmlParser().parse(install4jTemplateFile)
1790
1791     // turn off code signing if no OSX_KEYPASS
1792     if (OSX_KEYPASS == "") {
1793       install4jConfigXml.'**'.codeSigning.each { codeSigning ->
1794         codeSigning.'@macEnabled' = "false"
1795       }
1796       install4jConfigXml.'**'.windows.each { windows ->
1797         windows.'@runPostProcessor' = "false"
1798       }
1799     }
1800
1801     // turn off checksum creation for LOCAL channel
1802     def e = install4jConfigXml.application[0]
1803     if (CHANNEL == "LOCAL") {
1804       e.'@createChecksums' = "false"
1805     } else {
1806       e.'@createChecksums' = "true"
1807     }
1808
1809     // put file association actions where placeholder action is
1810     def install4jFileAssociationsText = install4jFileAssociationsFile.text
1811     def fileAssociationActions = new XmlParser().parseText("<actions>${install4jFileAssociationsText}</actions>")
1812     install4jConfigXml.'**'.action.any { a -> // .any{} stops after the first one that returns true
1813       if (a.'@name' == 'EXTENSIONS_REPLACED_BY_GRADLE') {
1814         def parent = a.parent()
1815         parent.remove(a)
1816         fileAssociationActions.each { faa ->
1817             parent.append(faa)
1818         }
1819         // don't need to continue in .any loop once replacements have been made
1820         return true
1821       }
1822     }
1823
1824     // use Windows Program Group with Examples folder for RELEASE, and Program Group without Examples for everything else
1825     // NB we're deleting the /other/ one!
1826     // Also remove the examples subdir from non-release versions
1827     def customizedIdToDelete = "PROGRAM_GROUP_RELEASE"
1828     // 2.11.1.0 NOT releasing with the Examples folder in the Program Group
1829     if (false && CHANNEL=="RELEASE") { // remove 'false && ' to include Examples folder in RELEASE channel
1830       customizedIdToDelete = "PROGRAM_GROUP_NON_RELEASE"
1831     } else {
1832       // remove the examples subdir from Full File Set
1833       def files = install4jConfigXml.files[0]
1834       def fileset = files.filesets.fileset.find { fs -> fs.'@customizedId' == "FULL_FILE_SET" }
1835       def root = files.roots.root.find { r -> r.'@fileset' == fileset.'@id' }
1836       def mountPoint = files.mountPoints.mountPoint.find { mp -> mp.'@root' == root.'@id' }
1837       def dirEntry = files.entries.dirEntry.find { de -> de.'@mountPoint' == mountPoint.'@id' && de.'@subDirectory' == "examples" }
1838       dirEntry.parent().remove(dirEntry)
1839     }
1840     install4jConfigXml.'**'.action.any { a ->
1841       if (a.'@customizedId' == customizedIdToDelete) {
1842         def parent = a.parent()
1843         parent.remove(a)
1844         return true
1845       }
1846     }
1847
1848     // write install4j file
1849     install4jConfFile.text = XmlUtil.serialize(install4jConfigXml)
1850   }
1851 }
1852
1853
1854 clean {
1855   doFirst {
1856     delete install4jConfFile
1857   }
1858 }
1859
1860
1861 task installers(type: com.install4j.gradle.Install4jTask) {
1862   group = "distribution"
1863   description = "Create the install4j installers"
1864   dependsOn getdown
1865   dependsOn copyInstall4jTemplate
1866
1867   projectFile = install4jConfFile
1868
1869   // create an md5 for the input files to use as version for install4j conf file
1870   def digest = MessageDigest.getInstance("MD5")
1871   digest.update(
1872     (file("${install4jDir}/${install4j_template}").text + 
1873     file("${install4jDir}/${install4j_info_plist_file_associations}").text +
1874     file("${install4jDir}/${install4j_installer_file_associations}").text).bytes)
1875   def filesMd5 = new BigInteger(1, digest.digest()).toString(16)
1876   if (filesMd5.length() >= 8) {
1877     filesMd5 = filesMd5.substring(0,8)
1878   }
1879   def install4jTemplateVersion = "${JALVIEW_VERSION}_F${filesMd5}_C${gitHash}"
1880   // make install4jBuildDir relative to jalviewDir
1881   def install4jBuildDir = "${install4j_build_dir}/${JAVA_VERSION}"
1882
1883   variables = [
1884     'JALVIEW_NAME': jalview_name,
1885     'JALVIEW_APPLICATION_NAME': install4jApplicationName,
1886     'JALVIEW_DIR': "../..",
1887     'OSX_KEYSTORE': OSX_KEYSTORE,
1888     'OSX_APPLEID': OSX_APPLEID,
1889     'OSX_ALTOOLPASS': OSX_ALTOOLPASS,
1890     'JSIGN_SH': JSIGN_SH,
1891     'JRE_DIR': getdown_app_dir_java,
1892     'INSTALLER_TEMPLATE_VERSION': install4jTemplateVersion,
1893     'JALVIEW_VERSION': JALVIEW_VERSION,
1894     'JAVA_MIN_VERSION': JAVA_MIN_VERSION,
1895     'JAVA_MAX_VERSION': JAVA_MAX_VERSION,
1896     'JAVA_VERSION': JAVA_VERSION,
1897     'JAVA_INTEGER_VERSION': JAVA_INTEGER_VERSION,
1898     'VERSION': JALVIEW_VERSION,
1899     'MACOS_JAVA_VM_DIR': macosJavaVMDir,
1900     'WINDOWS_JAVA_VM_DIR': windowsJavaVMDir,
1901     'LINUX_JAVA_VM_DIR': linuxJavaVMDir,
1902     'MACOS_JAVA_VM_TGZ': macosJavaVMTgz,
1903     'WINDOWS_JAVA_VM_TGZ': windowsJavaVMTgz,
1904     'LINUX_JAVA_VM_TGZ': linuxJavaVMTgz,
1905     'COPYRIGHT_MESSAGE': install4j_copyright_message,
1906     'BUNDLE_ID': install4jBundleId,
1907     'INTERNAL_ID': install4jInternalId,
1908     'WINDOWS_APPLICATION_ID': install4jWinApplicationId,
1909     'MACOS_DMG_DS_STORE': install4jDMGDSStore,
1910     'MACOS_DMG_BG_IMAGE': install4jDMGBackgroundImage,
1911     'INSTALLER_NAME': install4jInstallerName,
1912     'INSTALL4J_UTILS_DIR': install4j_utils_dir,
1913     'GETDOWN_WEBSITE_DIR': getdown_website_dir,
1914     'GETDOWN_FILES_DIR': getdown_files_dir,
1915     'GETDOWN_RESOURCE_DIR': getdown_resource_dir,
1916     'GETDOWN_DIST_DIR': getdownAppDistDir,
1917     'GETDOWN_ALT_DIR': getdown_app_dir_alt,
1918     'GETDOWN_INSTALL_DIR': getdown_install_dir,
1919     'INFO_PLIST_FILE_ASSOCIATIONS_FILE': install4j_info_plist_file_associations,
1920     'BUILD_DIR': install4jBuildDir,
1921     'APPLICATION_CATEGORIES': install4j_application_categories,
1922     'APPLICATION_FOLDER': install4jApplicationFolder,
1923     'UNIX_APPLICATION_FOLDER': install4jUnixApplicationFolder,
1924     'EXECUTABLE_NAME': install4jExecutableName,
1925     'EXTRA_SCHEME': install4jExtraScheme,
1926     'MAC_ICONS_FILE': install4jMacIconsFile,
1927     'WINDOWS_ICONS_FILE': install4jWindowsIconsFile,
1928     'PNG_ICON_FILE': install4jPngIconFile,
1929     'BACKGROUND': install4jBackground,
1930
1931   ]
1932
1933   //println("INSTALL4J VARIABLES:")
1934   //variables.each{k,v->println("${k}=${v}")}
1935
1936   destination = "${jalviewDir}/${install4jBuildDir}"
1937   buildSelected = true
1938
1939   if (install4j_faster.equals("true") || CHANNEL.startsWith("LOCAL")) {
1940     faster = true
1941     disableSigning = true
1942     disableNotarization = true
1943   }
1944
1945   if (OSX_KEYPASS) {
1946     macKeystorePassword = OSX_KEYPASS
1947   } 
1948   
1949   if (OSX_ALTOOLPASS) {
1950     appleIdPassword = OSX_ALTOOLPASS
1951     disableNotarization = false
1952   } else {
1953     disableNotarization = true
1954   }
1955
1956   doFirst {
1957     println("Using projectFile "+projectFile)
1958     if (!disableNotarization) { println("Will notarize OSX App DMG") }
1959   }
1960   verbose=true
1961
1962   inputs.dir(getdownWebsiteDir)
1963   inputs.file(install4jConfFile)
1964   inputs.file("${install4jDir}/${install4j_info_plist_file_associations}")
1965   inputs.dir(macosJavaVMDir)
1966   inputs.dir(windowsJavaVMDir)
1967   outputs.dir("${jalviewDir}/${install4j_build_dir}/${JAVA_VERSION}")
1968 }
1969
1970
1971 spotless {
1972   java {
1973     eclipse().configFile(eclipse_codestyle_file)
1974   }
1975 }
1976
1977
1978 task sourceDist(type: Tar) {
1979   group "distribution"
1980   description "Create a source .tar.gz file for distribution"
1981
1982   dependsOn createBuildProperties
1983   dependsOn convertMdFiles
1984
1985   def VERSION_UNDERSCORES = JALVIEW_VERSION.replaceAll("\\.", "_")
1986   def outputFileName = "${project.name}_${VERSION_UNDERSCORES}.tar.gz"
1987   archiveFileName = outputFileName
1988   
1989   compression Compression.GZIP
1990   
1991   into project.name
1992
1993   def EXCLUDE_FILES=[
1994     "build/*",
1995     "bin/*",
1996     "test-output/",
1997     "test-reports",
1998     "tests",
1999     "clover*/*",
2000     ".*",
2001     "benchmarking/*",
2002     "**/.*",
2003     "*.class",
2004     "**/*.class","$j11modDir/**/*.jar","appletlib","**/*locales",
2005     "*locales/**",
2006     "utils/InstallAnywhere",
2007     "**/*.log",
2008   ] 
2009   def PROCESS_FILES=[
2010     "AUTHORS",
2011     "CITATION",
2012     "FEATURETODO",
2013     "JAVA-11-README",
2014     "FEATURETODO",
2015     "LICENSE",
2016     "**/README",
2017     "RELEASE",
2018     "THIRDPARTYLIBS",
2019     "TESTNG",
2020     "build.gradle",
2021     "gradle.properties",
2022     "**/*.java",
2023     "**/*.html",
2024     "**/*.xml",
2025     "**/*.gradle",
2026     "**/*.groovy",
2027     "**/*.properties",
2028     "**/*.perl",
2029     "**/*.sh",
2030   ]
2031   def INCLUDE_FILES=[
2032     ".settings/org.eclipse.jdt.core.jalview.prefs",
2033   ]
2034
2035   from(jalviewDir) {
2036     exclude (EXCLUDE_FILES)
2037     include (PROCESS_FILES)
2038     filter(ReplaceTokens,
2039       beginToken: '$$',
2040       endToken: '$$',
2041       tokens: [
2042         'Version-Rel': JALVIEW_VERSION,
2043         'Year-Rel': getDate("yyyy")
2044       ]
2045     )
2046   }
2047   from(jalviewDir) {
2048     exclude (EXCLUDE_FILES)
2049     exclude (PROCESS_FILES)
2050     exclude ("appletlib")
2051     exclude ("**/*locales")
2052     exclude ("*locales/**")
2053     exclude ("utils/InstallAnywhere")
2054
2055     exclude (getdown_files_dir)
2056     exclude (getdown_website_dir)
2057
2058     // exluding these as not using jars as modules yet
2059     exclude ("${j11modDir}/**/*.jar")
2060   }
2061   from(jalviewDir) {
2062     include(INCLUDE_FILES)
2063   }
2064 //  from (jalviewDir) {
2065 //    // explicit includes for stuff that seemed to not get included
2066 //    include(fileTree("test/**/*."))
2067 //    exclude(EXCLUDE_FILES)
2068 //    exclude(PROCESS_FILES)
2069 //  }
2070
2071   from(file(buildProperties).getParent()) {
2072     include(file(buildProperties).getName())
2073     rename(file(buildProperties).getName(), "build_properties")
2074     filter({ line ->
2075       line.replaceAll("^INSTALLATION=.*\$","INSTALLATION=Source Release"+" git-commit\\\\:"+gitHash+" ["+gitBranch+"]")
2076     })
2077   }
2078
2079 }
2080
2081
2082 task helppages {
2083   dependsOn copyHelp
2084   dependsOn pubhtmlhelp
2085   
2086   inputs.dir("${helpBuildDir}/${help_dir}")
2087   outputs.dir("${buildDir}/distributions/${help_dir}")
2088 }
2089
2090
2091 task j2sSetHeadlessBuild {
2092   doFirst {
2093     IN_ECLIPSE = false
2094   }
2095 }
2096
2097
2098 task jalviewjsEnableAltFileProperty(type: WriteProperties) {
2099   group "jalviewjs"
2100   description "Enable the alternative J2S Config file for headless build"
2101
2102   outputFile = jalviewjsJ2sSettingsFileName
2103   def j2sPropsFile = file(jalviewjsJ2sSettingsFileName)
2104   def j2sProps = new Properties()
2105   if (j2sPropsFile.exists()) {
2106     try {
2107       def j2sPropsFileFIS = new FileInputStream(j2sPropsFile)
2108       j2sProps.load(j2sPropsFileFIS)
2109       j2sPropsFileFIS.close()
2110
2111       j2sProps.each { prop, val ->
2112         property(prop, val)
2113       }
2114     } catch (Exception e) {
2115       println("Exception reading ${jalviewjsJ2sSettingsFileName}")
2116       e.printStackTrace()
2117     }
2118   }
2119   if (! j2sProps.stringPropertyNames().contains(jalviewjs_j2s_alt_file_property_config)) {
2120     property(jalviewjs_j2s_alt_file_property_config, jalviewjs_j2s_alt_file_property)
2121   }
2122 }
2123
2124
2125 task jalviewjsSetEclipseWorkspace {
2126   def propKey = "jalviewjs_eclipse_workspace"
2127   def propVal = null
2128   if (project.hasProperty(propKey)) {
2129     propVal = project.getProperty(propKey)
2130     if (propVal.startsWith("~/")) {
2131       propVal = System.getProperty("user.home") + propVal.substring(1)
2132     }
2133   }
2134   def propsFileName = "${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_eclipse_workspace_location_file}"
2135   def propsFile = file(propsFileName)
2136   def eclipseWsDir = propVal
2137   def props = new Properties()
2138
2139   def writeProps = true
2140   if (( eclipseWsDir == null || !file(eclipseWsDir).exists() ) && propsFile.exists()) {
2141     def ins = new FileInputStream(propsFileName)
2142     props.load(ins)
2143     ins.close()
2144     if (props.getProperty(propKey, null) != null) {
2145       eclipseWsDir = props.getProperty(propKey)
2146       writeProps = false
2147     }
2148   }
2149
2150   if (eclipseWsDir == null || !file(eclipseWsDir).exists()) {
2151     def tempDir = File.createTempDir()
2152     eclipseWsDir = tempDir.getAbsolutePath()
2153     writeProps = true
2154   }
2155   eclipseWorkspace = file(eclipseWsDir)
2156
2157   doFirst {
2158     // do not run a headless transpile when we claim to be in Eclipse
2159     if (IN_ECLIPSE) {
2160       println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
2161       throw new StopExecutionException("Not running headless transpile whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
2162     } else {
2163       println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
2164     }
2165
2166     if (writeProps) {
2167       props.setProperty(propKey, eclipseWsDir)
2168       propsFile.parentFile.mkdirs()
2169       def bytes = new ByteArrayOutputStream()
2170       props.store(bytes, null)
2171       def propertiesString = bytes.toString()
2172       propsFile.text = propertiesString
2173       print("NEW ")
2174     } else {
2175       print("EXISTING ")
2176     }
2177
2178     println("ECLIPSE WORKSPACE: "+eclipseWorkspace.getPath())
2179   }
2180
2181   //inputs.property(propKey, eclipseWsDir) // eclipseWsDir only gets set once this task runs, so will be out-of-date
2182   outputs.file(propsFileName)
2183   outputs.upToDateWhen { eclipseWorkspace.exists() && propsFile.exists() }
2184 }
2185
2186
2187 task jalviewjsEclipsePaths {
2188   def eclipseProduct
2189
2190   def eclipseRoot = jalviewjs_eclipse_root
2191   if (eclipseRoot.startsWith("~/")) {
2192     eclipseRoot = System.getProperty("user.home") + eclipseRoot.substring(1)
2193   }
2194   if (OperatingSystem.current().isMacOsX()) {
2195     eclipseRoot += "/Eclipse.app"
2196     eclipseBinary = "${eclipseRoot}/Contents/MacOS/eclipse"
2197     eclipseProduct = "${eclipseRoot}/Contents/Eclipse/.eclipseproduct"
2198   } else if (OperatingSystem.current().isWindows()) { // check these paths!!
2199     if (file("${eclipseRoot}/eclipse").isDirectory() && file("${eclipseRoot}/eclipse/.eclipseproduct").exists()) {
2200       eclipseRoot += "/eclipse"
2201     }
2202     eclipseBinary = "${eclipseRoot}/eclipse.exe"
2203     eclipseProduct = "${eclipseRoot}/.eclipseproduct"
2204   } else { // linux or unix
2205     if (file("${eclipseRoot}/eclipse").isDirectory() && file("${eclipseRoot}/eclipse/.eclipseproduct").exists()) {
2206       eclipseRoot += "/eclipse"
2207 println("eclipseDir exists")
2208     }
2209     eclipseBinary = "${eclipseRoot}/eclipse"
2210     eclipseProduct = "${eclipseRoot}/.eclipseproduct"
2211   }
2212
2213   eclipseVersion = "4.13" // default
2214   def assumedVersion = true
2215   if (file(eclipseProduct).exists()) {
2216     def fis = new FileInputStream(eclipseProduct)
2217     def props = new Properties()
2218     props.load(fis)
2219     eclipseVersion = props.getProperty("version")
2220     fis.close()
2221     assumedVersion = false
2222   }
2223   
2224   def propKey = "eclipse_debug"
2225   eclipseDebug = (project.hasProperty(propKey) && project.getProperty(propKey).equals("true"))
2226
2227   doFirst {
2228     // do not run a headless transpile when we claim to be in Eclipse
2229     if (IN_ECLIPSE) {
2230       println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
2231       throw new StopExecutionException("Not running headless transpile whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
2232     } else {
2233       println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
2234     }
2235
2236     if (!assumedVersion) {
2237       println("ECLIPSE VERSION=${eclipseVersion}")
2238     }
2239   }
2240 }
2241
2242
2243 task printProperties {
2244   group "Debug"
2245   description "Output to console all System.properties"
2246   doFirst {
2247     System.properties.each { key, val -> System.out.println("Property: ${key}=${val}") }
2248   }
2249 }
2250
2251
2252 task eclipseSetup {
2253   dependsOn eclipseProject
2254   dependsOn eclipseClasspath
2255   dependsOn eclipseJdt
2256 }
2257
2258
2259 // this version (type: Copy) will delete anything in the eclipse dropins folder that isn't in fromDropinsDir
2260 task jalviewjsEclipseCopyDropins(type: Copy) {
2261   dependsOn jalviewjsEclipsePaths
2262
2263   def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjs_eclipse_dropins_dir}", include: "*.jar")
2264   inputFiles += file("${jalviewDir}/${jalviewjsJ2sPlugin}")
2265   def outputDir = "${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_eclipse_tmp_dropins_dir}"
2266
2267   from inputFiles
2268   into outputDir
2269 }
2270
2271
2272 // this eclipse -clean doesn't actually work
2273 task jalviewjsCleanEclipse(type: Exec) {
2274   dependsOn eclipseSetup
2275   dependsOn jalviewjsEclipsePaths
2276   dependsOn jalviewjsEclipseCopyDropins
2277
2278   executable(eclipseBinary)
2279   args(["-nosplash", "--launcher.suppressErrors", "-data", eclipseWorkspace.getPath(), "-clean", "-console", "-consoleLog"])
2280   if (eclipseDebug) {
2281     args += "-debug"
2282   }
2283   args += "-l"
2284
2285   def inputString = """exit
2286 y
2287 """
2288   def inputByteStream = new ByteArrayInputStream(inputString.getBytes())
2289   standardInput = inputByteStream
2290 }
2291
2292 /* not really working yet
2293 jalviewjsEclipseCopyDropins.finalizedBy jalviewjsCleanEclipse
2294 */
2295
2296
2297 task jalviewjsTransferUnzipSwingJs {
2298   def file_zip = "${jalviewDir}/${jalviewjs_swingjs_zip}"
2299
2300   doLast {
2301     copy {
2302       from zipTree(file_zip)
2303       into "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}"
2304     }
2305   }
2306
2307   inputs.file file_zip
2308   outputs.dir "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}"
2309 }
2310
2311
2312 task jalviewjsTransferUnzipLib {
2313   def zipFiles = fileTree(dir: "${jalviewDir}/${jalviewjs_libjs_dir}", include: "*.zip")
2314
2315   doLast {
2316     zipFiles.each { file_zip -> 
2317       copy {
2318         from zipTree(file_zip)
2319         into "${jalviewDir}/${jalviewjsTransferSiteLibDir}"
2320       }
2321     }
2322   }
2323
2324   inputs.files zipFiles
2325   outputs.dir "${jalviewDir}/${jalviewjsTransferSiteLibDir}"
2326 }
2327
2328
2329 task jalviewjsTransferUnzipAllLibs {
2330   dependsOn jalviewjsTransferUnzipSwingJs
2331   dependsOn jalviewjsTransferUnzipLib
2332 }
2333
2334
2335 task jalviewjsCreateJ2sSettings(type: WriteProperties) {
2336   group "JalviewJS"
2337   description "Create the alternative j2s file from the j2s.* properties"
2338
2339   jalviewjsJ2sProps = project.properties.findAll { it.key.startsWith("j2s.") }.sort { it.key }
2340   def siteDirProperty = "j2s.site.directory"
2341   def setSiteDir = false
2342   jalviewjsJ2sProps.each { prop, val ->
2343     if (val != null) {
2344       if (prop == siteDirProperty) {
2345         if (!(val.startsWith('/') || val.startsWith("file://") )) {
2346           val = "${jalviewDir}/${jalviewjsTransferSiteJsDir}/${val}"
2347         }
2348         setSiteDir = true
2349       }
2350       property(prop,val)
2351     }
2352     if (!setSiteDir) { // default site location, don't override specifically set property
2353       property(siteDirProperty,"${jalviewDirRelativePath}/${jalviewjsTransferSiteJsDir}")
2354     }
2355   }
2356   outputFile = jalviewjsJ2sAltSettingsFileName
2357
2358   if (! IN_ECLIPSE) {
2359     inputs.properties(jalviewjsJ2sProps)
2360     outputs.file(jalviewjsJ2sAltSettingsFileName)
2361   }
2362 }
2363
2364
2365 task jalviewjsEclipseSetup {
2366   dependsOn jalviewjsEclipseCopyDropins
2367   dependsOn jalviewjsSetEclipseWorkspace
2368   dependsOn jalviewjsCreateJ2sSettings
2369 }
2370
2371
2372 task jalviewjsSyncAllLibs (type: Sync) {
2373   dependsOn jalviewjsTransferUnzipAllLibs
2374   def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjsTransferSiteLibDir}")
2375   inputFiles += fileTree(dir: "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}")
2376   def outputDir = "${jalviewDir}/${jalviewjsSiteDir}"
2377
2378   from inputFiles
2379   into outputDir
2380   def outputFiles = []
2381   rename { filename ->
2382     outputFiles += "${outputDir}/${filename}"
2383     null
2384   }
2385   preserve {
2386     include "**"
2387   }
2388   outputs.files outputFiles
2389   inputs.files inputFiles
2390 }
2391
2392
2393 task jalviewjsSyncResources (type: Sync) {
2394   dependsOn buildResources
2395
2396   def inputFiles = fileTree(dir: resourcesBuildDir)
2397   def outputDir = "${jalviewDir}/${jalviewjsSiteDir}/${jalviewjs_j2s_subdir}"
2398
2399   from inputFiles
2400   into outputDir
2401   def outputFiles = []
2402   rename { filename ->
2403     outputFiles += "${outputDir}/${filename}"
2404     null
2405   }
2406   preserve {
2407     include "**"
2408   }
2409   outputs.files outputFiles
2410   inputs.files inputFiles
2411 }
2412
2413
2414 task jalviewjsSyncSiteResources (type: Sync) {
2415   def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjs_site_resource_dir}")
2416   def outputDir = "${jalviewDir}/${jalviewjsSiteDir}"
2417
2418   from inputFiles
2419   into outputDir
2420   def outputFiles = []
2421   rename { filename ->
2422     outputFiles += "${outputDir}/${filename}"
2423     null
2424   }
2425   preserve {
2426     include "**"
2427   }
2428   outputs.files outputFiles
2429   inputs.files inputFiles
2430 }
2431
2432
2433 task jalviewjsSyncBuildProperties (type: Sync) {
2434   dependsOn createBuildProperties
2435   def inputFiles = [file(buildProperties)]
2436   def outputDir = "${jalviewDir}/${jalviewjsSiteDir}/${jalviewjs_j2s_subdir}"
2437
2438   from inputFiles
2439   into outputDir
2440   def outputFiles = []
2441   rename { filename ->
2442     outputFiles += "${outputDir}/${filename}"
2443     null
2444   }
2445   preserve {
2446     include "**"
2447   }
2448   outputs.files outputFiles
2449   inputs.files inputFiles
2450 }
2451
2452
2453 task jalviewjsProjectImport(type: Exec) {
2454   dependsOn eclipseSetup
2455   dependsOn jalviewjsEclipsePaths
2456   dependsOn jalviewjsEclipseSetup
2457
2458   doFirst {
2459     // do not run a headless import when we claim to be in Eclipse
2460     if (IN_ECLIPSE) {
2461       println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
2462       throw new StopExecutionException("Not running headless import whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
2463     } else {
2464       println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
2465     }
2466   }
2467
2468   //def projdir = eclipseWorkspace.getPath()+"/.metadata/.plugins/org.eclipse.core.resources/.projects/jalview/org.eclipse.jdt.core"
2469   def projdir = eclipseWorkspace.getPath()+"/.metadata/.plugins/org.eclipse.core.resources/.projects/jalview"
2470   executable(eclipseBinary)
2471   args(["-nosplash", "--launcher.suppressErrors", "-application", "com.seeq.eclipse.importprojects.headlessimport", "-data", eclipseWorkspace.getPath(), "-import", jalviewDirAbsolutePath])
2472   if (eclipseDebug) {
2473     args += "-debug"
2474   }
2475   args += [ "--launcher.appendVmargs", "-vmargs", "-Dorg.eclipse.equinox.p2.reconciler.dropins.directory=${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_eclipse_tmp_dropins_dir}" ]
2476   if (!IN_ECLIPSE) {
2477     args += [ "-D${j2sHeadlessBuildProperty}=true" ]
2478     args += [ "-D${jalviewjs_j2s_alt_file_property}=${jalviewjsJ2sAltSettingsFileName}" ]
2479   }
2480
2481   inputs.file("${jalviewDir}/.project")
2482   outputs.upToDateWhen { 
2483     file(projdir).exists()
2484   }
2485 }
2486
2487
2488 task jalviewjsTranspile(type: Exec) {
2489   dependsOn jalviewjsEclipseSetup 
2490   dependsOn jalviewjsProjectImport
2491   dependsOn jalviewjsEclipsePaths
2492   if (!IN_ECLIPSE) {
2493     dependsOn jalviewjsEnableAltFileProperty
2494   }
2495
2496   doFirst {
2497     // do not run a headless transpile when we claim to be in Eclipse
2498     if (IN_ECLIPSE) {
2499       println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
2500       throw new StopExecutionException("Not running headless transpile whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
2501     } else {
2502       println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
2503     }
2504   }
2505
2506   executable(eclipseBinary)
2507   args(["-nosplash", "--launcher.suppressErrors", "-application", "org.eclipse.jdt.apt.core.aptBuild", "-data", eclipseWorkspace, "-${jalviewjs_eclipse_build_arg}", eclipse_project_name ])
2508   if (eclipseDebug) {
2509     args += "-debug"
2510   }
2511   args += [ "--launcher.appendVmargs", "-vmargs", "-Dorg.eclipse.equinox.p2.reconciler.dropins.directory=${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_eclipse_tmp_dropins_dir}" ]
2512   if (!IN_ECLIPSE) {
2513     args += [ "-D${j2sHeadlessBuildProperty}=true" ]
2514     args += [ "-D${jalviewjs_j2s_alt_file_property}=${jalviewjsJ2sAltSettingsFileName}" ]
2515   }
2516
2517   def stdout
2518   def stderr
2519   doFirst {
2520     stdout = new ByteArrayOutputStream()
2521     stderr = new ByteArrayOutputStream()
2522
2523     def logOutFileName = "${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}"
2524     def logOutFile = file(logOutFileName)
2525     logOutFile.createNewFile()
2526     logOutFile.text = """ROOT: ${jalviewjs_eclipse_root}
2527 BINARY: ${eclipseBinary}
2528 VERSION: ${eclipseVersion}
2529 WORKSPACE: ${eclipseWorkspace}
2530 DEBUG: ${eclipseDebug}
2531 ----
2532 """
2533     def logOutFOS = new FileOutputStream(logOutFile, true) // true == append
2534     // combine stdout and stderr
2535     def logErrFOS = logOutFOS
2536
2537     if (jalviewjs_j2s_to_console.equals("true")) {
2538       standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
2539         new org.apache.tools.ant.util.TeeOutputStream(
2540           logOutFOS,
2541           stdout),
2542         standardOutput)
2543       errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
2544         new org.apache.tools.ant.util.TeeOutputStream(
2545           logErrFOS,
2546           stderr),
2547         errorOutput)
2548     } else {
2549       standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
2550         logOutFOS,
2551         stdout)
2552       errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
2553         logErrFOS,
2554         stderr)
2555     }
2556   }
2557
2558   doLast {
2559     if (stdout.toString().contains("Error processing ")) {
2560       // j2s did not complete transpile
2561       //throw new TaskExecutionException("Error during transpilation:\n${stderr}\nSee eclipse transpile log file '${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}'")
2562       if (jalviewjs_ignore_transpile_errors.equals("true")) {
2563         println("IGNORING TRANSPILE ERRORS")
2564         println("See eclipse transpile log file '${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}'")
2565       } else {
2566         throw new GradleException("Error during transpilation:\n${stderr}\nSee eclipse transpile log file '${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}'")
2567       }
2568     }
2569   }
2570
2571   inputs.dir("${jalviewDir}/${sourceDir}")
2572   outputs.dir("${jalviewDir}/${jalviewjsTransferSiteJsDir}")
2573   outputs.upToDateWhen( { file("${jalviewDir}/${jalviewjsTransferSiteJsDir}${jalviewjs_server_resource}").exists() } )
2574 }
2575
2576
2577 def jalviewjsCallCore(String name, FileCollection list, String prefixFile, String suffixFile, String jsfile, String zjsfile, File logOutFile, Boolean logOutConsole) {
2578
2579   def stdout = new ByteArrayOutputStream()
2580   def stderr = new ByteArrayOutputStream()
2581
2582   def coreFile = file(jsfile)
2583   def msg = ""
2584   msg = "Creating core for ${name}...\nGenerating ${jsfile}"
2585   println(msg)
2586   logOutFile.createNewFile()
2587   logOutFile.append(msg+"\n")
2588
2589   def coreTop = file(prefixFile)
2590   def coreBottom = file(suffixFile)
2591   coreFile.getParentFile().mkdirs()
2592   coreFile.createNewFile()
2593   coreFile.write( coreTop.getText("UTF-8") )
2594   list.each {
2595     f ->
2596     if (f.exists()) {
2597       def t = f.getText("UTF-8")
2598       t.replaceAll("Clazz\\.([^_])","Clazz_${1}")
2599       coreFile.append( t )
2600     } else {
2601       msg = "...file '"+f.getPath()+"' does not exist, skipping"
2602       println(msg)
2603       logOutFile.append(msg+"\n")
2604     }
2605   }
2606   coreFile.append( coreBottom.getText("UTF-8") )
2607
2608   msg = "Generating ${zjsfile}"
2609   println(msg)
2610   logOutFile.append(msg+"\n")
2611   def logOutFOS = new FileOutputStream(logOutFile, true) // true == append
2612   def logErrFOS = logOutFOS
2613
2614   javaexec {
2615     classpath = files(["${jalviewDir}/${jalviewjs_closure_compiler}"])
2616     main = "com.google.javascript.jscomp.CommandLineRunner"
2617     jvmArgs = [ "-Dfile.encoding=UTF-8" ]
2618     args = [ "--compilation_level", "SIMPLE_OPTIMIZATIONS", "--warning_level", "QUIET", "--charset", "UTF-8", "--js", jsfile, "--js_output_file", zjsfile ]
2619     maxHeapSize = "2g"
2620
2621     msg = "\nRunning '"+commandLine.join(' ')+"'\n"
2622     println(msg)
2623     logOutFile.append(msg+"\n")
2624
2625     if (logOutConsole) {
2626       standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
2627         new org.apache.tools.ant.util.TeeOutputStream(
2628           logOutFOS,
2629           stdout),
2630         standardOutput)
2631         errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
2632           new org.apache.tools.ant.util.TeeOutputStream(
2633             logErrFOS,
2634             stderr),
2635           errorOutput)
2636     } else {
2637       standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
2638         logOutFOS,
2639         stdout)
2640         errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
2641           logErrFOS,
2642           stderr)
2643     }
2644   }
2645   msg = "--"
2646   println(msg)
2647   logOutFile.append(msg+"\n")
2648 }
2649
2650
2651 task jalviewjsBuildAllCores {
2652   group "JalviewJS"
2653   description "Build the core js lib closures listed in the classlists dir"
2654   dependsOn jalviewjsTranspile
2655   dependsOn jalviewjsTransferUnzipSwingJs
2656
2657   def j2sDir = "${jalviewDir}/${jalviewjsTransferSiteJsDir}/${jalviewjs_j2s_subdir}"
2658   def swingJ2sDir = "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}/${jalviewjs_j2s_subdir}"
2659   def libJ2sDir = "${jalviewDir}/${jalviewjsTransferSiteLibDir}/${jalviewjs_j2s_subdir}"
2660   def jsDir = "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}/${jalviewjs_js_subdir}"
2661   def outputDir = "${jalviewDir}/${jalviewjsTransferSiteCoreDir}/${jalviewjs_j2s_subdir}/core"
2662   def prefixFile = "${jsDir}/core/coretop2.js"
2663   def suffixFile = "${jsDir}/core/corebottom2.js"
2664
2665   inputs.file prefixFile
2666   inputs.file suffixFile
2667
2668   def classlistFiles = []
2669   // add the classlists found int the jalviewjs_classlists_dir
2670   fileTree(dir: "${jalviewDir}/${jalviewjs_classlists_dir}", include: "*.txt").each {
2671     file ->
2672     def name = file.getName() - ".txt"
2673     classlistFiles += [
2674       'file': file,
2675       'name': name
2676     ]
2677   }
2678
2679   // _jmol and _jalview cores. Add any other peculiar classlist.txt files here
2680   //classlistFiles += [ 'file': file("${jalviewDir}/${jalviewjs_classlist_jmol}"), 'name': "_jvjmol" ]
2681   classlistFiles += [ 'file': file("${jalviewDir}/${jalviewjs_classlist_jalview}"), 'name': jalviewjsJalviewCoreName ]
2682
2683   jalviewjsCoreClasslists = []
2684
2685   classlistFiles.each {
2686     hash ->
2687
2688     def file = hash['file']
2689     if (! file.exists()) {
2690       //println("...classlist file '"+file.getPath()+"' does not exist, skipping")
2691       return false // this is a "continue" in groovy .each closure
2692     }
2693     def name = hash['name']
2694     if (name == null) {
2695       name = file.getName() - ".txt"
2696     }
2697
2698     def filelist = []
2699     file.eachLine {
2700       line ->
2701         filelist += line
2702     }
2703     def list = fileTree(dir: j2sDir, includes: filelist)
2704
2705     def jsfile = "${outputDir}/core${name}.js"
2706     def zjsfile = "${outputDir}/core${name}.z.js"
2707
2708     jalviewjsCoreClasslists += [
2709       'jsfile': jsfile,
2710       'zjsfile': zjsfile,
2711       'list': list,
2712       'name': name
2713     ]
2714
2715     inputs.file(file)
2716     inputs.files(list)
2717     outputs.file(jsfile)
2718     outputs.file(zjsfile)
2719   }
2720   
2721   // _stevesoft core. add any cores without a classlist here (and the inputs and outputs)
2722   def stevesoftClasslistName = "_stevesoft"
2723   def stevesoftClasslist = [
2724     'jsfile': "${outputDir}/core${stevesoftClasslistName}.js",
2725     'zjsfile': "${outputDir}/core${stevesoftClasslistName}.z.js",
2726     'list': fileTree(dir: j2sDir, include: "com/stevesoft/pat/**/*.js"),
2727     'name': stevesoftClasslistName
2728   ]
2729   jalviewjsCoreClasslists += stevesoftClasslist
2730   inputs.files(stevesoftClasslist['list'])
2731   outputs.file(stevesoftClasslist['jsfile'])
2732   outputs.file(stevesoftClasslist['zjsfile'])
2733
2734   // _all core
2735   def allClasslistName = "_all"
2736   def allJsFiles = fileTree(dir: j2sDir, include: "**/*.js")
2737   allJsFiles += fileTree(
2738     dir: libJ2sDir,
2739     include: "**/*.js",
2740     excludes: [
2741       // these exlusions are files that the closure-compiler produces errors for. Should fix them
2742       "**/org/jmol/jvxl/readers/IsoIntersectFileReader.js",
2743       "**/org/jmol/export/JSExporter.js"
2744     ]
2745   )
2746   allJsFiles += fileTree(
2747     dir: swingJ2sDir,
2748     include: "**/*.js",
2749     excludes: [
2750       // these exlusions are files that the closure-compiler produces errors for. Should fix them
2751       "**/sun/misc/Unsafe.js",
2752       "**/swingjs/jquery/jquery-editable-select.js",
2753       "**/swingjs/jquery/j2sComboBox.js",
2754       "**/sun/misc/FloatingDecimal.js"
2755     ]
2756   )
2757   def allClasslist = [
2758     'jsfile': "${outputDir}/core${allClasslistName}.js",
2759     'zjsfile': "${outputDir}/core${allClasslistName}.z.js",
2760     'list': allJsFiles,
2761     'name': allClasslistName
2762   ]
2763   // not including this version of "all" core at the moment
2764   //jalviewjsCoreClasslists += allClasslist
2765   inputs.files(allClasslist['list'])
2766   outputs.file(allClasslist['jsfile'])
2767   outputs.file(allClasslist['zjsfile'])
2768
2769   doFirst {
2770     def logOutFile = file("${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_j2s_closure_stdout}")
2771     logOutFile.getParentFile().mkdirs()
2772     logOutFile.createNewFile()
2773     logOutFile.write(getDate("yyyy-MM-dd HH:mm:ss")+" jalviewjsBuildAllCores\n----\n")
2774
2775     jalviewjsCoreClasslists.each {
2776       jalviewjsCallCore(it.name, it.list, prefixFile, suffixFile, it.jsfile, it.zjsfile, logOutFile, jalviewjs_j2s_to_console.equals("true"))
2777     }
2778   }
2779
2780 }
2781
2782
2783 def jalviewjsPublishCoreTemplate(String coreName, String templateName, File inputFile, String outputFile) {
2784   copy {
2785     from inputFile
2786     into file(outputFile).getParentFile()
2787     rename { filename ->
2788       if (filename.equals(inputFile.getName())) {
2789         return file(outputFile).getName()
2790       }
2791       return null
2792     }
2793     filter(ReplaceTokens,
2794       beginToken: '_',
2795       endToken: '_',
2796       tokens: [
2797         'MAIN': '"'+main_class+'"',
2798         'CODE': "null",
2799         'NAME': jalviewjsJalviewTemplateName+" [core ${coreName}]",
2800         'COREKEY': jalviewjs_core_key,
2801         'CORENAME': coreName
2802       ]
2803     )
2804   }
2805 }
2806
2807
2808 task jalviewjsPublishCoreTemplates {
2809   dependsOn jalviewjsBuildAllCores
2810   def inputFileName = "${jalviewDir}/${j2s_coretemplate_html}"
2811   def inputFile = file(inputFileName)
2812   def outputDir = "${jalviewDir}/${jalviewjsTransferSiteCoreDir}"
2813
2814   def outputFiles = []
2815   jalviewjsCoreClasslists.each { cl ->
2816     def outputFile = "${outputDir}/${jalviewjsJalviewTemplateName}_${cl.name}.html"
2817     cl['outputfile'] = outputFile
2818     outputFiles += outputFile
2819   }
2820
2821   doFirst {
2822     jalviewjsCoreClasslists.each { cl ->
2823       jalviewjsPublishCoreTemplate(cl.name, jalviewjsJalviewTemplateName, inputFile, cl.outputfile)
2824     }
2825   }
2826   inputs.file(inputFile)
2827   outputs.files(outputFiles)
2828 }
2829
2830
2831 task jalviewjsSyncCore (type: Sync) {
2832   dependsOn jalviewjsBuildAllCores
2833   dependsOn jalviewjsPublishCoreTemplates
2834   def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjsTransferSiteCoreDir}")
2835   def outputDir = "${jalviewDir}/${jalviewjsSiteDir}"
2836
2837   from inputFiles
2838   into outputDir
2839   def outputFiles = []
2840   rename { filename ->
2841     outputFiles += "${outputDir}/${filename}"
2842     null
2843   }
2844   preserve {
2845     include "**"
2846   }
2847   outputs.files outputFiles
2848   inputs.files inputFiles
2849 }
2850
2851
2852 // this Copy version of TransferSiteJs will delete anything else in the target dir
2853 task jalviewjsCopyTransferSiteJs(type: Copy) {
2854   dependsOn jalviewjsTranspile
2855   from "${jalviewDir}/${jalviewjsTransferSiteJsDir}"
2856   into "${jalviewDir}/${jalviewjsSiteDir}"
2857 }
2858
2859
2860 // this Sync version of TransferSite is used by buildship to keep the website automatically up to date when a file changes
2861 task jalviewjsSyncTransferSiteJs(type: Sync) {
2862   from "${jalviewDir}/${jalviewjsTransferSiteJsDir}"
2863   include "**/*.*"
2864   into "${jalviewDir}/${jalviewjsSiteDir}"
2865   preserve {
2866     include "**"
2867   }
2868 }
2869
2870
2871 jalviewjsSyncAllLibs.mustRunAfter jalviewjsCopyTransferSiteJs
2872 jalviewjsSyncResources.mustRunAfter jalviewjsCopyTransferSiteJs
2873 jalviewjsSyncSiteResources.mustRunAfter jalviewjsCopyTransferSiteJs
2874 jalviewjsSyncBuildProperties.mustRunAfter jalviewjsCopyTransferSiteJs
2875
2876 jalviewjsSyncAllLibs.mustRunAfter jalviewjsSyncTransferSiteJs
2877 jalviewjsSyncResources.mustRunAfter jalviewjsSyncTransferSiteJs
2878 jalviewjsSyncSiteResources.mustRunAfter jalviewjsSyncTransferSiteJs
2879 jalviewjsSyncBuildProperties.mustRunAfter jalviewjsSyncTransferSiteJs
2880
2881
2882 task jalviewjsPrepareSite {
2883   group "JalviewJS"
2884   description "Prepares the website folder including unzipping files and copying resources"
2885   dependsOn jalviewjsSyncAllLibs
2886   dependsOn jalviewjsSyncResources
2887   dependsOn jalviewjsSyncSiteResources
2888   dependsOn jalviewjsSyncBuildProperties
2889   dependsOn jalviewjsSyncCore
2890 }
2891
2892
2893 task jalviewjsBuildSite {
2894   group "JalviewJS"
2895   description "Builds the whole website including transpiled code"
2896   dependsOn jalviewjsCopyTransferSiteJs
2897   dependsOn jalviewjsPrepareSite
2898 }
2899
2900
2901 task cleanJalviewjsTransferSite {
2902   doFirst {
2903     delete "${jalviewDir}/${jalviewjsTransferSiteJsDir}"
2904     delete "${jalviewDir}/${jalviewjsTransferSiteLibDir}"
2905     delete "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}"
2906     delete "${jalviewDir}/${jalviewjsTransferSiteCoreDir}"
2907   }
2908 }
2909
2910
2911 task cleanJalviewjsSite {
2912   dependsOn cleanJalviewjsTransferSite
2913   doFirst {
2914     delete "${jalviewDir}/${jalviewjsSiteDir}"
2915   }
2916 }
2917
2918
2919 task jalviewjsSiteTar(type: Tar) {
2920   group "JalviewJS"
2921   description "Creates a tar.gz file for the website"
2922   dependsOn jalviewjsBuildSite
2923   def outputFilename = "jalviewjs-site-${JALVIEW_VERSION}.tar.gz"
2924   archiveFileName = outputFilename
2925
2926   compression Compression.GZIP
2927
2928   from "${jalviewDir}/${jalviewjsSiteDir}"
2929   into jalviewjs_site_dir // this is inside the tar file
2930
2931   inputs.dir("${jalviewDir}/${jalviewjsSiteDir}")
2932 }
2933
2934
2935 task jalviewjsServer {
2936   group "JalviewJS"
2937   def filename = "jalviewjsTest.html"
2938   description "Starts a webserver on localhost to test the website. See ${filename} to access local site on most recently used port."
2939   def htmlFile = "${jalviewDirAbsolutePath}/${filename}"
2940   doLast {
2941
2942     SimpleHttpFileServerFactory factory = new SimpleHttpFileServerFactory()
2943     def port = Integer.valueOf(jalviewjs_server_port)
2944     def start = port
2945     def running = false
2946     def url
2947     def jalviewjsServer
2948     while(port < start+1000 && !running) {
2949       try {
2950         def doc_root = new File("${jalviewDirAbsolutePath}/${jalviewjsSiteDir}")
2951         jalviewjsServer = factory.start(doc_root, port)
2952         running = true
2953         url = jalviewjsServer.getResourceUrl(jalviewjs_server_resource)
2954         println("SERVER STARTED with document root ${doc_root}.")
2955         println("Go to "+url+" . Run  gradle --stop  to stop (kills all gradle daemons).")
2956         println("For debug: "+url+"?j2sdebug")
2957         println("For verbose: "+url+"?j2sverbose")
2958       } catch (Exception e) {
2959         port++;
2960       }
2961     }
2962     def htmlText = """
2963       <p><a href="${url}">JalviewJS Test. &lt;${url}&gt;</a></p>
2964       <p><a href="${url}?j2sdebug">JalviewJS Test with debug. &lt;${url}?j2sdebug&gt;</a></p>
2965       <p><a href="${url}?j2sverbose">JalviewJS Test with verbose. &lt;${url}?j2sdebug&gt;</a></p>
2966       """
2967     jalviewjsCoreClasslists.each { cl ->
2968       def urlcore = jalviewjsServer.getResourceUrl(file(cl.outputfile).getName())
2969       htmlText += """
2970       <p><a href="${urlcore}">${jalviewjsJalviewTemplateName} [core ${cl.name}]. &lt;${urlcore}&gt;</a></p>
2971       """
2972       println("For core ${cl.name}: "+urlcore)
2973     }
2974
2975     file(htmlFile).text = htmlText
2976   }
2977
2978   outputs.file(htmlFile)
2979   outputs.upToDateWhen({false})
2980 }
2981
2982
2983 task cleanJalviewjsAll {
2984   group "JalviewJS"
2985   description "Delete all configuration and build artifacts to do with JalviewJS build"
2986   dependsOn cleanJalviewjsSite
2987   dependsOn jalviewjsEclipsePaths
2988   
2989   doFirst {
2990     delete "${jalviewDir}/${jalviewjsBuildDir}"
2991     delete "${jalviewDir}/${eclipse_bin_dir}"
2992     if (eclipseWorkspace != null && file(eclipseWorkspace.getAbsolutePath()+"/.metadata").exists()) {
2993       delete file(eclipseWorkspace.getAbsolutePath()+"/.metadata")
2994     }
2995     delete jalviewjsJ2sAltSettingsFileName
2996   }
2997
2998   outputs.upToDateWhen( { false } )
2999 }
3000
3001
3002 task jalviewjsIDE_checkJ2sPlugin {
3003   group "00 JalviewJS in Eclipse"
3004   description "Compare the swingjs/net.sf.j2s.core(-j11)?.jar file with the Eclipse IDE's plugin version (found in the 'dropins' dir)"
3005
3006   doFirst {
3007     def j2sPlugin = string("${jalviewDir}/${jalviewjsJ2sPlugin}")
3008     def j2sPluginFile = file(j2sPlugin)
3009     def eclipseHome = System.properties["eclipse.home.location"]
3010     if (eclipseHome == null || ! IN_ECLIPSE) {
3011       throw new StopExecutionException("Cannot find running Eclipse home from System.properties['eclipse.home.location']. Skipping J2S Plugin Check.")
3012     }
3013     def eclipseJ2sPluginDirs = [ "${eclipseHome}/dropins" ]
3014     def altPluginsDir = System.properties["org.eclipse.equinox.p2.reconciler.dropins.directory"]
3015     if (altPluginsDir != null && file(altPluginsDir).exists()) {
3016       eclipseJ2sPluginDirs += altPluginsDir
3017     }
3018     def foundPlugin = false
3019     def j2sPluginFileName = j2sPluginFile.getName()
3020     def eclipseJ2sPlugin
3021     def eclipseJ2sPluginFile
3022     eclipseJ2sPluginDirs.any { dir ->
3023       eclipseJ2sPlugin = "${dir}/${j2sPluginFileName}"
3024       eclipseJ2sPluginFile = file(eclipseJ2sPlugin)
3025       if (eclipseJ2sPluginFile.exists()) {
3026         foundPlugin = true
3027         return true
3028       }
3029     }
3030     if (!foundPlugin) {
3031       def msg = "Eclipse J2S Plugin is not installed (could not find '${j2sPluginFileName}' in\n"+eclipseJ2sPluginDirs.join("\n")+"\n)\nTry running task jalviewjsIDE_copyJ2sPlugin"
3032       System.err.println(msg)
3033       throw new StopExecutionException(msg)
3034     }
3035
3036     def digest = MessageDigest.getInstance("MD5")
3037
3038     digest.update(j2sPluginFile.text.bytes)
3039     def j2sPluginMd5 = new BigInteger(1, digest.digest()).toString(16).padLeft(32, '0')
3040
3041     digest.update(eclipseJ2sPluginFile.text.bytes)
3042     def eclipseJ2sPluginMd5 = new BigInteger(1, digest.digest()).toString(16).padLeft(32, '0')
3043      
3044     if (j2sPluginMd5 != eclipseJ2sPluginMd5) {
3045       def msg = "WARNING! Eclipse J2S Plugin '${eclipseJ2sPlugin}' is different to this commit's version '${j2sPlugin}'"
3046       System.err.println(msg)
3047       throw new StopExecutionException(msg)
3048     } else {
3049       def msg = "Eclipse J2S Plugin '${eclipseJ2sPlugin}' is the same as '${j2sPlugin}' (this is good)"
3050       println(msg)
3051     }
3052   }
3053 }
3054
3055 task jalviewjsIDE_copyJ2sPlugin {
3056   group "00 JalviewJS in Eclipse"
3057   description "Copy the swingjs/net.sf.j2s.core(-j11)?.jar file into the Eclipse IDE's 'dropins' dir"
3058
3059   doFirst {
3060     def j2sPlugin = string("${jalviewDir}/${jalviewjsJ2sPlugin}")
3061     def j2sPluginFile = file(j2sPlugin)
3062     def eclipseHome = System.properties["eclipse.home.location"]
3063     if (eclipseHome == null || ! IN_ECLIPSE) {
3064       throw new StopExecutionException("Cannot find running Eclipse home from System.properties['eclipse.home.location']. NOT copying J2S Plugin.")
3065     }
3066     def eclipseJ2sPlugin = "${eclipseHome}/dropins/${j2sPluginFile.getName()}"
3067     def eclipseJ2sPluginFile = file(eclipseJ2sPlugin)
3068     def msg = "WARNING! Copying this commit's j2s plugin '${j2sPlugin}' to Eclipse J2S Plugin '${eclipseJ2sPlugin}'\n* May require an Eclipse restart"
3069     System.err.println(msg)
3070     copy {
3071       from j2sPlugin
3072       eclipseJ2sPluginFile.getParentFile().mkdirs()
3073       into eclipseJ2sPluginFile.getParent()
3074     }
3075   }
3076 }
3077
3078
3079 task jalviewjsIDE_j2sFile {
3080   group "00 JalviewJS in Eclipse"
3081   description "Creates the .j2s file"
3082   dependsOn jalviewjsCreateJ2sSettings
3083 }
3084
3085
3086 task jalviewjsIDE_SyncCore {
3087   group "00 JalviewJS in Eclipse"
3088   description "Build the core js lib closures listed in the classlists dir and publish core html from template"
3089   dependsOn jalviewjsSyncCore
3090 }
3091
3092
3093 task jalviewjsIDE_SyncSiteAll {
3094   dependsOn jalviewjsSyncAllLibs
3095   dependsOn jalviewjsSyncResources
3096   dependsOn jalviewjsSyncSiteResources
3097   dependsOn jalviewjsSyncBuildProperties
3098 }
3099
3100
3101 cleanJalviewjsTransferSite.mustRunAfter jalviewjsIDE_SyncSiteAll
3102
3103
3104 task jalviewjsIDE_PrepareSite {
3105   group "00 JalviewJS in Eclipse"
3106   description "Sync libs and resources to site dir, but not closure cores"
3107
3108   dependsOn jalviewjsIDE_SyncSiteAll
3109   //dependsOn cleanJalviewjsTransferSite // not sure why this clean is here -- will slow down a re-run of this task
3110 }
3111
3112
3113 task jalviewjsIDE_AssembleSite {
3114   group "00 JalviewJS in Eclipse"
3115   description "Assembles unzipped supporting zipfiles, resources, site resources and closure cores into the Eclipse transpiled site"
3116   dependsOn jalviewjsPrepareSite
3117 }
3118
3119
3120 task jalviewjsIDE_SiteClean {
3121   group "00 JalviewJS in Eclipse"
3122   description "Deletes the Eclipse transpiled site"
3123   dependsOn cleanJalviewjsSite
3124 }
3125
3126
3127 task jalviewjsIDE_Server {
3128   group "00 JalviewJS in Eclipse"
3129   description "Starts a webserver on localhost to test the website"
3130   dependsOn jalviewjsServer
3131 }
3132
3133
3134 // buildship runs this at import or gradle refresh
3135 task eclipseSynchronizationTask {
3136   //dependsOn eclipseSetup
3137   dependsOn createBuildProperties
3138   if (J2S_ENABLED) {
3139     dependsOn jalviewjsIDE_j2sFile
3140     dependsOn jalviewjsIDE_checkJ2sPlugin
3141     dependsOn jalviewjsIDE_PrepareSite
3142   }
3143 }
3144
3145
3146 // buildship runs this at build time or project refresh
3147 task eclipseAutoBuildTask {
3148   //dependsOn jalviewjsIDE_checkJ2sPlugin
3149   //dependsOn jalviewjsIDE_PrepareSite
3150 }
3151
3152
3153 task jalviewjs {
3154   group "JalviewJS"
3155   description "Build the site"
3156   dependsOn jalviewjsBuildSite
3157 }