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