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