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
1740 group = "Verification"
1741 description = "Runs all testTaskN tasks)"
1744 dependsOn cloverClasses
1746 dependsOn testClasses
1749 // not running tests in this task
1752 /* testTask0 is the main test task */
1753 task testTask0(type: Test) {
1754 group = "Verification"
1755 description = "The main test task. Runs all non-testTaskN-labelled tests (unless excluded)"
1757 includeGroups testng_groups.split(",")
1758 excludeGroups testng_excluded_groups.split(",")
1759 tasks.withType(Test).matching {it.name.startsWith("testTask") && it.name != name}.all {t -> excludeGroups t.name}
1761 useDefaultListeners=true
1765 /* separated tests */
1766 task testTask1(type: Test) {
1767 group = "Verification"
1768 description = "Tests that need to be isolated from the main test run"
1771 excludeGroups testng_excluded_groups.split(",")
1773 useDefaultListeners=true
1777 /* insert more testTaskNs here -- change N to next digit or other string */
1779 task testTaskN(type: Test) {
1780 group = "Verification"
1781 description = "Tests that need to be isolated from the main test run"
1784 excludeGroups testng_excluded_groups.split(",")
1786 useDefaultListeners=true
1792 * adapted from https://medium.com/@wasyl/pretty-tests-summary-in-gradle-744804dd676c
1793 * to summarise test results from all Test tasks
1795 /* START of test tasks results summary */
1796 import groovy.time.TimeCategory
1797 import org.gradle.api.tasks.testing.logging.TestExceptionFormat
1798 import org.gradle.api.tasks.testing.logging.TestLogEvent
1799 rootProject.ext.testsResults = [] // Container for tests summaries
1801 tasks.withType(Test).matching {t -> t.getName().startsWith("testTask")}.all { testTask ->
1803 // from original test task
1805 dependsOn cloverClasses
1807 dependsOn testClasses //?
1810 // run main tests first
1811 if (!testTask.name.equals("testTask0"))
1812 testTask.mustRunAfter "testTask0"
1814 testTask.testLogging { logging ->
1815 events TestLogEvent.FAILED
1816 // TestLogEvent.SKIPPED,
1817 // TestLogEvent.STANDARD_OUT,
1818 // TestLogEvent.STANDARD_ERROR
1820 exceptionFormat TestExceptionFormat.FULL
1823 showStackTraces true
1825 info.events = [ TestLogEvent.FAILED ]
1830 ignoreFailures = true // Always try to run all tests for all modules
1832 afterSuite { desc, result ->
1834 return // Only summarize results for whole modules
1836 def resultsInfo = [testTask.project.name, testTask.name, result, TimeCategory.minus(new Date(result.endTime), new Date(result.startTime)), testTask.reports.html.entryPoint]
1838 rootProject.ext.testsResults.add(resultsInfo)
1841 // from original test task
1842 maxHeapSize = "1024m"
1844 workingDir = jalviewDir
1845 def testLaf = project.findProperty("test_laf")
1846 if (testLaf != null) {
1847 println("Setting Test LaF to '${testLaf}'")
1848 systemProperty "laf", testLaf
1850 def testHiDPIScale = project.findProperty("test_HiDPIScale")
1851 if (testHiDPIScale != null) {
1852 println("Setting Test HiDPI Scale to '${testHiDPIScale}'")
1853 systemProperty "sun.java2d.uiScale", testHiDPIScale
1855 sourceCompatibility = compile_source_compatibility
1856 targetCompatibility = compile_target_compatibility
1857 jvmArgs += additional_compiler_args
1860 // this is not perfect yet -- we should only add the commandLineIncludePatterns to the
1861 // testTasks that include the tests, and exclude all from the others.
1862 // get --test argument
1863 filter.commandLineIncludePatterns = test.filter.commandLineIncludePatterns
1864 // do something with testTask.getCandidateClassFiles() to see if the test should silently finish because of the
1865 // commandLineIncludePatterns not matching anything. Instead we are doing setFailOnNoMatchingTests(false) below
1869 println("Running tests " + (useClover?"WITH":"WITHOUT") + " clover")
1874 /* don't fail on no matching tests (so --tests will run across all testTasks) */
1875 testTask.filter.setFailOnNoMatchingTests(false)
1877 /* ensure the "test" task dependsOn all the testTasks */
1878 test.dependsOn testTask
1881 gradle.buildFinished {
1882 def allResults = rootProject.ext.testsResults
1884 if (!allResults.isEmpty()) {
1885 printResults allResults
1886 allResults.each {r ->
1887 if (r[2].resultType == TestResult.ResultType.FAILURE)
1888 throw new GradleException("Failed tests!")
1893 private static String colString(styler, col, colour, text) {
1894 return col?"${styler[colour](text)}":text
1897 private static String getSummaryLine(s, pn, tn, rt, rc, rs, rf, rsk, t, col) {
1898 def colour = 'black'
1906 case TestResult.ResultType.SUCCESS:
1909 case TestResult.ResultType.FAILURE:
1917 StringBuilder sb = new StringBuilder()
1921 sb.append(" results: ")
1922 sb.append(colString(s, col && !nocol, colour, text))
1924 sb.append("${rc} tests, ")
1925 sb.append(colString(s, col && rs > 0, 'green', rs))
1926 sb.append(" successes, ")
1927 sb.append(colString(s, col && rf > 0, 'red', rf))
1928 sb.append(" failures, ")
1929 sb.append("${rsk} skipped) in ${t}")
1930 return sb.toString()
1933 private static void printResults(allResults) {
1935 // styler from https://stackoverflow.com/a/56139852
1936 def styler = 'black red green yellow blue magenta cyan white'.split().toList().withIndex(30).collectEntries { key, val -> [(key) : { "\033[${val}m${it}\033[0m" }] }
1939 def failedTests = false
1940 def summaryLines = []
1942 def totalsuccess = 0
1945 def totaltime = TimeCategory.getSeconds(0)
1946 // sort on project name then task name
1947 allResults.sort {a, b -> a[0] == b[0]? a[1]<=>b[1]:a[0] <=> b[0]}.each {
1948 def projectName = it[0]
1949 def taskName = it[1]
1953 def summaryCol = getSummaryLine(styler, projectName, taskName, result.resultType, result.testCount, result.successfulTestCount, result.failedTestCount, result.skippedTestCount, time, true)
1954 def summaryPlain = getSummaryLine(styler, projectName, taskName, result.resultType, result.testCount, result.successfulTestCount, result.failedTestCount, result.skippedTestCount, time, false)
1955 def reportLine = "Report file: ${report}"
1956 def ls = summaryPlain.length()
1957 def lr = reportLine.length()
1958 def m = [ls, lr].max()
1961 def info = [ls, summaryCol, reportLine]
1962 summaryLines.add(info)
1963 failedTests |= result.resultType == TestResult.ResultType.FAILURE
1964 totalcount += result.testCount
1965 totalsuccess += result.successfulTestCount
1966 totalfail += result.failedTestCount
1967 totalskip += result.skippedTestCount
1970 def totalSummaryCol = getSummaryLine(styler, "OVERALL", "", failedTests?TestResult.ResultType.FAILURE:TestResult.ResultType.SUCCESS, totalcount, totalsuccess, totalfail, totalskip, totaltime, true)
1971 def totalSummaryPlain = getSummaryLine(styler, "OVERALL", "", failedTests?TestResult.ResultType.FAILURE:TestResult.ResultType.SUCCESS, totalcount, totalsuccess, totalfail, totalskip, totaltime, false)
1972 def tls = totalSummaryPlain.length()
1973 if (tls > maxLength)
1975 def info = [tls, totalSummaryCol, null]
1976 summaryLines.add(info)
1978 def allSummaries = []
1979 for(sInfo : summaryLines) {
1981 def summary = sInfo[1]
1982 def report = sInfo[2]
1984 StringBuilder sb = new StringBuilder()
1985 sb.append("│" + summary + " " * (maxLength - ls) + "│")
1986 if (report != null) {
1987 sb.append("\n│" + report + " " * (maxLength - report.length()) + "│")
1989 allSummaries += sb.toString()
1992 println "┌${"${"─" * maxLength}"}┐"
1993 println allSummaries.join("\n├${"${"─" * maxLength}"}┤\n")
1994 println "└${"${"─" * maxLength}"}┘"
1996 /* END of test tasks results summary */
1999 task compileLinkCheck(type: JavaCompile) {
2001 classpath = files("${jalviewDir}/${utils_dir}")
2002 destinationDir = file("${jalviewDir}/${utils_dir}")
2003 source = fileTree(dir: "${jalviewDir}/${utils_dir}", include: ["HelpLinksChecker.java", "BufferedLineReader.java"])
2005 inputs.file("${jalviewDir}/${utils_dir}/HelpLinksChecker.java")
2006 inputs.file("${jalviewDir}/${utils_dir}/HelpLinksChecker.java")
2007 outputs.file("${jalviewDir}/${utils_dir}/HelpLinksChecker.class")
2008 outputs.file("${jalviewDir}/${utils_dir}/BufferedLineReader.class")
2012 task linkCheck(type: JavaExec) {
2014 dependsOn compileLinkCheck
2016 def helpLinksCheckerOutFile = file("${jalviewDir}/${utils_dir}/HelpLinksChecker.out")
2017 classpath = files("${jalviewDir}/${utils_dir}")
2018 main = "HelpLinksChecker"
2019 workingDir = "${helpBuildDir}"
2020 args = [ "${helpBuildDir}/${help_dir}", "-nointernet" ]
2022 def outFOS = new FileOutputStream(helpLinksCheckerOutFile, false) // false == don't append
2023 standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
2026 errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
2030 inputs.dir(helpBuildDir)
2031 outputs.file(helpLinksCheckerOutFile)
2035 // import the pubhtmlhelp target
2036 ant.properties.basedir = "${jalviewDir}"
2037 ant.properties.helpBuildDir = "${helpBuildDir}/${help_dir}"
2038 ant.importBuild "${utils_dir}/publishHelp.xml"
2041 task cleanPackageDir(type: Delete) {
2043 delete fileTree(dir: "${jalviewDir}/${package_dir}", include: "*.jar")
2053 attributes "Main-Class": main_class,
2054 "Permissions": "all-permissions",
2055 "Application-Name": applicationName,
2056 "Codebase": application_codebase,
2057 "Implementation-Version": JALVIEW_VERSION
2060 def outputDir = "${jalviewDir}/${package_dir}"
2061 destinationDirectory = file(outputDir)
2062 archiveFileName = rootProject.name+".jar"
2063 duplicatesStrategy "EXCLUDE"
2070 exclude "**/*.jar.*"
2072 inputs.dir(sourceSets.main.java.outputDir)
2073 sourceSets.main.resources.srcDirs.each{ dir ->
2076 outputs.file("${outputDir}/${archiveFileName}")
2080 task copyJars(type: Copy) {
2081 from fileTree(dir: classesDir, include: "**/*.jar").files
2082 into "${jalviewDir}/${package_dir}"
2086 // doing a Sync instead of Copy as Copy doesn't deal with "outputs" very well
2087 task syncJars(type: Sync) {
2089 from fileTree(dir: "${jalviewDir}/${libDistDir}", include: "**/*.jar").files
2090 into "${jalviewDir}/${package_dir}"
2092 include jar.archiveFileName.getOrNull()
2099 description = "Put all required libraries in dist"
2100 // order of "cleanPackageDir", "copyJars", "jar" important!
2101 jar.mustRunAfter cleanPackageDir
2102 syncJars.mustRunAfter cleanPackageDir
2103 dependsOn cleanPackageDir
2106 outputs.dir("${jalviewDir}/${package_dir}")
2111 dependsOn cleanPackageDir
2118 group = "distribution"
2119 description = "Create a single jar file with all dependency libraries merged. Can be run with java -jar"
2123 from ("${jalviewDir}/${libDistDir}") {
2127 attributes "Implementation-Version": JALVIEW_VERSION,
2128 "Application-Name": applicationName
2131 duplicatesStrategy "INCLUDE"
2133 mainClassName = shadow_jar_main_class
2135 classifier = "all-"+JALVIEW_VERSION+"-j"+JAVA_VERSION
2139 task getdownImagesCopy() {
2140 inputs.dir getdownImagesDir
2141 outputs.dir getdownImagesBuildDir
2145 from(getdownImagesDir) {
2146 include("*getdown*.png")
2148 into getdownImagesBuildDir
2153 task getdownImagesProcess() {
2154 dependsOn getdownImagesCopy
2157 if (backgroundImageText) {
2158 if (convertBinary == null) {
2159 throw new StopExecutionException("No ImageMagick convert binary installed at '${convertBinaryExpectedLocation}'")
2161 if (!project.hasProperty("getdown_background_image_text_suffix_cmd")) {
2162 throw new StopExecutionException("No property 'getdown_background_image_text_suffix_cmd' defined. See channel_gradle.properties for channel ${CHANNEL}")
2164 fileTree(dir: getdownImagesBuildDir, include: "*background*.png").getFiles().each { file ->
2166 executable convertBinary
2169 '-font', getdown_background_image_text_font,
2170 '-fill', getdown_background_image_text_colour,
2171 '-draw', sprintf(getdown_background_image_text_suffix_cmd, channelSuffix),
2172 '-draw', sprintf(getdown_background_image_text_commit_cmd, "git-commit: ${gitHash}"),
2173 '-draw', sprintf(getdown_background_image_text_date_cmd, getDate("yyyy-MM-dd HH:mm:ss")),
2182 task getdownImages() {
2183 dependsOn getdownImagesProcess
2186 task getdownWebsite() {
2187 group = "distribution"
2188 description = "Create the getdown minimal app folder, and website folder for this version of jalview. Website folder also used for offline app installer"
2190 dependsOn getdownImages
2195 def getdownWebsiteResourceFilenames = []
2196 def getdownResourceDir = getdownResourceDir
2197 def getdownResourceFilenames = []
2200 // clean the getdown website and files dir before creating getdown folders
2201 delete getdownAppBaseDir
2202 delete getdownFilesDir
2205 from buildProperties
2206 rename(file(buildProperties).getName(), getdown_build_properties)
2209 getdownWebsiteResourceFilenames += "${getdownAppDistDir}/${getdown_build_properties}"
2212 from channelPropsFile
2213 filter(ReplaceTokens,
2217 'SUFFIX': channelSuffix
2220 into getdownAppBaseDir
2222 getdownWebsiteResourceFilenames += file(channelPropsFile).getName()
2224 // set some getdownTxt_ properties then go through all properties looking for getdownTxt_...
2225 def props = project.properties.sort { it.key }
2226 if (getdownAltJavaMinVersion != null && getdownAltJavaMinVersion.length() > 0) {
2227 props.put("getdown_txt_java_min_version", getdownAltJavaMinVersion)
2229 if (getdownAltJavaMaxVersion != null && getdownAltJavaMaxVersion.length() > 0) {
2230 props.put("getdown_txt_java_max_version", getdownAltJavaMaxVersion)
2232 if (getdownAltMultiJavaLocation != null && getdownAltMultiJavaLocation.length() > 0) {
2233 props.put("getdown_txt_multi_java_location", getdownAltMultiJavaLocation)
2235 if (getdownImagesBuildDir != null && file(getdownImagesBuildDir).exists()) {
2236 props.put("getdown_txt_ui.background_image", "${getdownImagesBuildDir}/${getdown_background_image}")
2237 props.put("getdown_txt_ui.instant_background_image", "${getdownImagesBuildDir}/${getdown_instant_background_image}")
2238 props.put("getdown_txt_ui.error_background", "${getdownImagesBuildDir}/${getdown_error_background}")
2239 props.put("getdown_txt_ui.progress_image", "${getdownImagesBuildDir}/${getdown_progress_image}")
2240 props.put("getdown_txt_ui.icon", "${getdownImagesDir}/${getdown_icon}")
2241 props.put("getdown_txt_ui.mac_dock_icon", "${getdownImagesDir}/${getdown_mac_dock_icon}")
2244 props.put("getdown_txt_title", jalview_name)
2245 props.put("getdown_txt_ui.name", applicationName)
2247 // start with appbase
2248 getdownTextLines += "appbase = ${getdownAppBase}"
2249 props.each{ prop, val ->
2250 if (prop.startsWith("getdown_txt_") && val != null) {
2251 if (prop.startsWith("getdown_txt_multi_")) {
2252 def key = prop.substring(18)
2253 val.split(",").each{ v ->
2254 def line = "${key} = ${v}"
2255 getdownTextLines += line
2258 // file values rationalised
2259 if (val.indexOf('/') > -1 || prop.startsWith("getdown_txt_resource")) {
2261 if (val.indexOf('/') == 0) {
2264 } else if (val.indexOf('/') > 0) {
2265 // relative path (relative to jalviewDir)
2266 r = file( "${jalviewDir}/${val}" )
2269 val = "${getdown_resource_dir}/" + r.getName()
2270 getdownWebsiteResourceFilenames += val
2271 getdownResourceFilenames += r.getPath()
2274 if (! prop.startsWith("getdown_txt_resource")) {
2275 def line = prop.substring(12) + " = ${val}"
2276 getdownTextLines += line
2282 getdownWebsiteResourceFilenames.each{ filename ->
2283 getdownTextLines += "resource = ${filename}"
2285 getdownResourceFilenames.each{ filename ->
2288 into getdownResourceDir
2292 def getdownWrapperScripts = [ getdown_bash_wrapper_script, getdown_powershell_wrapper_script, getdown_batch_wrapper_script ]
2293 getdownWrapperScripts.each{ script ->
2294 def s = file( "${jalviewDir}/utils/getdown/${getdown_wrapper_script_dir}/${script}" )
2298 into "${getdownAppBaseDir}/${getdown_wrapper_script_dir}"
2300 getdownTextLines += "resource = ${getdown_wrapper_script_dir}/${script}"
2305 fileTree(file(package_dir)).each{ f ->
2306 if (f.isDirectory()) {
2307 def files = fileTree(dir: f, include: ["*"]).getFiles()
2309 } else if (f.exists()) {
2313 def jalviewJar = jar.archiveFileName.getOrNull()
2314 // put jalview.jar first for CLASSPATH and .properties files reasons
2315 codeFiles.sort{a, b -> ( a.getName() == jalviewJar ? -1 : ( b.getName() == jalviewJar ? 1 : a <=> b ) ) }.each{f ->
2316 def name = f.getName()
2317 def line = "code = ${getdownAppDistDir}/${name}"
2318 getdownTextLines += line
2325 // NOT USING MODULES YET, EVERYTHING SHOULD BE IN dist
2327 if (JAVA_VERSION.equals("11")) {
2328 def j11libFiles = fileTree(dir: "${jalviewDir}/${j11libDir}", include: ["*.jar"]).getFiles()
2329 j11libFiles.sort().each{f ->
2330 def name = f.getName()
2331 def line = "code = ${getdown_j11lib_dir}/${name}"
2332 getdownTextLines += line
2335 into getdownJ11libDir
2341 // 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.
2342 //getdownTextLines += "class = " + file(getdownLauncher).getName()
2343 getdownTextLines += "resource = ${getdown_launcher_new}"
2344 getdownTextLines += "class = ${main_class}"
2345 // Not setting these properties in general so that getdownappbase and getdowndistdir will default to release version in jalview.bin.Cache
2346 if (getdownSetAppBaseProperty) {
2347 getdownTextLines += "jvmarg = -Dgetdowndistdir=${getdownAppDistDir}"
2348 getdownTextLines += "jvmarg = -Dgetdownappbase=${getdownAppBase}"
2351 def getdownTxt = file("${getdownAppBaseDir}/getdown.txt")
2352 getdownTxt.write(getdownTextLines.join("\n"))
2354 getdownLaunchJvl = getdown_launch_jvl_name + ( (jvlChannelName != null && jvlChannelName.length() > 0)?"-${jvlChannelName}":"" ) + ".jvl"
2355 def launchJvl = file("${getdownAppBaseDir}/${getdownLaunchJvl}")
2356 launchJvl.write("appbase=${getdownAppBase}")
2358 // files going into the getdown website dir: getdown-launcher.jar
2360 from getdownLauncher
2361 rename(file(getdownLauncher).getName(), getdown_launcher_new)
2362 into getdownAppBaseDir
2365 // files going into the getdown website dir: getdown-launcher(-local).jar
2367 from getdownLauncher
2368 if (file(getdownLauncher).getName() != getdown_launcher) {
2369 rename(file(getdownLauncher).getName(), getdown_launcher)
2371 into getdownAppBaseDir
2374 // files going into the getdown website dir: ./install dir and files
2375 if (! (CHANNEL.startsWith("ARCHIVE") || CHANNEL.startsWith("DEVELOP"))) {
2378 from getdownLauncher
2379 from "${getdownAppDir}/${getdown_build_properties}"
2380 if (file(getdownLauncher).getName() != getdown_launcher) {
2381 rename(file(getdownLauncher).getName(), getdown_launcher)
2383 into getdownInstallDir
2386 // and make a copy in the getdown files dir (these are not downloaded by getdown)
2388 from getdownInstallDir
2389 into getdownFilesInstallDir
2393 // files going into the getdown files dir: getdown.txt, getdown-launcher.jar, channel-launch.jvl, build_properties
2397 from getdownLauncher
2398 from "${getdownAppBaseDir}/${getdown_build_properties}"
2399 from "${getdownAppBaseDir}/${channel_props}"
2400 if (file(getdownLauncher).getName() != getdown_launcher) {
2401 rename(file(getdownLauncher).getName(), getdown_launcher)
2403 into getdownFilesDir
2406 // and ./resource (not all downloaded by getdown)
2408 from getdownResourceDir
2409 into "${getdownFilesDir}/${getdown_resource_dir}"
2414 inputs.dir("${jalviewDir}/${package_dir}")
2416 outputs.dir(getdownAppBaseDir)
2417 outputs.dir(getdownFilesDir)
2421 // a helper task to allow getdown digest of any dir: `gradle getdownDigestDir -PDIGESTDIR=/path/to/my/random/getdown/dir
2422 task getdownDigestDir(type: JavaExec) {
2424 description "A task to run a getdown Digest on a dir with getdown.txt. Provide a DIGESTDIR property via -PDIGESTDIR=..."
2426 def digestDirPropertyName = "DIGESTDIR"
2428 classpath = files(getdownLauncher)
2429 def digestDir = findProperty(digestDirPropertyName)
2430 if (digestDir == null) {
2431 throw new GradleException("Must provide a DIGESTDIR value to produce an alternative getdown digest")
2435 main = "com.threerings.getdown.tools.Digester"
2439 task getdownDigest(type: JavaExec) {
2440 group = "distribution"
2441 description = "Digest the getdown website folder"
2442 dependsOn getdownWebsite
2444 classpath = files(getdownLauncher)
2446 main = "com.threerings.getdown.tools.Digester"
2447 args getdownAppBaseDir
2448 inputs.dir(getdownAppBaseDir)
2449 outputs.file("${getdownAppBaseDir}/digest2.txt")
2454 group = "distribution"
2455 description = "Create the minimal and full getdown app folder for installers and website and create digest file"
2456 dependsOn getdownDigest
2458 if (reportRsyncCommand) {
2459 def fromDir = getdownAppBaseDir + (getdownAppBaseDir.endsWith('/')?'':'/')
2460 def toDir = "${getdown_rsync_dest}/${getdownDir}" + (getdownDir.endsWith('/')?'':'/')
2461 println "LIKELY RSYNC COMMAND:"
2462 println "mkdir -p '$toDir'\nrsync -avh --delete '$fromDir' '$toDir'"
2463 if (RUNRSYNC == "true") {
2465 commandLine "mkdir", "-p", toDir
2468 commandLine "rsync", "-avh", "--delete", fromDir, toDir
2476 task getdownArchiveBuild() {
2477 group = "distribution"
2478 description = "Put files in the archive dir to go on the website"
2480 dependsOn getdownWebsite
2482 def v = "v${JALVIEW_VERSION_UNDERSCORES}"
2483 def vDir = "${getdownArchiveDir}/${v}"
2484 getdownFullArchiveDir = "${vDir}/getdown"
2485 getdownVersionLaunchJvl = "${vDir}/jalview-${v}.jvl"
2487 def vAltDir = "alt_${v}"
2488 def archiveImagesDir = "${jalviewDir}/${channel_properties_dir}/old/images"
2491 // cleanup old "old" dir
2492 delete getdownArchiveDir
2494 def getdownArchiveTxt = file("${getdownFullArchiveDir}/getdown.txt")
2495 getdownArchiveTxt.getParentFile().mkdirs()
2496 def getdownArchiveTextLines = []
2497 def getdownFullArchiveAppBase = "${getdownArchiveAppBase}${getdownArchiveAppBase.endsWith("/")?"":"/"}${v}/getdown/"
2501 from "${getdownAppBaseDir}/${getdownAppDistDir}"
2502 into "${getdownFullArchiveDir}/${vAltDir}"
2505 getdownTextLines.each { line ->
2506 line = line.replaceAll("^(?<s>appbase\\s*=\\s*).*", '${s}'+getdownFullArchiveAppBase)
2507 line = line.replaceAll("^(?<s>(resource|code)\\s*=\\s*)${getdownAppDistDir}/", '${s}'+vAltDir+"/")
2508 line = line.replaceAll("^(?<s>ui.background_image\\s*=\\s*).*\\.png", '${s}'+"${getdown_resource_dir}/jalview_archive_getdown_background.png")
2509 line = line.replaceAll("^(?<s>ui.instant_background_image\\s*=\\s*).*\\.png", '${s}'+"${getdown_resource_dir}/jalview_archive_getdown_background_initialising.png")
2510 line = line.replaceAll("^(?<s>ui.error_background\\s*=\\s*).*\\.png", '${s}'+"${getdown_resource_dir}/jalview_archive_getdown_background_error.png")
2511 line = line.replaceAll("^(?<s>ui.progress_image\\s*=\\s*).*\\.png", '${s}'+"${getdown_resource_dir}/jalview_archive_getdown_progress_bar.png")
2512 // remove the existing resource = resource/ or bin/ lines
2513 if (! line.matches("resource\\s*=\\s*(resource|bin)/.*")) {
2514 getdownArchiveTextLines += line
2518 // the resource dir -- add these files as resource lines in getdown.txt
2520 from "${archiveImagesDir}"
2521 into "${getdownFullArchiveDir}/${getdown_resource_dir}"
2523 getdownArchiveTextLines += "resource = ${getdown_resource_dir}/${file.getName()}"
2527 getdownArchiveTxt.write(getdownArchiveTextLines.join("\n"))
2529 def vLaunchJvl = file(getdownVersionLaunchJvl)
2530 vLaunchJvl.getParentFile().mkdirs()
2531 vLaunchJvl.write("appbase=${getdownFullArchiveAppBase}\n")
2532 def vLaunchJvlPath = vLaunchJvl.toPath().toAbsolutePath()
2533 def jvlLinkPath = file("${vDir}/jalview.jvl").toPath().toAbsolutePath()
2534 // for some reason filepath.relativize(fileInSameDirPath) gives a path to "../" which is wrong
2535 //java.nio.file.Files.createSymbolicLink(jvlLinkPath, jvlLinkPath.relativize(vLaunchJvlPath));
2536 java.nio.file.Files.createSymbolicLink(jvlLinkPath, java.nio.file.Paths.get(".",vLaunchJvl.getName()));
2538 // files going into the getdown files dir: getdown.txt, getdown-launcher.jar, channel-launch.jvl, build_properties
2540 from getdownLauncher
2541 from "${getdownAppBaseDir}/${getdownLaunchJvl}"
2542 from "${getdownAppBaseDir}/${getdown_launcher_new}"
2543 from "${getdownAppBaseDir}/${channel_props}"
2544 if (file(getdownLauncher).getName() != getdown_launcher) {
2545 rename(file(getdownLauncher).getName(), getdown_launcher)
2547 into getdownFullArchiveDir
2553 task getdownArchiveDigest(type: JavaExec) {
2554 group = "distribution"
2555 description = "Digest the getdown archive folder"
2557 dependsOn getdownArchiveBuild
2560 classpath = files(getdownLauncher)
2561 args getdownFullArchiveDir
2563 main = "com.threerings.getdown.tools.Digester"
2564 inputs.dir(getdownFullArchiveDir)
2565 outputs.file("${getdownFullArchiveDir}/digest2.txt")
2568 task getdownArchive() {
2569 group = "distribution"
2570 description = "Build the website archive dir with getdown digest"
2572 dependsOn getdownArchiveBuild
2573 dependsOn getdownArchiveDigest
2576 tasks.withType(JavaCompile) {
2577 options.encoding = 'UTF-8'
2583 delete getdownAppBaseDir
2584 delete getdownFilesDir
2585 delete getdownArchiveDir
2591 if (file(install4jHomeDir).exists()) {
2593 } else if (file(System.getProperty("user.home")+"/buildtools/install4j").exists()) {
2594 install4jHomeDir = System.getProperty("user.home")+"/buildtools/install4j"
2595 } else if (file("/Applications/install4j.app/Contents/Resources/app").exists()) {
2596 install4jHomeDir = "/Applications/install4j.app/Contents/Resources/app"
2598 installDir(file(install4jHomeDir))
2600 mediaTypes = Arrays.asList(install4j_media_types.split(","))
2604 task copyInstall4jTemplate {
2605 def install4jTemplateFile = file("${install4jDir}/${install4j_template}")
2606 def install4jFileAssociationsFile = file("${install4jDir}/${install4j_installer_file_associations}")
2607 inputs.file(install4jTemplateFile)
2608 inputs.file(install4jFileAssociationsFile)
2609 inputs.property("CHANNEL", { CHANNEL })
2610 outputs.file(install4jConfFile)
2613 def install4jConfigXml = new XmlParser().parse(install4jTemplateFile)
2615 // turn off code signing if no OSX_KEYPASS
2616 if (OSX_KEYPASS == "") {
2617 install4jConfigXml.'**'.codeSigning.each { codeSigning ->
2618 codeSigning.'@macEnabled' = "false"
2620 install4jConfigXml.'**'.windows.each { windows ->
2621 windows.'@runPostProcessor' = "false"
2625 // disable install screen for OSX dmg (for 2.11.2.0)
2626 install4jConfigXml.'**'.macosArchive.each { macosArchive ->
2627 macosArchive.attributes().remove('executeSetupApp')
2628 macosArchive.attributes().remove('setupAppId')
2631 // turn off checksum creation for LOCAL channel
2632 def e = install4jConfigXml.application[0]
2633 e.'@createChecksums' = string(install4jCheckSums)
2635 // put file association actions where placeholder action is
2636 def install4jFileAssociationsText = install4jFileAssociationsFile.text
2637 def fileAssociationActions = new XmlParser().parseText("<actions>${install4jFileAssociationsText}</actions>")
2638 install4jConfigXml.'**'.action.any { a -> // .any{} stops after the first one that returns true
2639 if (a.'@name' == 'EXTENSIONS_REPLACED_BY_GRADLE') {
2640 def parent = a.parent()
2642 fileAssociationActions.each { faa ->
2645 // don't need to continue in .any loop once replacements have been made
2650 // use Windows Program Group with Examples folder for RELEASE, and Program Group without Examples for everything else
2651 // NB we're deleting the /other/ one!
2652 // Also remove the examples subdir from non-release versions
2653 def customizedIdToDelete = "PROGRAM_GROUP_RELEASE"
2654 // 2.11.1.0 NOT releasing with the Examples folder in the Program Group
2655 if (false && CHANNEL=="RELEASE") { // remove 'false && ' to include Examples folder in RELEASE channel
2656 customizedIdToDelete = "PROGRAM_GROUP_NON_RELEASE"
2658 // remove the examples subdir from Full File Set
2659 def files = install4jConfigXml.files[0]
2660 def fileset = files.filesets.fileset.find { fs -> fs.'@customizedId' == "FULL_FILE_SET" }
2661 def root = files.roots.root.find { r -> r.'@fileset' == fileset.'@id' }
2662 def mountPoint = files.mountPoints.mountPoint.find { mp -> mp.'@root' == root.'@id' }
2663 def dirEntry = files.entries.dirEntry.find { de -> de.'@mountPoint' == mountPoint.'@id' && de.'@subDirectory' == "examples" }
2664 dirEntry.parent().remove(dirEntry)
2666 install4jConfigXml.'**'.action.any { a ->
2667 if (a.'@customizedId' == customizedIdToDelete) {
2668 def parent = a.parent()
2674 // write install4j file
2675 install4jConfFile.text = XmlUtil.serialize(install4jConfigXml)
2682 delete install4jConfFile
2686 task cleanInstallersDataFiles {
2687 def installersOutputTxt = file("${jalviewDir}/${install4jBuildDir}/output.txt")
2688 def installersSha256 = file("${jalviewDir}/${install4jBuildDir}/sha256sums")
2689 def hugoDataJsonFile = file("${jalviewDir}/${install4jBuildDir}/installers-${JALVIEW_VERSION_UNDERSCORES}.json")
2691 delete installersOutputTxt
2692 delete installersSha256
2693 delete hugoDataJsonFile
2697 task install4jDMGBackgroundImageCopy {
2698 inputs.file "${install4jDMGBackgroundImageDir}/${install4jDMGBackgroundImageFile}"
2699 outputs.dir "${install4jDMGBackgroundImageBuildDir}"
2702 from(install4jDMGBackgroundImageDir) {
2703 include(install4jDMGBackgroundImageFile)
2705 into install4jDMGBackgroundImageBuildDir
2710 task install4jDMGBackgroundImageProcess {
2711 dependsOn install4jDMGBackgroundImageCopy
2714 if (backgroundImageText) {
2715 if (convertBinary == null) {
2716 throw new StopExecutionException("No ImageMagick convert binary installed at '${convertBinaryExpectedLocation}'")
2718 if (!project.hasProperty("install4j_background_image_text_suffix_cmd")) {
2719 throw new StopExecutionException("No property 'install4j_background_image_text_suffix_cmd' defined. See channel_gradle.properties for channel ${CHANNEL}")
2721 fileTree(dir: install4jDMGBackgroundImageBuildDir, include: "*.png").getFiles().each { file ->
2723 executable convertBinary
2726 '-font', install4j_background_image_text_font,
2727 '-fill', install4j_background_image_text_colour,
2728 '-draw', sprintf(install4j_background_image_text_suffix_cmd, channelSuffix),
2729 '-draw', sprintf(install4j_background_image_text_commit_cmd, "git-commit: ${gitHash}"),
2730 '-draw', sprintf(install4j_background_image_text_date_cmd, getDate("yyyy-MM-dd HH:mm:ss")),
2739 task install4jDMGBackgroundImage {
2740 dependsOn install4jDMGBackgroundImageProcess
2743 task installerFiles(type: com.install4j.gradle.Install4jTask) {
2744 group = "distribution"
2745 description = "Create the install4j installers"
2747 dependsOn copyInstall4jTemplate
2748 dependsOn cleanInstallersDataFiles
2749 dependsOn install4jDMGBackgroundImage
2751 projectFile = install4jConfFile
2753 // create an md5 for the input files to use as version for install4j conf file
2754 def digest = MessageDigest.getInstance("MD5")
2756 (file("${install4jDir}/${install4j_template}").text +
2757 file("${install4jDir}/${install4j_info_plist_file_associations}").text +
2758 file("${install4jDir}/${install4j_installer_file_associations}").text).bytes)
2759 def filesMd5 = new BigInteger(1, digest.digest()).toString(16)
2760 if (filesMd5.length() >= 8) {
2761 filesMd5 = filesMd5.substring(0,8)
2763 def install4jTemplateVersion = "${JALVIEW_VERSION}_F${filesMd5}_C${gitHash}"
2766 'JALVIEW_NAME': jalview_name,
2767 'JALVIEW_APPLICATION_NAME': applicationName,
2768 'JALVIEW_DIR': "../..",
2769 'OSX_KEYSTORE': OSX_KEYSTORE,
2770 'OSX_APPLEID': OSX_APPLEID,
2771 'OSX_ALTOOLPASS': OSX_ALTOOLPASS,
2772 'JSIGN_SH': JSIGN_SH,
2773 'JRE_DIR': getdown_app_dir_java,
2774 'INSTALLER_TEMPLATE_VERSION': install4jTemplateVersion,
2775 'JALVIEW_VERSION': JALVIEW_VERSION,
2776 'JAVA_MIN_VERSION': JAVA_MIN_VERSION,
2777 'JAVA_MAX_VERSION': JAVA_MAX_VERSION,
2778 'JAVA_VERSION': JAVA_VERSION,
2779 'JAVA_INTEGER_VERSION': JAVA_INTEGER_VERSION,
2780 'VERSION': JALVIEW_VERSION,
2781 'COPYRIGHT_MESSAGE': install4j_copyright_message,
2782 'BUNDLE_ID': install4jBundleId,
2783 'INTERNAL_ID': install4jInternalId,
2784 'WINDOWS_APPLICATION_ID': install4jWinApplicationId,
2785 'MACOS_DMG_DS_STORE': install4jDMGDSStore,
2786 'MACOS_DMG_BG_IMAGE': "${install4jDMGBackgroundImageBuildDir}/${install4jDMGBackgroundImageFile}",
2787 'WRAPPER_LINK': getdownWrapperLink,
2788 'BASH_WRAPPER_SCRIPT': getdown_bash_wrapper_script,
2789 'POWERSHELL_WRAPPER_SCRIPT': getdown_powershell_wrapper_script,
2790 'BATCH_WRAPPER_SCRIPT': getdown_batch_wrapper_script,
2791 'WRAPPER_SCRIPT_BIN_DIR': getdown_wrapper_script_dir,
2792 'INSTALLER_NAME': install4jInstallerName,
2793 'INSTALL4J_UTILS_DIR': install4j_utils_dir,
2794 'GETDOWN_CHANNEL_DIR': getdownChannelDir,
2795 'GETDOWN_FILES_DIR': getdown_files_dir,
2796 'GETDOWN_RESOURCE_DIR': getdown_resource_dir,
2797 'GETDOWN_DIST_DIR': getdownAppDistDir,
2798 'GETDOWN_ALT_DIR': getdown_app_dir_alt,
2799 'GETDOWN_INSTALL_DIR': getdown_install_dir,
2800 'INFO_PLIST_FILE_ASSOCIATIONS_FILE': install4j_info_plist_file_associations,
2801 'BUILD_DIR': install4jBuildDir,
2802 'APPLICATION_CATEGORIES': install4j_application_categories,
2803 'APPLICATION_FOLDER': install4jApplicationFolder,
2804 'UNIX_APPLICATION_FOLDER': install4jUnixApplicationFolder,
2805 'EXECUTABLE_NAME': install4jExecutableName,
2806 'EXTRA_SCHEME': install4jExtraScheme,
2807 'MAC_ICONS_FILE': install4jMacIconsFile,
2808 'WINDOWS_ICONS_FILE': install4jWindowsIconsFile,
2809 'PNG_ICON_FILE': install4jPngIconFile,
2810 'BACKGROUND': install4jBackground,
2815 'windows': 'WINDOWS',
2819 // these are the bundled OS/architecture VMs needed by install4j
2822 [ "mac", "aarch64" ],
2823 [ "windows", "x64" ],
2825 [ "linux", "aarch64" ]
2827 osArch.forEach { os, arch ->
2828 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)
2829 // N.B. For some reason install4j requires the below filename to have underscores and not hyphens
2830 // otherwise running `gradle installers` generates a non-useful error:
2831 // `install4j: compilation failed. Reason: java.lang.NumberFormatException: For input string: "windows"`
2832 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)
2835 //println("INSTALL4J VARIABLES:")
2836 //variables.each{k,v->println("${k}=${v}")}
2838 destination = "${jalviewDir}/${install4jBuildDir}"
2839 buildSelected = true
2841 if (install4j_faster.equals("true") || CHANNEL.startsWith("LOCAL")) {
2843 disableSigning = true
2844 disableNotarization = true
2848 macKeystorePassword = OSX_KEYPASS
2851 if (OSX_ALTOOLPASS) {
2852 appleIdPassword = OSX_ALTOOLPASS
2853 disableNotarization = false
2855 disableNotarization = true
2859 println("Using projectFile "+projectFile)
2860 if (!disableNotarization) { println("Will notarize OSX App DMG") }
2864 inputs.dir(getdownAppBaseDir)
2865 inputs.file(install4jConfFile)
2866 inputs.file("${install4jDir}/${install4j_info_plist_file_associations}")
2867 outputs.dir("${jalviewDir}/${install4j_build_dir}/${JAVA_VERSION}")
2870 def getDataHash(File myFile) {
2871 HashCode hash = Files.asByteSource(myFile).hash(Hashing.sha256())
2872 return myFile.exists()
2874 "file" : myFile.getName(),
2875 "filesize" : myFile.length(),
2876 "sha256" : hash.toString()
2881 def writeDataJsonFile(File installersOutputTxt, File installersSha256, File dataJsonFile) {
2883 "channel" : getdownChannelName,
2884 "date" : getDate("yyyy-MM-dd HH:mm:ss"),
2885 "git-commit" : "${gitHash} [${gitBranch}]",
2886 "version" : JALVIEW_VERSION
2888 // install4j installer files
2889 if (installersOutputTxt.exists()) {
2891 installersOutputTxt.readLines().each { def line ->
2892 if (line.startsWith("#")) {
2895 line.replaceAll("\n","")
2896 def vals = line.split("\t")
2897 def filename = vals[3]
2898 def filesize = file(filename).length()
2899 filename = filename.replaceAll(/^.*\//, "")
2900 hash[vals[0]] = [ "id" : vals[0], "os" : vals[1], "name" : vals[2], "file" : filename, "filesize" : filesize ]
2901 idHash."${filename}" = vals[0]
2903 if (install4jCheckSums && installersSha256.exists()) {
2904 installersSha256.readLines().each { def line ->
2905 if (line.startsWith("#")) {
2908 line.replaceAll("\n","")
2909 def vals = line.split(/\s+\*?/)
2910 def filename = vals[1]
2911 def innerHash = (hash.(idHash."${filename}"))."sha256" = vals[0]
2917 "JAR": shadowJar.archiveFile, // executable JAR
2918 "JVL": getdownVersionLaunchJvl, // version JVL
2919 "SOURCE": sourceDist.archiveFile // source TGZ
2920 ].each { key, value ->
2921 def file = file(value)
2922 if (file.exists()) {
2923 def fileHash = getDataHash(file)
2924 if (fileHash != null) {
2925 hash."${key}" = fileHash;
2929 return dataJsonFile.write(new JsonBuilder(hash).toPrettyString())
2932 task staticMakeInstallersJsonFile {
2934 def output = findProperty("i4j_output")
2935 def sha256 = findProperty("i4j_sha256")
2936 def json = findProperty("i4j_json")
2937 if (output == null || sha256 == null || json == null) {
2938 throw new GradleException("Must provide paths to all of output.txt, sha256sums, and output.json with '-Pi4j_output=... -Pi4j_sha256=... -Pi4j_json=...")
2940 writeDataJsonFile(file(output), file(sha256), file(json))
2945 dependsOn installerFiles
2951 eclipse().configFile(eclipse_codestyle_file)
2955 task createSourceReleaseProperties(type: WriteProperties) {
2956 group = "distribution"
2957 description = "Create the source RELEASE properties file"
2959 def sourceTarBuildDir = "${buildDir}/sourceTar"
2960 def sourceReleasePropertiesFile = "${sourceTarBuildDir}/RELEASE"
2961 outputFile (sourceReleasePropertiesFile)
2964 releaseProps.each{ key, val -> property key, val }
2965 property "git.branch", gitBranch
2966 property "git.hash", gitHash
2969 outputs.file(outputFile)
2972 task sourceDist(type: Tar) {
2973 group "distribution"
2974 description "Create a source .tar.gz file for distribution"
2976 dependsOn createBuildProperties
2977 dependsOn convertMdFiles
2978 dependsOn eclipseAllPreferences
2979 dependsOn createSourceReleaseProperties
2982 def outputFileName = "${project.name}_${JALVIEW_VERSION_UNDERSCORES}.tar.gz"
2983 archiveFileName = outputFileName
2985 compression Compression.GZIP
3000 "**/*.class","$j11modDir/**/*.jar","appletlib","**/*locales",
3002 "utils/InstallAnywhere",
3017 "gradle.properties",
3029 ".settings/org.eclipse.buildship.core.prefs",
3030 ".settings/org.eclipse.jdt.core.prefs"
3034 exclude (EXCLUDE_FILES)
3035 include (PROCESS_FILES)
3036 filter(ReplaceTokens,
3040 'Version-Rel': JALVIEW_VERSION,
3041 'Year-Rel': getDate("yyyy")
3046 exclude (EXCLUDE_FILES)
3047 exclude (PROCESS_FILES)
3048 exclude ("appletlib")
3049 exclude ("**/*locales")
3050 exclude ("*locales/**")
3051 exclude ("utils/InstallAnywhere")
3053 exclude (getdown_files_dir)
3054 // getdown_website_dir and getdown_archive_dir moved to build/website/docroot/getdown
3055 //exclude (getdown_website_dir)
3056 //exclude (getdown_archive_dir)
3058 // exluding these as not using jars as modules yet
3059 exclude ("${j11modDir}/**/*.jar")
3062 include(INCLUDE_FILES)
3064 // from (jalviewDir) {
3065 // // explicit includes for stuff that seemed to not get included
3066 // include(fileTree("test/**/*."))
3067 // exclude(EXCLUDE_FILES)
3068 // exclude(PROCESS_FILES)
3071 from(file(buildProperties).getParent()) {
3072 include(file(buildProperties).getName())
3073 rename(file(buildProperties).getName(), "build_properties")
3075 line.replaceAll("^INSTALLATION=.*\$","INSTALLATION=Source Release"+" git-commit\\\\:"+gitHash+" ["+gitBranch+"]")
3079 def sourceTarBuildDir = "${buildDir}/sourceTar"
3080 from(sourceTarBuildDir) {
3081 // this includes the appended RELEASE properties file
3085 task dataInstallersJson {
3087 description "Create the installers-VERSION.json data file for installer files created"
3089 mustRunAfter installers
3090 mustRunAfter shadowJar
3091 mustRunAfter sourceDist
3092 mustRunAfter getdownArchive
3094 def installersOutputTxt = file("${jalviewDir}/${install4jBuildDir}/output.txt")
3095 def installersSha256 = file("${jalviewDir}/${install4jBuildDir}/sha256sums")
3097 if (installersOutputTxt.exists()) {
3098 inputs.file(installersOutputTxt)
3100 if (install4jCheckSums && installersSha256.exists()) {
3101 inputs.file(installersSha256)
3104 shadowJar.archiveFile, // executable JAR
3105 getdownVersionLaunchJvl, // version JVL
3106 sourceDist.archiveFile // source TGZ
3107 ].each { fileName ->
3108 if (file(fileName).exists()) {
3109 inputs.file(fileName)
3113 outputs.file(hugoDataJsonFile)
3116 writeDataJsonFile(installersOutputTxt, installersSha256, hugoDataJsonFile)
3122 description "Copies all help pages to build dir. Runs ant task 'pubhtmlhelp'."
3125 dependsOn pubhtmlhelp
3127 inputs.dir("${helpBuildDir}/${help_dir}")
3128 outputs.dir("${buildDir}/distributions/${help_dir}")
3132 task j2sSetHeadlessBuild {
3139 task jalviewjsEnableAltFileProperty(type: WriteProperties) {
3141 description "Enable the alternative J2S Config file for headless build"
3143 outputFile = jalviewjsJ2sSettingsFileName
3144 def j2sPropsFile = file(jalviewjsJ2sSettingsFileName)
3145 def j2sProps = new Properties()
3146 if (j2sPropsFile.exists()) {
3148 def j2sPropsFileFIS = new FileInputStream(j2sPropsFile)
3149 j2sProps.load(j2sPropsFileFIS)
3150 j2sPropsFileFIS.close()
3152 j2sProps.each { prop, val ->
3155 } catch (Exception e) {
3156 println("Exception reading ${jalviewjsJ2sSettingsFileName}")
3160 if (! j2sProps.stringPropertyNames().contains(jalviewjs_j2s_alt_file_property_config)) {
3161 property(jalviewjs_j2s_alt_file_property_config, jalviewjs_j2s_alt_file_property)
3166 task jalviewjsSetEclipseWorkspace {
3167 def propKey = "jalviewjs_eclipse_workspace"
3169 if (project.hasProperty(propKey)) {
3170 propVal = project.getProperty(propKey)
3171 if (propVal.startsWith("~/")) {
3172 propVal = System.getProperty("user.home") + propVal.substring(1)
3175 def propsFileName = "${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_eclipse_workspace_location_file}"
3176 def propsFile = file(propsFileName)
3177 def eclipseWsDir = propVal
3178 def props = new Properties()
3180 def writeProps = true
3181 if (( eclipseWsDir == null || !file(eclipseWsDir).exists() ) && propsFile.exists()) {
3182 def ins = new FileInputStream(propsFileName)
3185 if (props.getProperty(propKey, null) != null) {
3186 eclipseWsDir = props.getProperty(propKey)
3191 if (eclipseWsDir == null || !file(eclipseWsDir).exists()) {
3192 def tempDir = File.createTempDir()
3193 eclipseWsDir = tempDir.getAbsolutePath()
3196 eclipseWorkspace = file(eclipseWsDir)
3199 // do not run a headless transpile when we claim to be in Eclipse
3201 println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3202 throw new StopExecutionException("Not running headless transpile whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
3204 println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3208 props.setProperty(propKey, eclipseWsDir)
3209 propsFile.parentFile.mkdirs()
3210 def bytes = new ByteArrayOutputStream()
3211 props.store(bytes, null)
3212 def propertiesString = bytes.toString()
3213 propsFile.text = propertiesString
3219 println("ECLIPSE WORKSPACE: "+eclipseWorkspace.getPath())
3222 //inputs.property(propKey, eclipseWsDir) // eclipseWsDir only gets set once this task runs, so will be out-of-date
3223 outputs.file(propsFileName)
3224 outputs.upToDateWhen { eclipseWorkspace.exists() && propsFile.exists() }
3228 task jalviewjsEclipsePaths {
3231 def eclipseRoot = jalviewjs_eclipse_root
3232 if (eclipseRoot.startsWith("~/")) {
3233 eclipseRoot = System.getProperty("user.home") + eclipseRoot.substring(1)
3235 if (OperatingSystem.current().isMacOsX()) {
3236 eclipseRoot += "/Eclipse.app"
3237 eclipseBinary = "${eclipseRoot}/Contents/MacOS/eclipse"
3238 eclipseProduct = "${eclipseRoot}/Contents/Eclipse/.eclipseproduct"
3239 } else if (OperatingSystem.current().isWindows()) { // check these paths!!
3240 if (file("${eclipseRoot}/eclipse").isDirectory() && file("${eclipseRoot}/eclipse/.eclipseproduct").exists()) {
3241 eclipseRoot += "/eclipse"
3243 eclipseBinary = "${eclipseRoot}/eclipse.exe"
3244 eclipseProduct = "${eclipseRoot}/.eclipseproduct"
3245 } else { // linux or unix
3246 if (file("${eclipseRoot}/eclipse").isDirectory() && file("${eclipseRoot}/eclipse/.eclipseproduct").exists()) {
3247 eclipseRoot += "/eclipse"
3248 println("eclipseDir exists")
3250 eclipseBinary = "${eclipseRoot}/eclipse"
3251 eclipseProduct = "${eclipseRoot}/.eclipseproduct"
3254 eclipseVersion = "4.13" // default
3255 def assumedVersion = true
3256 if (file(eclipseProduct).exists()) {
3257 def fis = new FileInputStream(eclipseProduct)
3258 def props = new Properties()
3260 eclipseVersion = props.getProperty("version")
3262 assumedVersion = false
3265 def propKey = "eclipse_debug"
3266 eclipseDebug = (project.hasProperty(propKey) && project.getProperty(propKey).equals("true"))
3269 // do not run a headless transpile when we claim to be in Eclipse
3271 println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3272 throw new StopExecutionException("Not running headless transpile whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
3274 println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3277 if (!assumedVersion) {
3278 println("ECLIPSE VERSION=${eclipseVersion}")
3284 task printProperties {
3286 description "Output to console all System.properties"
3288 System.properties.each { key, val -> System.out.println("Property: ${key}=${val}") }
3294 dependsOn eclipseProject
3295 dependsOn eclipseClasspath
3296 dependsOn eclipseJdt
3300 // this version (type: Copy) will delete anything in the eclipse dropins folder that isn't in fromDropinsDir
3301 task jalviewjsEclipseCopyDropins(type: Copy) {
3302 dependsOn jalviewjsEclipsePaths
3304 def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjs_eclipse_dropins_dir}", include: "*.jar")
3305 inputFiles += file("${jalviewDir}/${jalviewjsJ2sPlugin}")
3306 def outputDir = "${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_eclipse_tmp_dropins_dir}"
3313 // this eclipse -clean doesn't actually work
3314 task jalviewjsCleanEclipse(type: Exec) {
3315 dependsOn eclipseSetup
3316 dependsOn jalviewjsEclipsePaths
3317 dependsOn jalviewjsEclipseCopyDropins
3319 executable(eclipseBinary)
3320 args(["-nosplash", "--launcher.suppressErrors", "-data", eclipseWorkspace.getPath(), "-clean", "-console", "-consoleLog"])
3326 def inputString = """exit
3329 def inputByteStream = new ByteArrayInputStream(inputString.getBytes())
3330 standardInput = inputByteStream
3333 /* not really working yet
3334 jalviewjsEclipseCopyDropins.finalizedBy jalviewjsCleanEclipse
3338 task jalviewjsTransferUnzipSwingJs {
3339 def file_zip = "${jalviewDir}/${jalviewjs_swingjs_zip}"
3343 from zipTree(file_zip)
3344 into "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}"
3348 inputs.file file_zip
3349 outputs.dir "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}"
3353 task jalviewjsTransferUnzipLib {
3354 def zipFiles = fileTree(dir: "${jalviewDir}/${jalviewjs_libjs_dir}", include: "*.zip")
3357 zipFiles.each { file_zip ->
3359 from zipTree(file_zip)
3360 into "${jalviewDir}/${jalviewjsTransferSiteLibDir}"
3365 inputs.files zipFiles
3366 outputs.dir "${jalviewDir}/${jalviewjsTransferSiteLibDir}"
3370 task jalviewjsTransferUnzipAllLibs {
3371 dependsOn jalviewjsTransferUnzipSwingJs
3372 dependsOn jalviewjsTransferUnzipLib
3376 task jalviewjsCreateJ2sSettings(type: WriteProperties) {
3378 description "Create the alternative j2s file from the j2s.* properties"
3380 jalviewjsJ2sProps = project.properties.findAll { it.key.startsWith("j2s.") }.sort { it.key }
3381 def siteDirProperty = "j2s.site.directory"
3382 def setSiteDir = false
3383 jalviewjsJ2sProps.each { prop, val ->
3385 if (prop == siteDirProperty) {
3386 if (!(val.startsWith('/') || val.startsWith("file://") )) {
3387 val = "${jalviewDir}/${jalviewjsTransferSiteJsDir}/${val}"
3393 if (!setSiteDir) { // default site location, don't override specifically set property
3394 property(siteDirProperty,"${jalviewDirRelativePath}/${jalviewjsTransferSiteJsDir}")
3397 outputFile = jalviewjsJ2sAltSettingsFileName
3400 inputs.properties(jalviewjsJ2sProps)
3401 outputs.file(jalviewjsJ2sAltSettingsFileName)
3406 task jalviewjsEclipseSetup {
3407 dependsOn jalviewjsEclipseCopyDropins
3408 dependsOn jalviewjsSetEclipseWorkspace
3409 dependsOn jalviewjsCreateJ2sSettings
3413 task jalviewjsSyncAllLibs (type: Sync) {
3414 dependsOn jalviewjsTransferUnzipAllLibs
3415 def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjsTransferSiteLibDir}")
3416 inputFiles += fileTree(dir: "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}")
3417 def outputDir = "${jalviewDir}/${jalviewjsSiteDir}"
3421 def outputFiles = []
3422 rename { filename ->
3423 outputFiles += "${outputDir}/${filename}"
3430 // should this be exclude really ?
3431 duplicatesStrategy "INCLUDE"
3433 outputs.files outputFiles
3434 inputs.files inputFiles
3438 task jalviewjsSyncResources (type: Sync) {
3439 dependsOn buildResources
3441 def inputFiles = fileTree(dir: resourcesBuildDir)
3442 def outputDir = "${jalviewDir}/${jalviewjsSiteDir}/${jalviewjs_j2s_subdir}"
3446 def outputFiles = []
3447 rename { filename ->
3448 outputFiles += "${outputDir}/${filename}"
3454 outputs.files outputFiles
3455 inputs.files inputFiles
3459 task jalviewjsSyncSiteResources (type: Sync) {
3460 def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjs_site_resource_dir}")
3461 def outputDir = "${jalviewDir}/${jalviewjsSiteDir}"
3465 def outputFiles = []
3466 rename { filename ->
3467 outputFiles += "${outputDir}/${filename}"
3473 outputs.files outputFiles
3474 inputs.files inputFiles
3478 task jalviewjsSyncBuildProperties (type: Sync) {
3479 dependsOn createBuildProperties
3480 def inputFiles = [file(buildProperties)]
3481 def outputDir = "${jalviewDir}/${jalviewjsSiteDir}/${jalviewjs_j2s_subdir}"
3485 def outputFiles = []
3486 rename { filename ->
3487 outputFiles += "${outputDir}/${filename}"
3493 outputs.files outputFiles
3494 inputs.files inputFiles
3498 task jalviewjsProjectImport(type: Exec) {
3499 dependsOn eclipseSetup
3500 dependsOn jalviewjsEclipsePaths
3501 dependsOn jalviewjsEclipseSetup
3504 // do not run a headless import when we claim to be in Eclipse
3506 println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3507 throw new StopExecutionException("Not running headless import whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
3509 println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3513 //def projdir = eclipseWorkspace.getPath()+"/.metadata/.plugins/org.eclipse.core.resources/.projects/jalview/org.eclipse.jdt.core"
3514 def projdir = eclipseWorkspace.getPath()+"/.metadata/.plugins/org.eclipse.core.resources/.projects/jalview"
3515 executable(eclipseBinary)
3516 args(["-nosplash", "--launcher.suppressErrors", "-application", "com.seeq.eclipse.importprojects.headlessimport", "-data", eclipseWorkspace.getPath(), "-import", jalviewDirAbsolutePath])
3520 args += [ "--launcher.appendVmargs", "-vmargs", "-Dorg.eclipse.equinox.p2.reconciler.dropins.directory=${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_eclipse_tmp_dropins_dir}" ]
3522 args += [ "-D${j2sHeadlessBuildProperty}=true" ]
3523 args += [ "-D${jalviewjs_j2s_alt_file_property}=${jalviewjsJ2sAltSettingsFileName}" ]
3526 inputs.file("${jalviewDir}/.project")
3527 outputs.upToDateWhen {
3528 file(projdir).exists()
3533 task jalviewjsTranspile(type: Exec) {
3534 dependsOn jalviewjsEclipseSetup
3535 dependsOn jalviewjsProjectImport
3536 dependsOn jalviewjsEclipsePaths
3538 dependsOn jalviewjsEnableAltFileProperty
3542 // do not run a headless transpile when we claim to be in Eclipse
3544 println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3545 throw new StopExecutionException("Not running headless transpile whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
3547 println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3551 executable(eclipseBinary)
3552 args(["-nosplash", "--launcher.suppressErrors", "-application", "org.eclipse.jdt.apt.core.aptBuild", "-data", eclipseWorkspace, "-${jalviewjs_eclipse_build_arg}", eclipse_project_name ])
3556 args += [ "--launcher.appendVmargs", "-vmargs", "-Dorg.eclipse.equinox.p2.reconciler.dropins.directory=${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_eclipse_tmp_dropins_dir}" ]
3558 args += [ "-D${j2sHeadlessBuildProperty}=true" ]
3559 args += [ "-D${jalviewjs_j2s_alt_file_property}=${jalviewjsJ2sAltSettingsFileName}" ]
3565 stdout = new ByteArrayOutputStream()
3566 stderr = new ByteArrayOutputStream()
3568 def logOutFileName = "${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}"
3569 def logOutFile = file(logOutFileName)
3570 logOutFile.createNewFile()
3571 logOutFile.text = """ROOT: ${jalviewjs_eclipse_root}
3572 BINARY: ${eclipseBinary}
3573 VERSION: ${eclipseVersion}
3574 WORKSPACE: ${eclipseWorkspace}
3575 DEBUG: ${eclipseDebug}
3578 def logOutFOS = new FileOutputStream(logOutFile, true) // true == append
3579 // combine stdout and stderr
3580 def logErrFOS = logOutFOS
3582 if (jalviewjs_j2s_to_console.equals("true")) {
3583 standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
3584 new org.apache.tools.ant.util.TeeOutputStream(
3588 errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
3589 new org.apache.tools.ant.util.TeeOutputStream(
3594 standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
3597 errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
3604 if (stdout.toString().contains("Error processing ")) {
3605 // j2s did not complete transpile
3606 //throw new TaskExecutionException("Error during transpilation:\n${stderr}\nSee eclipse transpile log file '${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}'")
3607 if (jalviewjs_ignore_transpile_errors.equals("true")) {
3608 println("IGNORING TRANSPILE ERRORS")
3609 println("See eclipse transpile log file '${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}'")
3611 throw new GradleException("Error during transpilation:\n${stderr}\nSee eclipse transpile log file '${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}'")
3616 inputs.dir("${jalviewDir}/${sourceDir}")
3617 outputs.dir("${jalviewDir}/${jalviewjsTransferSiteJsDir}")
3618 outputs.upToDateWhen( { file("${jalviewDir}/${jalviewjsTransferSiteJsDir}${jalviewjs_server_resource}").exists() } )
3622 def jalviewjsCallCore(String name, FileCollection list, String prefixFile, String suffixFile, String jsfile, String zjsfile, File logOutFile, Boolean logOutConsole) {
3624 def stdout = new ByteArrayOutputStream()
3625 def stderr = new ByteArrayOutputStream()
3627 def coreFile = file(jsfile)
3629 msg = "Creating core for ${name}...\nGenerating ${jsfile}"
3631 logOutFile.createNewFile()
3632 logOutFile.append(msg+"\n")
3634 def coreTop = file(prefixFile)
3635 def coreBottom = file(suffixFile)
3636 coreFile.getParentFile().mkdirs()
3637 coreFile.createNewFile()
3638 coreFile.write( coreTop.getText("UTF-8") )
3642 def t = f.getText("UTF-8")
3643 t.replaceAll("Clazz\\.([^_])","Clazz_${1}")
3644 coreFile.append( t )
3646 msg = "...file '"+f.getPath()+"' does not exist, skipping"
3648 logOutFile.append(msg+"\n")
3651 coreFile.append( coreBottom.getText("UTF-8") )
3653 msg = "Generating ${zjsfile}"
3655 logOutFile.append(msg+"\n")
3656 def logOutFOS = new FileOutputStream(logOutFile, true) // true == append
3657 def logErrFOS = logOutFOS
3660 classpath = files(["${jalviewDir}/${jalviewjs_closure_compiler}"])
3661 main = "com.google.javascript.jscomp.CommandLineRunner"
3662 jvmArgs = [ "-Dfile.encoding=UTF-8" ]
3663 args = [ "--compilation_level", "SIMPLE_OPTIMIZATIONS", "--warning_level", "QUIET", "--charset", "UTF-8", "--js", jsfile, "--js_output_file", zjsfile ]
3666 msg = "\nRunning '"+commandLine.join(' ')+"'\n"
3668 logOutFile.append(msg+"\n")
3670 if (logOutConsole) {
3671 standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
3672 new org.apache.tools.ant.util.TeeOutputStream(
3676 errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
3677 new org.apache.tools.ant.util.TeeOutputStream(
3682 standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
3685 errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
3692 logOutFile.append(msg+"\n")
3696 task jalviewjsBuildAllCores {
3698 description "Build the core js lib closures listed in the classlists dir"
3699 dependsOn jalviewjsTranspile
3700 dependsOn jalviewjsTransferUnzipSwingJs
3702 def j2sDir = "${jalviewDir}/${jalviewjsTransferSiteJsDir}/${jalviewjs_j2s_subdir}"
3703 def swingJ2sDir = "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}/${jalviewjs_j2s_subdir}"
3704 def libJ2sDir = "${jalviewDir}/${jalviewjsTransferSiteLibDir}/${jalviewjs_j2s_subdir}"
3705 def jsDir = "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}/${jalviewjs_js_subdir}"
3706 def outputDir = "${jalviewDir}/${jalviewjsTransferSiteCoreDir}/${jalviewjs_j2s_subdir}/core"
3707 def prefixFile = "${jsDir}/core/coretop2.js"
3708 def suffixFile = "${jsDir}/core/corebottom2.js"
3710 inputs.file prefixFile
3711 inputs.file suffixFile
3713 def classlistFiles = []
3714 // add the classlists found int the jalviewjs_classlists_dir
3715 fileTree(dir: "${jalviewDir}/${jalviewjs_classlists_dir}", include: "*.txt").each {
3717 def name = file.getName() - ".txt"
3724 // _jmol and _jalview cores. Add any other peculiar classlist.txt files here
3725 //classlistFiles += [ 'file': file("${jalviewDir}/${jalviewjs_classlist_jmol}"), 'name': "_jvjmol" ]
3726 classlistFiles += [ 'file': file("${jalviewDir}/${jalviewjs_classlist_jalview}"), 'name': jalviewjsJalviewCoreName ]
3728 jalviewjsCoreClasslists = []
3730 classlistFiles.each {
3733 def file = hash['file']
3734 if (! file.exists()) {
3735 //println("...classlist file '"+file.getPath()+"' does not exist, skipping")
3736 return false // this is a "continue" in groovy .each closure
3738 def name = hash['name']
3740 name = file.getName() - ".txt"
3748 def list = fileTree(dir: j2sDir, includes: filelist)
3750 def jsfile = "${outputDir}/core${name}.js"
3751 def zjsfile = "${outputDir}/core${name}.z.js"
3753 jalviewjsCoreClasslists += [
3762 outputs.file(jsfile)
3763 outputs.file(zjsfile)
3766 // _stevesoft core. add any cores without a classlist here (and the inputs and outputs)
3767 def stevesoftClasslistName = "_stevesoft"
3768 def stevesoftClasslist = [
3769 'jsfile': "${outputDir}/core${stevesoftClasslistName}.js",
3770 'zjsfile': "${outputDir}/core${stevesoftClasslistName}.z.js",
3771 'list': fileTree(dir: j2sDir, include: "com/stevesoft/pat/**/*.js"),
3772 'name': stevesoftClasslistName
3774 jalviewjsCoreClasslists += stevesoftClasslist
3775 inputs.files(stevesoftClasslist['list'])
3776 outputs.file(stevesoftClasslist['jsfile'])
3777 outputs.file(stevesoftClasslist['zjsfile'])
3780 def allClasslistName = "_all"
3781 def allJsFiles = fileTree(dir: j2sDir, include: "**/*.js")
3782 allJsFiles += fileTree(
3786 // these exlusions are files that the closure-compiler produces errors for. Should fix them
3787 "**/org/jmol/jvxl/readers/IsoIntersectFileReader.js",
3788 "**/org/jmol/export/JSExporter.js"
3791 allJsFiles += fileTree(
3795 // these exlusions are files that the closure-compiler produces errors for. Should fix them
3796 "**/sun/misc/Unsafe.js",
3797 "**/swingjs/jquery/jquery-editable-select.js",
3798 "**/swingjs/jquery/j2sComboBox.js",
3799 "**/sun/misc/FloatingDecimal.js"
3802 def allClasslist = [
3803 'jsfile': "${outputDir}/core${allClasslistName}.js",
3804 'zjsfile': "${outputDir}/core${allClasslistName}.z.js",
3806 'name': allClasslistName
3808 // not including this version of "all" core at the moment
3809 //jalviewjsCoreClasslists += allClasslist
3810 inputs.files(allClasslist['list'])
3811 outputs.file(allClasslist['jsfile'])
3812 outputs.file(allClasslist['zjsfile'])
3815 def logOutFile = file("${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_j2s_closure_stdout}")
3816 logOutFile.getParentFile().mkdirs()
3817 logOutFile.createNewFile()
3818 logOutFile.write(getDate("yyyy-MM-dd HH:mm:ss")+" jalviewjsBuildAllCores\n----\n")
3820 jalviewjsCoreClasslists.each {
3821 jalviewjsCallCore(it.name, it.list, prefixFile, suffixFile, it.jsfile, it.zjsfile, logOutFile, jalviewjs_j2s_to_console.equals("true"))
3828 def jalviewjsPublishCoreTemplate(String coreName, String templateName, File inputFile, String outputFile) {
3831 into file(outputFile).getParentFile()
3832 rename { filename ->
3833 if (filename.equals(inputFile.getName())) {
3834 return file(outputFile).getName()
3838 filter(ReplaceTokens,
3842 'MAIN': '"'+main_class+'"',
3844 'NAME': jalviewjsJalviewTemplateName+" [core ${coreName}]",
3845 'COREKEY': jalviewjs_core_key,
3846 'CORENAME': coreName
3853 task jalviewjsPublishCoreTemplates {
3854 dependsOn jalviewjsBuildAllCores
3855 def inputFileName = "${jalviewDir}/${j2s_coretemplate_html}"
3856 def inputFile = file(inputFileName)
3857 def outputDir = "${jalviewDir}/${jalviewjsTransferSiteCoreDir}"
3859 def outputFiles = []
3860 jalviewjsCoreClasslists.each { cl ->
3861 def outputFile = "${outputDir}/${jalviewjsJalviewTemplateName}_${cl.name}.html"
3862 cl['outputfile'] = outputFile
3863 outputFiles += outputFile
3867 jalviewjsCoreClasslists.each { cl ->
3868 jalviewjsPublishCoreTemplate(cl.name, jalviewjsJalviewTemplateName, inputFile, cl.outputfile)
3871 inputs.file(inputFile)
3872 outputs.files(outputFiles)
3876 task jalviewjsSyncCore (type: Sync) {
3877 dependsOn jalviewjsBuildAllCores
3878 dependsOn jalviewjsPublishCoreTemplates
3879 def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjsTransferSiteCoreDir}")
3880 def outputDir = "${jalviewDir}/${jalviewjsSiteDir}"
3884 def outputFiles = []
3885 rename { filename ->
3886 outputFiles += "${outputDir}/${filename}"
3892 outputs.files outputFiles
3893 inputs.files inputFiles
3897 // this Copy version of TransferSiteJs will delete anything else in the target dir
3898 task jalviewjsCopyTransferSiteJs(type: Copy) {
3899 dependsOn jalviewjsTranspile
3900 from "${jalviewDir}/${jalviewjsTransferSiteJsDir}"
3901 into "${jalviewDir}/${jalviewjsSiteDir}"
3905 // this Sync version of TransferSite is used by buildship to keep the website automatically up to date when a file changes
3906 task jalviewjsSyncTransferSiteJs(type: Sync) {
3907 from "${jalviewDir}/${jalviewjsTransferSiteJsDir}"
3909 into "${jalviewDir}/${jalviewjsSiteDir}"
3916 jalviewjsSyncAllLibs.mustRunAfter jalviewjsCopyTransferSiteJs
3917 jalviewjsSyncResources.mustRunAfter jalviewjsCopyTransferSiteJs
3918 jalviewjsSyncSiteResources.mustRunAfter jalviewjsCopyTransferSiteJs
3919 jalviewjsSyncBuildProperties.mustRunAfter jalviewjsCopyTransferSiteJs
3921 jalviewjsSyncAllLibs.mustRunAfter jalviewjsSyncTransferSiteJs
3922 jalviewjsSyncResources.mustRunAfter jalviewjsSyncTransferSiteJs
3923 jalviewjsSyncSiteResources.mustRunAfter jalviewjsSyncTransferSiteJs
3924 jalviewjsSyncBuildProperties.mustRunAfter jalviewjsSyncTransferSiteJs
3927 task jalviewjsPrepareSite {
3929 description "Prepares the website folder including unzipping files and copying resources"
3930 dependsOn jalviewjsSyncAllLibs
3931 dependsOn jalviewjsSyncResources
3932 dependsOn jalviewjsSyncSiteResources
3933 dependsOn jalviewjsSyncBuildProperties
3934 dependsOn jalviewjsSyncCore
3938 task jalviewjsBuildSite {
3940 description "Builds the whole website including transpiled code"
3941 dependsOn jalviewjsCopyTransferSiteJs
3942 dependsOn jalviewjsPrepareSite
3946 task cleanJalviewjsTransferSite {
3948 delete "${jalviewDir}/${jalviewjsTransferSiteJsDir}"
3949 delete "${jalviewDir}/${jalviewjsTransferSiteLibDir}"
3950 delete "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}"
3951 delete "${jalviewDir}/${jalviewjsTransferSiteCoreDir}"
3956 task cleanJalviewjsSite {
3957 dependsOn cleanJalviewjsTransferSite
3959 delete "${jalviewDir}/${jalviewjsSiteDir}"
3964 task jalviewjsSiteTar(type: Tar) {
3966 description "Creates a tar.gz file for the website"
3967 dependsOn jalviewjsBuildSite
3968 def outputFilename = "jalviewjs-site-${JALVIEW_VERSION}.tar.gz"
3969 archiveFileName = outputFilename
3971 compression Compression.GZIP
3973 from "${jalviewDir}/${jalviewjsSiteDir}"
3974 into jalviewjs_site_dir // this is inside the tar file
3976 inputs.dir("${jalviewDir}/${jalviewjsSiteDir}")
3980 task jalviewjsServer {
3982 def filename = "jalviewjsTest.html"
3983 description "Starts a webserver on localhost to test the website. See ${filename} to access local site on most recently used port."
3984 def htmlFile = "${jalviewDirAbsolutePath}/${filename}"
3989 def f = Class.forName("org.gradle.plugins.javascript.envjs.http.simple.SimpleHttpFileServerFactory")
3990 factory = f.newInstance()
3991 } catch (ClassNotFoundException e) {
3992 throw new GradleException("Unable to create SimpleHttpFileServerFactory")
3994 def port = Integer.valueOf(jalviewjs_server_port)
3999 while(port < start+1000 && !running) {
4001 def doc_root = new File("${jalviewDirAbsolutePath}/${jalviewjsSiteDir}")
4002 jalviewjsServer = factory.start(doc_root, port)
4004 url = jalviewjsServer.getResourceUrl(jalviewjs_server_resource)
4005 println("SERVER STARTED with document root ${doc_root}.")
4006 println("Go to "+url+" . Run gradle --stop to stop (kills all gradle daemons).")
4007 println("For debug: "+url+"?j2sdebug")
4008 println("For verbose: "+url+"?j2sverbose")
4009 } catch (Exception e) {
4014 <p><a href="${url}">JalviewJS Test. <${url}></a></p>
4015 <p><a href="${url}?j2sdebug">JalviewJS Test with debug. <${url}?j2sdebug></a></p>
4016 <p><a href="${url}?j2sverbose">JalviewJS Test with verbose. <${url}?j2sdebug></a></p>
4018 jalviewjsCoreClasslists.each { cl ->
4019 def urlcore = jalviewjsServer.getResourceUrl(file(cl.outputfile).getName())
4021 <p><a href="${urlcore}">${jalviewjsJalviewTemplateName} [core ${cl.name}]. <${urlcore}></a></p>
4023 println("For core ${cl.name}: "+urlcore)
4026 file(htmlFile).text = htmlText
4029 outputs.file(htmlFile)
4030 outputs.upToDateWhen({false})
4034 task cleanJalviewjsAll {
4036 description "Delete all configuration and build artifacts to do with JalviewJS build"
4037 dependsOn cleanJalviewjsSite
4038 dependsOn jalviewjsEclipsePaths
4041 delete "${jalviewDir}/${jalviewjsBuildDir}"
4042 delete "${jalviewDir}/${eclipse_bin_dir}"
4043 if (eclipseWorkspace != null && file(eclipseWorkspace.getAbsolutePath()+"/.metadata").exists()) {
4044 delete file(eclipseWorkspace.getAbsolutePath()+"/.metadata")
4046 delete jalviewjsJ2sAltSettingsFileName
4049 outputs.upToDateWhen( { false } )
4053 task jalviewjsIDE_checkJ2sPlugin {
4054 group "00 JalviewJS in Eclipse"
4055 description "Compare the swingjs/net.sf.j2s.core(-j11)?.jar file with the Eclipse IDE's plugin version (found in the 'dropins' dir)"
4058 def j2sPlugin = string("${jalviewDir}/${jalviewjsJ2sPlugin}")
4059 def j2sPluginFile = file(j2sPlugin)
4060 def eclipseHome = System.properties["eclipse.home.location"]
4061 if (eclipseHome == null || ! IN_ECLIPSE) {
4062 throw new StopExecutionException("Cannot find running Eclipse home from System.properties['eclipse.home.location']. Skipping J2S Plugin Check.")
4064 def eclipseJ2sPluginDirs = [ "${eclipseHome}/dropins" ]
4065 def altPluginsDir = System.properties["org.eclipse.equinox.p2.reconciler.dropins.directory"]
4066 if (altPluginsDir != null && file(altPluginsDir).exists()) {
4067 eclipseJ2sPluginDirs += altPluginsDir
4069 def foundPlugin = false
4070 def j2sPluginFileName = j2sPluginFile.getName()
4071 def eclipseJ2sPlugin
4072 def eclipseJ2sPluginFile
4073 eclipseJ2sPluginDirs.any { dir ->
4074 eclipseJ2sPlugin = "${dir}/${j2sPluginFileName}"
4075 eclipseJ2sPluginFile = file(eclipseJ2sPlugin)
4076 if (eclipseJ2sPluginFile.exists()) {
4082 def msg = "Eclipse J2S Plugin is not installed (could not find '${j2sPluginFileName}' in\n"+eclipseJ2sPluginDirs.join("\n")+"\n)\nTry running task jalviewjsIDE_copyJ2sPlugin"
4083 System.err.println(msg)
4084 throw new StopExecutionException(msg)
4087 def digest = MessageDigest.getInstance("MD5")
4089 digest.update(j2sPluginFile.text.bytes)
4090 def j2sPluginMd5 = new BigInteger(1, digest.digest()).toString(16).padLeft(32, '0')
4092 digest.update(eclipseJ2sPluginFile.text.bytes)
4093 def eclipseJ2sPluginMd5 = new BigInteger(1, digest.digest()).toString(16).padLeft(32, '0')
4095 if (j2sPluginMd5 != eclipseJ2sPluginMd5) {
4096 def msg = "WARNING! Eclipse J2S Plugin '${eclipseJ2sPlugin}' is different to this commit's version '${j2sPlugin}'"
4097 System.err.println(msg)
4098 throw new StopExecutionException(msg)
4100 def msg = "Eclipse J2S Plugin '${eclipseJ2sPlugin}' is the same as '${j2sPlugin}' (this is good)"
4106 task jalviewjsIDE_copyJ2sPlugin {
4107 group "00 JalviewJS in Eclipse"
4108 description "Copy the swingjs/net.sf.j2s.core(-j11)?.jar file into the Eclipse IDE's 'dropins' dir"
4111 def j2sPlugin = string("${jalviewDir}/${jalviewjsJ2sPlugin}")
4112 def j2sPluginFile = file(j2sPlugin)
4113 def eclipseHome = System.properties["eclipse.home.location"]
4114 if (eclipseHome == null || ! IN_ECLIPSE) {
4115 throw new StopExecutionException("Cannot find running Eclipse home from System.properties['eclipse.home.location']. NOT copying J2S Plugin.")
4117 def eclipseJ2sPlugin = "${eclipseHome}/dropins/${j2sPluginFile.getName()}"
4118 def eclipseJ2sPluginFile = file(eclipseJ2sPlugin)
4119 def msg = "WARNING! Copying this commit's j2s plugin '${j2sPlugin}' to Eclipse J2S Plugin '${eclipseJ2sPlugin}'\n* May require an Eclipse restart"
4120 System.err.println(msg)
4123 eclipseJ2sPluginFile.getParentFile().mkdirs()
4124 into eclipseJ2sPluginFile.getParent()
4130 task jalviewjsIDE_j2sFile {
4131 group "00 JalviewJS in Eclipse"
4132 description "Creates the .j2s file"
4133 dependsOn jalviewjsCreateJ2sSettings
4137 task jalviewjsIDE_SyncCore {
4138 group "00 JalviewJS in Eclipse"
4139 description "Build the core js lib closures listed in the classlists dir and publish core html from template"
4140 dependsOn jalviewjsSyncCore
4144 task jalviewjsIDE_SyncSiteAll {
4145 dependsOn jalviewjsSyncAllLibs
4146 dependsOn jalviewjsSyncResources
4147 dependsOn jalviewjsSyncSiteResources
4148 dependsOn jalviewjsSyncBuildProperties
4152 cleanJalviewjsTransferSite.mustRunAfter jalviewjsIDE_SyncSiteAll
4155 task jalviewjsIDE_PrepareSite {
4156 group "00 JalviewJS in Eclipse"
4157 description "Sync libs and resources to site dir, but not closure cores"
4159 dependsOn jalviewjsIDE_SyncSiteAll
4160 //dependsOn cleanJalviewjsTransferSite // not sure why this clean is here -- will slow down a re-run of this task
4164 task jalviewjsIDE_AssembleSite {
4165 group "00 JalviewJS in Eclipse"
4166 description "Assembles unzipped supporting zipfiles, resources, site resources and closure cores into the Eclipse transpiled site"
4167 dependsOn jalviewjsPrepareSite
4171 task jalviewjsIDE_SiteClean {
4172 group "00 JalviewJS in Eclipse"
4173 description "Deletes the Eclipse transpiled site"
4174 dependsOn cleanJalviewjsSite
4178 task jalviewjsIDE_Server {
4179 group "00 JalviewJS in Eclipse"
4180 description "Starts a webserver on localhost to test the website"
4181 dependsOn jalviewjsServer
4185 // buildship runs this at import or gradle refresh
4186 task eclipseSynchronizationTask {
4187 //dependsOn eclipseSetup
4188 dependsOn createBuildProperties
4190 dependsOn jalviewjsIDE_j2sFile
4191 dependsOn jalviewjsIDE_checkJ2sPlugin
4192 dependsOn jalviewjsIDE_PrepareSite
4197 // buildship runs this at build time or project refresh
4198 task eclipseAutoBuildTask {
4199 //dependsOn jalviewjsIDE_checkJ2sPlugin
4200 //dependsOn jalviewjsIDE_PrepareSite
4206 description "Build the site"
4207 dependsOn jalviewjsBuildSite