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.0' // 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 //run.dependsOn prepare
1738 //testReportDirName = "test-reports" // note that test workingDir will be $jalviewDir
1743 dependsOn cloverClasses
1745 dependsOn compileJava //?
1749 includeGroups testng_groups
1750 excludeGroups testng_excluded_groups
1752 useDefaultListeners=true
1755 maxHeapSize = "4096m"
1756 jvmArgs '-Xmx4096m', '-Xms4096m'
1757 maxParallelForks = 1
1761 maxParallelForks = 1
1764 jvmArgs '-Xmx2048m', '-Xms2048m'
1767 workingDir = jalviewDir
1768 def testLaf = project.findProperty("test_laf")
1769 if (testLaf != null) {
1770 println("Setting Test LaF to '${testLaf}'")
1771 systemProperty "laf", testLaf
1773 def testHiDPIScale = project.findProperty("test_HiDPIScale")
1774 if (testHiDPIScale != null) {
1775 println("Setting Test HiDPI Scale to '${testHiDPIScale}'")
1776 systemProperty "sun.java2d.uiScale", testHiDPIScale
1778 sourceCompatibility = compile_source_compatibility
1779 targetCompatibility = compile_target_compatibility
1780 jvmArgs += additional_compiler_args
1784 println("Running tests " + (useClover?"WITH":"WITHOUT") + " clover")
1790 task compileLinkCheck(type: JavaCompile) {
1792 classpath = files("${jalviewDir}/${utils_dir}")
1793 destinationDir = file("${jalviewDir}/${utils_dir}")
1794 source = fileTree(dir: "${jalviewDir}/${utils_dir}", include: ["HelpLinksChecker.java", "BufferedLineReader.java"])
1796 inputs.file("${jalviewDir}/${utils_dir}/HelpLinksChecker.java")
1797 inputs.file("${jalviewDir}/${utils_dir}/HelpLinksChecker.java")
1798 outputs.file("${jalviewDir}/${utils_dir}/HelpLinksChecker.class")
1799 outputs.file("${jalviewDir}/${utils_dir}/BufferedLineReader.class")
1803 task linkCheck(type: JavaExec) {
1805 dependsOn compileLinkCheck
1807 def helpLinksCheckerOutFile = file("${jalviewDir}/${utils_dir}/HelpLinksChecker.out")
1808 classpath = files("${jalviewDir}/${utils_dir}")
1809 main = "HelpLinksChecker"
1810 workingDir = "${helpBuildDir}"
1811 args = [ "${helpBuildDir}/${help_dir}", "-nointernet" ]
1813 def outFOS = new FileOutputStream(helpLinksCheckerOutFile, false) // false == don't append
1814 standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
1817 errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
1821 inputs.dir(helpBuildDir)
1822 outputs.file(helpLinksCheckerOutFile)
1826 // import the pubhtmlhelp target
1827 ant.properties.basedir = "${jalviewDir}"
1828 ant.properties.helpBuildDir = "${helpBuildDir}/${help_dir}"
1829 ant.importBuild "${utils_dir}/publishHelp.xml"
1832 task cleanPackageDir(type: Delete) {
1834 delete fileTree(dir: "${jalviewDir}/${package_dir}", include: "*.jar")
1844 attributes "Main-Class": main_class,
1845 "Permissions": "all-permissions",
1846 "Application-Name": applicationName,
1847 "Codebase": application_codebase,
1848 "Implementation-Version": JALVIEW_VERSION
1851 def outputDir = "${jalviewDir}/${package_dir}"
1852 destinationDirectory = file(outputDir)
1853 archiveFileName = rootProject.name+".jar"
1854 duplicatesStrategy "EXCLUDE"
1861 exclude "**/*.jar.*"
1863 inputs.dir(sourceSets.main.java.outputDir)
1864 sourceSets.main.resources.srcDirs.each{ dir ->
1867 outputs.file("${outputDir}/${archiveFileName}")
1871 task copyJars(type: Copy) {
1872 from fileTree(dir: classesDir, include: "**/*.jar").files
1873 into "${jalviewDir}/${package_dir}"
1877 // doing a Sync instead of Copy as Copy doesn't deal with "outputs" very well
1878 task syncJars(type: Sync) {
1880 from fileTree(dir: "${jalviewDir}/${libDistDir}", include: "**/*.jar").files
1881 into "${jalviewDir}/${package_dir}"
1883 include jar.archiveFileName.getOrNull()
1890 description = "Put all required libraries in dist"
1891 // order of "cleanPackageDir", "copyJars", "jar" important!
1892 jar.mustRunAfter cleanPackageDir
1893 syncJars.mustRunAfter cleanPackageDir
1894 dependsOn cleanPackageDir
1897 outputs.dir("${jalviewDir}/${package_dir}")
1902 dependsOn cleanPackageDir
1909 group = "distribution"
1910 description = "Create a single jar file with all dependency libraries merged. Can be run with java -jar"
1914 from ("${jalviewDir}/${libDistDir}") {
1918 attributes "Implementation-Version": JALVIEW_VERSION,
1919 "Application-Name": applicationName
1922 duplicatesStrategy "INCLUDE"
1924 mainClassName = shadow_jar_main_class
1926 classifier = "all-"+JALVIEW_VERSION+"-j"+JAVA_VERSION
1930 task getdownImagesCopy() {
1931 inputs.dir getdownImagesDir
1932 outputs.dir getdownImagesBuildDir
1936 from(getdownImagesDir) {
1937 include("*getdown*.png")
1939 into getdownImagesBuildDir
1944 task getdownImagesProcess() {
1945 dependsOn getdownImagesCopy
1948 if (backgroundImageText) {
1949 if (convertBinary == null) {
1950 throw new StopExecutionException("No ImageMagick convert binary installed at '${convertBinaryExpectedLocation}'")
1952 if (!project.hasProperty("getdown_background_image_text_suffix_cmd")) {
1953 throw new StopExecutionException("No property 'getdown_background_image_text_suffix_cmd' defined. See channel_gradle.properties for channel ${CHANNEL}")
1955 fileTree(dir: getdownImagesBuildDir, include: "*background*.png").getFiles().each { file ->
1957 executable convertBinary
1960 '-font', getdown_background_image_text_font,
1961 '-fill', getdown_background_image_text_colour,
1962 '-draw', sprintf(getdown_background_image_text_suffix_cmd, channelSuffix),
1963 '-draw', sprintf(getdown_background_image_text_commit_cmd, "git-commit: ${gitHash}"),
1964 '-draw', sprintf(getdown_background_image_text_date_cmd, getDate("yyyy-MM-dd HH:mm:ss")),
1973 task getdownImages() {
1974 dependsOn getdownImagesProcess
1977 task getdownWebsite() {
1978 group = "distribution"
1979 description = "Create the getdown minimal app folder, and website folder for this version of jalview. Website folder also used for offline app installer"
1981 dependsOn getdownImages
1986 def getdownWebsiteResourceFilenames = []
1987 def getdownResourceDir = getdownResourceDir
1988 def getdownResourceFilenames = []
1991 // clean the getdown website and files dir before creating getdown folders
1992 delete getdownAppBaseDir
1993 delete getdownFilesDir
1996 from buildProperties
1997 rename(file(buildProperties).getName(), getdown_build_properties)
2000 getdownWebsiteResourceFilenames += "${getdownAppDistDir}/${getdown_build_properties}"
2003 from channelPropsFile
2004 filter(ReplaceTokens,
2008 'SUFFIX': channelSuffix
2011 into getdownAppBaseDir
2013 getdownWebsiteResourceFilenames += file(channelPropsFile).getName()
2015 // set some getdownTxt_ properties then go through all properties looking for getdownTxt_...
2016 def props = project.properties.sort { it.key }
2017 if (getdownAltJavaMinVersion != null && getdownAltJavaMinVersion.length() > 0) {
2018 props.put("getdown_txt_java_min_version", getdownAltJavaMinVersion)
2020 if (getdownAltJavaMaxVersion != null && getdownAltJavaMaxVersion.length() > 0) {
2021 props.put("getdown_txt_java_max_version", getdownAltJavaMaxVersion)
2023 if (getdownAltMultiJavaLocation != null && getdownAltMultiJavaLocation.length() > 0) {
2024 props.put("getdown_txt_multi_java_location", getdownAltMultiJavaLocation)
2026 if (getdownImagesBuildDir != null && file(getdownImagesBuildDir).exists()) {
2027 props.put("getdown_txt_ui.background_image", "${getdownImagesBuildDir}/${getdown_background_image}")
2028 props.put("getdown_txt_ui.instant_background_image", "${getdownImagesBuildDir}/${getdown_instant_background_image}")
2029 props.put("getdown_txt_ui.error_background", "${getdownImagesBuildDir}/${getdown_error_background}")
2030 props.put("getdown_txt_ui.progress_image", "${getdownImagesBuildDir}/${getdown_progress_image}")
2031 props.put("getdown_txt_ui.icon", "${getdownImagesBuildDir}/${getdown_icon}")
2032 props.put("getdown_txt_ui.mac_dock_icon", "${getdownImagesBuildDir}/${getdown_mac_dock_icon}")
2035 props.put("getdown_txt_title", jalview_name)
2036 props.put("getdown_txt_ui.name", applicationName)
2038 // start with appbase
2039 getdownTextLines += "appbase = ${getdownAppBase}"
2040 props.each{ prop, val ->
2041 if (prop.startsWith("getdown_txt_") && val != null) {
2042 if (prop.startsWith("getdown_txt_multi_")) {
2043 def key = prop.substring(18)
2044 val.split(",").each{ v ->
2045 def line = "${key} = ${v}"
2046 getdownTextLines += line
2049 // file values rationalised
2050 if (val.indexOf('/') > -1 || prop.startsWith("getdown_txt_resource")) {
2052 if (val.indexOf('/') == 0) {
2055 } else if (val.indexOf('/') > 0) {
2056 // relative path (relative to jalviewDir)
2057 r = file( "${jalviewDir}/${val}" )
2060 val = "${getdown_resource_dir}/" + r.getName()
2061 getdownWebsiteResourceFilenames += val
2062 getdownResourceFilenames += r.getPath()
2065 if (! prop.startsWith("getdown_txt_resource")) {
2066 def line = prop.substring(12) + " = ${val}"
2067 getdownTextLines += line
2073 getdownWebsiteResourceFilenames.each{ filename ->
2074 getdownTextLines += "resource = ${filename}"
2076 getdownResourceFilenames.each{ filename ->
2079 into getdownResourceDir
2083 def getdownWrapperScripts = [ getdown_bash_wrapper_script, getdown_powershell_wrapper_script, getdown_batch_wrapper_script ]
2084 getdownWrapperScripts.each{ script ->
2085 def s = file( "${jalviewDir}/utils/getdown/${getdown_wrapper_script_dir}/${script}" )
2089 into "${getdownAppBaseDir}/${getdown_wrapper_script_dir}"
2091 getdownTextLines += "resource = ${getdown_wrapper_script_dir}/${script}"
2096 fileTree(file(package_dir)).each{ f ->
2097 if (f.isDirectory()) {
2098 def files = fileTree(dir: f, include: ["*"]).getFiles()
2100 } else if (f.exists()) {
2104 def jalviewJar = jar.archiveFileName.getOrNull()
2105 // put jalview.jar first for CLASSPATH and .properties files reasons
2106 codeFiles.sort{a, b -> ( a.getName() == jalviewJar ? -1 : ( b.getName() == jalviewJar ? 1 : a <=> b ) ) }.each{f ->
2107 def name = f.getName()
2108 def line = "code = ${getdownAppDistDir}/${name}"
2109 getdownTextLines += line
2116 // NOT USING MODULES YET, EVERYTHING SHOULD BE IN dist
2118 if (JAVA_VERSION.equals("11")) {
2119 def j11libFiles = fileTree(dir: "${jalviewDir}/${j11libDir}", include: ["*.jar"]).getFiles()
2120 j11libFiles.sort().each{f ->
2121 def name = f.getName()
2122 def line = "code = ${getdown_j11lib_dir}/${name}"
2123 getdownTextLines += line
2126 into getdownJ11libDir
2132 // 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.
2133 //getdownTextLines += "class = " + file(getdownLauncher).getName()
2134 getdownTextLines += "resource = ${getdown_launcher_new}"
2135 getdownTextLines += "class = ${main_class}"
2136 // Not setting these properties in general so that getdownappbase and getdowndistdir will default to release version in jalview.bin.Cache
2137 if (getdownSetAppBaseProperty) {
2138 getdownTextLines += "jvmarg = -Dgetdowndistdir=${getdownAppDistDir}"
2139 getdownTextLines += "jvmarg = -Dgetdownappbase=${getdownAppBase}"
2142 def getdownTxt = file("${getdownAppBaseDir}/getdown.txt")
2143 getdownTxt.write(getdownTextLines.join("\n"))
2145 getdownLaunchJvl = getdown_launch_jvl_name + ( (jvlChannelName != null && jvlChannelName.length() > 0)?"-${jvlChannelName}":"" ) + ".jvl"
2146 def launchJvl = file("${getdownAppBaseDir}/${getdownLaunchJvl}")
2147 launchJvl.write("appbase=${getdownAppBase}")
2149 // files going into the getdown website dir: getdown-launcher.jar
2151 from getdownLauncher
2152 rename(file(getdownLauncher).getName(), getdown_launcher_new)
2153 into getdownAppBaseDir
2156 // files going into the getdown website dir: getdown-launcher(-local).jar
2158 from getdownLauncher
2159 if (file(getdownLauncher).getName() != getdown_launcher) {
2160 rename(file(getdownLauncher).getName(), getdown_launcher)
2162 into getdownAppBaseDir
2165 // files going into the getdown website dir: ./install dir and files
2166 if (! (CHANNEL.startsWith("ARCHIVE") || CHANNEL.startsWith("DEVELOP"))) {
2169 from getdownLauncher
2170 from "${getdownAppDir}/${getdown_build_properties}"
2171 if (file(getdownLauncher).getName() != getdown_launcher) {
2172 rename(file(getdownLauncher).getName(), getdown_launcher)
2174 into getdownInstallDir
2177 // and make a copy in the getdown files dir (these are not downloaded by getdown)
2179 from getdownInstallDir
2180 into getdownFilesInstallDir
2184 // files going into the getdown files dir: getdown.txt, getdown-launcher.jar, channel-launch.jvl, build_properties
2188 from getdownLauncher
2189 from "${getdownAppBaseDir}/${getdown_build_properties}"
2190 from "${getdownAppBaseDir}/${channel_props}"
2191 if (file(getdownLauncher).getName() != getdown_launcher) {
2192 rename(file(getdownLauncher).getName(), getdown_launcher)
2194 into getdownFilesDir
2197 // and ./resource (not all downloaded by getdown)
2199 from getdownResourceDir
2200 into "${getdownFilesDir}/${getdown_resource_dir}"
2205 inputs.dir("${jalviewDir}/${package_dir}")
2207 outputs.dir(getdownAppBaseDir)
2208 outputs.dir(getdownFilesDir)
2212 // a helper task to allow getdown digest of any dir: `gradle getdownDigestDir -PDIGESTDIR=/path/to/my/random/getdown/dir
2213 task getdownDigestDir(type: JavaExec) {
2215 description "A task to run a getdown Digest on a dir with getdown.txt. Provide a DIGESTDIR property via -PDIGESTDIR=..."
2217 def digestDirPropertyName = "DIGESTDIR"
2219 classpath = files(getdownLauncher)
2220 def digestDir = findProperty(digestDirPropertyName)
2221 if (digestDir == null) {
2222 throw new GradleException("Must provide a DIGESTDIR value to produce an alternative getdown digest")
2226 main = "com.threerings.getdown.tools.Digester"
2230 task getdownDigest(type: JavaExec) {
2231 group = "distribution"
2232 description = "Digest the getdown website folder"
2233 dependsOn getdownWebsite
2235 classpath = files(getdownLauncher)
2237 main = "com.threerings.getdown.tools.Digester"
2238 args getdownAppBaseDir
2239 inputs.dir(getdownAppBaseDir)
2240 outputs.file("${getdownAppBaseDir}/digest2.txt")
2245 group = "distribution"
2246 description = "Create the minimal and full getdown app folder for installers and website and create digest file"
2247 dependsOn getdownDigest
2249 if (reportRsyncCommand) {
2250 def fromDir = getdownAppBaseDir + (getdownAppBaseDir.endsWith('/')?'':'/')
2251 def toDir = "${getdown_rsync_dest}/${getdownDir}" + (getdownDir.endsWith('/')?'':'/')
2252 println "LIKELY RSYNC COMMAND:"
2253 println "mkdir -p '$toDir'\nrsync -avh --delete '$fromDir' '$toDir'"
2254 if (RUNRSYNC == "true") {
2256 commandLine "mkdir", "-p", toDir
2259 commandLine "rsync", "-avh", "--delete", fromDir, toDir
2267 task getdownArchiveBuild() {
2268 group = "distribution"
2269 description = "Put files in the archive dir to go on the website"
2271 dependsOn getdownWebsite
2273 def v = "v${JALVIEW_VERSION_UNDERSCORES}"
2274 def vDir = "${getdownArchiveDir}/${v}"
2275 getdownFullArchiveDir = "${vDir}/getdown"
2276 getdownVersionLaunchJvl = "${vDir}/jalview-${v}.jvl"
2278 def vAltDir = "alt_${v}"
2279 def archiveImagesDir = "${jalviewDir}/${channel_properties_dir}/old/images"
2282 // cleanup old "old" dir
2283 delete getdownArchiveDir
2285 def getdownArchiveTxt = file("${getdownFullArchiveDir}/getdown.txt")
2286 getdownArchiveTxt.getParentFile().mkdirs()
2287 def getdownArchiveTextLines = []
2288 def getdownFullArchiveAppBase = "${getdownArchiveAppBase}${getdownArchiveAppBase.endsWith("/")?"":"/"}${v}/getdown/"
2292 from "${getdownAppBaseDir}/${getdownAppDistDir}"
2293 into "${getdownFullArchiveDir}/${vAltDir}"
2296 getdownTextLines.each { line ->
2297 line = line.replaceAll("^(?<s>appbase\\s*=\\s*).*", '${s}'+getdownFullArchiveAppBase)
2298 line = line.replaceAll("^(?<s>(resource|code)\\s*=\\s*)${getdownAppDistDir}/", '${s}'+vAltDir+"/")
2299 line = line.replaceAll("^(?<s>ui.background_image\\s*=\\s*).*\\.png", '${s}'+"${getdown_resource_dir}/jalview_archive_getdown_background.png")
2300 line = line.replaceAll("^(?<s>ui.instant_background_image\\s*=\\s*).*\\.png", '${s}'+"${getdown_resource_dir}/jalview_archive_getdown_background_initialising.png")
2301 line = line.replaceAll("^(?<s>ui.error_background\\s*=\\s*).*\\.png", '${s}'+"${getdown_resource_dir}/jalview_archive_getdown_background_error.png")
2302 line = line.replaceAll("^(?<s>ui.progress_image\\s*=\\s*).*\\.png", '${s}'+"${getdown_resource_dir}/jalview_archive_getdown_progress_bar.png")
2303 // remove the existing resource = resource/ or bin/ lines
2304 if (! line.matches("resource\\s*=\\s*(resource|bin)/.*")) {
2305 getdownArchiveTextLines += line
2309 // the resource dir -- add these files as resource lines in getdown.txt
2311 from "${archiveImagesDir}"
2312 into "${getdownFullArchiveDir}/${getdown_resource_dir}"
2314 getdownArchiveTextLines += "resource = ${getdown_resource_dir}/${file.getName()}"
2318 getdownArchiveTxt.write(getdownArchiveTextLines.join("\n"))
2320 def vLaunchJvl = file(getdownVersionLaunchJvl)
2321 vLaunchJvl.getParentFile().mkdirs()
2322 vLaunchJvl.write("appbase=${getdownFullArchiveAppBase}\n")
2323 def vLaunchJvlPath = vLaunchJvl.toPath().toAbsolutePath()
2324 def jvlLinkPath = file("${vDir}/jalview.jvl").toPath().toAbsolutePath()
2325 // for some reason filepath.relativize(fileInSameDirPath) gives a path to "../" which is wrong
2326 //java.nio.file.Files.createSymbolicLink(jvlLinkPath, jvlLinkPath.relativize(vLaunchJvlPath));
2327 java.nio.file.Files.createSymbolicLink(jvlLinkPath, java.nio.file.Paths.get(".",vLaunchJvl.getName()));
2329 // files going into the getdown files dir: getdown.txt, getdown-launcher.jar, channel-launch.jvl, build_properties
2331 from getdownLauncher
2332 from "${getdownAppBaseDir}/${getdownLaunchJvl}"
2333 from "${getdownAppBaseDir}/${getdown_launcher_new}"
2334 from "${getdownAppBaseDir}/${channel_props}"
2335 if (file(getdownLauncher).getName() != getdown_launcher) {
2336 rename(file(getdownLauncher).getName(), getdown_launcher)
2338 into getdownFullArchiveDir
2344 task getdownArchiveDigest(type: JavaExec) {
2345 group = "distribution"
2346 description = "Digest the getdown archive folder"
2348 dependsOn getdownArchiveBuild
2351 classpath = files(getdownLauncher)
2352 args getdownFullArchiveDir
2354 main = "com.threerings.getdown.tools.Digester"
2355 inputs.dir(getdownFullArchiveDir)
2356 outputs.file("${getdownFullArchiveDir}/digest2.txt")
2359 task getdownArchive() {
2360 group = "distribution"
2361 description = "Build the website archive dir with getdown digest"
2363 dependsOn getdownArchiveBuild
2364 dependsOn getdownArchiveDigest
2367 tasks.withType(JavaCompile) {
2368 options.encoding = 'UTF-8'
2374 delete getdownAppBaseDir
2375 delete getdownFilesDir
2376 delete getdownArchiveDir
2382 if (file(install4jHomeDir).exists()) {
2384 } else if (file(System.getProperty("user.home")+"/buildtools/install4j").exists()) {
2385 install4jHomeDir = System.getProperty("user.home")+"/buildtools/install4j"
2386 } else if (file("/Applications/install4j.app/Contents/Resources/app").exists()) {
2387 install4jHomeDir = "/Applications/install4j.app/Contents/Resources/app"
2389 installDir(file(install4jHomeDir))
2391 mediaTypes = Arrays.asList(install4j_media_types.split(","))
2395 task copyInstall4jTemplate {
2396 def install4jTemplateFile = file("${install4jDir}/${install4j_template}")
2397 def install4jFileAssociationsFile = file("${install4jDir}/${install4j_installer_file_associations}")
2398 inputs.file(install4jTemplateFile)
2399 inputs.file(install4jFileAssociationsFile)
2400 inputs.property("CHANNEL", { CHANNEL })
2401 outputs.file(install4jConfFile)
2404 def install4jConfigXml = new XmlParser().parse(install4jTemplateFile)
2406 // turn off code signing if no OSX_KEYPASS
2407 if (OSX_KEYPASS == "") {
2408 install4jConfigXml.'**'.codeSigning.each { codeSigning ->
2409 codeSigning.'@macEnabled' = "false"
2411 install4jConfigXml.'**'.windows.each { windows ->
2412 windows.'@runPostProcessor' = "false"
2416 // disable install screen for OSX dmg (for 2.11.2.0)
2417 install4jConfigXml.'**'.macosArchive.each { macosArchive ->
2418 macosArchive.attributes().remove('executeSetupApp')
2419 macosArchive.attributes().remove('setupAppId')
2422 // turn off checksum creation for LOCAL channel
2423 def e = install4jConfigXml.application[0]
2424 e.'@createChecksums' = string(install4jCheckSums)
2426 // put file association actions where placeholder action is
2427 def install4jFileAssociationsText = install4jFileAssociationsFile.text
2428 def fileAssociationActions = new XmlParser().parseText("<actions>${install4jFileAssociationsText}</actions>")
2429 install4jConfigXml.'**'.action.any { a -> // .any{} stops after the first one that returns true
2430 if (a.'@name' == 'EXTENSIONS_REPLACED_BY_GRADLE') {
2431 def parent = a.parent()
2433 fileAssociationActions.each { faa ->
2436 // don't need to continue in .any loop once replacements have been made
2441 // use Windows Program Group with Examples folder for RELEASE, and Program Group without Examples for everything else
2442 // NB we're deleting the /other/ one!
2443 // Also remove the examples subdir from non-release versions
2444 def customizedIdToDelete = "PROGRAM_GROUP_RELEASE"
2445 // 2.11.1.0 NOT releasing with the Examples folder in the Program Group
2446 if (false && CHANNEL=="RELEASE") { // remove 'false && ' to include Examples folder in RELEASE channel
2447 customizedIdToDelete = "PROGRAM_GROUP_NON_RELEASE"
2449 // remove the examples subdir from Full File Set
2450 def files = install4jConfigXml.files[0]
2451 def fileset = files.filesets.fileset.find { fs -> fs.'@customizedId' == "FULL_FILE_SET" }
2452 def root = files.roots.root.find { r -> r.'@fileset' == fileset.'@id' }
2453 def mountPoint = files.mountPoints.mountPoint.find { mp -> mp.'@root' == root.'@id' }
2454 def dirEntry = files.entries.dirEntry.find { de -> de.'@mountPoint' == mountPoint.'@id' && de.'@subDirectory' == "examples" }
2455 dirEntry.parent().remove(dirEntry)
2457 install4jConfigXml.'**'.action.any { a ->
2458 if (a.'@customizedId' == customizedIdToDelete) {
2459 def parent = a.parent()
2465 // write install4j file
2466 install4jConfFile.text = XmlUtil.serialize(install4jConfigXml)
2473 delete install4jConfFile
2477 task cleanInstallersDataFiles {
2478 def installersOutputTxt = file("${jalviewDir}/${install4jBuildDir}/output.txt")
2479 def installersSha256 = file("${jalviewDir}/${install4jBuildDir}/sha256sums")
2480 def hugoDataJsonFile = file("${jalviewDir}/${install4jBuildDir}/installers-${JALVIEW_VERSION_UNDERSCORES}.json")
2482 delete installersOutputTxt
2483 delete installersSha256
2484 delete hugoDataJsonFile
2488 task install4jDMGBackgroundImageCopy {
2489 inputs.file "${install4jDMGBackgroundImageDir}/${install4jDMGBackgroundImageFile}"
2490 outputs.dir "${install4jDMGBackgroundImageBuildDir}"
2493 from(install4jDMGBackgroundImageDir) {
2494 include(install4jDMGBackgroundImageFile)
2496 into install4jDMGBackgroundImageBuildDir
2501 task install4jDMGBackgroundImageProcess {
2502 dependsOn install4jDMGBackgroundImageCopy
2505 if (backgroundImageText) {
2506 if (convertBinary == null) {
2507 throw new StopExecutionException("No ImageMagick convert binary installed at '${convertBinaryExpectedLocation}'")
2509 if (!project.hasProperty("install4j_background_image_text_suffix_cmd")) {
2510 throw new StopExecutionException("No property 'install4j_background_image_text_suffix_cmd' defined. See channel_gradle.properties for channel ${CHANNEL}")
2512 fileTree(dir: install4jDMGBackgroundImageBuildDir, include: "*.png").getFiles().each { file ->
2514 executable convertBinary
2517 '-font', install4j_background_image_text_font,
2518 '-fill', install4j_background_image_text_colour,
2519 '-draw', sprintf(install4j_background_image_text_suffix_cmd, channelSuffix),
2520 '-draw', sprintf(install4j_background_image_text_commit_cmd, "git-commit: ${gitHash}"),
2521 '-draw', sprintf(install4j_background_image_text_date_cmd, getDate("yyyy-MM-dd HH:mm:ss")),
2530 task install4jDMGBackgroundImage {
2531 dependsOn install4jDMGBackgroundImageProcess
2534 task installerFiles(type: com.install4j.gradle.Install4jTask) {
2535 group = "distribution"
2536 description = "Create the install4j installers"
2538 dependsOn copyInstall4jTemplate
2539 dependsOn cleanInstallersDataFiles
2540 dependsOn install4jDMGBackgroundImage
2542 projectFile = install4jConfFile
2544 // create an md5 for the input files to use as version for install4j conf file
2545 def digest = MessageDigest.getInstance("MD5")
2547 (file("${install4jDir}/${install4j_template}").text +
2548 file("${install4jDir}/${install4j_info_plist_file_associations}").text +
2549 file("${install4jDir}/${install4j_installer_file_associations}").text).bytes)
2550 def filesMd5 = new BigInteger(1, digest.digest()).toString(16)
2551 if (filesMd5.length() >= 8) {
2552 filesMd5 = filesMd5.substring(0,8)
2554 def install4jTemplateVersion = "${JALVIEW_VERSION}_F${filesMd5}_C${gitHash}"
2557 'JALVIEW_NAME': jalview_name,
2558 'JALVIEW_APPLICATION_NAME': applicationName,
2559 'JALVIEW_DIR': "../..",
2560 'OSX_KEYSTORE': OSX_KEYSTORE,
2561 'OSX_APPLEID': OSX_APPLEID,
2562 'OSX_ALTOOLPASS': OSX_ALTOOLPASS,
2563 'JSIGN_SH': JSIGN_SH,
2564 'JRE_DIR': getdown_app_dir_java,
2565 'INSTALLER_TEMPLATE_VERSION': install4jTemplateVersion,
2566 'JALVIEW_VERSION': JALVIEW_VERSION,
2567 'JAVA_MIN_VERSION': JAVA_MIN_VERSION,
2568 'JAVA_MAX_VERSION': JAVA_MAX_VERSION,
2569 'JAVA_VERSION': JAVA_VERSION,
2570 'JAVA_INTEGER_VERSION': JAVA_INTEGER_VERSION,
2571 'VERSION': JALVIEW_VERSION,
2572 'COPYRIGHT_MESSAGE': install4j_copyright_message,
2573 'BUNDLE_ID': install4jBundleId,
2574 'INTERNAL_ID': install4jInternalId,
2575 'WINDOWS_APPLICATION_ID': install4jWinApplicationId,
2576 'MACOS_DMG_DS_STORE': install4jDMGDSStore,
2577 'MACOS_DMG_BG_IMAGE': "${install4jDMGBackgroundImageBuildDir}/${install4jDMGBackgroundImageFile}",
2578 'WRAPPER_LINK': getdownWrapperLink,
2579 'BASH_WRAPPER_SCRIPT': getdown_bash_wrapper_script,
2580 'POWERSHELL_WRAPPER_SCRIPT': getdown_powershell_wrapper_script,
2581 'WRAPPER_SCRIPT_BIN_DIR': getdown_wrapper_script_dir,
2582 'INSTALLER_NAME': install4jInstallerName,
2583 'INSTALL4J_UTILS_DIR': install4j_utils_dir,
2584 'GETDOWN_CHANNEL_DIR': getdownChannelDir,
2585 'GETDOWN_FILES_DIR': getdown_files_dir,
2586 'GETDOWN_RESOURCE_DIR': getdown_resource_dir,
2587 'GETDOWN_DIST_DIR': getdownAppDistDir,
2588 'GETDOWN_ALT_DIR': getdown_app_dir_alt,
2589 'GETDOWN_INSTALL_DIR': getdown_install_dir,
2590 'INFO_PLIST_FILE_ASSOCIATIONS_FILE': install4j_info_plist_file_associations,
2591 'BUILD_DIR': install4jBuildDir,
2592 'APPLICATION_CATEGORIES': install4j_application_categories,
2593 'APPLICATION_FOLDER': install4jApplicationFolder,
2594 'UNIX_APPLICATION_FOLDER': install4jUnixApplicationFolder,
2595 'EXECUTABLE_NAME': install4jExecutableName,
2596 'EXTRA_SCHEME': install4jExtraScheme,
2597 'MAC_ICONS_FILE': install4jMacIconsFile,
2598 'WINDOWS_ICONS_FILE': install4jWindowsIconsFile,
2599 'PNG_ICON_FILE': install4jPngIconFile,
2600 'BACKGROUND': install4jBackground,
2605 'windows': 'WINDOWS',
2609 // these are the bundled OS/architecture VMs needed by install4j
2612 [ "mac", "aarch64" ],
2613 [ "windows", "x64" ],
2615 [ "linux", "aarch64" ]
2617 osArch.forEach { os, arch ->
2618 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)
2619 // N.B. For some reason install4j requires the below filename to have underscores and not hyphens
2620 // otherwise running `gradle installers` generates a non-useful error:
2621 // `install4j: compilation failed. Reason: java.lang.NumberFormatException: For input string: "windows"`
2622 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)
2625 //println("INSTALL4J VARIABLES:")
2626 //variables.each{k,v->println("${k}=${v}")}
2628 destination = "${jalviewDir}/${install4jBuildDir}"
2629 buildSelected = true
2631 if (install4j_faster.equals("true") || CHANNEL.startsWith("LOCAL")) {
2633 disableSigning = true
2634 disableNotarization = true
2638 macKeystorePassword = OSX_KEYPASS
2641 if (OSX_ALTOOLPASS) {
2642 appleIdPassword = OSX_ALTOOLPASS
2643 disableNotarization = false
2645 disableNotarization = true
2649 println("Using projectFile "+projectFile)
2650 if (!disableNotarization) { println("Will notarize OSX App DMG") }
2654 inputs.dir(getdownAppBaseDir)
2655 inputs.file(install4jConfFile)
2656 inputs.file("${install4jDir}/${install4j_info_plist_file_associations}")
2657 outputs.dir("${jalviewDir}/${install4j_build_dir}/${JAVA_VERSION}")
2660 def getDataHash(File myFile) {
2661 HashCode hash = Files.asByteSource(myFile).hash(Hashing.sha256())
2662 return myFile.exists()
2664 "file" : myFile.getName(),
2665 "filesize" : myFile.length(),
2666 "sha256" : hash.toString()
2671 def writeDataJsonFile(File installersOutputTxt, File installersSha256, File dataJsonFile) {
2673 "channel" : getdownChannelName,
2674 "date" : getDate("yyyy-MM-dd HH:mm:ss"),
2675 "git-commit" : "${gitHash} [${gitBranch}]",
2676 "version" : JALVIEW_VERSION
2678 // install4j installer files
2679 if (installersOutputTxt.exists()) {
2681 installersOutputTxt.readLines().each { def line ->
2682 if (line.startsWith("#")) {
2685 line.replaceAll("\n","")
2686 def vals = line.split("\t")
2687 def filename = vals[3]
2688 def filesize = file(filename).length()
2689 filename = filename.replaceAll(/^.*\//, "")
2690 hash[vals[0]] = [ "id" : vals[0], "os" : vals[1], "name" : vals[2], "file" : filename, "filesize" : filesize ]
2691 idHash."${filename}" = vals[0]
2693 if (install4jCheckSums && installersSha256.exists()) {
2694 installersSha256.readLines().each { def line ->
2695 if (line.startsWith("#")) {
2698 line.replaceAll("\n","")
2699 def vals = line.split(/\s+\*?/)
2700 def filename = vals[1]
2701 def innerHash = (hash.(idHash."${filename}"))."sha256" = vals[0]
2707 "JAR": shadowJar.archiveFile, // executable JAR
2708 "JVL": getdownVersionLaunchJvl, // version JVL
2709 "SOURCE": sourceDist.archiveFile // source TGZ
2710 ].each { key, value ->
2711 def file = file(value)
2712 if (file.exists()) {
2713 def fileHash = getDataHash(file)
2714 if (fileHash != null) {
2715 hash."${key}" = fileHash;
2719 return dataJsonFile.write(new JsonBuilder(hash).toPrettyString())
2722 task staticMakeInstallersJsonFile {
2724 def output = findProperty("i4j_output")
2725 def sha256 = findProperty("i4j_sha256")
2726 def json = findProperty("i4j_json")
2727 if (output == null || sha256 == null || json == null) {
2728 throw new GradleException("Must provide paths to all of output.txt, sha256sums, and output.json with '-Pi4j_output=... -Pi4j_sha256=... -Pi4j_json=...")
2730 writeDataJsonFile(file(output), file(sha256), file(json))
2735 dependsOn installerFiles
2741 eclipse().configFile(eclipse_codestyle_file)
2745 task createSourceReleaseProperties(type: WriteProperties) {
2746 group = "distribution"
2747 description = "Create the source RELEASE properties file"
2749 def sourceTarBuildDir = "${buildDir}/sourceTar"
2750 def sourceReleasePropertiesFile = "${sourceTarBuildDir}/RELEASE"
2751 outputFile (sourceReleasePropertiesFile)
2754 releaseProps.each{ key, val -> property key, val }
2755 property "git.branch", gitBranch
2756 property "git.hash", gitHash
2759 outputs.file(outputFile)
2762 task sourceDist(type: Tar) {
2763 group "distribution"
2764 description "Create a source .tar.gz file for distribution"
2766 dependsOn createBuildProperties
2767 dependsOn convertMdFiles
2768 dependsOn eclipseAllPreferences
2769 dependsOn createSourceReleaseProperties
2772 def outputFileName = "${project.name}_${JALVIEW_VERSION_UNDERSCORES}.tar.gz"
2773 archiveFileName = outputFileName
2775 compression Compression.GZIP
2790 "**/*.class","$j11modDir/**/*.jar","appletlib","**/*locales",
2792 "utils/InstallAnywhere",
2807 "gradle.properties",
2819 ".settings/org.eclipse.buildship.core.prefs",
2820 ".settings/org.eclipse.jdt.core.prefs"
2824 exclude (EXCLUDE_FILES)
2825 include (PROCESS_FILES)
2826 filter(ReplaceTokens,
2830 'Version-Rel': JALVIEW_VERSION,
2831 'Year-Rel': getDate("yyyy")
2836 exclude (EXCLUDE_FILES)
2837 exclude (PROCESS_FILES)
2838 exclude ("appletlib")
2839 exclude ("**/*locales")
2840 exclude ("*locales/**")
2841 exclude ("utils/InstallAnywhere")
2843 exclude (getdown_files_dir)
2844 // getdown_website_dir and getdown_archive_dir moved to build/website/docroot/getdown
2845 //exclude (getdown_website_dir)
2846 //exclude (getdown_archive_dir)
2848 // exluding these as not using jars as modules yet
2849 exclude ("${j11modDir}/**/*.jar")
2852 include(INCLUDE_FILES)
2854 // from (jalviewDir) {
2855 // // explicit includes for stuff that seemed to not get included
2856 // include(fileTree("test/**/*."))
2857 // exclude(EXCLUDE_FILES)
2858 // exclude(PROCESS_FILES)
2861 from(file(buildProperties).getParent()) {
2862 include(file(buildProperties).getName())
2863 rename(file(buildProperties).getName(), "build_properties")
2865 line.replaceAll("^INSTALLATION=.*\$","INSTALLATION=Source Release"+" git-commit\\\\:"+gitHash+" ["+gitBranch+"]")
2869 def sourceTarBuildDir = "${buildDir}/sourceTar"
2870 from(sourceTarBuildDir) {
2871 // this includes the appended RELEASE properties file
2875 task dataInstallersJson {
2877 description "Create the installers-VERSION.json data file for installer files created"
2879 mustRunAfter installers
2880 mustRunAfter shadowJar
2881 mustRunAfter sourceDist
2882 mustRunAfter getdownArchive
2884 def installersOutputTxt = file("${jalviewDir}/${install4jBuildDir}/output.txt")
2885 def installersSha256 = file("${jalviewDir}/${install4jBuildDir}/sha256sums")
2887 if (installersOutputTxt.exists()) {
2888 inputs.file(installersOutputTxt)
2890 if (install4jCheckSums && installersSha256.exists()) {
2891 inputs.file(installersSha256)
2894 shadowJar.archiveFile, // executable JAR
2895 getdownVersionLaunchJvl, // version JVL
2896 sourceDist.archiveFile // source TGZ
2897 ].each { fileName ->
2898 if (file(fileName).exists()) {
2899 inputs.file(fileName)
2903 outputs.file(hugoDataJsonFile)
2906 writeDataJsonFile(installersOutputTxt, installersSha256, hugoDataJsonFile)
2912 description "Copies all help pages to build dir. Runs ant task 'pubhtmlhelp'."
2915 dependsOn pubhtmlhelp
2917 inputs.dir("${helpBuildDir}/${help_dir}")
2918 outputs.dir("${buildDir}/distributions/${help_dir}")
2922 task j2sSetHeadlessBuild {
2929 task jalviewjsEnableAltFileProperty(type: WriteProperties) {
2931 description "Enable the alternative J2S Config file for headless build"
2933 outputFile = jalviewjsJ2sSettingsFileName
2934 def j2sPropsFile = file(jalviewjsJ2sSettingsFileName)
2935 def j2sProps = new Properties()
2936 if (j2sPropsFile.exists()) {
2938 def j2sPropsFileFIS = new FileInputStream(j2sPropsFile)
2939 j2sProps.load(j2sPropsFileFIS)
2940 j2sPropsFileFIS.close()
2942 j2sProps.each { prop, val ->
2945 } catch (Exception e) {
2946 println("Exception reading ${jalviewjsJ2sSettingsFileName}")
2950 if (! j2sProps.stringPropertyNames().contains(jalviewjs_j2s_alt_file_property_config)) {
2951 property(jalviewjs_j2s_alt_file_property_config, jalviewjs_j2s_alt_file_property)
2956 task jalviewjsSetEclipseWorkspace {
2957 def propKey = "jalviewjs_eclipse_workspace"
2959 if (project.hasProperty(propKey)) {
2960 propVal = project.getProperty(propKey)
2961 if (propVal.startsWith("~/")) {
2962 propVal = System.getProperty("user.home") + propVal.substring(1)
2965 def propsFileName = "${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_eclipse_workspace_location_file}"
2966 def propsFile = file(propsFileName)
2967 def eclipseWsDir = propVal
2968 def props = new Properties()
2970 def writeProps = true
2971 if (( eclipseWsDir == null || !file(eclipseWsDir).exists() ) && propsFile.exists()) {
2972 def ins = new FileInputStream(propsFileName)
2975 if (props.getProperty(propKey, null) != null) {
2976 eclipseWsDir = props.getProperty(propKey)
2981 if (eclipseWsDir == null || !file(eclipseWsDir).exists()) {
2982 def tempDir = File.createTempDir()
2983 eclipseWsDir = tempDir.getAbsolutePath()
2986 eclipseWorkspace = file(eclipseWsDir)
2989 // do not run a headless transpile when we claim to be in Eclipse
2991 println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
2992 throw new StopExecutionException("Not running headless transpile whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
2994 println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
2998 props.setProperty(propKey, eclipseWsDir)
2999 propsFile.parentFile.mkdirs()
3000 def bytes = new ByteArrayOutputStream()
3001 props.store(bytes, null)
3002 def propertiesString = bytes.toString()
3003 propsFile.text = propertiesString
3009 println("ECLIPSE WORKSPACE: "+eclipseWorkspace.getPath())
3012 //inputs.property(propKey, eclipseWsDir) // eclipseWsDir only gets set once this task runs, so will be out-of-date
3013 outputs.file(propsFileName)
3014 outputs.upToDateWhen { eclipseWorkspace.exists() && propsFile.exists() }
3018 task jalviewjsEclipsePaths {
3021 def eclipseRoot = jalviewjs_eclipse_root
3022 if (eclipseRoot.startsWith("~/")) {
3023 eclipseRoot = System.getProperty("user.home") + eclipseRoot.substring(1)
3025 if (OperatingSystem.current().isMacOsX()) {
3026 eclipseRoot += "/Eclipse.app"
3027 eclipseBinary = "${eclipseRoot}/Contents/MacOS/eclipse"
3028 eclipseProduct = "${eclipseRoot}/Contents/Eclipse/.eclipseproduct"
3029 } else if (OperatingSystem.current().isWindows()) { // check these paths!!
3030 if (file("${eclipseRoot}/eclipse").isDirectory() && file("${eclipseRoot}/eclipse/.eclipseproduct").exists()) {
3031 eclipseRoot += "/eclipse"
3033 eclipseBinary = "${eclipseRoot}/eclipse.exe"
3034 eclipseProduct = "${eclipseRoot}/.eclipseproduct"
3035 } else { // linux or unix
3036 if (file("${eclipseRoot}/eclipse").isDirectory() && file("${eclipseRoot}/eclipse/.eclipseproduct").exists()) {
3037 eclipseRoot += "/eclipse"
3038 println("eclipseDir exists")
3040 eclipseBinary = "${eclipseRoot}/eclipse"
3041 eclipseProduct = "${eclipseRoot}/.eclipseproduct"
3044 eclipseVersion = "4.13" // default
3045 def assumedVersion = true
3046 if (file(eclipseProduct).exists()) {
3047 def fis = new FileInputStream(eclipseProduct)
3048 def props = new Properties()
3050 eclipseVersion = props.getProperty("version")
3052 assumedVersion = false
3055 def propKey = "eclipse_debug"
3056 eclipseDebug = (project.hasProperty(propKey) && project.getProperty(propKey).equals("true"))
3059 // do not run a headless transpile when we claim to be in Eclipse
3061 println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3062 throw new StopExecutionException("Not running headless transpile whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
3064 println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3067 if (!assumedVersion) {
3068 println("ECLIPSE VERSION=${eclipseVersion}")
3074 task printProperties {
3076 description "Output to console all System.properties"
3078 System.properties.each { key, val -> System.out.println("Property: ${key}=${val}") }
3084 dependsOn eclipseProject
3085 dependsOn eclipseClasspath
3086 dependsOn eclipseJdt
3090 // this version (type: Copy) will delete anything in the eclipse dropins folder that isn't in fromDropinsDir
3091 task jalviewjsEclipseCopyDropins(type: Copy) {
3092 dependsOn jalviewjsEclipsePaths
3094 def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjs_eclipse_dropins_dir}", include: "*.jar")
3095 inputFiles += file("${jalviewDir}/${jalviewjsJ2sPlugin}")
3096 def outputDir = "${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_eclipse_tmp_dropins_dir}"
3103 // this eclipse -clean doesn't actually work
3104 task jalviewjsCleanEclipse(type: Exec) {
3105 dependsOn eclipseSetup
3106 dependsOn jalviewjsEclipsePaths
3107 dependsOn jalviewjsEclipseCopyDropins
3109 executable(eclipseBinary)
3110 args(["-nosplash", "--launcher.suppressErrors", "-data", eclipseWorkspace.getPath(), "-clean", "-console", "-consoleLog"])
3116 def inputString = """exit
3119 def inputByteStream = new ByteArrayInputStream(inputString.getBytes())
3120 standardInput = inputByteStream
3123 /* not really working yet
3124 jalviewjsEclipseCopyDropins.finalizedBy jalviewjsCleanEclipse
3128 task jalviewjsTransferUnzipSwingJs {
3129 def file_zip = "${jalviewDir}/${jalviewjs_swingjs_zip}"
3133 from zipTree(file_zip)
3134 into "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}"
3138 inputs.file file_zip
3139 outputs.dir "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}"
3143 task jalviewjsTransferUnzipLib {
3144 def zipFiles = fileTree(dir: "${jalviewDir}/${jalviewjs_libjs_dir}", include: "*.zip")
3147 zipFiles.each { file_zip ->
3149 from zipTree(file_zip)
3150 into "${jalviewDir}/${jalviewjsTransferSiteLibDir}"
3155 inputs.files zipFiles
3156 outputs.dir "${jalviewDir}/${jalviewjsTransferSiteLibDir}"
3160 task jalviewjsTransferUnzipAllLibs {
3161 dependsOn jalviewjsTransferUnzipSwingJs
3162 dependsOn jalviewjsTransferUnzipLib
3166 task jalviewjsCreateJ2sSettings(type: WriteProperties) {
3168 description "Create the alternative j2s file from the j2s.* properties"
3170 jalviewjsJ2sProps = project.properties.findAll { it.key.startsWith("j2s.") }.sort { it.key }
3171 def siteDirProperty = "j2s.site.directory"
3172 def setSiteDir = false
3173 jalviewjsJ2sProps.each { prop, val ->
3175 if (prop == siteDirProperty) {
3176 if (!(val.startsWith('/') || val.startsWith("file://") )) {
3177 val = "${jalviewDir}/${jalviewjsTransferSiteJsDir}/${val}"
3183 if (!setSiteDir) { // default site location, don't override specifically set property
3184 property(siteDirProperty,"${jalviewDirRelativePath}/${jalviewjsTransferSiteJsDir}")
3187 outputFile = jalviewjsJ2sAltSettingsFileName
3190 inputs.properties(jalviewjsJ2sProps)
3191 outputs.file(jalviewjsJ2sAltSettingsFileName)
3196 task jalviewjsEclipseSetup {
3197 dependsOn jalviewjsEclipseCopyDropins
3198 dependsOn jalviewjsSetEclipseWorkspace
3199 dependsOn jalviewjsCreateJ2sSettings
3203 task jalviewjsSyncAllLibs (type: Sync) {
3204 dependsOn jalviewjsTransferUnzipAllLibs
3205 def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjsTransferSiteLibDir}")
3206 inputFiles += fileTree(dir: "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}")
3207 def outputDir = "${jalviewDir}/${jalviewjsSiteDir}"
3211 def outputFiles = []
3212 rename { filename ->
3213 outputFiles += "${outputDir}/${filename}"
3220 // should this be exclude really ?
3221 duplicatesStrategy "INCLUDE"
3223 outputs.files outputFiles
3224 inputs.files inputFiles
3228 task jalviewjsSyncResources (type: Sync) {
3229 dependsOn buildResources
3231 def inputFiles = fileTree(dir: resourcesBuildDir)
3232 def outputDir = "${jalviewDir}/${jalviewjsSiteDir}/${jalviewjs_j2s_subdir}"
3236 def outputFiles = []
3237 rename { filename ->
3238 outputFiles += "${outputDir}/${filename}"
3244 outputs.files outputFiles
3245 inputs.files inputFiles
3249 task jalviewjsSyncSiteResources (type: Sync) {
3250 def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjs_site_resource_dir}")
3251 def outputDir = "${jalviewDir}/${jalviewjsSiteDir}"
3255 def outputFiles = []
3256 rename { filename ->
3257 outputFiles += "${outputDir}/${filename}"
3263 outputs.files outputFiles
3264 inputs.files inputFiles
3268 task jalviewjsSyncBuildProperties (type: Sync) {
3269 dependsOn createBuildProperties
3270 def inputFiles = [file(buildProperties)]
3271 def outputDir = "${jalviewDir}/${jalviewjsSiteDir}/${jalviewjs_j2s_subdir}"
3275 def outputFiles = []
3276 rename { filename ->
3277 outputFiles += "${outputDir}/${filename}"
3283 outputs.files outputFiles
3284 inputs.files inputFiles
3288 task jalviewjsProjectImport(type: Exec) {
3289 dependsOn eclipseSetup
3290 dependsOn jalviewjsEclipsePaths
3291 dependsOn jalviewjsEclipseSetup
3294 // do not run a headless import when we claim to be in Eclipse
3296 println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3297 throw new StopExecutionException("Not running headless import whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
3299 println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3303 //def projdir = eclipseWorkspace.getPath()+"/.metadata/.plugins/org.eclipse.core.resources/.projects/jalview/org.eclipse.jdt.core"
3304 def projdir = eclipseWorkspace.getPath()+"/.metadata/.plugins/org.eclipse.core.resources/.projects/jalview"
3305 executable(eclipseBinary)
3306 args(["-nosplash", "--launcher.suppressErrors", "-application", "com.seeq.eclipse.importprojects.headlessimport", "-data", eclipseWorkspace.getPath(), "-import", jalviewDirAbsolutePath])
3310 args += [ "--launcher.appendVmargs", "-vmargs", "-Dorg.eclipse.equinox.p2.reconciler.dropins.directory=${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_eclipse_tmp_dropins_dir}" ]
3312 args += [ "-D${j2sHeadlessBuildProperty}=true" ]
3313 args += [ "-D${jalviewjs_j2s_alt_file_property}=${jalviewjsJ2sAltSettingsFileName}" ]
3316 inputs.file("${jalviewDir}/.project")
3317 outputs.upToDateWhen {
3318 file(projdir).exists()
3323 task jalviewjsTranspile(type: Exec) {
3324 dependsOn jalviewjsEclipseSetup
3325 dependsOn jalviewjsProjectImport
3326 dependsOn jalviewjsEclipsePaths
3328 dependsOn jalviewjsEnableAltFileProperty
3332 // do not run a headless transpile when we claim to be in Eclipse
3334 println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3335 throw new StopExecutionException("Not running headless transpile whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
3337 println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3341 executable(eclipseBinary)
3342 args(["-nosplash", "--launcher.suppressErrors", "-application", "org.eclipse.jdt.apt.core.aptBuild", "-data", eclipseWorkspace, "-${jalviewjs_eclipse_build_arg}", eclipse_project_name ])
3346 args += [ "--launcher.appendVmargs", "-vmargs", "-Dorg.eclipse.equinox.p2.reconciler.dropins.directory=${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_eclipse_tmp_dropins_dir}" ]
3348 args += [ "-D${j2sHeadlessBuildProperty}=true" ]
3349 args += [ "-D${jalviewjs_j2s_alt_file_property}=${jalviewjsJ2sAltSettingsFileName}" ]
3355 stdout = new ByteArrayOutputStream()
3356 stderr = new ByteArrayOutputStream()
3358 def logOutFileName = "${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}"
3359 def logOutFile = file(logOutFileName)
3360 logOutFile.createNewFile()
3361 logOutFile.text = """ROOT: ${jalviewjs_eclipse_root}
3362 BINARY: ${eclipseBinary}
3363 VERSION: ${eclipseVersion}
3364 WORKSPACE: ${eclipseWorkspace}
3365 DEBUG: ${eclipseDebug}
3368 def logOutFOS = new FileOutputStream(logOutFile, true) // true == append
3369 // combine stdout and stderr
3370 def logErrFOS = logOutFOS
3372 if (jalviewjs_j2s_to_console.equals("true")) {
3373 standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
3374 new org.apache.tools.ant.util.TeeOutputStream(
3378 errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
3379 new org.apache.tools.ant.util.TeeOutputStream(
3384 standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
3387 errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
3394 if (stdout.toString().contains("Error processing ")) {
3395 // j2s did not complete transpile
3396 //throw new TaskExecutionException("Error during transpilation:\n${stderr}\nSee eclipse transpile log file '${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}'")
3397 if (jalviewjs_ignore_transpile_errors.equals("true")) {
3398 println("IGNORING TRANSPILE ERRORS")
3399 println("See eclipse transpile log file '${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}'")
3401 throw new GradleException("Error during transpilation:\n${stderr}\nSee eclipse transpile log file '${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}'")
3406 inputs.dir("${jalviewDir}/${sourceDir}")
3407 outputs.dir("${jalviewDir}/${jalviewjsTransferSiteJsDir}")
3408 outputs.upToDateWhen( { file("${jalviewDir}/${jalviewjsTransferSiteJsDir}${jalviewjs_server_resource}").exists() } )
3412 def jalviewjsCallCore(String name, FileCollection list, String prefixFile, String suffixFile, String jsfile, String zjsfile, File logOutFile, Boolean logOutConsole) {
3414 def stdout = new ByteArrayOutputStream()
3415 def stderr = new ByteArrayOutputStream()
3417 def coreFile = file(jsfile)
3419 msg = "Creating core for ${name}...\nGenerating ${jsfile}"
3421 logOutFile.createNewFile()
3422 logOutFile.append(msg+"\n")
3424 def coreTop = file(prefixFile)
3425 def coreBottom = file(suffixFile)
3426 coreFile.getParentFile().mkdirs()
3427 coreFile.createNewFile()
3428 coreFile.write( coreTop.getText("UTF-8") )
3432 def t = f.getText("UTF-8")
3433 t.replaceAll("Clazz\\.([^_])","Clazz_${1}")
3434 coreFile.append( t )
3436 msg = "...file '"+f.getPath()+"' does not exist, skipping"
3438 logOutFile.append(msg+"\n")
3441 coreFile.append( coreBottom.getText("UTF-8") )
3443 msg = "Generating ${zjsfile}"
3445 logOutFile.append(msg+"\n")
3446 def logOutFOS = new FileOutputStream(logOutFile, true) // true == append
3447 def logErrFOS = logOutFOS
3450 classpath = files(["${jalviewDir}/${jalviewjs_closure_compiler}"])
3451 main = "com.google.javascript.jscomp.CommandLineRunner"
3452 jvmArgs = [ "-Dfile.encoding=UTF-8" ]
3453 args = [ "--compilation_level", "SIMPLE_OPTIMIZATIONS", "--warning_level", "QUIET", "--charset", "UTF-8", "--js", jsfile, "--js_output_file", zjsfile ]
3456 msg = "\nRunning '"+commandLine.join(' ')+"'\n"
3458 logOutFile.append(msg+"\n")
3460 if (logOutConsole) {
3461 standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
3462 new org.apache.tools.ant.util.TeeOutputStream(
3466 errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
3467 new org.apache.tools.ant.util.TeeOutputStream(
3472 standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
3475 errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
3482 logOutFile.append(msg+"\n")
3486 task jalviewjsBuildAllCores {
3488 description "Build the core js lib closures listed in the classlists dir"
3489 dependsOn jalviewjsTranspile
3490 dependsOn jalviewjsTransferUnzipSwingJs
3492 def j2sDir = "${jalviewDir}/${jalviewjsTransferSiteJsDir}/${jalviewjs_j2s_subdir}"
3493 def swingJ2sDir = "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}/${jalviewjs_j2s_subdir}"
3494 def libJ2sDir = "${jalviewDir}/${jalviewjsTransferSiteLibDir}/${jalviewjs_j2s_subdir}"
3495 def jsDir = "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}/${jalviewjs_js_subdir}"
3496 def outputDir = "${jalviewDir}/${jalviewjsTransferSiteCoreDir}/${jalviewjs_j2s_subdir}/core"
3497 def prefixFile = "${jsDir}/core/coretop2.js"
3498 def suffixFile = "${jsDir}/core/corebottom2.js"
3500 inputs.file prefixFile
3501 inputs.file suffixFile
3503 def classlistFiles = []
3504 // add the classlists found int the jalviewjs_classlists_dir
3505 fileTree(dir: "${jalviewDir}/${jalviewjs_classlists_dir}", include: "*.txt").each {
3507 def name = file.getName() - ".txt"
3514 // _jmol and _jalview cores. Add any other peculiar classlist.txt files here
3515 //classlistFiles += [ 'file': file("${jalviewDir}/${jalviewjs_classlist_jmol}"), 'name': "_jvjmol" ]
3516 classlistFiles += [ 'file': file("${jalviewDir}/${jalviewjs_classlist_jalview}"), 'name': jalviewjsJalviewCoreName ]
3518 jalviewjsCoreClasslists = []
3520 classlistFiles.each {
3523 def file = hash['file']
3524 if (! file.exists()) {
3525 //println("...classlist file '"+file.getPath()+"' does not exist, skipping")
3526 return false // this is a "continue" in groovy .each closure
3528 def name = hash['name']
3530 name = file.getName() - ".txt"
3538 def list = fileTree(dir: j2sDir, includes: filelist)
3540 def jsfile = "${outputDir}/core${name}.js"
3541 def zjsfile = "${outputDir}/core${name}.z.js"
3543 jalviewjsCoreClasslists += [
3552 outputs.file(jsfile)
3553 outputs.file(zjsfile)
3556 // _stevesoft core. add any cores without a classlist here (and the inputs and outputs)
3557 def stevesoftClasslistName = "_stevesoft"
3558 def stevesoftClasslist = [
3559 'jsfile': "${outputDir}/core${stevesoftClasslistName}.js",
3560 'zjsfile': "${outputDir}/core${stevesoftClasslistName}.z.js",
3561 'list': fileTree(dir: j2sDir, include: "com/stevesoft/pat/**/*.js"),
3562 'name': stevesoftClasslistName
3564 jalviewjsCoreClasslists += stevesoftClasslist
3565 inputs.files(stevesoftClasslist['list'])
3566 outputs.file(stevesoftClasslist['jsfile'])
3567 outputs.file(stevesoftClasslist['zjsfile'])
3570 def allClasslistName = "_all"
3571 def allJsFiles = fileTree(dir: j2sDir, include: "**/*.js")
3572 allJsFiles += fileTree(
3576 // these exlusions are files that the closure-compiler produces errors for. Should fix them
3577 "**/org/jmol/jvxl/readers/IsoIntersectFileReader.js",
3578 "**/org/jmol/export/JSExporter.js"
3581 allJsFiles += fileTree(
3585 // these exlusions are files that the closure-compiler produces errors for. Should fix them
3586 "**/sun/misc/Unsafe.js",
3587 "**/swingjs/jquery/jquery-editable-select.js",
3588 "**/swingjs/jquery/j2sComboBox.js",
3589 "**/sun/misc/FloatingDecimal.js"
3592 def allClasslist = [
3593 'jsfile': "${outputDir}/core${allClasslistName}.js",
3594 'zjsfile': "${outputDir}/core${allClasslistName}.z.js",
3596 'name': allClasslistName
3598 // not including this version of "all" core at the moment
3599 //jalviewjsCoreClasslists += allClasslist
3600 inputs.files(allClasslist['list'])
3601 outputs.file(allClasslist['jsfile'])
3602 outputs.file(allClasslist['zjsfile'])
3605 def logOutFile = file("${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_j2s_closure_stdout}")
3606 logOutFile.getParentFile().mkdirs()
3607 logOutFile.createNewFile()
3608 logOutFile.write(getDate("yyyy-MM-dd HH:mm:ss")+" jalviewjsBuildAllCores\n----\n")
3610 jalviewjsCoreClasslists.each {
3611 jalviewjsCallCore(it.name, it.list, prefixFile, suffixFile, it.jsfile, it.zjsfile, logOutFile, jalviewjs_j2s_to_console.equals("true"))
3618 def jalviewjsPublishCoreTemplate(String coreName, String templateName, File inputFile, String outputFile) {
3621 into file(outputFile).getParentFile()
3622 rename { filename ->
3623 if (filename.equals(inputFile.getName())) {
3624 return file(outputFile).getName()
3628 filter(ReplaceTokens,
3632 'MAIN': '"'+main_class+'"',
3634 'NAME': jalviewjsJalviewTemplateName+" [core ${coreName}]",
3635 'COREKEY': jalviewjs_core_key,
3636 'CORENAME': coreName
3643 task jalviewjsPublishCoreTemplates {
3644 dependsOn jalviewjsBuildAllCores
3645 def inputFileName = "${jalviewDir}/${j2s_coretemplate_html}"
3646 def inputFile = file(inputFileName)
3647 def outputDir = "${jalviewDir}/${jalviewjsTransferSiteCoreDir}"
3649 def outputFiles = []
3650 jalviewjsCoreClasslists.each { cl ->
3651 def outputFile = "${outputDir}/${jalviewjsJalviewTemplateName}_${cl.name}.html"
3652 cl['outputfile'] = outputFile
3653 outputFiles += outputFile
3657 jalviewjsCoreClasslists.each { cl ->
3658 jalviewjsPublishCoreTemplate(cl.name, jalviewjsJalviewTemplateName, inputFile, cl.outputfile)
3661 inputs.file(inputFile)
3662 outputs.files(outputFiles)
3666 task jalviewjsSyncCore (type: Sync) {
3667 dependsOn jalviewjsBuildAllCores
3668 dependsOn jalviewjsPublishCoreTemplates
3669 def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjsTransferSiteCoreDir}")
3670 def outputDir = "${jalviewDir}/${jalviewjsSiteDir}"
3674 def outputFiles = []
3675 rename { filename ->
3676 outputFiles += "${outputDir}/${filename}"
3682 outputs.files outputFiles
3683 inputs.files inputFiles
3687 // this Copy version of TransferSiteJs will delete anything else in the target dir
3688 task jalviewjsCopyTransferSiteJs(type: Copy) {
3689 dependsOn jalviewjsTranspile
3690 from "${jalviewDir}/${jalviewjsTransferSiteJsDir}"
3691 into "${jalviewDir}/${jalviewjsSiteDir}"
3695 // this Sync version of TransferSite is used by buildship to keep the website automatically up to date when a file changes
3696 task jalviewjsSyncTransferSiteJs(type: Sync) {
3697 from "${jalviewDir}/${jalviewjsTransferSiteJsDir}"
3699 into "${jalviewDir}/${jalviewjsSiteDir}"
3706 jalviewjsSyncAllLibs.mustRunAfter jalviewjsCopyTransferSiteJs
3707 jalviewjsSyncResources.mustRunAfter jalviewjsCopyTransferSiteJs
3708 jalviewjsSyncSiteResources.mustRunAfter jalviewjsCopyTransferSiteJs
3709 jalviewjsSyncBuildProperties.mustRunAfter jalviewjsCopyTransferSiteJs
3711 jalviewjsSyncAllLibs.mustRunAfter jalviewjsSyncTransferSiteJs
3712 jalviewjsSyncResources.mustRunAfter jalviewjsSyncTransferSiteJs
3713 jalviewjsSyncSiteResources.mustRunAfter jalviewjsSyncTransferSiteJs
3714 jalviewjsSyncBuildProperties.mustRunAfter jalviewjsSyncTransferSiteJs
3717 task jalviewjsPrepareSite {
3719 description "Prepares the website folder including unzipping files and copying resources"
3720 dependsOn jalviewjsSyncAllLibs
3721 dependsOn jalviewjsSyncResources
3722 dependsOn jalviewjsSyncSiteResources
3723 dependsOn jalviewjsSyncBuildProperties
3724 dependsOn jalviewjsSyncCore
3728 task jalviewjsBuildSite {
3730 description "Builds the whole website including transpiled code"
3731 dependsOn jalviewjsCopyTransferSiteJs
3732 dependsOn jalviewjsPrepareSite
3736 task cleanJalviewjsTransferSite {
3738 delete "${jalviewDir}/${jalviewjsTransferSiteJsDir}"
3739 delete "${jalviewDir}/${jalviewjsTransferSiteLibDir}"
3740 delete "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}"
3741 delete "${jalviewDir}/${jalviewjsTransferSiteCoreDir}"
3746 task cleanJalviewjsSite {
3747 dependsOn cleanJalviewjsTransferSite
3749 delete "${jalviewDir}/${jalviewjsSiteDir}"
3754 task jalviewjsSiteTar(type: Tar) {
3756 description "Creates a tar.gz file for the website"
3757 dependsOn jalviewjsBuildSite
3758 def outputFilename = "jalviewjs-site-${JALVIEW_VERSION}.tar.gz"
3759 archiveFileName = outputFilename
3761 compression Compression.GZIP
3763 from "${jalviewDir}/${jalviewjsSiteDir}"
3764 into jalviewjs_site_dir // this is inside the tar file
3766 inputs.dir("${jalviewDir}/${jalviewjsSiteDir}")
3770 task jalviewjsServer {
3772 def filename = "jalviewjsTest.html"
3773 description "Starts a webserver on localhost to test the website. See ${filename} to access local site on most recently used port."
3774 def htmlFile = "${jalviewDirAbsolutePath}/${filename}"
3779 def f = Class.forName("org.gradle.plugins.javascript.envjs.http.simple.SimpleHttpFileServerFactory")
3780 factory = f.newInstance()
3781 } catch (ClassNotFoundException e) {
3782 throw new GradleException("Unable to create SimpleHttpFileServerFactory")
3784 def port = Integer.valueOf(jalviewjs_server_port)
3789 while(port < start+1000 && !running) {
3791 def doc_root = new File("${jalviewDirAbsolutePath}/${jalviewjsSiteDir}")
3792 jalviewjsServer = factory.start(doc_root, port)
3794 url = jalviewjsServer.getResourceUrl(jalviewjs_server_resource)
3795 println("SERVER STARTED with document root ${doc_root}.")
3796 println("Go to "+url+" . Run gradle --stop to stop (kills all gradle daemons).")
3797 println("For debug: "+url+"?j2sdebug")
3798 println("For verbose: "+url+"?j2sverbose")
3799 } catch (Exception e) {
3804 <p><a href="${url}">JalviewJS Test. <${url}></a></p>
3805 <p><a href="${url}?j2sdebug">JalviewJS Test with debug. <${url}?j2sdebug></a></p>
3806 <p><a href="${url}?j2sverbose">JalviewJS Test with verbose. <${url}?j2sdebug></a></p>
3808 jalviewjsCoreClasslists.each { cl ->
3809 def urlcore = jalviewjsServer.getResourceUrl(file(cl.outputfile).getName())
3811 <p><a href="${urlcore}">${jalviewjsJalviewTemplateName} [core ${cl.name}]. <${urlcore}></a></p>
3813 println("For core ${cl.name}: "+urlcore)
3816 file(htmlFile).text = htmlText
3819 outputs.file(htmlFile)
3820 outputs.upToDateWhen({false})
3824 task cleanJalviewjsAll {
3826 description "Delete all configuration and build artifacts to do with JalviewJS build"
3827 dependsOn cleanJalviewjsSite
3828 dependsOn jalviewjsEclipsePaths
3831 delete "${jalviewDir}/${jalviewjsBuildDir}"
3832 delete "${jalviewDir}/${eclipse_bin_dir}"
3833 if (eclipseWorkspace != null && file(eclipseWorkspace.getAbsolutePath()+"/.metadata").exists()) {
3834 delete file(eclipseWorkspace.getAbsolutePath()+"/.metadata")
3836 delete jalviewjsJ2sAltSettingsFileName
3839 outputs.upToDateWhen( { false } )
3843 task jalviewjsIDE_checkJ2sPlugin {
3844 group "00 JalviewJS in Eclipse"
3845 description "Compare the swingjs/net.sf.j2s.core(-j11)?.jar file with the Eclipse IDE's plugin version (found in the 'dropins' dir)"
3848 def j2sPlugin = string("${jalviewDir}/${jalviewjsJ2sPlugin}")
3849 def j2sPluginFile = file(j2sPlugin)
3850 def eclipseHome = System.properties["eclipse.home.location"]
3851 if (eclipseHome == null || ! IN_ECLIPSE) {
3852 throw new StopExecutionException("Cannot find running Eclipse home from System.properties['eclipse.home.location']. Skipping J2S Plugin Check.")
3854 def eclipseJ2sPluginDirs = [ "${eclipseHome}/dropins" ]
3855 def altPluginsDir = System.properties["org.eclipse.equinox.p2.reconciler.dropins.directory"]
3856 if (altPluginsDir != null && file(altPluginsDir).exists()) {
3857 eclipseJ2sPluginDirs += altPluginsDir
3859 def foundPlugin = false
3860 def j2sPluginFileName = j2sPluginFile.getName()
3861 def eclipseJ2sPlugin
3862 def eclipseJ2sPluginFile
3863 eclipseJ2sPluginDirs.any { dir ->
3864 eclipseJ2sPlugin = "${dir}/${j2sPluginFileName}"
3865 eclipseJ2sPluginFile = file(eclipseJ2sPlugin)
3866 if (eclipseJ2sPluginFile.exists()) {
3872 def msg = "Eclipse J2S Plugin is not installed (could not find '${j2sPluginFileName}' in\n"+eclipseJ2sPluginDirs.join("\n")+"\n)\nTry running task jalviewjsIDE_copyJ2sPlugin"
3873 System.err.println(msg)
3874 throw new StopExecutionException(msg)
3877 def digest = MessageDigest.getInstance("MD5")
3879 digest.update(j2sPluginFile.text.bytes)
3880 def j2sPluginMd5 = new BigInteger(1, digest.digest()).toString(16).padLeft(32, '0')
3882 digest.update(eclipseJ2sPluginFile.text.bytes)
3883 def eclipseJ2sPluginMd5 = new BigInteger(1, digest.digest()).toString(16).padLeft(32, '0')
3885 if (j2sPluginMd5 != eclipseJ2sPluginMd5) {
3886 def msg = "WARNING! Eclipse J2S Plugin '${eclipseJ2sPlugin}' is different to this commit's version '${j2sPlugin}'"
3887 System.err.println(msg)
3888 throw new StopExecutionException(msg)
3890 def msg = "Eclipse J2S Plugin '${eclipseJ2sPlugin}' is the same as '${j2sPlugin}' (this is good)"
3896 task jalviewjsIDE_copyJ2sPlugin {
3897 group "00 JalviewJS in Eclipse"
3898 description "Copy the swingjs/net.sf.j2s.core(-j11)?.jar file into the Eclipse IDE's 'dropins' dir"
3901 def j2sPlugin = string("${jalviewDir}/${jalviewjsJ2sPlugin}")
3902 def j2sPluginFile = file(j2sPlugin)
3903 def eclipseHome = System.properties["eclipse.home.location"]
3904 if (eclipseHome == null || ! IN_ECLIPSE) {
3905 throw new StopExecutionException("Cannot find running Eclipse home from System.properties['eclipse.home.location']. NOT copying J2S Plugin.")
3907 def eclipseJ2sPlugin = "${eclipseHome}/dropins/${j2sPluginFile.getName()}"
3908 def eclipseJ2sPluginFile = file(eclipseJ2sPlugin)
3909 def msg = "WARNING! Copying this commit's j2s plugin '${j2sPlugin}' to Eclipse J2S Plugin '${eclipseJ2sPlugin}'\n* May require an Eclipse restart"
3910 System.err.println(msg)
3913 eclipseJ2sPluginFile.getParentFile().mkdirs()
3914 into eclipseJ2sPluginFile.getParent()
3920 task jalviewjsIDE_j2sFile {
3921 group "00 JalviewJS in Eclipse"
3922 description "Creates the .j2s file"
3923 dependsOn jalviewjsCreateJ2sSettings
3927 task jalviewjsIDE_SyncCore {
3928 group "00 JalviewJS in Eclipse"
3929 description "Build the core js lib closures listed in the classlists dir and publish core html from template"
3930 dependsOn jalviewjsSyncCore
3934 task jalviewjsIDE_SyncSiteAll {
3935 dependsOn jalviewjsSyncAllLibs
3936 dependsOn jalviewjsSyncResources
3937 dependsOn jalviewjsSyncSiteResources
3938 dependsOn jalviewjsSyncBuildProperties
3942 cleanJalviewjsTransferSite.mustRunAfter jalviewjsIDE_SyncSiteAll
3945 task jalviewjsIDE_PrepareSite {
3946 group "00 JalviewJS in Eclipse"
3947 description "Sync libs and resources to site dir, but not closure cores"
3949 dependsOn jalviewjsIDE_SyncSiteAll
3950 //dependsOn cleanJalviewjsTransferSite // not sure why this clean is here -- will slow down a re-run of this task
3954 task jalviewjsIDE_AssembleSite {
3955 group "00 JalviewJS in Eclipse"
3956 description "Assembles unzipped supporting zipfiles, resources, site resources and closure cores into the Eclipse transpiled site"
3957 dependsOn jalviewjsPrepareSite
3961 task jalviewjsIDE_SiteClean {
3962 group "00 JalviewJS in Eclipse"
3963 description "Deletes the Eclipse transpiled site"
3964 dependsOn cleanJalviewjsSite
3968 task jalviewjsIDE_Server {
3969 group "00 JalviewJS in Eclipse"
3970 description "Starts a webserver on localhost to test the website"
3971 dependsOn jalviewjsServer
3975 // buildship runs this at import or gradle refresh
3976 task eclipseSynchronizationTask {
3977 //dependsOn eclipseSetup
3978 dependsOn createBuildProperties
3980 dependsOn jalviewjsIDE_j2sFile
3981 dependsOn jalviewjsIDE_checkJ2sPlugin
3982 dependsOn jalviewjsIDE_PrepareSite
3987 // buildship runs this at build time or project refresh
3988 task eclipseAutoBuildTask {
3989 //dependsOn jalviewjsIDE_checkJ2sPlugin
3990 //dependsOn jalviewjsIDE_PrepareSite
3996 description "Build the site"
3997 dependsOn jalviewjsBuildSite