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