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