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