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