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 java.util.concurrent.Executors
14 import java.util.concurrent.Future
15 import java.util.concurrent.ScheduledExecutorService
16 import java.util.concurrent.TimeUnit
17 import groovy.transform.ExternalizeMethods
18 import groovy.util.XmlParser
19 import groovy.xml.XmlUtil
20 import groovy.json.JsonBuilder
21 import com.vladsch.flexmark.util.ast.Node
22 import com.vladsch.flexmark.html.HtmlRenderer
23 import com.vladsch.flexmark.parser.Parser
24 import com.vladsch.flexmark.util.data.MutableDataSet
25 import com.vladsch.flexmark.ext.gfm.tasklist.TaskListExtension
26 import com.vladsch.flexmark.ext.tables.TablesExtension
27 import com.vladsch.flexmark.ext.gfm.strikethrough.StrikethroughExtension
28 import com.vladsch.flexmark.ext.autolink.AutolinkExtension
29 import com.vladsch.flexmark.ext.anchorlink.AnchorLinkExtension
30 import com.vladsch.flexmark.ext.toc.TocExtension
31 import com.google.common.hash.HashCode
32 import com.google.common.hash.Hashing
33 import com.google.common.io.Files
34 import org.jsoup.Jsoup
35 import org.jsoup.nodes.Element
43 classpath "com.vladsch.flexmark:flexmark-all:0.62.0"
44 classpath "org.jsoup:jsoup:1.14.3"
45 classpath "com.eowise:gradle-imagemagick:0.5.1"
54 id "com.diffplug.gradle.spotless" version "3.28.0"
55 id 'com.github.johnrengelman.shadow' version '6.0.0'
56 id 'com.install4j.gradle' version '10.0.3'
57 id 'com.dorongold.task-tree' version '2.1.1' // only needed to display task dependency tree with gradle task1 [task2 ...] taskTree
58 id 'com.palantir.git-version' version '0.13.0' apply false
69 // in ext the values are cast to Object. Ensure string values are cast as String (and not GStringImpl) for later use
70 def string(Object o) {
71 return o == null ? "" : o.toString()
74 def overrideProperties(String propsFileName, boolean output = false) {
75 if (propsFileName == null) {
78 def propsFile = file(propsFileName)
79 if (propsFile != null && propsFile.exists()) {
80 println("Using properties from file '${propsFileName}'")
82 def p = new Properties()
83 def localPropsFIS = new FileInputStream(propsFile)
89 if (project.hasProperty(key)) {
90 oldval = project.findProperty(key)
91 project.setProperty(key, val)
93 println("Overriding property '${key}' ('${oldval}') with ${file(propsFile).getName()} value '${val}'")
96 ext.setProperty(key, val)
98 println("Setting ext property '${key}' with ${file(propsFile).getName()}s value '${val}'")
102 } catch (Exception e) {
103 println("Exception reading local.properties")
110 jalviewDirAbsolutePath = file(jalviewDir).getAbsolutePath()
111 jalviewDirRelativePath = jalviewDir
114 getdownChannelName = CHANNEL.toLowerCase()
115 // default to "default". Currently only has different cosmetics for "develop", "release", "default"
116 propertiesChannelName = ["develop", "release", "test-release", "jalviewjs", "jalviewjs-release" ].contains(getdownChannelName) ? getdownChannelName : "default"
117 channelDirName = propertiesChannelName
118 // Import channel_properties
119 if (getdownChannelName.startsWith("develop-")) {
120 channelDirName = "develop-SUFFIX"
122 channelDir = string("${jalviewDir}/${channel_properties_dir}/${channelDirName}")
123 channelGradleProperties = string("${channelDir}/channel_gradle.properties")
124 channelPropsFile = string("${channelDir}/${resource_dir}/${channel_props}")
125 overrideProperties(channelGradleProperties, false)
126 // local build environment properties
127 // can be "projectDir/local.properties"
128 overrideProperties("${projectDir}/local.properties", true)
129 // or "../projectDir_local.properties"
130 overrideProperties(projectDir.getParent() + "/" + projectDir.getName() + "_local.properties", true)
133 // Import releaseProps from the RELEASE file
134 // or a file specified via JALVIEW_RELEASE_FILE if defined
135 // Expect jalview.version and target release branch in jalview.release
136 releaseProps = new Properties();
137 def releasePropFile = findProperty("JALVIEW_RELEASE_FILE");
138 def defaultReleasePropFile = "${jalviewDirAbsolutePath}/RELEASE";
140 (new File(releasePropFile!=null ? releasePropFile : defaultReleasePropFile)).withInputStream {
141 releaseProps.load(it)
143 } catch (Exception fileLoadError) {
144 throw new Error("Couldn't load release properties file "+(releasePropFile==null ? defaultReleasePropFile : "from custom location: releasePropFile"),fileLoadError);
147 // Set JALVIEW_VERSION if it is not already set
148 if (findProperty("JALVIEW_VERSION")==null || "".equals(JALVIEW_VERSION)) {
149 JALVIEW_VERSION = releaseProps.get("jalview.version")
151 println("JALVIEW_VERSION is set to '${JALVIEW_VERSION}'")
153 // this property set when running Eclipse headlessly
154 j2sHeadlessBuildProperty = string("net.sf.j2s.core.headlessbuild")
155 // this property set by Eclipse
156 eclipseApplicationProperty = string("eclipse.application")
157 // CHECK IF RUNNING FROM WITHIN ECLIPSE
158 def eclipseApplicationPropertyVal = System.properties[eclipseApplicationProperty]
159 IN_ECLIPSE = eclipseApplicationPropertyVal != null && eclipseApplicationPropertyVal.startsWith("org.eclipse.ui.")
160 // BUT WITHOUT THE HEADLESS BUILD PROPERTY SET
161 if (System.properties[j2sHeadlessBuildProperty].equals("true")) {
162 println("Setting IN_ECLIPSE to ${IN_ECLIPSE} as System.properties['${j2sHeadlessBuildProperty}'] == '${System.properties[j2sHeadlessBuildProperty]}'")
166 println("WITHIN ECLIPSE IDE")
168 println("HEADLESS BUILD")
171 J2S_ENABLED = (project.hasProperty('j2s.compiler.status') && project['j2s.compiler.status'] != null && project['j2s.compiler.status'] == "enable")
173 println("J2S ENABLED")
176 System.properties.sort { it.key }.each {
177 key, val -> println("SYSTEM PROPERTY ${key}='${val}'")
180 if (false && IN_ECLIPSE) {
181 jalviewDir = jalviewDirAbsolutePath
186 buildDate = new Date().format("yyyyMMdd")
189 bareSourceDir = string(source_dir)
190 sourceDir = string("${jalviewDir}/${bareSourceDir}")
191 resourceDir = string("${jalviewDir}/${resource_dir}")
192 bareTestSourceDir = string(test_source_dir)
193 testDir = string("${jalviewDir}/${bareTestSourceDir}")
195 classesDir = string("${jalviewDir}/${classes_dir}")
196 destinationDirectory = file(classesDir)
199 useClover = clover.equals("true")
200 cloverBuildDir = "${buildDir}/clover"
201 cloverInstrDir = file("${cloverBuildDir}/clover-instr")
202 cloverClassesDir = file("${cloverBuildDir}/clover-classes")
203 cloverReportDir = file("${buildDir}/reports/clover")
204 cloverTestInstrDir = file("${cloverBuildDir}/clover-test-instr")
205 cloverTestClassesDir = file("${cloverBuildDir}/clover-test-classes")
206 //cloverTestClassesDir = cloverClassesDir
207 cloverDb = string("${cloverBuildDir}/clover.db")
209 testSourceDir = useClover ? cloverTestInstrDir : testDir
210 testClassesDir = useClover ? cloverTestClassesDir : "${jalviewDir}/${test_output_dir}"
213 backgroundImageText = BACKGROUNDIMAGETEXT
214 getdownChannelDir = string("${getdown_website_dir}/${propertiesChannelName}")
215 getdownAppBaseDir = string("${jalviewDir}/${getdownChannelDir}/${JAVA_VERSION}")
216 getdownArchiveDir = string("${jalviewDir}/${getdown_archive_dir}")
217 getdownFullArchiveDir = null
218 getdownTextLines = []
219 getdownLaunchJvl = null
220 getdownVersionLaunchJvl = null
222 buildProperties = null
224 // the following values might be overridden by the CHANNEL switch
225 getdownDir = string("${getdownChannelName}/${JAVA_VERSION}")
226 getdownAppBase = string("${getdown_channel_base}/${getdownDir}")
227 getdownArchiveAppBase = getdown_archive_base
228 getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher}")
229 getdownAppDistDir = getdown_app_dir_alt
230 getdownImagesDir = string("${jalviewDir}/${getdown_images_dir}")
231 getdownImagesBuildDir = string("${buildDir}/imagemagick/getdown")
232 getdownSetAppBaseProperty = false // whether to pass the appbase and appdistdir to the application
233 reportRsyncCommand = false
234 jvlChannelName = CHANNEL.toLowerCase()
235 install4jSuffix = CHANNEL.substring(0, 1).toUpperCase() + CHANNEL.substring(1).toLowerCase(); // BUILD -> Build
236 install4jDMGDSStore = "${install4j_images_dir}/${install4j_dmg_ds_store}"
237 install4jDMGBackgroundImageDir = "${install4j_images_dir}"
238 install4jDMGBackgroundImageBuildDir = "build/imagemagick/install4j"
239 install4jDMGBackgroundImageFile = "${install4j_dmg_background}"
240 install4jInstallerName = "${jalview_name} Non-Release Installer"
241 install4jExecutableName = install4j_executable_name
242 install4jExtraScheme = "jalviewx"
243 install4jMacIconsFile = string("${install4j_images_dir}/${install4j_mac_icons_file}")
244 install4jWindowsIconsFile = string("${install4j_images_dir}/${install4j_windows_icons_file}")
245 install4jPngIconFile = string("${install4j_images_dir}/${install4j_png_icon_file}")
246 install4jBackground = string("${install4j_images_dir}/${install4j_background}")
247 install4jBuildDir = "${install4j_build_dir}/${JAVA_VERSION}"
248 install4jCheckSums = true
250 applicationName = "${jalview_name}"
254 // TODO: get bamboo build artifact URL for getdown artifacts
255 getdown_channel_base = bamboo_channelbase
256 getdownChannelName = string("${bamboo_planKey}/${JAVA_VERSION}")
257 getdownAppBase = string("${bamboo_channelbase}/${bamboo_planKey}${bamboo_getdown_channel_suffix}/${JAVA_VERSION}")
258 jvlChannelName += "_${getdownChannelName}"
259 // automatically add the test group Not-bamboo for exclusion
260 if ("".equals(testng_excluded_groups)) {
261 testng_excluded_groups = "Not-bamboo"
263 install4jExtraScheme = "jalviewb"
264 backgroundImageText = true
267 case [ "RELEASE", "JALVIEWJS-RELEASE" ]:
268 getdownAppDistDir = getdown_app_dir_release
269 getdownSetAppBaseProperty = true
270 reportRsyncCommand = true
272 install4jInstallerName = "${jalview_name} Installer"
276 getdownChannelName = CHANNEL.toLowerCase()+"/${JALVIEW_VERSION}"
277 getdownDir = string("${getdownChannelName}/${JAVA_VERSION}")
278 getdownAppBase = string("${getdown_channel_base}/${getdownDir}")
279 if (!file("${ARCHIVEDIR}/${package_dir}").exists()) {
280 throw new GradleException("Must provide an ARCHIVEDIR value to produce an archive distribution")
282 package_dir = string("${ARCHIVEDIR}/${package_dir}")
283 buildProperties = string("${ARCHIVEDIR}/${classes_dir}/${build_properties_file}")
286 reportRsyncCommand = true
287 install4jExtraScheme = "jalviewa"
291 getdownChannelName = string("archive/${JALVIEW_VERSION}")
292 getdownDir = string("${getdownChannelName}/${JAVA_VERSION}")
293 getdownAppBase = file(getdownAppBaseDir).toURI().toString()
294 if (!file("${ARCHIVEDIR}/${package_dir}").exists()) {
295 throw new GradleException("Must provide an ARCHIVEDIR value to produce an archive distribution [did not find '${ARCHIVEDIR}/${package_dir}']")
297 package_dir = string("${ARCHIVEDIR}/${package_dir}")
298 buildProperties = string("${ARCHIVEDIR}/${classes_dir}/${build_properties_file}")
301 reportRsyncCommand = true
302 getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher_local}")
303 install4jSuffix = "Archive"
304 install4jExtraScheme = "jalviewa"
307 case ~/^DEVELOP-([\.\-\w]*)$/:
308 def suffix = Matcher.lastMatcher[0][1]
309 reportRsyncCommand = true
310 getdownSetAppBaseProperty = true
311 JALVIEW_VERSION=JALVIEW_VERSION+"-d${suffix}-${buildDate}"
312 install4jSuffix = "Develop ${suffix}"
313 install4jExtraScheme = "jalviewd"
314 install4jInstallerName = "${jalview_name} Develop ${suffix} Installer"
315 getdownChannelName = string("develop-${suffix}")
316 getdownChannelDir = string("${getdown_website_dir}/${getdownChannelName}")
317 getdownAppBaseDir = string("${jalviewDir}/${getdownChannelDir}/${JAVA_VERSION}")
318 getdownDir = string("${getdownChannelName}/${JAVA_VERSION}")
319 getdownAppBase = string("${getdown_channel_base}/${getdownDir}")
320 channelSuffix = string(suffix)
321 backgroundImageText = true
325 reportRsyncCommand = true
326 getdownSetAppBaseProperty = true
327 // DEVELOP-RELEASE is usually associated with a Jalview release series so set the version
328 JALVIEW_VERSION=JALVIEW_VERSION+"-d${buildDate}"
330 install4jSuffix = "Develop"
331 install4jExtraScheme = "jalviewd"
332 install4jInstallerName = "${jalview_name} Develop Installer"
333 backgroundImageText = true
337 reportRsyncCommand = true
338 getdownSetAppBaseProperty = true
339 // Don't ignore transpile errors for release build
340 if (jalviewjs_ignore_transpile_errors.equals("true")) {
341 jalviewjs_ignore_transpile_errors = "false"
342 println("Setting jalviewjs_ignore_transpile_errors to 'false'")
344 JALVIEW_VERSION = JALVIEW_VERSION+"-test"
345 install4jSuffix = "Test"
346 install4jExtraScheme = "jalviewt"
347 install4jInstallerName = "${jalview_name} Test Installer"
348 backgroundImageText = true
351 case ~/^SCRATCH(|-[-\w]*)$/:
352 getdownChannelName = CHANNEL
353 JALVIEW_VERSION = JALVIEW_VERSION+"-"+CHANNEL
355 getdownDir = string("${getdownChannelName}/${JAVA_VERSION}")
356 getdownAppBase = string("${getdown_channel_base}/${getdownDir}")
357 reportRsyncCommand = true
358 install4jSuffix = "Scratch"
362 if (!file("${LOCALDIR}").exists()) {
363 throw new GradleException("Must provide a LOCALDIR value to produce a local distribution")
365 getdownAppBase = file(file("${LOCALDIR}").getAbsolutePath()).toURI().toString()
366 getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher_local}")
368 JALVIEW_VERSION = "TEST"
369 install4jSuffix = "Test-Local"
370 install4jExtraScheme = "jalviewt"
371 install4jInstallerName = "${jalview_name} Test Installer"
372 backgroundImageText = true
375 case [ "LOCAL", "JALVIEWJS" ]:
376 JALVIEW_VERSION = "TEST"
377 getdownAppBase = file(getdownAppBaseDir).toURI().toString()
378 getdownArchiveAppBase = file("${jalviewDir}/${getdown_archive_dir}").toURI().toString()
379 getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher_local}")
380 install4jExtraScheme = "jalviewl"
381 install4jCheckSums = false
384 default: // something wrong specified
385 throw new GradleException("CHANNEL must be one of BUILD, RELEASE, ARCHIVE, DEVELOP, TEST-RELEASE, SCRATCH-..., LOCAL [default]")
389 JALVIEW_VERSION_UNDERSCORES = JALVIEW_VERSION.replaceAll("\\.", "_")
390 hugoDataJsonFile = file("${jalviewDir}/${hugo_build_dir}/${hugo_data_installers_dir}/installers-${JALVIEW_VERSION_UNDERSCORES}.json")
391 hugoArchiveMdFile = file("${jalviewDir}/${hugo_build_dir}/${hugo_version_archive_dir}/Version-${JALVIEW_VERSION_UNDERSCORES}/_index.md")
392 // override getdownAppBase if requested
393 if (findProperty("getdown_appbase_override") != null) {
394 // revert to LOCAL if empty string
395 if (string(getdown_appbase_override) == "") {
396 getdownAppBase = file(getdownAppBaseDir).toURI().toString()
397 getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher_local}")
398 } else if (string(getdown_appbase_override).startsWith("file://")) {
399 getdownAppBase = string(getdown_appbase_override)
400 getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher_local}")
402 getdownAppBase = string(getdown_appbase_override)
404 println("Overriding getdown appbase with '${getdownAppBase}'")
406 // sanitise file name for jalview launcher file for this channel
407 jvlChannelName = jvlChannelName.replaceAll("[^\\w\\-]+", "_")
408 // install4j application and folder names
409 if (install4jSuffix == "") {
410 install4jBundleId = "${install4j_bundle_id}"
411 install4jWinApplicationId = install4j_release_win_application_id
413 applicationName = "${jalview_name} ${install4jSuffix}"
414 install4jBundleId = "${install4j_bundle_id}-" + install4jSuffix.toLowerCase()
415 // add int hash of install4jSuffix to the last part of the application_id
416 def id = install4j_release_win_application_id
417 def idsplitreverse = id.split("-").reverse()
418 idsplitreverse[0] = idsplitreverse[0].toInteger() + install4jSuffix.hashCode()
419 install4jWinApplicationId = idsplitreverse.reverse().join("-")
421 // sanitise folder and id names
422 // install4jApplicationFolder = e.g. "Jalview Build"
423 install4jApplicationFolder = applicationName
424 .replaceAll("[\"'~:/\\\\\\s]", "_") // replace all awkward filename chars " ' ~ : / \
425 .replaceAll("_+", "_") // collapse __
426 install4jInternalId = applicationName
428 .replaceAll("[^\\w\\-\\.]", "_") // replace other non [alphanumeric,_,-,.]
429 .replaceAll("_+", "") // collapse __
430 //.replaceAll("_*-_*", "-") // collapse _-_
431 install4jUnixApplicationFolder = applicationName
433 .replaceAll("[^\\w\\-\\.]", "_") // replace other non [alphanumeric,_,-,.]
434 .replaceAll("_+", "_") // collapse __
435 .replaceAll("_*-_*", "-") // collapse _-_
438 getdownWrapperLink = install4jUnixApplicationFolder // e.g. "jalview_local"
439 getdownAppDir = string("${getdownAppBaseDir}/${getdownAppDistDir}")
440 //getdownJ11libDir = "${getdownAppBaseDir}/${getdown_j11lib_dir}"
441 getdownResourceDir = string("${getdownAppBaseDir}/${getdown_resource_dir}")
442 getdownInstallDir = string("${getdownAppBaseDir}/${getdown_install_dir}")
443 getdownFilesDir = string("${jalviewDir}/${getdown_files_dir}/${JAVA_VERSION}/")
444 getdownFilesInstallDir = string("${getdownFilesDir}/${getdown_install_dir}")
445 /* compile without modules -- using classpath libraries
446 modules_compileClasspath = fileTree(dir: "${jalviewDir}/${j11modDir}", include: ["*.jar"])
447 modules_runtimeClasspath = modules_compileClasspath
453 apply plugin: "com.palantir.git-version"
454 def details = versionDetails()
455 gitHash = details.gitHash
456 gitBranch = details.branchName
457 } catch(org.gradle.api.internal.plugins.PluginApplicationException e) {
458 println("Not in a git repository. Using git values from RELEASE properties file.")
459 gitHash = releaseProps.getProperty("git.hash")
460 gitBranch = releaseProps.getProperty("git.branch")
461 } catch(java.lang.RuntimeException e1) {
462 throw new GradleException("Error with git-version plugin. Directory '.git' exists but versionDetails() cannot be found.")
465 println("Using a ${CHANNEL} profile.")
467 additional_compiler_args = []
468 // configure classpath/args for j8/j11 compilation
469 if (JAVA_VERSION.equals("1.8")) {
470 JAVA_INTEGER_VERSION = string("8")
473 libDistDir = j8libDir
474 compile_source_compatibility = 1.8
475 compile_target_compatibility = 1.8
476 // these are getdown.txt properties defined dependent on the JAVA_VERSION
477 getdownAltJavaMinVersion = string(findProperty("getdown_alt_java8_min_version"))
478 getdownAltJavaMaxVersion = string(findProperty("getdown_alt_java8_max_version"))
479 // this property is assigned below and expanded to multiple lines in the getdown task
480 getdownAltMultiJavaLocation = string(findProperty("getdown_alt_java8_txt_multi_java_location"))
481 // this property is for the Java library used in eclipse
482 eclipseJavaRuntimeName = string("JavaSE-1.8")
483 } else if (JAVA_VERSION.equals("11")) {
484 JAVA_INTEGER_VERSION = string("11")
486 libDistDir = j11libDir
487 compile_source_compatibility = 11
488 compile_target_compatibility = 11
489 getdownAltJavaMinVersion = string(findProperty("getdown_alt_java11_min_version"))
490 getdownAltJavaMaxVersion = string(findProperty("getdown_alt_java11_max_version"))
491 getdownAltMultiJavaLocation = string(findProperty("getdown_alt_java11_txt_multi_java_location"))
492 eclipseJavaRuntimeName = string("JavaSE-11")
493 /* compile without modules -- using classpath libraries
494 additional_compiler_args += [
495 '--module-path', modules_compileClasspath.asPath,
496 '--add-modules', j11modules
499 } else if (JAVA_VERSION.equals("17")) {
500 JAVA_INTEGER_VERSION = string("17")
502 libDistDir = j17libDir
503 compile_source_compatibility = 17
504 compile_target_compatibility = 17
505 getdownAltJavaMinVersion = string(findProperty("getdown_alt_java11_min_version"))
506 getdownAltJavaMaxVersion = string(findProperty("getdown_alt_java11_max_version"))
507 getdownAltMultiJavaLocation = string(findProperty("getdown_alt_java11_txt_multi_java_location"))
508 eclipseJavaRuntimeName = string("JavaSE-17")
509 /* compile without modules -- using classpath libraries
510 additional_compiler_args += [
511 '--module-path', modules_compileClasspath.asPath,
512 '--add-modules', j11modules
516 throw new GradleException("JAVA_VERSION=${JAVA_VERSION} not currently supported by Jalview")
521 JAVA_MIN_VERSION = JAVA_VERSION
522 JAVA_MAX_VERSION = JAVA_VERSION
523 jreInstallsDir = string(jre_installs_dir)
524 if (jreInstallsDir.startsWith("~/")) {
525 jreInstallsDir = System.getProperty("user.home") + jreInstallsDir.substring(1)
527 install4jDir = string("${jalviewDir}/${install4j_utils_dir}")
528 install4jConfFileName = string("jalview-install4j-conf.install4j")
529 install4jConfFile = file("${install4jDir}/${install4jConfFileName}")
530 install4jHomeDir = install4j_home_dir
531 if (install4jHomeDir.startsWith("~/")) {
532 install4jHomeDir = System.getProperty("user.home") + install4jHomeDir.substring(1)
535 resourceBuildDir = string("${buildDir}/resources")
536 resourcesBuildDir = string("${resourceBuildDir}/resources_build")
537 helpBuildDir = string("${resourceBuildDir}/help_build")
538 docBuildDir = string("${resourceBuildDir}/doc_build")
540 if (buildProperties == null) {
541 buildProperties = string("${resourcesBuildDir}/${build_properties_file}")
543 buildingHTML = string("${jalviewDir}/${doc_dir}/building.html")
544 helpParentDir = string("${jalviewDir}/${help_parent_dir}")
545 helpSourceDir = string("${helpParentDir}/${help_dir}")
546 helpFile = string("${helpBuildDir}/${help_dir}/help.jhm")
549 convertBinaryExpectedLocation = imagemagick_convert
550 if (convertBinaryExpectedLocation.startsWith("~/")) {
551 convertBinaryExpectedLocation = System.getProperty("user.home") + convertBinaryExpectedLocation.substring(1)
553 if (file(convertBinaryExpectedLocation).exists()) {
554 convertBinary = convertBinaryExpectedLocation
557 relativeBuildDir = file(jalviewDirAbsolutePath).toPath().relativize(buildDir.toPath())
558 jalviewjsBuildDir = string("${relativeBuildDir}/jalviewjs")
559 jalviewjsSiteDir = string("${jalviewjsBuildDir}/${jalviewjs_site_dir}")
561 jalviewjsTransferSiteJsDir = string(jalviewjsSiteDir)
563 jalviewjsTransferSiteJsDir = string("${jalviewjsBuildDir}/tmp/${jalviewjs_site_dir}_js")
565 jalviewjsTransferSiteLibDir = string("${jalviewjsBuildDir}/tmp/${jalviewjs_site_dir}_lib")
566 jalviewjsTransferSiteSwingJsDir = string("${jalviewjsBuildDir}/tmp/${jalviewjs_site_dir}_swingjs")
567 jalviewjsTransferSiteCoreDir = string("${jalviewjsBuildDir}/tmp/${jalviewjs_site_dir}_core")
568 jalviewjsJalviewCoreHtmlFile = string("")
569 jalviewjsJalviewCoreName = string(jalviewjs_core_name)
570 jalviewjsCoreClasslists = []
571 jalviewjsJalviewTemplateName = string(jalviewjs_name)
572 jalviewjsJ2sSettingsFileName = string("${jalviewDir}/${jalviewjs_j2s_settings}")
573 jalviewjsJ2sAltSettingsFileName = string("${jalviewDir}/${jalviewjs_j2s_alt_settings}")
574 jalviewjsJ2sProps = null
575 jalviewjsJ2sPlugin = jalviewjs_j2s_plugin
576 jalviewjsStderrLaunchFilename = "${jalviewjsSiteDir}/"+(file(jalviewjs_stderr_launch).getName())
578 eclipseWorkspace = null
579 eclipseBinary = string("")
580 eclipseVersion = string("")
583 jalviewjsChromiumUserDir = "${jalviewjsBuildDir}/${jalviewjs_chromium_user_dir}"
584 jalviewjsChromiumProfileDir = "${ext.jalviewjsChromiumUserDir}/${jalviewjs_chromium_profile_name}"
594 destinationDirectory = file(classesDir)
598 srcDirs = [ resourcesBuildDir, docBuildDir, helpBuildDir ]
601 compileClasspath = files(sourceSets.main.java.destinationDirectory)
602 compileClasspath += fileTree(dir: "${jalviewDir}/${libDir}", include: ["*.jar"])
604 runtimeClasspath = compileClasspath
605 runtimeClasspath += files(sourceSets.main.resources.srcDirs)
610 srcDirs cloverInstrDir
611 destinationDirectory = cloverClassesDir
615 srcDirs = sourceSets.main.resources.srcDirs
618 compileClasspath = files( sourceSets.clover.java.destinationDirectory )
619 //compileClasspath += files( testClassesDir )
620 compileClasspath += fileTree(dir: "${jalviewDir}/${libDir}", include: ["*.jar"])
621 compileClasspath += fileTree(dir: "${jalviewDir}/${clover_lib_dir}", include: ["*.jar"])
622 compileClasspath += fileTree(dir: "${jalviewDir}/${utils_dir}/testnglibs", include: ["**/*.jar"])
624 runtimeClasspath = compileClasspath
629 srcDirs testSourceDir
630 destinationDirectory = file(testClassesDir)
634 srcDirs = useClover ? sourceSets.clover.resources.srcDirs : sourceSets.main.resources.srcDirs
637 compileClasspath = files( sourceSets.test.java.destinationDirectory )
638 compileClasspath += useClover ? sourceSets.clover.compileClasspath : sourceSets.main.compileClasspath
639 compileClasspath += fileTree(dir: "${jalviewDir}/${utils_dir}/testnglibs", include: ["**/*.jar"])
641 runtimeClasspath = compileClasspath
642 runtimeClasspath += files(sourceSets.test.resources.srcDirs)
648 // eclipse project and settings files creation, also used by buildship
651 name = eclipse_project_name
653 natures 'org.eclipse.jdt.core.javanature',
654 'org.eclipse.jdt.groovy.core.groovyNature',
655 'org.eclipse.buildship.core.gradleprojectnature'
657 buildCommand 'org.eclipse.jdt.core.javabuilder'
658 buildCommand 'org.eclipse.buildship.core.gradleprojectbuilder'
662 //defaultOutputDir = sourceSets.main.java.destinationDirectory
663 configurations.each{ c->
664 if (c.isCanBeResolved()) {
665 minusConfigurations += [c]
669 plusConfigurations = [ ]
673 def removeTheseToo = []
674 HashMap<String, Boolean> alreadyAddedSrcPath = new HashMap<>();
675 cp.entries.each { entry ->
676 // This conditional removes all src classpathentries that a) have already been added or b) aren't "src" or "test".
677 // e.g. this removes the resources dir being copied into bin/main, bin/test AND bin/clover
678 // we add the resources and help/help dirs in as libs afterwards (see below)
679 if (entry.kind == 'src') {
680 if (alreadyAddedSrcPath.getAt(entry.path) || !(entry.path == bareSourceDir || entry.path == bareTestSourceDir)) {
681 removeTheseToo += entry
683 alreadyAddedSrcPath.putAt(entry.path, true)
688 cp.entries.removeAll(removeTheseToo)
690 //cp.entries += new Output("${eclipse_bin_dir}/main")
691 if (file(helpParentDir).isDirectory()) {
692 cp.entries += new Library(fileReference(helpParentDir))
694 if (file(resourceDir).isDirectory()) {
695 cp.entries += new Library(fileReference(resourceDir))
698 HashMap<String, Boolean> alreadyAddedLibPath = new HashMap<>();
700 sourceSets.main.compileClasspath.findAll { it.name.endsWith(".jar") }.any {
701 //don't want to add destinationDirectory as eclipse is using its own output dir in bin/main
702 if (it.isDirectory() || ! it.exists()) {
703 // don't add dirs to classpath, especially if they don't exist
704 return false // groovy "continue" in .any closure
706 def itPath = it.toString()
707 if (itPath.startsWith("${jalviewDirAbsolutePath}/")) {
708 // make relative path
709 itPath = itPath.substring(jalviewDirAbsolutePath.length()+1)
711 if (alreadyAddedLibPath.get(itPath)) {
712 //println("Not adding duplicate entry "+itPath)
714 //println("Adding entry "+itPath)
715 cp.entries += new Library(fileReference(itPath))
716 alreadyAddedLibPath.put(itPath, true)
720 sourceSets.test.compileClasspath.findAll { it.name.endsWith(".jar") }.any {
721 //no longer want to add destinationDirectory as eclipse is using its own output dir in bin/main
722 if (it.isDirectory() || ! it.exists()) {
723 // don't add dirs to classpath
724 return false // groovy "continue" in .any closure
727 def itPath = it.toString()
728 if (itPath.startsWith("${jalviewDirAbsolutePath}/")) {
729 itPath = itPath.substring(jalviewDirAbsolutePath.length()+1)
731 if (alreadyAddedLibPath.get(itPath)) {
734 def lib = new Library(fileReference(itPath))
735 lib.entryAttributes["test"] = "true"
737 alreadyAddedLibPath.put(itPath, true)
745 containers 'org.eclipse.buildship.core.gradleclasspathcontainer'
750 // for the IDE, use java 11 compatibility
751 sourceCompatibility = compile_source_compatibility
752 targetCompatibility = compile_target_compatibility
753 javaRuntimeName = eclipseJavaRuntimeName
755 // add in jalview project specific properties/preferences into eclipse core preferences
757 withProperties { props ->
758 def jalview_prefs = new Properties()
759 def ins = new FileInputStream("${jalviewDirAbsolutePath}/${eclipse_extra_jdt_prefs_file}")
760 jalview_prefs.load(ins)
762 jalview_prefs.forEach { t, v ->
763 if (props.getAt(t) == null) {
767 // codestyle file -- overrides previous formatter prefs
768 def csFile = file("${jalviewDirAbsolutePath}/${eclipse_codestyle_file}")
769 if (csFile.exists()) {
770 XmlParser parser = new XmlParser()
771 def profiles = parser.parse(csFile)
772 def profile = profiles.'profile'.find { p -> (p.'@kind' == "CodeFormatterProfile" && p.'@name' == "Jalview") }
773 if (profile != null) {
774 profile.'setting'.each { s ->
776 def value = s.'@value'
777 if (id != null && value != null) {
778 props.putAt(id, value)
789 // Don't want these to be activated if in headless build
790 synchronizationTasks "eclipseSynchronizationTask"
791 //autoBuildTasks "eclipseAutoBuildTask"
797 /* hack to change eclipse prefs in .settings files other than org.eclipse.jdt.core.prefs */
798 // Class to allow updating arbitrary properties files
799 class PropertiesFile extends PropertiesPersistableConfigurationObject {
800 public PropertiesFile(PropertiesTransformer t) { super(t); }
801 @Override protected void load(Properties properties) { }
802 @Override protected void store(Properties properties) { }
803 @Override protected String getDefaultResourceName() { return ""; }
804 // This is necessary, because PropertiesPersistableConfigurationObject fails
805 // if no default properties file exists.
806 @Override public void loadDefaults() { load(new StringBufferInputStream("")); }
809 // Task to update arbitrary properties files (set outputFile)
810 class PropertiesFileTask extends PropertiesGeneratorTask<PropertiesFile> {
811 private final PropertiesFileContentMerger file;
812 public PropertiesFileTask() { file = new PropertiesFileContentMerger(getTransformer()); }
813 protected PropertiesFile create() { return new PropertiesFile(getTransformer()); }
814 protected void configure(PropertiesFile props) {
815 file.getBeforeMerged().execute(props); file.getWhenMerged().execute(props);
817 public void file(Closure closure) { ConfigureUtil.configure(closure, file); }
820 task eclipseUIPreferences(type: PropertiesFileTask) {
821 description = "Generate Eclipse additional settings"
822 def filename = "org.eclipse.jdt.ui.prefs"
823 outputFile = "$projectDir/.settings/${filename}" as File
826 it.load new FileInputStream("$projectDir/utils/eclipse/${filename}" as String)
831 task eclipseGroovyCorePreferences(type: PropertiesFileTask) {
832 description = "Generate Eclipse additional settings"
833 def filename = "org.eclipse.jdt.groovy.core.prefs"
834 outputFile = "$projectDir/.settings/${filename}" as File
837 it.load new FileInputStream("$projectDir/utils/eclipse/${filename}" as String)
842 task eclipseAllPreferences {
844 dependsOn eclipseUIPreferences
845 dependsOn eclipseGroovyCorePreferences
848 eclipseUIPreferences.mustRunAfter eclipseJdt
849 eclipseGroovyCorePreferences.mustRunAfter eclipseJdt
851 /* end of eclipse preferences hack */
859 delete cloverBuildDir
860 delete cloverReportDir
865 task cloverInstrJava(type: JavaExec) {
866 group = "Verification"
867 description = "Create clover instrumented source java files"
869 dependsOn cleanClover
871 inputs.files(sourceSets.main.allJava)
872 outputs.dir(cloverInstrDir)
874 //classpath = fileTree(dir: "${jalviewDir}/${clover_lib_dir}", include: ["*.jar"])
875 classpath = sourceSets.clover.compileClasspath
876 main = "com.atlassian.clover.CloverInstr"
884 cloverInstrDir.getPath(),
886 def srcFiles = sourceSets.main.allJava.files
889 { file -> file.absolutePath }
892 args argsList.toArray()
895 delete cloverInstrDir
896 println("Clover: About to instrument "+srcFiles.size() +" files")
901 task cloverInstrTests(type: JavaExec) {
902 group = "Verification"
903 description = "Create clover instrumented source test files"
905 dependsOn cleanClover
907 inputs.files(testDir)
908 outputs.dir(cloverTestInstrDir)
910 classpath = sourceSets.clover.compileClasspath
911 main = "com.atlassian.clover.CloverInstr"
921 cloverTestInstrDir.getPath(),
923 args argsList.toArray()
926 delete cloverTestInstrDir
927 println("Clover: About to instrument test files")
933 group = "Verification"
934 description = "Create clover instrumented all source files"
936 dependsOn cloverInstrJava
937 dependsOn cloverInstrTests
941 cloverClasses.dependsOn cloverInstr
944 task cloverConsoleReport(type: JavaExec) {
945 group = "Verification"
946 description = "Creates clover console report"
949 file(cloverDb).exists()
952 inputs.dir cloverClassesDir
954 classpath = sourceSets.clover.runtimeClasspath
955 main = "com.atlassian.clover.reporters.console.ConsoleReporter"
957 if (cloverreport_mem.length() > 0) {
958 maxHeapSize = cloverreport_mem
960 if (cloverreport_jvmargs.length() > 0) {
961 jvmArgs Arrays.asList(cloverreport_jvmargs.split(" "))
971 args argsList.toArray()
975 task cloverHtmlReport(type: JavaExec) {
976 group = "Verification"
977 description = "Creates clover HTML report"
980 file(cloverDb).exists()
983 def cloverHtmlDir = cloverReportDir
984 inputs.dir cloverClassesDir
985 outputs.dir cloverHtmlDir
987 classpath = sourceSets.clover.runtimeClasspath
988 main = "com.atlassian.clover.reporters.html.HtmlReporter"
990 if (cloverreport_mem.length() > 0) {
991 maxHeapSize = cloverreport_mem
993 if (cloverreport_jvmargs.length() > 0) {
994 jvmArgs Arrays.asList(cloverreport_jvmargs.split(" "))
1005 if (cloverreport_html_options.length() > 0) {
1006 argsList += cloverreport_html_options.split(" ")
1009 args argsList.toArray()
1013 task cloverXmlReport(type: JavaExec) {
1014 group = "Verification"
1015 description = "Creates clover XML report"
1018 file(cloverDb).exists()
1021 def cloverXmlFile = "${cloverReportDir}/clover.xml"
1022 inputs.dir cloverClassesDir
1023 outputs.file cloverXmlFile
1025 classpath = sourceSets.clover.runtimeClasspath
1026 main = "com.atlassian.clover.reporters.xml.XMLReporter"
1028 if (cloverreport_mem.length() > 0) {
1029 maxHeapSize = cloverreport_mem
1031 if (cloverreport_jvmargs.length() > 0) {
1032 jvmArgs Arrays.asList(cloverreport_jvmargs.split(" "))
1043 if (cloverreport_xml_options.length() > 0) {
1044 argsList += cloverreport_xml_options.split(" ")
1047 args argsList.toArray()
1052 group = "Verification"
1053 description = "Creates clover reports"
1055 dependsOn cloverXmlReport
1056 dependsOn cloverHtmlReport
1063 sourceCompatibility = compile_source_compatibility
1064 targetCompatibility = compile_target_compatibility
1065 options.compilerArgs += additional_compiler_args
1066 print ("Setting target compatibility to "+targetCompatibility+"\n")
1068 //classpath += configurations.cloverRuntime
1074 // JBP->BS should the print statement in doFirst refer to compile_target_compatibility ?
1075 sourceCompatibility = compile_source_compatibility
1076 targetCompatibility = compile_target_compatibility
1077 options.compilerArgs += additional_compiler_args
1078 options.encoding = "UTF-8"
1080 print ("Setting target compatibility to "+compile_target_compatibility+"\n")
1087 sourceCompatibility = compile_source_compatibility
1088 targetCompatibility = compile_target_compatibility
1089 options.compilerArgs += additional_compiler_args
1091 print ("Setting target compatibility to "+targetCompatibility+"\n")
1098 delete sourceSets.main.java.destinationDirectory
1104 dependsOn cleanClover
1106 delete sourceSets.test.java.destinationDirectory
1111 // format is a string like date.format("dd MMMM yyyy")
1112 def getDate(format) {
1113 return date.format(format)
1117 def convertMdToHtml (FileTree mdFiles, File cssFile) {
1118 MutableDataSet options = new MutableDataSet()
1120 def extensions = new ArrayList<>()
1121 extensions.add(AnchorLinkExtension.create())
1122 extensions.add(AutolinkExtension.create())
1123 extensions.add(StrikethroughExtension.create())
1124 extensions.add(TaskListExtension.create())
1125 extensions.add(TablesExtension.create())
1126 extensions.add(TocExtension.create())
1128 options.set(Parser.EXTENSIONS, extensions)
1130 // set GFM table parsing options
1131 options.set(TablesExtension.WITH_CAPTION, false)
1132 options.set(TablesExtension.COLUMN_SPANS, false)
1133 options.set(TablesExtension.MIN_HEADER_ROWS, 1)
1134 options.set(TablesExtension.MAX_HEADER_ROWS, 1)
1135 options.set(TablesExtension.APPEND_MISSING_COLUMNS, true)
1136 options.set(TablesExtension.DISCARD_EXTRA_COLUMNS, true)
1137 options.set(TablesExtension.HEADER_SEPARATOR_COLUMN_MATCH, true)
1139 options.set(AnchorLinkExtension.ANCHORLINKS_SET_ID, false)
1140 options.set(AnchorLinkExtension.ANCHORLINKS_ANCHOR_CLASS, "anchor")
1141 options.set(AnchorLinkExtension.ANCHORLINKS_SET_NAME, true)
1142 options.set(AnchorLinkExtension.ANCHORLINKS_TEXT_PREFIX, "<span class=\"octicon octicon-link\"></span>")
1144 Parser parser = Parser.builder(options).build()
1145 HtmlRenderer renderer = HtmlRenderer.builder(options).build()
1147 mdFiles.each { mdFile ->
1148 // add table of contents
1149 def mdText = "[TOC]\n"+mdFile.text
1151 // grab the first top-level title
1153 def titleRegex = /(?m)^#(\s+|([^#]))(.*)/
1154 def matcher = mdText =~ titleRegex
1155 if (matcher.size() > 0) {
1156 // matcher[0][2] is the first character of the title if there wasn't any whitespace after the #
1157 title = (matcher[0][2] != null ? matcher[0][2] : "")+matcher[0][3]
1159 // or use the filename if none found
1160 if (title == null) {
1161 title = mdFile.getName()
1164 Node document = parser.parse(mdText)
1165 String htmlBody = renderer.render(document)
1166 def htmlText = '''<html>
1167 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
1168 <html xmlns="http://www.w3.org/1999/xhtml">
1170 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
1171 <meta http-equiv="Content-Style-Type" content="text/css" />
1172 <meta name="generator" content="flexmark" />
1174 htmlText += ((title != null) ? " <title>${title}</title>" : '' )
1176 <style type="text/css">code{white-space: pre;}</style>
1178 htmlText += ((cssFile != null) ? cssFile.text : '')
1179 htmlText += '''</head>
1182 htmlText += htmlBody
1188 def htmlFilePath = mdFile.getPath().replaceAll(/\..*?$/, ".html")
1189 def htmlFile = file(htmlFilePath)
1190 println("Creating ${htmlFilePath}")
1191 htmlFile.text = htmlText
1196 task copyDocs(type: Copy) {
1197 def inputDir = "${jalviewDir}/${doc_dir}"
1198 def destinationDirectory = "${docBuildDir}/${doc_dir}"
1202 include('**/*.html')
1204 filter(ReplaceTokens,
1208 'Version-Rel': JALVIEW_VERSION,
1209 'Year-Rel': getDate("yyyy")
1216 exclude('**/*.html')
1219 into destinationDirectory
1221 inputs.dir(inputDir)
1222 outputs.dir(destinationDirectory)
1226 task convertMdFiles {
1228 def mdFiles = fileTree(dir: docBuildDir, include: "**/*.md")
1229 def cssFile = file("${jalviewDir}/${flexmark_css}")
1232 convertMdToHtml(mdFiles, cssFile)
1235 inputs.files(mdFiles)
1236 inputs.file(cssFile)
1239 mdFiles.each { mdFile ->
1240 def htmlFilePath = mdFile.getPath().replaceAll(/\..*?$/, ".html")
1241 htmlFiles.add(file(htmlFilePath))
1243 outputs.files(htmlFiles)
1247 def hugoTemplateSubstitutions(String input, Map extras=null) {
1248 def replacements = [
1249 DATE: getDate("yyyy-MM-dd"),
1250 CHANNEL: propertiesChannelName,
1251 APPLICATION_NAME: applicationName,
1253 GIT_BRANCH: gitBranch,
1254 VERSION: JALVIEW_VERSION,
1255 JAVA_VERSION: JAVA_VERSION,
1256 VERSION_UNDERSCORES: JALVIEW_VERSION_UNDERSCORES,
1261 if (extras != null) {
1262 extras.each{ k, v ->
1263 output = output.replaceAll("__${k}__", ((v == null)?"":v))
1266 replacements.each{ k, v ->
1267 output = output.replaceAll("__${k}__", ((v == null)?"":v))
1272 def mdFileComponents(File mdFile, def dateOnly=false) {
1275 if (mdFile.exists()) {
1276 def inFrontMatter = false
1277 def firstLine = true
1278 mdFile.eachLine { line ->
1279 if (line.matches("---")) {
1280 def prev = inFrontMatter
1281 inFrontMatter = firstLine
1282 if (inFrontMatter != prev)
1285 if (inFrontMatter) {
1287 if (m == line =~ /^date:\s*(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})/) {
1288 map["date"] = new Date().parse("yyyy-MM-dd HH:mm:ss", m[0][1])
1289 } else if (m == line =~ /^date:\s*(\d{4}-\d{2}-\d{2})/) {
1290 map["date"] = new Date().parse("yyyy-MM-dd", m[0][1])
1291 } else if (m == line =~ /^channel:\s*(\S+)/) {
1292 map["channel"] = m[0][1]
1293 } else if (m == line =~ /^version:\s*(\S+)/) {
1294 map["version"] = m[0][1]
1295 } else if (m == line =~ /^\s*([^:]+)\s*:\s*(\S.*)/) {
1296 map[ m[0][1] ] = m[0][2]
1298 if (dateOnly && map["date"] != null) {
1304 content += line+"\n"
1309 return dateOnly ? map["date"] : [map, content]
1312 task hugoTemplates {
1314 description "Create partially populated md pages for hugo website build"
1316 def hugoTemplatesDir = file("${jalviewDir}/${hugo_templates_dir}")
1317 def hugoBuildDir = "${jalviewDir}/${hugo_build_dir}"
1318 def templateFiles = fileTree(dir: hugoTemplatesDir)
1319 def releaseMdFile = file("${jalviewDir}/${releases_dir}/release-${JALVIEW_VERSION_UNDERSCORES}.md")
1320 def whatsnewMdFile = file("${jalviewDir}/${whatsnew_dir}/whatsnew-${JALVIEW_VERSION_UNDERSCORES}.md")
1321 def oldJvlFile = file("${jalviewDir}/${hugo_old_jvl}")
1322 def jalviewjsFile = file("${jalviewDir}/${hugo_jalviewjs}")
1325 // specific release template for version archive
1328 def givenDate = null
1329 def givenChannel = null
1330 def givenVersion = null
1331 if (CHANNEL == "RELEASE") {
1332 def (map, content) = mdFileComponents(releaseMdFile)
1333 givenDate = map.date
1334 givenChannel = map.channel
1335 givenVersion = map.version
1337 if (givenVersion != null && givenVersion != JALVIEW_VERSION) {
1338 throw new GradleException("'version' header (${givenVersion}) found in ${releaseMdFile} does not match JALVIEW_VERSION (${JALVIEW_VERSION})")
1341 if (whatsnewMdFile.exists())
1342 whatsnew = whatsnewMdFile.text
1345 def oldJvl = oldJvlFile.exists() ? oldJvlFile.collect{it} : []
1346 def jalviewjsLink = jalviewjsFile.exists() ? jalviewjsFile.collect{it} : []
1348 def changesHugo = null
1349 if (changes != null) {
1350 changesHugo = '<div class="release_notes">\n\n'
1351 def inSection = false
1352 changes.eachLine { line ->
1354 if (m == line =~ /^##([^#].*)$/) {
1356 changesHugo += "</div>\n\n"
1358 def section = m[0][1].trim()
1359 section = section.toLowerCase()
1360 section = section.replaceAll(/ +/, "_")
1361 section = section.replaceAll(/[^a-z0-9_\-]/, "")
1362 changesHugo += "<div class=\"${section}\">\n\n"
1364 } else if (m == line =~ /^(\s*-\s*)<!--([^>]+)-->(.*?)(<br\/?>)?\s*$/) {
1365 def comment = m[0][2].trim()
1366 if (comment != "") {
1367 comment = comment.replaceAll('"', """)
1369 comment.eachMatch(/JAL-\d+/) { jal -> issuekeys += jal }
1370 def newline = m[0][1]
1371 if (comment.trim() != "")
1372 newline += "{{<comment>}}${comment}{{</comment>}} "
1373 newline += m[0][3].trim()
1374 if (issuekeys.size() > 0)
1375 newline += " {{< jal issue=\"${issuekeys.join(",")}\" alt=\"${comment}\" >}}"
1376 if (m[0][4] != null)
1381 changesHugo += line+"\n"
1384 changesHugo += "\n</div>\n\n"
1386 changesHugo += '</div>'
1389 templateFiles.each{ templateFile ->
1390 def newFileName = string(hugoTemplateSubstitutions(templateFile.getName()))
1391 def relPath = hugoTemplatesDir.toPath().relativize(templateFile.toPath()).getParent()
1392 def newRelPathName = hugoTemplateSubstitutions( relPath.toString() )
1394 def outPathName = string("${hugoBuildDir}/$newRelPathName")
1398 rename(templateFile.getName(), newFileName)
1402 def newFile = file("${outPathName}/${newFileName}".toString())
1403 def content = newFile.text
1404 newFile.text = hugoTemplateSubstitutions(content,
1407 CHANGES: changesHugo,
1408 DATE: givenDate == null ? "" : givenDate.format("yyyy-MM-dd"),
1409 DRAFT: givenDate == null ? "true" : "false",
1410 JALVIEWJSLINK: jalviewjsLink.contains(JALVIEW_VERSION) ? "true" : "false",
1411 JVL_HEADER: oldJvl.contains(JALVIEW_VERSION) ? "jvl: true" : ""
1418 inputs.file(oldJvlFile)
1419 inputs.dir(hugoTemplatesDir)
1420 inputs.property("JALVIEW_VERSION", { JALVIEW_VERSION })
1421 inputs.property("CHANNEL", { CHANNEL })
1424 def getMdDate(File mdFile) {
1425 return mdFileComponents(mdFile, true)
1428 def getMdSections(String content) {
1430 def sectionContent = ""
1431 def sectionName = null
1432 content.eachLine { line ->
1434 if (m == line =~ /^##([^#].*)$/) {
1435 if (sectionName != null) {
1436 sections[sectionName] = sectionContent
1440 sectionName = m[0][1].trim()
1441 sectionName = sectionName.toLowerCase()
1442 sectionName = sectionName.replaceAll(/ +/, "_")
1443 sectionName = sectionName.replaceAll(/[^a-z0-9_\-]/, "")
1444 } else if (sectionName != null) {
1445 sectionContent += line+"\n"
1448 if (sectionContent != null) {
1449 sections[sectionName] = sectionContent
1455 task copyHelp(type: Copy) {
1456 def inputDir = helpSourceDir
1457 def destinationDirectory = "${helpBuildDir}/${help_dir}"
1461 include('**/*.html')
1465 filter(ReplaceTokens,
1469 'Version-Rel': JALVIEW_VERSION,
1470 'Year-Rel': getDate("yyyy")
1477 exclude('**/*.html')
1482 into destinationDirectory
1484 inputs.dir(inputDir)
1485 outputs.files(helpFile)
1486 outputs.dir(destinationDirectory)
1491 task releasesTemplates {
1493 description "Recreate whatsNew.html and releases.html from markdown files and templates in help"
1497 def releasesTemplateFile = file("${jalviewDir}/${releases_template}")
1498 def whatsnewTemplateFile = file("${jalviewDir}/${whatsnew_template}")
1499 def releasesHtmlFile = file("${helpBuildDir}/${help_dir}/${releases_html}")
1500 def whatsnewHtmlFile = file("${helpBuildDir}/${help_dir}/${whatsnew_html}")
1501 def releasesMdDir = "${jalviewDir}/${releases_dir}"
1502 def whatsnewMdDir = "${jalviewDir}/${whatsnew_dir}"
1505 def releaseMdFile = file("${releasesMdDir}/release-${JALVIEW_VERSION_UNDERSCORES}.md")
1506 def whatsnewMdFile = file("${whatsnewMdDir}/whatsnew-${JALVIEW_VERSION_UNDERSCORES}.md")
1508 if (CHANNEL == "RELEASE") {
1509 if (!releaseMdFile.exists()) {
1510 throw new GradleException("File ${releaseMdFile} must be created for RELEASE")
1512 if (!whatsnewMdFile.exists()) {
1513 throw new GradleException("File ${whatsnewMdFile} must be created for RELEASE")
1517 def releaseFiles = fileTree(dir: releasesMdDir, include: "release-*.md")
1518 def releaseFilesDates = releaseFiles.collectEntries {
1519 [(it): getMdDate(it)]
1521 releaseFiles = releaseFiles.sort { a,b -> releaseFilesDates[a].compareTo(releaseFilesDates[b]) }
1523 def releasesTemplate = releasesTemplateFile.text
1524 def m = releasesTemplate =~ /(?s)__VERSION_LOOP_START__(.*)__VERSION_LOOP_END__/
1525 def versionTemplate = m[0][1]
1527 MutableDataSet options = new MutableDataSet()
1529 def extensions = new ArrayList<>()
1530 options.set(Parser.EXTENSIONS, extensions)
1531 options.set(Parser.HTML_BLOCK_COMMENT_ONLY_FULL_LINE, true)
1533 Parser parser = Parser.builder(options).build()
1534 HtmlRenderer renderer = HtmlRenderer.builder(options).build()
1536 def actualVersions = releaseFiles.collect { rf ->
1537 def (rfMap, rfContent) = mdFileComponents(rf)
1538 return rfMap.version
1540 def versionsHtml = ""
1541 def linkedVersions = []
1542 releaseFiles.reverse().each { rFile ->
1543 def (rMap, rContent) = mdFileComponents(rFile)
1545 def versionLink = ""
1546 def partialVersion = ""
1547 def firstPart = true
1548 rMap.version.split("\\.").each { part ->
1549 def displayPart = ( firstPart ? "" : "." ) + part
1550 partialVersion += displayPart
1552 linkedVersions.contains(partialVersion)
1553 || ( actualVersions.contains(partialVersion) && partialVersion != rMap.version )
1555 versionLink += displayPart
1557 versionLink += "<a id=\"Jalview.${partialVersion}\">${displayPart}</a>"
1558 linkedVersions += partialVersion
1562 def displayDate = releaseFilesDates[rFile].format("dd/MM/yyyy")
1565 def rContentProcessed = ""
1566 rContent.eachLine { line ->
1567 if (lm == line =~ /^(\s*-)(\s*<!--[^>]*?-->)(.*)$/) {
1568 line = "${lm[0][1]}${lm[0][3]}${lm[0][2]}"
1569 } else if (lm == line =~ /^###([^#]+.*)$/) {
1570 line = "_${lm[0][1].trim()}_"
1572 rContentProcessed += line + "\n"
1575 def rContentSections = getMdSections(rContentProcessed)
1576 def rVersion = versionTemplate
1577 if (rVersion != "") {
1578 def rNewFeatures = rContentSections["new_features"]
1579 def rIssuesResolved = rContentSections["issues_resolved"]
1580 Node newFeaturesNode = parser.parse(rNewFeatures)
1581 String newFeaturesHtml = renderer.render(newFeaturesNode)
1582 Node issuesResolvedNode = parser.parse(rIssuesResolved)
1583 String issuesResolvedHtml = renderer.render(issuesResolvedNode)
1584 rVersion = hugoTemplateSubstitutions(rVersion,
1586 VERSION: rMap.version,
1587 VERSION_LINK: versionLink,
1588 DISPLAY_DATE: displayDate,
1589 NEW_FEATURES: newFeaturesHtml,
1590 ISSUES_RESOLVED: issuesResolvedHtml
1593 versionsHtml += rVersion
1597 releasesTemplate = releasesTemplate.replaceAll("(?s)__VERSION_LOOP_START__.*__VERSION_LOOP_END__", versionsHtml)
1598 releasesTemplate = hugoTemplateSubstitutions(releasesTemplate)
1599 releasesHtmlFile.text = releasesTemplate
1601 if (whatsnewMdFile.exists()) {
1602 def wnDisplayDate = releaseFilesDates[releaseMdFile] != null ? releaseFilesDates[releaseMdFile].format("dd MMMM yyyy") : ""
1603 def whatsnewMd = hugoTemplateSubstitutions(whatsnewMdFile.text)
1604 Node whatsnewNode = parser.parse(whatsnewMd)
1605 String whatsnewHtml = renderer.render(whatsnewNode)
1606 whatsnewHtml = whatsnewTemplateFile.text.replaceAll("__WHATS_NEW__", whatsnewHtml)
1607 whatsnewHtmlFile.text = hugoTemplateSubstitutions(whatsnewHtml,
1609 VERSION: JALVIEW_VERSION,
1610 DISPLAY_DATE: wnDisplayDate
1613 } else if (gradle.taskGraph.hasTask(":linkCheck")) {
1614 whatsnewHtmlFile.text = "Development build " + getDate("yyyy-MM-dd HH:mm:ss")
1619 inputs.file(releasesTemplateFile)
1620 inputs.file(whatsnewTemplateFile)
1621 inputs.dir(releasesMdDir)
1622 inputs.dir(whatsnewMdDir)
1623 outputs.file(releasesHtmlFile)
1624 outputs.file(whatsnewHtmlFile)
1629 task copyResources(type: Copy) {
1631 description = "Copy (and make text substitutions in) the resources dir to the build area"
1633 def inputDir = resourceDir
1634 def destinationDirectory = resourcesBuildDir
1638 include('**/*.html')
1640 filter(ReplaceTokens,
1644 'Version-Rel': JALVIEW_VERSION,
1645 'Year-Rel': getDate("yyyy")
1652 exclude('**/*.html')
1655 into destinationDirectory
1657 inputs.dir(inputDir)
1658 outputs.dir(destinationDirectory)
1661 task copyChannelResources(type: Copy) {
1662 dependsOn copyResources
1664 description = "Copy the channel resources dir to the build resources area"
1666 def inputDir = "${channelDir}/${resource_dir}"
1667 def destinationDirectory = resourcesBuildDir
1669 include(channel_props)
1670 filter(ReplaceTokens,
1674 'SUFFIX': channelSuffix
1679 exclude(channel_props)
1681 into destinationDirectory
1683 inputs.dir(inputDir)
1684 outputs.dir(destinationDirectory)
1687 task createBuildProperties(type: WriteProperties) {
1688 dependsOn copyResources
1689 dependsOn copyChannelResources
1691 description = "Create the ${buildProperties} file"
1693 inputs.dir(sourceDir)
1694 inputs.dir(resourcesBuildDir)
1695 outputFile (buildProperties)
1696 // taking time specific comment out to allow better incremental builds
1697 comment "--Jalview Build Details--\n"+getDate("yyyy-MM-dd HH:mm:ss")
1698 //comment "--Jalview Build Details--\n"+getDate("yyyy-MM-dd")
1699 property "BUILD_DATE", getDate("HH:mm:ss dd MMMM yyyy")
1700 property "VERSION", JALVIEW_VERSION
1701 property "INSTALLATION", INSTALLATION+" git-commit:"+gitHash+" ["+gitBranch+"]"
1702 property "JAVA_COMPILE_VERSION", JAVA_INTEGER_VERSION
1703 if (getdownSetAppBaseProperty) {
1704 property "GETDOWNAPPBASE", getdownAppBase
1705 property "GETDOWNAPPDISTDIR", getdownAppDistDir
1707 outputs.file(outputFile)
1711 task buildIndices(type: JavaExec) {
1713 //dependsOn releasesTemplates
1714 classpath = sourceSets.main.compileClasspath
1715 main = "com.sun.java.help.search.Indexer"
1716 workingDir = "${helpBuildDir}/${help_dir}"
1719 inputs.dir("${workingDir}/${argDir}")
1721 outputs.dir("${classesDir}/doc")
1722 outputs.dir("${classesDir}/help")
1723 outputs.file("${workingDir}/JavaHelpSearch/DOCS")
1724 outputs.file("${workingDir}/JavaHelpSearch/DOCS.TAB")
1725 outputs.file("${workingDir}/JavaHelpSearch/OFFSETS")
1726 outputs.file("${workingDir}/JavaHelpSearch/POSITIONS")
1727 outputs.file("${workingDir}/JavaHelpSearch/SCHEMA")
1728 outputs.file("${workingDir}/JavaHelpSearch/TMAP")
1731 task buildResources {
1732 dependsOn copyResources
1733 dependsOn copyChannelResources
1734 dependsOn createBuildProperties
1738 dependsOn buildResources
1741 //dependsOn releasesTemplates
1742 dependsOn convertMdFiles
1743 dependsOn buildIndices
1747 // random block of dependencies
1748 compileJava.dependsOn prepare
1749 run.dependsOn compileJava
1750 //run.dependsOn prepare
1751 compileTestJava.dependsOn compileJava //
1752 compileTestJava.dependsOn buildIndices //
1753 processResources.dependsOn copyChannelResources //
1754 processResources.dependsOn copyResources //
1755 processResources.dependsOn createBuildProperties //
1756 processResources.dependsOn copyDocs //
1757 processResources.dependsOn convertMdFiles //
1758 processResources.dependsOn copyHelp //
1759 processResources.dependsOn buildIndices //
1761 group = "Verification"
1762 description = "Runs all testTaskN tasks)"
1765 dependsOn cloverClasses
1767 dependsOn testClasses
1770 // not running tests in this task
1773 /* testTask0 is the main test task */
1774 task testTask0(type: Test) {
1775 group = "Verification"
1776 description = "The main test task. Runs all non-testTaskN-labelled tests (unless excluded)"
1778 includeGroups testng_groups.split(",")
1779 excludeGroups testng_excluded_groups.split(",")
1780 tasks.withType(Test).matching {it.name.startsWith("testTask") && it.name != name}.all {t -> excludeGroups t.name}
1782 useDefaultListeners=true
1784 timeout = Duration.ofMinutes(15)
1787 /* separated tests */
1788 task testTask1(type: Test) {
1789 group = "Verification"
1790 description = "Tests that need to be isolated from the main test run"
1793 excludeGroups testng_excluded_groups.split(",")
1795 useDefaultListeners=true
1797 timeout = Duration.ofMinutes(5)
1800 task testTask2(type: Test) {
1801 group = "Verification"
1802 description = "Tests that need to be isolated from the main test run"
1805 excludeGroups testng_excluded_groups.split(",")
1807 useDefaultListeners=true
1809 timeout = Duration.ofMinutes(5)
1811 task testTask3(type: Test) {
1812 group = "Verification"
1813 description = "Tests that need to be isolated from the main test run"
1816 excludeGroups testng_excluded_groups.split(",")
1818 useDefaultListeners=true
1820 timeout = Duration.ofMinutes(5)
1823 /* insert more testTaskNs here -- change N to next digit or other string */
1825 task testTaskN(type: Test) {
1826 group = "Verification"
1827 description = "Tests that need to be isolated from the main test run"
1830 excludeGroups testng_excluded_groups.split(",")
1832 useDefaultListeners=true
1839 * adapted from https://medium.com/@wasyl/pretty-tests-summary-in-gradle-744804dd676c
1840 * to summarise test results from all Test tasks
1842 /* START of test tasks results summary */
1843 import groovy.time.TimeCategory
1844 import org.gradle.api.tasks.testing.logging.TestExceptionFormat
1845 import org.gradle.api.tasks.testing.logging.TestLogEvent
1846 rootProject.ext.testsResults = [] // Container for tests summaries
1848 tasks.withType(Test).matching {t -> t.getName().startsWith("testTask")}.all { testTask ->
1850 // from original test task
1852 dependsOn cloverClasses
1854 dependsOn testClasses //?
1857 // run main tests first
1858 if (!testTask.name.equals("testTask0"))
1859 testTask.mustRunAfter "testTask0"
1861 testTask.testLogging { logging ->
1862 events TestLogEvent.FAILED
1863 // TestLogEvent.SKIPPED,
1864 // TestLogEvent.STANDARD_OUT,
1865 // TestLogEvent.STANDARD_ERROR
1867 exceptionFormat TestExceptionFormat.FULL
1870 showStackTraces true
1872 showStandardStreams true
1874 info.events = [ TestLogEvent.FAILED ]
1877 if (OperatingSystem.current().isMacOsX()) {
1878 testTask.systemProperty "apple.awt.UIElement", "true"
1879 testTask.environment "JAVA_TOOL_OPTIONS", "-Dapple.awt.UIElement=true"
1883 ignoreFailures = true // Always try to run all tests for all modules
1885 afterSuite { desc, result ->
1887 return // Only summarize results for whole modules
1889 def resultsInfo = [testTask.project.name, testTask.name, result, TimeCategory.minus(new Date(result.endTime), new Date(result.startTime)), testTask.reports.html.entryPoint]
1891 rootProject.ext.testsResults.add(resultsInfo)
1894 // from original test task
1895 maxHeapSize = "1024m"
1897 workingDir = jalviewDir
1898 def testLaf = project.findProperty("test_laf")
1899 if (testLaf != null) {
1900 println("Setting Test LaF to '${testLaf}'")
1901 systemProperty "laf", testLaf
1903 def testHiDPIScale = project.findProperty("test_HiDPIScale")
1904 if (testHiDPIScale != null) {
1905 println("Setting Test HiDPI Scale to '${testHiDPIScale}'")
1906 systemProperty "sun.java2d.uiScale", testHiDPIScale
1908 sourceCompatibility = compile_source_compatibility
1909 targetCompatibility = compile_target_compatibility
1910 jvmArgs += additional_compiler_args
1913 // this is not perfect yet -- we should only add the commandLineIncludePatterns to the
1914 // testTasks that include the tests, and exclude all from the others.
1915 // get --test argument
1916 filter.commandLineIncludePatterns = test.filter.commandLineIncludePatterns
1917 // do something with testTask.getCandidateClassFiles() to see if the test should silently finish because of the
1918 // commandLineIncludePatterns not matching anything. Instead we are doing setFailOnNoMatchingTests(false) below
1922 println("Running tests " + (useClover?"WITH":"WITHOUT") + " clover")
1927 /* don't fail on no matching tests (so --tests will run across all testTasks) */
1928 testTask.filter.setFailOnNoMatchingTests(false)
1930 /* ensure the "test" task dependsOn all the testTasks */
1931 test.dependsOn testTask
1934 gradle.buildFinished {
1935 def allResults = rootProject.ext.testsResults
1937 if (!allResults.isEmpty()) {
1938 printResults allResults
1939 allResults.each {r ->
1940 if (r[2].resultType == TestResult.ResultType.FAILURE)
1941 throw new GradleException("Failed tests!")
1946 private static String colString(styler, col, colour, text) {
1947 return col?"${styler[colour](text)}":text
1950 private static String getSummaryLine(s, pn, tn, rt, rc, rs, rf, rsk, t, col) {
1951 def colour = 'black'
1959 case TestResult.ResultType.SUCCESS:
1962 case TestResult.ResultType.FAILURE:
1970 StringBuilder sb = new StringBuilder()
1974 sb.append(" results: ")
1975 sb.append(colString(s, col && !nocol, colour, text))
1977 sb.append("${rc} tests, ")
1978 sb.append(colString(s, col && rs > 0, 'green', rs))
1979 sb.append(" successes, ")
1980 sb.append(colString(s, col && rf > 0, 'red', rf))
1981 sb.append(" failures, ")
1982 sb.append("${rsk} skipped) in ${t}")
1983 return sb.toString()
1986 private static void printResults(allResults) {
1988 // styler from https://stackoverflow.com/a/56139852
1989 def styler = 'black red green yellow blue magenta cyan white'.split().toList().withIndex(30).collectEntries { key, val -> [(key) : { "\033[${val}m${it}\033[0m" }] }
1992 def failedTests = false
1993 def summaryLines = []
1995 def totalsuccess = 0
1998 def totaltime = TimeCategory.getSeconds(0)
1999 // sort on project name then task name
2000 allResults.sort {a, b -> a[0] == b[0]? a[1]<=>b[1]:a[0] <=> b[0]}.each {
2001 def projectName = it[0]
2002 def taskName = it[1]
2006 def summaryCol = getSummaryLine(styler, projectName, taskName, result.resultType, result.testCount, result.successfulTestCount, result.failedTestCount, result.skippedTestCount, time, true)
2007 def summaryPlain = getSummaryLine(styler, projectName, taskName, result.resultType, result.testCount, result.successfulTestCount, result.failedTestCount, result.skippedTestCount, time, false)
2008 def reportLine = "Report file: ${report}"
2009 def ls = summaryPlain.length()
2010 def lr = reportLine.length()
2011 def m = [ls, lr].max()
2014 def info = [ls, summaryCol, reportLine]
2015 summaryLines.add(info)
2016 failedTests |= result.resultType == TestResult.ResultType.FAILURE
2017 totalcount += result.testCount
2018 totalsuccess += result.successfulTestCount
2019 totalfail += result.failedTestCount
2020 totalskip += result.skippedTestCount
2023 def totalSummaryCol = getSummaryLine(styler, "OVERALL", "", failedTests?TestResult.ResultType.FAILURE:TestResult.ResultType.SUCCESS, totalcount, totalsuccess, totalfail, totalskip, totaltime, true)
2024 def totalSummaryPlain = getSummaryLine(styler, "OVERALL", "", failedTests?TestResult.ResultType.FAILURE:TestResult.ResultType.SUCCESS, totalcount, totalsuccess, totalfail, totalskip, totaltime, false)
2025 def tls = totalSummaryPlain.length()
2026 if (tls > maxLength)
2028 def info = [tls, totalSummaryCol, null]
2029 summaryLines.add(info)
2031 def allSummaries = []
2032 for(sInfo : summaryLines) {
2034 def summary = sInfo[1]
2035 def report = sInfo[2]
2037 StringBuilder sb = new StringBuilder()
2038 sb.append("│" + summary + " " * (maxLength - ls) + "│")
2039 if (report != null) {
2040 sb.append("\n│" + report + " " * (maxLength - report.length()) + "│")
2042 allSummaries += sb.toString()
2045 println "┌${"${"─" * maxLength}"}┐"
2046 println allSummaries.join("\n├${"${"─" * maxLength}"}┤\n")
2047 println "└${"${"─" * maxLength}"}┘"
2049 /* END of test tasks results summary */
2053 task compileLinkCheck(type: JavaCompile) {
2055 classpath = files("${jalviewDir}/${utils_dir}")
2056 destinationDir = file("${jalviewDir}/${utils_dir}")
2057 source = fileTree(dir: "${jalviewDir}/${utils_dir}", include: ["HelpLinksChecker.java", "BufferedLineReader.java"])
2059 inputs.file("${jalviewDir}/${utils_dir}/HelpLinksChecker.java")
2060 inputs.file("${jalviewDir}/${utils_dir}/HelpLinksChecker.java")
2061 outputs.file("${jalviewDir}/${utils_dir}/HelpLinksChecker.class")
2062 outputs.file("${jalviewDir}/${utils_dir}/BufferedLineReader.class")
2066 task linkCheck(type: JavaExec) {
2068 dependsOn compileLinkCheck
2070 def helpLinksCheckerOutFile = file("${jalviewDir}/${utils_dir}/HelpLinksChecker.out")
2071 classpath = files("${jalviewDir}/${utils_dir}")
2072 main = "HelpLinksChecker"
2073 workingDir = "${helpBuildDir}"
2074 args = [ "${helpBuildDir}/${help_dir}", "-nointernet" ]
2076 def outFOS = new FileOutputStream(helpLinksCheckerOutFile, false) // false == don't append
2077 standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
2080 errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
2084 inputs.dir(helpBuildDir)
2085 outputs.file(helpLinksCheckerOutFile)
2090 // import the pubhtmlhelp target
2091 ant.properties.basedir = "${jalviewDir}"
2092 ant.properties.helpBuildDir = "${helpBuildDir}/${help_dir}"
2093 ant.importBuild "${utils_dir}/publishHelp.xml"
2096 task cleanPackageDir(type: Delete) {
2098 delete fileTree(dir: "${jalviewDir}/${package_dir}", include: "*.jar")
2102 // block of dependencies
2103 //compileTestJava.dependsOn compileLinkCheck //
2104 //copyChannelResources.dependsOn compileLinkCheck //
2105 //convertMdFiles.dependsOn compileLinkCheck //
2109 dependsOn //linkCheck
2112 attributes "Main-Class": main_class,
2113 "Permissions": "all-permissions",
2114 "Application-Name": applicationName,
2115 "Codebase": application_codebase,
2116 "Implementation-Version": JALVIEW_VERSION
2119 def destinationDirectory = "${jalviewDir}/${package_dir}"
2120 destinationDirectory = file(destinationDirectory)
2121 archiveFileName = rootProject.name+".jar"
2122 duplicatesStrategy "EXCLUDE"
2129 exclude "**/*.jar.*"
2131 inputs.dir(sourceSets.main.java.destinationDirectory)
2132 sourceSets.main.resources.srcDirs.each{ dir ->
2135 outputs.file("${destinationDirectory}/${archiveFileName}")
2139 task copyJars(type: Copy) {
2140 from fileTree(dir: classesDir, include: "**/*.jar").files
2141 into "${jalviewDir}/${package_dir}"
2145 // doing a Sync instead of Copy as Copy doesn't deal with "outputs" very well
2146 task syncJars(type: Sync) {
2148 from fileTree(dir: "${jalviewDir}/${libDistDir}", include: "**/*.jar").files
2149 into "${jalviewDir}/${package_dir}"
2151 include jar.archiveFileName.getOrNull()
2158 description = "Put all required libraries in dist"
2159 // order of "cleanPackageDir", "copyJars", "jar" important!
2160 jar.mustRunAfter cleanPackageDir
2161 syncJars.mustRunAfter cleanPackageDir
2162 dependsOn cleanPackageDir
2165 outputs.dir("${jalviewDir}/${package_dir}")
2170 dependsOn cleanPackageDir
2176 task launcherJar(type: Jar) {
2179 "Main-Class": shadow_jar_main_class,
2180 "Implementation-Version": JALVIEW_VERSION,
2181 "Application-Name": applicationName
2187 group = "distribution"
2188 description = "Create a single jar file with all dependency libraries merged. Can be run with java -jar"
2193 def jarFiles = fileTree(dir: "${jalviewDir}/${libDistDir}", include: "*.jar", exclude: "regex.jar").getFiles()
2194 def groovyJars = jarFiles.findAll {it1 -> file(it1).getName().startsWith("groovy-swing")}
2195 def otherJars = jarFiles.findAll {it2 -> !file(it2).getName().startsWith("groovy-swing")}
2200 // shadowJar manifest must inheritFrom another Jar task. Can't set attributes here.
2201 inheritFrom(project.tasks.launcherJar.manifest)
2203 // we need to include the groovy-swing Include-Package for it to run in the shadowJar
2205 def jarFileManifests = []
2206 groovyJars.each { jarFile ->
2207 def mf = zipTree(jarFile).getFiles().find { it.getName().equals("MANIFEST.MF") }
2209 jarFileManifests += mf
2213 from (jarFileManifests) {
2214 eachEntry { details ->
2215 if (!details.key.equals("Import-Package")) {
2223 duplicatesStrategy "INCLUDE"
2225 // this mainClassName is mandatory but gets ignored due to manifest created in doFirst{}. Set the Main-Class as an attribute in launcherJar instead
2226 mainClassName = shadow_jar_main_class
2228 archiveClassifier = "all-"+JALVIEW_VERSION+"-j"+JAVA_VERSION
2232 task getdownImagesCopy() {
2233 inputs.dir getdownImagesDir
2234 outputs.dir getdownImagesBuildDir
2238 from(getdownImagesDir) {
2239 include("*getdown*.png")
2241 into getdownImagesBuildDir
2246 task getdownImagesProcess() {
2247 dependsOn getdownImagesCopy
2250 if (backgroundImageText) {
2251 if (convertBinary == null) {
2252 throw new StopExecutionException("No ImageMagick convert binary installed at '${convertBinaryExpectedLocation}'")
2254 if (!project.hasProperty("getdown_background_image_text_suffix_cmd")) {
2255 throw new StopExecutionException("No property 'getdown_background_image_text_suffix_cmd' defined. See channel_gradle.properties for channel ${CHANNEL}")
2257 fileTree(dir: getdownImagesBuildDir, include: "*background*.png").getFiles().each { file ->
2259 executable convertBinary
2262 '-font', getdown_background_image_text_font,
2263 '-fill', getdown_background_image_text_colour,
2264 '-draw', sprintf(getdown_background_image_text_suffix_cmd, channelSuffix),
2265 '-draw', sprintf(getdown_background_image_text_commit_cmd, "git-commit: ${gitHash}"),
2266 '-draw', sprintf(getdown_background_image_text_date_cmd, getDate("yyyy-MM-dd HH:mm:ss")),
2275 task getdownImages() {
2276 dependsOn getdownImagesProcess
2279 task getdownWebsiteBuild() {
2280 group = "distribution"
2281 description = "Create the getdown minimal app folder, and website folder for this version of jalview. Website folder also used for offline app installer. No digest is created."
2283 dependsOn getdownImages
2288 def getdownWebsiteResourceFilenames = []
2289 def getdownResourceDir = getdownResourceDir
2290 def getdownResourceFilenames = []
2293 // clean the getdown website and files dir before creating getdown folders
2294 delete getdownAppBaseDir
2295 delete getdownFilesDir
2298 from buildProperties
2299 rename(file(buildProperties).getName(), getdown_build_properties)
2302 getdownWebsiteResourceFilenames += "${getdownAppDistDir}/${getdown_build_properties}"
2305 from channelPropsFile
2306 filter(ReplaceTokens,
2310 'SUFFIX': channelSuffix
2313 into getdownAppBaseDir
2315 getdownWebsiteResourceFilenames += file(channelPropsFile).getName()
2317 // set some getdownTxt_ properties then go through all properties looking for getdownTxt_...
2318 def props = project.properties.sort { it.key }
2319 if (getdownAltJavaMinVersion != null && getdownAltJavaMinVersion.length() > 0) {
2320 props.put("getdown_txt_java_min_version", getdownAltJavaMinVersion)
2322 if (getdownAltJavaMaxVersion != null && getdownAltJavaMaxVersion.length() > 0) {
2323 props.put("getdown_txt_java_max_version", getdownAltJavaMaxVersion)
2325 if (getdownAltMultiJavaLocation != null && getdownAltMultiJavaLocation.length() > 0) {
2326 props.put("getdown_txt_multi_java_location", getdownAltMultiJavaLocation)
2328 if (getdownImagesBuildDir != null && file(getdownImagesBuildDir).exists()) {
2329 props.put("getdown_txt_ui.background_image", "${getdownImagesBuildDir}/${getdown_background_image}")
2330 props.put("getdown_txt_ui.instant_background_image", "${getdownImagesBuildDir}/${getdown_instant_background_image}")
2331 props.put("getdown_txt_ui.error_background", "${getdownImagesBuildDir}/${getdown_error_background}")
2332 props.put("getdown_txt_ui.progress_image", "${getdownImagesBuildDir}/${getdown_progress_image}")
2333 props.put("getdown_txt_ui.icon", "${getdownImagesDir}/${getdown_icon}")
2334 props.put("getdown_txt_ui.mac_dock_icon", "${getdownImagesDir}/${getdown_mac_dock_icon}")
2337 props.put("getdown_txt_title", jalview_name)
2338 props.put("getdown_txt_ui.name", applicationName)
2340 // start with appbase
2341 getdownTextLines += "appbase = ${getdownAppBase}"
2342 props.each{ prop, val ->
2343 if (prop.startsWith("getdown_txt_") && val != null) {
2344 if (prop.startsWith("getdown_txt_multi_")) {
2345 def key = prop.substring(18)
2346 val.split(",").each{ v ->
2347 def line = "${key} = ${v}"
2348 getdownTextLines += line
2351 // file values rationalised
2352 if (val.indexOf('/') > -1 || prop.startsWith("getdown_txt_resource")) {
2354 if (val.indexOf('/') == 0) {
2357 } else if (val.indexOf('/') > 0) {
2358 // relative path (relative to jalviewDir)
2359 r = file( "${jalviewDir}/${val}" )
2362 val = "${getdown_resource_dir}/" + r.getName()
2363 getdownWebsiteResourceFilenames += val
2364 getdownResourceFilenames += r.getPath()
2367 if (! prop.startsWith("getdown_txt_resource")) {
2368 def line = prop.substring(12) + " = ${val}"
2369 getdownTextLines += line
2375 getdownWebsiteResourceFilenames.each{ filename ->
2376 getdownTextLines += "resource = ${filename}"
2378 getdownResourceFilenames.each{ filename ->
2381 into getdownResourceDir
2385 def getdownWrapperScripts = [ getdown_bash_wrapper_script, getdown_powershell_wrapper_script, getdown_batch_wrapper_script ]
2386 getdownWrapperScripts.each{ script ->
2387 def s = file( "${jalviewDir}/utils/getdown/${getdown_wrapper_script_dir}/${script}" )
2391 into "${getdownAppBaseDir}/${getdown_wrapper_script_dir}"
2393 getdownTextLines += "xresource = ${getdown_wrapper_script_dir}/${script}"
2398 fileTree(file(package_dir)).each{ f ->
2399 if (f.isDirectory()) {
2400 def files = fileTree(dir: f, include: ["*"]).getFiles()
2402 } else if (f.exists()) {
2406 def jalviewJar = jar.archiveFileName.getOrNull()
2407 // put jalview.jar first for CLASSPATH and .properties files reasons
2408 codeFiles.sort{a, b -> ( a.getName() == jalviewJar ? -1 : ( b.getName() == jalviewJar ? 1 : a <=> b ) ) }.each{f ->
2409 def name = f.getName()
2410 def line = "code = ${getdownAppDistDir}/${name}"
2411 getdownTextLines += line
2418 // NOT USING MODULES YET, EVERYTHING SHOULD BE IN dist
2420 if (JAVA_VERSION.equals("11")) {
2421 def j11libFiles = fileTree(dir: "${jalviewDir}/${j11libDir}", include: ["*.jar"]).getFiles()
2422 j11libFiles.sort().each{f ->
2423 def name = f.getName()
2424 def line = "code = ${getdown_j11lib_dir}/${name}"
2425 getdownTextLines += line
2428 into getdownJ11libDir
2434 // 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.
2435 //getdownTextLines += "class = " + file(getdownLauncher).getName()
2436 getdownTextLines += "resource = ${getdown_launcher_new}"
2437 getdownTextLines += "class = ${main_class}"
2438 // Not setting these properties in general so that getdownappbase and getdowndistdir will default to release version in jalview.bin.Cache
2439 if (getdownSetAppBaseProperty) {
2440 getdownTextLines += "jvmarg = -Dgetdowndistdir=${getdownAppDistDir}"
2441 getdownTextLines += "jvmarg = -Dgetdownappbase=${getdownAppBase}"
2444 def getdownTxt = file("${getdownAppBaseDir}/getdown.txt")
2445 getdownTxt.write(getdownTextLines.join("\n"))
2447 getdownLaunchJvl = getdown_launch_jvl_name + ( (jvlChannelName != null && jvlChannelName.length() > 0)?"-${jvlChannelName}":"" ) + ".jvl"
2448 def launchJvl = file("${getdownAppBaseDir}/${getdownLaunchJvl}")
2449 launchJvl.write("appbase=${getdownAppBase}")
2451 // files going into the getdown website dir: getdown-launcher.jar
2453 from getdownLauncher
2454 rename(file(getdownLauncher).getName(), getdown_launcher_new)
2455 into getdownAppBaseDir
2458 // files going into the getdown website dir: getdown-launcher(-local).jar
2460 from getdownLauncher
2461 if (file(getdownLauncher).getName() != getdown_launcher) {
2462 rename(file(getdownLauncher).getName(), getdown_launcher)
2464 into getdownAppBaseDir
2467 // files going into the getdown website dir: ./install dir and files
2468 if (! (CHANNEL.startsWith("ARCHIVE") || CHANNEL.startsWith("DEVELOP"))) {
2471 from getdownLauncher
2472 from "${getdownAppDir}/${getdown_build_properties}"
2473 if (file(getdownLauncher).getName() != getdown_launcher) {
2474 rename(file(getdownLauncher).getName(), getdown_launcher)
2476 into getdownInstallDir
2479 // and make a copy in the getdown files dir (these are not downloaded by getdown)
2481 from getdownInstallDir
2482 into getdownFilesInstallDir
2486 // files going into the getdown files dir: getdown.txt, getdown-launcher.jar, channel-launch.jvl, build_properties
2490 from getdownLauncher
2491 from "${getdownAppBaseDir}/${getdown_build_properties}"
2492 from "${getdownAppBaseDir}/${channel_props}"
2493 if (file(getdownLauncher).getName() != getdown_launcher) {
2494 rename(file(getdownLauncher).getName(), getdown_launcher)
2496 into getdownFilesDir
2499 // and ./resource (not all downloaded by getdown)
2501 from getdownResourceDir
2502 into "${getdownFilesDir}/${getdown_resource_dir}"
2507 inputs.dir("${jalviewDir}/${package_dir}")
2509 outputs.dir(getdownAppBaseDir)
2510 outputs.dir(getdownFilesDir)
2514 // a helper task to allow getdown digest of any dir: `gradle getdownDigestDir -PDIGESTDIR=/path/to/my/random/getdown/dir
2515 task getdownDigestDir(type: JavaExec) {
2517 description "A task to run a getdown Digest on a dir with getdown.txt. Provide a DIGESTDIR property via -PDIGESTDIR=..."
2519 def digestDirPropertyName = "DIGESTDIR"
2521 classpath = files(getdownLauncher)
2522 def digestDir = findProperty(digestDirPropertyName)
2523 if (digestDir == null) {
2524 throw new GradleException("Must provide a DIGESTDIR value to produce an alternative getdown digest")
2528 main = "com.threerings.getdown.tools.Digester"
2532 task getdownDigest(type: JavaExec) {
2533 group = "distribution"
2534 description = "Digest the getdown website folder"
2536 dependsOn getdownWebsiteBuild
2539 classpath = files(getdownLauncher)
2541 main = "com.threerings.getdown.tools.Digester"
2542 args getdownAppBaseDir
2543 inputs.dir(getdownAppBaseDir)
2544 outputs.file("${getdownAppBaseDir}/digest2.txt")
2549 group = "distribution"
2550 description = "Create the minimal and full getdown app folder for installers and website and create digest file"
2551 dependsOn getdownDigest
2553 if (reportRsyncCommand) {
2554 def fromDir = getdownAppBaseDir + (getdownAppBaseDir.endsWith('/')?'':'/')
2555 def toDir = "${getdown_rsync_dest}/${getdownDir}" + (getdownDir.endsWith('/')?'':'/')
2556 println "LIKELY RSYNC COMMAND:"
2557 println "mkdir -p '$toDir'\nrsync -avh --delete '$fromDir' '$toDir'"
2558 if (RUNRSYNC == "true") {
2560 commandLine "mkdir", "-p", toDir
2563 commandLine "rsync", "-avh", "--delete", fromDir, toDir
2570 task getdownWebsite {
2571 group = "distribution"
2572 description = "A task to create the whole getdown channel website dir including digest file"
2574 dependsOn getdownWebsiteBuild
2575 dependsOn getdownDigest
2578 task getdownArchiveBuild() {
2579 group = "distribution"
2580 description = "Put files in the archive dir to go on the website"
2582 dependsOn getdownWebsiteBuild
2584 def v = "v${JALVIEW_VERSION_UNDERSCORES}"
2585 def vDir = "${getdownArchiveDir}/${v}"
2586 getdownFullArchiveDir = "${vDir}/getdown"
2587 getdownVersionLaunchJvl = "${vDir}/jalview-${v}.jvl"
2589 def vAltDir = "alt_${v}"
2590 def archiveImagesDir = "${jalviewDir}/${channel_properties_dir}/old/images"
2593 // cleanup old "old" dir
2594 delete getdownArchiveDir
2596 def getdownArchiveTxt = file("${getdownFullArchiveDir}/getdown.txt")
2597 getdownArchiveTxt.getParentFile().mkdirs()
2598 def getdownArchiveTextLines = []
2599 def getdownFullArchiveAppBase = "${getdownArchiveAppBase}${getdownArchiveAppBase.endsWith("/")?"":"/"}${v}/getdown/"
2603 from "${getdownAppBaseDir}/${getdownAppDistDir}"
2604 into "${getdownFullArchiveDir}/${vAltDir}"
2607 getdownTextLines.each { line ->
2608 line = line.replaceAll("^(?<s>appbase\\s*=\\s*).*", '${s}'+getdownFullArchiveAppBase)
2609 line = line.replaceAll("^(?<s>(resource|code)\\s*=\\s*)${getdownAppDistDir}/", '${s}'+vAltDir+"/")
2610 line = line.replaceAll("^(?<s>ui.background_image\\s*=\\s*).*\\.png", '${s}'+"${getdown_resource_dir}/jalview_archive_getdown_background.png")
2611 line = line.replaceAll("^(?<s>ui.instant_background_image\\s*=\\s*).*\\.png", '${s}'+"${getdown_resource_dir}/jalview_archive_getdown_background_initialising.png")
2612 line = line.replaceAll("^(?<s>ui.error_background\\s*=\\s*).*\\.png", '${s}'+"${getdown_resource_dir}/jalview_archive_getdown_background_error.png")
2613 line = line.replaceAll("^(?<s>ui.progress_image\\s*=\\s*).*\\.png", '${s}'+"${getdown_resource_dir}/jalview_archive_getdown_progress_bar.png")
2614 // remove the existing resource = resource/ or bin/ lines
2615 if (! line.matches("resource\\s*=\\s*(resource|bin)/.*")) {
2616 getdownArchiveTextLines += line
2620 // the resource dir -- add these files as resource lines in getdown.txt
2622 from "${archiveImagesDir}"
2623 into "${getdownFullArchiveDir}/${getdown_resource_dir}"
2625 getdownArchiveTextLines += "resource = ${getdown_resource_dir}/${file.getName()}"
2629 getdownArchiveTxt.write(getdownArchiveTextLines.join("\n"))
2631 def vLaunchJvl = file(getdownVersionLaunchJvl)
2632 vLaunchJvl.getParentFile().mkdirs()
2633 vLaunchJvl.write("appbase=${getdownFullArchiveAppBase}\n")
2634 def vLaunchJvlPath = vLaunchJvl.toPath().toAbsolutePath()
2635 def jvlLinkPath = file("${vDir}/jalview.jvl").toPath().toAbsolutePath()
2636 // for some reason filepath.relativize(fileInSameDirPath) gives a path to "../" which is wrong
2637 //java.nio.file.Files.createSymbolicLink(jvlLinkPath, jvlLinkPath.relativize(vLaunchJvlPath));
2638 java.nio.file.Files.createSymbolicLink(jvlLinkPath, java.nio.file.Paths.get(".",vLaunchJvl.getName()));
2640 // files going into the getdown files dir: getdown.txt, getdown-launcher.jar, channel-launch.jvl, build_properties
2642 from getdownLauncher
2643 from "${getdownAppBaseDir}/${getdownLaunchJvl}"
2644 from "${getdownAppBaseDir}/${getdown_launcher_new}"
2645 from "${getdownAppBaseDir}/${channel_props}"
2646 if (file(getdownLauncher).getName() != getdown_launcher) {
2647 rename(file(getdownLauncher).getName(), getdown_launcher)
2649 into getdownFullArchiveDir
2655 task getdownArchiveDigest(type: JavaExec) {
2656 group = "distribution"
2657 description = "Digest the getdown archive folder"
2659 dependsOn getdownArchiveBuild
2662 classpath = files(getdownLauncher)
2663 args getdownFullArchiveDir
2665 main = "com.threerings.getdown.tools.Digester"
2666 inputs.dir(getdownFullArchiveDir)
2667 outputs.file("${getdownFullArchiveDir}/digest2.txt")
2670 task getdownArchive() {
2671 group = "distribution"
2672 description = "Build the website archive dir with getdown digest"
2674 dependsOn getdownArchiveBuild
2675 dependsOn getdownArchiveDigest
2678 tasks.withType(JavaCompile) {
2679 options.encoding = 'UTF-8'
2685 delete getdownAppBaseDir
2686 delete getdownFilesDir
2687 delete getdownArchiveDir
2693 if (file(install4jHomeDir).exists()) {
2695 } else if (file(System.getProperty("user.home")+"/buildtools/install4j").exists()) {
2696 install4jHomeDir = System.getProperty("user.home")+"/buildtools/install4j"
2697 } else if (file("/Applications/install4j.app/Contents/Resources/app").exists()) {
2698 install4jHomeDir = "/Applications/install4j.app/Contents/Resources/app"
2700 installDir(file(install4jHomeDir))
2702 mediaTypes = Arrays.asList(install4j_media_types.split(","))
2706 task copyInstall4jTemplate {
2707 def install4jTemplateFile = file("${install4jDir}/${install4j_template}")
2708 def install4jFileAssociationsFile = file("${install4jDir}/${install4j_installer_file_associations}")
2709 inputs.file(install4jTemplateFile)
2710 inputs.file(install4jFileAssociationsFile)
2711 inputs.property("CHANNEL", { CHANNEL })
2712 outputs.file(install4jConfFile)
2715 def install4jConfigXml = new XmlParser().parse(install4jTemplateFile)
2717 // turn off code signing if no OSX_KEYPASS
2718 if (OSX_KEYPASS == "") {
2719 install4jConfigXml.'**'.codeSigning.each { codeSigning ->
2720 codeSigning.'@macEnabled' = "false"
2722 install4jConfigXml.'**'.windows.each { windows ->
2723 windows.'@runPostProcessor' = "false"
2727 // disable install screen for OSX dmg (for 2.11.2.0)
2728 install4jConfigXml.'**'.macosArchive.each { macosArchive ->
2729 macosArchive.attributes().remove('executeSetupApp')
2730 macosArchive.attributes().remove('setupAppId')
2733 // turn off checksum creation for LOCAL channel
2734 def e = install4jConfigXml.application[0]
2735 e.'@createChecksums' = string(install4jCheckSums)
2737 // put file association actions where placeholder action is
2738 def install4jFileAssociationsText = install4jFileAssociationsFile.text
2739 def fileAssociationActions = new XmlParser().parseText("<actions>${install4jFileAssociationsText}</actions>")
2740 install4jConfigXml.'**'.action.any { a -> // .any{} stops after the first one that returns true
2741 if (a.'@name' == 'EXTENSIONS_REPLACED_BY_GRADLE') {
2742 def parent = a.parent()
2744 fileAssociationActions.each { faa ->
2747 // don't need to continue in .any loop once replacements have been made
2752 // use Windows Program Group with Examples folder for RELEASE, and Program Group without Examples for everything else
2753 // NB we're deleting the /other/ one!
2754 // Also remove the examples subdir from non-release versions
2755 def customizedIdToDelete = "PROGRAM_GROUP_RELEASE"
2756 // 2.11.1.0 NOT releasing with the Examples folder in the Program Group
2757 if (false && CHANNEL=="RELEASE") { // remove 'false && ' to include Examples folder in RELEASE channel
2758 customizedIdToDelete = "PROGRAM_GROUP_NON_RELEASE"
2760 // remove the examples subdir from Full File Set
2761 def files = install4jConfigXml.files[0]
2762 def fileset = files.filesets.fileset.find { fs -> fs.'@customizedId' == "FULL_FILE_SET" }
2763 def root = files.roots.root.find { r -> r.'@fileset' == fileset.'@id' }
2764 def mountPoint = files.mountPoints.mountPoint.find { mp -> mp.'@root' == root.'@id' }
2765 def dirEntry = files.entries.dirEntry.find { de -> de.'@mountPoint' == mountPoint.'@id' && de.'@subDirectory' == "examples" }
2766 dirEntry.parent().remove(dirEntry)
2768 install4jConfigXml.'**'.action.any { a ->
2769 if (a.'@customizedId' == customizedIdToDelete) {
2770 def parent = a.parent()
2776 // write install4j file
2777 install4jConfFile.text = XmlUtil.serialize(install4jConfigXml)
2784 delete install4jConfFile
2788 task cleanInstallersDataFiles {
2789 def installersOutputTxt = file("${jalviewDir}/${install4jBuildDir}/output.txt")
2790 def installersSha256 = file("${jalviewDir}/${install4jBuildDir}/sha256sums")
2791 def hugoDataJsonFile = file("${jalviewDir}/${install4jBuildDir}/installers-${JALVIEW_VERSION_UNDERSCORES}.json")
2793 delete installersOutputTxt
2794 delete installersSha256
2795 delete hugoDataJsonFile
2799 task install4jDMGBackgroundImageCopy {
2800 inputs.file "${install4jDMGBackgroundImageDir}/${install4jDMGBackgroundImageFile}"
2801 outputs.dir "${install4jDMGBackgroundImageBuildDir}"
2804 from(install4jDMGBackgroundImageDir) {
2805 include(install4jDMGBackgroundImageFile)
2807 into install4jDMGBackgroundImageBuildDir
2812 task install4jDMGBackgroundImageProcess {
2813 dependsOn install4jDMGBackgroundImageCopy
2816 if (backgroundImageText) {
2817 if (convertBinary == null) {
2818 throw new StopExecutionException("No ImageMagick convert binary installed at '${convertBinaryExpectedLocation}'")
2820 if (!project.hasProperty("install4j_background_image_text_suffix_cmd")) {
2821 throw new StopExecutionException("No property 'install4j_background_image_text_suffix_cmd' defined. See channel_gradle.properties for channel ${CHANNEL}")
2823 fileTree(dir: install4jDMGBackgroundImageBuildDir, include: "*.png").getFiles().each { file ->
2825 executable convertBinary
2828 '-font', install4j_background_image_text_font,
2829 '-fill', install4j_background_image_text_colour,
2830 '-draw', sprintf(install4j_background_image_text_suffix_cmd, channelSuffix),
2831 '-draw', sprintf(install4j_background_image_text_commit_cmd, "git-commit: ${gitHash}"),
2832 '-draw', sprintf(install4j_background_image_text_date_cmd, getDate("yyyy-MM-dd HH:mm:ss")),
2841 task install4jDMGBackgroundImage {
2842 dependsOn install4jDMGBackgroundImageProcess
2845 task installerFiles(type: com.install4j.gradle.Install4jTask) {
2846 group = "distribution"
2847 description = "Create the install4j installers"
2849 dependsOn copyInstall4jTemplate
2850 dependsOn cleanInstallersDataFiles
2851 dependsOn install4jDMGBackgroundImage
2853 projectFile = install4jConfFile
2855 // create an md5 for the input files to use as version for install4j conf file
2856 def digest = MessageDigest.getInstance("MD5")
2858 (file("${install4jDir}/${install4j_template}").text +
2859 file("${install4jDir}/${install4j_info_plist_file_associations}").text +
2860 file("${install4jDir}/${install4j_installer_file_associations}").text).bytes)
2861 def filesMd5 = new BigInteger(1, digest.digest()).toString(16)
2862 if (filesMd5.length() >= 8) {
2863 filesMd5 = filesMd5.substring(0,8)
2865 def install4jTemplateVersion = "${JALVIEW_VERSION}_F${filesMd5}_C${gitHash}"
2868 'JALVIEW_NAME': jalview_name,
2869 'JALVIEW_APPLICATION_NAME': applicationName,
2870 'JALVIEW_DIR': "../..",
2871 'OSX_KEYSTORE': OSX_KEYSTORE,
2872 'OSX_APPLEID': OSX_APPLEID,
2873 'OSX_ALTOOLPASS': OSX_ALTOOLPASS,
2874 'JSIGN_SH': JSIGN_SH,
2875 'JRE_DIR': getdown_app_dir_java,
2876 'INSTALLER_TEMPLATE_VERSION': install4jTemplateVersion,
2877 'JALVIEW_VERSION': JALVIEW_VERSION,
2878 'JAVA_MIN_VERSION': JAVA_MIN_VERSION,
2879 'JAVA_MAX_VERSION': JAVA_MAX_VERSION,
2880 'JAVA_VERSION': JAVA_VERSION,
2881 'JAVA_INTEGER_VERSION': JAVA_INTEGER_VERSION,
2882 'VERSION': JALVIEW_VERSION,
2883 'COPYRIGHT_MESSAGE': install4j_copyright_message,
2884 'BUNDLE_ID': install4jBundleId,
2885 'INTERNAL_ID': install4jInternalId,
2886 'WINDOWS_APPLICATION_ID': install4jWinApplicationId,
2887 'MACOS_DMG_DS_STORE': install4jDMGDSStore,
2888 'MACOS_DMG_BG_IMAGE': "${install4jDMGBackgroundImageBuildDir}/${install4jDMGBackgroundImageFile}",
2889 'WRAPPER_LINK': getdownWrapperLink,
2890 'BASH_WRAPPER_SCRIPT': getdown_bash_wrapper_script,
2891 'POWERSHELL_WRAPPER_SCRIPT': getdown_powershell_wrapper_script,
2892 'BATCH_WRAPPER_SCRIPT': getdown_batch_wrapper_script,
2893 'WRAPPER_SCRIPT_BIN_DIR': getdown_wrapper_script_dir,
2894 'INSTALLER_NAME': install4jInstallerName,
2895 'INSTALL4J_UTILS_DIR': install4j_utils_dir,
2896 'GETDOWN_CHANNEL_DIR': getdownChannelDir,
2897 'GETDOWN_FILES_DIR': getdown_files_dir,
2898 'GETDOWN_RESOURCE_DIR': getdown_resource_dir,
2899 'GETDOWN_DIST_DIR': getdownAppDistDir,
2900 'GETDOWN_ALT_DIR': getdown_app_dir_alt,
2901 'GETDOWN_INSTALL_DIR': getdown_install_dir,
2902 'INFO_PLIST_FILE_ASSOCIATIONS_FILE': install4j_info_plist_file_associations,
2903 'BUILD_DIR': install4jBuildDir,
2904 'APPLICATION_CATEGORIES': install4j_application_categories,
2905 'APPLICATION_FOLDER': install4jApplicationFolder,
2906 'UNIX_APPLICATION_FOLDER': install4jUnixApplicationFolder,
2907 'EXECUTABLE_NAME': install4jExecutableName,
2908 'EXTRA_SCHEME': install4jExtraScheme,
2909 'MAC_ICONS_FILE': install4jMacIconsFile,
2910 'WINDOWS_ICONS_FILE': install4jWindowsIconsFile,
2911 'PNG_ICON_FILE': install4jPngIconFile,
2912 'BACKGROUND': install4jBackground,
2917 'windows': 'WINDOWS',
2921 // these are the bundled OS/architecture VMs needed by install4j
2924 [ "mac", "aarch64" ],
2925 [ "windows", "x64" ],
2927 [ "linux", "aarch64" ]
2929 osArch.forEach { os, arch ->
2930 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)
2931 // N.B. For some reason install4j requires the below filename to have underscores and not hyphens
2932 // otherwise running `gradle installers` generates a non-useful error:
2933 // `install4j: compilation failed. Reason: java.lang.NumberFormatException: For input string: "windows"`
2934 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)
2937 //println("INSTALL4J VARIABLES:")
2938 //variables.each{k,v->println("${k}=${v}")}
2940 destination = "${jalviewDir}/${install4jBuildDir}"
2941 buildSelected = true
2943 if (install4j_faster.equals("true") || CHANNEL.startsWith("LOCAL")) {
2945 disableSigning = true
2946 disableNotarization = true
2950 macKeystorePassword = OSX_KEYPASS
2953 if (OSX_ALTOOLPASS) {
2954 appleIdPassword = OSX_ALTOOLPASS
2955 disableNotarization = false
2957 disableNotarization = true
2961 println("Using projectFile "+projectFile)
2962 if (!disableNotarization) { println("Will notarize OSX App DMG") }
2966 inputs.dir(getdownAppBaseDir)
2967 inputs.file(install4jConfFile)
2968 inputs.file("${install4jDir}/${install4j_info_plist_file_associations}")
2969 outputs.dir("${jalviewDir}/${install4j_build_dir}/${JAVA_VERSION}")
2972 def getDataHash(File myFile) {
2973 HashCode hash = Files.asByteSource(myFile).hash(Hashing.sha256())
2974 return myFile.exists()
2976 "file" : myFile.getName(),
2977 "filesize" : myFile.length(),
2978 "sha256" : hash.toString()
2983 def writeDataJsonFile(File installersOutputTxt, File installersSha256, File dataJsonFile) {
2985 "channel" : getdownChannelName,
2986 "date" : getDate("yyyy-MM-dd HH:mm:ss"),
2987 "git-commit" : "${gitHash} [${gitBranch}]",
2988 "version" : JALVIEW_VERSION
2990 // install4j installer files
2991 if (installersOutputTxt.exists()) {
2993 installersOutputTxt.readLines().each { def line ->
2994 if (line.startsWith("#")) {
2997 line.replaceAll("\n","")
2998 def vals = line.split("\t")
2999 def filename = vals[3]
3000 def filesize = file(filename).length()
3001 filename = filename.replaceAll(/^.*\//, "")
3002 hash[vals[0]] = [ "id" : vals[0], "os" : vals[1], "name" : vals[2], "file" : filename, "filesize" : filesize ]
3003 idHash."${filename}" = vals[0]
3005 if (install4jCheckSums && installersSha256.exists()) {
3006 installersSha256.readLines().each { def line ->
3007 if (line.startsWith("#")) {
3010 line.replaceAll("\n","")
3011 def vals = line.split(/\s+\*?/)
3012 def filename = vals[1]
3013 def innerHash = (hash.(idHash."${filename}"))."sha256" = vals[0]
3019 "JAR": shadowJar.archiveFile, // executable JAR
3020 "JVL": getdownVersionLaunchJvl, // version JVL
3021 "SOURCE": sourceDist.archiveFile // source TGZ
3022 ].each { key, value ->
3023 def file = file(value)
3024 if (file.exists()) {
3025 def fileHash = getDataHash(file)
3026 if (fileHash != null) {
3027 hash."${key}" = fileHash;
3031 return dataJsonFile.write(new JsonBuilder(hash).toPrettyString())
3034 task staticMakeInstallersJsonFile {
3036 def output = findProperty("i4j_output")
3037 def sha256 = findProperty("i4j_sha256")
3038 def json = findProperty("i4j_json")
3039 if (output == null || sha256 == null || json == null) {
3040 throw new GradleException("Must provide paths to all of output.txt, sha256sums, and output.json with '-Pi4j_output=... -Pi4j_sha256=... -Pi4j_json=...")
3042 writeDataJsonFile(file(output), file(sha256), file(json))
3047 dependsOn installerFiles
3053 eclipse().configFile(eclipse_codestyle_file)
3057 task createSourceReleaseProperties(type: WriteProperties) {
3058 group = "distribution"
3059 description = "Create the source RELEASE properties file"
3061 def sourceTarBuildDir = "${buildDir}/sourceTar"
3062 def sourceReleasePropertiesFile = "${sourceTarBuildDir}/RELEASE"
3063 outputFile (sourceReleasePropertiesFile)
3066 releaseProps.each{ key, val -> property key, val }
3067 property "git.branch", gitBranch
3068 property "git.hash", gitHash
3071 outputs.file(outputFile)
3074 task sourceDist(type: Tar) {
3075 group "distribution"
3076 description "Create a source .tar.gz file for distribution"
3078 dependsOn createBuildProperties
3079 dependsOn convertMdFiles
3080 dependsOn eclipseAllPreferences
3081 dependsOn createSourceReleaseProperties
3084 def outputFileName = "${project.name}_${JALVIEW_VERSION_UNDERSCORES}.tar.gz"
3085 archiveFileName = outputFileName
3087 compression Compression.GZIP
3103 "**/*.class","$j11modDir/**/*.jar","appletlib","**/*locales",
3105 "utils/InstallAnywhere",
3120 "gradle.properties",
3132 ".settings/org.eclipse.buildship.core.prefs",
3133 ".settings/org.eclipse.jdt.core.prefs"
3137 exclude (EXCLUDE_FILES)
3138 include (PROCESS_FILES)
3139 filter(ReplaceTokens,
3143 'Version-Rel': JALVIEW_VERSION,
3144 'Year-Rel': getDate("yyyy")
3149 exclude (EXCLUDE_FILES)
3150 exclude (PROCESS_FILES)
3151 exclude ("appletlib")
3152 exclude ("**/*locales")
3153 exclude ("*locales/**")
3154 exclude ("utils/InstallAnywhere")
3156 exclude (getdown_files_dir)
3157 // getdown_website_dir and getdown_archive_dir moved to build/website/docroot/getdown
3158 //exclude (getdown_website_dir)
3159 //exclude (getdown_archive_dir)
3161 // exluding these as not using jars as modules yet
3162 exclude ("${j11modDir}/**/*.jar")
3165 include(INCLUDE_FILES)
3167 // from (jalviewDir) {
3168 // // explicit includes for stuff that seemed to not get included
3169 // include(fileTree("test/**/*."))
3170 // exclude(EXCLUDE_FILES)
3171 // exclude(PROCESS_FILES)
3174 from(file(buildProperties).getParent()) {
3175 include(file(buildProperties).getName())
3176 rename(file(buildProperties).getName(), "build_properties")
3178 line.replaceAll("^INSTALLATION=.*\$","INSTALLATION=Source Release"+" git-commit\\\\:"+gitHash+" ["+gitBranch+"]")
3182 def sourceTarBuildDir = "${buildDir}/sourceTar"
3183 from(sourceTarBuildDir) {
3184 // this includes the appended RELEASE properties file
3188 task dataInstallersJson {
3190 description "Create the installers-VERSION.json data file for installer files created"
3192 mustRunAfter installers
3193 mustRunAfter shadowJar
3194 mustRunAfter sourceDist
3195 mustRunAfter getdownArchive
3197 def installersOutputTxt = file("${jalviewDir}/${install4jBuildDir}/output.txt")
3198 def installersSha256 = file("${jalviewDir}/${install4jBuildDir}/sha256sums")
3200 if (installersOutputTxt.exists()) {
3201 inputs.file(installersOutputTxt)
3203 if (install4jCheckSums && installersSha256.exists()) {
3204 inputs.file(installersSha256)
3207 shadowJar.archiveFile, // executable JAR
3208 getdownVersionLaunchJvl, // version JVL
3209 sourceDist.archiveFile // source TGZ
3210 ].each { fileName ->
3211 if (file(fileName).exists()) {
3212 inputs.file(fileName)
3216 outputs.file(hugoDataJsonFile)
3219 writeDataJsonFile(installersOutputTxt, installersSha256, hugoDataJsonFile)
3225 description "Copies all help pages to build dir. Runs ant task 'pubhtmlhelp'."
3228 dependsOn pubhtmlhelp
3230 inputs.dir("${helpBuildDir}/${help_dir}")
3231 outputs.dir("${buildDir}/distributions/${help_dir}")
3235 task j2sSetHeadlessBuild {
3242 task jalviewjsEnableAltFileProperty(type: WriteProperties) {
3244 description "Enable the alternative J2S Config file for headless build"
3246 outputFile = jalviewjsJ2sSettingsFileName
3247 def j2sPropsFile = file(jalviewjsJ2sSettingsFileName)
3248 def j2sProps = new Properties()
3249 if (j2sPropsFile.exists()) {
3251 def j2sPropsFileFIS = new FileInputStream(j2sPropsFile)
3252 j2sProps.load(j2sPropsFileFIS)
3253 j2sPropsFileFIS.close()
3255 j2sProps.each { prop, val ->
3258 } catch (Exception e) {
3259 println("Exception reading ${jalviewjsJ2sSettingsFileName}")
3263 if (! j2sProps.stringPropertyNames().contains(jalviewjs_j2s_alt_file_property_config)) {
3264 property(jalviewjs_j2s_alt_file_property_config, jalviewjs_j2s_alt_file_property)
3269 task jalviewjsSetEclipseWorkspace {
3270 def propKey = "jalviewjs_eclipse_workspace"
3272 if (project.hasProperty(propKey)) {
3273 propVal = project.getProperty(propKey)
3274 if (propVal.startsWith("~/")) {
3275 propVal = System.getProperty("user.home") + propVal.substring(1)
3278 def propsFileName = "${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_eclipse_workspace_location_file}"
3279 def propsFile = file(propsFileName)
3280 def eclipseWsDir = propVal
3281 def props = new Properties()
3283 def writeProps = true
3284 if (( eclipseWsDir == null || !file(eclipseWsDir).exists() ) && propsFile.exists()) {
3285 def ins = new FileInputStream(propsFileName)
3288 if (props.getProperty(propKey, null) != null) {
3289 eclipseWsDir = props.getProperty(propKey)
3294 if (eclipseWsDir == null || !file(eclipseWsDir).exists()) {
3295 def tempDir = File.createTempDir()
3296 eclipseWsDir = tempDir.getAbsolutePath()
3299 eclipseWorkspace = file(eclipseWsDir)
3302 // do not run a headless transpile when we claim to be in Eclipse
3304 println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3305 throw new StopExecutionException("Not running headless transpile whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
3307 println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3311 props.setProperty(propKey, eclipseWsDir)
3312 propsFile.parentFile.mkdirs()
3313 def bytes = new ByteArrayOutputStream()
3314 props.store(bytes, null)
3315 def propertiesString = bytes.toString()
3316 propsFile.text = propertiesString
3322 println("ECLIPSE WORKSPACE: "+eclipseWorkspace.getPath())
3325 //inputs.property(propKey, eclipseWsDir) // eclipseWsDir only gets set once this task runs, so will be out-of-date
3326 outputs.file(propsFileName)
3327 outputs.upToDateWhen { eclipseWorkspace.exists() && propsFile.exists() }
3331 task jalviewjsEclipsePaths {
3334 def eclipseRoot = jalviewjs_eclipse_root
3335 if (eclipseRoot.startsWith("~/")) {
3336 eclipseRoot = System.getProperty("user.home") + eclipseRoot.substring(1)
3338 if (OperatingSystem.current().isMacOsX()) {
3339 eclipseRoot += "/Eclipse.app"
3340 eclipseBinary = "${eclipseRoot}/Contents/MacOS/eclipse"
3341 eclipseProduct = "${eclipseRoot}/Contents/Eclipse/.eclipseproduct"
3342 } else if (OperatingSystem.current().isWindows()) { // check these paths!!
3343 if (file("${eclipseRoot}/eclipse").isDirectory() && file("${eclipseRoot}/eclipse/.eclipseproduct").exists()) {
3344 eclipseRoot += "/eclipse"
3346 eclipseBinary = "${eclipseRoot}/eclipse.exe"
3347 eclipseProduct = "${eclipseRoot}/.eclipseproduct"
3348 } else { // linux or unix
3349 if (file("${eclipseRoot}/eclipse").isDirectory() && file("${eclipseRoot}/eclipse/.eclipseproduct").exists()) {
3350 eclipseRoot += "/eclipse"
3351 println("eclipseDir exists")
3353 eclipseBinary = "${eclipseRoot}/eclipse"
3354 eclipseProduct = "${eclipseRoot}/.eclipseproduct"
3357 eclipseVersion = "4.13" // default
3358 def assumedVersion = true
3359 if (file(eclipseProduct).exists()) {
3360 def fis = new FileInputStream(eclipseProduct)
3361 def props = new Properties()
3363 eclipseVersion = props.getProperty("version")
3365 assumedVersion = false
3368 def propKey = "eclipse_debug"
3369 eclipseDebug = (project.hasProperty(propKey) && project.getProperty(propKey).equals("true"))
3372 // do not run a headless transpile when we claim to be in Eclipse
3374 println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3375 throw new StopExecutionException("Not running headless transpile whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
3377 println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3380 if (!assumedVersion) {
3381 println("ECLIPSE VERSION=${eclipseVersion}")
3387 task printProperties {
3389 description "Output to console all System.properties"
3391 System.properties.each { key, val -> System.out.println("Property: ${key}=${val}") }
3397 dependsOn eclipseProject
3398 dependsOn eclipseClasspath
3399 dependsOn eclipseJdt
3403 // this version (type: Copy) will delete anything in the eclipse dropins folder that isn't in fromDropinsDir
3404 task jalviewjsEclipseCopyDropins(type: Copy) {
3405 dependsOn jalviewjsEclipsePaths
3407 def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjs_eclipse_dropins_dir}", include: "*.jar")
3408 inputFiles += file("${jalviewDir}/${jalviewjsJ2sPlugin}")
3409 def destinationDirectory = "${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_eclipse_tmp_dropins_dir}"
3412 into destinationDirectory
3416 // this eclipse -clean doesn't actually work
3417 task jalviewjsCleanEclipse(type: Exec) {
3418 dependsOn eclipseSetup
3419 dependsOn jalviewjsEclipsePaths
3420 dependsOn jalviewjsEclipseCopyDropins
3422 executable(eclipseBinary)
3423 args(["-nosplash", "--launcher.suppressErrors", "-data", eclipseWorkspace.getPath(), "-clean", "-console", "-consoleLog"])
3429 def inputString = """exit
3432 def inputByteStream = new ByteArrayInputStream(inputString.getBytes())
3433 standardInput = inputByteStream
3436 /* not really working yet
3437 jalviewjsEclipseCopyDropins.finalizedBy jalviewjsCleanEclipse
3441 task jalviewjsTransferUnzipSwingJs {
3442 def file_zip = "${jalviewDir}/${jalviewjs_swingjs_zip}"
3446 from zipTree(file_zip)
3447 into "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}"
3451 inputs.file file_zip
3452 outputs.dir "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}"
3456 task jalviewjsTransferUnzipLib {
3457 def zipFiles = fileTree(dir: "${jalviewDir}/${jalviewjs_libjs_dir}", include: "*.zip")
3460 zipFiles.each { file_zip ->
3462 from zipTree(file_zip)
3463 into "${jalviewDir}/${jalviewjsTransferSiteLibDir}"
3468 inputs.files zipFiles
3469 outputs.dir "${jalviewDir}/${jalviewjsTransferSiteLibDir}"
3473 task jalviewjsTransferUnzipAllLibs {
3474 dependsOn jalviewjsTransferUnzipSwingJs
3475 dependsOn jalviewjsTransferUnzipLib
3479 task jalviewjsCreateJ2sSettings(type: WriteProperties) {
3481 description "Create the alternative j2s file from the j2s.* properties"
3483 jalviewjsJ2sProps = project.properties.findAll { it.key.startsWith("j2s.") }.sort { it.key }
3484 def siteDirProperty = "j2s.site.directory"
3485 def setSiteDir = false
3486 jalviewjsJ2sProps.each { prop, val ->
3488 if (prop == siteDirProperty) {
3489 if (!(val.startsWith('/') || val.startsWith("file://") )) {
3490 val = "${jalviewDir}/${jalviewjsTransferSiteJsDir}/${val}"
3496 if (!setSiteDir) { // default site location, don't override specifically set property
3497 property(siteDirProperty,"${jalviewDirRelativePath}/${jalviewjsTransferSiteJsDir}")
3500 outputFile = jalviewjsJ2sAltSettingsFileName
3503 inputs.properties(jalviewjsJ2sProps)
3504 outputs.file(jalviewjsJ2sAltSettingsFileName)
3509 task jalviewjsEclipseSetup {
3510 dependsOn jalviewjsEclipseCopyDropins
3511 dependsOn jalviewjsSetEclipseWorkspace
3512 dependsOn jalviewjsCreateJ2sSettings
3516 task jalviewjsSyncAllLibs (type: Sync) {
3517 dependsOn jalviewjsTransferUnzipAllLibs
3518 def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjsTransferSiteLibDir}")
3519 inputFiles += fileTree(dir: "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}")
3520 def destinationDirectory = "${jalviewDir}/${jalviewjsSiteDir}"
3523 into destinationDirectory
3524 def outputFiles = []
3525 rename { filename ->
3526 outputFiles += "${destinationDirectory}/${filename}"
3533 // should this be exclude really ?
3534 duplicatesStrategy "INCLUDE"
3536 outputs.files outputFiles
3537 inputs.files inputFiles
3541 task jalviewjsSyncResources (type: Sync) {
3542 dependsOn buildResources
3544 def inputFiles = fileTree(dir: resourcesBuildDir)
3545 def destinationDirectory = "${jalviewDir}/${jalviewjsSiteDir}/${jalviewjs_j2s_subdir}"
3548 into destinationDirectory
3549 def outputFiles = []
3550 rename { filename ->
3551 outputFiles += "${destinationDirectory}/${filename}"
3557 outputs.files outputFiles
3558 inputs.files inputFiles
3562 task jalviewjsSyncSiteResources (type: Sync) {
3563 def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjs_site_resource_dir}")
3564 def destinationDirectory = "${jalviewDir}/${jalviewjsSiteDir}"
3567 into destinationDirectory
3568 def outputFiles = []
3569 rename { filename ->
3570 outputFiles += "${destinationDirectory}/${filename}"
3576 outputs.files outputFiles
3577 inputs.files inputFiles
3581 task jalviewjsSyncBuildProperties (type: Sync) {
3582 dependsOn createBuildProperties
3583 def inputFiles = [file(buildProperties)]
3584 def destinationDirectory = "${jalviewDir}/${jalviewjsSiteDir}/${jalviewjs_j2s_subdir}"
3587 into destinationDirectory
3588 def outputFiles = []
3589 rename { filename ->
3590 outputFiles += "${destinationDirectory}/${filename}"
3596 outputs.files outputFiles
3597 inputs.files inputFiles
3601 task jalviewjsProjectImport(type: Exec) {
3602 dependsOn eclipseSetup
3603 dependsOn jalviewjsEclipsePaths
3604 dependsOn jalviewjsEclipseSetup
3607 // do not run a headless import when we claim to be in Eclipse
3609 println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3610 throw new StopExecutionException("Not running headless import whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
3612 println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3616 //def projdir = eclipseWorkspace.getPath()+"/.metadata/.plugins/org.eclipse.core.resources/.projects/jalview/org.eclipse.jdt.core"
3617 def projdir = eclipseWorkspace.getPath()+"/.metadata/.plugins/org.eclipse.core.resources/.projects/jalview"
3618 executable(eclipseBinary)
3619 args(["-nosplash", "--launcher.suppressErrors", "-application", "com.seeq.eclipse.importprojects.headlessimport", "-data", eclipseWorkspace.getPath(), "-import", jalviewDirAbsolutePath])
3623 args += [ "--launcher.appendVmargs", "-vmargs", "-Dorg.eclipse.equinox.p2.reconciler.dropins.directory=${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_eclipse_tmp_dropins_dir}" ]
3625 args += [ "-D${j2sHeadlessBuildProperty}=true" ]
3626 args += [ "-D${jalviewjs_j2s_alt_file_property}=${jalviewjsJ2sAltSettingsFileName}" ]
3629 inputs.file("${jalviewDir}/.project")
3630 outputs.upToDateWhen {
3631 file(projdir).exists()
3636 task jalviewjsTranspile(type: Exec) {
3637 dependsOn jalviewjsEclipseSetup
3638 dependsOn jalviewjsProjectImport
3639 dependsOn jalviewjsEclipsePaths
3641 dependsOn jalviewjsEnableAltFileProperty
3645 // do not run a headless transpile when we claim to be in Eclipse
3647 println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3648 throw new StopExecutionException("Not running headless transpile whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
3650 println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3654 executable(eclipseBinary)
3655 args(["-nosplash", "--launcher.suppressErrors", "-application", "org.eclipse.jdt.apt.core.aptBuild", "-data", eclipseWorkspace, "-${jalviewjs_eclipse_build_arg}", eclipse_project_name ])
3659 args += [ "--launcher.appendVmargs", "-vmargs", "-Dorg.eclipse.equinox.p2.reconciler.dropins.directory=${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_eclipse_tmp_dropins_dir}" ]
3661 args += [ "-D${j2sHeadlessBuildProperty}=true" ]
3662 args += [ "-D${jalviewjs_j2s_alt_file_property}=${jalviewjsJ2sAltSettingsFileName}" ]
3668 stdout = new ByteArrayOutputStream()
3669 stderr = new ByteArrayOutputStream()
3671 def logOutFileName = "${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}"
3672 def logOutFile = file(logOutFileName)
3673 logOutFile.createNewFile()
3674 logOutFile.text = """ROOT: ${jalviewjs_eclipse_root}
3675 BINARY: ${eclipseBinary}
3676 VERSION: ${eclipseVersion}
3677 WORKSPACE: ${eclipseWorkspace}
3678 DEBUG: ${eclipseDebug}
3681 def logOutFOS = new FileOutputStream(logOutFile, true) // true == append
3682 // combine stdout and stderr
3683 def logErrFOS = logOutFOS
3685 if (jalviewjs_j2s_to_console.equals("true")) {
3686 standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
3687 new org.apache.tools.ant.util.TeeOutputStream(
3691 errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
3692 new org.apache.tools.ant.util.TeeOutputStream(
3697 standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
3700 errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
3707 if (stdout.toString().contains("Error processing ")) {
3708 // j2s did not complete transpile
3709 //throw new TaskExecutionException("Error during transpilation:\n${stderr}\nSee eclipse transpile log file '${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}'")
3710 if (jalviewjs_ignore_transpile_errors.equals("true")) {
3711 println("IGNORING TRANSPILE ERRORS")
3712 println("See eclipse transpile log file '${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}'")
3714 throw new GradleException("Error during transpilation:\n${stderr}\nSee eclipse transpile log file '${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}'")
3719 inputs.dir("${jalviewDir}/${sourceDir}")
3720 outputs.dir("${jalviewDir}/${jalviewjsTransferSiteJsDir}")
3721 outputs.upToDateWhen( { file("${jalviewDir}/${jalviewjsTransferSiteJsDir}${jalviewjs_server_resource}").exists() } )
3725 def jalviewjsCallCore(String name, FileCollection list, String prefixFile, String suffixFile, String jsfile, String zjsfile, File logOutFile, Boolean logOutConsole) {
3727 def stdout = new ByteArrayOutputStream()
3728 def stderr = new ByteArrayOutputStream()
3730 def coreFile = file(jsfile)
3732 msg = "Creating core for ${name}...\nGenerating ${jsfile}"
3734 logOutFile.createNewFile()
3735 logOutFile.append(msg+"\n")
3737 def coreTop = file(prefixFile)
3738 def coreBottom = file(suffixFile)
3739 coreFile.getParentFile().mkdirs()
3740 coreFile.createNewFile()
3741 coreFile.write( coreTop.getText("UTF-8") )
3745 def t = f.getText("UTF-8")
3746 t.replaceAll("Clazz\\.([^_])","Clazz_${1}")
3747 coreFile.append( t )
3749 msg = "...file '"+f.getPath()+"' does not exist, skipping"
3751 logOutFile.append(msg+"\n")
3754 coreFile.append( coreBottom.getText("UTF-8") )
3756 msg = "Generating ${zjsfile}"
3758 logOutFile.append(msg+"\n")
3759 def logOutFOS = new FileOutputStream(logOutFile, true) // true == append
3760 def logErrFOS = logOutFOS
3763 classpath = files(["${jalviewDir}/${jalviewjs_closure_compiler}"])
3764 main = "com.google.javascript.jscomp.CommandLineRunner"
3765 jvmArgs = [ "-Dfile.encoding=UTF-8" ]
3766 args = [ "--compilation_level", "SIMPLE_OPTIMIZATIONS", "--warning_level", "QUIET", "--charset", "UTF-8", "--js", jsfile, "--js_output_file", zjsfile ]
3769 msg = "\nRunning '"+commandLine.join(' ')+"'\n"
3771 logOutFile.append(msg+"\n")
3773 if (logOutConsole) {
3774 standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
3775 new org.apache.tools.ant.util.TeeOutputStream(
3779 errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
3780 new org.apache.tools.ant.util.TeeOutputStream(
3785 standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
3788 errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
3795 logOutFile.append(msg+"\n")
3799 task jalviewjsBuildAllCores {
3801 description "Build the core js lib closures listed in the classlists dir"
3802 dependsOn jalviewjsTranspile
3803 dependsOn jalviewjsTransferUnzipSwingJs
3805 def j2sDir = "${jalviewDir}/${jalviewjsTransferSiteJsDir}/${jalviewjs_j2s_subdir}"
3806 def swingJ2sDir = "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}/${jalviewjs_j2s_subdir}"
3807 def libJ2sDir = "${jalviewDir}/${jalviewjsTransferSiteLibDir}/${jalviewjs_j2s_subdir}"
3808 def jsDir = "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}/${jalviewjs_js_subdir}"
3809 def destinationDirectory = "${jalviewDir}/${jalviewjsTransferSiteCoreDir}/${jalviewjs_j2s_subdir}/core"
3810 def prefixFile = "${jsDir}/core/coretop2.js"
3811 def suffixFile = "${jsDir}/core/corebottom2.js"
3813 inputs.file prefixFile
3814 inputs.file suffixFile
3816 def classlistFiles = []
3817 // add the classlists found int the jalviewjs_classlists_dir
3818 fileTree(dir: "${jalviewDir}/${jalviewjs_classlists_dir}", include: "*.txt").each {
3820 def name = file.getName() - ".txt"
3827 // _jmol and _jalview cores. Add any other peculiar classlist.txt files here
3828 //classlistFiles += [ 'file': file("${jalviewDir}/${jalviewjs_classlist_jmol}"), 'name': "_jvjmol" ]
3829 classlistFiles += [ 'file': file("${jalviewDir}/${jalviewjs_classlist_jalview}"), 'name': jalviewjsJalviewCoreName ]
3831 jalviewjsCoreClasslists = []
3833 classlistFiles.each {
3836 def file = hash['file']
3837 if (! file.exists()) {
3838 //println("...classlist file '"+file.getPath()+"' does not exist, skipping")
3839 return false // this is a "continue" in groovy .each closure
3841 def name = hash['name']
3843 name = file.getName() - ".txt"
3851 def list = fileTree(dir: j2sDir, includes: filelist)
3853 def jsfile = "${destinationDirectory}/core${name}.js"
3854 def zjsfile = "${destinationDirectory}/core${name}.z.js"
3856 jalviewjsCoreClasslists += [
3865 outputs.file(jsfile)
3866 outputs.file(zjsfile)
3869 // _stevesoft core. add any cores without a classlist here (and the inputs and outputs)
3870 def stevesoftClasslistName = "_stevesoft"
3871 def stevesoftClasslist = [
3872 'jsfile': "${destinationDirectory}/core${stevesoftClasslistName}.js",
3873 'zjsfile': "${destinationDirectory}/core${stevesoftClasslistName}.z.js",
3874 'list': fileTree(dir: j2sDir, include: "com/stevesoft/pat/**/*.js"),
3875 'name': stevesoftClasslistName
3877 jalviewjsCoreClasslists += stevesoftClasslist
3878 inputs.files(stevesoftClasslist['list'])
3879 outputs.file(stevesoftClasslist['jsfile'])
3880 outputs.file(stevesoftClasslist['zjsfile'])
3883 def allClasslistName = "_all"
3884 def allJsFiles = fileTree(dir: j2sDir, include: "**/*.js")
3885 allJsFiles += fileTree(
3889 // these exlusions are files that the closure-compiler produces errors for. Should fix them
3890 "**/org/jmol/jvxl/readers/IsoIntersectFileReader.js",
3891 "**/org/jmol/export/JSExporter.js"
3894 allJsFiles += fileTree(
3898 // these exlusions are files that the closure-compiler produces errors for. Should fix them
3899 "**/sun/misc/Unsafe.js",
3900 "**/swingjs/jquery/jquery-editable-select.js",
3901 "**/swingjs/jquery/j2sComboBox.js",
3902 "**/sun/misc/FloatingDecimal.js"
3905 def allClasslist = [
3906 'jsfile': "${destinationDirectory}/core${allClasslistName}.js",
3907 'zjsfile': "${destinationDirectory}/core${allClasslistName}.z.js",
3909 'name': allClasslistName
3911 // not including this version of "all" core at the moment
3912 //jalviewjsCoreClasslists += allClasslist
3913 inputs.files(allClasslist['list'])
3914 outputs.file(allClasslist['jsfile'])
3915 outputs.file(allClasslist['zjsfile'])
3918 def logOutFile = file("${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_j2s_closure_stdout}")
3919 logOutFile.getParentFile().mkdirs()
3920 logOutFile.createNewFile()
3921 logOutFile.write(getDate("yyyy-MM-dd HH:mm:ss")+" jalviewjsBuildAllCores\n----\n")
3923 jalviewjsCoreClasslists.each {
3924 jalviewjsCallCore(it.name, it.list, prefixFile, suffixFile, it.jsfile, it.zjsfile, logOutFile, jalviewjs_j2s_to_console.equals("true"))
3931 def jalviewjsPublishCoreTemplate(String coreName, String templateName, File inputFile, String outputFile) {
3934 into file(outputFile).getParentFile()
3935 rename { filename ->
3936 if (filename.equals(inputFile.getName())) {
3937 return file(outputFile).getName()
3941 filter(ReplaceTokens,
3945 'MAIN': '"'+main_class+'"',
3947 'NAME': jalviewjsJalviewTemplateName+" [core ${coreName}]",
3948 'COREKEY': jalviewjs_core_key,
3949 'CORENAME': coreName
3956 task jalviewjsPublishCoreTemplates {
3957 dependsOn jalviewjsBuildAllCores
3958 def inputFileName = "${jalviewDir}/${j2s_coretemplate_html}"
3959 def inputFile = file(inputFileName)
3960 def destinationDirectory = "${jalviewDir}/${jalviewjsTransferSiteCoreDir}"
3962 def outputFiles = []
3963 jalviewjsCoreClasslists.each { cl ->
3964 def outputFile = "${destinationDirectory}/${jalviewjsJalviewTemplateName}_${cl.name}.html"
3965 cl['outputfile'] = outputFile
3966 outputFiles += outputFile
3970 jalviewjsCoreClasslists.each { cl ->
3971 jalviewjsPublishCoreTemplate(cl.name, jalviewjsJalviewTemplateName, inputFile, cl.outputfile)
3974 inputs.file(inputFile)
3975 outputs.files(outputFiles)
3979 task jalviewjsSyncCore (type: Sync) {
3980 dependsOn jalviewjsBuildAllCores
3981 dependsOn jalviewjsPublishCoreTemplates
3982 def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjsTransferSiteCoreDir}")
3983 def destinationDirectory = "${jalviewDir}/${jalviewjsSiteDir}"
3986 into destinationDirectory
3987 def outputFiles = []
3988 rename { filename ->
3989 outputFiles += "${destinationDirectory}/${filename}"
3995 outputs.files outputFiles
3996 inputs.files inputFiles
4000 // this Copy version of TransferSiteJs will delete anything else in the target dir
4001 task jalviewjsCopyTransferSiteJs(type: Copy) {
4002 dependsOn jalviewjsTranspile
4003 from "${jalviewDir}/${jalviewjsTransferSiteJsDir}"
4004 into "${jalviewDir}/${jalviewjsSiteDir}"
4008 // this Sync version of TransferSite is used by buildship to keep the website automatically up to date when a file changes
4009 task jalviewjsSyncTransferSiteJs(type: Sync) {
4010 from "${jalviewDir}/${jalviewjsTransferSiteJsDir}"
4012 into "${jalviewDir}/${jalviewjsSiteDir}"
4019 jalviewjsSyncAllLibs.mustRunAfter jalviewjsCopyTransferSiteJs
4020 jalviewjsSyncResources.mustRunAfter jalviewjsCopyTransferSiteJs
4021 jalviewjsSyncSiteResources.mustRunAfter jalviewjsCopyTransferSiteJs
4022 jalviewjsSyncBuildProperties.mustRunAfter jalviewjsCopyTransferSiteJs
4024 jalviewjsSyncAllLibs.mustRunAfter jalviewjsSyncTransferSiteJs
4025 jalviewjsSyncResources.mustRunAfter jalviewjsSyncTransferSiteJs
4026 jalviewjsSyncSiteResources.mustRunAfter jalviewjsSyncTransferSiteJs
4027 jalviewjsSyncBuildProperties.mustRunAfter jalviewjsSyncTransferSiteJs
4030 task jalviewjsPrepareSite {
4032 description "Prepares the website folder including unzipping files and copying resources"
4033 dependsOn jalviewjsSyncAllLibs
4034 dependsOn jalviewjsSyncResources
4035 dependsOn jalviewjsSyncSiteResources
4036 dependsOn jalviewjsSyncBuildProperties
4037 dependsOn jalviewjsSyncCore
4041 task jalviewjsBuildSite {
4043 description "Builds the whole website including transpiled code"
4044 dependsOn jalviewjsCopyTransferSiteJs
4045 dependsOn jalviewjsPrepareSite
4049 task cleanJalviewjsTransferSite {
4051 delete "${jalviewDir}/${jalviewjsTransferSiteJsDir}"
4052 delete "${jalviewDir}/${jalviewjsTransferSiteLibDir}"
4053 delete "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}"
4054 delete "${jalviewDir}/${jalviewjsTransferSiteCoreDir}"
4059 task cleanJalviewjsSite {
4060 dependsOn cleanJalviewjsTransferSite
4062 delete "${jalviewDir}/${jalviewjsSiteDir}"
4067 task jalviewjsSiteTar(type: Tar) {
4069 description "Creates a tar.gz file for the website"
4070 dependsOn jalviewjsBuildSite
4071 def outputFilename = "jalviewjs-site-${JALVIEW_VERSION}.tar.gz"
4072 archiveFileName = outputFilename
4074 compression Compression.GZIP
4076 from "${jalviewDir}/${jalviewjsSiteDir}"
4077 into jalviewjs_site_dir // this is inside the tar file
4079 inputs.dir("${jalviewDir}/${jalviewjsSiteDir}")
4083 task jalviewjsServer {
4085 def filename = "jalviewjsTest.html"
4086 description "Starts a webserver on localhost to test the website. See ${filename} to access local site on most recently used port."
4087 def htmlFile = "${jalviewDirAbsolutePath}/${filename}"
4092 def f = Class.forName("org.gradle.plugins.javascript.envjs.http.simple.SimpleHttpFileServerFactory")
4093 factory = f.newInstance()
4094 } catch (ClassNotFoundException e) {
4095 throw new GradleException("Unable to create SimpleHttpFileServerFactory")
4097 def port = Integer.valueOf(jalviewjs_server_port)
4102 while(port < start+1000 && !running) {
4104 def doc_root = new File("${jalviewDirAbsolutePath}/${jalviewjsSiteDir}")
4105 jalviewjsServer = factory.start(doc_root, port)
4107 url = jalviewjsServer.getResourceUrl(jalviewjs_server_resource)
4108 println("SERVER STARTED with document root ${doc_root}.")
4109 println("Go to "+url+" . Run gradle --stop to stop (kills all gradle daemons).")
4110 println("For debug: "+url+"?j2sdebug")
4111 println("For verbose: "+url+"?j2sverbose")
4112 } catch (Exception e) {
4117 <p><a href="${url}">JalviewJS Test. <${url}></a></p>
4118 <p><a href="${url}?j2sdebug">JalviewJS Test with debug. <${url}?j2sdebug></a></p>
4119 <p><a href="${url}?j2sverbose">JalviewJS Test with verbose. <${url}?j2sdebug></a></p>
4121 jalviewjsCoreClasslists.each { cl ->
4122 def urlcore = jalviewjsServer.getResourceUrl(file(cl.outputfile).getName())
4124 <p><a href="${urlcore}">${jalviewjsJalviewTemplateName} [core ${cl.name}]. <${urlcore}></a></p>
4126 println("For core ${cl.name}: "+urlcore)
4129 file(htmlFile).text = htmlText
4132 outputs.file(htmlFile)
4133 outputs.upToDateWhen({false})
4137 task cleanJalviewjsAll {
4139 description "Delete all configuration and build artifacts to do with JalviewJS build"
4140 dependsOn cleanJalviewjsSite
4141 dependsOn jalviewjsEclipsePaths
4144 delete "${jalviewDir}/${jalviewjsBuildDir}"
4145 delete "${jalviewDir}/${eclipse_bin_dir}"
4146 if (eclipseWorkspace != null && file(eclipseWorkspace.getAbsolutePath()+"/.metadata").exists()) {
4147 delete file(eclipseWorkspace.getAbsolutePath()+"/.metadata")
4149 delete jalviewjsJ2sAltSettingsFileName
4152 outputs.upToDateWhen( { false } )
4156 task jalviewjsIDE_checkJ2sPlugin {
4157 group "00 JalviewJS in Eclipse"
4158 description "Compare the swingjs/net.sf.j2s.core(-j11)?.jar file with the Eclipse IDE's plugin version (found in the 'dropins' dir)"
4161 def j2sPlugin = string("${jalviewDir}/${jalviewjsJ2sPlugin}")
4162 def j2sPluginFile = file(j2sPlugin)
4163 def eclipseHome = System.properties["eclipse.home.location"]
4164 if (eclipseHome == null || ! IN_ECLIPSE) {
4165 throw new StopExecutionException("Cannot find running Eclipse home from System.properties['eclipse.home.location']. Skipping J2S Plugin Check.")
4167 def eclipseJ2sPluginDirs = [ "${eclipseHome}/dropins" ]
4168 def altPluginsDir = System.properties["org.eclipse.equinox.p2.reconciler.dropins.directory"]
4169 if (altPluginsDir != null && file(altPluginsDir).exists()) {
4170 eclipseJ2sPluginDirs += altPluginsDir
4172 def foundPlugin = false
4173 def j2sPluginFileName = j2sPluginFile.getName()
4174 def eclipseJ2sPlugin
4175 def eclipseJ2sPluginFile
4176 eclipseJ2sPluginDirs.any { dir ->
4177 eclipseJ2sPlugin = "${dir}/${j2sPluginFileName}"
4178 eclipseJ2sPluginFile = file(eclipseJ2sPlugin)
4179 if (eclipseJ2sPluginFile.exists()) {
4185 def msg = "Eclipse J2S Plugin is not installed (could not find '${j2sPluginFileName}' in\n"+eclipseJ2sPluginDirs.join("\n")+"\n)\nTry running task jalviewjsIDE_copyJ2sPlugin"
4186 System.err.println(msg)
4187 throw new StopExecutionException(msg)
4190 def digest = MessageDigest.getInstance("MD5")
4192 digest.update(j2sPluginFile.text.bytes)
4193 def j2sPluginMd5 = new BigInteger(1, digest.digest()).toString(16).padLeft(32, '0')
4195 digest.update(eclipseJ2sPluginFile.text.bytes)
4196 def eclipseJ2sPluginMd5 = new BigInteger(1, digest.digest()).toString(16).padLeft(32, '0')
4198 if (j2sPluginMd5 != eclipseJ2sPluginMd5) {
4199 def msg = "WARNING! Eclipse J2S Plugin '${eclipseJ2sPlugin}' is different to this commit's version '${j2sPlugin}'"
4200 System.err.println(msg)
4201 throw new StopExecutionException(msg)
4203 def msg = "Eclipse J2S Plugin '${eclipseJ2sPlugin}' is the same as '${j2sPlugin}' (this is good)"
4209 task jalviewjsIDE_copyJ2sPlugin {
4210 group "00 JalviewJS in Eclipse"
4211 description "Copy the swingjs/net.sf.j2s.core(-j11)?.jar file into the Eclipse IDE's 'dropins' dir"
4214 def j2sPlugin = string("${jalviewDir}/${jalviewjsJ2sPlugin}")
4215 def j2sPluginFile = file(j2sPlugin)
4216 def eclipseHome = System.properties["eclipse.home.location"]
4217 if (eclipseHome == null || ! IN_ECLIPSE) {
4218 throw new StopExecutionException("Cannot find running Eclipse home from System.properties['eclipse.home.location']. NOT copying J2S Plugin.")
4220 def eclipseJ2sPlugin = "${eclipseHome}/dropins/${j2sPluginFile.getName()}"
4221 def eclipseJ2sPluginFile = file(eclipseJ2sPlugin)
4222 def msg = "WARNING! Copying this commit's j2s plugin '${j2sPlugin}' to Eclipse J2S Plugin '${eclipseJ2sPlugin}'\n* May require an Eclipse restart"
4223 System.err.println(msg)
4226 eclipseJ2sPluginFile.getParentFile().mkdirs()
4227 into eclipseJ2sPluginFile.getParent()
4233 task jalviewjsIDE_j2sFile {
4234 group "00 JalviewJS in Eclipse"
4235 description "Creates the .j2s file"
4236 dependsOn jalviewjsCreateJ2sSettings
4240 task jalviewjsIDE_SyncCore {
4241 group "00 JalviewJS in Eclipse"
4242 description "Build the core js lib closures listed in the classlists dir and publish core html from template"
4243 dependsOn jalviewjsSyncCore
4247 task jalviewjsIDE_SyncSiteAll {
4248 dependsOn jalviewjsSyncAllLibs
4249 dependsOn jalviewjsSyncResources
4250 dependsOn jalviewjsSyncSiteResources
4251 dependsOn jalviewjsSyncBuildProperties
4255 cleanJalviewjsTransferSite.mustRunAfter jalviewjsIDE_SyncSiteAll
4258 task jalviewjsIDE_PrepareSite {
4259 group "00 JalviewJS in Eclipse"
4260 description "Sync libs and resources to site dir, but not closure cores"
4262 dependsOn jalviewjsIDE_SyncSiteAll
4263 //dependsOn cleanJalviewjsTransferSite // not sure why this clean is here -- will slow down a re-run of this task
4267 task jalviewjsIDE_AssembleSite {
4268 group "00 JalviewJS in Eclipse"
4269 description "Assembles unzipped supporting zipfiles, resources, site resources and closure cores into the Eclipse transpiled site"
4270 dependsOn jalviewjsPrepareSite
4274 task jalviewjsIDE_SiteClean {
4275 group "00 JalviewJS in Eclipse"
4276 description "Deletes the Eclipse transpiled site"
4277 dependsOn cleanJalviewjsSite
4281 task jalviewjsIDE_Server {
4282 group "00 JalviewJS in Eclipse"
4283 description "Starts a webserver on localhost to test the website"
4284 dependsOn jalviewjsServer
4288 // buildship runs this at import or gradle refresh
4289 task eclipseSynchronizationTask {
4290 //dependsOn eclipseSetup
4291 dependsOn createBuildProperties
4293 dependsOn jalviewjsIDE_j2sFile
4294 dependsOn jalviewjsIDE_checkJ2sPlugin
4295 dependsOn jalviewjsIDE_PrepareSite
4300 // buildship runs this at build time or project refresh
4301 task eclipseAutoBuildTask {
4302 //dependsOn jalviewjsIDE_checkJ2sPlugin
4303 //dependsOn jalviewjsIDE_PrepareSite
4307 task jalviewjsCopyStderrLaunchFile(type: Copy) {
4308 from file(jalviewjs_stderr_launch)
4309 into jalviewjsSiteDir
4311 inputs.file jalviewjs_stderr_launch
4312 outputs.file jalviewjsStderrLaunchFilename
4315 task cleanJalviewjsChromiumUserDir {
4317 delete jalviewjsChromiumUserDir
4319 outputs.dir jalviewjsChromiumUserDir
4320 // always run when depended on
4321 outputs.upToDateWhen { !file(jalviewjsChromiumUserDir).exists() }
4324 task jalviewjsChromiumProfile {
4325 dependsOn cleanJalviewjsChromiumUserDir
4326 mustRunAfter cleanJalviewjsChromiumUserDir
4328 def firstRun = file("${jalviewjsChromiumUserDir}/First Run")
4331 mkdir jalviewjsChromiumProfileDir
4334 outputs.file firstRun
4337 task jalviewjsLaunchTest {
4339 description "Check JalviewJS opens in a browser"
4340 dependsOn jalviewjsBuildSite
4341 dependsOn jalviewjsCopyStderrLaunchFile
4342 dependsOn jalviewjsChromiumProfile
4344 def macOS = OperatingSystem.current().isMacOsX()
4345 def chromiumBinary = macOS ? jalviewjs_macos_chromium_binary : jalviewjs_chromium_binary
4346 if (chromiumBinary.startsWith("~/")) {
4347 chromiumBinary = System.getProperty("user.home") + chromiumBinary.substring(1)
4353 def timeoutms = Integer.valueOf(jalviewjs_chromium_overall_timeout) * 1000
4355 def binary = file(chromiumBinary)
4356 if (!binary.exists()) {
4357 throw new StopExecutionException("Could not find chromium binary '${chromiumBinary}'. Cannot run task ${name}.")
4359 stdout = new ByteArrayOutputStream()
4360 stderr = new ByteArrayOutputStream()
4363 if (jalviewjs_j2s_to_console.equals("true")) {
4364 execStdout = new org.apache.tools.ant.util.TeeOutputStream(
4367 execStderr = new org.apache.tools.ant.util.TeeOutputStream(
4375 "--no-sandbox", // --no-sandbox IS USED BY THE THORIUM APPIMAGE ON THE BUILDSERVER
4378 "--timeout=${timeoutms}",
4379 "--virtual-time-budget=${timeoutms}",
4380 "--user-data-dir=${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_chromium_user_dir}",
4381 "--profile-directory=${jalviewjs_chromium_profile_name}",
4382 "--allow-file-access-from-files",
4383 "--enable-logging=stderr",
4384 "file://${jalviewDirAbsolutePath}/${jalviewjsStderrLaunchFilename}"
4387 if (true || macOS) {
4388 ScheduledExecutorService executor = Executors.newScheduledThreadPool(3);
4389 Future f1 = executor.submit(
4392 standardOutput = execStdout
4393 errorOutput = execStderr
4394 executable(chromiumBinary)
4396 println "COMMAND: '"+commandLine.join(" ")+"'"
4398 executor.shutdownNow()
4402 def noChangeBytes = 0
4403 def noChangeIterations = 0
4404 executor.scheduleAtFixedRate(
4406 String stderrString = stderr.toString()
4407 // shutdown the task if we have a success string
4408 if (stderrString.contains(jalviewjs_desktop_init_string)) {
4411 executor.shutdownNow()
4413 // if no change in stderr for 10s then also end
4414 if (noChangeIterations >= jalviewjs_chromium_idle_timeout) {
4415 executor.shutdownNow()
4417 if (stderrString.length() == noChangeBytes) {
4418 noChangeIterations++
4420 noChangeBytes = stderrString.length()
4421 noChangeIterations = 0
4424 1, 1, TimeUnit.SECONDS)
4426 executor.schedule(new Runnable(){
4429 executor.shutdownNow()
4431 }, timeoutms, TimeUnit.MILLISECONDS)
4433 executor.awaitTermination(timeoutms+10000, TimeUnit.MILLISECONDS)
4434 executor.shutdownNow()
4441 stderr.toString().eachLine { line ->
4442 if (line.contains(jalviewjs_desktop_init_string)) {
4443 println("Found line '"+line+"'")
4449 throw new GradleException("Could not find evidence of Desktop launch in JalviewJS.")
4457 description "Build the JalviewJS site and run the launch test"
4458 dependsOn jalviewjsBuildSite
4459 dependsOn jalviewjsLaunchTest