JAL-3577 Fixed Jalview Programme Group in Windows menu. Added examples folder for...
[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.eclipse.model.Output
4 import org.gradle.plugins.ide.eclipse.model.Library
5 import java.security.MessageDigest
6 import groovy.transform.ExternalizeMethods
7 import groovy.util.XmlParser
8 import groovy.xml.XmlUtil
9
10
11 buildscript {
12   repositories {
13     mavenCentral()
14     mavenLocal()
15   }
16   dependencies {
17     classpath 'org.openclover:clover:4.4.1'
18   }
19 }
20
21
22 plugins {
23   id 'java'
24   id 'application'
25   id 'eclipse'
26   id 'com.github.johnrengelman.shadow' version '4.0.3'
27   id 'com.install4j.gradle' version '8.0.4'
28   id 'com.dorongold.task-tree' version '1.5' // only needed to display task dependency tree with  gradle task1 [task2 ...] taskTree
29 }
30
31 repositories {
32   jcenter()
33   mavenCentral()
34   mavenLocal()
35 }
36
37
38 // in ext the values are cast to Object. Ensure string values are cast as String (and not GStringImpl) for later use
39 def string(Object o) {
40   return o == null ? "" : o.toString()
41 }
42
43
44 ext {
45   jalviewDirAbsolutePath = file(jalviewDir).getAbsolutePath()
46   jalviewDirRelativePath = jalviewDir
47
48   // local build environment properties
49   // can be "projectDir/local.properties"
50   def localProps = "${projectDir}/local.properties"
51   def propsFile = null;
52   if (file(localProps).exists()) {
53     propsFile = localProps
54   }
55   // or "../projectDir_local.properties"
56   def dirLocalProps = projectDir.getParent() + "/" + projectDir.getName() + "_local.properties"
57   if (file(dirLocalProps).exists()) {
58     propsFile = dirLocalProps
59   }
60   if (propsFile != null) {
61     try {
62       def p = new Properties()
63       def localPropsFIS = new FileInputStream(propsFile)
64       p.load(localPropsFIS)
65       localPropsFIS.close()
66       p.each {
67         key, val -> 
68           def oldval = findProperty(key)
69           setProperty(key, val)
70           if (oldval != null) {
71             println("Overriding property '${key}' ('${oldval}') with ${file(propsFile).getName()} value '${val}'")
72           } else {
73             println("Setting unknown property '${key}' with ${file(propsFile).getName()}s value '${val}'")
74           }
75       }
76     } catch (Exception e) {
77       System.out.println("Exception reading local.properties")
78     }
79   }
80
81   // this property set when running Eclipse headlessly
82   j2sHeadlessBuildProperty = string("net.sf.j2s.core.headlessbuild")
83   // this property set by Eclipse
84   eclipseApplicationProperty = string("eclipse.application")
85   // CHECK IF RUNNING FROM WITHIN ECLIPSE
86   def eclipseApplicationPropertyVal = System.properties[eclipseApplicationProperty]
87   IN_ECLIPSE = eclipseApplicationPropertyVal != null && eclipseApplicationPropertyVal.startsWith("org.eclipse.ui.")
88   // BUT WITHOUT THE HEADLESS BUILD PROPERTY SET
89   if (System.properties[j2sHeadlessBuildProperty].equals("true")) {
90     println("Setting IN_ECLIPSE to ${IN_ECLIPSE} as System.properties['${j2sHeadlessBuildProperty}'] == '${System.properties[j2sHeadlessBuildProperty]}'")
91     IN_ECLIPSE = false
92   }
93   if (IN_ECLIPSE) {
94     println("WITHIN ECLIPSE IDE")
95   } else {
96     println("HEADLESS BUILD")
97   }
98   /* *-/
99   System.properties.sort { it.key }.each {
100     key, val -> println("SYSTEM PROPERTY ${key}='${val}'")
101   }
102   /-* *-/
103   if (false && IN_ECLIPSE) {
104     jalviewDir = jalviewDirAbsolutePath
105   }
106   */
107
108   // essentials
109   bareSourceDir = string(source_dir)
110   sourceDir = string("${jalviewDir}/${bareSourceDir}")
111   resourceDir = string("${jalviewDir}/${resource_dir}")
112   bareTestSourceDir = string(test_source_dir)
113   testSourceDir = string("${jalviewDir}/${bareTestSourceDir}")
114
115   // clover
116   cloverInstrDir = file("${buildDir}/${cloverSourcesInstrDir}")
117   cloverDb = string("${buildDir}/clover/clover.db")
118   classesDir = string("${jalviewDir}/${classes_dir}")
119   if (clover.equals("true")) {
120     use_clover = true
121     classesDir = string("${buildDir}/${cloverClassesDir}")
122   } else {
123     use_clover = false
124     classesDir = string("${jalviewDir}/${classes_dir}")
125   }
126
127   classes = classesDir
128
129   getdownWebsiteDir = string("${jalviewDir}/${getdown_website_dir}/${JAVA_VERSION}")
130   buildDist = true
131
132   // the following values might be overridden by the CHANNEL switch
133   getdownChannelName = CHANNEL.toLowerCase()
134   getdownDir = string("${getdownChannelName}/${JAVA_VERSION}")
135   getdownAppBase = string("${getdown_channel_base}/${getdownDir}")
136   getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher}")
137   getdownAppDistDir = getdown_app_dir_alt
138   buildProperties = string("${classesDir}/${build_properties_file}")
139   reportRsyncCommand = false
140   jvlChannelName = CHANNEL.toLowerCase()
141   install4jSuffix = CHANNEL.substring(0, 1).toUpperCase() + CHANNEL.substring(1).toLowerCase(); // BUILD -> Build
142   install4jDSStore = "DS_Store-NON-RELEASE"
143   install4jDMGBackgroundImage = "jalview_dmg_background-NON-RELEASE.png"
144   install4jInstallerName = "${jalview_name} Non-Release Installer"
145   install4jExecutableName = jalview_name.replaceAll("[^\\w]+", "_").toLowerCase()
146   install4jExtraScheme = "jalviewx"
147   switch (CHANNEL) {
148
149     case "BUILD":
150     // TODO: get bamboo build artifact URL for getdown artifacts
151     getdown_channel_base = bamboo_channelbase
152     getdownChannelName = string("${bamboo_planKey}/${JAVA_VERSION}")
153     getdownAppBase = string("${bamboo_channelbase}/${bamboo_planKey}${bamboo_getdown_channel_suffix}/${JAVA_VERSION}")
154     jvlChannelName += "_${getdownChannelName}"
155     // automatically add the test group Not-bamboo for exclusion 
156     if ("".equals(testngExcludedGroups)) { 
157       testngExcludedGroups = "Not-bamboo"
158     }
159     install4jExtraScheme = "jalviewb"
160     break
161
162     case "RELEASE":
163     getdownAppDistDir = getdown_app_dir_release
164     reportRsyncCommand = true
165     install4jSuffix = ""
166     install4jDSStore = "DS_Store"
167     install4jDMGBackgroundImage = "jalview_dmg_background.png"
168     install4jInstallerName = "${jalview_name} Installer"
169     break
170
171     case "ARCHIVE":
172     getdownChannelName = CHANNEL.toLowerCase()+"/${JALVIEW_VERSION}"
173     getdownDir = string("${getdownChannelName}/${JAVA_VERSION}")
174     getdownAppBase = string("${getdown_channel_base}/${getdownDir}")
175     if (!file("${ARCHIVEDIR}/${packageDir}").exists()) {
176       throw new GradleException("Must provide an ARCHIVEDIR value to produce an archive distribution")
177     } else {
178       packageDir = string("${ARCHIVEDIR}/${packageDir}")
179       buildProperties = string("${ARCHIVEDIR}/${classes_dir}/${build_properties_file}")
180       buildDist = false
181     }
182     reportRsyncCommand = true
183     install4jExtraScheme = "jalviewa"
184     break
185
186     case "ARCHIVELOCAL":
187     getdownChannelName = string("archive/${JALVIEW_VERSION}")
188     getdownDir = string("${getdownChannelName}/${JAVA_VERSION}")
189     getdownAppBase = file(getdownWebsiteDir).toURI().toString()
190     if (!file("${ARCHIVEDIR}/${packageDir}").exists()) {
191       throw new GradleException("Must provide an ARCHIVEDIR value to produce an archive distribution")
192     } else {
193       packageDir = string("${ARCHIVEDIR}/${packageDir}")
194       buildProperties = string("${ARCHIVEDIR}/${classes_dir}/${build_properties_file}")
195       buildDist = false
196     }
197     reportRsyncCommand = true
198     getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher_local}")
199     install4jSuffix = "Archive"
200     install4jExtraScheme = "jalviewa"
201     break
202
203     case "DEVELOP":
204     reportRsyncCommand = true
205     install4jExtraScheme = "jalviewd"
206     break
207
208     case "TEST-RELEASE":
209     reportRsyncCommand = true
210     JALVIEW_VERSION = "TEST"
211     install4jSuffix = "Test"
212     install4jDSStore = "DS_Store-TEST-RELEASE"
213     install4jDMGBackgroundImage = "jalview_dmg_background.png"
214     install4jExtraScheme = "jalviewt"
215     install4jInstallerName = "${jalview_name} Test Installer"
216     break
217
218     case ~/^SCRATCH(|-[-\w]*)$/:
219     getdownChannelName = CHANNEL
220     getdownDir = string("${getdownChannelName}/${JAVA_VERSION}")
221     getdownAppBase = string("${getdown_channel_base}/${getdownDir}")
222     reportRsyncCommand = true
223     install4jSuffix = "Scratch"
224     break
225
226     case "TEST-LOCAL":
227     if (!file("${LOCALDIR}").exists()) {
228       throw new GradleException("Must provide a LOCALDIR value to produce a local distribution")
229     } else {
230       getdownAppBase = file(file("${LOCALDIR}").getAbsolutePath()).toURI().toString()
231       getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher_local}")
232     }
233     JALVIEW_VERSION = "TEST"
234     install4jSuffix = "Test-Local"
235     install4jDSStore = "DS_Store-TEST-RELEASE"
236     install4jDMGBackgroundImage = "jalview_dmg_background.png"
237     install4jExtraScheme = "jalviewt"
238     install4jInstallerName = "${jalview_name} Test Installer"
239     break
240
241     case "LOCAL":
242     getdownAppBase = file(getdownWebsiteDir).toURI().toString()
243     getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher_local}")
244     install4jExtraScheme = "jalviewl"
245     break
246
247     default: // something wrong specified
248     throw new GradleException("CHANNEL must be one of BUILD, RELEASE, ARCHIVE, DEVELOP, TEST-RELEASE, SCRATCH-..., LOCAL [default]")
249     break
250
251   }
252   // override getdownAppBase if requested
253   if (findProperty("getdown_appbase_override") != null) {
254     getdownAppBase = string(getProperty("getdown_appbase_override"))
255     println("Overriding getdown appbase with '${getdownAppBase}'")
256   }
257   // sanitise file name for jalview launcher file for this channel
258   jvlChannelName = jvlChannelName.replaceAll("[^\\w\\-]+", "_")
259   // install4j application and folder names
260   if (install4jSuffix == "") {
261     install4jApplicationName = "${jalview_name}"
262     install4jBundleId = "${install4j_bundle_id}"
263     install4jWinApplicationId = install4j_release_win_application_id
264   } else {
265     install4jApplicationName = "${jalview_name} ${install4jSuffix}"
266     install4jBundleId = "${install4j_bundle_id}-" + install4jSuffix.toLowerCase()
267     // add int hash of install4jSuffix to the last part of the application_id
268     def id = install4j_release_win_application_id
269     def idsplitreverse = id.split("-").reverse()
270     idsplitreverse[0] = idsplitreverse[0].toInteger() + install4jSuffix.hashCode()
271     install4jWinApplicationId = idsplitreverse.reverse().join("-")
272   }
273   // sanitise folder and id names
274   // install4jApplicationFolder = e.g. "Jalview Build"
275   install4jApplicationFolder = install4jApplicationName
276                                     .replaceAll("[\"'~:/\\\\\\s]", "_") // replace all awkward filename chars " ' ~ : / \
277                                     .replaceAll("_+", "_") // collapse __
278   install4jInternalId = install4jApplicationName
279                                     .replaceAll(" ","_")
280                                     .replaceAll("[^\\w\\-\\.]", "_") // replace other non [alphanumeric,_,-,.]
281                                     .replaceAll("_+", "") // collapse __
282                                     //.replaceAll("_*-_*", "-") // collapse _-_
283   install4jUnixApplicationFolder = install4jApplicationName
284                                     .replaceAll(" ","_")
285                                     .replaceAll("[^\\w\\-\\.]", "_") // replace other non [alphanumeric,_,-,.]
286                                     .replaceAll("_+", "_") // collapse __
287                                     .replaceAll("_*-_*", "-") // collapse _-_
288                                     .toLowerCase()
289
290   getdownAppDir = string("${getdownWebsiteDir}/${getdownAppDistDir}")
291   //getdownJ11libDir = "${getdownWebsiteDir}/${getdown_j11lib_dir}"
292   getdownResourceDir = string("${getdownWebsiteDir}/${getdown_resource_dir}")
293   getdownInstallDir = string("${getdownWebsiteDir}/${getdown_install_dir}")
294   getdownFilesDir = string("${jalviewDir}/${getdown_files_dir}/${JAVA_VERSION}/")
295   getdownFilesInstallDir = string("${getdownFilesDir}/${getdown_install_dir}")
296   /* compile without modules -- using classpath libraries
297   modules_compileClasspath = fileTree(dir: "${jalviewDir}/${j11modDir}", include: ["*.jar"])
298   modules_runtimeClasspath = modules_compileClasspath
299   */
300   gitHash = string("")
301   gitBranch = string("")
302
303   println("Using a ${CHANNEL} profile.")
304
305   additional_compiler_args = []
306   // configure classpath/args for j8/j11 compilation
307   if (JAVA_VERSION.equals("1.8")) {
308     JAVA_INTEGER_VERSION = string("8")
309     //libDir = j8libDir
310     libDir = j11libDir
311     libDistDir = j8libDir
312     compile_source_compatibility = 1.8
313     compile_target_compatibility = 1.8
314     // these are getdown.txt properties defined dependent on the JAVA_VERSION
315     getdownAltJavaMinVersion = string(findProperty("getdown_alt_java8_min_version"))
316     getdownAltJavaMaxVersion = string(findProperty("getdown_alt_java8_max_version"))
317     // this property is assigned below and expanded to multiple lines in the getdown task
318     getdownAltMultiJavaLocation = string(findProperty("getdown_alt_java8_txt_multi_java_location"))
319     // this property is for the Java library used in eclipse
320     eclipseJavaRuntimeName = string("JavaSE-1.8")
321   } else if (JAVA_VERSION.equals("11")) {
322     JAVA_INTEGER_VERSION = string("11")
323     libDir = j11libDir
324     libDistDir = j11libDir
325     compile_source_compatibility = 11
326     compile_target_compatibility = 11
327     getdownAltJavaMinVersion = string(findProperty("getdown_alt_java11_min_version"))
328     getdownAltJavaMaxVersion = string(findProperty("getdown_alt_java11_max_version"))
329     getdownAltMultiJavaLocation = string(findProperty("getdown_alt_java11_txt_multi_java_location"))
330     eclipseJavaRuntimeName = string("JavaSE-11")
331     /* compile without modules -- using classpath libraries
332     additional_compiler_args += [
333     '--module-path', modules_compileClasspath.asPath,
334     '--add-modules', j11modules
335     ]
336      */
337   } else if (JAVA_VERSION.equals("12") || JAVA_VERSION.equals("13")) {
338     JAVA_INTEGER_VERSION = JAVA_VERSION
339     libDir = j11libDir
340     libDistDir = j11libDir
341     compile_source_compatibility = JAVA_VERSION
342     compile_target_compatibility = JAVA_VERSION
343     getdownAltJavaMinVersion = string(findProperty("getdown_alt_java11_min_version"))
344     getdownAltJavaMaxVersion = string(findProperty("getdown_alt_java11_max_version"))
345     getdownAltMultiJavaLocation = string(findProperty("getdown_alt_java11_txt_multi_java_location"))
346     eclipseJavaRuntimeName = string("JavaSE-11")
347     /* compile without modules -- using classpath libraries
348     additional_compiler_args += [
349     '--module-path', modules_compileClasspath.asPath,
350     '--add-modules', j11modules
351     ]
352      */
353   } else {
354     throw new GradleException("JAVA_VERSION=${JAVA_VERSION} not currently supported by Jalview")
355   }
356
357
358   // for install4j
359   JAVA_MIN_VERSION = JAVA_VERSION
360   JAVA_MAX_VERSION = JAVA_VERSION
361   def jreInstallsDir = string(jre_installs_dir)
362   if (jreInstallsDir.startsWith("~/")) {
363     jreInstallsDir = System.getProperty("user.home") + jreInstallsDir.substring(1)
364   }
365   macosJavaVMDir = string("${jreInstallsDir}/jre-${JAVA_INTEGER_VERSION}-mac-x64/jre")
366   macosJavaVMTgz = string("${jreInstallsDir}/tgz/jre-${JAVA_INTEGER_VERSION}-mac-x64.tar.gz")
367   windowsJavaVMDir = string("${jreInstallsDir}/jre-${JAVA_INTEGER_VERSION}-windows-x64/jre")
368   windowsJavaVMTgz = string("${jreInstallsDir}/tgz/jre-${JAVA_INTEGER_VERSION}-windows-x64.tar.gz")
369   linuxJavaVMDir = string("${jreInstallsDir}/jre-${JAVA_INTEGER_VERSION}-linux-x64/jre")
370   linuxJavaVMTgz = string("${jreInstallsDir}/tgz/jre-${JAVA_INTEGER_VERSION}-linux-x64.tar.gz")
371   install4jDir = string("${jalviewDir}/${install4j_utils_dir}")
372   install4jConfFileName = string("jalview-install4j-conf.install4j")
373   install4jConfFile = file("${install4jDir}/${install4jConfFileName}")
374   install4jHomeDir = install4j_home_dir
375   if (install4jHomeDir.startsWith("~/")) {
376     install4jHomeDir = System.getProperty("user.home") + install4jHomeDir.substring(1)
377   }
378
379
380
381   buildingHTML = string("${jalviewDir}/${docDir}/building.html")
382   helpFile = string("${classesDir}/${help_dir}/help.jhm")
383   helpParentDir = string("${jalviewDir}/${help_parent_dir}")
384   helpSourceDir = string("${helpParentDir}/${help_dir}")
385
386
387   relativeBuildDir = file(jalviewDirAbsolutePath).toPath().relativize(buildDir.toPath())
388   jalviewjsBuildDir = string("${relativeBuildDir}/jalviewjs")
389   jalviewjsSiteDir = string("${jalviewjsBuildDir}/${jalviewjs_site_dir}")
390   if (IN_ECLIPSE) {
391     jalviewjsTransferSiteJsDir = string(jalviewjsSiteDir)
392   } else {
393     jalviewjsTransferSiteJsDir = string("${jalviewjsBuildDir}/tmp/${jalviewjs_site_dir}_js")
394   }
395   jalviewjsTransferSiteLibDir = string("${jalviewjsBuildDir}/tmp/${jalviewjs_site_dir}_lib")
396   jalviewjsTransferSiteSwingJsDir = string("${jalviewjsBuildDir}/tmp/${jalviewjs_site_dir}_swingjs")
397   jalviewjsTransferSiteCoreDir = string("${jalviewjsBuildDir}/tmp/${jalviewjs_site_dir}_core")
398   jalviewjsJalviewCoreHtmlFile = string("")
399   jalviewjsJalviewCoreName = string(jalviewjs_core_name)
400   jalviewjsCoreClasslists = []
401   jalviewjsJalviewTemplateName = string(jalviewjs_name)
402   jalviewjsJ2sSettingsFileName = string("${jalviewDir}/${jalviewjs_j2s_settings}")
403   jalviewjsJ2sProps = null
404
405   eclipseWorkspace = null
406   eclipseBinary = string("")
407   eclipseVersion = string("")
408   eclipseDebug = false
409   // ENDEXT
410 }
411
412
413 sourceSets {
414   main {
415     java {
416       srcDirs sourceDir
417       outputDir = file(classesDir)
418     }
419
420     resources {
421       srcDirs resourceDir
422       srcDirs += helpParentDir
423     }
424
425     jar.destinationDir = file("${jalviewDir}/${packageDir}")
426
427     compileClasspath = files(sourceSets.main.java.outputDir)
428     //compileClasspath += files(sourceSets.main.resources.srcDirs)
429     compileClasspath += fileTree(dir: "${jalviewDir}/${libDir}", include: ["*.jar"])
430
431     runtimeClasspath = compileClasspath
432   }
433
434   clover {
435     java {
436       srcDirs = [ cloverInstrDir ]
437       outputDir = file("${buildDir}/${cloverClassesDir}")
438     }
439
440     resources {
441       srcDirs = sourceSets.main.resources.srcDirs
442     }
443     compileClasspath = configurations.cloverRuntime + files( sourceSets.clover.java.outputDir )
444     compileClasspath += files(sourceSets.main.java.outputDir)
445     compileClasspath += sourceSets.main.compileClasspath
446     compileClasspath += fileTree(dir: "${jalviewDir}/${utilsDir}", include: ["**/*.jar"])
447     compileClasspath += fileTree(dir: "${jalviewDir}/${libDir}", include: ["*.jar"])
448
449     runtimeClasspath = compileClasspath
450   }
451
452   test {
453     java {
454       srcDirs testSourceDir
455       outputDir = file("${jalviewDir}/${testOutputDir}")
456     }
457
458     resources {
459       srcDirs = sourceSets.main.resources.srcDirs
460     }
461
462     compileClasspath = files( sourceSets.test.java.outputDir )
463
464     if (use_clover) {
465       compileClasspath = sourceSets.clover.compileClasspath
466     } else {
467       compileClasspath += files(sourceSets.main.java.outputDir)
468     }
469
470     compileClasspath += fileTree(dir: "${jalviewDir}/${libDir}", include: ["*.jar"])
471     compileClasspath += fileTree(dir: "${jalviewDir}/${utilsDir}/testnglibs", include: ["**/*.jar"])
472     compileClasspath += fileTree(dir: "${jalviewDir}/${utilsDir}/testlibs", include: ["**/*.jar"])
473
474     runtimeClasspath = compileClasspath
475   }
476 }
477
478
479 // clover bits
480 dependencies {
481   if (use_clover) {
482     cloverCompile 'org.openclover:clover:4.4.1'
483     testCompile 'org.openclover:clover:4.4.1'
484   }
485 }
486
487 configurations {
488   cloverRuntime
489   cloverRuntime.extendsFrom cloverCompile
490 }
491
492
493 // eclipse project and settings files creation, also used by buildship
494 eclipse {
495   project {
496     name = eclipse_project_name
497
498     natures 'org.eclipse.jdt.core.javanature',
499     'org.eclipse.jdt.groovy.core.groovyNature',
500     'org.eclipse.buildship.core.gradleprojectnature'
501
502     buildCommand 'org.eclipse.jdt.core.javabuilder'
503     buildCommand 'org.eclipse.buildship.core.gradleprojectbuilder'
504   }
505
506   classpath {
507     //defaultOutputDir = sourceSets.main.java.outputDir
508     def removeThese = []
509     configurations.each{
510       if (it.isCanBeResolved()) {
511         removeThese += it
512       }
513     }
514
515     minusConfigurations += removeThese
516     plusConfigurations = [ ]
517     file {
518
519       whenMerged { cp ->
520         def removeTheseToo = []
521         HashMap<String, Boolean> alreadyAddedSrcPath = new HashMap<>();
522         cp.entries.each { entry ->
523           // This conditional removes all src classpathentries that a) have already been added or b) aren't "src" or "test".
524           // e.g. this removes the resources dir being copied into bin/main, bin/test AND bin/clover
525           // we add the resources and help/help dirs in as libs afterwards (see below)
526           if (entry.kind == 'src') {
527             if (alreadyAddedSrcPath.getAt(entry.path) || !(entry.path == bareSourceDir || entry.path == bareTestSourceDir)) {
528               removeTheseToo += entry
529             } else {
530               alreadyAddedSrcPath.putAt(entry.path, true)
531             }
532           }
533
534         }
535         cp.entries.removeAll(removeTheseToo)
536
537         //cp.entries += new Output("${eclipse_bin_dir}/main")
538         if (file(helpParentDir).isDirectory()) {
539           cp.entries += new Library(fileReference(helpParentDir))
540         }
541         if (file(resourceDir).isDirectory()) {
542           cp.entries += new Library(fileReference(resourceDir))
543         }
544
545         HashMap<String, Boolean> alreadyAddedLibPath = new HashMap<>();
546
547         sourceSets.main.compileClasspath.findAll { it.name.endsWith(".jar") }.any {
548           //don't want to add outputDir as eclipse is using its own output dir in bin/main
549           if (it.isDirectory() || ! it.exists()) {
550             // don't add dirs to classpath, especially if they don't exist
551             return false // groovy "continue" in .any closure
552           }
553           def itPath = it.toString()
554           if (itPath.startsWith("${jalviewDirAbsolutePath}/")) {
555             // make relative path
556             itPath = itPath.substring(jalviewDirAbsolutePath.length()+1)
557           }
558           if (alreadyAddedLibPath.get(itPath)) {
559             //println("Not adding duplicate entry "+itPath)
560           } else {
561             //println("Adding entry "+itPath)
562             cp.entries += new Library(fileReference(itPath))
563             alreadyAddedLibPath.put(itPath, true)
564           }
565         }
566
567         sourceSets.test.compileClasspath.findAll { it.name.endsWith(".jar") }.any {
568           //no longer want to add outputDir as eclipse is using its own output dir in bin/main
569           if (it.isDirectory() || ! it.exists()) {
570             // don't add dirs to classpath
571             return false // groovy "continue" in .any closure
572           }
573
574           def itPath = it.toString()
575           if (itPath.startsWith("${jalviewDirAbsolutePath}/")) {
576             itPath = itPath.substring(jalviewDirAbsolutePath.length()+1)
577           }
578           if (alreadyAddedLibPath.get(itPath)) {
579             // don't duplicate
580           } else {
581             def lib = new Library(fileReference(itPath))
582             lib.entryAttributes["test"] = "true"
583             cp.entries += lib
584             alreadyAddedLibPath.put(itPath, true)
585           }
586         }
587
588       } // whenMerged
589
590     } // file
591
592     containers 'org.eclipse.buildship.core.gradleclasspathcontainer'
593
594   } // classpath
595
596   jdt {
597     // for the IDE, use java 11 compatibility
598     sourceCompatibility = compile_source_compatibility
599     targetCompatibility = compile_target_compatibility
600     javaRuntimeName = eclipseJavaRuntimeName
601
602     // add in jalview project specific properties/preferences into eclipse core preferences
603     file {
604       withProperties { props ->
605         def jalview_prefs = new Properties()
606         def ins = new FileInputStream("${jalviewDirAbsolutePath}/${eclipse_extra_jdt_prefs_file}")
607         jalview_prefs.load(ins)
608         ins.close()
609         jalview_prefs.forEach { t, v ->
610           if (props.getAt(t) == null) {
611             props.putAt(t, v)
612           }
613         }
614       }
615     }
616
617   } // jdt
618
619   if (IN_ECLIPSE) {
620     // Don't want these to be activated if in headless build
621     synchronizationTasks "eclipseSynchronizationTask"
622     autoBuildTasks "eclipseAutoBuildTask"
623
624   }
625 }
626
627
628 task cloverInstr {
629   // only instrument source, we build test classes as normal
630   inputs.files files (sourceSets.main.allJava,sourceSets.test.allJava) // , fileTree(dir:"$jalviewDir/$testSourceDir", include: ["**/*.java"]))
631   outputs.dir cloverInstrDir
632
633   doFirst {
634     delete cloverInstrDir
635     def argsList = [
636       "--initstring",
637       cloverDb,
638       "-d",
639       cloverInstrDir.getPath(),
640     ]
641     argsList.addAll(
642       inputs.files.files.collect(
643         { file -> file.absolutePath }
644       )
645     )
646     String[] args = argsList.toArray()
647     println("About to instrument "+args.length +" files")
648     com.atlassian.clover.CloverInstr.mainImpl(args)
649   }
650 }
651
652
653 cloverClasses.dependsOn cloverInstr
654
655
656 task cloverReport {
657   group = "Verification"
658   description = "Creates the Clover report"
659   inputs.dir "${buildDir}/clover"
660   outputs.dir "${reportsDir}/clover"
661   onlyIf {
662     file(cloverDb).exists()
663   }
664   doFirst {
665     def argsList = [
666       "--initstring",
667       cloverDb,
668       "-o",
669       "${reportsDir}/clover"
670     ]
671     String[] args = argsList.toArray()
672     com.atlassian.clover.reporters.html.HtmlReporter.runReport(args)
673
674     // and generate ${reportsDir}/clover/clover.xml
675     args = [
676       "--initstring",
677       cloverDb,
678       "-o",
679       "${reportsDir}/clover/clover.xml"
680     ].toArray()
681     com.atlassian.clover.reporters.xml.XMLReporter.runReport(args)
682   }
683 }
684
685
686 compileCloverJava {
687
688   doFirst {
689     sourceCompatibility = compile_source_compatibility
690     targetCompatibility = compile_target_compatibility
691     options.compilerArgs += additional_compiler_args
692     print ("Setting target compatibility to "+targetCompatibility+"\n")
693   }
694   classpath += configurations.cloverRuntime
695 }
696
697
698 task cleanClover {
699   doFirst {
700     delete cloverInstrDir
701     delete cloverDb
702   }
703 }
704 // end clover bits
705
706
707 compileJava {
708
709   doFirst {
710     sourceCompatibility = compile_source_compatibility
711     targetCompatibility = compile_target_compatibility
712     options.compilerArgs = additional_compiler_args
713     print ("Setting target compatibility to "+targetCompatibility+"\n")
714   }
715
716 }
717
718
719 compileTestJava {
720   if (use_clover) {
721     dependsOn compileCloverJava
722     classpath += configurations.cloverRuntime
723   } else {
724     classpath += sourceSets.main.runtimeClasspath
725   }
726   doFirst {
727     sourceCompatibility = compile_source_compatibility
728     targetCompatibility = compile_target_compatibility
729     options.compilerArgs = additional_compiler_args
730     print ("Setting target compatibility to "+targetCompatibility+"\n")
731   }
732 }
733
734
735 clean {
736   doFirst {
737     delete sourceSets.main.java.outputDir
738   }
739 }
740
741
742 cleanTest {
743   dependsOn cleanClover
744   doFirst {
745     delete sourceSets.test.java.outputDir
746   }
747 }
748
749
750 // format is a string like date.format("dd MMMM yyyy")
751 def getDate(format) {
752   def date = new Date()
753   return date.format(format)
754 }
755
756
757 task setGitVals {
758   def hashStdOut = new ByteArrayOutputStream()
759   exec {
760     commandLine "git", "rev-parse", "--short", "HEAD"
761     standardOutput = hashStdOut
762     ignoreExitValue true
763   }
764
765   def branchStdOut = new ByteArrayOutputStream()
766   exec {
767     commandLine "git", "rev-parse", "--abbrev-ref", "HEAD"
768     standardOutput = branchStdOut
769     ignoreExitValue true
770   }
771
772   gitHash = hashStdOut.toString().trim()
773   gitBranch = branchStdOut.toString().trim()
774
775   outputs.upToDateWhen { false }
776 }
777
778
779 task createBuildProperties(type: WriteProperties) {
780   dependsOn setGitVals
781   inputs.dir(sourceDir)
782   inputs.dir(resourceDir)
783   file(buildProperties).getParentFile().mkdirs()
784   outputFile (buildProperties)
785   // taking time specific comment out to allow better incremental builds
786   comment "--Jalview Build Details--\n"+getDate("yyyy-MM-dd HH:mm:ss")
787   //comment "--Jalview Build Details--\n"+getDate("yyyy-MM-dd")
788   property "BUILD_DATE", getDate("HH:mm:ss dd MMMM yyyy")
789   property "VERSION", JALVIEW_VERSION
790   property "INSTALLATION", INSTALLATION+" git-commit:"+gitHash+" ["+gitBranch+"]"
791   outputs.file(outputFile)
792 }
793
794
795 task cleanBuildingHTML(type: Delete) {
796   doFirst {
797     delete buildingHTML
798   }
799 }
800
801
802 task convertBuildingMD(type: Exec) {
803   dependsOn cleanBuildingHTML
804   def buildingMD = "${jalviewDir}/${docDir}/building.md"
805   def css = "${jalviewDir}/${docDir}/github.css"
806
807   def pandoc = null
808   pandoc_exec.split(",").each {
809     if (file(it.trim()).exists()) {
810       pandoc = it.trim()
811       return true
812     }
813   }
814
815   def hostname = "hostname".execute().text.trim()
816   def buildtoolsPandoc = System.getProperty("user.home")+"/buildtools/pandoc/bin/pandoc"
817   if ((pandoc == null || ! file(pandoc).exists()) && file(buildtoolsPandoc).exists()) {
818     pandoc = System.getProperty("user.home")+"/buildtools/pandoc/bin/pandoc"
819   }
820
821   doFirst {
822     if (pandoc != null && file(pandoc).exists()) {
823         commandLine pandoc, '-s', '-o', buildingHTML, '--metadata', 'pagetitle="Building Jalview from Source"', '--toc', '-H', css, buildingMD
824     } else {
825         println("Cannot find pandoc. Skipping convert building.md to HTML")
826         throw new StopExecutionException("Cannot find pandoc. Skipping convert building.md to HTML")
827     }
828   }
829
830   ignoreExitValue true
831
832   inputs.file(buildingMD)
833   inputs.file(css)
834   outputs.file(buildingHTML)
835 }
836
837
838 clean {
839   doFirst {
840     delete buildingHTML
841   }
842 }
843
844
845 task syncDocs(type: Sync) {
846   dependsOn convertBuildingMD
847   def syncDir = "${classesDir}/${docDir}"
848   from fileTree("${jalviewDir}/${docDir}")
849   into syncDir
850
851 }
852
853
854 task copyHelp(type: Copy) {
855   def inputDir = helpSourceDir
856   def outputDir = "${classesDir}/${help_dir}"
857   from(inputDir) {
858     exclude '**/*.gif'
859     exclude '**/*.jpg'
860     exclude '**/*.png'
861     filter(ReplaceTokens,
862       beginToken: '$$',
863       endToken: '$$',
864       tokens: [
865         'Version-Rel': JALVIEW_VERSION,
866         'Year-Rel': getDate("yyyy")
867       ]
868     )
869   }
870   from(inputDir) {
871     include '**/*.gif'
872     include '**/*.jpg'
873     include '**/*.png'
874   }
875   into outputDir
876
877   inputs.dir(inputDir)
878   outputs.files(helpFile)
879   outputs.dir(outputDir)
880 }
881
882
883 task syncLib(type: Sync) {
884   def syncDir = "${classesDir}/${libDistDir}"
885   from fileTree("${jalviewDir}/${libDistDir}")
886   into syncDir
887 }
888
889
890 task syncResources(type: Sync) {
891   from resourceDir
892   include "**/*.*"
893   into "${classesDir}"
894   preserve {
895     include "**"
896   }
897 }
898
899
900 task prepare {
901   dependsOn syncResources
902   dependsOn syncDocs
903   dependsOn copyHelp
904 }
905
906
907 //testReportDirName = "test-reports" // note that test workingDir will be $jalviewDir
908 test {
909   dependsOn prepare
910   dependsOn compileJava
911   if (use_clover) {
912     dependsOn cloverInstr
913   }
914
915   if (use_clover) {
916     print("Running tests " + (use_clover?"WITH":"WITHOUT") + " clover [clover="+use_clover+"]\n")
917   }
918
919   useTestNG() {
920     includeGroups testngGroups
921     excludeGroups testngExcludedGroups
922     preserveOrder true
923     useDefaultListeners=true
924   }
925
926   maxHeapSize = "1024m"
927
928   workingDir = jalviewDir
929   //systemProperties 'clover.jar' System.properties.clover.jar
930   sourceCompatibility = compile_source_compatibility
931   targetCompatibility = compile_target_compatibility
932   jvmArgs += additional_compiler_args
933
934 }
935
936
937 task buildIndices(type: JavaExec) {
938   dependsOn copyHelp
939   classpath = sourceSets.main.compileClasspath
940   main = "com.sun.java.help.search.Indexer"
941   workingDir = "${classesDir}/${help_dir}"
942   def argDir = "html"
943   args = [ argDir ]
944   inputs.dir("${workingDir}/${argDir}")
945
946   outputs.dir("${classesDir}/doc")
947   outputs.dir("${classesDir}/help")
948   outputs.file("${workingDir}/JavaHelpSearch/DOCS")
949   outputs.file("${workingDir}/JavaHelpSearch/DOCS.TAB")
950   outputs.file("${workingDir}/JavaHelpSearch/OFFSETS")
951   outputs.file("${workingDir}/JavaHelpSearch/POSITIONS")
952   outputs.file("${workingDir}/JavaHelpSearch/SCHEMA")
953   outputs.file("${workingDir}/JavaHelpSearch/TMAP")
954 }
955
956
957 task compileLinkCheck(type: JavaCompile) {
958   options.fork = true
959   classpath = files("${jalviewDir}/${utilsDir}")
960   destinationDir = file("${jalviewDir}/${utilsDir}")
961   source = fileTree(dir: "${jalviewDir}/${utilsDir}", include: ["HelpLinksChecker.java", "BufferedLineReader.java"])
962
963   inputs.file("${jalviewDir}/${utilsDir}/HelpLinksChecker.java")
964   inputs.file("${jalviewDir}/${utilsDir}/HelpLinksChecker.java")
965   outputs.file("${jalviewDir}/${utilsDir}/HelpLinksChecker.class")
966   outputs.file("${jalviewDir}/${utilsDir}/BufferedLineReader.class")
967 }
968
969
970 task linkCheck(type: JavaExec) {
971   dependsOn prepare, compileLinkCheck
972
973   def helpLinksCheckerOutFile = file("${jalviewDir}/${utilsDir}/HelpLinksChecker.out")
974   classpath = files("${jalviewDir}/${utilsDir}")
975   main = "HelpLinksChecker"
976   workingDir = jalviewDir
977   args = [ "${classesDir}/${help_dir}", "-nointernet" ]
978
979   def outFOS = new FileOutputStream(helpLinksCheckerOutFile, false) // false == don't append
980   def errFOS = outFOS
981   standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
982     outFOS,
983     standardOutput)
984   errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
985     outFOS,
986     errorOutput)
987
988   inputs.dir("${classesDir}/${help_dir}")
989   outputs.file(helpLinksCheckerOutFile)
990 }
991
992 // import the pubhtmlhelp target
993 ant.properties.basedir = "${jalviewDir}"
994 ant.properties.helpBuildDir = "${jalviewDirAbsolutePath}/${classes_dir}/${help_dir}"
995 ant.importBuild "${utilsDir}/publishHelp.xml"
996
997
998 task cleanPackageDir(type: Delete) {
999   doFirst {
1000     delete fileTree(dir: "${jalviewDir}/${packageDir}", include: "*.jar")
1001   }
1002 }
1003
1004 jar {
1005   dependsOn linkCheck
1006   dependsOn buildIndices
1007   dependsOn createBuildProperties
1008
1009   manifest {
1010     attributes "Main-Class": mainClass,
1011     "Permissions": "all-permissions",
1012     "Application-Name": "Jalview Desktop",
1013     "Codebase": application_codebase
1014   }
1015
1016   destinationDir = file("${jalviewDir}/${packageDir}")
1017   archiveName = rootProject.name+".jar"
1018
1019   exclude "cache*/**"
1020   exclude "*.jar"
1021   exclude "*.jar.*"
1022   exclude "**/*.jar"
1023   exclude "**/*.jar.*"
1024
1025   inputs.dir(classesDir)
1026   outputs.file("${jalviewDir}/${packageDir}/${archiveName}")
1027 }
1028
1029
1030 task copyJars(type: Copy) {
1031   from fileTree(dir: classesDir, include: "**/*.jar").files
1032   into "${jalviewDir}/${packageDir}"
1033 }
1034
1035
1036 // doing a Sync instead of Copy as Copy doesn't deal with "outputs" very well
1037 task syncJars(type: Sync) {
1038   from fileTree(dir: "${jalviewDir}/${libDistDir}", include: "**/*.jar").files
1039   into "${jalviewDir}/${packageDir}"
1040   preserve {
1041     include jar.archiveName
1042   }
1043 }
1044
1045
1046 task makeDist {
1047   group = "build"
1048   description = "Put all required libraries in dist"
1049   // order of "cleanPackageDir", "copyJars", "jar" important!
1050   jar.mustRunAfter cleanPackageDir
1051   syncJars.mustRunAfter cleanPackageDir
1052   dependsOn cleanPackageDir
1053   dependsOn syncJars
1054   dependsOn jar
1055   outputs.dir("${jalviewDir}/${packageDir}")
1056 }
1057
1058
1059 task cleanDist {
1060   dependsOn cleanPackageDir
1061   dependsOn cleanTest
1062   dependsOn clean
1063 }
1064
1065 shadowJar {
1066   group = "distribution"
1067   if (buildDist) {
1068     dependsOn makeDist
1069   }
1070   from ("${jalviewDir}/${libDistDir}") {
1071     include("*.jar")
1072   }
1073   manifest {
1074     attributes 'Implementation-Version': JALVIEW_VERSION
1075   }
1076   mainClassName = shadowJarMainClass
1077   mergeServiceFiles()
1078   classifier = "all-"+JALVIEW_VERSION+"-j"+JAVA_VERSION
1079   minimize()
1080 }
1081
1082
1083 task getdownWebsite() {
1084   group = "distribution"
1085   description = "Create the getdown minimal app folder, and website folder for this version of jalview. Website folder also used for offline app installer"
1086   if (buildDist) {
1087     dependsOn makeDist
1088   }
1089
1090   def getdownWebsiteResourceFilenames = []
1091   def getdownTextString = ""
1092   def getdownResourceDir = getdownResourceDir
1093   def getdownResourceFilenames = []
1094
1095   doFirst {
1096     // clean the getdown website and files dir before creating getdown folders
1097     delete getdownWebsiteDir
1098     delete getdownFilesDir
1099
1100     copy {
1101       from buildProperties
1102       rename(build_properties_file, getdown_build_properties)
1103       into getdownAppDir
1104     }
1105     getdownWebsiteResourceFilenames += "${getdownAppDistDir}/${getdown_build_properties}"
1106
1107     // set some getdown_txt_ properties then go through all properties looking for getdown_txt_...
1108     def props = project.properties.sort { it.key }
1109     if (getdownAltJavaMinVersion != null && getdownAltJavaMinVersion.length() > 0) {
1110       props.put("getdown_txt_java_min_version", getdownAltJavaMinVersion)
1111     }
1112     if (getdownAltJavaMaxVersion != null && getdownAltJavaMaxVersion.length() > 0) {
1113       props.put("getdown_txt_java_max_version", getdownAltJavaMaxVersion)
1114     }
1115     if (getdownAltMultiJavaLocation != null && getdownAltMultiJavaLocation.length() > 0) {
1116       props.put("getdown_txt_multi_java_location", getdownAltMultiJavaLocation)
1117     }
1118
1119     props.put("getdown_txt_title", jalview_name)
1120     props.put("getdown_txt_ui.name", install4jApplicationName)
1121
1122     // start with appbase
1123     getdownTextString += "appbase = ${getdownAppBase}\n"
1124     props.each{ prop, val ->
1125       if (prop.startsWith("getdown_txt_") && val != null) {
1126         if (prop.startsWith("getdown_txt_multi_")) {
1127           def key = prop.substring(18)
1128           val.split(",").each{ v ->
1129             def line = "${key} = ${v}\n"
1130             getdownTextString += line
1131           }
1132         } else {
1133           // file values rationalised
1134           if (val.indexOf('/') > -1 || prop.startsWith("getdown_txt_resource")) {
1135             def r = null
1136             if (val.indexOf('/') == 0) {
1137               // absolute path
1138               r = file(val)
1139             } else if (val.indexOf('/') > 0) {
1140               // relative path (relative to jalviewDir)
1141               r = file( "${jalviewDir}/${val}" )
1142             }
1143             if (r.exists()) {
1144               val = "${getdown_resource_dir}/" + r.getName()
1145               getdownWebsiteResourceFilenames += val
1146               getdownResourceFilenames += r.getPath()
1147             }
1148           }
1149           if (! prop.startsWith("getdown_txt_resource")) {
1150             def line = prop.substring(12) + " = ${val}\n"
1151             getdownTextString += line
1152           }
1153         }
1154       }
1155     }
1156
1157     getdownWebsiteResourceFilenames.each{ filename ->
1158       getdownTextString += "resource = ${filename}\n"
1159     }
1160     getdownResourceFilenames.each{ filename ->
1161       copy {
1162         from filename
1163         into getdownResourceDir
1164       }
1165     }
1166
1167     def codeFiles = []
1168     fileTree(file(packageDir)).each{ f ->
1169       if (f.isDirectory()) {
1170         def files = fileTree(dir: f, include: ["*"]).getFiles()
1171         codeFiles += files
1172       } else if (f.exists()) {
1173         codeFiles += f
1174       }
1175     }
1176     codeFiles.sort().each{f ->
1177       def name = f.getName()
1178       def line = "code = ${getdownAppDistDir}/${name}\n"
1179       getdownTextString += line
1180       copy {
1181         from f.getPath()
1182         into getdownAppDir
1183       }
1184     }
1185
1186     // NOT USING MODULES YET, EVERYTHING SHOULD BE IN dist
1187     /*
1188     if (JAVA_VERSION.equals("11")) {
1189     def j11libFiles = fileTree(dir: "${jalviewDir}/${j11libDir}", include: ["*.jar"]).getFiles()
1190     j11libFiles.sort().each{f ->
1191     def name = f.getName()
1192     def line = "code = ${getdown_j11lib_dir}/${name}\n"
1193     getdownTextString += line
1194     copy {
1195     from f.getPath()
1196     into getdownJ11libDir
1197     }
1198     }
1199     }
1200      */
1201
1202     // 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.
1203     //getdownTextString += "class = " + file(getdownLauncher).getName() + "\n"
1204     getdownTextString += "resource = ${getdown_launcher_new}\n"
1205     getdownTextString += "class = ${mainClass}\n"
1206
1207     def getdown_txt = file("${getdownWebsiteDir}/getdown.txt")
1208     getdown_txt.write(getdownTextString)
1209
1210     def getdownLaunchJvl = getdown_launch_jvl_name + ( (jvlChannelName != null && jvlChannelName.length() > 0)?"-${jvlChannelName}":"" ) + ".jvl"
1211     def launchJvl = file("${getdownWebsiteDir}/${getdownLaunchJvl}")
1212     launchJvl.write("appbase=${getdownAppBase}")
1213
1214     copy {
1215       from getdownLauncher
1216       rename(file(getdownLauncher).getName(), getdown_launcher_new)
1217       into getdownWebsiteDir
1218     }
1219
1220     copy {
1221       from getdownLauncher
1222       if (file(getdownLauncher).getName() != getdown_launcher) {
1223         rename(file(getdownLauncher).getName(), getdown_launcher)
1224       }
1225       into getdownWebsiteDir
1226     }
1227
1228     if (! (CHANNEL.startsWith("ARCHIVE") || CHANNEL.startsWith("DEVELOP"))) {
1229       copy {
1230         from getdown_txt
1231         from getdownLauncher
1232         from "${getdownWebsiteDir}/${getdown_build_properties}"
1233         if (file(getdownLauncher).getName() != getdown_launcher) {
1234           rename(file(getdownLauncher).getName(), getdown_launcher)
1235         }
1236         into getdownInstallDir
1237       }
1238
1239       copy {
1240         from getdownInstallDir
1241         into getdownFilesInstallDir
1242       }
1243     }
1244
1245     copy {
1246       from getdown_txt
1247       from launchJvl
1248       from getdownLauncher
1249       from "${getdownWebsiteDir}/${getdown_build_properties}"
1250       if (file(getdownLauncher).getName() != getdown_launcher) {
1251         rename(file(getdownLauncher).getName(), getdown_launcher)
1252       }
1253       into getdownFilesDir
1254     }
1255
1256     copy {
1257       from getdownResourceDir
1258       into "${getdownFilesDir}/${getdown_resource_dir}"
1259     }
1260   }
1261
1262   if (buildDist) {
1263     inputs.dir("${jalviewDir}/${packageDir}")
1264   }
1265   outputs.dir(getdownWebsiteDir)
1266   outputs.dir(getdownFilesDir)
1267 }
1268
1269
1270 // a helper task to allow getdown digest of any dir: `gradle getdownDigestDir -PDIGESTDIR=/path/to/my/random/getdown/dir
1271 task getdownDigestDir(type: JavaExec) {
1272   def digestDirPropertyName = "DIGESTDIR"
1273   description = "Digest a local dir (-P${digestDirPropertyName}=...) for getdown"
1274   doFirst {
1275     classpath = files(getdownLauncher)
1276     def digestDir = findProperty(digestDirPropertyName)
1277     if (digestDir == null) {
1278       throw new GradleException("Must provide a DIGESTDIR value to produce an alternative getdown digest")
1279     }
1280     args digestDir
1281   }
1282   main = "com.threerings.getdown.tools.Digester"
1283 }
1284
1285
1286 task getdownDigest(type: JavaExec) {
1287   group = "distribution"
1288   description = "Digest the getdown website folder"
1289   dependsOn getdownWebsite
1290   doFirst {
1291     classpath = files(getdownLauncher)
1292   }
1293   main = "com.threerings.getdown.tools.Digester"
1294   args getdownWebsiteDir
1295   inputs.dir(getdownWebsiteDir)
1296   outputs.file("${getdownWebsiteDir}/digest2.txt")
1297 }
1298
1299
1300 task getdown() {
1301   group = "distribution"
1302   description = "Create the minimal and full getdown app folder for installers and website and create digest file"
1303   dependsOn getdownDigest
1304   doLast {
1305     if (reportRsyncCommand) {
1306       def fromDir = getdownWebsiteDir + (getdownWebsiteDir.endsWith('/')?'':'/')
1307       def toDir = "${getdown_rsync_dest}/${getdownDir}" + (getdownDir.endsWith('/')?'':'/')
1308       println "LIKELY RSYNC COMMAND:"
1309       println "mkdir -p '$toDir'\nrsync -avh --delete '$fromDir' '$toDir'"
1310       if (RUNRSYNC == "true") {
1311         exec {
1312           commandLine "mkdir", "-p", toDir
1313         }
1314         exec {
1315           commandLine "rsync", "-avh", "--delete", fromDir, toDir
1316         }
1317       }
1318     }
1319   }
1320 }
1321
1322
1323 clean {
1324   doFirst {
1325     delete getdownWebsiteDir
1326     delete getdownFilesDir
1327   }
1328 }
1329
1330
1331 install4j {
1332   if (file(install4jHomeDir).exists()) {
1333     // good to go!
1334   } else if (file(System.getProperty("user.home")+"/buildtools/install4j").exists()) {
1335     install4jHomeDir = System.getProperty("user.home")+"/buildtools/install4j"
1336   } else if (file("/Applications/install4j.app/Contents/Resources/app").exists()) {
1337     install4jHomeDir = "/Applications/install4j.app/Contents/Resources/app"
1338   }
1339   installDir(file(install4jHomeDir))
1340
1341   mediaTypes = Arrays.asList(install4j_media_types.split(","))
1342 }
1343
1344
1345 task copyInstall4jTemplate {
1346   def install4jTemplateFile = file("${install4jDir}/${install4j_template}")
1347   def install4jFileAssociationsFile = file("${install4jDir}/${install4j_installer_file_associations}")
1348   inputs.file(install4jTemplateFile)
1349   inputs.file(install4jFileAssociationsFile)
1350   inputs.property("CHANNEL", { CHANNEL })
1351   outputs.file(install4jConfFile)
1352
1353   doLast {
1354     def install4jConfigXml = new XmlParser().parse(install4jTemplateFile)
1355
1356     // turn off code signing if no OSX_KEYPASS
1357     if (OSX_KEYPASS == "") {
1358       install4jConfigXml.'**'.codeSigning.each { codeSigning ->
1359         codeSigning.'@macEnabled' = "false"
1360       }
1361       install4jConfigXml.'**'.windows.each { windows ->
1362         windows.'@runPostProcessor' = "false"
1363       }
1364     }
1365
1366     // turn off checksum creation for LOCAL channel
1367     def e = install4jConfigXml.application[0]
1368     if (CHANNEL == "LOCAL") {
1369       e.'@createChecksums' = "false"
1370     } else {
1371       e.'@createChecksums' = "true"
1372     }
1373
1374     // put file association actions where placeholder action is
1375     def install4jFileAssociationsText = install4jFileAssociationsFile.text
1376     def fileAssociationActions = new XmlParser().parseText("<actions>${install4jFileAssociationsText}</actions>")
1377     install4jConfigXml.'**'.action.any { a -> // .any{} stops after the first one that returns true
1378       if (a.'@name' == 'EXTENSIONS_REPLACED_BY_GRADLE') {
1379         def parent = a.parent()
1380         parent.remove(a)
1381         fileAssociationActions.each { faa ->
1382             parent.append(faa)
1383         }
1384         // don't need to continue in .any loop once replacements have been made
1385         return true
1386       }
1387     }
1388
1389     // use Windows Program Group with Examples folder for RELEASE, and Program Group without Examples for everything else
1390     // NB we're deleting the /other/ one!
1391     // Also remove the examples subdir from non-release versions
1392     def customizedIdToDelete = "PROGRAM_GROUP_RELEASE"
1393     if (CHANNEL=="RELEASE") {
1394       customizedIdToDelete = "PROGRAM_GROUP_NON_RELEASE"
1395     } else {
1396       // remove the examples subdir from Full File Set
1397       def files = install4jConfigXml.files[0]
1398       def fileset = files.filesets.fileset.find { fs -> fs.'@customizedId' == "FULL_FILE_SET" }
1399       def root = files.roots.root.find { r -> r.'@fileset' == fileset.'@id' }
1400       def mountPoint = files.mountPoints.mountPoint.find { mp -> mp.'@root' == root.'@id' }
1401       def dirEntry = files.entries.dirEntry.find { de -> de.'@mountPoint' == mountPoint.'@id' && de.'@subDirectory' == "examples" }
1402       dirEntry.parent().remove(dirEntry)
1403     }
1404     install4jConfigXml.'**'.action.any { a ->
1405       if (a.'@customizedId' == customizedIdToDelete) {
1406         def parent = a.parent()
1407         parent.remove(a)
1408         return true
1409       }
1410     }
1411
1412     // remove the "Uninstall Old Jalview (optional)" symlink from DMG for non-release DS_Stores
1413     if (! (CHANNEL == "RELEASE" || CHANNEL == "TEST-RELEASE" ) ) {
1414       def symlink = install4jConfigXml.'**'.topLevelFiles.symlink.find { sl -> sl.'@name' == "Uninstall Old Jalview (optional).app" }
1415       symlink.parent().remove(symlink)
1416     }
1417
1418     // write install4j file
1419     install4jConfFile.text = XmlUtil.serialize(install4jConfigXml)
1420   }
1421 }
1422
1423
1424 clean {
1425   doFirst {
1426     delete install4jConfFile
1427   }
1428 }
1429
1430
1431 task installers(type: com.install4j.gradle.Install4jTask) {
1432   group = "distribution"
1433   description = "Create the install4j installers"
1434   dependsOn setGitVals
1435   dependsOn getdown
1436   dependsOn copyInstall4jTemplate
1437
1438   projectFile = install4jConfFile
1439
1440   // create an md5 for the input files to use as version for install4j conf file
1441   def digest = MessageDigest.getInstance("MD5")
1442   digest.update(
1443     (file("${install4jDir}/${install4j_template}").text + 
1444     file("${install4jDir}/${install4j_info_plist_file_associations}").text +
1445     file("${install4jDir}/${install4j_installer_file_associations}").text).bytes)
1446   def filesMd5 = new BigInteger(1, digest.digest()).toString(16)
1447   if (filesMd5.length() >= 8) {
1448     filesMd5 = filesMd5.substring(0,8)
1449   }
1450   def install4jTemplateVersion = "${JALVIEW_VERSION}_F${filesMd5}_C${gitHash}"
1451   // make install4jBuildDir relative to jalviewDir
1452   def install4jBuildDir = "${install4j_build_dir}/${JAVA_VERSION}"
1453
1454   variables = [
1455     'JALVIEW_NAME': jalview_name,
1456     'JALVIEW_APPLICATION_NAME': install4jApplicationName,
1457     'JALVIEW_DIR': "../..",
1458     'OSX_KEYSTORE': OSX_KEYSTORE,
1459     'JSIGN_SH': JSIGN_SH,
1460     'JRE_DIR': getdown_app_dir_java,
1461     'INSTALLER_TEMPLATE_VERSION': install4jTemplateVersion,
1462     'JALVIEW_VERSION': JALVIEW_VERSION,
1463     'JAVA_MIN_VERSION': JAVA_MIN_VERSION,
1464     'JAVA_MAX_VERSION': JAVA_MAX_VERSION,
1465     'JAVA_VERSION': JAVA_VERSION,
1466     'JAVA_INTEGER_VERSION': JAVA_INTEGER_VERSION,
1467     'VERSION': JALVIEW_VERSION,
1468     'MACOS_JAVA_VM_DIR': macosJavaVMDir,
1469     'WINDOWS_JAVA_VM_DIR': windowsJavaVMDir,
1470     'LINUX_JAVA_VM_DIR': linuxJavaVMDir,
1471     'MACOS_JAVA_VM_TGZ': macosJavaVMTgz,
1472     'WINDOWS_JAVA_VM_TGZ': windowsJavaVMTgz,
1473     'LINUX_JAVA_VM_TGZ': linuxJavaVMTgz,
1474     'COPYRIGHT_MESSAGE': install4j_copyright_message,
1475     'BUNDLE_ID': install4jBundleId,
1476     'INTERNAL_ID': install4jInternalId,
1477     'WINDOWS_APPLICATION_ID': install4jWinApplicationId,
1478     'MACOS_DS_STORE': install4jDSStore,
1479     'MACOS_DMG_BG_IMAGE': install4jDMGBackgroundImage,
1480     'INSTALLER_NAME': install4jInstallerName,
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     'APPLICATION_CATEGORIES': install4j_application_categories,
1491     'APPLICATION_FOLDER': install4jApplicationFolder,
1492     'UNIX_APPLICATION_FOLDER': install4jUnixApplicationFolder,
1493     'EXECUTABLE_NAME': install4jExecutableName,
1494     'EXTRA_SCHEME': install4jExtraScheme,
1495   ]
1496
1497   //println("INSTALL4J VARIABLES:")
1498   //variables.each{k,v->println("${k}=${v}")}
1499
1500   destination = "${jalviewDir}/${install4jBuildDir}"
1501   buildSelected = true
1502
1503   if (install4j_faster.equals("true") || CHANNEL.startsWith("LOCAL")) {
1504     faster = true
1505     disableSigning = true
1506   }
1507
1508   if (OSX_KEYPASS) {
1509     macKeystorePassword = OSX_KEYPASS
1510   }
1511
1512   doFirst {
1513     println("Using projectFile "+projectFile)
1514   }
1515
1516   inputs.dir(getdownWebsiteDir)
1517   inputs.file(install4jConfFile)
1518   inputs.file("${install4jDir}/${install4j_info_plist_file_associations}")
1519   inputs.dir(macosJavaVMDir)
1520   inputs.dir(windowsJavaVMDir)
1521   outputs.dir("${jalviewDir}/${install4j_build_dir}/${JAVA_VERSION}")
1522 }
1523
1524
1525 task sourceDist(type: Tar) {
1526   
1527   def VERSION_UNDERSCORES = JALVIEW_VERSION.replaceAll("\\.", "_")
1528   def outputFileName = "${project.name}_${VERSION_UNDERSCORES}.tar.gz"
1529   // cater for buildship < 3.1 [3.0.1 is max version in eclipse 2018-09]
1530   try {
1531     archiveFileName = outputFileName
1532   } catch (Exception e) {
1533     archiveName = outputFileName
1534   }
1535   
1536   compression Compression.GZIP
1537   
1538   into project.name
1539
1540   def EXCLUDE_FILES=[
1541     "build/*",
1542     "bin/*",
1543     "test-output/",
1544     "test-reports",
1545     "tests",
1546     "clover*/*",
1547     ".*",
1548     "benchmarking/*",
1549     "**/.*",
1550     "*.class",
1551     "**/*.class","$j11modDir/**/*.jar","appletlib","**/*locales",
1552     "*locales/**",
1553     "utils/InstallAnywhere",
1554     "**/*.log",
1555   ] 
1556   def PROCESS_FILES=[
1557     "AUTHORS",
1558     "CITATION",
1559     "FEATURETODO",
1560     "JAVA-11-README",
1561     "FEATURETODO",
1562     "LICENSE",
1563     "**/README",
1564     "RELEASE",
1565     "THIRDPARTYLIBS",
1566     "TESTNG",
1567     "build.gradle",
1568     "gradle.properties",
1569     "**/*.java",
1570     "**/*.html",
1571     "**/*.xml",
1572     "**/*.gradle",
1573     "**/*.groovy",
1574     "**/*.properties",
1575     "**/*.perl",
1576     "**/*.sh",
1577   ]
1578   def INCLUDE_FILES=[
1579     ".settings/org.eclipse.jdt.core.jalview.prefs",
1580   ]
1581
1582   from(jalviewDir) {
1583     exclude (EXCLUDE_FILES)
1584     include (PROCESS_FILES)
1585     filter(ReplaceTokens,
1586       beginToken: '$$',
1587       endToken: '$$',
1588       tokens: [
1589         'Version-Rel': JALVIEW_VERSION,
1590         'Year-Rel': getDate("yyyy")
1591       ]
1592     )
1593   }
1594   from(jalviewDir) {
1595     exclude (EXCLUDE_FILES)
1596     exclude (PROCESS_FILES)
1597     exclude ("appletlib")
1598     exclude ("**/*locales")
1599     exclude ("*locales/**")
1600     exclude ("utils/InstallAnywhere")
1601
1602     exclude (getdown_files_dir)
1603     exclude (getdown_website_dir)
1604
1605     // exluding these as not using jars as modules yet
1606     exclude ("$j11modDir/**/*.jar")
1607   }
1608   from(jalviewDir) {
1609     include(INCLUDE_FILES)
1610   }
1611 //  from (jalviewDir) {
1612 //    // explicit includes for stuff that seemed to not get included
1613 //    include(fileTree("test/**/*."))
1614 //    exclude(EXCLUDE_FILES)
1615 //    exclude(PROCESS_FILES)
1616 //  }
1617 }
1618
1619
1620 task helppages {
1621   dependsOn copyHelp
1622   dependsOn pubhtmlhelp
1623   
1624   inputs.dir("${classesDir}/${help_dir}")
1625   outputs.dir("${buildDir}/distributions/${help_dir}")
1626 }
1627
1628 // LARGE AMOUNT OF JALVIEWJS STUFF DELETED HERE
1629 task eclipseAutoBuildTask {}
1630 task eclipseSynchronizationTask {}