1 /* Convention for properties. Read from gradle.properties, use lower_case_underlines for property names.
2 * For properties set within build.gradle, use camelCaseNoSpace.
4 import org.apache.tools.ant.filters.ReplaceTokens
5 import org.gradle.internal.os.OperatingSystem
6 import org.gradle.plugins.ide.internal.generator.PropertiesPersistableConfigurationObject
7 import org.gradle.api.internal.PropertiesTransformer
8 import org.gradle.util.ConfigureUtil
9 import org.gradle.plugins.ide.eclipse.model.Output
10 import org.gradle.plugins.ide.eclipse.model.Library
11 import java.security.MessageDigest
12 import java.util.regex.Matcher
13 import groovy.transform.ExternalizeMethods
14 import groovy.util.XmlParser
15 import groovy.xml.XmlUtil
16 import groovy.json.JsonBuilder
17 import com.vladsch.flexmark.util.ast.Node
18 import com.vladsch.flexmark.html.HtmlRenderer
19 import com.vladsch.flexmark.parser.Parser
20 import com.vladsch.flexmark.util.data.MutableDataSet
21 import com.vladsch.flexmark.ext.gfm.tasklist.TaskListExtension
22 import com.vladsch.flexmark.ext.tables.TablesExtension
23 import com.vladsch.flexmark.ext.gfm.strikethrough.StrikethroughExtension
24 import com.vladsch.flexmark.ext.autolink.AutolinkExtension
25 import com.vladsch.flexmark.ext.anchorlink.AnchorLinkExtension
26 import com.vladsch.flexmark.ext.toc.TocExtension
27 import com.google.common.hash.HashCode
28 import com.google.common.hash.Hashing
29 import com.google.common.io.Files
30 import org.jsoup.Jsoup
31 import org.jsoup.nodes.Element
39 classpath "com.vladsch.flexmark:flexmark-all:0.62.0"
40 classpath "org.jsoup:jsoup:1.14.3"
41 classpath "com.eowise:gradle-imagemagick:0.5.1"
50 id "com.diffplug.gradle.spotless" version "3.28.0"
51 id 'com.github.johnrengelman.shadow' version '4.0.3'
52 id 'com.install4j.gradle' version '10.0.3'
53 id 'com.dorongold.task-tree' version '2.1.1' // only needed to display task dependency tree with gradle task1 [task2 ...] taskTree
54 id 'com.palantir.git-version' version '0.13.0' apply false
65 // in ext the values are cast to Object. Ensure string values are cast as String (and not GStringImpl) for later use
66 def string(Object o) {
67 return o == null ? "" : o.toString()
70 def overrideProperties(String propsFileName, boolean output = false) {
71 if (propsFileName == null) {
74 def propsFile = file(propsFileName)
75 if (propsFile != null && propsFile.exists()) {
76 println("Using properties from file '${propsFileName}'")
78 def p = new Properties()
79 def localPropsFIS = new FileInputStream(propsFile)
85 if (project.hasProperty(key)) {
86 oldval = project.findProperty(key)
87 project.setProperty(key, val)
89 println("Overriding property '${key}' ('${oldval}') with ${file(propsFile).getName()} value '${val}'")
92 ext.setProperty(key, val)
94 println("Setting ext property '${key}' with ${file(propsFile).getName()}s value '${val}'")
98 } catch (Exception e) {
99 println("Exception reading local.properties")
106 jalviewDirAbsolutePath = file(jalviewDir).getAbsolutePath()
107 jalviewDirRelativePath = jalviewDir
110 getdownChannelName = CHANNEL.toLowerCase()
111 // default to "default". Currently only has different cosmetics for "develop", "release", "default"
112 propertiesChannelName = ["develop", "release", "test-release", "jalviewjs", "jalviewjs-release" ].contains(getdownChannelName) ? getdownChannelName : "default"
113 channelDirName = propertiesChannelName
114 // Import channel_properties
115 if (getdownChannelName.startsWith("develop-")) {
116 channelDirName = "develop-SUFFIX"
118 channelDir = string("${jalviewDir}/${channel_properties_dir}/${channelDirName}")
119 channelGradleProperties = string("${channelDir}/channel_gradle.properties")
120 channelPropsFile = string("${channelDir}/${resource_dir}/${channel_props}")
121 overrideProperties(channelGradleProperties, false)
122 // local build environment properties
123 // can be "projectDir/local.properties"
124 overrideProperties("${projectDir}/local.properties", true)
125 // or "../projectDir_local.properties"
126 overrideProperties(projectDir.getParent() + "/" + projectDir.getName() + "_local.properties", true)
129 // Import releaseProps from the RELEASE file
130 // or a file specified via JALVIEW_RELEASE_FILE if defined
131 // Expect jalview.version and target release branch in jalview.release
132 releaseProps = new Properties();
133 def releasePropFile = findProperty("JALVIEW_RELEASE_FILE");
134 def defaultReleasePropFile = "${jalviewDirAbsolutePath}/RELEASE";
136 (new File(releasePropFile!=null ? releasePropFile : defaultReleasePropFile)).withInputStream {
137 releaseProps.load(it)
139 } catch (Exception fileLoadError) {
140 throw new Error("Couldn't load release properties file "+(releasePropFile==null ? defaultReleasePropFile : "from custom location: releasePropFile"),fileLoadError);
143 // Set JALVIEW_VERSION if it is not already set
144 if (findProperty("JALVIEW_VERSION")==null || "".equals(JALVIEW_VERSION)) {
145 JALVIEW_VERSION = releaseProps.get("jalview.version")
147 println("JALVIEW_VERSION is set to '${JALVIEW_VERSION}'")
149 // this property set when running Eclipse headlessly
150 j2sHeadlessBuildProperty = string("net.sf.j2s.core.headlessbuild")
151 // this property set by Eclipse
152 eclipseApplicationProperty = string("eclipse.application")
153 // CHECK IF RUNNING FROM WITHIN ECLIPSE
154 def eclipseApplicationPropertyVal = System.properties[eclipseApplicationProperty]
155 IN_ECLIPSE = eclipseApplicationPropertyVal != null && eclipseApplicationPropertyVal.startsWith("org.eclipse.ui.")
156 // BUT WITHOUT THE HEADLESS BUILD PROPERTY SET
157 if (System.properties[j2sHeadlessBuildProperty].equals("true")) {
158 println("Setting IN_ECLIPSE to ${IN_ECLIPSE} as System.properties['${j2sHeadlessBuildProperty}'] == '${System.properties[j2sHeadlessBuildProperty]}'")
162 println("WITHIN ECLIPSE IDE")
164 println("HEADLESS BUILD")
167 J2S_ENABLED = (project.hasProperty('j2s.compiler.status') && project['j2s.compiler.status'] != null && project['j2s.compiler.status'] == "enable")
169 println("J2S ENABLED")
172 System.properties.sort { it.key }.each {
173 key, val -> println("SYSTEM PROPERTY ${key}='${val}'")
176 if (false && IN_ECLIPSE) {
177 jalviewDir = jalviewDirAbsolutePath
182 buildDate = new Date().format("yyyyMMdd")
185 bareSourceDir = string(source_dir)
186 sourceDir = string("${jalviewDir}/${bareSourceDir}")
187 resourceDir = string("${jalviewDir}/${resource_dir}")
188 bareTestSourceDir = string(test_source_dir)
189 testDir = string("${jalviewDir}/${bareTestSourceDir}")
191 classesDir = string("${jalviewDir}/${classes_dir}")
194 useClover = clover.equals("true")
195 cloverBuildDir = "${buildDir}/clover"
196 cloverInstrDir = file("${cloverBuildDir}/clover-instr")
197 cloverClassesDir = file("${cloverBuildDir}/clover-classes")
198 cloverReportDir = file("${buildDir}/reports/clover")
199 cloverTestInstrDir = file("${cloverBuildDir}/clover-test-instr")
200 cloverTestClassesDir = file("${cloverBuildDir}/clover-test-classes")
201 //cloverTestClassesDir = cloverClassesDir
202 cloverDb = string("${cloverBuildDir}/clover.db")
204 testSourceDir = useClover ? cloverTestInstrDir : testDir
205 testClassesDir = useClover ? cloverTestClassesDir : "${jalviewDir}/${test_output_dir}"
208 backgroundImageText = BACKGROUNDIMAGETEXT
209 getdownChannelDir = string("${getdown_website_dir}/${propertiesChannelName}")
210 getdownAppBaseDir = string("${jalviewDir}/${getdownChannelDir}/${JAVA_VERSION}")
211 getdownArchiveDir = string("${jalviewDir}/${getdown_archive_dir}")
212 getdownFullArchiveDir = null
213 getdownTextLines = []
214 getdownLaunchJvl = null
215 getdownVersionLaunchJvl = null
217 buildProperties = null
219 // the following values might be overridden by the CHANNEL switch
220 getdownDir = string("${getdownChannelName}/${JAVA_VERSION}")
221 getdownAppBase = string("${getdown_channel_base}/${getdownDir}")
222 getdownArchiveAppBase = getdown_archive_base
223 getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher}")
224 getdownAppDistDir = getdown_app_dir_alt
225 getdownImagesDir = string("${jalviewDir}/${getdown_images_dir}")
226 getdownImagesBuildDir = string("${buildDir}/imagemagick/getdown")
227 getdownSetAppBaseProperty = false // whether to pass the appbase and appdistdir to the application
228 reportRsyncCommand = false
229 jvlChannelName = CHANNEL.toLowerCase()
230 install4jSuffix = CHANNEL.substring(0, 1).toUpperCase() + CHANNEL.substring(1).toLowerCase(); // BUILD -> Build
231 install4jDMGDSStore = "${install4j_images_dir}/${install4j_dmg_ds_store}"
232 install4jDMGBackgroundImageDir = "${install4j_images_dir}"
233 install4jDMGBackgroundImageBuildDir = "build/imagemagick/install4j"
234 install4jDMGBackgroundImageFile = "${install4j_dmg_background}"
235 install4jInstallerName = "${jalview_name} Non-Release Installer"
236 install4jExecutableName = install4j_executable_name
237 install4jExtraScheme = "jalviewx"
238 install4jMacIconsFile = string("${install4j_images_dir}/${install4j_mac_icons_file}")
239 install4jWindowsIconsFile = string("${install4j_images_dir}/${install4j_windows_icons_file}")
240 install4jPngIconFile = string("${install4j_images_dir}/${install4j_png_icon_file}")
241 install4jBackground = string("${install4j_images_dir}/${install4j_background}")
242 install4jBuildDir = "${install4j_build_dir}/${JAVA_VERSION}"
243 install4jCheckSums = true
245 applicationName = "${jalview_name}"
249 // TODO: get bamboo build artifact URL for getdown artifacts
250 getdown_channel_base = bamboo_channelbase
251 getdownChannelName = string("${bamboo_planKey}/${JAVA_VERSION}")
252 getdownAppBase = string("${bamboo_channelbase}/${bamboo_planKey}${bamboo_getdown_channel_suffix}/${JAVA_VERSION}")
253 jvlChannelName += "_${getdownChannelName}"
254 // automatically add the test group Not-bamboo for exclusion
255 if ("".equals(testng_excluded_groups)) {
256 testng_excluded_groups = "Not-bamboo"
258 install4jExtraScheme = "jalviewb"
259 backgroundImageText = true
262 case [ "RELEASE", "JALVIEWJS-RELEASE" ]:
263 getdownAppDistDir = getdown_app_dir_release
264 getdownSetAppBaseProperty = true
265 reportRsyncCommand = true
267 install4jInstallerName = "${jalview_name} Installer"
271 getdownChannelName = CHANNEL.toLowerCase()+"/${JALVIEW_VERSION}"
272 getdownDir = string("${getdownChannelName}/${JAVA_VERSION}")
273 getdownAppBase = string("${getdown_channel_base}/${getdownDir}")
274 if (!file("${ARCHIVEDIR}/${package_dir}").exists()) {
275 throw new GradleException("Must provide an ARCHIVEDIR value to produce an archive distribution")
277 package_dir = string("${ARCHIVEDIR}/${package_dir}")
278 buildProperties = string("${ARCHIVEDIR}/${classes_dir}/${build_properties_file}")
281 reportRsyncCommand = true
282 install4jExtraScheme = "jalviewa"
286 getdownChannelName = string("archive/${JALVIEW_VERSION}")
287 getdownDir = string("${getdownChannelName}/${JAVA_VERSION}")
288 getdownAppBase = file(getdownAppBaseDir).toURI().toString()
289 if (!file("${ARCHIVEDIR}/${package_dir}").exists()) {
290 throw new GradleException("Must provide an ARCHIVEDIR value to produce an archive distribution [did not find '${ARCHIVEDIR}/${package_dir}']")
292 package_dir = string("${ARCHIVEDIR}/${package_dir}")
293 buildProperties = string("${ARCHIVEDIR}/${classes_dir}/${build_properties_file}")
296 reportRsyncCommand = true
297 getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher_local}")
298 install4jSuffix = "Archive"
299 install4jExtraScheme = "jalviewa"
302 case ~/^DEVELOP-([\.\-\w]*)$/:
303 def suffix = Matcher.lastMatcher[0][1]
304 reportRsyncCommand = true
305 getdownSetAppBaseProperty = true
306 JALVIEW_VERSION=JALVIEW_VERSION+"-d${suffix}-${buildDate}"
307 install4jSuffix = "Develop ${suffix}"
308 install4jExtraScheme = "jalviewd"
309 install4jInstallerName = "${jalview_name} Develop ${suffix} Installer"
310 getdownChannelName = string("develop-${suffix}")
311 getdownChannelDir = string("${getdown_website_dir}/${getdownChannelName}")
312 getdownAppBaseDir = string("${jalviewDir}/${getdownChannelDir}/${JAVA_VERSION}")
313 getdownDir = string("${getdownChannelName}/${JAVA_VERSION}")
314 getdownAppBase = string("${getdown_channel_base}/${getdownDir}")
315 channelSuffix = string(suffix)
316 backgroundImageText = true
320 reportRsyncCommand = true
321 getdownSetAppBaseProperty = true
322 // DEVELOP-RELEASE is usually associated with a Jalview release series so set the version
323 JALVIEW_VERSION=JALVIEW_VERSION+"-d${buildDate}"
325 install4jSuffix = "Develop"
326 install4jExtraScheme = "jalviewd"
327 install4jInstallerName = "${jalview_name} Develop Installer"
328 backgroundImageText = true
332 reportRsyncCommand = true
333 getdownSetAppBaseProperty = true
334 // Don't ignore transpile errors for release build
335 if (jalviewjs_ignore_transpile_errors.equals("true")) {
336 jalviewjs_ignore_transpile_errors = "false"
337 println("Setting jalviewjs_ignore_transpile_errors to 'false'")
339 JALVIEW_VERSION = JALVIEW_VERSION+"-test"
340 install4jSuffix = "Test"
341 install4jExtraScheme = "jalviewt"
342 install4jInstallerName = "${jalview_name} Test Installer"
343 backgroundImageText = true
346 case ~/^SCRATCH(|-[-\w]*)$/:
347 getdownChannelName = CHANNEL
348 JALVIEW_VERSION = JALVIEW_VERSION+"-"+CHANNEL
350 getdownDir = string("${getdownChannelName}/${JAVA_VERSION}")
351 getdownAppBase = string("${getdown_channel_base}/${getdownDir}")
352 reportRsyncCommand = true
353 install4jSuffix = "Scratch"
357 if (!file("${LOCALDIR}").exists()) {
358 throw new GradleException("Must provide a LOCALDIR value to produce a local distribution")
360 getdownAppBase = file(file("${LOCALDIR}").getAbsolutePath()).toURI().toString()
361 getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher_local}")
363 JALVIEW_VERSION = "TEST"
364 install4jSuffix = "Test-Local"
365 install4jExtraScheme = "jalviewt"
366 install4jInstallerName = "${jalview_name} Test Installer"
367 backgroundImageText = true
370 case [ "LOCAL", "JALVIEWJS" ]:
371 JALVIEW_VERSION = "TEST"
372 getdownAppBase = file(getdownAppBaseDir).toURI().toString()
373 getdownArchiveAppBase = file("${jalviewDir}/${getdown_archive_dir}").toURI().toString()
374 getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher_local}")
375 install4jExtraScheme = "jalviewl"
376 install4jCheckSums = false
379 default: // something wrong specified
380 throw new GradleException("CHANNEL must be one of BUILD, RELEASE, ARCHIVE, DEVELOP, TEST-RELEASE, SCRATCH-..., LOCAL [default]")
384 JALVIEW_VERSION_UNDERSCORES = JALVIEW_VERSION.replaceAll("\\.", "_")
385 hugoDataJsonFile = file("${jalviewDir}/${hugo_build_dir}/${hugo_data_installers_dir}/installers-${JALVIEW_VERSION_UNDERSCORES}.json")
386 hugoArchiveMdFile = file("${jalviewDir}/${hugo_build_dir}/${hugo_version_archive_dir}/Version-${JALVIEW_VERSION_UNDERSCORES}/_index.md")
387 // override getdownAppBase if requested
388 if (findProperty("getdown_appbase_override") != null) {
389 // revert to LOCAL if empty string
390 if (string(getdown_appbase_override) == "") {
391 getdownAppBase = file(getdownAppBaseDir).toURI().toString()
392 getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher_local}")
393 } else if (string(getdown_appbase_override).startsWith("file://")) {
394 getdownAppBase = string(getdown_appbase_override)
395 getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher_local}")
397 getdownAppBase = string(getdown_appbase_override)
399 println("Overriding getdown appbase with '${getdownAppBase}'")
401 // sanitise file name for jalview launcher file for this channel
402 jvlChannelName = jvlChannelName.replaceAll("[^\\w\\-]+", "_")
403 // install4j application and folder names
404 if (install4jSuffix == "") {
405 install4jBundleId = "${install4j_bundle_id}"
406 install4jWinApplicationId = install4j_release_win_application_id
408 applicationName = "${jalview_name} ${install4jSuffix}"
409 install4jBundleId = "${install4j_bundle_id}-" + install4jSuffix.toLowerCase()
410 // add int hash of install4jSuffix to the last part of the application_id
411 def id = install4j_release_win_application_id
412 def idsplitreverse = id.split("-").reverse()
413 idsplitreverse[0] = idsplitreverse[0].toInteger() + install4jSuffix.hashCode()
414 install4jWinApplicationId = idsplitreverse.reverse().join("-")
416 // sanitise folder and id names
417 // install4jApplicationFolder = e.g. "Jalview Build"
418 install4jApplicationFolder = applicationName
419 .replaceAll("[\"'~:/\\\\\\s]", "_") // replace all awkward filename chars " ' ~ : / \
420 .replaceAll("_+", "_") // collapse __
421 install4jInternalId = applicationName
423 .replaceAll("[^\\w\\-\\.]", "_") // replace other non [alphanumeric,_,-,.]
424 .replaceAll("_+", "") // collapse __
425 //.replaceAll("_*-_*", "-") // collapse _-_
426 install4jUnixApplicationFolder = applicationName
428 .replaceAll("[^\\w\\-\\.]", "_") // replace other non [alphanumeric,_,-,.]
429 .replaceAll("_+", "_") // collapse __
430 .replaceAll("_*-_*", "-") // collapse _-_
433 getdownWrapperLink = install4jUnixApplicationFolder // e.g. "jalview_local"
434 getdownAppDir = string("${getdownAppBaseDir}/${getdownAppDistDir}")
435 //getdownJ11libDir = "${getdownAppBaseDir}/${getdown_j11lib_dir}"
436 getdownResourceDir = string("${getdownAppBaseDir}/${getdown_resource_dir}")
437 getdownInstallDir = string("${getdownAppBaseDir}/${getdown_install_dir}")
438 getdownFilesDir = string("${jalviewDir}/${getdown_files_dir}/${JAVA_VERSION}/")
439 getdownFilesInstallDir = string("${getdownFilesDir}/${getdown_install_dir}")
440 /* compile without modules -- using classpath libraries
441 modules_compileClasspath = fileTree(dir: "${jalviewDir}/${j11modDir}", include: ["*.jar"])
442 modules_runtimeClasspath = modules_compileClasspath
448 apply plugin: "com.palantir.git-version"
449 def details = versionDetails()
450 gitHash = details.gitHash
451 gitBranch = details.branchName
452 } catch(org.gradle.api.internal.plugins.PluginApplicationException e) {
453 println("Not in a git repository. Using git values from RELEASE properties file.")
454 gitHash = releaseProps.getProperty("git.hash")
455 gitBranch = releaseProps.getProperty("git.branch")
456 } catch(java.lang.RuntimeException e1) {
457 throw new GradleException("Error with git-version plugin. Directory '.git' exists but versionDetails() cannot be found.")
460 println("Using a ${CHANNEL} profile.")
462 additional_compiler_args = []
463 // configure classpath/args for j8/j11 compilation
464 if (JAVA_VERSION.equals("1.8")) {
465 JAVA_INTEGER_VERSION = string("8")
468 libDistDir = j8libDir
469 compile_source_compatibility = 1.8
470 compile_target_compatibility = 1.8
471 // these are getdown.txt properties defined dependent on the JAVA_VERSION
472 getdownAltJavaMinVersion = string(findProperty("getdown_alt_java8_min_version"))
473 getdownAltJavaMaxVersion = string(findProperty("getdown_alt_java8_max_version"))
474 // this property is assigned below and expanded to multiple lines in the getdown task
475 getdownAltMultiJavaLocation = string(findProperty("getdown_alt_java8_txt_multi_java_location"))
476 // this property is for the Java library used in eclipse
477 eclipseJavaRuntimeName = string("JavaSE-1.8")
478 } else if (JAVA_VERSION.equals("11")) {
479 JAVA_INTEGER_VERSION = string("11")
481 libDistDir = j11libDir
482 compile_source_compatibility = 11
483 compile_target_compatibility = 11
484 getdownAltJavaMinVersion = string(findProperty("getdown_alt_java11_min_version"))
485 getdownAltJavaMaxVersion = string(findProperty("getdown_alt_java11_max_version"))
486 getdownAltMultiJavaLocation = string(findProperty("getdown_alt_java11_txt_multi_java_location"))
487 eclipseJavaRuntimeName = string("JavaSE-11")
488 /* compile without modules -- using classpath libraries
489 additional_compiler_args += [
490 '--module-path', modules_compileClasspath.asPath,
491 '--add-modules', j11modules
494 } else if (JAVA_VERSION.equals("17")) {
495 JAVA_INTEGER_VERSION = string("17")
497 libDistDir = j17libDir
498 compile_source_compatibility = 17
499 compile_target_compatibility = 17
500 getdownAltJavaMinVersion = string(findProperty("getdown_alt_java11_min_version"))
501 getdownAltJavaMaxVersion = string(findProperty("getdown_alt_java11_max_version"))
502 getdownAltMultiJavaLocation = string(findProperty("getdown_alt_java11_txt_multi_java_location"))
503 eclipseJavaRuntimeName = string("JavaSE-17")
504 /* compile without modules -- using classpath libraries
505 additional_compiler_args += [
506 '--module-path', modules_compileClasspath.asPath,
507 '--add-modules', j11modules
511 throw new GradleException("JAVA_VERSION=${JAVA_VERSION} not currently supported by Jalview")
516 JAVA_MIN_VERSION = JAVA_VERSION
517 JAVA_MAX_VERSION = JAVA_VERSION
518 jreInstallsDir = string(jre_installs_dir)
519 if (jreInstallsDir.startsWith("~/")) {
520 jreInstallsDir = System.getProperty("user.home") + jreInstallsDir.substring(1)
522 install4jDir = string("${jalviewDir}/${install4j_utils_dir}")
523 install4jConfFileName = string("jalview-install4j-conf.install4j")
524 install4jConfFile = file("${install4jDir}/${install4jConfFileName}")
525 install4jHomeDir = install4j_home_dir
526 if (install4jHomeDir.startsWith("~/")) {
527 install4jHomeDir = System.getProperty("user.home") + install4jHomeDir.substring(1)
530 resourceBuildDir = string("${buildDir}/resources")
531 resourcesBuildDir = string("${resourceBuildDir}/resources_build")
532 helpBuildDir = string("${resourceBuildDir}/help_build")
533 docBuildDir = string("${resourceBuildDir}/doc_build")
535 if (buildProperties == null) {
536 buildProperties = string("${resourcesBuildDir}/${build_properties_file}")
538 buildingHTML = string("${jalviewDir}/${doc_dir}/building.html")
539 helpParentDir = string("${jalviewDir}/${help_parent_dir}")
540 helpSourceDir = string("${helpParentDir}/${help_dir}")
541 helpFile = string("${helpBuildDir}/${help_dir}/help.jhm")
544 convertBinaryExpectedLocation = imagemagick_convert
545 if (convertBinaryExpectedLocation.startsWith("~/")) {
546 convertBinaryExpectedLocation = System.getProperty("user.home") + convertBinaryExpectedLocation.substring(1)
548 if (file(convertBinaryExpectedLocation).exists()) {
549 convertBinary = convertBinaryExpectedLocation
552 relativeBuildDir = file(jalviewDirAbsolutePath).toPath().relativize(buildDir.toPath())
553 jalviewjsBuildDir = string("${relativeBuildDir}/jalviewjs")
554 jalviewjsSiteDir = string("${jalviewjsBuildDir}/${jalviewjs_site_dir}")
556 jalviewjsTransferSiteJsDir = string(jalviewjsSiteDir)
558 jalviewjsTransferSiteJsDir = string("${jalviewjsBuildDir}/tmp/${jalviewjs_site_dir}_js")
560 jalviewjsTransferSiteLibDir = string("${jalviewjsBuildDir}/tmp/${jalviewjs_site_dir}_lib")
561 jalviewjsTransferSiteSwingJsDir = string("${jalviewjsBuildDir}/tmp/${jalviewjs_site_dir}_swingjs")
562 jalviewjsTransferSiteCoreDir = string("${jalviewjsBuildDir}/tmp/${jalviewjs_site_dir}_core")
563 jalviewjsJalviewCoreHtmlFile = string("")
564 jalviewjsJalviewCoreName = string(jalviewjs_core_name)
565 jalviewjsCoreClasslists = []
566 jalviewjsJalviewTemplateName = string(jalviewjs_name)
567 jalviewjsJ2sSettingsFileName = string("${jalviewDir}/${jalviewjs_j2s_settings}")
568 jalviewjsJ2sAltSettingsFileName = string("${jalviewDir}/${jalviewjs_j2s_alt_settings}")
569 jalviewjsJ2sProps = null
570 jalviewjsJ2sPlugin = jalviewjs_j2s_plugin
572 eclipseWorkspace = null
573 eclipseBinary = string("")
574 eclipseVersion = string("")
584 outputDir = file(classesDir)
588 srcDirs = [ resourcesBuildDir, docBuildDir, helpBuildDir ]
591 compileClasspath = files(sourceSets.main.java.outputDir)
592 compileClasspath += fileTree(dir: "${jalviewDir}/${libDir}", include: ["*.jar"])
594 runtimeClasspath = compileClasspath
595 runtimeClasspath += files(sourceSets.main.resources.srcDirs)
600 srcDirs cloverInstrDir
601 outputDir = cloverClassesDir
605 srcDirs = sourceSets.main.resources.srcDirs
608 compileClasspath = files( sourceSets.clover.java.outputDir )
609 //compileClasspath += files( testClassesDir )
610 compileClasspath += fileTree(dir: "${jalviewDir}/${libDir}", include: ["*.jar"])
611 compileClasspath += fileTree(dir: "${jalviewDir}/${clover_lib_dir}", include: ["*.jar"])
612 compileClasspath += fileTree(dir: "${jalviewDir}/${utils_dir}/testnglibs", include: ["**/*.jar"])
614 runtimeClasspath = compileClasspath
619 srcDirs testSourceDir
620 outputDir = file(testClassesDir)
624 srcDirs = useClover ? sourceSets.clover.resources.srcDirs : sourceSets.main.resources.srcDirs
627 compileClasspath = files( sourceSets.test.java.outputDir )
628 compileClasspath += useClover ? sourceSets.clover.compileClasspath : sourceSets.main.compileClasspath
629 compileClasspath += fileTree(dir: "${jalviewDir}/${utils_dir}/testnglibs", include: ["**/*.jar"])
631 runtimeClasspath = compileClasspath
632 runtimeClasspath += files(sourceSets.test.resources.srcDirs)
638 // eclipse project and settings files creation, also used by buildship
641 name = eclipse_project_name
643 natures 'org.eclipse.jdt.core.javanature',
644 'org.eclipse.jdt.groovy.core.groovyNature',
645 'org.eclipse.buildship.core.gradleprojectnature'
647 buildCommand 'org.eclipse.jdt.core.javabuilder'
648 buildCommand 'org.eclipse.buildship.core.gradleprojectbuilder'
652 //defaultOutputDir = sourceSets.main.java.outputDir
653 configurations.each{ c->
654 if (c.isCanBeResolved()) {
655 minusConfigurations += [c]
659 plusConfigurations = [ ]
663 def removeTheseToo = []
664 HashMap<String, Boolean> alreadyAddedSrcPath = new HashMap<>();
665 cp.entries.each { entry ->
666 // This conditional removes all src classpathentries that a) have already been added or b) aren't "src" or "test".
667 // e.g. this removes the resources dir being copied into bin/main, bin/test AND bin/clover
668 // we add the resources and help/help dirs in as libs afterwards (see below)
669 if (entry.kind == 'src') {
670 if (alreadyAddedSrcPath.getAt(entry.path) || !(entry.path == bareSourceDir || entry.path == bareTestSourceDir)) {
671 removeTheseToo += entry
673 alreadyAddedSrcPath.putAt(entry.path, true)
678 cp.entries.removeAll(removeTheseToo)
680 //cp.entries += new Output("${eclipse_bin_dir}/main")
681 if (file(helpParentDir).isDirectory()) {
682 cp.entries += new Library(fileReference(helpParentDir))
684 if (file(resourceDir).isDirectory()) {
685 cp.entries += new Library(fileReference(resourceDir))
688 HashMap<String, Boolean> alreadyAddedLibPath = new HashMap<>();
690 sourceSets.main.compileClasspath.findAll { it.name.endsWith(".jar") }.any {
691 //don't want to add outputDir as eclipse is using its own output dir in bin/main
692 if (it.isDirectory() || ! it.exists()) {
693 // don't add dirs to classpath, especially if they don't exist
694 return false // groovy "continue" in .any closure
696 def itPath = it.toString()
697 if (itPath.startsWith("${jalviewDirAbsolutePath}/")) {
698 // make relative path
699 itPath = itPath.substring(jalviewDirAbsolutePath.length()+1)
701 if (alreadyAddedLibPath.get(itPath)) {
702 //println("Not adding duplicate entry "+itPath)
704 //println("Adding entry "+itPath)
705 cp.entries += new Library(fileReference(itPath))
706 alreadyAddedLibPath.put(itPath, true)
710 sourceSets.test.compileClasspath.findAll { it.name.endsWith(".jar") }.any {
711 //no longer want to add outputDir as eclipse is using its own output dir in bin/main
712 if (it.isDirectory() || ! it.exists()) {
713 // don't add dirs to classpath
714 return false // groovy "continue" in .any closure
717 def itPath = it.toString()
718 if (itPath.startsWith("${jalviewDirAbsolutePath}/")) {
719 itPath = itPath.substring(jalviewDirAbsolutePath.length()+1)
721 if (alreadyAddedLibPath.get(itPath)) {
724 def lib = new Library(fileReference(itPath))
725 lib.entryAttributes["test"] = "true"
727 alreadyAddedLibPath.put(itPath, true)
735 containers 'org.eclipse.buildship.core.gradleclasspathcontainer'
740 // for the IDE, use java 11 compatibility
741 sourceCompatibility = compile_source_compatibility
742 targetCompatibility = compile_target_compatibility
743 javaRuntimeName = eclipseJavaRuntimeName
745 // add in jalview project specific properties/preferences into eclipse core preferences
747 withProperties { props ->
748 def jalview_prefs = new Properties()
749 def ins = new FileInputStream("${jalviewDirAbsolutePath}/${eclipse_extra_jdt_prefs_file}")
750 jalview_prefs.load(ins)
752 jalview_prefs.forEach { t, v ->
753 if (props.getAt(t) == null) {
757 // codestyle file -- overrides previous formatter prefs
758 def csFile = file("${jalviewDirAbsolutePath}/${eclipse_codestyle_file}")
759 if (csFile.exists()) {
760 XmlParser parser = new XmlParser()
761 def profiles = parser.parse(csFile)
762 def profile = profiles.'profile'.find { p -> (p.'@kind' == "CodeFormatterProfile" && p.'@name' == "Jalview") }
763 if (profile != null) {
764 profile.'setting'.each { s ->
766 def value = s.'@value'
767 if (id != null && value != null) {
768 props.putAt(id, value)
779 // Don't want these to be activated if in headless build
780 synchronizationTasks "eclipseSynchronizationTask"
781 //autoBuildTasks "eclipseAutoBuildTask"
787 /* hack to change eclipse prefs in .settings files other than org.eclipse.jdt.core.prefs */
788 // Class to allow updating arbitrary properties files
789 class PropertiesFile extends PropertiesPersistableConfigurationObject {
790 public PropertiesFile(PropertiesTransformer t) { super(t); }
791 @Override protected void load(Properties properties) { }
792 @Override protected void store(Properties properties) { }
793 @Override protected String getDefaultResourceName() { return ""; }
794 // This is necessary, because PropertiesPersistableConfigurationObject fails
795 // if no default properties file exists.
796 @Override public void loadDefaults() { load(new StringBufferInputStream("")); }
799 // Task to update arbitrary properties files (set outputFile)
800 class PropertiesFileTask extends PropertiesGeneratorTask<PropertiesFile> {
801 private final PropertiesFileContentMerger file;
802 public PropertiesFileTask() { file = new PropertiesFileContentMerger(getTransformer()); }
803 protected PropertiesFile create() { return new PropertiesFile(getTransformer()); }
804 protected void configure(PropertiesFile props) {
805 file.getBeforeMerged().execute(props); file.getWhenMerged().execute(props);
807 public void file(Closure closure) { ConfigureUtil.configure(closure, file); }
810 task eclipseUIPreferences(type: PropertiesFileTask) {
811 description = "Generate Eclipse additional settings"
812 def filename = "org.eclipse.jdt.ui.prefs"
813 outputFile = "$projectDir/.settings/${filename}" as File
816 it.load new FileInputStream("$projectDir/utils/eclipse/${filename}" as String)
821 task eclipseGroovyCorePreferences(type: PropertiesFileTask) {
822 description = "Generate Eclipse additional settings"
823 def filename = "org.eclipse.jdt.groovy.core.prefs"
824 outputFile = "$projectDir/.settings/${filename}" as File
827 it.load new FileInputStream("$projectDir/utils/eclipse/${filename}" as String)
832 task eclipseAllPreferences {
834 dependsOn eclipseUIPreferences
835 dependsOn eclipseGroovyCorePreferences
838 eclipseUIPreferences.mustRunAfter eclipseJdt
839 eclipseGroovyCorePreferences.mustRunAfter eclipseJdt
841 /* end of eclipse preferences hack */
849 delete cloverBuildDir
850 delete cloverReportDir
855 task cloverInstrJava(type: JavaExec) {
856 group = "Verification"
857 description = "Create clover instrumented source java files"
859 dependsOn cleanClover
861 inputs.files(sourceSets.main.allJava)
862 outputs.dir(cloverInstrDir)
864 //classpath = fileTree(dir: "${jalviewDir}/${clover_lib_dir}", include: ["*.jar"])
865 classpath = sourceSets.clover.compileClasspath
866 main = "com.atlassian.clover.CloverInstr"
874 cloverInstrDir.getPath(),
876 def srcFiles = sourceSets.main.allJava.files
879 { file -> file.absolutePath }
882 args argsList.toArray()
885 delete cloverInstrDir
886 println("Clover: About to instrument "+srcFiles.size() +" files")
891 task cloverInstrTests(type: JavaExec) {
892 group = "Verification"
893 description = "Create clover instrumented source test files"
895 dependsOn cleanClover
897 inputs.files(testDir)
898 outputs.dir(cloverTestInstrDir)
900 classpath = sourceSets.clover.compileClasspath
901 main = "com.atlassian.clover.CloverInstr"
911 cloverTestInstrDir.getPath(),
913 args argsList.toArray()
916 delete cloverTestInstrDir
917 println("Clover: About to instrument test files")
923 group = "Verification"
924 description = "Create clover instrumented all source files"
926 dependsOn cloverInstrJava
927 dependsOn cloverInstrTests
931 cloverClasses.dependsOn cloverInstr
934 task cloverConsoleReport(type: JavaExec) {
935 group = "Verification"
936 description = "Creates clover console report"
939 file(cloverDb).exists()
942 inputs.dir cloverClassesDir
944 classpath = sourceSets.clover.runtimeClasspath
945 main = "com.atlassian.clover.reporters.console.ConsoleReporter"
947 if (cloverreport_mem.length() > 0) {
948 maxHeapSize = cloverreport_mem
950 if (cloverreport_jvmargs.length() > 0) {
951 jvmArgs Arrays.asList(cloverreport_jvmargs.split(" "))
961 args argsList.toArray()
965 task cloverHtmlReport(type: JavaExec) {
966 group = "Verification"
967 description = "Creates clover HTML report"
970 file(cloverDb).exists()
973 def cloverHtmlDir = cloverReportDir
974 inputs.dir cloverClassesDir
975 outputs.dir cloverHtmlDir
977 classpath = sourceSets.clover.runtimeClasspath
978 main = "com.atlassian.clover.reporters.html.HtmlReporter"
980 if (cloverreport_mem.length() > 0) {
981 maxHeapSize = cloverreport_mem
983 if (cloverreport_jvmargs.length() > 0) {
984 jvmArgs Arrays.asList(cloverreport_jvmargs.split(" "))
995 if (cloverreport_html_options.length() > 0) {
996 argsList += cloverreport_html_options.split(" ")
999 args argsList.toArray()
1003 task cloverXmlReport(type: JavaExec) {
1004 group = "Verification"
1005 description = "Creates clover XML report"
1008 file(cloverDb).exists()
1011 def cloverXmlFile = "${cloverReportDir}/clover.xml"
1012 inputs.dir cloverClassesDir
1013 outputs.file cloverXmlFile
1015 classpath = sourceSets.clover.runtimeClasspath
1016 main = "com.atlassian.clover.reporters.xml.XMLReporter"
1018 if (cloverreport_mem.length() > 0) {
1019 maxHeapSize = cloverreport_mem
1021 if (cloverreport_jvmargs.length() > 0) {
1022 jvmArgs Arrays.asList(cloverreport_jvmargs.split(" "))
1033 if (cloverreport_xml_options.length() > 0) {
1034 argsList += cloverreport_xml_options.split(" ")
1037 args argsList.toArray()
1042 group = "Verification"
1043 description = "Creates clover reports"
1045 dependsOn cloverXmlReport
1046 dependsOn cloverHtmlReport
1053 sourceCompatibility = compile_source_compatibility
1054 targetCompatibility = compile_target_compatibility
1055 options.compilerArgs += additional_compiler_args
1056 print ("Setting target compatibility to "+targetCompatibility+"\n")
1058 //classpath += configurations.cloverRuntime
1064 // JBP->BS should the print statement in doFirst refer to compile_target_compatibility ?
1065 sourceCompatibility = compile_source_compatibility
1066 targetCompatibility = compile_target_compatibility
1067 options.compilerArgs += additional_compiler_args
1068 options.encoding = "UTF-8"
1070 print ("Setting target compatibility to "+compile_target_compatibility+"\n")
1077 sourceCompatibility = compile_source_compatibility
1078 targetCompatibility = compile_target_compatibility
1079 options.compilerArgs += additional_compiler_args
1081 print ("Setting target compatibility to "+targetCompatibility+"\n")
1088 delete sourceSets.main.java.outputDir
1094 dependsOn cleanClover
1096 delete sourceSets.test.java.outputDir
1101 // format is a string like date.format("dd MMMM yyyy")
1102 def getDate(format) {
1103 return date.format(format)
1107 def convertMdToHtml (FileTree mdFiles, File cssFile) {
1108 MutableDataSet options = new MutableDataSet()
1110 def extensions = new ArrayList<>()
1111 extensions.add(AnchorLinkExtension.create())
1112 extensions.add(AutolinkExtension.create())
1113 extensions.add(StrikethroughExtension.create())
1114 extensions.add(TaskListExtension.create())
1115 extensions.add(TablesExtension.create())
1116 extensions.add(TocExtension.create())
1118 options.set(Parser.EXTENSIONS, extensions)
1120 // set GFM table parsing options
1121 options.set(TablesExtension.WITH_CAPTION, false)
1122 options.set(TablesExtension.COLUMN_SPANS, false)
1123 options.set(TablesExtension.MIN_HEADER_ROWS, 1)
1124 options.set(TablesExtension.MAX_HEADER_ROWS, 1)
1125 options.set(TablesExtension.APPEND_MISSING_COLUMNS, true)
1126 options.set(TablesExtension.DISCARD_EXTRA_COLUMNS, true)
1127 options.set(TablesExtension.HEADER_SEPARATOR_COLUMN_MATCH, true)
1129 options.set(AnchorLinkExtension.ANCHORLINKS_SET_ID, false)
1130 options.set(AnchorLinkExtension.ANCHORLINKS_ANCHOR_CLASS, "anchor")
1131 options.set(AnchorLinkExtension.ANCHORLINKS_SET_NAME, true)
1132 options.set(AnchorLinkExtension.ANCHORLINKS_TEXT_PREFIX, "<span class=\"octicon octicon-link\"></span>")
1134 Parser parser = Parser.builder(options).build()
1135 HtmlRenderer renderer = HtmlRenderer.builder(options).build()
1137 mdFiles.each { mdFile ->
1138 // add table of contents
1139 def mdText = "[TOC]\n"+mdFile.text
1141 // grab the first top-level title
1143 def titleRegex = /(?m)^#(\s+|([^#]))(.*)/
1144 def matcher = mdText =~ titleRegex
1145 if (matcher.size() > 0) {
1146 // matcher[0][2] is the first character of the title if there wasn't any whitespace after the #
1147 title = (matcher[0][2] != null ? matcher[0][2] : "")+matcher[0][3]
1149 // or use the filename if none found
1150 if (title == null) {
1151 title = mdFile.getName()
1154 Node document = parser.parse(mdText)
1155 String htmlBody = renderer.render(document)
1156 def htmlText = '''<html>
1157 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
1158 <html xmlns="http://www.w3.org/1999/xhtml">
1160 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
1161 <meta http-equiv="Content-Style-Type" content="text/css" />
1162 <meta name="generator" content="flexmark" />
1164 htmlText += ((title != null) ? " <title>${title}</title>" : '' )
1166 <style type="text/css">code{white-space: pre;}</style>
1168 htmlText += ((cssFile != null) ? cssFile.text : '')
1169 htmlText += '''</head>
1172 htmlText += htmlBody
1178 def htmlFilePath = mdFile.getPath().replaceAll(/\..*?$/, ".html")
1179 def htmlFile = file(htmlFilePath)
1180 println("Creating ${htmlFilePath}")
1181 htmlFile.text = htmlText
1186 task copyDocs(type: Copy) {
1187 def inputDir = "${jalviewDir}/${doc_dir}"
1188 def outputDir = "${docBuildDir}/${doc_dir}"
1192 include('**/*.html')
1194 filter(ReplaceTokens,
1198 'Version-Rel': JALVIEW_VERSION,
1199 'Year-Rel': getDate("yyyy")
1206 exclude('**/*.html')
1211 inputs.dir(inputDir)
1212 outputs.dir(outputDir)
1216 task convertMdFiles {
1218 def mdFiles = fileTree(dir: docBuildDir, include: "**/*.md")
1219 def cssFile = file("${jalviewDir}/${flexmark_css}")
1222 convertMdToHtml(mdFiles, cssFile)
1225 inputs.files(mdFiles)
1226 inputs.file(cssFile)
1229 mdFiles.each { mdFile ->
1230 def htmlFilePath = mdFile.getPath().replaceAll(/\..*?$/, ".html")
1231 htmlFiles.add(file(htmlFilePath))
1233 outputs.files(htmlFiles)
1237 def hugoTemplateSubstitutions(String input, Map extras=null) {
1238 def replacements = [
1239 DATE: getDate("yyyy-MM-dd"),
1240 CHANNEL: propertiesChannelName,
1241 APPLICATION_NAME: applicationName,
1243 GIT_BRANCH: gitBranch,
1244 VERSION: JALVIEW_VERSION,
1245 JAVA_VERSION: JAVA_VERSION,
1246 VERSION_UNDERSCORES: JALVIEW_VERSION_UNDERSCORES,
1251 if (extras != null) {
1252 extras.each{ k, v ->
1253 output = output.replaceAll("__${k}__", ((v == null)?"":v))
1256 replacements.each{ k, v ->
1257 output = output.replaceAll("__${k}__", ((v == null)?"":v))
1262 def mdFileComponents(File mdFile, def dateOnly=false) {
1265 if (mdFile.exists()) {
1266 def inFrontMatter = false
1267 def firstLine = true
1268 mdFile.eachLine { line ->
1269 if (line.matches("---")) {
1270 def prev = inFrontMatter
1271 inFrontMatter = firstLine
1272 if (inFrontMatter != prev)
1275 if (inFrontMatter) {
1277 if (m = line =~ /^date:\s*(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})/) {
1278 map["date"] = new Date().parse("yyyy-MM-dd HH:mm:ss", m[0][1])
1279 } else if (m = line =~ /^date:\s*(\d{4}-\d{2}-\d{2})/) {
1280 map["date"] = new Date().parse("yyyy-MM-dd", m[0][1])
1281 } else if (m = line =~ /^channel:\s*(\S+)/) {
1282 map["channel"] = m[0][1]
1283 } else if (m = line =~ /^version:\s*(\S+)/) {
1284 map["version"] = m[0][1]
1285 } else if (m = line =~ /^\s*([^:]+)\s*:\s*(\S.*)/) {
1286 map[ m[0][1] ] = m[0][2]
1288 if (dateOnly && map["date"] != null) {
1294 content += line+"\n"
1299 return dateOnly ? map["date"] : [map, content]
1302 task hugoTemplates {
1304 description "Create partially populated md pages for hugo website build"
1306 def hugoTemplatesDir = file("${jalviewDir}/${hugo_templates_dir}")
1307 def hugoBuildDir = "${jalviewDir}/${hugo_build_dir}"
1308 def templateFiles = fileTree(dir: hugoTemplatesDir)
1309 def releaseMdFile = file("${jalviewDir}/${releases_dir}/release-${JALVIEW_VERSION_UNDERSCORES}.md")
1310 def whatsnewMdFile = file("${jalviewDir}/${whatsnew_dir}/whatsnew-${JALVIEW_VERSION_UNDERSCORES}.md")
1311 def oldJvlFile = file("${jalviewDir}/${hugo_old_jvl}")
1312 def jalviewjsFile = file("${jalviewDir}/${hugo_jalviewjs}")
1315 // specific release template for version archive
1318 def givenDate = null
1319 def givenChannel = null
1320 def givenVersion = null
1321 if (CHANNEL == "RELEASE") {
1322 def (map, content) = mdFileComponents(releaseMdFile)
1323 givenDate = map.date
1324 givenChannel = map.channel
1325 givenVersion = map.version
1327 if (givenVersion != null && givenVersion != JALVIEW_VERSION) {
1328 throw new GradleException("'version' header (${givenVersion}) found in ${releaseMdFile} does not match JALVIEW_VERSION (${JALVIEW_VERSION})")
1331 if (whatsnewMdFile.exists())
1332 whatsnew = whatsnewMdFile.text
1335 def oldJvl = oldJvlFile.exists() ? oldJvlFile.collect{it} : []
1336 def jalviewjsLink = jalviewjsFile.exists() ? jalviewjsFile.collect{it} : []
1338 def changesHugo = null
1339 if (changes != null) {
1340 changesHugo = '<div class="release_notes">\n\n'
1341 def inSection = false
1342 changes.eachLine { line ->
1344 if (m = line =~ /^##([^#].*)$/) {
1346 changesHugo += "</div>\n\n"
1348 def section = m[0][1].trim()
1349 section = section.toLowerCase()
1350 section = section.replaceAll(/ +/, "_")
1351 section = section.replaceAll(/[^a-z0-9_\-]/, "")
1352 changesHugo += "<div class=\"${section}\">\n\n"
1354 } else if (m = line =~ /^(\s*-\s*)<!--([^>]+)-->(.*?)(<br\/?>)?\s*$/) {
1355 def comment = m[0][2].trim()
1356 if (comment != "") {
1357 comment = comment.replaceAll('"', """)
1359 comment.eachMatch(/JAL-\d+/) { jal -> issuekeys += jal }
1360 def newline = m[0][1]
1361 if (comment.trim() != "")
1362 newline += "{{<comment>}}${comment}{{</comment>}} "
1363 newline += m[0][3].trim()
1364 if (issuekeys.size() > 0)
1365 newline += " {{< jal issue=\"${issuekeys.join(",")}\" alt=\"${comment}\" >}}"
1366 if (m[0][4] != null)
1371 changesHugo += line+"\n"
1374 changesHugo += "\n</div>\n\n"
1376 changesHugo += '</div>'
1379 templateFiles.each{ templateFile ->
1380 def newFileName = string(hugoTemplateSubstitutions(templateFile.getName()))
1381 def relPath = hugoTemplatesDir.toPath().relativize(templateFile.toPath()).getParent()
1382 def newRelPathName = hugoTemplateSubstitutions( relPath.toString() )
1384 def outPathName = string("${hugoBuildDir}/$newRelPathName")
1388 rename(templateFile.getName(), newFileName)
1392 def newFile = file("${outPathName}/${newFileName}".toString())
1393 def content = newFile.text
1394 newFile.text = hugoTemplateSubstitutions(content,
1397 CHANGES: changesHugo,
1398 DATE: givenDate == null ? "" : givenDate.format("yyyy-MM-dd"),
1399 DRAFT: givenDate == null ? "true" : "false",
1400 JALVIEWJSLINK: jalviewjsLink.contains(JALVIEW_VERSION) ? "true" : "false",
1401 JVL_HEADER: oldJvl.contains(JALVIEW_VERSION) ? "jvl: true" : ""
1408 inputs.file(oldJvlFile)
1409 inputs.dir(hugoTemplatesDir)
1410 inputs.property("JALVIEW_VERSION", { JALVIEW_VERSION })
1411 inputs.property("CHANNEL", { CHANNEL })
1414 def getMdDate(File mdFile) {
1415 return mdFileComponents(mdFile, true)
1418 def getMdSections(String content) {
1420 def sectionContent = ""
1421 def sectionName = null
1422 content.eachLine { line ->
1424 if (m = line =~ /^##([^#].*)$/) {
1425 if (sectionName != null) {
1426 sections[sectionName] = sectionContent
1430 sectionName = m[0][1].trim()
1431 sectionName = sectionName.toLowerCase()
1432 sectionName = sectionName.replaceAll(/ +/, "_")
1433 sectionName = sectionName.replaceAll(/[^a-z0-9_\-]/, "")
1434 } else if (sectionName != null) {
1435 sectionContent += line+"\n"
1438 if (sectionContent != null) {
1439 sections[sectionName] = sectionContent
1445 task copyHelp(type: Copy) {
1446 def inputDir = helpSourceDir
1447 def outputDir = "${helpBuildDir}/${help_dir}"
1451 include('**/*.html')
1455 filter(ReplaceTokens,
1459 'Version-Rel': JALVIEW_VERSION,
1460 'Year-Rel': getDate("yyyy")
1467 exclude('**/*.html')
1474 inputs.dir(inputDir)
1475 outputs.files(helpFile)
1476 outputs.dir(outputDir)
1480 task releasesTemplates {
1482 description "Recreate whatsNew.html and releases.html from markdown files and templates in help"
1486 def releasesTemplateFile = file("${jalviewDir}/${releases_template}")
1487 def whatsnewTemplateFile = file("${jalviewDir}/${whatsnew_template}")
1488 def releasesHtmlFile = file("${helpBuildDir}/${help_dir}/${releases_html}")
1489 def whatsnewHtmlFile = file("${helpBuildDir}/${help_dir}/${whatsnew_html}")
1490 def releasesMdDir = "${jalviewDir}/${releases_dir}"
1491 def whatsnewMdDir = "${jalviewDir}/${whatsnew_dir}"
1494 def releaseMdFile = file("${releasesMdDir}/release-${JALVIEW_VERSION_UNDERSCORES}.md")
1495 def whatsnewMdFile = file("${whatsnewMdDir}/whatsnew-${JALVIEW_VERSION_UNDERSCORES}.md")
1497 if (CHANNEL == "RELEASE") {
1498 if (!releaseMdFile.exists()) {
1499 throw new GradleException("File ${releaseMdFile} must be created for RELEASE")
1501 if (!whatsnewMdFile.exists()) {
1502 throw new GradleException("File ${whatsnewMdFile} must be created for RELEASE")
1506 def releaseFiles = fileTree(dir: releasesMdDir, include: "release-*.md")
1507 def releaseFilesDates = releaseFiles.collectEntries {
1508 [(it): getMdDate(it)]
1510 releaseFiles = releaseFiles.sort { a,b -> releaseFilesDates[a].compareTo(releaseFilesDates[b]) }
1512 def releasesTemplate = releasesTemplateFile.text
1513 def m = releasesTemplate =~ /(?s)__VERSION_LOOP_START__(.*)__VERSION_LOOP_END__/
1514 def versionTemplate = m[0][1]
1516 MutableDataSet options = new MutableDataSet()
1518 def extensions = new ArrayList<>()
1519 options.set(Parser.EXTENSIONS, extensions)
1520 options.set(Parser.HTML_BLOCK_COMMENT_ONLY_FULL_LINE, true)
1522 Parser parser = Parser.builder(options).build()
1523 HtmlRenderer renderer = HtmlRenderer.builder(options).build()
1525 def actualVersions = releaseFiles.collect { rf ->
1526 def (rfMap, rfContent) = mdFileComponents(rf)
1527 return rfMap.version
1529 def versionsHtml = ""
1530 def linkedVersions = []
1531 releaseFiles.reverse().each { rFile ->
1532 def (rMap, rContent) = mdFileComponents(rFile)
1534 def versionLink = ""
1535 def partialVersion = ""
1536 def firstPart = true
1537 rMap.version.split("\\.").each { part ->
1538 def displayPart = ( firstPart ? "" : "." ) + part
1539 partialVersion += displayPart
1541 linkedVersions.contains(partialVersion)
1542 || ( actualVersions.contains(partialVersion) && partialVersion != rMap.version )
1544 versionLink += displayPart
1546 versionLink += "<a id=\"Jalview.${partialVersion}\">${displayPart}</a>"
1547 linkedVersions += partialVersion
1551 def displayDate = releaseFilesDates[rFile].format("dd/MM/yyyy")
1554 def rContentProcessed = ""
1555 rContent.eachLine { line ->
1556 if (lm = line =~ /^(\s*-)(\s*<!--[^>]*?-->)(.*)$/) {
1557 line = "${lm[0][1]}${lm[0][3]}${lm[0][2]}"
1558 } else if (lm = line =~ /^###([^#]+.*)$/) {
1559 line = "_${lm[0][1].trim()}_"
1561 rContentProcessed += line + "\n"
1564 def rContentSections = getMdSections(rContentProcessed)
1565 def rVersion = versionTemplate
1566 if (rVersion != "") {
1567 def rNewFeatures = rContentSections["new_features"]
1568 def rIssuesResolved = rContentSections["issues_resolved"]
1569 Node newFeaturesNode = parser.parse(rNewFeatures)
1570 String newFeaturesHtml = renderer.render(newFeaturesNode)
1571 Node issuesResolvedNode = parser.parse(rIssuesResolved)
1572 String issuesResolvedHtml = renderer.render(issuesResolvedNode)
1573 rVersion = hugoTemplateSubstitutions(rVersion,
1575 VERSION: rMap.version,
1576 VERSION_LINK: versionLink,
1577 DISPLAY_DATE: displayDate,
1578 NEW_FEATURES: newFeaturesHtml,
1579 ISSUES_RESOLVED: issuesResolvedHtml
1582 versionsHtml += rVersion
1586 releasesTemplate = releasesTemplate.replaceAll("(?s)__VERSION_LOOP_START__.*__VERSION_LOOP_END__", versionsHtml)
1587 releasesTemplate = hugoTemplateSubstitutions(releasesTemplate)
1588 releasesHtmlFile.text = releasesTemplate
1590 if (whatsnewMdFile.exists()) {
1591 def wnDisplayDate = releaseFilesDates[releaseMdFile] != null ? releaseFilesDates[releaseMdFile].format("dd MMMM yyyy") : ""
1592 def whatsnewMd = hugoTemplateSubstitutions(whatsnewMdFile.text)
1593 Node whatsnewNode = parser.parse(whatsnewMd)
1594 String whatsnewHtml = renderer.render(whatsnewNode)
1595 whatsnewHtml = whatsnewTemplateFile.text.replaceAll("__WHATS_NEW__", whatsnewHtml)
1596 whatsnewHtmlFile.text = hugoTemplateSubstitutions(whatsnewHtml,
1598 VERSION: JALVIEW_VERSION,
1599 DISPLAY_DATE: wnDisplayDate
1602 } else if (gradle.taskGraph.hasTask(":linkCheck")) {
1603 whatsnewHtmlFile.text = "Development build " + getDate("yyyy-MM-dd HH:mm:ss")
1608 inputs.file(releasesTemplateFile)
1609 inputs.file(whatsnewTemplateFile)
1610 inputs.dir(releasesMdDir)
1611 inputs.dir(whatsnewMdDir)
1612 outputs.file(releasesHtmlFile)
1613 outputs.file(whatsnewHtmlFile)
1617 task copyResources(type: Copy) {
1619 description = "Copy (and make text substitutions in) the resources dir to the build area"
1621 def inputDir = resourceDir
1622 def outputDir = resourcesBuildDir
1626 include('**/*.html')
1628 filter(ReplaceTokens,
1632 'Version-Rel': JALVIEW_VERSION,
1633 'Year-Rel': getDate("yyyy")
1640 exclude('**/*.html')
1645 inputs.dir(inputDir)
1646 outputs.dir(outputDir)
1649 task copyChannelResources(type: Copy) {
1650 dependsOn copyResources
1652 description = "Copy the channel resources dir to the build resources area"
1654 def inputDir = "${channelDir}/${resource_dir}"
1655 def outputDir = resourcesBuildDir
1657 include(channel_props)
1658 filter(ReplaceTokens,
1662 'SUFFIX': channelSuffix
1667 exclude(channel_props)
1671 inputs.dir(inputDir)
1672 outputs.dir(outputDir)
1675 task createBuildProperties(type: WriteProperties) {
1676 dependsOn copyResources
1678 description = "Create the ${buildProperties} file"
1680 inputs.dir(sourceDir)
1681 inputs.dir(resourcesBuildDir)
1682 outputFile (buildProperties)
1683 // taking time specific comment out to allow better incremental builds
1684 comment "--Jalview Build Details--\n"+getDate("yyyy-MM-dd HH:mm:ss")
1685 //comment "--Jalview Build Details--\n"+getDate("yyyy-MM-dd")
1686 property "BUILD_DATE", getDate("HH:mm:ss dd MMMM yyyy")
1687 property "VERSION", JALVIEW_VERSION
1688 property "INSTALLATION", INSTALLATION+" git-commit:"+gitHash+" ["+gitBranch+"]"
1689 property "JAVA_COMPILE_VERSION", JAVA_INTEGER_VERSION
1690 if (getdownSetAppBaseProperty) {
1691 property "GETDOWNAPPBASE", getdownAppBase
1692 property "GETDOWNAPPDISTDIR", getdownAppDistDir
1694 outputs.file(outputFile)
1698 task buildIndices(type: JavaExec) {
1700 classpath = sourceSets.main.compileClasspath
1701 main = "com.sun.java.help.search.Indexer"
1702 workingDir = "${helpBuildDir}/${help_dir}"
1705 inputs.dir("${workingDir}/${argDir}")
1707 outputs.dir("${classesDir}/doc")
1708 outputs.dir("${classesDir}/help")
1709 outputs.file("${workingDir}/JavaHelpSearch/DOCS")
1710 outputs.file("${workingDir}/JavaHelpSearch/DOCS.TAB")
1711 outputs.file("${workingDir}/JavaHelpSearch/OFFSETS")
1712 outputs.file("${workingDir}/JavaHelpSearch/POSITIONS")
1713 outputs.file("${workingDir}/JavaHelpSearch/SCHEMA")
1714 outputs.file("${workingDir}/JavaHelpSearch/TMAP")
1717 task buildResources {
1718 dependsOn copyResources
1719 dependsOn copyChannelResources
1720 dependsOn createBuildProperties
1724 dependsOn buildResources
1727 dependsOn releasesTemplates
1728 dependsOn convertMdFiles
1729 dependsOn buildIndices
1733 compileJava.dependsOn prepare
1734 run.dependsOn compileJava
1735 compileTestJava.dependsOn compileJava
1738 ext.testsFailed = false
1739 /* testTask0 is the main test task */
1740 task testTask0(type: Test) {
1741 group = "Verification"
1742 description = "The main test task. Runs all non-testTaskN-labelled tests (unless excluded)"
1744 includeGroups testng_groups.split(",")
1745 excludeGroups testng_excluded_groups.split(",")
1746 tasks.withType(Test).matching {it.name.startsWith("testTask") && it.name != name}.all {t -> excludeGroups t.name}
1748 useDefaultListeners=true
1752 /* separated tests */
1753 task testTask1(type: Test) {
1754 group = "Verification"
1755 description = "Tests that need to be isolated from the main test run"
1758 excludeGroups testng_excluded_groups.split(",")
1760 useDefaultListeners=true
1765 * adapted from https://medium.com/@wasyl/pretty-tests-summary-in-gradle-744804dd676c
1766 * to summarise test results from all Test tasks
1768 /* START of test tasks results summary */
1769 import groovy.time.TimeCategory
1770 import org.gradle.api.tasks.testing.logging.TestExceptionFormat
1771 import org.gradle.api.tasks.testing.logging.TestLogEvent
1773 rootProject.ext.testsResults = [] // Container for tests summaries
1775 tasks.withType(Test).matching {t -> t.getName().startsWith("testTask")}.all { testTask ->
1777 // from original test task
1779 dependsOn cloverClasses
1781 dependsOn testClasses //?
1784 // run main tests first
1785 if (!testTask.name.equals("testTask0"))
1786 testTask.mustRunAfter "testTask0"
1788 testTask.testLogging { logging ->
1789 events TestLogEvent.FAILED,
1790 TestLogEvent.SKIPPED,
1791 TestLogEvent.STANDARD_OUT,
1792 TestLogEvent.STANDARD_ERROR
1794 exceptionFormat TestExceptionFormat.FULL
1797 showStackTraces true
1800 ignoreFailures = true // Always try to run all tests for all modules
1802 afterSuite { desc, result ->
1804 if (desc.parent) return // Only summarize results for whole modules
1806 String summary = "${testTask.project.name}:${testTask.name} results: ${result.resultType} " +
1808 "${result.testCount} tests, " +
1809 "${result.successfulTestCount} successes, " +
1810 "${result.failedTestCount} failures, " +
1811 "${result.skippedTestCount} skipped" +
1813 "in ${TimeCategory.minus(new Date(result.endTime), new Date(result.startTime))}" +
1815 "Report file: ${testTask.reports.html.entryPoint}"
1817 // Add reports in `testsResults`, keep failed suites at the end
1818 if (result.resultType == TestResult.ResultType.SUCCESS) {
1819 rootProject.ext.testsResults.add(0, summary)
1821 rootProject.ext.testsResults += summary
1824 if (result.resultType == TestResult.ResultType.FAILURE) {
1829 // from original test task
1830 maxHeapSize = "1024m"
1832 workingDir = jalviewDir
1833 def testLaf = project.findProperty("test_laf")
1834 if (testLaf != null) {
1835 println("Setting Test LaF to '${testLaf}'")
1836 systemProperty "laf", testLaf
1838 def testHiDPIScale = project.findProperty("test_HiDPIScale")
1839 if (testHiDPIScale != null) {
1840 println("Setting Test HiDPI Scale to '${testHiDPIScale}'")
1841 systemProperty "sun.java2d.uiScale", testHiDPIScale
1843 sourceCompatibility = compile_source_compatibility
1844 targetCompatibility = compile_target_compatibility
1845 jvmArgs += additional_compiler_args
1849 println("Running tests " + (useClover?"WITH":"WITHOUT") + " clover")
1855 gradle.buildFinished {
1856 def allResults = rootProject.ext.testsResults
1858 if (!allResults.isEmpty()) {
1859 printResults allResults
1863 private static void printResults(allResults) {
1864 def maxLength = allResults*.readLines().flatten().collect { it.length() }.max()
1866 println "┌${"${"─" * maxLength}"}┐"
1868 println allResults.collect {
1869 it.readLines().collect {
1870 "│" + it + " " * (maxLength - it.length()) + "│"
1872 }.join("\n├${"${"─" * maxLength}"}┤\n")
1874 println "└${"${"─" * maxLength}"}┘"
1876 /* END of test tasks results summary */
1878 task verifyTestStatus {
1879 group = "Verification"
1880 description = "Task that FAILs the build if any tests failed"
1883 throw new GradleException("There were failing tests!")
1889 // from original test task
1891 dependsOn cloverClasses
1893 dependsOn testClasses
1895 dependsOn tasks.withType(Test).matching {t -> t.getName().startsWith("testTask")}
1896 finalizedBy verifyTestStatus
1899 // not running tests in this task
1904 task compileLinkCheck(type: JavaCompile) {
1906 classpath = files("${jalviewDir}/${utils_dir}")
1907 destinationDir = file("${jalviewDir}/${utils_dir}")
1908 source = fileTree(dir: "${jalviewDir}/${utils_dir}", include: ["HelpLinksChecker.java", "BufferedLineReader.java"])
1910 inputs.file("${jalviewDir}/${utils_dir}/HelpLinksChecker.java")
1911 inputs.file("${jalviewDir}/${utils_dir}/HelpLinksChecker.java")
1912 outputs.file("${jalviewDir}/${utils_dir}/HelpLinksChecker.class")
1913 outputs.file("${jalviewDir}/${utils_dir}/BufferedLineReader.class")
1917 task linkCheck(type: JavaExec) {
1919 dependsOn compileLinkCheck
1921 def helpLinksCheckerOutFile = file("${jalviewDir}/${utils_dir}/HelpLinksChecker.out")
1922 classpath = files("${jalviewDir}/${utils_dir}")
1923 main = "HelpLinksChecker"
1924 workingDir = "${helpBuildDir}"
1925 args = [ "${helpBuildDir}/${help_dir}", "-nointernet" ]
1927 def outFOS = new FileOutputStream(helpLinksCheckerOutFile, false) // false == don't append
1928 standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
1931 errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
1935 inputs.dir(helpBuildDir)
1936 outputs.file(helpLinksCheckerOutFile)
1940 // import the pubhtmlhelp target
1941 ant.properties.basedir = "${jalviewDir}"
1942 ant.properties.helpBuildDir = "${helpBuildDir}/${help_dir}"
1943 ant.importBuild "${utils_dir}/publishHelp.xml"
1946 task cleanPackageDir(type: Delete) {
1948 delete fileTree(dir: "${jalviewDir}/${package_dir}", include: "*.jar")
1958 attributes "Main-Class": main_class,
1959 "Permissions": "all-permissions",
1960 "Application-Name": applicationName,
1961 "Codebase": application_codebase,
1962 "Implementation-Version": JALVIEW_VERSION
1965 def outputDir = "${jalviewDir}/${package_dir}"
1966 destinationDirectory = file(outputDir)
1967 archiveFileName = rootProject.name+".jar"
1968 duplicatesStrategy "EXCLUDE"
1975 exclude "**/*.jar.*"
1977 inputs.dir(sourceSets.main.java.outputDir)
1978 sourceSets.main.resources.srcDirs.each{ dir ->
1981 outputs.file("${outputDir}/${archiveFileName}")
1985 task copyJars(type: Copy) {
1986 from fileTree(dir: classesDir, include: "**/*.jar").files
1987 into "${jalviewDir}/${package_dir}"
1991 // doing a Sync instead of Copy as Copy doesn't deal with "outputs" very well
1992 task syncJars(type: Sync) {
1994 from fileTree(dir: "${jalviewDir}/${libDistDir}", include: "**/*.jar").files
1995 into "${jalviewDir}/${package_dir}"
1997 include jar.archiveFileName.getOrNull()
2004 description = "Put all required libraries in dist"
2005 // order of "cleanPackageDir", "copyJars", "jar" important!
2006 jar.mustRunAfter cleanPackageDir
2007 syncJars.mustRunAfter cleanPackageDir
2008 dependsOn cleanPackageDir
2011 outputs.dir("${jalviewDir}/${package_dir}")
2016 dependsOn cleanPackageDir
2023 group = "distribution"
2024 description = "Create a single jar file with all dependency libraries merged. Can be run with java -jar"
2028 from ("${jalviewDir}/${libDistDir}") {
2032 attributes "Implementation-Version": JALVIEW_VERSION,
2033 "Application-Name": applicationName
2036 duplicatesStrategy "INCLUDE"
2038 mainClassName = shadow_jar_main_class
2040 classifier = "all-"+JALVIEW_VERSION+"-j"+JAVA_VERSION
2044 task getdownImagesCopy() {
2045 inputs.dir getdownImagesDir
2046 outputs.dir getdownImagesBuildDir
2050 from(getdownImagesDir) {
2051 include("*getdown*.png")
2053 into getdownImagesBuildDir
2058 task getdownImagesProcess() {
2059 dependsOn getdownImagesCopy
2062 if (backgroundImageText) {
2063 if (convertBinary == null) {
2064 throw new StopExecutionException("No ImageMagick convert binary installed at '${convertBinaryExpectedLocation}'")
2066 if (!project.hasProperty("getdown_background_image_text_suffix_cmd")) {
2067 throw new StopExecutionException("No property 'getdown_background_image_text_suffix_cmd' defined. See channel_gradle.properties for channel ${CHANNEL}")
2069 fileTree(dir: getdownImagesBuildDir, include: "*background*.png").getFiles().each { file ->
2071 executable convertBinary
2074 '-font', getdown_background_image_text_font,
2075 '-fill', getdown_background_image_text_colour,
2076 '-draw', sprintf(getdown_background_image_text_suffix_cmd, channelSuffix),
2077 '-draw', sprintf(getdown_background_image_text_commit_cmd, "git-commit: ${gitHash}"),
2078 '-draw', sprintf(getdown_background_image_text_date_cmd, getDate("yyyy-MM-dd HH:mm:ss")),
2087 task getdownImages() {
2088 dependsOn getdownImagesProcess
2091 task getdownWebsite() {
2092 group = "distribution"
2093 description = "Create the getdown minimal app folder, and website folder for this version of jalview. Website folder also used for offline app installer"
2095 dependsOn getdownImages
2100 def getdownWebsiteResourceFilenames = []
2101 def getdownResourceDir = getdownResourceDir
2102 def getdownResourceFilenames = []
2105 // clean the getdown website and files dir before creating getdown folders
2106 delete getdownAppBaseDir
2107 delete getdownFilesDir
2110 from buildProperties
2111 rename(file(buildProperties).getName(), getdown_build_properties)
2114 getdownWebsiteResourceFilenames += "${getdownAppDistDir}/${getdown_build_properties}"
2117 from channelPropsFile
2118 filter(ReplaceTokens,
2122 'SUFFIX': channelSuffix
2125 into getdownAppBaseDir
2127 getdownWebsiteResourceFilenames += file(channelPropsFile).getName()
2129 // set some getdownTxt_ properties then go through all properties looking for getdownTxt_...
2130 def props = project.properties.sort { it.key }
2131 if (getdownAltJavaMinVersion != null && getdownAltJavaMinVersion.length() > 0) {
2132 props.put("getdown_txt_java_min_version", getdownAltJavaMinVersion)
2134 if (getdownAltJavaMaxVersion != null && getdownAltJavaMaxVersion.length() > 0) {
2135 props.put("getdown_txt_java_max_version", getdownAltJavaMaxVersion)
2137 if (getdownAltMultiJavaLocation != null && getdownAltMultiJavaLocation.length() > 0) {
2138 props.put("getdown_txt_multi_java_location", getdownAltMultiJavaLocation)
2140 if (getdownImagesBuildDir != null && file(getdownImagesBuildDir).exists()) {
2141 props.put("getdown_txt_ui.background_image", "${getdownImagesBuildDir}/${getdown_background_image}")
2142 props.put("getdown_txt_ui.instant_background_image", "${getdownImagesBuildDir}/${getdown_instant_background_image}")
2143 props.put("getdown_txt_ui.error_background", "${getdownImagesBuildDir}/${getdown_error_background}")
2144 props.put("getdown_txt_ui.progress_image", "${getdownImagesBuildDir}/${getdown_progress_image}")
2145 props.put("getdown_txt_ui.icon", "${getdownImagesBuildDir}/${getdown_icon}")
2146 props.put("getdown_txt_ui.mac_dock_icon", "${getdownImagesBuildDir}/${getdown_mac_dock_icon}")
2149 props.put("getdown_txt_title", jalview_name)
2150 props.put("getdown_txt_ui.name", applicationName)
2152 // start with appbase
2153 getdownTextLines += "appbase = ${getdownAppBase}"
2154 props.each{ prop, val ->
2155 if (prop.startsWith("getdown_txt_") && val != null) {
2156 if (prop.startsWith("getdown_txt_multi_")) {
2157 def key = prop.substring(18)
2158 val.split(",").each{ v ->
2159 def line = "${key} = ${v}"
2160 getdownTextLines += line
2163 // file values rationalised
2164 if (val.indexOf('/') > -1 || prop.startsWith("getdown_txt_resource")) {
2166 if (val.indexOf('/') == 0) {
2169 } else if (val.indexOf('/') > 0) {
2170 // relative path (relative to jalviewDir)
2171 r = file( "${jalviewDir}/${val}" )
2174 val = "${getdown_resource_dir}/" + r.getName()
2175 getdownWebsiteResourceFilenames += val
2176 getdownResourceFilenames += r.getPath()
2179 if (! prop.startsWith("getdown_txt_resource")) {
2180 def line = prop.substring(12) + " = ${val}"
2181 getdownTextLines += line
2187 getdownWebsiteResourceFilenames.each{ filename ->
2188 getdownTextLines += "resource = ${filename}"
2190 getdownResourceFilenames.each{ filename ->
2193 into getdownResourceDir
2197 def getdownWrapperScripts = [ getdown_bash_wrapper_script, getdown_powershell_wrapper_script, getdown_batch_wrapper_script ]
2198 getdownWrapperScripts.each{ script ->
2199 def s = file( "${jalviewDir}/utils/getdown/${getdown_wrapper_script_dir}/${script}" )
2203 into "${getdownAppBaseDir}/${getdown_wrapper_script_dir}"
2205 getdownTextLines += "resource = ${getdown_wrapper_script_dir}/${script}"
2210 fileTree(file(package_dir)).each{ f ->
2211 if (f.isDirectory()) {
2212 def files = fileTree(dir: f, include: ["*"]).getFiles()
2214 } else if (f.exists()) {
2218 def jalviewJar = jar.archiveFileName.getOrNull()
2219 // put jalview.jar first for CLASSPATH and .properties files reasons
2220 codeFiles.sort{a, b -> ( a.getName() == jalviewJar ? -1 : ( b.getName() == jalviewJar ? 1 : a <=> b ) ) }.each{f ->
2221 def name = f.getName()
2222 def line = "code = ${getdownAppDistDir}/${name}"
2223 getdownTextLines += line
2230 // NOT USING MODULES YET, EVERYTHING SHOULD BE IN dist
2232 if (JAVA_VERSION.equals("11")) {
2233 def j11libFiles = fileTree(dir: "${jalviewDir}/${j11libDir}", include: ["*.jar"]).getFiles()
2234 j11libFiles.sort().each{f ->
2235 def name = f.getName()
2236 def line = "code = ${getdown_j11lib_dir}/${name}"
2237 getdownTextLines += line
2240 into getdownJ11libDir
2246 // 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.
2247 //getdownTextLines += "class = " + file(getdownLauncher).getName()
2248 getdownTextLines += "resource = ${getdown_launcher_new}"
2249 getdownTextLines += "class = ${main_class}"
2250 // Not setting these properties in general so that getdownappbase and getdowndistdir will default to release version in jalview.bin.Cache
2251 if (getdownSetAppBaseProperty) {
2252 getdownTextLines += "jvmarg = -Dgetdowndistdir=${getdownAppDistDir}"
2253 getdownTextLines += "jvmarg = -Dgetdownappbase=${getdownAppBase}"
2256 def getdownTxt = file("${getdownAppBaseDir}/getdown.txt")
2257 getdownTxt.write(getdownTextLines.join("\n"))
2259 getdownLaunchJvl = getdown_launch_jvl_name + ( (jvlChannelName != null && jvlChannelName.length() > 0)?"-${jvlChannelName}":"" ) + ".jvl"
2260 def launchJvl = file("${getdownAppBaseDir}/${getdownLaunchJvl}")
2261 launchJvl.write("appbase=${getdownAppBase}")
2263 // files going into the getdown website dir: getdown-launcher.jar
2265 from getdownLauncher
2266 rename(file(getdownLauncher).getName(), getdown_launcher_new)
2267 into getdownAppBaseDir
2270 // files going into the getdown website dir: getdown-launcher(-local).jar
2272 from getdownLauncher
2273 if (file(getdownLauncher).getName() != getdown_launcher) {
2274 rename(file(getdownLauncher).getName(), getdown_launcher)
2276 into getdownAppBaseDir
2279 // files going into the getdown website dir: ./install dir and files
2280 if (! (CHANNEL.startsWith("ARCHIVE") || CHANNEL.startsWith("DEVELOP"))) {
2283 from getdownLauncher
2284 from "${getdownAppDir}/${getdown_build_properties}"
2285 if (file(getdownLauncher).getName() != getdown_launcher) {
2286 rename(file(getdownLauncher).getName(), getdown_launcher)
2288 into getdownInstallDir
2291 // and make a copy in the getdown files dir (these are not downloaded by getdown)
2293 from getdownInstallDir
2294 into getdownFilesInstallDir
2298 // files going into the getdown files dir: getdown.txt, getdown-launcher.jar, channel-launch.jvl, build_properties
2302 from getdownLauncher
2303 from "${getdownAppBaseDir}/${getdown_build_properties}"
2304 from "${getdownAppBaseDir}/${channel_props}"
2305 if (file(getdownLauncher).getName() != getdown_launcher) {
2306 rename(file(getdownLauncher).getName(), getdown_launcher)
2308 into getdownFilesDir
2311 // and ./resource (not all downloaded by getdown)
2313 from getdownResourceDir
2314 into "${getdownFilesDir}/${getdown_resource_dir}"
2319 inputs.dir("${jalviewDir}/${package_dir}")
2321 outputs.dir(getdownAppBaseDir)
2322 outputs.dir(getdownFilesDir)
2326 // a helper task to allow getdown digest of any dir: `gradle getdownDigestDir -PDIGESTDIR=/path/to/my/random/getdown/dir
2327 task getdownDigestDir(type: JavaExec) {
2329 description "A task to run a getdown Digest on a dir with getdown.txt. Provide a DIGESTDIR property via -PDIGESTDIR=..."
2331 def digestDirPropertyName = "DIGESTDIR"
2333 classpath = files(getdownLauncher)
2334 def digestDir = findProperty(digestDirPropertyName)
2335 if (digestDir == null) {
2336 throw new GradleException("Must provide a DIGESTDIR value to produce an alternative getdown digest")
2340 main = "com.threerings.getdown.tools.Digester"
2344 task getdownDigest(type: JavaExec) {
2345 group = "distribution"
2346 description = "Digest the getdown website folder"
2347 dependsOn getdownWebsite
2349 classpath = files(getdownLauncher)
2351 main = "com.threerings.getdown.tools.Digester"
2352 args getdownAppBaseDir
2353 inputs.dir(getdownAppBaseDir)
2354 outputs.file("${getdownAppBaseDir}/digest2.txt")
2359 group = "distribution"
2360 description = "Create the minimal and full getdown app folder for installers and website and create digest file"
2361 dependsOn getdownDigest
2363 if (reportRsyncCommand) {
2364 def fromDir = getdownAppBaseDir + (getdownAppBaseDir.endsWith('/')?'':'/')
2365 def toDir = "${getdown_rsync_dest}/${getdownDir}" + (getdownDir.endsWith('/')?'':'/')
2366 println "LIKELY RSYNC COMMAND:"
2367 println "mkdir -p '$toDir'\nrsync -avh --delete '$fromDir' '$toDir'"
2368 if (RUNRSYNC == "true") {
2370 commandLine "mkdir", "-p", toDir
2373 commandLine "rsync", "-avh", "--delete", fromDir, toDir
2381 task getdownArchiveBuild() {
2382 group = "distribution"
2383 description = "Put files in the archive dir to go on the website"
2385 dependsOn getdownWebsite
2387 def v = "v${JALVIEW_VERSION_UNDERSCORES}"
2388 def vDir = "${getdownArchiveDir}/${v}"
2389 getdownFullArchiveDir = "${vDir}/getdown"
2390 getdownVersionLaunchJvl = "${vDir}/jalview-${v}.jvl"
2392 def vAltDir = "alt_${v}"
2393 def archiveImagesDir = "${jalviewDir}/${channel_properties_dir}/old/images"
2396 // cleanup old "old" dir
2397 delete getdownArchiveDir
2399 def getdownArchiveTxt = file("${getdownFullArchiveDir}/getdown.txt")
2400 getdownArchiveTxt.getParentFile().mkdirs()
2401 def getdownArchiveTextLines = []
2402 def getdownFullArchiveAppBase = "${getdownArchiveAppBase}${getdownArchiveAppBase.endsWith("/")?"":"/"}${v}/getdown/"
2406 from "${getdownAppBaseDir}/${getdownAppDistDir}"
2407 into "${getdownFullArchiveDir}/${vAltDir}"
2410 getdownTextLines.each { line ->
2411 line = line.replaceAll("^(?<s>appbase\\s*=\\s*).*", '${s}'+getdownFullArchiveAppBase)
2412 line = line.replaceAll("^(?<s>(resource|code)\\s*=\\s*)${getdownAppDistDir}/", '${s}'+vAltDir+"/")
2413 line = line.replaceAll("^(?<s>ui.background_image\\s*=\\s*).*\\.png", '${s}'+"${getdown_resource_dir}/jalview_archive_getdown_background.png")
2414 line = line.replaceAll("^(?<s>ui.instant_background_image\\s*=\\s*).*\\.png", '${s}'+"${getdown_resource_dir}/jalview_archive_getdown_background_initialising.png")
2415 line = line.replaceAll("^(?<s>ui.error_background\\s*=\\s*).*\\.png", '${s}'+"${getdown_resource_dir}/jalview_archive_getdown_background_error.png")
2416 line = line.replaceAll("^(?<s>ui.progress_image\\s*=\\s*).*\\.png", '${s}'+"${getdown_resource_dir}/jalview_archive_getdown_progress_bar.png")
2417 // remove the existing resource = resource/ or bin/ lines
2418 if (! line.matches("resource\\s*=\\s*(resource|bin)/.*")) {
2419 getdownArchiveTextLines += line
2423 // the resource dir -- add these files as resource lines in getdown.txt
2425 from "${archiveImagesDir}"
2426 into "${getdownFullArchiveDir}/${getdown_resource_dir}"
2428 getdownArchiveTextLines += "resource = ${getdown_resource_dir}/${file.getName()}"
2432 getdownArchiveTxt.write(getdownArchiveTextLines.join("\n"))
2434 def vLaunchJvl = file(getdownVersionLaunchJvl)
2435 vLaunchJvl.getParentFile().mkdirs()
2436 vLaunchJvl.write("appbase=${getdownFullArchiveAppBase}\n")
2437 def vLaunchJvlPath = vLaunchJvl.toPath().toAbsolutePath()
2438 def jvlLinkPath = file("${vDir}/jalview.jvl").toPath().toAbsolutePath()
2439 // for some reason filepath.relativize(fileInSameDirPath) gives a path to "../" which is wrong
2440 //java.nio.file.Files.createSymbolicLink(jvlLinkPath, jvlLinkPath.relativize(vLaunchJvlPath));
2441 java.nio.file.Files.createSymbolicLink(jvlLinkPath, java.nio.file.Paths.get(".",vLaunchJvl.getName()));
2443 // files going into the getdown files dir: getdown.txt, getdown-launcher.jar, channel-launch.jvl, build_properties
2445 from getdownLauncher
2446 from "${getdownAppBaseDir}/${getdownLaunchJvl}"
2447 from "${getdownAppBaseDir}/${getdown_launcher_new}"
2448 from "${getdownAppBaseDir}/${channel_props}"
2449 if (file(getdownLauncher).getName() != getdown_launcher) {
2450 rename(file(getdownLauncher).getName(), getdown_launcher)
2452 into getdownFullArchiveDir
2458 task getdownArchiveDigest(type: JavaExec) {
2459 group = "distribution"
2460 description = "Digest the getdown archive folder"
2462 dependsOn getdownArchiveBuild
2465 classpath = files(getdownLauncher)
2466 args getdownFullArchiveDir
2468 main = "com.threerings.getdown.tools.Digester"
2469 inputs.dir(getdownFullArchiveDir)
2470 outputs.file("${getdownFullArchiveDir}/digest2.txt")
2473 task getdownArchive() {
2474 group = "distribution"
2475 description = "Build the website archive dir with getdown digest"
2477 dependsOn getdownArchiveBuild
2478 dependsOn getdownArchiveDigest
2481 tasks.withType(JavaCompile) {
2482 options.encoding = 'UTF-8'
2488 delete getdownAppBaseDir
2489 delete getdownFilesDir
2490 delete getdownArchiveDir
2496 if (file(install4jHomeDir).exists()) {
2498 } else if (file(System.getProperty("user.home")+"/buildtools/install4j").exists()) {
2499 install4jHomeDir = System.getProperty("user.home")+"/buildtools/install4j"
2500 } else if (file("/Applications/install4j.app/Contents/Resources/app").exists()) {
2501 install4jHomeDir = "/Applications/install4j.app/Contents/Resources/app"
2503 installDir(file(install4jHomeDir))
2505 mediaTypes = Arrays.asList(install4j_media_types.split(","))
2509 task copyInstall4jTemplate {
2510 def install4jTemplateFile = file("${install4jDir}/${install4j_template}")
2511 def install4jFileAssociationsFile = file("${install4jDir}/${install4j_installer_file_associations}")
2512 inputs.file(install4jTemplateFile)
2513 inputs.file(install4jFileAssociationsFile)
2514 inputs.property("CHANNEL", { CHANNEL })
2515 outputs.file(install4jConfFile)
2518 def install4jConfigXml = new XmlParser().parse(install4jTemplateFile)
2520 // turn off code signing if no OSX_KEYPASS
2521 if (OSX_KEYPASS == "") {
2522 install4jConfigXml.'**'.codeSigning.each { codeSigning ->
2523 codeSigning.'@macEnabled' = "false"
2525 install4jConfigXml.'**'.windows.each { windows ->
2526 windows.'@runPostProcessor' = "false"
2530 // disable install screen for OSX dmg (for 2.11.2.0)
2531 install4jConfigXml.'**'.macosArchive.each { macosArchive ->
2532 macosArchive.attributes().remove('executeSetupApp')
2533 macosArchive.attributes().remove('setupAppId')
2536 // turn off checksum creation for LOCAL channel
2537 def e = install4jConfigXml.application[0]
2538 e.'@createChecksums' = string(install4jCheckSums)
2540 // put file association actions where placeholder action is
2541 def install4jFileAssociationsText = install4jFileAssociationsFile.text
2542 def fileAssociationActions = new XmlParser().parseText("<actions>${install4jFileAssociationsText}</actions>")
2543 install4jConfigXml.'**'.action.any { a -> // .any{} stops after the first one that returns true
2544 if (a.'@name' == 'EXTENSIONS_REPLACED_BY_GRADLE') {
2545 def parent = a.parent()
2547 fileAssociationActions.each { faa ->
2550 // don't need to continue in .any loop once replacements have been made
2555 // use Windows Program Group with Examples folder for RELEASE, and Program Group without Examples for everything else
2556 // NB we're deleting the /other/ one!
2557 // Also remove the examples subdir from non-release versions
2558 def customizedIdToDelete = "PROGRAM_GROUP_RELEASE"
2559 // 2.11.1.0 NOT releasing with the Examples folder in the Program Group
2560 if (false && CHANNEL=="RELEASE") { // remove 'false && ' to include Examples folder in RELEASE channel
2561 customizedIdToDelete = "PROGRAM_GROUP_NON_RELEASE"
2563 // remove the examples subdir from Full File Set
2564 def files = install4jConfigXml.files[0]
2565 def fileset = files.filesets.fileset.find { fs -> fs.'@customizedId' == "FULL_FILE_SET" }
2566 def root = files.roots.root.find { r -> r.'@fileset' == fileset.'@id' }
2567 def mountPoint = files.mountPoints.mountPoint.find { mp -> mp.'@root' == root.'@id' }
2568 def dirEntry = files.entries.dirEntry.find { de -> de.'@mountPoint' == mountPoint.'@id' && de.'@subDirectory' == "examples" }
2569 dirEntry.parent().remove(dirEntry)
2571 install4jConfigXml.'**'.action.any { a ->
2572 if (a.'@customizedId' == customizedIdToDelete) {
2573 def parent = a.parent()
2579 // write install4j file
2580 install4jConfFile.text = XmlUtil.serialize(install4jConfigXml)
2587 delete install4jConfFile
2591 task cleanInstallersDataFiles {
2592 def installersOutputTxt = file("${jalviewDir}/${install4jBuildDir}/output.txt")
2593 def installersSha256 = file("${jalviewDir}/${install4jBuildDir}/sha256sums")
2594 def hugoDataJsonFile = file("${jalviewDir}/${install4jBuildDir}/installers-${JALVIEW_VERSION_UNDERSCORES}.json")
2596 delete installersOutputTxt
2597 delete installersSha256
2598 delete hugoDataJsonFile
2602 task install4jDMGBackgroundImageCopy {
2603 inputs.file "${install4jDMGBackgroundImageDir}/${install4jDMGBackgroundImageFile}"
2604 outputs.dir "${install4jDMGBackgroundImageBuildDir}"
2607 from(install4jDMGBackgroundImageDir) {
2608 include(install4jDMGBackgroundImageFile)
2610 into install4jDMGBackgroundImageBuildDir
2615 task install4jDMGBackgroundImageProcess {
2616 dependsOn install4jDMGBackgroundImageCopy
2619 if (backgroundImageText) {
2620 if (convertBinary == null) {
2621 throw new StopExecutionException("No ImageMagick convert binary installed at '${convertBinaryExpectedLocation}'")
2623 if (!project.hasProperty("install4j_background_image_text_suffix_cmd")) {
2624 throw new StopExecutionException("No property 'install4j_background_image_text_suffix_cmd' defined. See channel_gradle.properties for channel ${CHANNEL}")
2626 fileTree(dir: install4jDMGBackgroundImageBuildDir, include: "*.png").getFiles().each { file ->
2628 executable convertBinary
2631 '-font', install4j_background_image_text_font,
2632 '-fill', install4j_background_image_text_colour,
2633 '-draw', sprintf(install4j_background_image_text_suffix_cmd, channelSuffix),
2634 '-draw', sprintf(install4j_background_image_text_commit_cmd, "git-commit: ${gitHash}"),
2635 '-draw', sprintf(install4j_background_image_text_date_cmd, getDate("yyyy-MM-dd HH:mm:ss")),
2644 task install4jDMGBackgroundImage {
2645 dependsOn install4jDMGBackgroundImageProcess
2648 task installerFiles(type: com.install4j.gradle.Install4jTask) {
2649 group = "distribution"
2650 description = "Create the install4j installers"
2652 dependsOn copyInstall4jTemplate
2653 dependsOn cleanInstallersDataFiles
2654 dependsOn install4jDMGBackgroundImage
2656 projectFile = install4jConfFile
2658 // create an md5 for the input files to use as version for install4j conf file
2659 def digest = MessageDigest.getInstance("MD5")
2661 (file("${install4jDir}/${install4j_template}").text +
2662 file("${install4jDir}/${install4j_info_plist_file_associations}").text +
2663 file("${install4jDir}/${install4j_installer_file_associations}").text).bytes)
2664 def filesMd5 = new BigInteger(1, digest.digest()).toString(16)
2665 if (filesMd5.length() >= 8) {
2666 filesMd5 = filesMd5.substring(0,8)
2668 def install4jTemplateVersion = "${JALVIEW_VERSION}_F${filesMd5}_C${gitHash}"
2671 'JALVIEW_NAME': jalview_name,
2672 'JALVIEW_APPLICATION_NAME': applicationName,
2673 'JALVIEW_DIR': "../..",
2674 'OSX_KEYSTORE': OSX_KEYSTORE,
2675 'OSX_APPLEID': OSX_APPLEID,
2676 'OSX_ALTOOLPASS': OSX_ALTOOLPASS,
2677 'JSIGN_SH': JSIGN_SH,
2678 'JRE_DIR': getdown_app_dir_java,
2679 'INSTALLER_TEMPLATE_VERSION': install4jTemplateVersion,
2680 'JALVIEW_VERSION': JALVIEW_VERSION,
2681 'JAVA_MIN_VERSION': JAVA_MIN_VERSION,
2682 'JAVA_MAX_VERSION': JAVA_MAX_VERSION,
2683 'JAVA_VERSION': JAVA_VERSION,
2684 'JAVA_INTEGER_VERSION': JAVA_INTEGER_VERSION,
2685 'VERSION': JALVIEW_VERSION,
2686 'COPYRIGHT_MESSAGE': install4j_copyright_message,
2687 'BUNDLE_ID': install4jBundleId,
2688 'INTERNAL_ID': install4jInternalId,
2689 'WINDOWS_APPLICATION_ID': install4jWinApplicationId,
2690 'MACOS_DMG_DS_STORE': install4jDMGDSStore,
2691 'MACOS_DMG_BG_IMAGE': "${install4jDMGBackgroundImageBuildDir}/${install4jDMGBackgroundImageFile}",
2692 'WRAPPER_LINK': getdownWrapperLink,
2693 'BASH_WRAPPER_SCRIPT': getdown_bash_wrapper_script,
2694 'POWERSHELL_WRAPPER_SCRIPT': getdown_powershell_wrapper_script,
2695 'WRAPPER_SCRIPT_BIN_DIR': getdown_wrapper_script_dir,
2696 'INSTALLER_NAME': install4jInstallerName,
2697 'INSTALL4J_UTILS_DIR': install4j_utils_dir,
2698 'GETDOWN_CHANNEL_DIR': getdownChannelDir,
2699 'GETDOWN_FILES_DIR': getdown_files_dir,
2700 'GETDOWN_RESOURCE_DIR': getdown_resource_dir,
2701 'GETDOWN_DIST_DIR': getdownAppDistDir,
2702 'GETDOWN_ALT_DIR': getdown_app_dir_alt,
2703 'GETDOWN_INSTALL_DIR': getdown_install_dir,
2704 'INFO_PLIST_FILE_ASSOCIATIONS_FILE': install4j_info_plist_file_associations,
2705 'BUILD_DIR': install4jBuildDir,
2706 'APPLICATION_CATEGORIES': install4j_application_categories,
2707 'APPLICATION_FOLDER': install4jApplicationFolder,
2708 'UNIX_APPLICATION_FOLDER': install4jUnixApplicationFolder,
2709 'EXECUTABLE_NAME': install4jExecutableName,
2710 'EXTRA_SCHEME': install4jExtraScheme,
2711 'MAC_ICONS_FILE': install4jMacIconsFile,
2712 'WINDOWS_ICONS_FILE': install4jWindowsIconsFile,
2713 'PNG_ICON_FILE': install4jPngIconFile,
2714 'BACKGROUND': install4jBackground,
2719 'windows': 'WINDOWS',
2723 // these are the bundled OS/architecture VMs needed by install4j
2726 [ "mac", "aarch64" ],
2727 [ "windows", "x64" ],
2729 [ "linux", "aarch64" ]
2731 osArch.forEach { os, arch ->
2732 variables[ sprintf("%s_%s_JAVA_VM_DIR", varNameMap[os], arch.toUpperCase(Locale.ROOT)) ] = sprintf("%s/jre-%s-%s-%s/jre", jreInstallsDir, JAVA_INTEGER_VERSION, os, arch)
2733 // N.B. For some reason install4j requires the below filename to have underscores and not hyphens
2734 // otherwise running `gradle installers` generates a non-useful error:
2735 // `install4j: compilation failed. Reason: java.lang.NumberFormatException: For input string: "windows"`
2736 variables[ sprintf("%s_%s_JAVA_VM_TGZ", varNameMap[os], arch.toUpperCase(Locale.ROOT)) ] = sprintf("%s/tgz/jre_%s_%s_%s.tar.gz", jreInstallsDir, JAVA_INTEGER_VERSION, os, arch)
2739 //println("INSTALL4J VARIABLES:")
2740 //variables.each{k,v->println("${k}=${v}")}
2742 destination = "${jalviewDir}/${install4jBuildDir}"
2743 buildSelected = true
2745 if (install4j_faster.equals("true") || CHANNEL.startsWith("LOCAL")) {
2747 disableSigning = true
2748 disableNotarization = true
2752 macKeystorePassword = OSX_KEYPASS
2755 if (OSX_ALTOOLPASS) {
2756 appleIdPassword = OSX_ALTOOLPASS
2757 disableNotarization = false
2759 disableNotarization = true
2763 println("Using projectFile "+projectFile)
2764 if (!disableNotarization) { println("Will notarize OSX App DMG") }
2768 inputs.dir(getdownAppBaseDir)
2769 inputs.file(install4jConfFile)
2770 inputs.file("${install4jDir}/${install4j_info_plist_file_associations}")
2771 outputs.dir("${jalviewDir}/${install4j_build_dir}/${JAVA_VERSION}")
2774 def getDataHash(File myFile) {
2775 HashCode hash = Files.asByteSource(myFile).hash(Hashing.sha256())
2776 return myFile.exists()
2778 "file" : myFile.getName(),
2779 "filesize" : myFile.length(),
2780 "sha256" : hash.toString()
2785 def writeDataJsonFile(File installersOutputTxt, File installersSha256, File dataJsonFile) {
2787 "channel" : getdownChannelName,
2788 "date" : getDate("yyyy-MM-dd HH:mm:ss"),
2789 "git-commit" : "${gitHash} [${gitBranch}]",
2790 "version" : JALVIEW_VERSION
2792 // install4j installer files
2793 if (installersOutputTxt.exists()) {
2795 installersOutputTxt.readLines().each { def line ->
2796 if (line.startsWith("#")) {
2799 line.replaceAll("\n","")
2800 def vals = line.split("\t")
2801 def filename = vals[3]
2802 def filesize = file(filename).length()
2803 filename = filename.replaceAll(/^.*\//, "")
2804 hash[vals[0]] = [ "id" : vals[0], "os" : vals[1], "name" : vals[2], "file" : filename, "filesize" : filesize ]
2805 idHash."${filename}" = vals[0]
2807 if (install4jCheckSums && installersSha256.exists()) {
2808 installersSha256.readLines().each { def line ->
2809 if (line.startsWith("#")) {
2812 line.replaceAll("\n","")
2813 def vals = line.split(/\s+\*?/)
2814 def filename = vals[1]
2815 def innerHash = (hash.(idHash."${filename}"))."sha256" = vals[0]
2821 "JAR": shadowJar.archiveFile, // executable JAR
2822 "JVL": getdownVersionLaunchJvl, // version JVL
2823 "SOURCE": sourceDist.archiveFile // source TGZ
2824 ].each { key, value ->
2825 def file = file(value)
2826 if (file.exists()) {
2827 def fileHash = getDataHash(file)
2828 if (fileHash != null) {
2829 hash."${key}" = fileHash;
2833 return dataJsonFile.write(new JsonBuilder(hash).toPrettyString())
2836 task staticMakeInstallersJsonFile {
2838 def output = findProperty("i4j_output")
2839 def sha256 = findProperty("i4j_sha256")
2840 def json = findProperty("i4j_json")
2841 if (output == null || sha256 == null || json == null) {
2842 throw new GradleException("Must provide paths to all of output.txt, sha256sums, and output.json with '-Pi4j_output=... -Pi4j_sha256=... -Pi4j_json=...")
2844 writeDataJsonFile(file(output), file(sha256), file(json))
2849 dependsOn installerFiles
2855 eclipse().configFile(eclipse_codestyle_file)
2859 task createSourceReleaseProperties(type: WriteProperties) {
2860 group = "distribution"
2861 description = "Create the source RELEASE properties file"
2863 def sourceTarBuildDir = "${buildDir}/sourceTar"
2864 def sourceReleasePropertiesFile = "${sourceTarBuildDir}/RELEASE"
2865 outputFile (sourceReleasePropertiesFile)
2868 releaseProps.each{ key, val -> property key, val }
2869 property "git.branch", gitBranch
2870 property "git.hash", gitHash
2873 outputs.file(outputFile)
2876 task sourceDist(type: Tar) {
2877 group "distribution"
2878 description "Create a source .tar.gz file for distribution"
2880 dependsOn createBuildProperties
2881 dependsOn convertMdFiles
2882 dependsOn eclipseAllPreferences
2883 dependsOn createSourceReleaseProperties
2886 def outputFileName = "${project.name}_${JALVIEW_VERSION_UNDERSCORES}.tar.gz"
2887 archiveFileName = outputFileName
2889 compression Compression.GZIP
2904 "**/*.class","$j11modDir/**/*.jar","appletlib","**/*locales",
2906 "utils/InstallAnywhere",
2921 "gradle.properties",
2933 ".settings/org.eclipse.buildship.core.prefs",
2934 ".settings/org.eclipse.jdt.core.prefs"
2938 exclude (EXCLUDE_FILES)
2939 include (PROCESS_FILES)
2940 filter(ReplaceTokens,
2944 'Version-Rel': JALVIEW_VERSION,
2945 'Year-Rel': getDate("yyyy")
2950 exclude (EXCLUDE_FILES)
2951 exclude (PROCESS_FILES)
2952 exclude ("appletlib")
2953 exclude ("**/*locales")
2954 exclude ("*locales/**")
2955 exclude ("utils/InstallAnywhere")
2957 exclude (getdown_files_dir)
2958 // getdown_website_dir and getdown_archive_dir moved to build/website/docroot/getdown
2959 //exclude (getdown_website_dir)
2960 //exclude (getdown_archive_dir)
2962 // exluding these as not using jars as modules yet
2963 exclude ("${j11modDir}/**/*.jar")
2966 include(INCLUDE_FILES)
2968 // from (jalviewDir) {
2969 // // explicit includes for stuff that seemed to not get included
2970 // include(fileTree("test/**/*."))
2971 // exclude(EXCLUDE_FILES)
2972 // exclude(PROCESS_FILES)
2975 from(file(buildProperties).getParent()) {
2976 include(file(buildProperties).getName())
2977 rename(file(buildProperties).getName(), "build_properties")
2979 line.replaceAll("^INSTALLATION=.*\$","INSTALLATION=Source Release"+" git-commit\\\\:"+gitHash+" ["+gitBranch+"]")
2983 def sourceTarBuildDir = "${buildDir}/sourceTar"
2984 from(sourceTarBuildDir) {
2985 // this includes the appended RELEASE properties file
2989 task dataInstallersJson {
2991 description "Create the installers-VERSION.json data file for installer files created"
2993 mustRunAfter installers
2994 mustRunAfter shadowJar
2995 mustRunAfter sourceDist
2996 mustRunAfter getdownArchive
2998 def installersOutputTxt = file("${jalviewDir}/${install4jBuildDir}/output.txt")
2999 def installersSha256 = file("${jalviewDir}/${install4jBuildDir}/sha256sums")
3001 if (installersOutputTxt.exists()) {
3002 inputs.file(installersOutputTxt)
3004 if (install4jCheckSums && installersSha256.exists()) {
3005 inputs.file(installersSha256)
3008 shadowJar.archiveFile, // executable JAR
3009 getdownVersionLaunchJvl, // version JVL
3010 sourceDist.archiveFile // source TGZ
3011 ].each { fileName ->
3012 if (file(fileName).exists()) {
3013 inputs.file(fileName)
3017 outputs.file(hugoDataJsonFile)
3020 writeDataJsonFile(installersOutputTxt, installersSha256, hugoDataJsonFile)
3026 description "Copies all help pages to build dir. Runs ant task 'pubhtmlhelp'."
3029 dependsOn pubhtmlhelp
3031 inputs.dir("${helpBuildDir}/${help_dir}")
3032 outputs.dir("${buildDir}/distributions/${help_dir}")
3036 task j2sSetHeadlessBuild {
3043 task jalviewjsEnableAltFileProperty(type: WriteProperties) {
3045 description "Enable the alternative J2S Config file for headless build"
3047 outputFile = jalviewjsJ2sSettingsFileName
3048 def j2sPropsFile = file(jalviewjsJ2sSettingsFileName)
3049 def j2sProps = new Properties()
3050 if (j2sPropsFile.exists()) {
3052 def j2sPropsFileFIS = new FileInputStream(j2sPropsFile)
3053 j2sProps.load(j2sPropsFileFIS)
3054 j2sPropsFileFIS.close()
3056 j2sProps.each { prop, val ->
3059 } catch (Exception e) {
3060 println("Exception reading ${jalviewjsJ2sSettingsFileName}")
3064 if (! j2sProps.stringPropertyNames().contains(jalviewjs_j2s_alt_file_property_config)) {
3065 property(jalviewjs_j2s_alt_file_property_config, jalviewjs_j2s_alt_file_property)
3070 task jalviewjsSetEclipseWorkspace {
3071 def propKey = "jalviewjs_eclipse_workspace"
3073 if (project.hasProperty(propKey)) {
3074 propVal = project.getProperty(propKey)
3075 if (propVal.startsWith("~/")) {
3076 propVal = System.getProperty("user.home") + propVal.substring(1)
3079 def propsFileName = "${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_eclipse_workspace_location_file}"
3080 def propsFile = file(propsFileName)
3081 def eclipseWsDir = propVal
3082 def props = new Properties()
3084 def writeProps = true
3085 if (( eclipseWsDir == null || !file(eclipseWsDir).exists() ) && propsFile.exists()) {
3086 def ins = new FileInputStream(propsFileName)
3089 if (props.getProperty(propKey, null) != null) {
3090 eclipseWsDir = props.getProperty(propKey)
3095 if (eclipseWsDir == null || !file(eclipseWsDir).exists()) {
3096 def tempDir = File.createTempDir()
3097 eclipseWsDir = tempDir.getAbsolutePath()
3100 eclipseWorkspace = file(eclipseWsDir)
3103 // do not run a headless transpile when we claim to be in Eclipse
3105 println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3106 throw new StopExecutionException("Not running headless transpile whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
3108 println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3112 props.setProperty(propKey, eclipseWsDir)
3113 propsFile.parentFile.mkdirs()
3114 def bytes = new ByteArrayOutputStream()
3115 props.store(bytes, null)
3116 def propertiesString = bytes.toString()
3117 propsFile.text = propertiesString
3123 println("ECLIPSE WORKSPACE: "+eclipseWorkspace.getPath())
3126 //inputs.property(propKey, eclipseWsDir) // eclipseWsDir only gets set once this task runs, so will be out-of-date
3127 outputs.file(propsFileName)
3128 outputs.upToDateWhen { eclipseWorkspace.exists() && propsFile.exists() }
3132 task jalviewjsEclipsePaths {
3135 def eclipseRoot = jalviewjs_eclipse_root
3136 if (eclipseRoot.startsWith("~/")) {
3137 eclipseRoot = System.getProperty("user.home") + eclipseRoot.substring(1)
3139 if (OperatingSystem.current().isMacOsX()) {
3140 eclipseRoot += "/Eclipse.app"
3141 eclipseBinary = "${eclipseRoot}/Contents/MacOS/eclipse"
3142 eclipseProduct = "${eclipseRoot}/Contents/Eclipse/.eclipseproduct"
3143 } else if (OperatingSystem.current().isWindows()) { // check these paths!!
3144 if (file("${eclipseRoot}/eclipse").isDirectory() && file("${eclipseRoot}/eclipse/.eclipseproduct").exists()) {
3145 eclipseRoot += "/eclipse"
3147 eclipseBinary = "${eclipseRoot}/eclipse.exe"
3148 eclipseProduct = "${eclipseRoot}/.eclipseproduct"
3149 } else { // linux or unix
3150 if (file("${eclipseRoot}/eclipse").isDirectory() && file("${eclipseRoot}/eclipse/.eclipseproduct").exists()) {
3151 eclipseRoot += "/eclipse"
3152 println("eclipseDir exists")
3154 eclipseBinary = "${eclipseRoot}/eclipse"
3155 eclipseProduct = "${eclipseRoot}/.eclipseproduct"
3158 eclipseVersion = "4.13" // default
3159 def assumedVersion = true
3160 if (file(eclipseProduct).exists()) {
3161 def fis = new FileInputStream(eclipseProduct)
3162 def props = new Properties()
3164 eclipseVersion = props.getProperty("version")
3166 assumedVersion = false
3169 def propKey = "eclipse_debug"
3170 eclipseDebug = (project.hasProperty(propKey) && project.getProperty(propKey).equals("true"))
3173 // do not run a headless transpile when we claim to be in Eclipse
3175 println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3176 throw new StopExecutionException("Not running headless transpile whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
3178 println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3181 if (!assumedVersion) {
3182 println("ECLIPSE VERSION=${eclipseVersion}")
3188 task printProperties {
3190 description "Output to console all System.properties"
3192 System.properties.each { key, val -> System.out.println("Property: ${key}=${val}") }
3198 dependsOn eclipseProject
3199 dependsOn eclipseClasspath
3200 dependsOn eclipseJdt
3204 // this version (type: Copy) will delete anything in the eclipse dropins folder that isn't in fromDropinsDir
3205 task jalviewjsEclipseCopyDropins(type: Copy) {
3206 dependsOn jalviewjsEclipsePaths
3208 def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjs_eclipse_dropins_dir}", include: "*.jar")
3209 inputFiles += file("${jalviewDir}/${jalviewjsJ2sPlugin}")
3210 def outputDir = "${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_eclipse_tmp_dropins_dir}"
3217 // this eclipse -clean doesn't actually work
3218 task jalviewjsCleanEclipse(type: Exec) {
3219 dependsOn eclipseSetup
3220 dependsOn jalviewjsEclipsePaths
3221 dependsOn jalviewjsEclipseCopyDropins
3223 executable(eclipseBinary)
3224 args(["-nosplash", "--launcher.suppressErrors", "-data", eclipseWorkspace.getPath(), "-clean", "-console", "-consoleLog"])
3230 def inputString = """exit
3233 def inputByteStream = new ByteArrayInputStream(inputString.getBytes())
3234 standardInput = inputByteStream
3237 /* not really working yet
3238 jalviewjsEclipseCopyDropins.finalizedBy jalviewjsCleanEclipse
3242 task jalviewjsTransferUnzipSwingJs {
3243 def file_zip = "${jalviewDir}/${jalviewjs_swingjs_zip}"
3247 from zipTree(file_zip)
3248 into "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}"
3252 inputs.file file_zip
3253 outputs.dir "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}"
3257 task jalviewjsTransferUnzipLib {
3258 def zipFiles = fileTree(dir: "${jalviewDir}/${jalviewjs_libjs_dir}", include: "*.zip")
3261 zipFiles.each { file_zip ->
3263 from zipTree(file_zip)
3264 into "${jalviewDir}/${jalviewjsTransferSiteLibDir}"
3269 inputs.files zipFiles
3270 outputs.dir "${jalviewDir}/${jalviewjsTransferSiteLibDir}"
3274 task jalviewjsTransferUnzipAllLibs {
3275 dependsOn jalviewjsTransferUnzipSwingJs
3276 dependsOn jalviewjsTransferUnzipLib
3280 task jalviewjsCreateJ2sSettings(type: WriteProperties) {
3282 description "Create the alternative j2s file from the j2s.* properties"
3284 jalviewjsJ2sProps = project.properties.findAll { it.key.startsWith("j2s.") }.sort { it.key }
3285 def siteDirProperty = "j2s.site.directory"
3286 def setSiteDir = false
3287 jalviewjsJ2sProps.each { prop, val ->
3289 if (prop == siteDirProperty) {
3290 if (!(val.startsWith('/') || val.startsWith("file://") )) {
3291 val = "${jalviewDir}/${jalviewjsTransferSiteJsDir}/${val}"
3297 if (!setSiteDir) { // default site location, don't override specifically set property
3298 property(siteDirProperty,"${jalviewDirRelativePath}/${jalviewjsTransferSiteJsDir}")
3301 outputFile = jalviewjsJ2sAltSettingsFileName
3304 inputs.properties(jalviewjsJ2sProps)
3305 outputs.file(jalviewjsJ2sAltSettingsFileName)
3310 task jalviewjsEclipseSetup {
3311 dependsOn jalviewjsEclipseCopyDropins
3312 dependsOn jalviewjsSetEclipseWorkspace
3313 dependsOn jalviewjsCreateJ2sSettings
3317 task jalviewjsSyncAllLibs (type: Sync) {
3318 dependsOn jalviewjsTransferUnzipAllLibs
3319 def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjsTransferSiteLibDir}")
3320 inputFiles += fileTree(dir: "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}")
3321 def outputDir = "${jalviewDir}/${jalviewjsSiteDir}"
3325 def outputFiles = []
3326 rename { filename ->
3327 outputFiles += "${outputDir}/${filename}"
3334 // should this be exclude really ?
3335 duplicatesStrategy "INCLUDE"
3337 outputs.files outputFiles
3338 inputs.files inputFiles
3342 task jalviewjsSyncResources (type: Sync) {
3343 dependsOn buildResources
3345 def inputFiles = fileTree(dir: resourcesBuildDir)
3346 def outputDir = "${jalviewDir}/${jalviewjsSiteDir}/${jalviewjs_j2s_subdir}"
3350 def outputFiles = []
3351 rename { filename ->
3352 outputFiles += "${outputDir}/${filename}"
3358 outputs.files outputFiles
3359 inputs.files inputFiles
3363 task jalviewjsSyncSiteResources (type: Sync) {
3364 def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjs_site_resource_dir}")
3365 def outputDir = "${jalviewDir}/${jalviewjsSiteDir}"
3369 def outputFiles = []
3370 rename { filename ->
3371 outputFiles += "${outputDir}/${filename}"
3377 outputs.files outputFiles
3378 inputs.files inputFiles
3382 task jalviewjsSyncBuildProperties (type: Sync) {
3383 dependsOn createBuildProperties
3384 def inputFiles = [file(buildProperties)]
3385 def outputDir = "${jalviewDir}/${jalviewjsSiteDir}/${jalviewjs_j2s_subdir}"
3389 def outputFiles = []
3390 rename { filename ->
3391 outputFiles += "${outputDir}/${filename}"
3397 outputs.files outputFiles
3398 inputs.files inputFiles
3402 task jalviewjsProjectImport(type: Exec) {
3403 dependsOn eclipseSetup
3404 dependsOn jalviewjsEclipsePaths
3405 dependsOn jalviewjsEclipseSetup
3408 // do not run a headless import when we claim to be in Eclipse
3410 println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3411 throw new StopExecutionException("Not running headless import whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
3413 println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3417 //def projdir = eclipseWorkspace.getPath()+"/.metadata/.plugins/org.eclipse.core.resources/.projects/jalview/org.eclipse.jdt.core"
3418 def projdir = eclipseWorkspace.getPath()+"/.metadata/.plugins/org.eclipse.core.resources/.projects/jalview"
3419 executable(eclipseBinary)
3420 args(["-nosplash", "--launcher.suppressErrors", "-application", "com.seeq.eclipse.importprojects.headlessimport", "-data", eclipseWorkspace.getPath(), "-import", jalviewDirAbsolutePath])
3424 args += [ "--launcher.appendVmargs", "-vmargs", "-Dorg.eclipse.equinox.p2.reconciler.dropins.directory=${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_eclipse_tmp_dropins_dir}" ]
3426 args += [ "-D${j2sHeadlessBuildProperty}=true" ]
3427 args += [ "-D${jalviewjs_j2s_alt_file_property}=${jalviewjsJ2sAltSettingsFileName}" ]
3430 inputs.file("${jalviewDir}/.project")
3431 outputs.upToDateWhen {
3432 file(projdir).exists()
3437 task jalviewjsTranspile(type: Exec) {
3438 dependsOn jalviewjsEclipseSetup
3439 dependsOn jalviewjsProjectImport
3440 dependsOn jalviewjsEclipsePaths
3442 dependsOn jalviewjsEnableAltFileProperty
3446 // do not run a headless transpile when we claim to be in Eclipse
3448 println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3449 throw new StopExecutionException("Not running headless transpile whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
3451 println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3455 executable(eclipseBinary)
3456 args(["-nosplash", "--launcher.suppressErrors", "-application", "org.eclipse.jdt.apt.core.aptBuild", "-data", eclipseWorkspace, "-${jalviewjs_eclipse_build_arg}", eclipse_project_name ])
3460 args += [ "--launcher.appendVmargs", "-vmargs", "-Dorg.eclipse.equinox.p2.reconciler.dropins.directory=${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_eclipse_tmp_dropins_dir}" ]
3462 args += [ "-D${j2sHeadlessBuildProperty}=true" ]
3463 args += [ "-D${jalviewjs_j2s_alt_file_property}=${jalviewjsJ2sAltSettingsFileName}" ]
3469 stdout = new ByteArrayOutputStream()
3470 stderr = new ByteArrayOutputStream()
3472 def logOutFileName = "${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}"
3473 def logOutFile = file(logOutFileName)
3474 logOutFile.createNewFile()
3475 logOutFile.text = """ROOT: ${jalviewjs_eclipse_root}
3476 BINARY: ${eclipseBinary}
3477 VERSION: ${eclipseVersion}
3478 WORKSPACE: ${eclipseWorkspace}
3479 DEBUG: ${eclipseDebug}
3482 def logOutFOS = new FileOutputStream(logOutFile, true) // true == append
3483 // combine stdout and stderr
3484 def logErrFOS = logOutFOS
3486 if (jalviewjs_j2s_to_console.equals("true")) {
3487 standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
3488 new org.apache.tools.ant.util.TeeOutputStream(
3492 errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
3493 new org.apache.tools.ant.util.TeeOutputStream(
3498 standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
3501 errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
3508 if (stdout.toString().contains("Error processing ")) {
3509 // j2s did not complete transpile
3510 //throw new TaskExecutionException("Error during transpilation:\n${stderr}\nSee eclipse transpile log file '${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}'")
3511 if (jalviewjs_ignore_transpile_errors.equals("true")) {
3512 println("IGNORING TRANSPILE ERRORS")
3513 println("See eclipse transpile log file '${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}'")
3515 throw new GradleException("Error during transpilation:\n${stderr}\nSee eclipse transpile log file '${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}'")
3520 inputs.dir("${jalviewDir}/${sourceDir}")
3521 outputs.dir("${jalviewDir}/${jalviewjsTransferSiteJsDir}")
3522 outputs.upToDateWhen( { file("${jalviewDir}/${jalviewjsTransferSiteJsDir}${jalviewjs_server_resource}").exists() } )
3526 def jalviewjsCallCore(String name, FileCollection list, String prefixFile, String suffixFile, String jsfile, String zjsfile, File logOutFile, Boolean logOutConsole) {
3528 def stdout = new ByteArrayOutputStream()
3529 def stderr = new ByteArrayOutputStream()
3531 def coreFile = file(jsfile)
3533 msg = "Creating core for ${name}...\nGenerating ${jsfile}"
3535 logOutFile.createNewFile()
3536 logOutFile.append(msg+"\n")
3538 def coreTop = file(prefixFile)
3539 def coreBottom = file(suffixFile)
3540 coreFile.getParentFile().mkdirs()
3541 coreFile.createNewFile()
3542 coreFile.write( coreTop.getText("UTF-8") )
3546 def t = f.getText("UTF-8")
3547 t.replaceAll("Clazz\\.([^_])","Clazz_${1}")
3548 coreFile.append( t )
3550 msg = "...file '"+f.getPath()+"' does not exist, skipping"
3552 logOutFile.append(msg+"\n")
3555 coreFile.append( coreBottom.getText("UTF-8") )
3557 msg = "Generating ${zjsfile}"
3559 logOutFile.append(msg+"\n")
3560 def logOutFOS = new FileOutputStream(logOutFile, true) // true == append
3561 def logErrFOS = logOutFOS
3564 classpath = files(["${jalviewDir}/${jalviewjs_closure_compiler}"])
3565 main = "com.google.javascript.jscomp.CommandLineRunner"
3566 jvmArgs = [ "-Dfile.encoding=UTF-8" ]
3567 args = [ "--compilation_level", "SIMPLE_OPTIMIZATIONS", "--warning_level", "QUIET", "--charset", "UTF-8", "--js", jsfile, "--js_output_file", zjsfile ]
3570 msg = "\nRunning '"+commandLine.join(' ')+"'\n"
3572 logOutFile.append(msg+"\n")
3574 if (logOutConsole) {
3575 standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
3576 new org.apache.tools.ant.util.TeeOutputStream(
3580 errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
3581 new org.apache.tools.ant.util.TeeOutputStream(
3586 standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
3589 errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
3596 logOutFile.append(msg+"\n")
3600 task jalviewjsBuildAllCores {
3602 description "Build the core js lib closures listed in the classlists dir"
3603 dependsOn jalviewjsTranspile
3604 dependsOn jalviewjsTransferUnzipSwingJs
3606 def j2sDir = "${jalviewDir}/${jalviewjsTransferSiteJsDir}/${jalviewjs_j2s_subdir}"
3607 def swingJ2sDir = "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}/${jalviewjs_j2s_subdir}"
3608 def libJ2sDir = "${jalviewDir}/${jalviewjsTransferSiteLibDir}/${jalviewjs_j2s_subdir}"
3609 def jsDir = "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}/${jalviewjs_js_subdir}"
3610 def outputDir = "${jalviewDir}/${jalviewjsTransferSiteCoreDir}/${jalviewjs_j2s_subdir}/core"
3611 def prefixFile = "${jsDir}/core/coretop2.js"
3612 def suffixFile = "${jsDir}/core/corebottom2.js"
3614 inputs.file prefixFile
3615 inputs.file suffixFile
3617 def classlistFiles = []
3618 // add the classlists found int the jalviewjs_classlists_dir
3619 fileTree(dir: "${jalviewDir}/${jalviewjs_classlists_dir}", include: "*.txt").each {
3621 def name = file.getName() - ".txt"
3628 // _jmol and _jalview cores. Add any other peculiar classlist.txt files here
3629 //classlistFiles += [ 'file': file("${jalviewDir}/${jalviewjs_classlist_jmol}"), 'name': "_jvjmol" ]
3630 classlistFiles += [ 'file': file("${jalviewDir}/${jalviewjs_classlist_jalview}"), 'name': jalviewjsJalviewCoreName ]
3632 jalviewjsCoreClasslists = []
3634 classlistFiles.each {
3637 def file = hash['file']
3638 if (! file.exists()) {
3639 //println("...classlist file '"+file.getPath()+"' does not exist, skipping")
3640 return false // this is a "continue" in groovy .each closure
3642 def name = hash['name']
3644 name = file.getName() - ".txt"
3652 def list = fileTree(dir: j2sDir, includes: filelist)
3654 def jsfile = "${outputDir}/core${name}.js"
3655 def zjsfile = "${outputDir}/core${name}.z.js"
3657 jalviewjsCoreClasslists += [
3666 outputs.file(jsfile)
3667 outputs.file(zjsfile)
3670 // _stevesoft core. add any cores without a classlist here (and the inputs and outputs)
3671 def stevesoftClasslistName = "_stevesoft"
3672 def stevesoftClasslist = [
3673 'jsfile': "${outputDir}/core${stevesoftClasslistName}.js",
3674 'zjsfile': "${outputDir}/core${stevesoftClasslistName}.z.js",
3675 'list': fileTree(dir: j2sDir, include: "com/stevesoft/pat/**/*.js"),
3676 'name': stevesoftClasslistName
3678 jalviewjsCoreClasslists += stevesoftClasslist
3679 inputs.files(stevesoftClasslist['list'])
3680 outputs.file(stevesoftClasslist['jsfile'])
3681 outputs.file(stevesoftClasslist['zjsfile'])
3684 def allClasslistName = "_all"
3685 def allJsFiles = fileTree(dir: j2sDir, include: "**/*.js")
3686 allJsFiles += fileTree(
3690 // these exlusions are files that the closure-compiler produces errors for. Should fix them
3691 "**/org/jmol/jvxl/readers/IsoIntersectFileReader.js",
3692 "**/org/jmol/export/JSExporter.js"
3695 allJsFiles += fileTree(
3699 // these exlusions are files that the closure-compiler produces errors for. Should fix them
3700 "**/sun/misc/Unsafe.js",
3701 "**/swingjs/jquery/jquery-editable-select.js",
3702 "**/swingjs/jquery/j2sComboBox.js",
3703 "**/sun/misc/FloatingDecimal.js"
3706 def allClasslist = [
3707 'jsfile': "${outputDir}/core${allClasslistName}.js",
3708 'zjsfile': "${outputDir}/core${allClasslistName}.z.js",
3710 'name': allClasslistName
3712 // not including this version of "all" core at the moment
3713 //jalviewjsCoreClasslists += allClasslist
3714 inputs.files(allClasslist['list'])
3715 outputs.file(allClasslist['jsfile'])
3716 outputs.file(allClasslist['zjsfile'])
3719 def logOutFile = file("${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_j2s_closure_stdout}")
3720 logOutFile.getParentFile().mkdirs()
3721 logOutFile.createNewFile()
3722 logOutFile.write(getDate("yyyy-MM-dd HH:mm:ss")+" jalviewjsBuildAllCores\n----\n")
3724 jalviewjsCoreClasslists.each {
3725 jalviewjsCallCore(it.name, it.list, prefixFile, suffixFile, it.jsfile, it.zjsfile, logOutFile, jalviewjs_j2s_to_console.equals("true"))
3732 def jalviewjsPublishCoreTemplate(String coreName, String templateName, File inputFile, String outputFile) {
3735 into file(outputFile).getParentFile()
3736 rename { filename ->
3737 if (filename.equals(inputFile.getName())) {
3738 return file(outputFile).getName()
3742 filter(ReplaceTokens,
3746 'MAIN': '"'+main_class+'"',
3748 'NAME': jalviewjsJalviewTemplateName+" [core ${coreName}]",
3749 'COREKEY': jalviewjs_core_key,
3750 'CORENAME': coreName
3757 task jalviewjsPublishCoreTemplates {
3758 dependsOn jalviewjsBuildAllCores
3759 def inputFileName = "${jalviewDir}/${j2s_coretemplate_html}"
3760 def inputFile = file(inputFileName)
3761 def outputDir = "${jalviewDir}/${jalviewjsTransferSiteCoreDir}"
3763 def outputFiles = []
3764 jalviewjsCoreClasslists.each { cl ->
3765 def outputFile = "${outputDir}/${jalviewjsJalviewTemplateName}_${cl.name}.html"
3766 cl['outputfile'] = outputFile
3767 outputFiles += outputFile
3771 jalviewjsCoreClasslists.each { cl ->
3772 jalviewjsPublishCoreTemplate(cl.name, jalviewjsJalviewTemplateName, inputFile, cl.outputfile)
3775 inputs.file(inputFile)
3776 outputs.files(outputFiles)
3780 task jalviewjsSyncCore (type: Sync) {
3781 dependsOn jalviewjsBuildAllCores
3782 dependsOn jalviewjsPublishCoreTemplates
3783 def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjsTransferSiteCoreDir}")
3784 def outputDir = "${jalviewDir}/${jalviewjsSiteDir}"
3788 def outputFiles = []
3789 rename { filename ->
3790 outputFiles += "${outputDir}/${filename}"
3796 outputs.files outputFiles
3797 inputs.files inputFiles
3801 // this Copy version of TransferSiteJs will delete anything else in the target dir
3802 task jalviewjsCopyTransferSiteJs(type: Copy) {
3803 dependsOn jalviewjsTranspile
3804 from "${jalviewDir}/${jalviewjsTransferSiteJsDir}"
3805 into "${jalviewDir}/${jalviewjsSiteDir}"
3809 // this Sync version of TransferSite is used by buildship to keep the website automatically up to date when a file changes
3810 task jalviewjsSyncTransferSiteJs(type: Sync) {
3811 from "${jalviewDir}/${jalviewjsTransferSiteJsDir}"
3813 into "${jalviewDir}/${jalviewjsSiteDir}"
3820 jalviewjsSyncAllLibs.mustRunAfter jalviewjsCopyTransferSiteJs
3821 jalviewjsSyncResources.mustRunAfter jalviewjsCopyTransferSiteJs
3822 jalviewjsSyncSiteResources.mustRunAfter jalviewjsCopyTransferSiteJs
3823 jalviewjsSyncBuildProperties.mustRunAfter jalviewjsCopyTransferSiteJs
3825 jalviewjsSyncAllLibs.mustRunAfter jalviewjsSyncTransferSiteJs
3826 jalviewjsSyncResources.mustRunAfter jalviewjsSyncTransferSiteJs
3827 jalviewjsSyncSiteResources.mustRunAfter jalviewjsSyncTransferSiteJs
3828 jalviewjsSyncBuildProperties.mustRunAfter jalviewjsSyncTransferSiteJs
3831 task jalviewjsPrepareSite {
3833 description "Prepares the website folder including unzipping files and copying resources"
3834 dependsOn jalviewjsSyncAllLibs
3835 dependsOn jalviewjsSyncResources
3836 dependsOn jalviewjsSyncSiteResources
3837 dependsOn jalviewjsSyncBuildProperties
3838 dependsOn jalviewjsSyncCore
3842 task jalviewjsBuildSite {
3844 description "Builds the whole website including transpiled code"
3845 dependsOn jalviewjsCopyTransferSiteJs
3846 dependsOn jalviewjsPrepareSite
3850 task cleanJalviewjsTransferSite {
3852 delete "${jalviewDir}/${jalviewjsTransferSiteJsDir}"
3853 delete "${jalviewDir}/${jalviewjsTransferSiteLibDir}"
3854 delete "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}"
3855 delete "${jalviewDir}/${jalviewjsTransferSiteCoreDir}"
3860 task cleanJalviewjsSite {
3861 dependsOn cleanJalviewjsTransferSite
3863 delete "${jalviewDir}/${jalviewjsSiteDir}"
3868 task jalviewjsSiteTar(type: Tar) {
3870 description "Creates a tar.gz file for the website"
3871 dependsOn jalviewjsBuildSite
3872 def outputFilename = "jalviewjs-site-${JALVIEW_VERSION}.tar.gz"
3873 archiveFileName = outputFilename
3875 compression Compression.GZIP
3877 from "${jalviewDir}/${jalviewjsSiteDir}"
3878 into jalviewjs_site_dir // this is inside the tar file
3880 inputs.dir("${jalviewDir}/${jalviewjsSiteDir}")
3884 task jalviewjsServer {
3886 def filename = "jalviewjsTest.html"
3887 description "Starts a webserver on localhost to test the website. See ${filename} to access local site on most recently used port."
3888 def htmlFile = "${jalviewDirAbsolutePath}/${filename}"
3893 def f = Class.forName("org.gradle.plugins.javascript.envjs.http.simple.SimpleHttpFileServerFactory")
3894 factory = f.newInstance()
3895 } catch (ClassNotFoundException e) {
3896 throw new GradleException("Unable to create SimpleHttpFileServerFactory")
3898 def port = Integer.valueOf(jalviewjs_server_port)
3903 while(port < start+1000 && !running) {
3905 def doc_root = new File("${jalviewDirAbsolutePath}/${jalviewjsSiteDir}")
3906 jalviewjsServer = factory.start(doc_root, port)
3908 url = jalviewjsServer.getResourceUrl(jalviewjs_server_resource)
3909 println("SERVER STARTED with document root ${doc_root}.")
3910 println("Go to "+url+" . Run gradle --stop to stop (kills all gradle daemons).")
3911 println("For debug: "+url+"?j2sdebug")
3912 println("For verbose: "+url+"?j2sverbose")
3913 } catch (Exception e) {
3918 <p><a href="${url}">JalviewJS Test. <${url}></a></p>
3919 <p><a href="${url}?j2sdebug">JalviewJS Test with debug. <${url}?j2sdebug></a></p>
3920 <p><a href="${url}?j2sverbose">JalviewJS Test with verbose. <${url}?j2sdebug></a></p>
3922 jalviewjsCoreClasslists.each { cl ->
3923 def urlcore = jalviewjsServer.getResourceUrl(file(cl.outputfile).getName())
3925 <p><a href="${urlcore}">${jalviewjsJalviewTemplateName} [core ${cl.name}]. <${urlcore}></a></p>
3927 println("For core ${cl.name}: "+urlcore)
3930 file(htmlFile).text = htmlText
3933 outputs.file(htmlFile)
3934 outputs.upToDateWhen({false})
3938 task cleanJalviewjsAll {
3940 description "Delete all configuration and build artifacts to do with JalviewJS build"
3941 dependsOn cleanJalviewjsSite
3942 dependsOn jalviewjsEclipsePaths
3945 delete "${jalviewDir}/${jalviewjsBuildDir}"
3946 delete "${jalviewDir}/${eclipse_bin_dir}"
3947 if (eclipseWorkspace != null && file(eclipseWorkspace.getAbsolutePath()+"/.metadata").exists()) {
3948 delete file(eclipseWorkspace.getAbsolutePath()+"/.metadata")
3950 delete jalviewjsJ2sAltSettingsFileName
3953 outputs.upToDateWhen( { false } )
3957 task jalviewjsIDE_checkJ2sPlugin {
3958 group "00 JalviewJS in Eclipse"
3959 description "Compare the swingjs/net.sf.j2s.core(-j11)?.jar file with the Eclipse IDE's plugin version (found in the 'dropins' dir)"
3962 def j2sPlugin = string("${jalviewDir}/${jalviewjsJ2sPlugin}")
3963 def j2sPluginFile = file(j2sPlugin)
3964 def eclipseHome = System.properties["eclipse.home.location"]
3965 if (eclipseHome == null || ! IN_ECLIPSE) {
3966 throw new StopExecutionException("Cannot find running Eclipse home from System.properties['eclipse.home.location']. Skipping J2S Plugin Check.")
3968 def eclipseJ2sPluginDirs = [ "${eclipseHome}/dropins" ]
3969 def altPluginsDir = System.properties["org.eclipse.equinox.p2.reconciler.dropins.directory"]
3970 if (altPluginsDir != null && file(altPluginsDir).exists()) {
3971 eclipseJ2sPluginDirs += altPluginsDir
3973 def foundPlugin = false
3974 def j2sPluginFileName = j2sPluginFile.getName()
3975 def eclipseJ2sPlugin
3976 def eclipseJ2sPluginFile
3977 eclipseJ2sPluginDirs.any { dir ->
3978 eclipseJ2sPlugin = "${dir}/${j2sPluginFileName}"
3979 eclipseJ2sPluginFile = file(eclipseJ2sPlugin)
3980 if (eclipseJ2sPluginFile.exists()) {
3986 def msg = "Eclipse J2S Plugin is not installed (could not find '${j2sPluginFileName}' in\n"+eclipseJ2sPluginDirs.join("\n")+"\n)\nTry running task jalviewjsIDE_copyJ2sPlugin"
3987 System.err.println(msg)
3988 throw new StopExecutionException(msg)
3991 def digest = MessageDigest.getInstance("MD5")
3993 digest.update(j2sPluginFile.text.bytes)
3994 def j2sPluginMd5 = new BigInteger(1, digest.digest()).toString(16).padLeft(32, '0')
3996 digest.update(eclipseJ2sPluginFile.text.bytes)
3997 def eclipseJ2sPluginMd5 = new BigInteger(1, digest.digest()).toString(16).padLeft(32, '0')
3999 if (j2sPluginMd5 != eclipseJ2sPluginMd5) {
4000 def msg = "WARNING! Eclipse J2S Plugin '${eclipseJ2sPlugin}' is different to this commit's version '${j2sPlugin}'"
4001 System.err.println(msg)
4002 throw new StopExecutionException(msg)
4004 def msg = "Eclipse J2S Plugin '${eclipseJ2sPlugin}' is the same as '${j2sPlugin}' (this is good)"
4010 task jalviewjsIDE_copyJ2sPlugin {
4011 group "00 JalviewJS in Eclipse"
4012 description "Copy the swingjs/net.sf.j2s.core(-j11)?.jar file into the Eclipse IDE's 'dropins' dir"
4015 def j2sPlugin = string("${jalviewDir}/${jalviewjsJ2sPlugin}")
4016 def j2sPluginFile = file(j2sPlugin)
4017 def eclipseHome = System.properties["eclipse.home.location"]
4018 if (eclipseHome == null || ! IN_ECLIPSE) {
4019 throw new StopExecutionException("Cannot find running Eclipse home from System.properties['eclipse.home.location']. NOT copying J2S Plugin.")
4021 def eclipseJ2sPlugin = "${eclipseHome}/dropins/${j2sPluginFile.getName()}"
4022 def eclipseJ2sPluginFile = file(eclipseJ2sPlugin)
4023 def msg = "WARNING! Copying this commit's j2s plugin '${j2sPlugin}' to Eclipse J2S Plugin '${eclipseJ2sPlugin}'\n* May require an Eclipse restart"
4024 System.err.println(msg)
4027 eclipseJ2sPluginFile.getParentFile().mkdirs()
4028 into eclipseJ2sPluginFile.getParent()
4034 task jalviewjsIDE_j2sFile {
4035 group "00 JalviewJS in Eclipse"
4036 description "Creates the .j2s file"
4037 dependsOn jalviewjsCreateJ2sSettings
4041 task jalviewjsIDE_SyncCore {
4042 group "00 JalviewJS in Eclipse"
4043 description "Build the core js lib closures listed in the classlists dir and publish core html from template"
4044 dependsOn jalviewjsSyncCore
4048 task jalviewjsIDE_SyncSiteAll {
4049 dependsOn jalviewjsSyncAllLibs
4050 dependsOn jalviewjsSyncResources
4051 dependsOn jalviewjsSyncSiteResources
4052 dependsOn jalviewjsSyncBuildProperties
4056 cleanJalviewjsTransferSite.mustRunAfter jalviewjsIDE_SyncSiteAll
4059 task jalviewjsIDE_PrepareSite {
4060 group "00 JalviewJS in Eclipse"
4061 description "Sync libs and resources to site dir, but not closure cores"
4063 dependsOn jalviewjsIDE_SyncSiteAll
4064 //dependsOn cleanJalviewjsTransferSite // not sure why this clean is here -- will slow down a re-run of this task
4068 task jalviewjsIDE_AssembleSite {
4069 group "00 JalviewJS in Eclipse"
4070 description "Assembles unzipped supporting zipfiles, resources, site resources and closure cores into the Eclipse transpiled site"
4071 dependsOn jalviewjsPrepareSite
4075 task jalviewjsIDE_SiteClean {
4076 group "00 JalviewJS in Eclipse"
4077 description "Deletes the Eclipse transpiled site"
4078 dependsOn cleanJalviewjsSite
4082 task jalviewjsIDE_Server {
4083 group "00 JalviewJS in Eclipse"
4084 description "Starts a webserver on localhost to test the website"
4085 dependsOn jalviewjsServer
4089 // buildship runs this at import or gradle refresh
4090 task eclipseSynchronizationTask {
4091 //dependsOn eclipseSetup
4092 dependsOn createBuildProperties
4094 dependsOn jalviewjsIDE_j2sFile
4095 dependsOn jalviewjsIDE_checkJ2sPlugin
4096 dependsOn jalviewjsIDE_PrepareSite
4101 // buildship runs this at build time or project refresh
4102 task eclipseAutoBuildTask {
4103 //dependsOn jalviewjsIDE_checkJ2sPlugin
4104 //dependsOn jalviewjsIDE_PrepareSite
4110 description "Build the site"
4111 dependsOn jalviewjsBuildSite