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