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