JAL-3225 tasks to create extra desired settings for eclipse
[jalview.git] / build.gradle
1 import org.apache.tools.ant.filters.ReplaceTokens
2 import org.gradle.internal.os.OperatingSystem
3 import org.gradle.plugins.ide.internal.generator.PropertiesPersistableConfigurationObject
4 import org.gradle.api.internal.PropertiesTransformer
5 import org.gradle.util.ConfigureUtil
6 import org.gradle.plugins.ide.eclipse.model.Output
7 import org.gradle.plugins.ide.eclipse.model.Library
8 import java.security.MessageDigest
9 import groovy.transform.ExternalizeMethods
10 import groovy.util.XmlParser
11 import groovy.xml.XmlUtil
12
13
14 buildscript {
15   repositories {
16     mavenCentral()
17     mavenLocal()
18   }
19   dependencies {
20     classpath 'org.openclover:clover:4.4.1'
21   }
22 }
23
24
25 plugins {
26   id 'java'
27   id 'application'
28   id 'eclipse'
29   id 'com.github.johnrengelman.shadow' version '4.0.3'
30   id 'com.install4j.gradle' version '8.0.4'
31   id 'com.dorongold.task-tree' version '1.5' // only needed to display task dependency tree with  gradle task1 [task2 ...] taskTree
32 }
33
34 repositories {
35   jcenter()
36   mavenCentral()
37   mavenLocal()
38 }
39
40
41 // in ext the values are cast to Object. Ensure string values are cast as String (and not GStringImpl) for later use
42 def string(Object o) {
43   return o == null ? "" : o.toString()
44 }
45
46
47 ext {
48   jalviewDirAbsolutePath = file(jalviewDir).getAbsolutePath()
49   jalviewDirRelativePath = jalviewDir
50
51   // local build environment properties
52   // can be "projectDir/local.properties"
53   def localProps = "${projectDir}/local.properties"
54   def propsFile = null;
55   if (file(localProps).exists()) {
56     propsFile = localProps
57   }
58   // or "../projectDir_local.properties"
59   def dirLocalProps = projectDir.getParent() + "/" + projectDir.getName() + "_local.properties"
60   if (file(dirLocalProps).exists()) {
61     propsFile = dirLocalProps
62   }
63   if (propsFile != null) {
64     try {
65       def p = new Properties()
66       def localPropsFIS = new FileInputStream(propsFile)
67       p.load(localPropsFIS)
68       localPropsFIS.close()
69       p.each {
70         key, val -> 
71           def oldval = findProperty(key)
72           setProperty(key, val)
73           if (oldval != null) {
74             println("Overriding property '${key}' ('${oldval}') with ${file(propsFile).getName()} value '${val}'")
75           } else {
76             println("Setting unknown property '${key}' with ${file(propsFile).getName()}s value '${val}'")
77           }
78       }
79     } catch (Exception e) {
80       System.out.println("Exception reading local.properties")
81     }
82   }
83
84   // this property set when running Eclipse headlessly
85   j2sHeadlessBuildProperty = string("net.sf.j2s.core.headlessbuild")
86   // this property set by Eclipse
87   eclipseApplicationProperty = string("eclipse.application")
88   // CHECK IF RUNNING FROM WITHIN ECLIPSE
89   def eclipseApplicationPropertyVal = System.properties[eclipseApplicationProperty]
90   IN_ECLIPSE = eclipseApplicationPropertyVal != null && eclipseApplicationPropertyVal.startsWith("org.eclipse.ui.")
91   // BUT WITHOUT THE HEADLESS BUILD PROPERTY SET
92   if (System.properties[j2sHeadlessBuildProperty].equals("true")) {
93     println("Setting IN_ECLIPSE to ${IN_ECLIPSE} as System.properties['${j2sHeadlessBuildProperty}'] == '${System.properties[j2sHeadlessBuildProperty]}'")
94     IN_ECLIPSE = false
95   }
96   if (IN_ECLIPSE) {
97     println("WITHIN ECLIPSE IDE")
98   } else {
99     println("HEADLESS BUILD")
100   }
101   
102   J2S_ENABLED = (project.hasProperty('j2s.compiler.status') && project['j2s.compiler.status'] != null && project['j2s.compiler.status'] == "enable")
103   if (J2S_ENABLED) {
104     println("J2S ENABLED")
105   }
106   
107   /* *-/
108   System.properties.sort { it.key }.each {
109     key, val -> println("SYSTEM PROPERTY ${key}='${val}'")
110   }
111   /-* *-/
112   if (false && IN_ECLIPSE) {
113     jalviewDir = jalviewDirAbsolutePath
114   }
115   */
116
117   // essentials
118   bareSourceDir = string(source_dir)
119   sourceDir = string("${jalviewDir}/${bareSourceDir}")
120   resourceDir = string("${jalviewDir}/${resource_dir}")
121   bareTestSourceDir = string(test_source_dir)
122   testSourceDir = string("${jalviewDir}/${bareTestSourceDir}")
123
124   // clover
125   cloverInstrDir = file("${buildDir}/${cloverSourcesInstrDir}")
126   cloverDb = string("${buildDir}/clover/clover.db")
127   classesDir = string("${jalviewDir}/${classes_dir}")
128   if (clover.equals("true")) {
129     use_clover = true
130     classesDir = string("${buildDir}/${cloverClassesDir}")
131   } else {
132     use_clover = false
133     classesDir = string("${jalviewDir}/${classes_dir}")
134   }
135
136   classes = classesDir
137
138   getdownWebsiteDir = string("${jalviewDir}/${getdown_website_dir}/${JAVA_VERSION}")
139   buildDist = true
140
141   // the following values might be overridden by the CHANNEL switch
142   getdownChannelName = CHANNEL.toLowerCase()
143   getdownDir = string("${getdownChannelName}/${JAVA_VERSION}")
144   getdownAppBase = string("${getdown_channel_base}/${getdownDir}")
145   getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher}")
146   getdownAppDistDir = getdown_app_dir_alt
147   buildProperties = string("${resourceDir}/${build_properties_file}")
148   reportRsyncCommand = false
149   jvlChannelName = CHANNEL.toLowerCase()
150   switch (CHANNEL) {
151
152     case "BUILD":
153     // TODO: get bamboo build artifact URL for getdown artifacts
154     getdown_channel_base = bamboo_channelbase
155     getdownChannelName = string("${bamboo_planKey}/${JAVA_VERSION}")
156     getdownAppBase = string("${bamboo_channelbase}/${bamboo_planKey}${bamboo_getdown_channel_suffix}/${JAVA_VERSION}")
157     jvlChannelName += "_${getdownChannelName}"
158     // automatically add the test group Not-bamboo for exclusion 
159     if ("".equals(testngExcludedGroups)) { 
160       testngExcludedGroups = "Not-bamboo"
161     }
162     break
163
164     case "RELEASE":
165     getdownAppDistDir = getdown_app_dir_release
166     reportRsyncCommand = true
167     // Don't ignore transpile errors for release build
168     if (jalviewjs_ignore_transpile_errors.equals("true")) {
169       jalviewjs_ignore_transpile_errors = "false"
170       println("Setting jalviewjs_ignore_transpile_errors to 'false'")
171     }
172     break
173
174     case "ARCHIVE":
175     getdownChannelName = CHANNEL.toLowerCase()+"/${JALVIEW_VERSION}"
176     getdownDir = string("${getdownChannelName}/${JAVA_VERSION}")
177     getdownAppBase = string("${getdown_channel_base}/${getdownDir}")
178     if (!file("${ARCHIVEDIR}/${packageDir}").exists()) {
179       throw new GradleException("Must provide an ARCHIVEDIR value to produce an archive distribution")
180     } else {
181       packageDir = string("${ARCHIVEDIR}/${packageDir}")
182       buildProperties = string("${buildDir}/archive/${build_properties_file}")
183       buildDist = false
184     }
185     reportRsyncCommand = true
186     break
187
188     case "ARCHIVELOCAL":
189     getdownChannelName = string("archive/${JALVIEW_VERSION}")
190     getdownDir = string("${getdownChannelName}/${JAVA_VERSION}")
191     getdownAppBase = file(getdownWebsiteDir).toURI().toString()
192     if (!file("${ARCHIVEDIR}/${packageDir}").exists()) {
193       throw new GradleException("Must provide an ARCHIVEDIR value to produce an archive distribution")
194     } else {
195       packageDir = string("${ARCHIVEDIR}/${packageDir}")
196       buildProperties = string("${buildDir}/archive/${build_properties_file}")
197       buildDist = false
198     }
199     reportRsyncCommand = true
200     getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher_local}")
201     break
202
203     case "DEVELOP":
204     reportRsyncCommand = true
205     break
206
207     case "TEST-RELEASE":
208     reportRsyncCommand = true
209     // Don't ignore transpile errors for release build
210     if (jalviewjs_ignore_transpile_errors.equals("true")) {
211       jalviewjs_ignore_transpile_errors = "false"
212       println("Setting jalviewjs_ignore_transpile_errors to 'false'")
213     }
214     break
215
216     case ~/^SCRATCH(|-[-\w]*)$/:
217     getdownChannelName = CHANNEL
218     getdownDir = string("${getdownChannelName}/${JAVA_VERSION}")
219     getdownAppBase = string("${getdown_channel_base}/${getdownDir}")
220     reportRsyncCommand = true
221     break
222
223     case "TEST-LOCAL":
224     if (!file("${LOCALDIR}").exists()) {
225       throw new GradleException("Must provide a LOCALDIR value to produce a local distribution")
226     } else {
227       getdownAppBase = file(file("${LOCALDIR}").getAbsolutePath()).toURI().toString()
228       getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher_local}")
229     }
230     break
231
232     case "LOCAL":
233     getdownAppBase = file(getdownWebsiteDir).toURI().toString()
234     getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher_local}")
235     break
236
237     default: // something wrong specified
238     throw new GradleException("CHANNEL must be one of BUILD, RELEASE, ARCHIVE, DEVELOP, TEST-RELEASE, SCRATCH-..., LOCAL [default]")
239     break
240
241   }
242   // override getdownAppBase if requested
243   if (findProperty("getdown_appbase_override") != null) {
244     getdownAppBase = string(getProperty("getdown_appbase_override"))
245     println("Overriding getdown appbase with '${getdownAppBase}'")
246   }
247   // sanitise file name for jalview launcher file for this channel
248   jvlChannelName = jvlChannelName.replaceAll(/[^\w\-]/,"_")
249
250   getdownAppDir = string("${getdownWebsiteDir}/${getdownAppDistDir}")
251   //getdownJ11libDir = "${getdownWebsiteDir}/${getdown_j11lib_dir}"
252   getdownResourceDir = string("${getdownWebsiteDir}/${getdown_resource_dir}")
253   getdownInstallDir = string("${getdownWebsiteDir}/${getdown_install_dir}")
254   getdownFilesDir = string("${jalviewDir}/${getdown_files_dir}/${JAVA_VERSION}/")
255   getdownFilesInstallDir = string("${getdownFilesDir}/${getdown_install_dir}")
256   /* compile without modules -- using classpath libraries
257   modules_compileClasspath = fileTree(dir: "${jalviewDir}/${j11modDir}", include: ["*.jar"])
258   modules_runtimeClasspath = modules_compileClasspath
259   */
260   gitHash = string("")
261   gitBranch = string("")
262
263   println("Using a ${CHANNEL} profile.")
264
265   additional_compiler_args = []
266   // configure classpath/args for j8/j11 compilation
267   if (JAVA_VERSION.equals("1.8")) {
268     JAVA_INTEGER_VERSION = string("8")
269     //libDir = j8libDir
270     libDir = j11libDir
271     libDistDir = j8libDir
272     compile_source_compatibility = 1.8
273     compile_target_compatibility = 1.8
274     // these are getdown.txt properties defined dependent on the JAVA_VERSION
275     getdownAltJavaMinVersion = string(findProperty("getdown_alt_java8_min_version"))
276     getdownAltJavaMaxVersion = string(findProperty("getdown_alt_java8_max_version"))
277     // this property is assigned below and expanded to multiple lines in the getdown task
278     getdownAltMultiJavaLocation = string(findProperty("getdown_alt_java8_txt_multi_java_location"))
279     // this property is for the Java library used in eclipse
280     eclipseJavaRuntimeName = string("JavaSE-1.8")
281   } else if (JAVA_VERSION.equals("11")) {
282     JAVA_INTEGER_VERSION = string("11")
283     libDir = j11libDir
284     libDistDir = j11libDir
285     compile_source_compatibility = 11
286     compile_target_compatibility = 11
287     getdownAltJavaMinVersion = string(findProperty("getdown_alt_java11_min_version"))
288     getdownAltJavaMaxVersion = string(findProperty("getdown_alt_java11_max_version"))
289     getdownAltMultiJavaLocation = string(findProperty("getdown_alt_java11_txt_multi_java_location"))
290     eclipseJavaRuntimeName = string("JavaSE-11")
291     /* compile without modules -- using classpath libraries
292     additional_compiler_args += [
293     '--module-path', modules_compileClasspath.asPath,
294     '--add-modules', j11modules
295     ]
296      */
297   } else if (JAVA_VERSION.equals("12") || JAVA_VERSION.equals("13")) {
298     JAVA_INTEGER_VERSION = JAVA_VERSION
299     libDir = j11libDir
300     libDistDir = j11libDir
301     compile_source_compatibility = JAVA_VERSION
302     compile_target_compatibility = JAVA_VERSION
303     getdownAltJavaMinVersion = string(findProperty("getdown_alt_java11_min_version"))
304     getdownAltJavaMaxVersion = string(findProperty("getdown_alt_java11_max_version"))
305     getdownAltMultiJavaLocation = string(findProperty("getdown_alt_java11_txt_multi_java_location"))
306     eclipseJavaRuntimeName = string("JavaSE-11")
307     /* compile without modules -- using classpath libraries
308     additional_compiler_args += [
309     '--module-path', modules_compileClasspath.asPath,
310     '--add-modules', j11modules
311     ]
312      */
313   } else {
314     throw new GradleException("JAVA_VERSION=${JAVA_VERSION} not currently supported by Jalview")
315   }
316
317
318   // for install4j
319   JAVA_MIN_VERSION = JAVA_VERSION
320   JAVA_MAX_VERSION = JAVA_VERSION
321   def jreInstallsDir = string(jre_installs_dir)
322   if (jreInstallsDir.startsWith("~/")) {
323     jreInstallsDir = System.getProperty("user.home") + jreInstallsDir.substring(1)
324   }
325   macosJavaVMDir = string("${jreInstallsDir}/jre-${JAVA_INTEGER_VERSION}-mac-x64/jre")
326   macosJavaVMTgz = string("${jreInstallsDir}/tgz/jre-${JAVA_INTEGER_VERSION}-mac-x64.tar.gz")
327   windowsJavaVMDir = string("${jreInstallsDir}/jre-${JAVA_INTEGER_VERSION}-windows-x64/jre")
328   windowsJavaVMTgz = string("${jreInstallsDir}/tgz/jre-${JAVA_INTEGER_VERSION}-windows-x64.tar.gz")
329   linuxJavaVMDir = string("${jreInstallsDir}/jre-${JAVA_INTEGER_VERSION}-linux-x64/jre")
330   linuxJavaVMTgz = string("${jreInstallsDir}/tgz/jre-${JAVA_INTEGER_VERSION}-linux-x64.tar.gz")
331   install4jDir = string("${jalviewDir}/${install4j_utils_dir}")
332   install4jConfFileName = string("jalview-install4j-conf.install4j")
333   install4jConfFile = file("${install4jDir}/${install4jConfFileName}")
334   install4jHomeDir = install4j_home_dir
335   if (install4jHomeDir.startsWith("~/")) {
336     install4jHomeDir = System.getProperty("user.home") + install4jHomeDir.substring(1)
337   }
338
339
340
341   buildingHTML = string("${jalviewDir}/${docDir}/building.html")
342   helpFile = string("${classesDir}/${help_dir}/help.jhm")
343   helpParentDir = string("${jalviewDir}/${help_parent_dir}")
344   helpSourceDir = string("${helpParentDir}/${help_dir}")
345
346
347   relativeBuildDir = file(jalviewDirAbsolutePath).toPath().relativize(buildDir.toPath())
348   jalviewjsBuildDir = string("${relativeBuildDir}/jalviewjs")
349   jalviewjsSiteDir = string("${jalviewjsBuildDir}/${jalviewjs_site_dir}")
350   if (IN_ECLIPSE) {
351     jalviewjsTransferSiteJsDir = string(jalviewjsSiteDir)
352   } else {
353     jalviewjsTransferSiteJsDir = string("${jalviewjsBuildDir}/tmp/${jalviewjs_site_dir}_js")
354   }
355   jalviewjsTransferSiteLibDir = string("${jalviewjsBuildDir}/tmp/${jalviewjs_site_dir}_lib")
356   jalviewjsTransferSiteSwingJsDir = string("${jalviewjsBuildDir}/tmp/${jalviewjs_site_dir}_swingjs")
357   jalviewjsTransferSiteCoreDir = string("${jalviewjsBuildDir}/tmp/${jalviewjs_site_dir}_core")
358   jalviewjsJalviewCoreHtmlFile = string("")
359   jalviewjsJalviewCoreName = string(jalviewjs_core_name)
360   jalviewjsCoreClasslists = []
361   jalviewjsJalviewTemplateName = string(jalviewjs_name)
362   jalviewjsJ2sSettingsFileName = string("${jalviewDir}/${jalviewjs_j2s_settings}")
363   jalviewjsJ2sProps = null
364   jalviewjsJ2sPlugin = jalviewjs_j2s_plugin
365
366   eclipseWorkspace = null
367   eclipseBinary = string("")
368   eclipseVersion = string("")
369   eclipseDebug = false
370   // ENDEXT
371 }
372
373
374 sourceSets {
375   main {
376     java {
377       srcDirs sourceDir
378       outputDir = file(classesDir)
379     }
380
381     resources {
382       srcDirs resourceDir
383       srcDirs += helpParentDir
384     }
385
386     jar.destinationDir = file("${jalviewDir}/${packageDir}")
387
388     compileClasspath = files(sourceSets.main.java.outputDir)
389     //compileClasspath += files(sourceSets.main.resources.srcDirs)
390     compileClasspath += fileTree(dir: "${jalviewDir}/${libDir}", include: ["*.jar"])
391
392     runtimeClasspath = compileClasspath
393   }
394
395   clover {
396     java {
397       srcDirs = [ cloverInstrDir ]
398       outputDir = file("${buildDir}/${cloverClassesDir}")
399     }
400
401     resources {
402       srcDirs = sourceSets.main.resources.srcDirs
403     }
404     compileClasspath = configurations.cloverRuntime + files( sourceSets.clover.java.outputDir )
405     compileClasspath += files(sourceSets.main.java.outputDir)
406     compileClasspath += sourceSets.main.compileClasspath
407     compileClasspath += fileTree(dir: "${jalviewDir}/${utilsDir}", include: ["**/*.jar"])
408     compileClasspath += fileTree(dir: "${jalviewDir}/${libDir}", include: ["*.jar"])
409
410     runtimeClasspath = compileClasspath
411   }
412
413   test {
414     java {
415       srcDirs testSourceDir
416       outputDir = file("${jalviewDir}/${testOutputDir}")
417     }
418
419     resources {
420       srcDirs = sourceSets.main.resources.srcDirs
421     }
422
423     compileClasspath = files( sourceSets.test.java.outputDir )
424
425     if (use_clover) {
426       compileClasspath = sourceSets.clover.compileClasspath
427     } else {
428       compileClasspath += files(sourceSets.main.java.outputDir)
429     }
430
431     compileClasspath += fileTree(dir: "${jalviewDir}/${libDir}", include: ["*.jar"])
432     compileClasspath += fileTree(dir: "${jalviewDir}/${utilsDir}/testnglibs", include: ["**/*.jar"])
433     compileClasspath += fileTree(dir: "${jalviewDir}/${utilsDir}/testlibs", include: ["**/*.jar"])
434
435     runtimeClasspath = compileClasspath
436   }
437 }
438
439
440 // clover bits
441 dependencies {
442   if (use_clover) {
443     cloverCompile 'org.openclover:clover:4.4.1'
444     testCompile 'org.openclover:clover:4.4.1'
445   }
446 }
447
448
449 configurations {
450   cloverRuntime
451   cloverRuntime.extendsFrom cloverCompile
452 }
453
454
455 // eclipse project and settings files creation, also used by buildship
456 eclipse {
457   project {
458     name = eclipse_project_name
459
460     natures 'org.eclipse.jdt.core.javanature',
461     'org.eclipse.jdt.groovy.core.groovyNature',
462     'org.eclipse.buildship.core.gradleprojectnature'
463
464     buildCommand 'org.eclipse.jdt.core.javabuilder'
465     buildCommand 'org.eclipse.buildship.core.gradleprojectbuilder'
466   }
467
468   classpath {
469     //defaultOutputDir = sourceSets.main.java.outputDir
470     def removeThese = []
471     configurations.each{
472       if (it.isCanBeResolved()) {
473         removeThese += it
474       }
475     }
476
477     minusConfigurations += removeThese
478     plusConfigurations = [ ]
479     file {
480
481       whenMerged { cp ->
482         def removeTheseToo = []
483         HashMap<String, Boolean> alreadyAddedSrcPath = new HashMap<>();
484         cp.entries.each { entry ->
485           // This conditional removes all src classpathentries that a) have already been added or b) aren't "src" or "test".
486           // e.g. this removes the resources dir being copied into bin/main, bin/test AND bin/clover
487           // we add the resources and help/help dirs in as libs afterwards (see below)
488           if (entry.kind == 'src') {
489             if (alreadyAddedSrcPath.getAt(entry.path) || !(entry.path == bareSourceDir || entry.path == bareTestSourceDir)) {
490               removeTheseToo += entry
491             } else {
492               alreadyAddedSrcPath.putAt(entry.path, true)
493             }
494           }
495
496         }
497         cp.entries.removeAll(removeTheseToo)
498
499         //cp.entries += new Output("${eclipse_bin_dir}/main")
500         if (file(helpParentDir).isDirectory()) {
501           cp.entries += new Library(fileReference(helpParentDir))
502         }
503         if (file(resourceDir).isDirectory()) {
504           cp.entries += new Library(fileReference(resourceDir))
505         }
506
507         HashMap<String, Boolean> alreadyAddedLibPath = new HashMap<>();
508
509         sourceSets.main.compileClasspath.findAll { it.name.endsWith(".jar") }.any {
510           //don't want to add outputDir as eclipse is using its own output dir in bin/main
511           if (it.isDirectory() || ! it.exists()) {
512             // don't add dirs to classpath, especially if they don't exist
513             return false // groovy "continue" in .any closure
514           }
515           def itPath = it.toString()
516           if (itPath.startsWith("${jalviewDirAbsolutePath}/")) {
517             // make relative path
518             itPath = itPath.substring(jalviewDirAbsolutePath.length()+1)
519           }
520           if (alreadyAddedLibPath.get(itPath)) {
521             //println("Not adding duplicate entry "+itPath)
522           } else {
523             //println("Adding entry "+itPath)
524             cp.entries += new Library(fileReference(itPath))
525             alreadyAddedLibPath.put(itPath, true)
526           }
527         }
528
529         sourceSets.test.compileClasspath.findAll { it.name.endsWith(".jar") }.any {
530           //no longer want to add outputDir as eclipse is using its own output dir in bin/main
531           if (it.isDirectory() || ! it.exists()) {
532             // don't add dirs to classpath
533             return false // groovy "continue" in .any closure
534           }
535
536           def itPath = it.toString()
537           if (itPath.startsWith("${jalviewDirAbsolutePath}/")) {
538             itPath = itPath.substring(jalviewDirAbsolutePath.length()+1)
539           }
540           if (alreadyAddedLibPath.get(itPath)) {
541             // don't duplicate
542           } else {
543             def lib = new Library(fileReference(itPath))
544             lib.entryAttributes["test"] = "true"
545             cp.entries += lib
546             alreadyAddedLibPath.put(itPath, true)
547           }
548         }
549
550       } // whenMerged
551
552     } // file
553
554     containers 'org.eclipse.buildship.core.gradleclasspathcontainer'
555
556   } // classpath
557
558   jdt {
559     // for the IDE, use java 11 compatibility
560     sourceCompatibility = compile_source_compatibility
561     targetCompatibility = compile_target_compatibility
562     javaRuntimeName = eclipseJavaRuntimeName
563
564     // add in jalview project specific properties/preferences into eclipse core preferences
565     // and also the codestyle XML file
566     file {
567       withProperties { props ->
568         def jalview_prefs = new Properties()
569         def ins = new FileInputStream("${jalviewDirAbsolutePath}/${eclipse_extra_jdt_prefs_file}")
570         jalview_prefs.load(ins)
571         ins.close()
572         jalview_prefs.forEach { t, v ->
573           if (props.getAt(t) == null) {
574             props.putAt(t, v)
575           }
576         }
577         // codestyle file -- overrides previous formatter prefs
578         def csFile = file("${jalviewDirAbsolutePath}/${eclipse_codestyle_file}")
579         if (csFile.exists()) {
580           XmlParser parser = new XmlParser()
581           def profiles = parser.parse(csFile)
582           def profile = profiles.'profile'.find { p -> (p.'@kind' == "CodeFormatterProfile" && p.'@name' == "Jalview") }
583           if (profile != null) {
584             profile.'setting'.each { s ->
585               def id = s.'@id'
586               def value = s.'@value'
587               if (id != null && value != null) {
588                 props.putAt(id, value)
589               }
590             }
591           }
592         }
593       }
594     }
595
596   } // jdt
597
598   if (IN_ECLIPSE) {
599     // Don't want these to be activated if in headless build
600     synchronizationTasks "eclipseSynchronizationTask"
601     //autoBuildTasks "eclipseAutoBuildTask"
602
603   }
604 }
605
606
607 /* hack to change eclipse prefs in .settings files other than org.eclipse.jdt.core.prefs */
608 // Class to allow updating arbitrary properties files
609 class PropertiesFile extends PropertiesPersistableConfigurationObject {
610   public PropertiesFile(PropertiesTransformer t) { super(t); }
611   @Override protected void load(Properties properties) { }
612   @Override protected void store(Properties properties) { }
613   @Override protected String getDefaultResourceName() { return ""; }
614   // This is necessary, because PropertiesPersistableConfigurationObject fails
615   // if no default properties file exists.
616   @Override public void loadDefaults() { load(new StringBufferInputStream("")); }
617 }
618
619 // Task to update arbitrary properties files (set outputFile)
620 class PropertiesFileTask extends PropertiesGeneratorTask<PropertiesFile> {
621   private final PropertiesFileContentMerger file;
622   public PropertiesFileTask() { file = new PropertiesFileContentMerger(getTransformer()); }
623   protected PropertiesFile create() { return new PropertiesFile(getTransformer()); }
624   protected void configure(PropertiesFile props) {
625     file.getBeforeMerged().execute(props); file.getWhenMerged().execute(props);
626   }
627   public void file(Closure closure) { ConfigureUtil.configure(closure, file); }
628 }
629
630 task eclipseUIPreferences(type: PropertiesFileTask) {
631   description = "Generate Eclipse additional settings"
632   def filename = "org.eclipse.jdt.ui.prefs"
633   outputFile = "$projectDir/.settings/${filename}" as File
634   file {
635     withProperties {
636       it.load new FileInputStream("$projectDir/utils/eclipse/${filename}" as String)
637     }
638   }
639 }
640
641 task eclipseGroovyCorePreferences(type: PropertiesFileTask) {
642   description = "Generate Eclipse additional settings"
643   def filename = "org.eclipse.jdt.groovy.core.prefs"
644   outputFile = "$projectDir/.settings/${filename}" as File
645   file {
646     withProperties {
647       it.load new FileInputStream("$projectDir/utils/eclipse/${filename}" as String)
648     }
649   }
650 }
651
652 task eclipseAllPreferences {
653   dependsOn eclipseJdt
654   dependsOn eclipseUIPreferences
655   dependsOn eclipseGroovyCorePreferences
656 }
657
658 eclipseUIPreferences.mustRunAfter eclipseJdt
659 eclipseGroovyCorePreferences.mustRunAfter eclipseJdt
660
661 /* end of eclipse preferences hack */
662
663
664 task cloverInstr {
665   // only instrument source, we build test classes as normal
666   inputs.files files (sourceSets.main.allJava,sourceSets.test.allJava) // , fileTree(dir:"$jalviewDir/$testSourceDir", include: ["**/*.java"]))
667   outputs.dir cloverInstrDir
668
669   doFirst {
670     delete cloverInstrDir
671     def argsList = [
672       "--initstring",
673       cloverDb,
674       "-d",
675       cloverInstrDir.getPath(),
676     ]
677     argsList.addAll(
678       inputs.files.files.collect(
679         { file -> file.absolutePath }
680       )
681     )
682     String[] args = argsList.toArray()
683     println("About to instrument "+args.length +" files")
684     com.atlassian.clover.CloverInstr.mainImpl(args)
685   }
686 }
687
688
689 cloverClasses.dependsOn cloverInstr
690
691
692 task cloverReport {
693   group = "Verification"
694   description = "Creates the Clover report"
695   inputs.dir "${buildDir}/clover"
696   outputs.dir "${reportsDir}/clover"
697   onlyIf {
698     file(cloverDb).exists()
699   }
700   doFirst {
701     def argsList = [
702       "--initstring",
703       cloverDb,
704       "-o",
705       "${reportsDir}/clover"
706     ]
707     String[] args = argsList.toArray()
708     com.atlassian.clover.reporters.html.HtmlReporter.runReport(args)
709
710     // and generate ${reportsDir}/clover/clover.xml
711     args = [
712       "--initstring",
713       cloverDb,
714       "-o",
715       "${reportsDir}/clover/clover.xml"
716     ].toArray()
717     com.atlassian.clover.reporters.xml.XMLReporter.runReport(args)
718   }
719 }
720
721
722 compileCloverJava {
723
724   doFirst {
725     sourceCompatibility = compile_source_compatibility
726     targetCompatibility = compile_target_compatibility
727     options.compilerArgs += additional_compiler_args
728     print ("Setting target compatibility to "+targetCompatibility+"\n")
729   }
730   classpath += configurations.cloverRuntime
731 }
732
733
734 task cleanClover {
735   doFirst {
736     delete cloverInstrDir
737     delete cloverDb
738   }
739 }
740 // end clover bits
741
742
743 compileJava {
744
745   doFirst {
746     sourceCompatibility = compile_source_compatibility
747     targetCompatibility = compile_target_compatibility
748     options.compilerArgs = additional_compiler_args
749     print ("Setting target compatibility to "+targetCompatibility+"\n")
750   }
751
752 }
753
754
755 compileTestJava {
756   if (use_clover) {
757     dependsOn compileCloverJava
758     classpath += configurations.cloverRuntime
759   } else {
760     classpath += sourceSets.main.runtimeClasspath
761   }
762   doFirst {
763     sourceCompatibility = compile_source_compatibility
764     targetCompatibility = compile_target_compatibility
765     options.compilerArgs = additional_compiler_args
766     print ("Setting target compatibility to "+targetCompatibility+"\n")
767   }
768 }
769
770
771 clean {
772   doFirst {
773     delete sourceSets.main.java.outputDir
774   }
775 }
776
777
778 cleanTest {
779   dependsOn cleanClover
780   doFirst {
781     delete sourceSets.test.java.outputDir
782   }
783 }
784
785
786 // format is a string like date.format("dd MMMM yyyy")
787 def getDate(format) {
788   def date = new Date()
789   return date.format(format)
790 }
791
792
793 task setGitVals {
794   def hashStdOut = new ByteArrayOutputStream()
795   exec {
796     commandLine "git", "rev-parse", "--short", "HEAD"
797     standardOutput = hashStdOut
798     ignoreExitValue true
799   }
800
801   def branchStdOut = new ByteArrayOutputStream()
802   exec {
803     commandLine "git", "rev-parse", "--abbrev-ref", "HEAD"
804     standardOutput = branchStdOut
805     ignoreExitValue true
806   }
807
808   gitHash = hashStdOut.toString().trim()
809   gitBranch = branchStdOut.toString().trim()
810
811   outputs.upToDateWhen { false }
812 }
813
814
815 task createBuildProperties(type: WriteProperties) {
816   group = "build"
817   description = "Create the ${buildProperties} file"
818   dependsOn setGitVals
819   inputs.dir(sourceDir)
820   inputs.dir(resourceDir)
821   file(buildProperties).getParentFile().mkdirs()
822   outputFile (buildProperties)
823   // taking time specific comment out to allow better incremental builds
824   comment "--Jalview Build Details--\n"+getDate("yyyy-MM-dd HH:mm:ss")
825   //comment "--Jalview Build Details--\n"+getDate("yyyy-MM-dd")
826   property "BUILD_DATE", getDate("HH:mm:ss dd MMMM yyyy")
827   property "VERSION", JALVIEW_VERSION
828   property "INSTALLATION", INSTALLATION+" git-commit:"+gitHash+" ["+gitBranch+"]"
829   outputs.file(outputFile)
830 }
831
832
833 clean {
834   doFirst {
835     delete buildProperties
836   }
837 }
838
839
840 task cleanBuildingHTML(type: Delete) {
841   doFirst {
842     delete buildingHTML
843   }
844 }
845
846
847 task convertBuildingMD(type: Exec) {
848   dependsOn cleanBuildingHTML
849   def buildingMD = "${jalviewDir}/${docDir}/building.md"
850   def css = "${jalviewDir}/${docDir}/github.css"
851
852   def pandoc = null
853   pandoc_exec.split(",").each {
854     if (file(it.trim()).exists()) {
855       pandoc = it.trim()
856       return true
857     }
858   }
859
860   def buildtoolsPandoc = System.getProperty("user.home")+"/buildtools/pandoc/bin/pandoc"
861   if ((pandoc == null || ! file(pandoc).exists()) && file(buildtoolsPandoc).exists()) {
862     pandoc = System.getProperty("user.home")+"/buildtools/pandoc/bin/pandoc"
863   }
864
865   doFirst {
866     if (pandoc != null && file(pandoc).exists()) {
867         commandLine pandoc, '-s', '-o', buildingHTML, '--metadata', 'pagetitle="Building Jalview from Source"', '--toc', '-H', css, buildingMD
868     } else {
869         println("Cannot find pandoc. Skipping convert building.md to HTML")
870         throw new StopExecutionException("Cannot find pandoc. Skipping convert building.md to HTML")
871     }
872   }
873
874   ignoreExitValue true
875
876   inputs.file(buildingMD)
877   inputs.file(css)
878   outputs.file(buildingHTML)
879 }
880
881
882 task syncDocs(type: Sync) {
883   dependsOn convertBuildingMD
884   def syncDir = "${classesDir}/${docDir}"
885   from fileTree("${jalviewDir}/${docDir}")
886   into syncDir
887
888 }
889
890
891 task copyHelp(type: Copy) {
892   def inputDir = helpSourceDir
893   def outputDir = "${classesDir}/${help_dir}"
894   from(inputDir) {
895     exclude '**/*.gif'
896     exclude '**/*.jpg'
897     exclude '**/*.png'
898     filter(ReplaceTokens,
899       beginToken: '$$',
900       endToken: '$$',
901       tokens: [
902         'Version-Rel': JALVIEW_VERSION,
903         'Year-Rel': getDate("yyyy")
904       ]
905     )
906   }
907   from(inputDir) {
908     include '**/*.gif'
909     include '**/*.jpg'
910     include '**/*.png'
911   }
912   into outputDir
913
914   inputs.dir(inputDir)
915   outputs.files(helpFile)
916   outputs.dir(outputDir)
917 }
918
919
920 task syncLib(type: Sync) {
921   def syncDir = "${classesDir}/${libDistDir}"
922   from fileTree("${jalviewDir}/${libDistDir}")
923   into syncDir
924 }
925
926
927 task syncResources(type: Sync) {
928   dependsOn createBuildProperties
929   from resourceDir
930   include "**/*.*"
931   into "${classesDir}"
932   preserve {
933     include "**"
934   }
935 }
936
937
938 task prepare {
939   dependsOn syncResources
940   dependsOn syncDocs
941   dependsOn copyHelp
942 }
943
944
945 //testReportDirName = "test-reports" // note that test workingDir will be $jalviewDir
946 test {
947   dependsOn prepare
948   dependsOn compileJava
949   if (use_clover) {
950     dependsOn cloverInstr
951   }
952
953   if (use_clover) {
954     print("Running tests " + (use_clover?"WITH":"WITHOUT") + " clover [clover="+use_clover+"]\n")
955   }
956
957   useTestNG() {
958     includeGroups testngGroups
959     excludeGroups testngExcludedGroups
960     preserveOrder true
961     useDefaultListeners=true
962   }
963
964   maxHeapSize = "1024m"
965
966   workingDir = jalviewDir
967   //systemProperties 'clover.jar' System.properties.clover.jar
968   sourceCompatibility = compile_source_compatibility
969   targetCompatibility = compile_target_compatibility
970   jvmArgs += additional_compiler_args
971
972 }
973
974
975 task buildIndices(type: JavaExec) {
976   dependsOn copyHelp
977   classpath = sourceSets.main.compileClasspath
978   main = "com.sun.java.help.search.Indexer"
979   workingDir = "${classesDir}/${help_dir}"
980   def argDir = "html"
981   args = [ argDir ]
982   inputs.dir("${workingDir}/${argDir}")
983
984   outputs.dir("${classesDir}/doc")
985   outputs.dir("${classesDir}/help")
986   outputs.file("${workingDir}/JavaHelpSearch/DOCS")
987   outputs.file("${workingDir}/JavaHelpSearch/DOCS.TAB")
988   outputs.file("${workingDir}/JavaHelpSearch/OFFSETS")
989   outputs.file("${workingDir}/JavaHelpSearch/POSITIONS")
990   outputs.file("${workingDir}/JavaHelpSearch/SCHEMA")
991   outputs.file("${workingDir}/JavaHelpSearch/TMAP")
992 }
993
994
995 task compileLinkCheck(type: JavaCompile) {
996   options.fork = true
997   classpath = files("${jalviewDir}/${utilsDir}")
998   destinationDir = file("${jalviewDir}/${utilsDir}")
999   source = fileTree(dir: "${jalviewDir}/${utilsDir}", include: ["HelpLinksChecker.java", "BufferedLineReader.java"])
1000
1001   inputs.file("${jalviewDir}/${utilsDir}/HelpLinksChecker.java")
1002   inputs.file("${jalviewDir}/${utilsDir}/HelpLinksChecker.java")
1003   outputs.file("${jalviewDir}/${utilsDir}/HelpLinksChecker.class")
1004   outputs.file("${jalviewDir}/${utilsDir}/BufferedLineReader.class")
1005 }
1006
1007
1008 task linkCheck(type: JavaExec) {
1009   dependsOn prepare, compileLinkCheck
1010
1011   def helpLinksCheckerOutFile = file("${jalviewDir}/${utilsDir}/HelpLinksChecker.out")
1012   classpath = files("${jalviewDir}/${utilsDir}")
1013   main = "HelpLinksChecker"
1014   workingDir = jalviewDir
1015   args = [ "${classesDir}/${help_dir}", "-nointernet" ]
1016
1017   def outFOS = new FileOutputStream(helpLinksCheckerOutFile, false) // false == don't append
1018   def errFOS = outFOS
1019   standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
1020     outFOS,
1021     standardOutput)
1022   errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
1023     outFOS,
1024     errorOutput)
1025
1026   inputs.dir("${classesDir}/${help_dir}")
1027   outputs.file(helpLinksCheckerOutFile)
1028 }
1029
1030 // import the pubhtmlhelp target
1031 ant.properties.basedir = "${jalviewDir}"
1032 ant.properties.helpBuildDir = "${jalviewDirAbsolutePath}/${classes_dir}/${help_dir}"
1033 ant.importBuild "${utilsDir}/publishHelp.xml"
1034
1035
1036 task cleanPackageDir(type: Delete) {
1037   doFirst {
1038     delete fileTree(dir: "${jalviewDir}/${packageDir}", include: "*.jar")
1039   }
1040 }
1041
1042
1043 jar {
1044   dependsOn linkCheck
1045   dependsOn buildIndices
1046   dependsOn createBuildProperties
1047
1048   manifest {
1049     attributes "Main-Class": mainClass,
1050     "Permissions": "all-permissions",
1051     "Application-Name": "Jalview Desktop",
1052     "Codebase": application_codebase
1053   }
1054
1055   destinationDir = file("${jalviewDir}/${packageDir}")
1056   archiveName = rootProject.name+".jar"
1057
1058   exclude "cache*/**"
1059   exclude "*.jar"
1060   exclude "*.jar.*"
1061   exclude "**/*.jar"
1062   exclude "**/*.jar.*"
1063
1064   inputs.dir(classesDir)
1065   outputs.file("${jalviewDir}/${packageDir}/${archiveName}")
1066 }
1067
1068
1069 task copyJars(type: Copy) {
1070   from fileTree(dir: classesDir, include: "**/*.jar").files
1071   into "${jalviewDir}/${packageDir}"
1072 }
1073
1074
1075 // doing a Sync instead of Copy as Copy doesn't deal with "outputs" very well
1076 task syncJars(type: Sync) {
1077   from fileTree(dir: "${jalviewDir}/${libDistDir}", include: "**/*.jar").files
1078   into "${jalviewDir}/${packageDir}"
1079   preserve {
1080     include jar.archiveName
1081   }
1082 }
1083
1084
1085 task makeDist {
1086   group = "build"
1087   description = "Put all required libraries in dist"
1088   // order of "cleanPackageDir", "copyJars", "jar" important!
1089   jar.mustRunAfter cleanPackageDir
1090   syncJars.mustRunAfter cleanPackageDir
1091   dependsOn cleanPackageDir
1092   dependsOn syncJars
1093   dependsOn jar
1094   outputs.dir("${jalviewDir}/${packageDir}")
1095 }
1096
1097
1098 task cleanDist {
1099   dependsOn cleanPackageDir
1100   dependsOn cleanTest
1101   dependsOn clean
1102 }
1103
1104 shadowJar {
1105   group = "distribution"
1106   if (buildDist) {
1107     dependsOn makeDist
1108   }
1109   from ("${jalviewDir}/${libDistDir}") {
1110     include("*.jar")
1111   }
1112   manifest {
1113     attributes 'Implementation-Version': JALVIEW_VERSION
1114   }
1115   mainClassName = shadowJarMainClass
1116   mergeServiceFiles()
1117   classifier = "all-"+JALVIEW_VERSION+"-j"+JAVA_VERSION
1118   minimize()
1119 }
1120
1121
1122 task getdownWebsite() {
1123   group = "distribution"
1124   description = "Create the getdown minimal app folder, and website folder for this version of jalview. Website folder also used for offline app installer"
1125   if (buildDist) {
1126     dependsOn makeDist
1127   }
1128
1129   def getdownWebsiteResourceFilenames = []
1130   def getdownTextString = ""
1131   def getdownResourceDir = getdownResourceDir
1132   def getdownResourceFilenames = []
1133
1134   doFirst {
1135     // clean the getdown website and files dir before creating getdown folders
1136     delete getdownWebsiteDir
1137     delete getdownFilesDir
1138
1139     copy {
1140       from buildProperties
1141       rename(build_properties_file, getdown_build_properties)
1142       into getdownAppDir
1143     }
1144     getdownWebsiteResourceFilenames += "${getdownAppDistDir}/${getdown_build_properties}"
1145
1146     // go through properties looking for getdown_txt_...
1147     def props = project.properties.sort { it.key }
1148     if (getdownAltJavaMinVersion != null && getdownAltJavaMinVersion.length() > 0) {
1149       props.put("getdown_txt_java_min_version", getdownAltJavaMinVersion)
1150     }
1151     if (getdownAltJavaMaxVersion != null && getdownAltJavaMaxVersion.length() > 0) {
1152       props.put("getdown_txt_java_max_version", getdownAltJavaMaxVersion)
1153     }
1154     if (getdownAltMultiJavaLocation != null && getdownAltMultiJavaLocation.length() > 0) {
1155       props.put("getdown_txt_multi_java_location", getdownAltMultiJavaLocation)
1156     }
1157
1158     props.put("getdown_txt_appbase", getdownAppBase)
1159     props.each{ prop, val ->
1160       if (prop.startsWith("getdown_txt_") && val != null) {
1161         if (prop.startsWith("getdown_txt_multi_")) {
1162           def key = prop.substring(18)
1163           val.split(",").each{ v ->
1164             def line = "${key} = ${v}\n"
1165             getdownTextString += line
1166           }
1167         } else {
1168           // file values rationalised
1169           if (val.indexOf('/') > -1 || prop.startsWith("getdown_txt_resource")) {
1170             def r = null
1171             if (val.indexOf('/') == 0) {
1172               // absolute path
1173               r = file(val)
1174             } else if (val.indexOf('/') > 0) {
1175               // relative path (relative to jalviewDir)
1176               r = file( "${jalviewDir}/${val}" )
1177             }
1178             if (r.exists()) {
1179               val = "${getdown_resource_dir}/" + r.getName()
1180               getdownWebsiteResourceFilenames += val
1181               getdownResourceFilenames += r.getPath()
1182             }
1183           }
1184           if (! prop.startsWith("getdown_txt_resource")) {
1185             def line = prop.substring(12) + " = ${val}\n"
1186             getdownTextString += line
1187           }
1188         }
1189       }
1190     }
1191
1192     getdownWebsiteResourceFilenames.each{ filename ->
1193       getdownTextString += "resource = ${filename}\n"
1194     }
1195     getdownResourceFilenames.each{ filename ->
1196       copy {
1197         from filename
1198         into getdownResourceDir
1199       }
1200     }
1201
1202     def codeFiles = []
1203     fileTree(file(packageDir)).each{ f ->
1204       if (f.isDirectory()) {
1205         def files = fileTree(dir: f, include: ["*"]).getFiles()
1206         codeFiles += files
1207       } else if (f.exists()) {
1208         codeFiles += f
1209       }
1210     }
1211     codeFiles.sort().each{f ->
1212       def name = f.getName()
1213       def line = "code = ${getdownAppDistDir}/${name}\n"
1214       getdownTextString += line
1215       copy {
1216         from f.getPath()
1217         into getdownAppDir
1218       }
1219     }
1220
1221     // NOT USING MODULES YET, EVERYTHING SHOULD BE IN dist
1222     /*
1223     if (JAVA_VERSION.equals("11")) {
1224     def j11libFiles = fileTree(dir: "${jalviewDir}/${j11libDir}", include: ["*.jar"]).getFiles()
1225     j11libFiles.sort().each{f ->
1226     def name = f.getName()
1227     def line = "code = ${getdown_j11lib_dir}/${name}\n"
1228     getdownTextString += line
1229     copy {
1230     from f.getPath()
1231     into getdownJ11libDir
1232     }
1233     }
1234     }
1235      */
1236
1237     // 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.
1238     //getdownTextString += "class = " + file(getdownLauncher).getName() + "\n"
1239     getdownTextString += "resource = ${getdown_launcher_new}\n"
1240     getdownTextString += "class = ${mainClass}\n"
1241
1242     def getdown_txt = file("${getdownWebsiteDir}/getdown.txt")
1243     getdown_txt.write(getdownTextString)
1244
1245     def getdownLaunchJvl = getdown_launch_jvl_name + ( (jvlChannelName != null && jvlChannelName.length() > 0)?"-${jvlChannelName}":"" ) + ".jvl"
1246     def launchJvl = file("${getdownWebsiteDir}/${getdownLaunchJvl}")
1247     launchJvl.write("appbase="+props.get("getdown_txt_appbase"))
1248
1249     copy {
1250       from getdownLauncher
1251       rename(file(getdownLauncher).getName(), getdown_launcher_new)
1252       into getdownWebsiteDir
1253     }
1254
1255     copy {
1256       from getdownLauncher
1257       if (file(getdownLauncher).getName() != getdown_launcher) {
1258         rename(file(getdownLauncher).getName(), getdown_launcher)
1259       }
1260       into getdownWebsiteDir
1261     }
1262
1263     if (! (CHANNEL.startsWith("ARCHIVE") || CHANNEL.startsWith("DEVELOP"))) {
1264       copy {
1265         from getdown_txt
1266         from getdownLauncher
1267         from "${getdownWebsiteDir}/${getdown_build_properties}"
1268         if (file(getdownLauncher).getName() != getdown_launcher) {
1269           rename(file(getdownLauncher).getName(), getdown_launcher)
1270         }
1271         into getdownInstallDir
1272       }
1273
1274       copy {
1275         from getdownInstallDir
1276         into getdownFilesInstallDir
1277       }
1278     }
1279
1280     copy {
1281       from getdown_txt
1282       from launchJvl
1283       from getdownLauncher
1284       from "${getdownWebsiteDir}/${getdown_build_properties}"
1285       if (file(getdownLauncher).getName() != getdown_launcher) {
1286         rename(file(getdownLauncher).getName(), getdown_launcher)
1287       }
1288       into getdownFilesDir
1289     }
1290
1291     copy {
1292       from getdownResourceDir
1293       into "${getdownFilesDir}/${getdown_resource_dir}"
1294     }
1295   }
1296
1297   if (buildDist) {
1298     inputs.dir("${jalviewDir}/${packageDir}")
1299   }
1300   outputs.dir(getdownWebsiteDir)
1301   outputs.dir(getdownFilesDir)
1302 }
1303
1304
1305 // a helper task to allow getdown digest of any dir: `gradle getdownDigestDir -PDIGESTDIR=/path/to/my/random/getdown/dir
1306 task getdownDigestDir(type: JavaExec) {
1307   def digestDirPropertyName = "DIGESTDIR"
1308   description = "Digest a local dir (-P${digestDirPropertyName}=...) for getdown"
1309   doFirst {
1310     classpath = files(getdownLauncher)
1311     def digestDir = findProperty(digestDirPropertyName)
1312     if (digestDir == null) {
1313       throw new GradleException("Must provide a DIGESTDIR value to produce an alternative getdown digest")
1314     }
1315     args digestDir
1316   }
1317   main = "com.threerings.getdown.tools.Digester"
1318 }
1319
1320
1321 task getdownDigest(type: JavaExec) {
1322   group = "distribution"
1323   description = "Digest the getdown website folder"
1324   dependsOn getdownWebsite
1325   doFirst {
1326     classpath = files(getdownLauncher)
1327   }
1328   main = "com.threerings.getdown.tools.Digester"
1329   args getdownWebsiteDir
1330   inputs.dir(getdownWebsiteDir)
1331   outputs.file("${getdownWebsiteDir}/digest2.txt")
1332 }
1333
1334
1335 task getdown() {
1336   group = "distribution"
1337   description = "Create the minimal and full getdown app folder for installers and website and create digest file"
1338   dependsOn getdownDigest
1339   doLast {
1340     if (reportRsyncCommand) {
1341       def fromDir = getdownWebsiteDir + (getdownWebsiteDir.endsWith('/')?'':'/')
1342       def toDir = "${getdown_rsync_dest}/${getdownDir}" + (getdownDir.endsWith('/')?'':'/')
1343       println "LIKELY RSYNC COMMAND:"
1344       println "mkdir -p '$toDir'\nrsync -avh --delete '$fromDir' '$toDir'"
1345       if (RUNRSYNC == "true") {
1346         exec {
1347           commandLine "mkdir", "-p", toDir
1348         }
1349         exec {
1350           commandLine "rsync", "-avh", "--delete", fromDir, toDir
1351         }
1352       }
1353     }
1354   }
1355 }
1356
1357
1358 clean {
1359   doFirst {
1360     delete getdownWebsiteDir
1361     delete getdownFilesDir
1362   }
1363 }
1364
1365
1366 install4j {
1367   if (file(install4jHomeDir).exists()) {
1368     // good to go!
1369   } else if (file(System.getProperty("user.home")+"/buildtools/install4j").exists()) {
1370     install4jHomeDir = System.getProperty("user.home")+"/buildtools/install4j"
1371   } else if (file("/Applications/install4j.app/Contents/Resources/app").exists()) {
1372     install4jHomeDir = "/Applications/install4j.app/Contents/Resources/app"
1373   }
1374   installDir(file(install4jHomeDir))
1375
1376   mediaTypes = Arrays.asList(install4j_media_types.split(","))
1377 }
1378
1379
1380 task copyInstall4jTemplate {
1381   def install4jTemplateFile = file("${install4jDir}/${install4j_template}")
1382   def install4jFileAssociationsFile = file("${install4jDir}/${install4j_installer_file_associations}")
1383   inputs.file(install4jTemplateFile)
1384   inputs.file(install4jFileAssociationsFile)
1385   outputs.file(install4jConfFile)
1386
1387   doLast {
1388     def install4jConfigXml = new XmlParser().parse(install4jTemplateFile)
1389
1390     // turn off code signing if no OSX_KEYPASS
1391     if (OSX_KEYPASS == "") {
1392       install4jConfigXml.'**'.codeSigning.each { codeSigning ->
1393         codeSigning.'@macEnabled' = "false"
1394       }
1395       install4jConfigXml.'**'.windows.each { windows ->
1396         windows.'@runPostProcessor' = "false"
1397       }
1398     }
1399
1400     // turn off checksum creation for LOCAL channel
1401     def e = install4jConfigXml.application[0]
1402     if (CHANNEL == "LOCAL") {
1403       e.'@createChecksums' = "false"
1404     } else {
1405       e.'@createChecksums' = "true"
1406     }
1407
1408     // put file association actions where placeholder action is
1409     def install4jFileAssociationsText = install4jFileAssociationsFile.text
1410     def fileAssociationActions = new XmlParser().parseText("<actions>${install4jFileAssociationsText}</actions>")
1411     install4jConfigXml.'**'.action.any { a ->
1412       if (a.'@name' == 'EXTENSIONS_REPLACED_BY_GRADLE') {
1413         def parent = a.parent()
1414         parent.remove(a)
1415         fileAssociationActions.each { faa ->
1416             parent.append(faa)
1417         }
1418         // don't need to continue in .any loop once replacements have been made
1419         return true
1420       }
1421     }
1422
1423     // write install4j file
1424     install4jConfFile.text = XmlUtil.serialize(install4jConfigXml)
1425   }
1426 }
1427
1428
1429 clean {
1430   doFirst {
1431     delete install4jConfFile
1432   }
1433 }
1434
1435
1436 task installers(type: com.install4j.gradle.Install4jTask) {
1437   group = "distribution"
1438   description = "Create the install4j installers"
1439   dependsOn setGitVals
1440   dependsOn getdown
1441   dependsOn copyInstall4jTemplate
1442
1443   projectFile = install4jConfFile
1444
1445   // create an md5 for the input files to use as version for install4j conf file
1446   def digest = MessageDigest.getInstance("MD5")
1447   digest.update(
1448     (file("${install4jDir}/${install4j_template}").text + 
1449     file("${install4jDir}/${install4j_info_plist_file_associations}").text +
1450     file("${install4jDir}/${install4j_installer_file_associations}").text).bytes)
1451   def filesMd5 = new BigInteger(1, digest.digest()).toString(16)
1452   if (filesMd5.length() >= 8) {
1453     filesMd5 = filesMd5.substring(0,8)
1454   }
1455   def install4jTemplateVersion = "${JALVIEW_VERSION}_F${filesMd5}_C${gitHash}"
1456   // make install4jBuildDir relative to jalviewDir
1457   def install4jBuildDir = "${install4j_build_dir}/${JAVA_VERSION}"
1458
1459   variables = [
1460     'JALVIEW_NAME': getdown_txt_title,
1461     'JALVIEW_DIR': "../..",
1462     'OSX_KEYSTORE': OSX_KEYSTORE,
1463     'JSIGN_SH': JSIGN_SH,
1464     'JRE_DIR': getdown_app_dir_java,
1465     'INSTALLER_TEMPLATE_VERSION': install4jTemplateVersion,
1466     'JALVIEW_VERSION': JALVIEW_VERSION,
1467     'JAVA_MIN_VERSION': JAVA_MIN_VERSION,
1468     'JAVA_MAX_VERSION': JAVA_MAX_VERSION,
1469     'JAVA_VERSION': JAVA_VERSION,
1470     'JAVA_INTEGER_VERSION': JAVA_INTEGER_VERSION,
1471     'VERSION': JALVIEW_VERSION,
1472     'MACOS_JAVA_VM_DIR': macosJavaVMDir,
1473     'WINDOWS_JAVA_VM_DIR': windowsJavaVMDir,
1474     'LINUX_JAVA_VM_DIR': linuxJavaVMDir,
1475     'MACOS_JAVA_VM_TGZ': macosJavaVMTgz,
1476     'WINDOWS_JAVA_VM_TGZ': windowsJavaVMTgz,
1477     'LINUX_JAVA_VM_TGZ': linuxJavaVMTgz,
1478     'COPYRIGHT_MESSAGE': install4j_copyright_message,
1479     'MACOS_BUNDLE_ID': install4j_macOS_bundle_id,
1480     'INSTALLER_NAME': install4j_installer_name,
1481     'INSTALL4J_UTILS_DIR': install4j_utils_dir,
1482     'GETDOWN_WEBSITE_DIR': getdown_website_dir,
1483     'GETDOWN_FILES_DIR': getdown_files_dir,
1484     'GETDOWN_RESOURCE_DIR': getdown_resource_dir,
1485     'GETDOWN_DIST_DIR': getdownAppDistDir,
1486     'GETDOWN_ALT_DIR': getdown_app_dir_alt,
1487     'GETDOWN_INSTALL_DIR': getdown_install_dir,
1488     'INFO_PLIST_FILE_ASSOCIATIONS_FILE': install4j_info_plist_file_associations,
1489     'BUILD_DIR': install4jBuildDir,
1490   ]
1491
1492   destination = "${jalviewDir}/${install4jBuildDir}"
1493   buildSelected = true
1494
1495   if (install4j_faster.equals("true") || CHANNEL.startsWith("LOCAL")) {
1496     faster = true
1497     disableSigning = true
1498   }
1499
1500   if (OSX_KEYPASS) {
1501     macKeystorePassword = OSX_KEYPASS
1502   }
1503
1504   doFirst {
1505     println("Using projectFile "+projectFile)
1506   }
1507
1508   inputs.dir(getdownWebsiteDir)
1509   inputs.file(install4jConfFile)
1510   inputs.file("${install4jDir}/${install4j_info_plist_file_associations}")
1511   inputs.dir(macosJavaVMDir)
1512   inputs.dir(windowsJavaVMDir)
1513   outputs.dir("${jalviewDir}/${install4j_build_dir}/${JAVA_VERSION}")
1514 }
1515
1516
1517 task sourceDist(type: Tar) {
1518   
1519   def VERSION_UNDERSCORES = JALVIEW_VERSION.replaceAll("\\.", "_")
1520   def outputFileName = "${project.name}_${VERSION_UNDERSCORES}.tar.gz"
1521   // cater for buildship < 3.1 [3.0.1 is max version in eclipse 2018-09]
1522   try {
1523     archiveFileName = outputFileName
1524   } catch (Exception e) {
1525     archiveName = outputFileName
1526   }
1527   
1528   compression Compression.GZIP
1529   
1530   into project.name
1531
1532   def EXCLUDE_FILES=[
1533     "build/*",
1534     "bin/*",
1535     "test-output/",
1536     "test-reports",
1537     "tests",
1538     "clover*/*",
1539     ".*",
1540     "benchmarking/*",
1541     "**/.*",
1542     "*.class",
1543     "**/*.class","$j11modDir/**/*.jar","appletlib","**/*locales",
1544     "*locales/**",
1545     "utils/InstallAnywhere",
1546     "**/*.log",
1547   ] 
1548   def PROCESS_FILES=[
1549     "AUTHORS",
1550     "CITATION",
1551     "FEATURETODO",
1552     "JAVA-11-README",
1553     "FEATURETODO",
1554     "LICENSE",
1555     "**/README",
1556     "RELEASE",
1557     "THIRDPARTYLIBS",
1558     "TESTNG",
1559     "build.gradle",
1560     "gradle.properties",
1561     "**/*.java",
1562     "**/*.html",
1563     "**/*.xml",
1564     "**/*.gradle",
1565     "**/*.groovy",
1566     "**/*.properties",
1567     "**/*.perl",
1568     "**/*.sh",
1569   ]
1570   def INCLUDE_FILES=[
1571     ".settings/org.eclipse.jdt.core.jalview.prefs",
1572   ]
1573
1574   from(jalviewDir) {
1575     exclude (EXCLUDE_FILES)
1576     include (PROCESS_FILES)
1577     filter(ReplaceTokens,
1578       beginToken: '$$',
1579       endToken: '$$',
1580       tokens: [
1581         'Version-Rel': JALVIEW_VERSION,
1582         'Year-Rel': getDate("yyyy")
1583       ]
1584     )
1585   }
1586   from(jalviewDir) {
1587     exclude (EXCLUDE_FILES)
1588     exclude (PROCESS_FILES)
1589     exclude ("appletlib")
1590     exclude ("**/*locales")
1591     exclude ("*locales/**")
1592     exclude ("utils/InstallAnywhere")
1593
1594     exclude (getdown_files_dir)
1595     exclude (getdown_website_dir)
1596
1597     // exluding these as not using jars as modules yet
1598     exclude ("${j11modDir}/**/*.jar")
1599   }
1600   from(jalviewDir) {
1601     include(INCLUDE_FILES)
1602   }
1603 //  from (jalviewDir) {
1604 //    // explicit includes for stuff that seemed to not get included
1605 //    include(fileTree("test/**/*."))
1606 //    exclude(EXCLUDE_FILES)
1607 //    exclude(PROCESS_FILES)
1608 //  }
1609 }
1610
1611
1612 task helppages {
1613   dependsOn copyHelp
1614   dependsOn pubhtmlhelp
1615   
1616   inputs.dir("${classesDir}/${help_dir}")
1617   outputs.dir("${buildDir}/distributions/${help_dir}")
1618 }
1619
1620
1621 task j2sSetHeadlessBuild {
1622   doFirst {
1623     IN_ECLIPSE = false
1624   }
1625 }
1626
1627
1628 task jalviewjsSetEclipseWorkspace {
1629   def propKey = "jalviewjs_eclipse_workspace"
1630   def propVal = null
1631   if (project.hasProperty(propKey)) {
1632     propVal = project.getProperty(propKey)
1633     if (propVal.startsWith("~/")) {
1634       propVal = System.getProperty("user.home") + propVal.substring(1)
1635     }
1636   }
1637   def propsFileName = "${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_eclipse_workspace_location_file}"
1638   def propsFile = file(propsFileName)
1639   def eclipseWsDir = propVal
1640   def props = new Properties()
1641
1642   def writeProps = true
1643   if (( eclipseWsDir == null || !file(eclipseWsDir).exists() ) && propsFile.exists()) {
1644     def ins = new FileInputStream(propsFileName)
1645     props.load(ins)
1646     ins.close()
1647     if (props.getProperty(propKey, null) != null) {
1648       eclipseWsDir = props.getProperty(propKey)
1649       writeProps = false
1650     }
1651   }
1652
1653   if (eclipseWsDir == null || !file(eclipseWsDir).exists()) {
1654     def tempDir = File.createTempDir()
1655     eclipseWsDir = tempDir.getAbsolutePath()
1656     writeProps = true
1657   }
1658   eclipseWorkspace = file(eclipseWsDir)
1659
1660   doFirst {
1661     // do not run a headless transpile when we claim to be in Eclipse
1662     if (IN_ECLIPSE) {
1663       println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
1664       throw new StopExecutionException("Not running headless transpile whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
1665     } else {
1666       println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
1667     }
1668
1669     if (writeProps) {
1670       props.setProperty(propKey, eclipseWsDir)
1671       propsFile.parentFile.mkdirs()
1672       def bytes = new ByteArrayOutputStream()
1673       props.store(bytes, null)
1674       def propertiesString = bytes.toString()
1675       propsFile.text = propertiesString
1676       print("NEW ")
1677     } else {
1678       print("EXISTING ")
1679     }
1680
1681     println("ECLIPSE WORKSPACE: "+eclipseWorkspace.getPath())
1682   }
1683
1684   //inputs.property(propKey, eclipseWsDir) // eclipseWsDir only gets set once this task runs, so will be out-of-date
1685   outputs.file(propsFileName)
1686   outputs.upToDateWhen { eclipseWorkspace.exists() && propsFile.exists() }
1687 }
1688
1689
1690 task jalviewjsEclipsePaths {
1691   def eclipseProduct
1692
1693   def eclipseRoot = jalviewjs_eclipse_root
1694   if (eclipseRoot.startsWith("~/")) {
1695     eclipseRoot = System.getProperty("user.home") + eclipseRoot.substring(1)
1696   }
1697   if (OperatingSystem.current().isMacOsX()) {
1698     eclipseRoot += "/Eclipse.app"
1699     eclipseBinary = "${eclipseRoot}/Contents/MacOS/eclipse"
1700     eclipseProduct = "${eclipseRoot}/Contents/Eclipse/.eclipseproduct"
1701   } else if (OperatingSystem.current().isWindows()) { // check these paths!!
1702     if (file("${eclipseRoot}/eclipse").isDirectory() && file("${eclipseRoot}/eclipse/.eclipseproduct").exists()) {
1703       eclipseRoot += "/eclipse.exe"
1704     }
1705     eclipseBinary = "${eclipseRoot}/eclipse"
1706     eclipseProduct = "${eclipseRoot}/.eclipseproduct"
1707   } else { // linux or unix
1708     if (file("${eclipseRoot}/eclipse").isDirectory() && file("${eclipseRoot}/eclipse/.eclipseproduct").exists()) {
1709       eclipseRoot += "/eclipse"
1710     }
1711     eclipseBinary = "${eclipseRoot}/eclipse"
1712     eclipseProduct = "${eclipseRoot}/.eclipseproduct"
1713   }
1714
1715   eclipseVersion = "4.13" // default
1716   def assumedVersion = true
1717   if (file(eclipseProduct).exists()) {
1718     def fis = new FileInputStream(eclipseProduct)
1719     def props = new Properties()
1720     props.load(fis)
1721     eclipseVersion = props.getProperty("version")
1722     fis.close()
1723     assumedVersion = false
1724   }
1725   
1726   def propKey = "eclipse_debug"
1727   eclipseDebug = (project.hasProperty(propKey) && project.getProperty(propKey).equals("true"))
1728
1729   doFirst {
1730     // do not run a headless transpile when we claim to be in Eclipse
1731     if (IN_ECLIPSE) {
1732       println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
1733       throw new StopExecutionException("Not running headless transpile whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
1734     } else {
1735       println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
1736     }
1737
1738     if (!assumedVersion) {
1739       println("ECLIPSE VERSION=${eclipseVersion}")
1740     }
1741   }
1742 }
1743
1744
1745 task printProperties {
1746   group "Debug"
1747   description "Output to console all System.properties"
1748   doFirst {
1749     System.properties.each { key, val -> System.out.println("Property: ${key}=${val}") }
1750   }
1751 }
1752
1753
1754 task eclipseSetup {
1755   dependsOn eclipseProject
1756   dependsOn eclipseClasspath
1757   dependsOn eclipseJdt
1758 }
1759
1760
1761 // this version (type: Copy) will delete anything in the eclipse dropins folder that isn't in fromDropinsDir
1762 task jalviewjsEclipseCopyDropins(type: Copy) {
1763   dependsOn jalviewjsEclipsePaths
1764
1765   def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjs_eclipse_dropins_dir}", include: "*.jar")
1766   inputFiles += file("${jalviewDir}/${jalviewjsJ2sPlugin}")
1767   def outputDir = "${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_eclipse_tmp_dropins_dir}"
1768
1769   from inputFiles
1770   into outputDir
1771 }
1772
1773
1774 // this eclipse -clean doesn't actually work
1775 task jalviewjsCleanEclipse(type: Exec) {
1776   dependsOn eclipseSetup
1777   dependsOn jalviewjsEclipsePaths
1778   dependsOn jalviewjsEclipseCopyDropins
1779
1780   executable(eclipseBinary)
1781   args(["-nosplash", "--launcher.suppressErrors", "-data", eclipseWorkspace.getPath(), "-clean", "-console", "-consoleLog"])
1782   if (eclipseDebug) {
1783     args += "-debug"
1784   }
1785   args += "-l"
1786
1787   def inputString = """exit
1788 y
1789 """
1790   def inputByteStream = new ByteArrayInputStream(inputString.getBytes())
1791   standardInput = inputByteStream
1792 }
1793
1794 /* not really working yet
1795 jalviewjsEclipseCopyDropins.finalizedBy jalviewjsCleanEclipse
1796 */
1797
1798
1799 task jalviewjsTransferUnzipSwingJs {
1800   def file_zip = "${jalviewDir}/${jalviewjs_swingjs_zip}"
1801
1802   doLast {
1803     copy {
1804       from zipTree(file_zip)
1805       into "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}"
1806     }
1807   }
1808
1809   inputs.file file_zip
1810   outputs.dir "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}"
1811 }
1812
1813
1814 task jalviewjsTransferUnzipLib {
1815   def zipFiles = fileTree(dir: "${jalviewDir}/${jalviewjs_libjs_dir}", include: "*.zip")
1816
1817   doLast {
1818     zipFiles.each { file_zip -> 
1819       copy {
1820         from zipTree(file_zip)
1821         into "${jalviewDir}/${jalviewjsTransferSiteLibDir}"
1822       }
1823     }
1824   }
1825
1826   inputs.files zipFiles
1827   outputs.dir "${jalviewDir}/${jalviewjsTransferSiteLibDir}"
1828 }
1829
1830
1831 task jalviewjsTransferUnzipAllLibs {
1832   dependsOn jalviewjsTransferUnzipSwingJs
1833   dependsOn jalviewjsTransferUnzipLib
1834 }
1835
1836
1837 task jalviewjsCreateJ2sSettings(type: WriteProperties) {
1838   group "JalviewJS"
1839   description "Create the .j2s file from the j2s.* properties"
1840
1841   jalviewjsJ2sProps = project.properties.findAll { it.key.startsWith("j2s.") }.sort { it.key }
1842   def siteDirProperty = "j2s.site.directory"
1843   def setSiteDir = false
1844   jalviewjsJ2sProps.each { prop, val ->
1845     if (val != null) {
1846       if (prop == siteDirProperty) {
1847         if (!(val.startsWith('/') || val.startsWith("file://") )) {
1848           val = "${jalviewDir}/${jalviewjsTransferSiteJsDir}/${val}"
1849         }
1850         setSiteDir = true
1851       }
1852       property(prop,val)
1853     }
1854     if (!setSiteDir) { // default site location, don't override specifically set property
1855       property(siteDirProperty,"${jalviewDirRelativePath}/${jalviewjsTransferSiteJsDir}")
1856     }
1857   }
1858   outputFile = jalviewjsJ2sSettingsFileName
1859
1860   if (! IN_ECLIPSE) {
1861     inputs.properties(jalviewjsJ2sProps)
1862     outputs.file(jalviewjsJ2sSettingsFileName)
1863   }
1864 }
1865
1866
1867 task jalviewjsEclipseSetup {
1868   dependsOn jalviewjsEclipseCopyDropins
1869   dependsOn jalviewjsSetEclipseWorkspace
1870   dependsOn jalviewjsCreateJ2sSettings
1871 }
1872
1873
1874 task jalviewjsSyncAllLibs (type: Sync) {
1875   dependsOn jalviewjsTransferUnzipAllLibs
1876   def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjsTransferSiteLibDir}")
1877   inputFiles += fileTree(dir: "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}")
1878   def outputDir = "${jalviewDir}/${jalviewjsSiteDir}"
1879
1880   from inputFiles
1881   into outputDir
1882   def outputFiles = []
1883   rename { filename ->
1884     outputFiles += "${outputDir}/${filename}"
1885     null
1886   }
1887   preserve {
1888     include "**"
1889   }
1890   outputs.files outputFiles
1891   inputs.files inputFiles
1892 }
1893
1894
1895 task jalviewjsSyncResources (type: Sync) {
1896   def inputFiles = fileTree(dir: resourceDir)
1897   def outputDir = "${jalviewDir}/${jalviewjsSiteDir}/${jalviewjs_j2s_subdir}"
1898
1899   from inputFiles
1900   into outputDir
1901   def outputFiles = []
1902   rename { filename ->
1903     outputFiles += "${outputDir}/${filename}"
1904     null
1905   }
1906   preserve {
1907     include "**"
1908   }
1909   outputs.files outputFiles
1910   inputs.files inputFiles
1911 }
1912
1913
1914 task jalviewjsSyncSiteResources (type: Sync) {
1915   def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjs_site_resource_dir}")
1916   def outputDir = "${jalviewDir}/${jalviewjsSiteDir}"
1917
1918   from inputFiles
1919   into outputDir
1920   def outputFiles = []
1921   rename { filename ->
1922     outputFiles += "${outputDir}/${filename}"
1923     null
1924   }
1925   preserve {
1926     include "**"
1927   }
1928   outputs.files outputFiles
1929   inputs.files inputFiles
1930 }
1931
1932
1933 task jalviewjsSyncBuildProperties (type: Sync) {
1934   dependsOn createBuildProperties
1935   def inputFiles = [file(buildProperties)]
1936   def outputDir = "${jalviewDir}/${jalviewjsSiteDir}/${jalviewjs_j2s_subdir}"
1937
1938   from inputFiles
1939   into outputDir
1940   def outputFiles = []
1941   rename { filename ->
1942     outputFiles += "${outputDir}/${filename}"
1943     null
1944   }
1945   preserve {
1946     include "**"
1947   }
1948   outputs.files outputFiles
1949   inputs.files inputFiles
1950 }
1951
1952
1953 task jalviewjsProjectImport(type: Exec) {
1954   dependsOn eclipseSetup
1955   dependsOn jalviewjsEclipsePaths
1956   dependsOn jalviewjsEclipseSetup
1957
1958   doFirst {
1959     // do not run a headless import when we claim to be in Eclipse
1960     if (IN_ECLIPSE) {
1961       println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
1962       throw new StopExecutionException("Not running headless import whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
1963     } else {
1964       println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
1965     }
1966   }
1967
1968   //def projdir = eclipseWorkspace.getPath()+"/.metadata/.plugins/org.eclipse.core.resources/.projects/jalview/org.eclipse.jdt.core"
1969   def projdir = eclipseWorkspace.getPath()+"/.metadata/.plugins/org.eclipse.core.resources/.projects/jalview"
1970   executable(eclipseBinary)
1971   args(["-nosplash", "--launcher.suppressErrors", "-application", "com.seeq.eclipse.importprojects.headlessimport", "-data", eclipseWorkspace.getPath(), "-import", jalviewDirAbsolutePath])
1972   if (eclipseDebug) {
1973     args += "-debug"
1974   }
1975   args += [ "--launcher.appendVmargs", "-vmargs", "-Dorg.eclipse.equinox.p2.reconciler.dropins.directory=${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_eclipse_tmp_dropins_dir}" ]
1976   if (!IN_ECLIPSE) {
1977     args += [ "-D${j2sHeadlessBuildProperty}=true" ]
1978   }
1979
1980   inputs.file("${jalviewDir}/.project")
1981   outputs.upToDateWhen { 
1982     file(projdir).exists()
1983   }
1984 }
1985
1986
1987 task jalviewjsTranspile(type: Exec) {
1988   dependsOn jalviewjsEclipseSetup 
1989   dependsOn jalviewjsProjectImport
1990   dependsOn jalviewjsEclipsePaths
1991
1992   doFirst {
1993     // do not run a headless transpile when we claim to be in Eclipse
1994     if (IN_ECLIPSE) {
1995       println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
1996       throw new StopExecutionException("Not running headless transpile whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
1997     } else {
1998       println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
1999     }
2000   }
2001
2002   executable(eclipseBinary)
2003   args(["-nosplash", "--launcher.suppressErrors", "-application", "org.eclipse.jdt.apt.core.aptBuild", "-data", eclipseWorkspace, "-${jalviewjs_eclipse_build_arg}", eclipse_project_name ])
2004   if (eclipseDebug) {
2005     args += "-debug"
2006   }
2007   args += [ "--launcher.appendVmargs", "-vmargs", "-Dorg.eclipse.equinox.p2.reconciler.dropins.directory=${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_eclipse_tmp_dropins_dir}" ]
2008   if (!IN_ECLIPSE) {
2009     args += [ "-D${j2sHeadlessBuildProperty}=true" ]
2010   }
2011
2012   def stdout
2013   def stderr
2014   doFirst {
2015     stdout = new ByteArrayOutputStream()
2016     stderr = new ByteArrayOutputStream()
2017
2018     def logOutFileName = "${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}"
2019     def logOutFile = file(logOutFileName)
2020     logOutFile.createNewFile()
2021     logOutFile.text = """ROOT: ${jalviewjs_eclipse_root}
2022 BINARY: ${eclipseBinary}
2023 VERSION: ${eclipseVersion}
2024 WORKSPACE: ${eclipseWorkspace}
2025 DEBUG: ${eclipseDebug}
2026 ----
2027 """
2028     def logOutFOS = new FileOutputStream(logOutFile, true) // true == append
2029     // combine stdout and stderr
2030     def logErrFOS = logOutFOS
2031
2032     if (jalviewjs_j2s_to_console.equals("true")) {
2033       standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
2034         new org.apache.tools.ant.util.TeeOutputStream(
2035           logOutFOS,
2036           stdout),
2037         standardOutput)
2038       errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
2039         new org.apache.tools.ant.util.TeeOutputStream(
2040           logErrFOS,
2041           stderr),
2042         errorOutput)
2043     } else {
2044       standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
2045         logOutFOS,
2046         stdout)
2047       errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
2048         logErrFOS,
2049         stderr)
2050     }
2051   }
2052
2053   doLast {
2054     if (stdout.toString().contains("Error processing ")) {
2055       // j2s did not complete transpile
2056       //throw new TaskExecutionException("Error during transpilation:\n${stderr}\nSee eclipse transpile log file '${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}'")
2057       if (jalviewjs_ignore_transpile_errors.equals("true")) {
2058         println("IGNORING TRANSPILE ERRORS")
2059         println("See eclipse transpile log file '${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}'")
2060       } else {
2061         throw new GradleException("Error during transpilation:\n${stderr}\nSee eclipse transpile log file '${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}'")
2062       }
2063     }
2064   }
2065
2066   inputs.dir("${jalviewDir}/${sourceDir}")
2067   outputs.dir("${jalviewDir}/${jalviewjsTransferSiteJsDir}")
2068   outputs.upToDateWhen( { file("${jalviewDir}/${jalviewjsTransferSiteJsDir}${jalviewjs_server_resource}").exists() } )
2069 }
2070
2071
2072 def jalviewjsCallCore(String name, FileCollection list, String prefixFile, String suffixFile, String jsfile, String zjsfile, File logOutFile, Boolean logOutConsole) {
2073
2074   def stdout = new ByteArrayOutputStream()
2075   def stderr = new ByteArrayOutputStream()
2076
2077   def coreFile = file(jsfile)
2078   def msg = ""
2079   msg = "Creating core for ${name}...\nGenerating ${jsfile}"
2080   println(msg)
2081   logOutFile.createNewFile()
2082   logOutFile.append(msg+"\n")
2083
2084   def coreTop = file(prefixFile)
2085   def coreBottom = file(suffixFile)
2086   coreFile.getParentFile().mkdirs()
2087   coreFile.createNewFile()
2088   coreFile.write( coreTop.text )
2089   list.each {
2090     f ->
2091     if (f.exists()) {
2092       def t = f.text
2093       t.replaceAll("Clazz\\.([^_])","Clazz_${1}")
2094       coreFile.append( t )
2095     } else {
2096       msg = "...file '"+f.getPath()+"' does not exist, skipping"
2097       println(msg)
2098       logOutFile.append(msg+"\n")
2099     }
2100   }
2101   coreFile.append( coreBottom.text )
2102
2103   msg = "Generating ${zjsfile}"
2104   println(msg)
2105   logOutFile.append(msg+"\n")
2106   def logOutFOS = new FileOutputStream(logOutFile, true) // true == append
2107   def logErrFOS = logOutFOS
2108
2109   javaexec {
2110     classpath = files(["${jalviewDir}/tools/closure_compiler.jar"])
2111     args = [ "--js", jsfile, "--js_output_file", zjsfile ]
2112     maxHeapSize = "2g"
2113
2114     msg = "\nRunning '"+commandLine.join(' ')+"'\n"
2115     println(msg)
2116     logOutFile.append(msg+"\n")
2117
2118     if (logOutConsole) {
2119       standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
2120         new org.apache.tools.ant.util.TeeOutputStream(
2121           logOutFOS,
2122           stdout),
2123         standardOutput)
2124         errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
2125           new org.apache.tools.ant.util.TeeOutputStream(
2126             logErrFOS,
2127             stderr),
2128           errorOutput)
2129     } else {
2130       standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
2131         logOutFOS,
2132         stdout)
2133         errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
2134           logErrFOS,
2135           stderr)
2136     }
2137   }
2138   msg = "--"
2139   println(msg)
2140   logOutFile.append(msg+"\n")
2141 }
2142
2143
2144 task jalviewjsBuildAllCores {
2145   group "JalviewJS"
2146   description "Build the core js lib closures listed in the classlists dir"
2147   dependsOn jalviewjsTranspile
2148   dependsOn jalviewjsTransferUnzipSwingJs
2149
2150   def j2sDir = "${jalviewDir}/${jalviewjsTransferSiteJsDir}/${jalviewjs_j2s_subdir}"
2151   def swingJ2sDir = "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}/${jalviewjs_j2s_subdir}"
2152   def libJ2sDir = "${jalviewDir}/${jalviewjsTransferSiteLibDir}/${jalviewjs_j2s_subdir}"
2153   def jsDir = "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}/${jalviewjs_js_subdir}"
2154   def outputDir = "${jalviewDir}/${jalviewjsTransferSiteCoreDir}/${jalviewjs_j2s_subdir}/core"
2155   def prefixFile = "${jsDir}/core/coretop2.js"
2156   def suffixFile = "${jsDir}/core/corebottom2.js"
2157
2158   inputs.file prefixFile
2159   inputs.file suffixFile
2160
2161   def classlistFiles = []
2162   // add the classlists found int the jalviewjs_classlists_dir
2163   fileTree(dir: "${jalviewDir}/${jalviewjs_classlists_dir}", include: "*.txt").each {
2164     file ->
2165     def name = file.getName() - ".txt"
2166     classlistFiles += [
2167       'file': file,
2168       'name': name
2169     ]
2170   }
2171
2172   // _jmol and _jalview cores. Add any other peculiar classlist.txt files here
2173   //classlistFiles += [ 'file': file("${jalviewDir}/${jalviewjs_classlist_jmol}"), 'name': "_jvjmol" ]
2174   classlistFiles += [ 'file': file("${jalviewDir}/${jalviewjs_classlist_jalview}"), 'name': jalviewjsJalviewCoreName ]
2175
2176   jalviewjsCoreClasslists = []
2177
2178   classlistFiles.each {
2179     hash ->
2180
2181     def file = hash['file']
2182     if (! file.exists()) {
2183       //println("...classlist file '"+file.getPath()+"' does not exist, skipping")
2184       return false // this is a "continue" in groovy .each closure
2185     }
2186     def name = hash['name']
2187     if (name == null) {
2188       name = file.getName() - ".txt"
2189     }
2190
2191     def filelist = []
2192     file.eachLine {
2193       line ->
2194         filelist += line
2195     }
2196     def list = fileTree(dir: j2sDir, includes: filelist)
2197
2198     def jsfile = "${outputDir}/core${name}.js"
2199     def zjsfile = "${outputDir}/core${name}.z.js"
2200
2201     jalviewjsCoreClasslists += [
2202       'jsfile': jsfile,
2203       'zjsfile': zjsfile,
2204       'list': list,
2205       'name': name
2206     ]
2207
2208     inputs.file(file)
2209     inputs.files(list)
2210     outputs.file(jsfile)
2211     outputs.file(zjsfile)
2212   }
2213   
2214   // _stevesoft core. add any cores without a classlist here (and the inputs and outputs)
2215   def stevesoftClasslistName = "_stevesoft"
2216   def stevesoftClasslist = [
2217     'jsfile': "${outputDir}/core${stevesoftClasslistName}.js",
2218     'zjsfile': "${outputDir}/core${stevesoftClasslistName}.z.js",
2219     'list': fileTree(dir: j2sDir, include: "com/stevesoft/pat/**/*.js"),
2220     'name': stevesoftClasslistName
2221   ]
2222   jalviewjsCoreClasslists += stevesoftClasslist
2223   inputs.files(stevesoftClasslist['list'])
2224   outputs.file(stevesoftClasslist['jsfile'])
2225   outputs.file(stevesoftClasslist['zjsfile'])
2226
2227   // _all core
2228   def allClasslistName = "_all"
2229   def allJsFiles = fileTree(dir: j2sDir, include: "**/*.js")
2230   allJsFiles += fileTree(
2231     dir: libJ2sDir,
2232     include: "**/*.js",
2233     excludes: [
2234       // these exlusions are files that the closure-compiler produces errors for. Should fix them
2235       "**/org/jmol/jvxl/readers/IsoIntersectFileReader.js",
2236       "**/org/jmol/export/JSExporter.js"
2237     ]
2238   )
2239   allJsFiles += fileTree(
2240     dir: swingJ2sDir,
2241     include: "**/*.js",
2242     excludes: [
2243       // these exlusions are files that the closure-compiler produces errors for. Should fix them
2244       "**/sun/misc/Unsafe.js",
2245       "**/swingjs/jquery/jquery-editable-select.js",
2246       "**/swingjs/jquery/j2sComboBox.js",
2247       "**/sun/misc/FloatingDecimal.js"
2248     ]
2249   )
2250   def allClasslist = [
2251     'jsfile': "${outputDir}/core${allClasslistName}.js",
2252     'zjsfile': "${outputDir}/core${allClasslistName}.z.js",
2253     'list': allJsFiles,
2254     'name': allClasslistName
2255   ]
2256   // not including this version of "all" core at the moment
2257   //jalviewjsCoreClasslists += allClasslist
2258   inputs.files(allClasslist['list'])
2259   outputs.file(allClasslist['jsfile'])
2260   outputs.file(allClasslist['zjsfile'])
2261
2262   doFirst {
2263     def logOutFile = file("${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_j2s_closure_stdout}")
2264     logOutFile.getParentFile().mkdirs()
2265     logOutFile.createNewFile()
2266     logOutFile.write(getDate("yyyy-MM-dd HH:mm:ss")+" jalviewjsBuildAllCores\n----\n")
2267
2268     jalviewjsCoreClasslists.each {
2269       jalviewjsCallCore(it.name, it.list, prefixFile, suffixFile, it.jsfile, it.zjsfile, logOutFile, jalviewjs_j2s_to_console.equals("true"))
2270     }
2271   }
2272
2273 }
2274
2275
2276 def jalviewjsPublishCoreTemplate(String coreName, String templateName, File inputFile, String outputFile) {
2277   copy {
2278     from inputFile
2279     into file(outputFile).getParentFile()
2280     rename { filename ->
2281       if (filename.equals(inputFile.getName())) {
2282         return file(outputFile).getName()
2283       }
2284       return null
2285     }
2286     filter(ReplaceTokens,
2287       beginToken: '_',
2288       endToken: '_',
2289       tokens: [
2290         'MAIN': '"'+mainClass+'"',
2291         'CODE': "null",
2292         'NAME': jalviewjsJalviewTemplateName+" [core ${coreName}]",
2293         'COREKEY': jalviewjs_core_key,
2294         'CORENAME': coreName
2295       ]
2296     )
2297   }
2298 }
2299
2300
2301 task jalviewjsPublishCoreTemplates {
2302   dependsOn jalviewjsBuildAllCores
2303   def inputFileName = "${jalviewDir}/${j2s_coretemplate_html}"
2304   def inputFile = file(inputFileName)
2305   def outputDir = "${jalviewDir}/${jalviewjsTransferSiteCoreDir}"
2306
2307   def outputFiles = []
2308   jalviewjsCoreClasslists.each { cl ->
2309     def outputFile = "${outputDir}/${jalviewjsJalviewTemplateName}_${cl.name}.html"
2310     cl['outputfile'] = outputFile
2311     outputFiles += outputFile
2312   }
2313
2314   doFirst {
2315     jalviewjsCoreClasslists.each { cl ->
2316       jalviewjsPublishCoreTemplate(cl.name, jalviewjsJalviewTemplateName, inputFile, cl.outputfile)
2317     }
2318   }
2319   inputs.file(inputFile)
2320   outputs.files(outputFiles)
2321 }
2322
2323
2324 task jalviewjsSyncCore (type: Sync) {
2325   dependsOn jalviewjsBuildAllCores
2326   dependsOn jalviewjsPublishCoreTemplates
2327   def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjsTransferSiteCoreDir}")
2328   def outputDir = "${jalviewDir}/${jalviewjsSiteDir}"
2329
2330   from inputFiles
2331   into outputDir
2332   def outputFiles = []
2333   rename { filename ->
2334     outputFiles += "${outputDir}/${filename}"
2335     null
2336   }
2337   preserve {
2338     include "**"
2339   }
2340   outputs.files outputFiles
2341   inputs.files inputFiles
2342 }
2343
2344
2345 // this Copy version of TransferSiteJs will delete anything else in the target dir
2346 task jalviewjsCopyTransferSiteJs(type: Copy) {
2347   dependsOn jalviewjsTranspile
2348   from "${jalviewDir}/${jalviewjsTransferSiteJsDir}"
2349   into "${jalviewDir}/${jalviewjsSiteDir}"
2350 }
2351
2352
2353 // this Sync version of TransferSite is used by buildship to keep the website automatically up to date when a file changes
2354 task jalviewjsSyncTransferSiteJs(type: Sync) {
2355   from "${jalviewDir}/${jalviewjsTransferSiteJsDir}"
2356   include "**/*.*"
2357   into "${jalviewDir}/${jalviewjsSiteDir}"
2358   preserve {
2359     include "**"
2360   }
2361 }
2362
2363
2364 jalviewjsSyncAllLibs.mustRunAfter jalviewjsCopyTransferSiteJs
2365 jalviewjsSyncResources.mustRunAfter jalviewjsCopyTransferSiteJs
2366 jalviewjsSyncSiteResources.mustRunAfter jalviewjsCopyTransferSiteJs
2367 jalviewjsSyncBuildProperties.mustRunAfter jalviewjsCopyTransferSiteJs
2368
2369 jalviewjsSyncAllLibs.mustRunAfter jalviewjsSyncTransferSiteJs
2370 jalviewjsSyncResources.mustRunAfter jalviewjsSyncTransferSiteJs
2371 jalviewjsSyncSiteResources.mustRunAfter jalviewjsSyncTransferSiteJs
2372 jalviewjsSyncBuildProperties.mustRunAfter jalviewjsSyncTransferSiteJs
2373
2374
2375 task jalviewjsPrepareSite {
2376   group "JalviewJS"
2377   description "Prepares the website folder including unzipping files and copying resources"
2378   dependsOn jalviewjsSyncAllLibs
2379   dependsOn jalviewjsSyncResources
2380   dependsOn jalviewjsSyncSiteResources
2381   dependsOn jalviewjsSyncBuildProperties
2382   dependsOn jalviewjsSyncCore
2383 }
2384
2385
2386 task jalviewjsBuildSite {
2387   group "JalviewJS"
2388   description "Builds the whole website including transpiled code"
2389   dependsOn jalviewjsCopyTransferSiteJs
2390   dependsOn jalviewjsPrepareSite
2391 }
2392
2393
2394 task cleanJalviewjsTransferSite {
2395   doFirst {
2396     delete "${jalviewDir}/${jalviewjsTransferSiteJsDir}"
2397     delete "${jalviewDir}/${jalviewjsTransferSiteLibDir}"
2398     delete "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}"
2399     delete "${jalviewDir}/${jalviewjsTransferSiteCoreDir}"
2400   }
2401 }
2402
2403
2404 task cleanJalviewjsSite {
2405   dependsOn cleanJalviewjsTransferSite
2406   doFirst {
2407     delete "${jalviewDir}/${jalviewjsSiteDir}"
2408   }
2409 }
2410
2411
2412 task jalviewjsSiteTar(type: Tar) {
2413   group "JalviewJS"
2414   description "Creates a tar.gz file for the website"
2415   dependsOn jalviewjsBuildSite
2416   def outputFilename = "jalviewjs-site-${JALVIEW_VERSION}.tar.gz"
2417   try {
2418     archiveFileName = outputFilename
2419   } catch (Exception e) {
2420     archiveName = outputFilename
2421   }
2422
2423   compression Compression.GZIP
2424
2425   from "${jalviewDir}/${jalviewjsSiteDir}"
2426   into jalviewjs_site_dir // this is inside the tar file
2427
2428   inputs.dir("${jalviewDir}/${jalviewjsSiteDir}")
2429 }
2430
2431
2432 task jalviewjsServer {
2433   group "JalviewJS"
2434   def filename = "jalviewjsTest.html"
2435   description "Starts a webserver on localhost to test the website. See ${filename} to access local site on most recently used port."
2436   def htmlFile = "${jalviewDirAbsolutePath}/${filename}"
2437   doLast {
2438
2439     SimpleHttpFileServerFactory factory = new SimpleHttpFileServerFactory()
2440     def port = Integer.valueOf(jalviewjs_server_port)
2441     def start = port
2442     def running = false
2443     def url
2444     def jalviewjsServer
2445     while(port < start+1000 && !running) {
2446       try {
2447         def doc_root = new File("${jalviewDirAbsolutePath}/${jalviewjsSiteDir}")
2448         jalviewjsServer = factory.start(doc_root, port)
2449         running = true
2450         url = jalviewjsServer.getResourceUrl(jalviewjs_server_resource)
2451         println("SERVER STARTED with document root ${doc_root}.")
2452         println("Go to "+url+" . Run  gradle --stop  to stop (kills all gradle daemons).")
2453         println("For debug: "+url+"?j2sdebug")
2454         println("For verbose: "+url+"?j2sverbose")
2455       } catch (Exception e) {
2456         port++;
2457       }
2458     }
2459     def htmlText = """
2460       <p><a href="${url}">JalviewJS Test. &lt;${url}&gt;</a></p>
2461       <p><a href="${url}?j2sdebug">JalviewJS Test with debug. &lt;${url}?j2sdebug&gt;</a></p>
2462       <p><a href="${url}?j2sverbose">JalviewJS Test with verbose. &lt;${url}?j2sdebug&gt;</a></p>
2463       """
2464     jalviewjsCoreClasslists.each { cl ->
2465       def urlcore = jalviewjsServer.getResourceUrl(file(cl.outputfile).getName())
2466       htmlText += """
2467       <p><a href="${urlcore}">${jalviewjsJalviewTemplateName} [core ${cl.name}]. &lt;${urlcore}&gt;</a></p>
2468       """
2469       println("For core ${cl.name}: "+urlcore)
2470     }
2471
2472     file(htmlFile).text = htmlText
2473   }
2474
2475   outputs.file(htmlFile)
2476   outputs.upToDateWhen({false})
2477 }
2478
2479
2480 task cleanJalviewjsAll {
2481   group "JalviewJS"
2482   description "Delete all configuration and build artifacts to do with JalviewJS build"
2483   dependsOn cleanJalviewjsSite
2484   dependsOn jalviewjsEclipsePaths
2485   
2486   doFirst {
2487     delete "${jalviewDir}/${jalviewjsBuildDir}"
2488     delete "${jalviewDir}/${eclipse_bin_dir}"
2489     if (eclipseWorkspace != null && file(eclipseWorkspace.getAbsolutePath()+"/.metadata").exists()) {
2490       delete file(eclipseWorkspace.getAbsolutePath()+"/.metadata")
2491     }
2492     delete "${jalviewDir}/${jalviewjs_j2s_settings}"
2493   }
2494
2495   outputs.upToDateWhen( { false } )
2496 }
2497
2498
2499 task jalviewjsIDE_checkJ2sPlugin {
2500   group "00 JalviewJS in Eclipse"
2501   description "Compare the swingjs/net.sf.j2s.core(-j11)?.jar file with the Eclipse IDE's plugin version (found in the 'dropins' dir)"
2502
2503   doFirst {
2504     def j2sPlugin = string("${jalviewDir}/${jalviewjsJ2sPlugin}")
2505     def j2sPluginFile = file(j2sPlugin)
2506     def eclipseHome = System.properties["eclipse.home.location"]
2507     if (eclipseHome == null || ! IN_ECLIPSE) {
2508       throw new StopExecutionException("Cannot find running Eclipse home from System.properties['eclipse.home.location']. Skipping J2S Plugin Check.")
2509     }
2510     def eclipseJ2sPlugin = "${eclipseHome}/dropins/${j2sPluginFile.getName()}"
2511     def eclipseJ2sPluginFile = file(eclipseJ2sPlugin)
2512     if (!eclipseJ2sPluginFile.exists()) {
2513       def msg = "Eclipse J2S Plugin is not installed (could not find '${eclipseJ2sPlugin}')\nTry running task jalviewjsIDE_copyJ2sPlugin"
2514       System.err.println(msg)
2515       throw new StopExecutionException(msg)
2516     }
2517
2518     def digest = MessageDigest.getInstance("MD5")
2519
2520     digest.update(j2sPluginFile.text.bytes)
2521     def j2sPluginMd5 = new BigInteger(1, digest.digest()).toString(16).padLeft(32, '0')
2522
2523     digest.update(eclipseJ2sPluginFile.text.bytes)
2524     def eclipseJ2sPluginMd5 = new BigInteger(1, digest.digest()).toString(16).padLeft(32, '0')
2525      
2526     if (j2sPluginMd5 != eclipseJ2sPluginMd5) {
2527       def msg = "WARNING! Eclipse J2S Plugin '${eclipseJ2sPlugin}' is different to this commit's version '${j2sPlugin}'"
2528       System.err.println(msg)
2529       throw new StopExecutionException(msg)
2530     } else {
2531       def msg = "Eclipse J2S Plugin is the same as '${j2sPlugin}' (this is good)"
2532       println(msg)
2533     }
2534   }
2535 }
2536
2537 task jalviewjsIDE_copyJ2sPlugin {
2538   group "00 JalviewJS in Eclipse"
2539   description "Copy the swingjs/net.sf.j2s.core(-j11)?.jar file into the Eclipse IDE's 'dropins' dir"
2540
2541   doFirst {
2542     def j2sPlugin = string("${jalviewDir}/${jalviewjsJ2sPlugin}")
2543     def j2sPluginFile = file(j2sPlugin)
2544     def eclipseHome = System.properties["eclipse.home.location"]
2545     if (eclipseHome == null || ! IN_ECLIPSE) {
2546       throw new StopExecutionException("Cannot find running Eclipse home from System.properties['eclipse.home.location']. NOT copying J2S Plugin.")
2547     }
2548     def eclipseJ2sPlugin = "${eclipseHome}/dropins/${j2sPluginFile.getName()}"
2549     def eclipseJ2sPluginFile = file(eclipseJ2sPlugin)
2550     def msg = "WARNING! Copying this commit's j2s plugin '${j2sPlugin}' to Eclipse J2S Plugin '${eclipseJ2sPlugin}'\n* May require an Eclipse restart"
2551     System.err.println(msg)
2552     copy {
2553       from j2sPlugin
2554       eclipseJ2sPluginFile.getParentFile().mkdirs()
2555       into eclipseJ2sPluginFile.getParent()
2556     }
2557   }
2558 }
2559
2560
2561 task jalviewjsIDE_j2sFile {
2562   group "00 JalviewJS in Eclipse"
2563   description "Creates the .j2s file"
2564   dependsOn jalviewjsCreateJ2sSettings
2565 }
2566
2567
2568 task jalviewjsIDE_SyncCore {
2569   group "00 JalviewJS in Eclipse"
2570   description "Build the core js lib closures listed in the classlists dir and publish core html from template"
2571   dependsOn jalviewjsSyncCore
2572 }
2573
2574
2575 task jalviewjsIDE_SyncSiteAll {
2576   dependsOn jalviewjsSyncAllLibs
2577   dependsOn jalviewjsSyncResources
2578   dependsOn jalviewjsSyncSiteResources
2579   dependsOn jalviewjsSyncBuildProperties
2580 }
2581
2582
2583 cleanJalviewjsTransferSite.mustRunAfter jalviewjsIDE_SyncSiteAll
2584
2585
2586 task jalviewjsIDE_PrepareSite {
2587   group "00 JalviewJS in Eclipse"
2588   description "Sync libs and resources to site dir, but not closure cores"
2589
2590   dependsOn jalviewjsIDE_SyncSiteAll
2591   dependsOn cleanJalviewjsTransferSite
2592 }
2593
2594
2595 task jalviewjsIDE_AssembleSite {
2596   group "00 JalviewJS in Eclipse"
2597   description "Assembles unzipped supporting zipfiles, resources, site resources and closure cores into the Eclipse transpiled site"
2598   dependsOn jalviewjsPrepareSite
2599 }
2600
2601
2602 task jalviewjsIDE_SiteClean {
2603   group "00 JalviewJS in Eclipse"
2604   description "Deletes the Eclipse transpiled site"
2605   dependsOn cleanJalviewjsSite
2606 }
2607
2608
2609 task jalviewjsIDE_Server {
2610   group "00 JalviewJS in Eclipse"
2611   description "Starts a webserver on localhost to test the website"
2612   dependsOn jalviewjsServer
2613 }
2614
2615
2616 // buildship runs this at import or gradle refresh
2617 task eclipseSynchronizationTask {
2618   //dependsOn eclipseSetup
2619   dependsOn createBuildProperties
2620   if (J2S_ENABLED) {
2621     dependsOn jalviewjsIDE_j2sFile
2622     dependsOn jalviewjsIDE_checkJ2sPlugin
2623     dependsOn jalviewjsIDE_PrepareSite
2624   }
2625 }
2626
2627
2628 // buildship runs this at build time or project refresh
2629 task eclipseAutoBuildTask {
2630   //dependsOn jalviewjsIDE_checkJ2sPlugin
2631   //dependsOn jalviewjsIDE_PrepareSite
2632 }
2633
2634
2635 task jalviewjs {
2636   group "JalviewJS"
2637   description "Build the site"
2638   dependsOn jalviewjsBuildSite
2639 }