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}")
198 useClover = clover.equals("true")
199 cloverBuildDir = "${buildDir}/clover"
200 cloverInstrDir = file("${cloverBuildDir}/clover-instr")
201 cloverClassesDir = file("${cloverBuildDir}/clover-classes")
202 cloverReportDir = file("${buildDir}/reports/clover")
203 cloverTestInstrDir = file("${cloverBuildDir}/clover-test-instr")
204 cloverTestClassesDir = file("${cloverBuildDir}/clover-test-classes")
205 //cloverTestClassesDir = cloverClassesDir
206 cloverDb = string("${cloverBuildDir}/clover.db")
208 testSourceDir = useClover ? cloverTestInstrDir : testDir
209 testClassesDir = useClover ? cloverTestClassesDir : "${jalviewDir}/${test_output_dir}"
212 backgroundImageText = BACKGROUNDIMAGETEXT
213 getdownChannelDir = string("${getdown_website_dir}/${propertiesChannelName}")
214 getdownAppBaseDir = string("${jalviewDir}/${getdownChannelDir}/${JAVA_VERSION}")
215 getdownArchiveDir = string("${jalviewDir}/${getdown_archive_dir}")
216 getdownFullArchiveDir = null
217 getdownTextLines = []
218 getdownLaunchJvl = null
219 getdownVersionLaunchJvl = null
221 buildProperties = null
223 // the following values might be overridden by the CHANNEL switch
224 getdownDir = string("${getdownChannelName}/${JAVA_VERSION}")
225 getdownAppBase = string("${getdown_channel_base}/${getdownDir}")
226 getdownArchiveAppBase = getdown_archive_base
227 getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher}")
228 getdownAppDistDir = getdown_app_dir_alt
229 getdownImagesDir = string("${jalviewDir}/${getdown_images_dir}")
230 getdownImagesBuildDir = string("${buildDir}/imagemagick/getdown")
231 getdownSetAppBaseProperty = false // whether to pass the appbase and appdistdir to the application
232 reportRsyncCommand = false
233 jvlChannelName = CHANNEL.toLowerCase()
234 install4jSuffix = CHANNEL.substring(0, 1).toUpperCase() + CHANNEL.substring(1).toLowerCase(); // BUILD -> Build
235 install4jDMGDSStore = "${install4j_images_dir}/${install4j_dmg_ds_store}"
236 install4jDMGBackgroundImageDir = "${install4j_images_dir}"
237 install4jDMGBackgroundImageBuildDir = "build/imagemagick/install4j"
238 install4jDMGBackgroundImageFile = "${install4j_dmg_background}"
239 install4jInstallerName = "${jalview_name} Non-Release Installer"
240 install4jExecutableName = install4j_executable_name
241 install4jExtraScheme = "jalviewextra"
242 install4jMacIconsFile = string("${install4j_images_dir}/${install4j_mac_icons_file}")
243 install4jWindowsIconsFile = string("${install4j_images_dir}/${install4j_windows_icons_file}")
244 install4jPngIconFile = string("${install4j_images_dir}/${install4j_png_icon_file}")
245 install4jBackground = string("${install4j_images_dir}/${install4j_background}")
246 install4jBuildDir = "${install4j_build_dir}/${JAVA_VERSION}"
247 install4jCheckSums = true
249 applicationName = "${jalview_name}"
253 // TODO: get bamboo build artifact URL for getdown artifacts
254 getdown_channel_base = bamboo_channelbase
255 getdownChannelName = string("${bamboo_planKey}/${JAVA_VERSION}")
256 getdownAppBase = string("${bamboo_channelbase}/${bamboo_planKey}${bamboo_getdown_channel_suffix}/${JAVA_VERSION}")
257 jvlChannelName += "_${getdownChannelName}"
258 // automatically add the test group Not-bamboo for exclusion
259 if ("".equals(testng_excluded_groups)) {
260 testng_excluded_groups = "Not-bamboo"
262 install4jExtraScheme = "jalviewb"
263 backgroundImageText = true
266 case [ "RELEASE", "JALVIEWJS-RELEASE" ]:
267 getdownAppDistDir = getdown_app_dir_release
268 getdownSetAppBaseProperty = true
269 reportRsyncCommand = true
271 install4jInstallerName = "${jalview_name} Installer"
272 install4jExtraScheme = (CHANNEL=="RELEASE")?"jalviewx":"jalviewjs"
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 outputDir = file(classesDir)
598 srcDirs = [ resourcesBuildDir, docBuildDir, helpBuildDir ]
601 compileClasspath = files(sourceSets.main.java.outputDir)
602 compileClasspath += fileTree(dir: "${jalviewDir}/${libDir}", include: ["*.jar"])
604 runtimeClasspath = compileClasspath
605 runtimeClasspath += files(sourceSets.main.resources.srcDirs)
610 srcDirs cloverInstrDir
611 outputDir = cloverClassesDir
615 srcDirs = sourceSets.main.resources.srcDirs
618 compileClasspath = files( sourceSets.clover.java.outputDir )
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 outputDir = file(testClassesDir)
634 srcDirs = useClover ? sourceSets.clover.resources.srcDirs : sourceSets.main.resources.srcDirs
637 compileClasspath = files( sourceSets.test.java.outputDir )
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.outputDir
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 outputDir 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 outputDir 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.outputDir
1104 dependsOn cleanClover
1106 delete sourceSets.test.java.outputDir
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 outputDir = "${docBuildDir}/${doc_dir}"
1202 include('**/*.html')
1204 filter(ReplaceTokens,
1208 'Version-Rel': JALVIEW_VERSION,
1209 'Year-Rel': getDate("yyyy")
1216 exclude('**/*.html')
1221 inputs.dir(inputDir)
1222 outputs.dir(outputDir)
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 outputDir = "${helpBuildDir}/${help_dir}"
1461 include('**/*.html')
1465 filter(ReplaceTokens,
1469 'Version-Rel': JALVIEW_VERSION,
1470 'Year-Rel': getDate("yyyy")
1477 exclude('**/*.html')
1484 inputs.dir(inputDir)
1485 outputs.files(helpFile)
1486 outputs.dir(outputDir)
1490 task releasesTemplates {
1492 description "Recreate whatsNew.html and releases.html from markdown files and templates in help"
1496 def releasesTemplateFile = file("${jalviewDir}/${releases_template}")
1497 def whatsnewTemplateFile = file("${jalviewDir}/${whatsnew_template}")
1498 def releasesHtmlFile = file("${helpBuildDir}/${help_dir}/${releases_html}")
1499 def whatsnewHtmlFile = file("${helpBuildDir}/${help_dir}/${whatsnew_html}")
1500 def releasesMdDir = "${jalviewDir}/${releases_dir}"
1501 def whatsnewMdDir = "${jalviewDir}/${whatsnew_dir}"
1504 def releaseMdFile = file("${releasesMdDir}/release-${JALVIEW_VERSION_UNDERSCORES}.md")
1505 def whatsnewMdFile = file("${whatsnewMdDir}/whatsnew-${JALVIEW_VERSION_UNDERSCORES}.md")
1507 if (CHANNEL == "RELEASE") {
1508 if (!releaseMdFile.exists()) {
1509 throw new GradleException("File ${releaseMdFile} must be created for RELEASE")
1511 if (!whatsnewMdFile.exists()) {
1512 throw new GradleException("File ${whatsnewMdFile} must be created for RELEASE")
1516 def releaseFiles = fileTree(dir: releasesMdDir, include: "release-*.md")
1517 def releaseFilesDates = releaseFiles.collectEntries {
1518 [(it): getMdDate(it)]
1520 releaseFiles = releaseFiles.sort { a,b -> releaseFilesDates[a].compareTo(releaseFilesDates[b]) }
1522 def releasesTemplate = releasesTemplateFile.text
1523 def m = releasesTemplate =~ /(?s)__VERSION_LOOP_START__(.*)__VERSION_LOOP_END__/
1524 def versionTemplate = m[0][1]
1526 MutableDataSet options = new MutableDataSet()
1528 def extensions = new ArrayList<>()
1529 options.set(Parser.EXTENSIONS, extensions)
1530 options.set(Parser.HTML_BLOCK_COMMENT_ONLY_FULL_LINE, true)
1532 Parser parser = Parser.builder(options).build()
1533 HtmlRenderer renderer = HtmlRenderer.builder(options).build()
1535 def actualVersions = releaseFiles.collect { rf ->
1536 def (rfMap, rfContent) = mdFileComponents(rf)
1537 return rfMap.version
1539 def versionsHtml = ""
1540 def linkedVersions = []
1541 releaseFiles.reverse().each { rFile ->
1542 def (rMap, rContent) = mdFileComponents(rFile)
1544 def versionLink = ""
1545 def partialVersion = ""
1546 def firstPart = true
1547 rMap.version.split("\\.").each { part ->
1548 def displayPart = ( firstPart ? "" : "." ) + part
1549 partialVersion += displayPart
1551 linkedVersions.contains(partialVersion)
1552 || ( actualVersions.contains(partialVersion) && partialVersion != rMap.version )
1554 versionLink += displayPart
1556 versionLink += "<a id=\"Jalview.${partialVersion}\">${displayPart}</a>"
1557 linkedVersions += partialVersion
1561 def displayDate = releaseFilesDates[rFile].format("dd/MM/yyyy")
1564 def rContentProcessed = ""
1565 rContent.eachLine { line ->
1566 if (lm = line =~ /^(\s*-)(\s*<!--[^>]*?-->)(.*)$/) {
1567 line = "${lm[0][1]}${lm[0][3]}${lm[0][2]}"
1568 } else if (lm = line =~ /^###([^#]+.*)$/) {
1569 line = "_${lm[0][1].trim()}_"
1571 rContentProcessed += line + "\n"
1574 def rContentSections = getMdSections(rContentProcessed)
1575 def rVersion = versionTemplate
1576 if (rVersion != "") {
1577 def rNewFeatures = rContentSections["new_features"]
1578 def rIssuesResolved = rContentSections["issues_resolved"]
1579 Node newFeaturesNode = parser.parse(rNewFeatures)
1580 String newFeaturesHtml = renderer.render(newFeaturesNode)
1581 Node issuesResolvedNode = parser.parse(rIssuesResolved)
1582 String issuesResolvedHtml = renderer.render(issuesResolvedNode)
1583 rVersion = hugoTemplateSubstitutions(rVersion,
1585 VERSION: rMap.version,
1586 VERSION_LINK: versionLink,
1587 DISPLAY_DATE: displayDate,
1588 NEW_FEATURES: newFeaturesHtml,
1589 ISSUES_RESOLVED: issuesResolvedHtml
1592 versionsHtml += rVersion
1596 releasesTemplate = releasesTemplate.replaceAll("(?s)__VERSION_LOOP_START__.*__VERSION_LOOP_END__", versionsHtml)
1597 releasesTemplate = hugoTemplateSubstitutions(releasesTemplate)
1598 releasesHtmlFile.text = releasesTemplate
1600 if (whatsnewMdFile.exists()) {
1601 def wnDisplayDate = releaseFilesDates[releaseMdFile] != null ? releaseFilesDates[releaseMdFile].format("dd MMMM yyyy") : ""
1602 def whatsnewMd = hugoTemplateSubstitutions(whatsnewMdFile.text)
1603 Node whatsnewNode = parser.parse(whatsnewMd)
1604 String whatsnewHtml = renderer.render(whatsnewNode)
1605 whatsnewHtml = whatsnewTemplateFile.text.replaceAll("__WHATS_NEW__", whatsnewHtml)
1606 whatsnewHtmlFile.text = hugoTemplateSubstitutions(whatsnewHtml,
1608 VERSION: JALVIEW_VERSION,
1609 DISPLAY_DATE: wnDisplayDate
1612 } else if (gradle.taskGraph.hasTask(":linkCheck")) {
1613 whatsnewHtmlFile.text = "Development build " + getDate("yyyy-MM-dd HH:mm:ss")
1618 inputs.file(releasesTemplateFile)
1619 inputs.file(whatsnewTemplateFile)
1620 inputs.dir(releasesMdDir)
1621 inputs.dir(whatsnewMdDir)
1622 outputs.file(releasesHtmlFile)
1623 outputs.file(whatsnewHtmlFile)
1627 task copyResources(type: Copy) {
1629 description = "Copy (and make text substitutions in) the resources dir to the build area"
1631 def inputDir = resourceDir
1632 def outputDir = resourcesBuildDir
1636 include('**/*.html')
1638 filter(ReplaceTokens,
1642 'Version-Rel': JALVIEW_VERSION,
1643 'Year-Rel': getDate("yyyy")
1650 exclude('**/*.html')
1655 inputs.dir(inputDir)
1656 outputs.dir(outputDir)
1659 task copyChannelResources(type: Copy) {
1660 dependsOn copyResources
1662 description = "Copy the channel resources dir to the build resources area"
1664 def inputDir = "${channelDir}/${resource_dir}"
1665 def outputDir = resourcesBuildDir
1667 include(channel_props)
1668 filter(ReplaceTokens,
1672 'SUFFIX': channelSuffix
1677 exclude(channel_props)
1681 inputs.dir(inputDir)
1682 outputs.dir(outputDir)
1685 task createBuildProperties(type: WriteProperties) {
1686 dependsOn copyResources
1688 description = "Create the ${buildProperties} file"
1690 inputs.dir(sourceDir)
1691 inputs.dir(resourcesBuildDir)
1692 outputFile (buildProperties)
1693 // taking time specific comment out to allow better incremental builds
1694 comment "--Jalview Build Details--\n"+getDate("yyyy-MM-dd HH:mm:ss")
1695 //comment "--Jalview Build Details--\n"+getDate("yyyy-MM-dd")
1696 property "BUILD_DATE", getDate("HH:mm:ss dd MMMM yyyy")
1697 property "VERSION", JALVIEW_VERSION
1698 property "INSTALLATION", INSTALLATION+" git-commit:"+gitHash+" ["+gitBranch+"]"
1699 property "JAVA_COMPILE_VERSION", JAVA_INTEGER_VERSION
1700 if (getdownSetAppBaseProperty) {
1701 property "GETDOWNAPPBASE", getdownAppBase
1702 property "GETDOWNAPPDISTDIR", getdownAppDistDir
1704 outputs.file(outputFile)
1708 task buildIndices(type: JavaExec) {
1710 classpath = sourceSets.main.compileClasspath
1711 main = "com.sun.java.help.search.Indexer"
1712 workingDir = "${helpBuildDir}/${help_dir}"
1715 inputs.dir("${workingDir}/${argDir}")
1717 outputs.dir("${classesDir}/doc")
1718 outputs.dir("${classesDir}/help")
1719 outputs.file("${workingDir}/JavaHelpSearch/DOCS")
1720 outputs.file("${workingDir}/JavaHelpSearch/DOCS.TAB")
1721 outputs.file("${workingDir}/JavaHelpSearch/OFFSETS")
1722 outputs.file("${workingDir}/JavaHelpSearch/POSITIONS")
1723 outputs.file("${workingDir}/JavaHelpSearch/SCHEMA")
1724 outputs.file("${workingDir}/JavaHelpSearch/TMAP")
1727 task buildResources {
1728 dependsOn copyResources
1729 dependsOn copyChannelResources
1730 dependsOn createBuildProperties
1734 dependsOn buildResources
1737 dependsOn releasesTemplates
1738 dependsOn convertMdFiles
1739 dependsOn buildIndices
1743 compileJava.dependsOn prepare
1744 run.dependsOn compileJava
1745 compileTestJava.dependsOn compileJava
1750 group = "Verification"
1751 description = "Runs all testTaskN tasks)"
1754 dependsOn cloverClasses
1756 dependsOn testClasses
1759 // not running tests in this task
1762 /* testTask0 is the main test task */
1763 task testTask0(type: Test) {
1764 group = "Verification"
1765 description = "The main test task. Runs all non-testTaskN-labelled tests (unless excluded)"
1767 includeGroups testng_groups.split(",")
1768 excludeGroups testng_excluded_groups.split(",")
1769 tasks.withType(Test).matching {it.name.startsWith("testTask") && it.name != name}.all {t -> excludeGroups t.name}
1771 useDefaultListeners=true
1773 timeout = Duration.ofMinutes(15)
1776 /* separated tests */
1777 task testTask1(type: Test) {
1778 group = "Verification"
1779 description = "Tests that need to be isolated from the main test run"
1782 excludeGroups testng_excluded_groups.split(",")
1784 useDefaultListeners=true
1786 timeout = Duration.ofMinutes(5)
1789 task testTask2(type: Test) {
1790 group = "Verification"
1791 description = "Tests that need to be isolated from the main test run"
1794 excludeGroups testng_excluded_groups.split(",")
1796 useDefaultListeners=true
1798 timeout = Duration.ofMinutes(5)
1800 task testTask3(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)
1812 /* insert more testTaskNs here -- change N to next digit or other string */
1814 task testTaskN(type: Test) {
1815 group = "Verification"
1816 description = "Tests that need to be isolated from the main test run"
1819 excludeGroups testng_excluded_groups.split(",")
1821 useDefaultListeners=true
1828 * adapted from https://medium.com/@wasyl/pretty-tests-summary-in-gradle-744804dd676c
1829 * to summarise test results from all Test tasks
1831 /* START of test tasks results summary */
1832 import groovy.time.TimeCategory
1833 import org.gradle.api.tasks.testing.logging.TestExceptionFormat
1834 import org.gradle.api.tasks.testing.logging.TestLogEvent
1835 rootProject.ext.testsResults = [] // Container for tests summaries
1837 tasks.withType(Test).matching {t -> t.getName().startsWith("testTask")}.all { testTask ->
1839 // from original test task
1841 dependsOn cloverClasses
1843 dependsOn testClasses //?
1846 // run main tests first
1847 if (!testTask.name.equals("testTask0"))
1848 testTask.mustRunAfter "testTask0"
1850 testTask.testLogging { logging ->
1851 events TestLogEvent.FAILED
1852 // TestLogEvent.SKIPPED,
1853 // TestLogEvent.STANDARD_OUT,
1854 // TestLogEvent.STANDARD_ERROR
1856 exceptionFormat TestExceptionFormat.FULL
1859 showStackTraces true
1861 showStandardStreams true
1863 info.events = [ TestLogEvent.FAILED ]
1866 if (OperatingSystem.current().isMacOsX()) {
1867 testTask.systemProperty "apple.awt.UIElement", "true"
1868 testTask.environment "JAVA_TOOL_OPTIONS", "-Dapple.awt.UIElement=true"
1872 ignoreFailures = true // Always try to run all tests for all modules
1874 afterSuite { desc, result ->
1876 return // Only summarize results for whole modules
1878 def resultsInfo = [testTask.project.name, testTask.name, result, TimeCategory.minus(new Date(result.endTime), new Date(result.startTime)), testTask.reports.html.entryPoint]
1880 rootProject.ext.testsResults.add(resultsInfo)
1883 // from original test task
1884 maxHeapSize = "1024m"
1886 workingDir = jalviewDir
1887 def testLaf = project.findProperty("test_laf")
1888 if (testLaf != null) {
1889 println("Setting Test LaF to '${testLaf}'")
1890 systemProperty "laf", testLaf
1892 def testHiDPIScale = project.findProperty("test_HiDPIScale")
1893 if (testHiDPIScale != null) {
1894 println("Setting Test HiDPI Scale to '${testHiDPIScale}'")
1895 systemProperty "sun.java2d.uiScale", testHiDPIScale
1897 sourceCompatibility = compile_source_compatibility
1898 targetCompatibility = compile_target_compatibility
1899 jvmArgs += additional_compiler_args
1902 // this is not perfect yet -- we should only add the commandLineIncludePatterns to the
1903 // testTasks that include the tests, and exclude all from the others.
1904 // get --test argument
1905 filter.commandLineIncludePatterns = test.filter.commandLineIncludePatterns
1906 // do something with testTask.getCandidateClassFiles() to see if the test should silently finish because of the
1907 // commandLineIncludePatterns not matching anything. Instead we are doing setFailOnNoMatchingTests(false) below
1911 println("Running tests " + (useClover?"WITH":"WITHOUT") + " clover")
1916 /* don't fail on no matching tests (so --tests will run across all testTasks) */
1917 testTask.filter.setFailOnNoMatchingTests(false)
1919 /* ensure the "test" task dependsOn all the testTasks */
1920 test.dependsOn testTask
1923 gradle.buildFinished {
1924 def allResults = rootProject.ext.testsResults
1926 if (!allResults.isEmpty()) {
1927 printResults allResults
1928 allResults.each {r ->
1929 if (r[2].resultType == TestResult.ResultType.FAILURE)
1930 throw new GradleException("Failed tests!")
1935 private static String colString(styler, col, colour, text) {
1936 return col?"${styler[colour](text)}":text
1939 private static String getSummaryLine(s, pn, tn, rt, rc, rs, rf, rsk, t, col) {
1940 def colour = 'black'
1948 case TestResult.ResultType.SUCCESS:
1951 case TestResult.ResultType.FAILURE:
1959 StringBuilder sb = new StringBuilder()
1963 sb.append(" results: ")
1964 sb.append(colString(s, col && !nocol, colour, text))
1966 sb.append("${rc} tests, ")
1967 sb.append(colString(s, col && rs > 0, 'green', rs))
1968 sb.append(" successes, ")
1969 sb.append(colString(s, col && rf > 0, 'red', rf))
1970 sb.append(" failures, ")
1971 sb.append("${rsk} skipped) in ${t}")
1972 return sb.toString()
1975 private static void printResults(allResults) {
1977 // styler from https://stackoverflow.com/a/56139852
1978 def styler = 'black red green yellow blue magenta cyan white'.split().toList().withIndex(30).collectEntries { key, val -> [(key) : { "\033[${val}m${it}\033[0m" }] }
1981 def failedTests = false
1982 def summaryLines = []
1984 def totalsuccess = 0
1987 def totaltime = TimeCategory.getSeconds(0)
1988 // sort on project name then task name
1989 allResults.sort {a, b -> a[0] == b[0]? a[1]<=>b[1]:a[0] <=> b[0]}.each {
1990 def projectName = it[0]
1991 def taskName = it[1]
1995 def summaryCol = getSummaryLine(styler, projectName, taskName, result.resultType, result.testCount, result.successfulTestCount, result.failedTestCount, result.skippedTestCount, time, true)
1996 def summaryPlain = getSummaryLine(styler, projectName, taskName, result.resultType, result.testCount, result.successfulTestCount, result.failedTestCount, result.skippedTestCount, time, false)
1997 def reportLine = "Report file: ${report}"
1998 def ls = summaryPlain.length()
1999 def lr = reportLine.length()
2000 def m = [ls, lr].max()
2003 def info = [ls, summaryCol, reportLine]
2004 summaryLines.add(info)
2005 failedTests |= result.resultType == TestResult.ResultType.FAILURE
2006 totalcount += result.testCount
2007 totalsuccess += result.successfulTestCount
2008 totalfail += result.failedTestCount
2009 totalskip += result.skippedTestCount
2012 def totalSummaryCol = getSummaryLine(styler, "OVERALL", "", failedTests?TestResult.ResultType.FAILURE:TestResult.ResultType.SUCCESS, totalcount, totalsuccess, totalfail, totalskip, totaltime, true)
2013 def totalSummaryPlain = getSummaryLine(styler, "OVERALL", "", failedTests?TestResult.ResultType.FAILURE:TestResult.ResultType.SUCCESS, totalcount, totalsuccess, totalfail, totalskip, totaltime, false)
2014 def tls = totalSummaryPlain.length()
2015 if (tls > maxLength)
2017 def info = [tls, totalSummaryCol, null]
2018 summaryLines.add(info)
2020 def allSummaries = []
2021 for(sInfo : summaryLines) {
2023 def summary = sInfo[1]
2024 def report = sInfo[2]
2026 StringBuilder sb = new StringBuilder()
2027 sb.append("│" + summary + " " * (maxLength - ls) + "│")
2028 if (report != null) {
2029 sb.append("\n│" + report + " " * (maxLength - report.length()) + "│")
2031 allSummaries += sb.toString()
2034 println "┌${"${"─" * maxLength}"}┐"
2035 println allSummaries.join("\n├${"${"─" * maxLength}"}┤\n")
2036 println "└${"${"─" * maxLength}"}┘"
2038 /* END of test tasks results summary */
2041 task compileLinkCheck(type: JavaCompile) {
2043 classpath = files("${jalviewDir}/${utils_dir}")
2044 destinationDir = file("${jalviewDir}/${utils_dir}")
2045 source = fileTree(dir: "${jalviewDir}/${utils_dir}", include: ["HelpLinksChecker.java", "BufferedLineReader.java"])
2047 inputs.file("${jalviewDir}/${utils_dir}/HelpLinksChecker.java")
2048 inputs.file("${jalviewDir}/${utils_dir}/HelpLinksChecker.java")
2049 outputs.file("${jalviewDir}/${utils_dir}/HelpLinksChecker.class")
2050 outputs.file("${jalviewDir}/${utils_dir}/BufferedLineReader.class")
2054 task linkCheck(type: JavaExec) {
2056 dependsOn compileLinkCheck
2058 def helpLinksCheckerOutFile = file("${jalviewDir}/${utils_dir}/HelpLinksChecker.out")
2059 classpath = files("${jalviewDir}/${utils_dir}")
2060 main = "HelpLinksChecker"
2061 workingDir = "${helpBuildDir}"
2062 args = [ "${helpBuildDir}/${help_dir}", "-nointernet" ]
2064 def outFOS = new FileOutputStream(helpLinksCheckerOutFile, false) // false == don't append
2065 standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
2068 errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
2072 inputs.dir(helpBuildDir)
2073 outputs.file(helpLinksCheckerOutFile)
2077 // import the pubhtmlhelp target
2078 ant.properties.basedir = "${jalviewDir}"
2079 ant.properties.helpBuildDir = "${helpBuildDir}/${help_dir}"
2080 ant.importBuild "${utils_dir}/publishHelp.xml"
2083 task cleanPackageDir(type: Delete) {
2085 delete fileTree(dir: "${jalviewDir}/${package_dir}", include: "*.jar")
2095 attributes "Main-Class": main_class,
2096 "Permissions": "all-permissions",
2097 "Application-Name": applicationName,
2098 "Codebase": application_codebase,
2099 "Implementation-Version": JALVIEW_VERSION
2102 def outputDir = "${jalviewDir}/${package_dir}"
2103 destinationDirectory = file(outputDir)
2104 archiveFileName = rootProject.name+".jar"
2105 duplicatesStrategy "EXCLUDE"
2112 exclude "**/*.jar.*"
2114 inputs.dir(sourceSets.main.java.outputDir)
2115 sourceSets.main.resources.srcDirs.each{ dir ->
2118 outputs.file("${outputDir}/${archiveFileName}")
2122 task copyJars(type: Copy) {
2123 from fileTree(dir: classesDir, include: "**/*.jar").files
2124 into "${jalviewDir}/${package_dir}"
2128 // doing a Sync instead of Copy as Copy doesn't deal with "outputs" very well
2129 task syncJars(type: Sync) {
2131 from fileTree(dir: "${jalviewDir}/${libDistDir}", include: "**/*.jar").files
2132 into "${jalviewDir}/${package_dir}"
2134 include jar.archiveFileName.getOrNull()
2141 description = "Put all required libraries in dist"
2142 // order of "cleanPackageDir", "copyJars", "jar" important!
2143 jar.mustRunAfter cleanPackageDir
2144 syncJars.mustRunAfter cleanPackageDir
2145 dependsOn cleanPackageDir
2148 outputs.dir("${jalviewDir}/${package_dir}")
2153 dependsOn cleanPackageDir
2159 task launcherJar(type: Jar) {
2162 "Main-Class": shadow_jar_main_class,
2163 "Implementation-Version": JALVIEW_VERSION,
2164 "Application-Name": applicationName
2170 group = "distribution"
2171 description = "Create a single jar file with all dependency libraries merged. Can be run with java -jar"
2176 def jarFiles = fileTree(dir: "${jalviewDir}/${libDistDir}", include: "*.jar", exclude: "regex.jar").getFiles()
2177 def groovyJars = jarFiles.findAll {it1 -> file(it1).getName().startsWith("groovy-swing")}
2178 def otherJars = jarFiles.findAll {it2 -> !file(it2).getName().startsWith("groovy-swing")}
2183 // shadowJar manifest must inheritFrom another Jar task. Can't set attributes here.
2184 inheritFrom(project.tasks.launcherJar.manifest)
2186 // we need to include the groovy-swing Include-Package for it to run in the shadowJar
2188 def jarFileManifests = []
2189 groovyJars.each { jarFile ->
2190 def mf = zipTree(jarFile).getFiles().find { it.getName().equals("MANIFEST.MF") }
2192 jarFileManifests += mf
2196 from (jarFileManifests) {
2197 eachEntry { details ->
2198 if (!details.key.equals("Import-Package")) {
2206 duplicatesStrategy "INCLUDE"
2208 // this mainClassName is mandatory but gets ignored due to manifest created in doFirst{}. Set the Main-Class as an attribute in launcherJar instead
2209 mainClassName = shadow_jar_main_class
2211 classifier = "all-"+JALVIEW_VERSION+"-j"+JAVA_VERSION
2215 task getdownImagesCopy() {
2216 inputs.dir getdownImagesDir
2217 outputs.dir getdownImagesBuildDir
2221 from(getdownImagesDir) {
2222 include("*getdown*.png")
2224 into getdownImagesBuildDir
2229 task getdownImagesProcess() {
2230 dependsOn getdownImagesCopy
2233 if (backgroundImageText) {
2234 if (convertBinary == null) {
2235 throw new StopExecutionException("No ImageMagick convert binary installed at '${convertBinaryExpectedLocation}'")
2237 if (!project.hasProperty("getdown_background_image_text_suffix_cmd")) {
2238 throw new StopExecutionException("No property 'getdown_background_image_text_suffix_cmd' defined. See channel_gradle.properties for channel ${CHANNEL}")
2240 fileTree(dir: getdownImagesBuildDir, include: "*background*.png").getFiles().each { file ->
2242 executable convertBinary
2245 '-font', getdown_background_image_text_font,
2246 '-fill', getdown_background_image_text_colour,
2247 '-draw', sprintf(getdown_background_image_text_suffix_cmd, channelSuffix),
2248 '-draw', sprintf(getdown_background_image_text_commit_cmd, "git-commit: ${gitHash}"),
2249 '-draw', sprintf(getdown_background_image_text_date_cmd, getDate("yyyy-MM-dd HH:mm:ss")),
2258 task getdownImages() {
2259 dependsOn getdownImagesProcess
2262 task getdownWebsiteBuild() {
2263 group = "distribution"
2264 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."
2266 dependsOn getdownImages
2271 def getdownWebsiteResourceFilenames = []
2272 def getdownResourceDir = getdownResourceDir
2273 def getdownResourceFilenames = []
2276 // clean the getdown website and files dir before creating getdown folders
2277 delete getdownAppBaseDir
2278 delete getdownFilesDir
2281 from buildProperties
2282 rename(file(buildProperties).getName(), getdown_build_properties)
2285 getdownWebsiteResourceFilenames += "${getdownAppDistDir}/${getdown_build_properties}"
2288 from channelPropsFile
2289 filter(ReplaceTokens,
2293 'SUFFIX': channelSuffix
2296 into getdownAppBaseDir
2298 getdownWebsiteResourceFilenames += file(channelPropsFile).getName()
2300 // set some getdownTxt_ properties then go through all properties looking for getdownTxt_...
2301 def props = project.properties.sort { it.key }
2302 if (getdownAltJavaMinVersion != null && getdownAltJavaMinVersion.length() > 0) {
2303 props.put("getdown_txt_java_min_version", getdownAltJavaMinVersion)
2305 if (getdownAltJavaMaxVersion != null && getdownAltJavaMaxVersion.length() > 0) {
2306 props.put("getdown_txt_java_max_version", getdownAltJavaMaxVersion)
2308 if (getdownAltMultiJavaLocation != null && getdownAltMultiJavaLocation.length() > 0) {
2309 props.put("getdown_txt_multi_java_location", getdownAltMultiJavaLocation)
2311 if (getdownImagesBuildDir != null && file(getdownImagesBuildDir).exists()) {
2312 props.put("getdown_txt_ui.background_image", "${getdownImagesBuildDir}/${getdown_background_image}")
2313 props.put("getdown_txt_ui.instant_background_image", "${getdownImagesBuildDir}/${getdown_instant_background_image}")
2314 props.put("getdown_txt_ui.error_background", "${getdownImagesBuildDir}/${getdown_error_background}")
2315 props.put("getdown_txt_ui.progress_image", "${getdownImagesBuildDir}/${getdown_progress_image}")
2316 props.put("getdown_txt_ui.icon", "${getdownImagesDir}/${getdown_icon}")
2317 props.put("getdown_txt_ui.mac_dock_icon", "${getdownImagesDir}/${getdown_mac_dock_icon}")
2320 props.put("getdown_txt_title", jalview_name)
2321 props.put("getdown_txt_ui.name", applicationName)
2323 // start with appbase
2324 getdownTextLines += "appbase = ${getdownAppBase}"
2325 props.each{ prop, val ->
2326 if (prop.startsWith("getdown_txt_") && val != null) {
2327 if (prop.startsWith("getdown_txt_multi_")) {
2328 def key = prop.substring(18)
2329 val.split(",").each{ v ->
2330 def line = "${key} = ${v}"
2331 getdownTextLines += line
2334 // file values rationalised
2335 if (val.indexOf('/') > -1 || prop.startsWith("getdown_txt_resource")) {
2337 if (val.indexOf('/') == 0) {
2340 } else if (val.indexOf('/') > 0) {
2341 // relative path (relative to jalviewDir)
2342 r = file( "${jalviewDir}/${val}" )
2345 val = "${getdown_resource_dir}/" + r.getName()
2346 getdownWebsiteResourceFilenames += val
2347 getdownResourceFilenames += r.getPath()
2350 if (! prop.startsWith("getdown_txt_resource")) {
2351 def line = prop.substring(12) + " = ${val}"
2352 getdownTextLines += line
2358 getdownWebsiteResourceFilenames.each{ filename ->
2359 getdownTextLines += "resource = ${filename}"
2361 getdownResourceFilenames.each{ filename ->
2364 into getdownResourceDir
2368 def getdownWrapperScripts = [ getdown_bash_wrapper_script, getdown_powershell_wrapper_script, getdown_batch_wrapper_script ]
2369 getdownWrapperScripts.each{ script ->
2370 def s = file( "${jalviewDir}/utils/getdown/${getdown_wrapper_script_dir}/${script}" )
2374 into "${getdownAppBaseDir}/${getdown_wrapper_script_dir}"
2376 getdownTextLines += "xresource = ${getdown_wrapper_script_dir}/${script}"
2381 fileTree(file(package_dir)).each{ f ->
2382 if (f.isDirectory()) {
2383 def files = fileTree(dir: f, include: ["*"]).getFiles()
2385 } else if (f.exists()) {
2389 def jalviewJar = jar.archiveFileName.getOrNull()
2390 // put jalview.jar first for CLASSPATH and .properties files reasons
2391 codeFiles.sort{a, b -> ( a.getName() == jalviewJar ? -1 : ( b.getName() == jalviewJar ? 1 : a <=> b ) ) }.each{f ->
2392 def name = f.getName()
2393 def line = "code = ${getdownAppDistDir}/${name}"
2394 getdownTextLines += line
2401 // NOT USING MODULES YET, EVERYTHING SHOULD BE IN dist
2403 if (JAVA_VERSION.equals("11")) {
2404 def j11libFiles = fileTree(dir: "${jalviewDir}/${j11libDir}", include: ["*.jar"]).getFiles()
2405 j11libFiles.sort().each{f ->
2406 def name = f.getName()
2407 def line = "code = ${getdown_j11lib_dir}/${name}"
2408 getdownTextLines += line
2411 into getdownJ11libDir
2417 // 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.
2418 //getdownTextLines += "class = " + file(getdownLauncher).getName()
2419 getdownTextLines += "resource = ${getdown_launcher_new}"
2420 getdownTextLines += "class = ${main_class}"
2421 // Not setting these properties in general so that getdownappbase and getdowndistdir will default to release version in jalview.bin.Cache
2422 if (getdownSetAppBaseProperty) {
2423 getdownTextLines += "jvmarg = -Dgetdowndistdir=${getdownAppDistDir}"
2424 getdownTextLines += "jvmarg = -Dgetdownappbase=${getdownAppBase}"
2427 def getdownTxt = file("${getdownAppBaseDir}/getdown.txt")
2428 getdownTxt.write(getdownTextLines.join("\n"))
2430 getdownLaunchJvl = getdown_launch_jvl_name + ( (jvlChannelName != null && jvlChannelName.length() > 0)?"-${jvlChannelName}":"" ) + ".jvl"
2431 def launchJvl = file("${getdownAppBaseDir}/${getdownLaunchJvl}")
2432 launchJvl.write("appbase=${getdownAppBase}")
2434 // files going into the getdown website dir: getdown-launcher.jar
2436 from getdownLauncher
2437 rename(file(getdownLauncher).getName(), getdown_launcher_new)
2438 into getdownAppBaseDir
2441 // files going into the getdown website dir: getdown-launcher(-local).jar
2443 from getdownLauncher
2444 if (file(getdownLauncher).getName() != getdown_launcher) {
2445 rename(file(getdownLauncher).getName(), getdown_launcher)
2447 into getdownAppBaseDir
2450 // files going into the getdown website dir: ./install dir and files
2451 if (! (CHANNEL.startsWith("ARCHIVE") || CHANNEL.startsWith("DEVELOP"))) {
2454 from getdownLauncher
2455 from "${getdownAppDir}/${getdown_build_properties}"
2456 if (file(getdownLauncher).getName() != getdown_launcher) {
2457 rename(file(getdownLauncher).getName(), getdown_launcher)
2459 into getdownInstallDir
2462 // and make a copy in the getdown files dir (these are not downloaded by getdown)
2464 from getdownInstallDir
2465 into getdownFilesInstallDir
2469 // files going into the getdown files dir: getdown.txt, getdown-launcher.jar, channel-launch.jvl, build_properties
2473 from getdownLauncher
2474 from "${getdownAppBaseDir}/${getdown_build_properties}"
2475 from "${getdownAppBaseDir}/${channel_props}"
2476 if (file(getdownLauncher).getName() != getdown_launcher) {
2477 rename(file(getdownLauncher).getName(), getdown_launcher)
2479 into getdownFilesDir
2482 // and ./resource (not all downloaded by getdown)
2484 from getdownResourceDir
2485 into "${getdownFilesDir}/${getdown_resource_dir}"
2490 inputs.dir("${jalviewDir}/${package_dir}")
2492 outputs.dir(getdownAppBaseDir)
2493 outputs.dir(getdownFilesDir)
2497 // a helper task to allow getdown digest of any dir: `gradle getdownDigestDir -PDIGESTDIR=/path/to/my/random/getdown/dir
2498 task getdownDigestDir(type: JavaExec) {
2500 description "A task to run a getdown Digest on a dir with getdown.txt. Provide a DIGESTDIR property via -PDIGESTDIR=..."
2502 def digestDirPropertyName = "DIGESTDIR"
2504 classpath = files(getdownLauncher)
2505 def digestDir = findProperty(digestDirPropertyName)
2506 if (digestDir == null) {
2507 throw new GradleException("Must provide a DIGESTDIR value to produce an alternative getdown digest")
2511 main = "com.threerings.getdown.tools.Digester"
2515 task getdownDigest(type: JavaExec) {
2516 group = "distribution"
2517 description = "Digest the getdown website folder"
2519 dependsOn getdownWebsiteBuild
2522 classpath = files(getdownLauncher)
2524 main = "com.threerings.getdown.tools.Digester"
2525 args getdownAppBaseDir
2526 inputs.dir(getdownAppBaseDir)
2527 outputs.file("${getdownAppBaseDir}/digest2.txt")
2532 group = "distribution"
2533 description = "Create the minimal and full getdown app folder for installers and website and create digest file"
2534 dependsOn getdownDigest
2536 if (reportRsyncCommand) {
2537 def fromDir = getdownAppBaseDir + (getdownAppBaseDir.endsWith('/')?'':'/')
2538 def toDir = "${getdown_rsync_dest}/${getdownDir}" + (getdownDir.endsWith('/')?'':'/')
2539 println "LIKELY RSYNC COMMAND:"
2540 println "mkdir -p '$toDir'\nrsync -avh --delete '$fromDir' '$toDir'"
2541 if (RUNRSYNC == "true") {
2543 commandLine "mkdir", "-p", toDir
2546 commandLine "rsync", "-avh", "--delete", fromDir, toDir
2553 task getdownWebsite {
2554 group = "distribution"
2555 description = "A task to create the whole getdown channel website dir including digest file"
2557 dependsOn getdownWebsiteBuild
2558 dependsOn getdownDigest
2561 task getdownArchiveBuild() {
2562 group = "distribution"
2563 description = "Put files in the archive dir to go on the website"
2565 dependsOn getdownWebsiteBuild
2567 def v = "v${JALVIEW_VERSION_UNDERSCORES}"
2568 def vDir = "${getdownArchiveDir}/${v}"
2569 getdownFullArchiveDir = "${vDir}/getdown"
2570 getdownVersionLaunchJvl = "${vDir}/jalview-${v}.jvl"
2572 def vAltDir = "alt_${v}"
2573 def archiveImagesDir = "${jalviewDir}/${channel_properties_dir}/old/images"
2576 // cleanup old "old" dir
2577 delete getdownArchiveDir
2579 def getdownArchiveTxt = file("${getdownFullArchiveDir}/getdown.txt")
2580 getdownArchiveTxt.getParentFile().mkdirs()
2581 def getdownArchiveTextLines = []
2582 def getdownFullArchiveAppBase = "${getdownArchiveAppBase}${getdownArchiveAppBase.endsWith("/")?"":"/"}${v}/getdown/"
2586 from "${getdownAppBaseDir}/${getdownAppDistDir}"
2587 into "${getdownFullArchiveDir}/${vAltDir}"
2590 getdownTextLines.each { line ->
2591 line = line.replaceAll("^(?<s>appbase\\s*=\\s*).*", '${s}'+getdownFullArchiveAppBase)
2592 line = line.replaceAll("^(?<s>(resource|code)\\s*=\\s*)${getdownAppDistDir}/", '${s}'+vAltDir+"/")
2593 line = line.replaceAll("^(?<s>ui.background_image\\s*=\\s*).*\\.png", '${s}'+"${getdown_resource_dir}/jalview_archive_getdown_background.png")
2594 line = line.replaceAll("^(?<s>ui.instant_background_image\\s*=\\s*).*\\.png", '${s}'+"${getdown_resource_dir}/jalview_archive_getdown_background_initialising.png")
2595 line = line.replaceAll("^(?<s>ui.error_background\\s*=\\s*).*\\.png", '${s}'+"${getdown_resource_dir}/jalview_archive_getdown_background_error.png")
2596 line = line.replaceAll("^(?<s>ui.progress_image\\s*=\\s*).*\\.png", '${s}'+"${getdown_resource_dir}/jalview_archive_getdown_progress_bar.png")
2597 // remove the existing resource = resource/ or bin/ lines
2598 if (! line.matches("resource\\s*=\\s*(resource|bin)/.*")) {
2599 getdownArchiveTextLines += line
2603 // the resource dir -- add these files as resource lines in getdown.txt
2605 from "${archiveImagesDir}"
2606 into "${getdownFullArchiveDir}/${getdown_resource_dir}"
2608 getdownArchiveTextLines += "resource = ${getdown_resource_dir}/${file.getName()}"
2612 // the wrapper scripts dir
2613 if ( file("${getdownAppBaseDir}/${getdown_wrapper_script_dir}").exists() ) {
2615 from "${getdownAppBaseDir}/${getdown_wrapper_script_dir}"
2616 into "${getdownFullArchiveDir}/${getdown_wrapper_script_dir}"
2620 getdownArchiveTxt.write(getdownArchiveTextLines.join("\n"))
2622 def vLaunchJvl = file(getdownVersionLaunchJvl)
2623 vLaunchJvl.getParentFile().mkdirs()
2624 vLaunchJvl.write("appbase=${getdownFullArchiveAppBase}\n")
2625 def vLaunchJvlPath = vLaunchJvl.toPath().toAbsolutePath()
2626 def jvlLinkPath = file("${vDir}/jalview.jvl").toPath().toAbsolutePath()
2627 // for some reason filepath.relativize(fileInSameDirPath) gives a path to "../" which is wrong
2628 //java.nio.file.Files.createSymbolicLink(jvlLinkPath, jvlLinkPath.relativize(vLaunchJvlPath));
2629 java.nio.file.Files.createSymbolicLink(jvlLinkPath, java.nio.file.Paths.get(".",vLaunchJvl.getName()));
2631 // files going into the getdown files dir: getdown.txt, getdown-launcher.jar, channel-launch.jvl, build_properties
2633 from getdownLauncher
2634 from "${getdownAppBaseDir}/${getdownLaunchJvl}"
2635 from "${getdownAppBaseDir}/${getdown_launcher_new}"
2636 from "${getdownAppBaseDir}/${channel_props}"
2637 if (file(getdownLauncher).getName() != getdown_launcher) {
2638 rename(file(getdownLauncher).getName(), getdown_launcher)
2640 into getdownFullArchiveDir
2646 task getdownArchiveDigest(type: JavaExec) {
2647 group = "distribution"
2648 description = "Digest the getdown archive folder"
2650 dependsOn getdownArchiveBuild
2653 classpath = files(getdownLauncher)
2654 args getdownFullArchiveDir
2656 main = "com.threerings.getdown.tools.Digester"
2657 inputs.dir(getdownFullArchiveDir)
2658 outputs.file("${getdownFullArchiveDir}/digest2.txt")
2661 task getdownArchive() {
2662 group = "distribution"
2663 description = "Build the website archive dir with getdown digest"
2665 dependsOn getdownArchiveBuild
2666 dependsOn getdownArchiveDigest
2669 tasks.withType(JavaCompile) {
2670 options.encoding = 'UTF-8'
2676 delete getdownAppBaseDir
2677 delete getdownFilesDir
2678 delete getdownArchiveDir
2684 if (file(install4jHomeDir).exists()) {
2686 } else if (file(System.getProperty("user.home")+"/buildtools/install4j").exists()) {
2687 install4jHomeDir = System.getProperty("user.home")+"/buildtools/install4j"
2688 } else if (file("/Applications/install4j.app/Contents/Resources/app").exists()) {
2689 install4jHomeDir = "/Applications/install4j.app/Contents/Resources/app"
2691 installDir(file(install4jHomeDir))
2693 mediaTypes = Arrays.asList(install4j_media_types.split(","))
2697 task copyInstall4jTemplate {
2698 def install4jTemplateFile = file("${install4jDir}/${install4j_template}")
2699 def install4jFileAssociationsFile = file("${install4jDir}/${install4j_installer_file_associations}")
2700 inputs.file(install4jTemplateFile)
2701 inputs.file(install4jFileAssociationsFile)
2702 inputs.property("CHANNEL", { CHANNEL })
2703 outputs.file(install4jConfFile)
2706 def install4jConfigXml = new XmlParser().parse(install4jTemplateFile)
2708 // turn off code signing if no OSX_KEYPASS
2709 if (OSX_KEYPASS == "") {
2710 install4jConfigXml.'**'.codeSigning.each { codeSigning ->
2711 codeSigning.'@macEnabled' = "false"
2713 install4jConfigXml.'**'.windows.each { windows ->
2714 windows.'@runPostProcessor' = "false"
2718 // disable install screen for OSX dmg (for 2.11.2.0)
2719 install4jConfigXml.'**'.macosArchive.each { macosArchive ->
2720 macosArchive.attributes().remove('executeSetupApp')
2721 macosArchive.attributes().remove('setupAppId')
2724 // turn off checksum creation for LOCAL channel
2725 def e = install4jConfigXml.application[0]
2726 e.'@createChecksums' = string(install4jCheckSums)
2728 // put file association actions where placeholder action is
2729 def install4jFileAssociationsText = install4jFileAssociationsFile.text
2730 def fileAssociationActions = new XmlParser().parseText("<actions>${install4jFileAssociationsText}</actions>")
2731 install4jConfigXml.'**'.action.any { a -> // .any{} stops after the first one that returns true
2732 if (a.'@name' == 'EXTENSIONS_REPLACED_BY_GRADLE') {
2733 def parent = a.parent()
2735 fileAssociationActions.each { faa ->
2738 // don't need to continue in .any loop once replacements have been made
2743 // use Windows Program Group with Examples folder for RELEASE, and Program Group without Examples for everything else
2744 // NB we're deleting the /other/ one!
2745 // Also remove the examples subdir from non-release versions
2746 def customizedIdToDelete = "PROGRAM_GROUP_RELEASE"
2747 // 2.11.1.0 NOT releasing with the Examples folder in the Program Group
2748 if (false && CHANNEL=="RELEASE") { // remove 'false && ' to include Examples folder in RELEASE channel
2749 customizedIdToDelete = "PROGRAM_GROUP_NON_RELEASE"
2751 // remove the examples subdir from Full File Set
2752 def files = install4jConfigXml.files[0]
2753 def fileset = files.filesets.fileset.find { fs -> fs.'@customizedId' == "FULL_FILE_SET" }
2754 def root = files.roots.root.find { r -> r.'@fileset' == fileset.'@id' }
2755 def mountPoint = files.mountPoints.mountPoint.find { mp -> mp.'@root' == root.'@id' }
2756 def dirEntry = files.entries.dirEntry.find { de -> de.'@mountPoint' == mountPoint.'@id' && de.'@subDirectory' == "examples" }
2757 dirEntry.parent().remove(dirEntry)
2759 install4jConfigXml.'**'.action.any { a ->
2760 if (a.'@customizedId' == customizedIdToDelete) {
2761 def parent = a.parent()
2767 // write install4j file
2768 install4jConfFile.text = XmlUtil.serialize(install4jConfigXml)
2775 delete install4jConfFile
2779 task cleanInstallersDataFiles {
2780 def installersOutputTxt = file("${jalviewDir}/${install4jBuildDir}/output.txt")
2781 def installersSha256 = file("${jalviewDir}/${install4jBuildDir}/sha256sums")
2782 def hugoDataJsonFile = file("${jalviewDir}/${install4jBuildDir}/installers-${JALVIEW_VERSION_UNDERSCORES}.json")
2784 delete installersOutputTxt
2785 delete installersSha256
2786 delete hugoDataJsonFile
2790 task install4jDMGBackgroundImageCopy {
2791 inputs.file "${install4jDMGBackgroundImageDir}/${install4jDMGBackgroundImageFile}"
2792 outputs.dir "${install4jDMGBackgroundImageBuildDir}"
2795 from(install4jDMGBackgroundImageDir) {
2796 include(install4jDMGBackgroundImageFile)
2798 into install4jDMGBackgroundImageBuildDir
2803 task install4jDMGBackgroundImageProcess {
2804 dependsOn install4jDMGBackgroundImageCopy
2807 if (backgroundImageText) {
2808 if (convertBinary == null) {
2809 throw new StopExecutionException("No ImageMagick convert binary installed at '${convertBinaryExpectedLocation}'")
2811 if (!project.hasProperty("install4j_background_image_text_suffix_cmd")) {
2812 throw new StopExecutionException("No property 'install4j_background_image_text_suffix_cmd' defined. See channel_gradle.properties for channel ${CHANNEL}")
2814 fileTree(dir: install4jDMGBackgroundImageBuildDir, include: "*.png").getFiles().each { file ->
2816 executable convertBinary
2819 '-font', install4j_background_image_text_font,
2820 '-fill', install4j_background_image_text_colour,
2821 '-draw', sprintf(install4j_background_image_text_suffix_cmd, channelSuffix),
2822 '-draw', sprintf(install4j_background_image_text_commit_cmd, "git-commit: ${gitHash}"),
2823 '-draw', sprintf(install4j_background_image_text_date_cmd, getDate("yyyy-MM-dd HH:mm:ss")),
2832 task install4jDMGBackgroundImage {
2833 dependsOn install4jDMGBackgroundImageProcess
2836 task installerFiles(type: com.install4j.gradle.Install4jTask) {
2837 group = "distribution"
2838 description = "Create the install4j installers"
2840 dependsOn copyInstall4jTemplate
2841 dependsOn cleanInstallersDataFiles
2842 dependsOn install4jDMGBackgroundImage
2844 projectFile = install4jConfFile
2846 // run install4j with 4g
2847 vmParameters = ["-Xmx4294967296"]
2849 // create an md5 for the input files to use as version for install4j conf file
2850 def digest = MessageDigest.getInstance("MD5")
2852 (file("${install4jDir}/${install4j_template}").text +
2853 file("${install4jDir}/${install4j_info_plist_file_associations}").text +
2854 file("${install4jDir}/${install4j_installer_file_associations}").text).bytes)
2855 def filesMd5 = new BigInteger(1, digest.digest()).toString(16)
2856 if (filesMd5.length() >= 8) {
2857 filesMd5 = filesMd5.substring(0,8)
2859 def install4jTemplateVersion = "${JALVIEW_VERSION}_F${filesMd5}_C${gitHash}"
2862 'JALVIEW_NAME': jalview_name,
2863 'JALVIEW_APPLICATION_NAME': applicationName,
2864 'JALVIEW_DIR': "../..",
2865 'OSX_KEYSTORE': OSX_KEYSTORE,
2866 'OSX_APPLEID': OSX_APPLEID,
2867 'OSX_ALTOOLPASS': OSX_ALTOOLPASS,
2868 'JSIGN_SH': JSIGN_SH,
2869 'JRE_DIR': getdown_app_dir_java,
2870 'INSTALLER_TEMPLATE_VERSION': install4jTemplateVersion,
2871 'JALVIEW_VERSION': JALVIEW_VERSION,
2872 'JAVA_MIN_VERSION': JAVA_MIN_VERSION,
2873 'JAVA_MAX_VERSION': JAVA_MAX_VERSION,
2874 'JAVA_VERSION': JAVA_VERSION,
2875 'JAVA_INTEGER_VERSION': JAVA_INTEGER_VERSION,
2876 'VERSION': JALVIEW_VERSION,
2877 'COPYRIGHT_MESSAGE': install4j_copyright_message,
2878 'BUNDLE_ID': install4jBundleId,
2879 'INTERNAL_ID': install4jInternalId,
2880 'WINDOWS_APPLICATION_ID': install4jWinApplicationId,
2881 'MACOS_DMG_DS_STORE': install4jDMGDSStore,
2882 'MACOS_DMG_BG_IMAGE': "${install4jDMGBackgroundImageBuildDir}/${install4jDMGBackgroundImageFile}",
2883 'WRAPPER_LINK': getdownWrapperLink,
2884 'BASH_WRAPPER_SCRIPT': getdown_bash_wrapper_script,
2885 'POWERSHELL_WRAPPER_SCRIPT': getdown_powershell_wrapper_script,
2886 'BATCH_WRAPPER_SCRIPT': getdown_batch_wrapper_script,
2887 'WRAPPER_SCRIPT_BIN_DIR': getdown_wrapper_script_dir,
2888 'INSTALLER_NAME': install4jInstallerName,
2889 'INSTALL4J_UTILS_DIR': install4j_utils_dir,
2890 'GETDOWN_CHANNEL_DIR': getdownChannelDir,
2891 'GETDOWN_FILES_DIR': getdown_files_dir,
2892 'GETDOWN_RESOURCE_DIR': getdown_resource_dir,
2893 'GETDOWN_DIST_DIR': getdownAppDistDir,
2894 'GETDOWN_ALT_DIR': getdown_app_dir_alt,
2895 'GETDOWN_INSTALL_DIR': getdown_install_dir,
2896 'INFO_PLIST_FILE_ASSOCIATIONS_FILE': install4j_info_plist_file_associations,
2897 'BUILD_DIR': install4jBuildDir,
2898 'APPLICATION_CATEGORIES': install4j_application_categories,
2899 'APPLICATION_FOLDER': install4jApplicationFolder,
2900 'UNIX_APPLICATION_FOLDER': install4jUnixApplicationFolder,
2901 'EXECUTABLE_NAME': install4jExecutableName,
2902 'EXTRA_SCHEME': install4jExtraScheme,
2903 'MAC_ICONS_FILE': install4jMacIconsFile,
2904 'WINDOWS_ICONS_FILE': install4jWindowsIconsFile,
2905 'PNG_ICON_FILE': install4jPngIconFile,
2906 'BACKGROUND': install4jBackground,
2911 'windows': 'WINDOWS',
2915 // these are the bundled OS/architecture VMs needed by install4j
2918 [ "mac", "aarch64" ],
2919 [ "windows", "x64" ],
2921 [ "linux", "aarch64" ]
2923 osArch.forEach { os, arch ->
2924 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)
2925 // N.B. For some reason install4j requires the below filename to have underscores and not hyphens
2926 // otherwise running `gradle installers` generates a non-useful error:
2927 // `install4j: compilation failed. Reason: java.lang.NumberFormatException: For input string: "windows"`
2928 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)
2931 //println("INSTALL4J VARIABLES:")
2932 //variables.each{k,v->println("${k}=${v}")}
2934 destination = "${jalviewDir}/${install4jBuildDir}"
2935 buildSelected = true
2937 if (install4j_faster.equals("true") || CHANNEL.startsWith("LOCAL")) {
2939 disableSigning = true
2940 disableNotarization = true
2944 macKeystorePassword = OSX_KEYPASS
2947 if (OSX_ALTOOLPASS) {
2948 appleIdPassword = OSX_ALTOOLPASS
2949 disableNotarization = false
2951 disableNotarization = true
2955 println("Using projectFile "+projectFile)
2956 if (!disableNotarization) { println("Will notarize OSX App DMG") }
2960 inputs.dir(getdownAppBaseDir)
2961 inputs.file(install4jConfFile)
2962 inputs.file("${install4jDir}/${install4j_info_plist_file_associations}")
2963 outputs.dir("${jalviewDir}/${install4j_build_dir}/${JAVA_VERSION}")
2966 def getDataHash(File myFile) {
2967 HashCode hash = Files.asByteSource(myFile).hash(Hashing.sha256())
2968 return myFile.exists()
2970 "file" : myFile.getName(),
2971 "filesize" : myFile.length(),
2972 "sha256" : hash.toString()
2977 def writeDataJsonFile(File installersOutputTxt, File installersSha256, File dataJsonFile) {
2979 "channel" : getdownChannelName,
2980 "date" : getDate("yyyy-MM-dd HH:mm:ss"),
2981 "git-commit" : "${gitHash} [${gitBranch}]",
2982 "version" : JALVIEW_VERSION
2984 // install4j installer files
2985 if (installersOutputTxt.exists()) {
2987 installersOutputTxt.readLines().each { def line ->
2988 if (line.startsWith("#")) {
2991 line.replaceAll("\n","")
2992 def vals = line.split("\t")
2993 def filename = vals[3]
2994 def filesize = file(filename).length()
2995 filename = filename.replaceAll(/^.*\//, "")
2996 hash[vals[0]] = [ "id" : vals[0], "os" : vals[1], "name" : vals[2], "file" : filename, "filesize" : filesize ]
2997 idHash."${filename}" = vals[0]
2999 if (install4jCheckSums && installersSha256.exists()) {
3000 installersSha256.readLines().each { def line ->
3001 if (line.startsWith("#")) {
3004 line.replaceAll("\n","")
3005 def vals = line.split(/\s+\*?/)
3006 def filename = vals[1]
3007 def innerHash = (hash.(idHash."${filename}"))."sha256" = vals[0]
3013 "JAR": shadowJar.archiveFile, // executable JAR
3014 "JVL": getdownVersionLaunchJvl, // version JVL
3015 "SOURCE": sourceDist.archiveFile // source TGZ
3016 ].each { key, value ->
3017 def file = file(value)
3018 if (file.exists()) {
3019 def fileHash = getDataHash(file)
3020 if (fileHash != null) {
3021 hash."${key}" = fileHash;
3025 return dataJsonFile.write(new JsonBuilder(hash).toPrettyString())
3028 task staticMakeInstallersJsonFile {
3030 def output = findProperty("i4j_output")
3031 def sha256 = findProperty("i4j_sha256")
3032 def json = findProperty("i4j_json")
3033 if (output == null || sha256 == null || json == null) {
3034 throw new GradleException("Must provide paths to all of output.txt, sha256sums, and output.json with '-Pi4j_output=... -Pi4j_sha256=... -Pi4j_json=...")
3036 writeDataJsonFile(file(output), file(sha256), file(json))
3041 dependsOn installerFiles
3047 eclipse().configFile(eclipse_codestyle_file)
3051 task createSourceReleaseProperties(type: WriteProperties) {
3052 group = "distribution"
3053 description = "Create the source RELEASE properties file"
3055 def sourceTarBuildDir = "${buildDir}/sourceTar"
3056 def sourceReleasePropertiesFile = "${sourceTarBuildDir}/RELEASE"
3057 outputFile (sourceReleasePropertiesFile)
3060 releaseProps.each{ key, val -> property key, val }
3061 property "git.branch", gitBranch
3062 property "git.hash", gitHash
3065 outputs.file(outputFile)
3068 task sourceDist(type: Tar) {
3069 group "distribution"
3070 description "Create a source .tar.gz file for distribution"
3072 dependsOn createBuildProperties
3073 dependsOn convertMdFiles
3074 dependsOn eclipseAllPreferences
3075 dependsOn createSourceReleaseProperties
3078 def outputFileName = "${project.name}_${JALVIEW_VERSION_UNDERSCORES}.tar.gz"
3079 archiveFileName = outputFileName
3081 compression Compression.GZIP
3097 "**/*.class","$j11modDir/**/*.jar","appletlib","**/*locales",
3099 "utils/InstallAnywhere",
3114 "gradle.properties",
3126 ".settings/org.eclipse.buildship.core.prefs",
3127 ".settings/org.eclipse.jdt.core.prefs"
3131 exclude (EXCLUDE_FILES)
3132 include (PROCESS_FILES)
3133 filter(ReplaceTokens,
3137 'Version-Rel': JALVIEW_VERSION,
3138 'Year-Rel': getDate("yyyy")
3143 exclude (EXCLUDE_FILES)
3144 exclude (PROCESS_FILES)
3145 exclude ("appletlib")
3146 exclude ("**/*locales")
3147 exclude ("*locales/**")
3148 exclude ("utils/InstallAnywhere")
3150 exclude (getdown_files_dir)
3151 // getdown_website_dir and getdown_archive_dir moved to build/website/docroot/getdown
3152 //exclude (getdown_website_dir)
3153 //exclude (getdown_archive_dir)
3155 // exluding these as not using jars as modules yet
3156 exclude ("${j11modDir}/**/*.jar")
3159 include(INCLUDE_FILES)
3161 // from (jalviewDir) {
3162 // // explicit includes for stuff that seemed to not get included
3163 // include(fileTree("test/**/*."))
3164 // exclude(EXCLUDE_FILES)
3165 // exclude(PROCESS_FILES)
3168 from(file(buildProperties).getParent()) {
3169 include(file(buildProperties).getName())
3170 rename(file(buildProperties).getName(), "build_properties")
3172 line.replaceAll("^INSTALLATION=.*\$","INSTALLATION=Source Release"+" git-commit\\\\:"+gitHash+" ["+gitBranch+"]")
3176 def sourceTarBuildDir = "${buildDir}/sourceTar"
3177 from(sourceTarBuildDir) {
3178 // this includes the appended RELEASE properties file
3182 task dataInstallersJson {
3184 description "Create the installers-VERSION.json data file for installer files created"
3186 mustRunAfter installers
3187 mustRunAfter shadowJar
3188 mustRunAfter sourceDist
3189 mustRunAfter getdownArchive
3191 def installersOutputTxt = file("${jalviewDir}/${install4jBuildDir}/output.txt")
3192 def installersSha256 = file("${jalviewDir}/${install4jBuildDir}/sha256sums")
3194 if (installersOutputTxt.exists()) {
3195 inputs.file(installersOutputTxt)
3197 if (install4jCheckSums && installersSha256.exists()) {
3198 inputs.file(installersSha256)
3201 shadowJar.archiveFile, // executable JAR
3202 getdownVersionLaunchJvl, // version JVL
3203 sourceDist.archiveFile // source TGZ
3204 ].each { fileName ->
3205 if (file(fileName).exists()) {
3206 inputs.file(fileName)
3210 outputs.file(hugoDataJsonFile)
3213 writeDataJsonFile(installersOutputTxt, installersSha256, hugoDataJsonFile)
3219 description "Copies all help pages to build dir. Runs ant task 'pubhtmlhelp'."
3222 dependsOn pubhtmlhelp
3224 inputs.dir("${helpBuildDir}/${help_dir}")
3225 outputs.dir("${buildDir}/distributions/${help_dir}")
3229 task j2sSetHeadlessBuild {
3236 task jalviewjsEnableAltFileProperty(type: WriteProperties) {
3238 description "Enable the alternative J2S Config file for headless build"
3240 outputFile = jalviewjsJ2sSettingsFileName
3241 def j2sPropsFile = file(jalviewjsJ2sSettingsFileName)
3242 def j2sProps = new Properties()
3243 if (j2sPropsFile.exists()) {
3245 def j2sPropsFileFIS = new FileInputStream(j2sPropsFile)
3246 j2sProps.load(j2sPropsFileFIS)
3247 j2sPropsFileFIS.close()
3249 j2sProps.each { prop, val ->
3252 } catch (Exception e) {
3253 println("Exception reading ${jalviewjsJ2sSettingsFileName}")
3257 if (! j2sProps.stringPropertyNames().contains(jalviewjs_j2s_alt_file_property_config)) {
3258 property(jalviewjs_j2s_alt_file_property_config, jalviewjs_j2s_alt_file_property)
3263 task jalviewjsSetEclipseWorkspace {
3264 def propKey = "jalviewjs_eclipse_workspace"
3266 if (project.hasProperty(propKey)) {
3267 propVal = project.getProperty(propKey)
3268 if (propVal.startsWith("~/")) {
3269 propVal = System.getProperty("user.home") + propVal.substring(1)
3272 def propsFileName = "${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_eclipse_workspace_location_file}"
3273 def propsFile = file(propsFileName)
3274 def eclipseWsDir = propVal
3275 def props = new Properties()
3277 def writeProps = true
3278 if (( eclipseWsDir == null || !file(eclipseWsDir).exists() ) && propsFile.exists()) {
3279 def ins = new FileInputStream(propsFileName)
3282 if (props.getProperty(propKey, null) != null) {
3283 eclipseWsDir = props.getProperty(propKey)
3288 if (eclipseWsDir == null || !file(eclipseWsDir).exists()) {
3289 def tempDir = File.createTempDir()
3290 eclipseWsDir = tempDir.getAbsolutePath()
3293 eclipseWorkspace = file(eclipseWsDir)
3296 // do not run a headless transpile when we claim to be in Eclipse
3298 println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3299 throw new StopExecutionException("Not running headless transpile whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
3301 println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3305 props.setProperty(propKey, eclipseWsDir)
3306 propsFile.parentFile.mkdirs()
3307 def bytes = new ByteArrayOutputStream()
3308 props.store(bytes, null)
3309 def propertiesString = bytes.toString()
3310 propsFile.text = propertiesString
3316 println("ECLIPSE WORKSPACE: "+eclipseWorkspace.getPath())
3319 //inputs.property(propKey, eclipseWsDir) // eclipseWsDir only gets set once this task runs, so will be out-of-date
3320 outputs.file(propsFileName)
3321 outputs.upToDateWhen { eclipseWorkspace.exists() && propsFile.exists() }
3325 task jalviewjsEclipsePaths {
3328 def eclipseRoot = jalviewjs_eclipse_root
3329 if (eclipseRoot.startsWith("~/")) {
3330 eclipseRoot = System.getProperty("user.home") + eclipseRoot.substring(1)
3332 if (OperatingSystem.current().isMacOsX()) {
3333 eclipseRoot += "/Eclipse.app"
3334 eclipseBinary = "${eclipseRoot}/Contents/MacOS/eclipse"
3335 eclipseProduct = "${eclipseRoot}/Contents/Eclipse/.eclipseproduct"
3336 } else if (OperatingSystem.current().isWindows()) { // check these paths!!
3337 if (file("${eclipseRoot}/eclipse").isDirectory() && file("${eclipseRoot}/eclipse/.eclipseproduct").exists()) {
3338 eclipseRoot += "/eclipse"
3340 eclipseBinary = "${eclipseRoot}/eclipse.exe"
3341 eclipseProduct = "${eclipseRoot}/.eclipseproduct"
3342 } else { // linux or unix
3343 if (file("${eclipseRoot}/eclipse").isDirectory() && file("${eclipseRoot}/eclipse/.eclipseproduct").exists()) {
3344 eclipseRoot += "/eclipse"
3345 println("eclipseDir exists")
3347 eclipseBinary = "${eclipseRoot}/eclipse"
3348 eclipseProduct = "${eclipseRoot}/.eclipseproduct"
3351 eclipseVersion = "4.13" // default
3352 def assumedVersion = true
3353 if (file(eclipseProduct).exists()) {
3354 def fis = new FileInputStream(eclipseProduct)
3355 def props = new Properties()
3357 eclipseVersion = props.getProperty("version")
3359 assumedVersion = false
3362 def propKey = "eclipse_debug"
3363 eclipseDebug = (project.hasProperty(propKey) && project.getProperty(propKey).equals("true"))
3366 // do not run a headless transpile when we claim to be in Eclipse
3368 println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3369 throw new StopExecutionException("Not running headless transpile whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
3371 println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3374 if (!assumedVersion) {
3375 println("ECLIPSE VERSION=${eclipseVersion}")
3381 task printProperties {
3383 description "Output to console all System.properties"
3385 System.properties.each { key, val -> System.out.println("Property: ${key}=${val}") }
3391 dependsOn eclipseProject
3392 dependsOn eclipseClasspath
3393 dependsOn eclipseJdt
3397 // this version (type: Copy) will delete anything in the eclipse dropins folder that isn't in fromDropinsDir
3398 task jalviewjsEclipseCopyDropins(type: Copy) {
3399 dependsOn jalviewjsEclipsePaths
3401 def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjs_eclipse_dropins_dir}", include: "*.jar")
3402 inputFiles += file("${jalviewDir}/${jalviewjsJ2sPlugin}")
3403 def outputDir = "${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_eclipse_tmp_dropins_dir}"
3410 // this eclipse -clean doesn't actually work
3411 task jalviewjsCleanEclipse(type: Exec) {
3412 dependsOn eclipseSetup
3413 dependsOn jalviewjsEclipsePaths
3414 dependsOn jalviewjsEclipseCopyDropins
3416 executable(eclipseBinary)
3417 args(["-nosplash", "--launcher.suppressErrors", "-data", eclipseWorkspace.getPath(), "-clean", "-console", "-consoleLog"])
3423 def inputString = """exit
3426 def inputByteStream = new ByteArrayInputStream(inputString.getBytes())
3427 standardInput = inputByteStream
3430 /* not really working yet
3431 jalviewjsEclipseCopyDropins.finalizedBy jalviewjsCleanEclipse
3435 task jalviewjsTransferUnzipSwingJs {
3436 def file_zip = "${jalviewDir}/${jalviewjs_swingjs_zip}"
3440 from zipTree(file_zip)
3441 into "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}"
3445 inputs.file file_zip
3446 outputs.dir "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}"
3450 task jalviewjsTransferUnzipLib {
3451 def zipFiles = fileTree(dir: "${jalviewDir}/${jalviewjs_libjs_dir}", include: "*.zip")
3454 zipFiles.each { file_zip ->
3456 from zipTree(file_zip)
3457 into "${jalviewDir}/${jalviewjsTransferSiteLibDir}"
3462 inputs.files zipFiles
3463 outputs.dir "${jalviewDir}/${jalviewjsTransferSiteLibDir}"
3467 task jalviewjsTransferUnzipAllLibs {
3468 dependsOn jalviewjsTransferUnzipSwingJs
3469 dependsOn jalviewjsTransferUnzipLib
3473 task jalviewjsCreateJ2sSettings(type: WriteProperties) {
3475 description "Create the alternative j2s file from the j2s.* properties"
3477 jalviewjsJ2sProps = project.properties.findAll { it.key.startsWith("j2s.") }.sort { it.key }
3478 def siteDirProperty = "j2s.site.directory"
3479 def setSiteDir = false
3480 jalviewjsJ2sProps.each { prop, val ->
3482 if (prop == siteDirProperty) {
3483 if (!(val.startsWith('/') || val.startsWith("file://") )) {
3484 val = "${jalviewDir}/${jalviewjsTransferSiteJsDir}/${val}"
3490 if (!setSiteDir) { // default site location, don't override specifically set property
3491 property(siteDirProperty,"${jalviewDirRelativePath}/${jalviewjsTransferSiteJsDir}")
3494 outputFile = jalviewjsJ2sAltSettingsFileName
3497 inputs.properties(jalviewjsJ2sProps)
3498 outputs.file(jalviewjsJ2sAltSettingsFileName)
3503 task jalviewjsEclipseSetup {
3504 dependsOn jalviewjsEclipseCopyDropins
3505 dependsOn jalviewjsSetEclipseWorkspace
3506 dependsOn jalviewjsCreateJ2sSettings
3510 task jalviewjsSyncAllLibs (type: Sync) {
3511 dependsOn jalviewjsTransferUnzipAllLibs
3512 def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjsTransferSiteLibDir}")
3513 inputFiles += fileTree(dir: "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}")
3514 def outputDir = "${jalviewDir}/${jalviewjsSiteDir}"
3518 def outputFiles = []
3519 rename { filename ->
3520 outputFiles += "${outputDir}/${filename}"
3527 // should this be exclude really ?
3528 duplicatesStrategy "INCLUDE"
3530 outputs.files outputFiles
3531 inputs.files inputFiles
3535 task jalviewjsSyncResources (type: Sync) {
3536 dependsOn buildResources
3538 def inputFiles = fileTree(dir: resourcesBuildDir)
3539 def outputDir = "${jalviewDir}/${jalviewjsSiteDir}/${jalviewjs_j2s_subdir}"
3543 def outputFiles = []
3544 rename { filename ->
3545 outputFiles += "${outputDir}/${filename}"
3551 outputs.files outputFiles
3552 inputs.files inputFiles
3556 task jalviewjsSyncSiteResources (type: Sync) {
3557 def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjs_site_resource_dir}")
3558 def outputDir = "${jalviewDir}/${jalviewjsSiteDir}"
3562 def outputFiles = []
3563 rename { filename ->
3564 outputFiles += "${outputDir}/${filename}"
3570 outputs.files outputFiles
3571 inputs.files inputFiles
3575 task jalviewjsSyncBuildProperties (type: Sync) {
3576 dependsOn createBuildProperties
3577 def inputFiles = [file(buildProperties)]
3578 def outputDir = "${jalviewDir}/${jalviewjsSiteDir}/${jalviewjs_j2s_subdir}"
3582 def outputFiles = []
3583 rename { filename ->
3584 outputFiles += "${outputDir}/${filename}"
3590 outputs.files outputFiles
3591 inputs.files inputFiles
3595 task jalviewjsProjectImport(type: Exec) {
3596 dependsOn eclipseSetup
3597 dependsOn jalviewjsEclipsePaths
3598 dependsOn jalviewjsEclipseSetup
3601 // do not run a headless import when we claim to be in Eclipse
3603 println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3604 throw new StopExecutionException("Not running headless import whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
3606 println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3610 //def projdir = eclipseWorkspace.getPath()+"/.metadata/.plugins/org.eclipse.core.resources/.projects/jalview/org.eclipse.jdt.core"
3611 def projdir = eclipseWorkspace.getPath()+"/.metadata/.plugins/org.eclipse.core.resources/.projects/jalview"
3612 executable(eclipseBinary)
3613 args(["-nosplash", "--launcher.suppressErrors", "-application", "com.seeq.eclipse.importprojects.headlessimport", "-data", eclipseWorkspace.getPath(), "-import", jalviewDirAbsolutePath])
3617 args += [ "--launcher.appendVmargs", "-vmargs", "-Dorg.eclipse.equinox.p2.reconciler.dropins.directory=${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_eclipse_tmp_dropins_dir}" ]
3619 args += [ "-D${j2sHeadlessBuildProperty}=true" ]
3620 args += [ "-D${jalviewjs_j2s_alt_file_property}=${jalviewjsJ2sAltSettingsFileName}" ]
3623 inputs.file("${jalviewDir}/.project")
3624 outputs.upToDateWhen {
3625 file(projdir).exists()
3630 task jalviewjsTranspile(type: Exec) {
3631 dependsOn jalviewjsEclipseSetup
3632 dependsOn jalviewjsProjectImport
3633 dependsOn jalviewjsEclipsePaths
3635 dependsOn jalviewjsEnableAltFileProperty
3639 // do not run a headless transpile when we claim to be in Eclipse
3641 println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3642 throw new StopExecutionException("Not running headless transpile whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
3644 println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3648 executable(eclipseBinary)
3649 args(["-nosplash", "--launcher.suppressErrors", "-application", "org.eclipse.jdt.apt.core.aptBuild", "-data", eclipseWorkspace, "-${jalviewjs_eclipse_build_arg}", eclipse_project_name ])
3653 args += [ "--launcher.appendVmargs", "-vmargs", "-Dorg.eclipse.equinox.p2.reconciler.dropins.directory=${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_eclipse_tmp_dropins_dir}" ]
3655 args += [ "-D${j2sHeadlessBuildProperty}=true" ]
3656 args += [ "-D${jalviewjs_j2s_alt_file_property}=${jalviewjsJ2sAltSettingsFileName}" ]
3662 stdout = new ByteArrayOutputStream()
3663 stderr = new ByteArrayOutputStream()
3665 def logOutFileName = "${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}"
3666 def logOutFile = file(logOutFileName)
3667 logOutFile.createNewFile()
3668 logOutFile.text = """ROOT: ${jalviewjs_eclipse_root}
3669 BINARY: ${eclipseBinary}
3670 VERSION: ${eclipseVersion}
3671 WORKSPACE: ${eclipseWorkspace}
3672 DEBUG: ${eclipseDebug}
3675 def logOutFOS = new FileOutputStream(logOutFile, true) // true == append
3676 // combine stdout and stderr
3677 def logErrFOS = logOutFOS
3679 if (jalviewjs_j2s_to_console.equals("true")) {
3680 standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
3681 new org.apache.tools.ant.util.TeeOutputStream(
3685 errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
3686 new org.apache.tools.ant.util.TeeOutputStream(
3691 standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
3694 errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
3701 if (stdout.toString().contains("Error processing ")) {
3702 // j2s did not complete transpile
3703 //throw new TaskExecutionException("Error during transpilation:\n${stderr}\nSee eclipse transpile log file '${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}'")
3704 if (jalviewjs_ignore_transpile_errors.equals("true")) {
3705 println("IGNORING TRANSPILE ERRORS")
3706 println("See eclipse transpile log file '${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}'")
3708 throw new GradleException("Error during transpilation:\n${stderr}\nSee eclipse transpile log file '${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}'")
3713 inputs.dir("${jalviewDir}/${sourceDir}")
3714 outputs.dir("${jalviewDir}/${jalviewjsTransferSiteJsDir}")
3715 outputs.upToDateWhen( { file("${jalviewDir}/${jalviewjsTransferSiteJsDir}${jalviewjs_server_resource}").exists() } )
3719 def jalviewjsCallCore(String name, FileCollection list, String prefixFile, String suffixFile, String jsfile, String zjsfile, File logOutFile, Boolean logOutConsole) {
3721 def stdout = new ByteArrayOutputStream()
3722 def stderr = new ByteArrayOutputStream()
3724 def coreFile = file(jsfile)
3726 msg = "Creating core for ${name}...\nGenerating ${jsfile}"
3728 logOutFile.createNewFile()
3729 logOutFile.append(msg+"\n")
3731 def coreTop = file(prefixFile)
3732 def coreBottom = file(suffixFile)
3733 coreFile.getParentFile().mkdirs()
3734 coreFile.createNewFile()
3735 coreFile.write( coreTop.getText("UTF-8") )
3739 def t = f.getText("UTF-8")
3740 t.replaceAll("Clazz\\.([^_])","Clazz_${1}")
3741 coreFile.append( t )
3743 msg = "...file '"+f.getPath()+"' does not exist, skipping"
3745 logOutFile.append(msg+"\n")
3748 coreFile.append( coreBottom.getText("UTF-8") )
3750 msg = "Generating ${zjsfile}"
3752 logOutFile.append(msg+"\n")
3753 def logOutFOS = new FileOutputStream(logOutFile, true) // true == append
3754 def logErrFOS = logOutFOS
3757 classpath = files(["${jalviewDir}/${jalviewjs_closure_compiler}"])
3758 main = "com.google.javascript.jscomp.CommandLineRunner"
3759 jvmArgs = [ "-Dfile.encoding=UTF-8" ]
3760 args = [ "--compilation_level", "SIMPLE_OPTIMIZATIONS", "--warning_level", "QUIET", "--charset", "UTF-8", "--js", jsfile, "--js_output_file", zjsfile ]
3763 msg = "\nRunning '"+commandLine.join(' ')+"'\n"
3765 logOutFile.append(msg+"\n")
3767 if (logOutConsole) {
3768 standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
3769 new org.apache.tools.ant.util.TeeOutputStream(
3773 errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
3774 new org.apache.tools.ant.util.TeeOutputStream(
3779 standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
3782 errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
3789 logOutFile.append(msg+"\n")
3793 task jalviewjsBuildAllCores {
3795 description "Build the core js lib closures listed in the classlists dir"
3796 dependsOn jalviewjsTranspile
3797 dependsOn jalviewjsTransferUnzipSwingJs
3799 def j2sDir = "${jalviewDir}/${jalviewjsTransferSiteJsDir}/${jalviewjs_j2s_subdir}"
3800 def swingJ2sDir = "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}/${jalviewjs_j2s_subdir}"
3801 def libJ2sDir = "${jalviewDir}/${jalviewjsTransferSiteLibDir}/${jalviewjs_j2s_subdir}"
3802 def jsDir = "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}/${jalviewjs_js_subdir}"
3803 def outputDir = "${jalviewDir}/${jalviewjsTransferSiteCoreDir}/${jalviewjs_j2s_subdir}/core"
3804 def prefixFile = "${jsDir}/core/coretop2.js"
3805 def suffixFile = "${jsDir}/core/corebottom2.js"
3807 inputs.file prefixFile
3808 inputs.file suffixFile
3810 def classlistFiles = []
3811 // add the classlists found int the jalviewjs_classlists_dir
3812 fileTree(dir: "${jalviewDir}/${jalviewjs_classlists_dir}", include: "*.txt").each {
3814 def name = file.getName() - ".txt"
3821 // _jmol and _jalview cores. Add any other peculiar classlist.txt files here
3822 //classlistFiles += [ 'file': file("${jalviewDir}/${jalviewjs_classlist_jmol}"), 'name': "_jvjmol" ]
3823 classlistFiles += [ 'file': file("${jalviewDir}/${jalviewjs_classlist_jalview}"), 'name': jalviewjsJalviewCoreName ]
3825 jalviewjsCoreClasslists = []
3827 classlistFiles.each {
3830 def file = hash['file']
3831 if (! file.exists()) {
3832 //println("...classlist file '"+file.getPath()+"' does not exist, skipping")
3833 return false // this is a "continue" in groovy .each closure
3835 def name = hash['name']
3837 name = file.getName() - ".txt"
3845 def list = fileTree(dir: j2sDir, includes: filelist)
3847 def jsfile = "${outputDir}/core${name}.js"
3848 def zjsfile = "${outputDir}/core${name}.z.js"
3850 jalviewjsCoreClasslists += [
3859 outputs.file(jsfile)
3860 outputs.file(zjsfile)
3863 // _stevesoft core. add any cores without a classlist here (and the inputs and outputs)
3864 def stevesoftClasslistName = "_stevesoft"
3865 def stevesoftClasslist = [
3866 'jsfile': "${outputDir}/core${stevesoftClasslistName}.js",
3867 'zjsfile': "${outputDir}/core${stevesoftClasslistName}.z.js",
3868 'list': fileTree(dir: j2sDir, include: "com/stevesoft/pat/**/*.js"),
3869 'name': stevesoftClasslistName
3871 jalviewjsCoreClasslists += stevesoftClasslist
3872 inputs.files(stevesoftClasslist['list'])
3873 outputs.file(stevesoftClasslist['jsfile'])
3874 outputs.file(stevesoftClasslist['zjsfile'])
3877 def allClasslistName = "_all"
3878 def allJsFiles = fileTree(dir: j2sDir, include: "**/*.js")
3879 allJsFiles += fileTree(
3883 // these exlusions are files that the closure-compiler produces errors for. Should fix them
3884 "**/org/jmol/jvxl/readers/IsoIntersectFileReader.js",
3885 "**/org/jmol/export/JSExporter.js"
3888 allJsFiles += fileTree(
3892 // these exlusions are files that the closure-compiler produces errors for. Should fix them
3893 "**/sun/misc/Unsafe.js",
3894 "**/swingjs/jquery/jquery-editable-select.js",
3895 "**/swingjs/jquery/j2sComboBox.js",
3896 "**/sun/misc/FloatingDecimal.js"
3899 def allClasslist = [
3900 'jsfile': "${outputDir}/core${allClasslistName}.js",
3901 'zjsfile': "${outputDir}/core${allClasslistName}.z.js",
3903 'name': allClasslistName
3905 // not including this version of "all" core at the moment
3906 //jalviewjsCoreClasslists += allClasslist
3907 inputs.files(allClasslist['list'])
3908 outputs.file(allClasslist['jsfile'])
3909 outputs.file(allClasslist['zjsfile'])
3912 def logOutFile = file("${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_j2s_closure_stdout}")
3913 logOutFile.getParentFile().mkdirs()
3914 logOutFile.createNewFile()
3915 logOutFile.write(getDate("yyyy-MM-dd HH:mm:ss")+" jalviewjsBuildAllCores\n----\n")
3917 jalviewjsCoreClasslists.each {
3918 jalviewjsCallCore(it.name, it.list, prefixFile, suffixFile, it.jsfile, it.zjsfile, logOutFile, jalviewjs_j2s_to_console.equals("true"))
3925 def jalviewjsPublishCoreTemplate(String coreName, String templateName, File inputFile, String outputFile) {
3928 into file(outputFile).getParentFile()
3929 rename { filename ->
3930 if (filename.equals(inputFile.getName())) {
3931 return file(outputFile).getName()
3935 filter(ReplaceTokens,
3939 'MAIN': '"'+main_class+'"',
3941 'NAME': jalviewjsJalviewTemplateName+" [core ${coreName}]",
3942 'COREKEY': jalviewjs_core_key,
3943 'CORENAME': coreName
3950 task jalviewjsPublishCoreTemplates {
3951 dependsOn jalviewjsBuildAllCores
3952 def inputFileName = "${jalviewDir}/${j2s_coretemplate_html}"
3953 def inputFile = file(inputFileName)
3954 def outputDir = "${jalviewDir}/${jalviewjsTransferSiteCoreDir}"
3956 def outputFiles = []
3957 jalviewjsCoreClasslists.each { cl ->
3958 def outputFile = "${outputDir}/${jalviewjsJalviewTemplateName}_${cl.name}.html"
3959 cl['outputfile'] = outputFile
3960 outputFiles += outputFile
3964 jalviewjsCoreClasslists.each { cl ->
3965 jalviewjsPublishCoreTemplate(cl.name, jalviewjsJalviewTemplateName, inputFile, cl.outputfile)
3968 inputs.file(inputFile)
3969 outputs.files(outputFiles)
3973 task jalviewjsSyncCore (type: Sync) {
3974 dependsOn jalviewjsBuildAllCores
3975 dependsOn jalviewjsPublishCoreTemplates
3976 def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjsTransferSiteCoreDir}")
3977 def outputDir = "${jalviewDir}/${jalviewjsSiteDir}"
3981 def outputFiles = []
3982 rename { filename ->
3983 outputFiles += "${outputDir}/${filename}"
3989 outputs.files outputFiles
3990 inputs.files inputFiles
3994 // this Copy version of TransferSiteJs will delete anything else in the target dir
3995 task jalviewjsCopyTransferSiteJs(type: Copy) {
3996 dependsOn jalviewjsTranspile
3997 from "${jalviewDir}/${jalviewjsTransferSiteJsDir}"
3998 into "${jalviewDir}/${jalviewjsSiteDir}"
4002 // this Sync version of TransferSite is used by buildship to keep the website automatically up to date when a file changes
4003 task jalviewjsSyncTransferSiteJs(type: Sync) {
4004 from "${jalviewDir}/${jalviewjsTransferSiteJsDir}"
4006 into "${jalviewDir}/${jalviewjsSiteDir}"
4013 jalviewjsSyncAllLibs.mustRunAfter jalviewjsCopyTransferSiteJs
4014 jalviewjsSyncResources.mustRunAfter jalviewjsCopyTransferSiteJs
4015 jalviewjsSyncSiteResources.mustRunAfter jalviewjsCopyTransferSiteJs
4016 jalviewjsSyncBuildProperties.mustRunAfter jalviewjsCopyTransferSiteJs
4018 jalviewjsSyncAllLibs.mustRunAfter jalviewjsSyncTransferSiteJs
4019 jalviewjsSyncResources.mustRunAfter jalviewjsSyncTransferSiteJs
4020 jalviewjsSyncSiteResources.mustRunAfter jalviewjsSyncTransferSiteJs
4021 jalviewjsSyncBuildProperties.mustRunAfter jalviewjsSyncTransferSiteJs
4024 task jalviewjsPrepareSite {
4026 description "Prepares the website folder including unzipping files and copying resources"
4027 dependsOn jalviewjsSyncAllLibs
4028 dependsOn jalviewjsSyncResources
4029 dependsOn jalviewjsSyncSiteResources
4030 dependsOn jalviewjsSyncBuildProperties
4031 dependsOn jalviewjsSyncCore
4035 task jalviewjsBuildSite {
4037 description "Builds the whole website including transpiled code"
4038 dependsOn jalviewjsCopyTransferSiteJs
4039 dependsOn jalviewjsPrepareSite
4043 task cleanJalviewjsTransferSite {
4045 delete "${jalviewDir}/${jalviewjsTransferSiteJsDir}"
4046 delete "${jalviewDir}/${jalviewjsTransferSiteLibDir}"
4047 delete "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}"
4048 delete "${jalviewDir}/${jalviewjsTransferSiteCoreDir}"
4053 task cleanJalviewjsSite {
4054 dependsOn cleanJalviewjsTransferSite
4056 delete "${jalviewDir}/${jalviewjsSiteDir}"
4061 task jalviewjsSiteTar(type: Tar) {
4063 description "Creates a tar.gz file for the website"
4064 dependsOn jalviewjsBuildSite
4065 def outputFilename = "jalviewjs-site-${JALVIEW_VERSION}.tar.gz"
4066 archiveFileName = outputFilename
4068 compression Compression.GZIP
4070 from "${jalviewDir}/${jalviewjsSiteDir}"
4071 into jalviewjs_site_dir // this is inside the tar file
4073 inputs.dir("${jalviewDir}/${jalviewjsSiteDir}")
4077 task jalviewjsServer {
4079 def filename = "jalviewjsTest.html"
4080 description "Starts a webserver on localhost to test the website. See ${filename} to access local site on most recently used port."
4081 def htmlFile = "${jalviewDirAbsolutePath}/${filename}"
4086 def f = Class.forName("org.gradle.plugins.javascript.envjs.http.simple.SimpleHttpFileServerFactory")
4087 factory = f.newInstance()
4088 } catch (ClassNotFoundException e) {
4089 throw new GradleException("Unable to create SimpleHttpFileServerFactory")
4091 def port = Integer.valueOf(jalviewjs_server_port)
4096 while(port < start+1000 && !running) {
4098 def doc_root = new File("${jalviewDirAbsolutePath}/${jalviewjsSiteDir}")
4099 jalviewjsServer = factory.start(doc_root, port)
4101 url = jalviewjsServer.getResourceUrl(jalviewjs_server_resource)
4102 println("SERVER STARTED with document root ${doc_root}.")
4103 println("Go to "+url+" . Run gradle --stop to stop (kills all gradle daemons).")
4104 println("For debug: "+url+"?j2sdebug")
4105 println("For verbose: "+url+"?j2sverbose")
4106 } catch (Exception e) {
4111 <p><a href="${url}">JalviewJS Test. <${url}></a></p>
4112 <p><a href="${url}?j2sdebug">JalviewJS Test with debug. <${url}?j2sdebug></a></p>
4113 <p><a href="${url}?j2sverbose">JalviewJS Test with verbose. <${url}?j2sdebug></a></p>
4115 jalviewjsCoreClasslists.each { cl ->
4116 def urlcore = jalviewjsServer.getResourceUrl(file(cl.outputfile).getName())
4118 <p><a href="${urlcore}">${jalviewjsJalviewTemplateName} [core ${cl.name}]. <${urlcore}></a></p>
4120 println("For core ${cl.name}: "+urlcore)
4123 file(htmlFile).text = htmlText
4126 outputs.file(htmlFile)
4127 outputs.upToDateWhen({false})
4131 task cleanJalviewjsAll {
4133 description "Delete all configuration and build artifacts to do with JalviewJS build"
4134 dependsOn cleanJalviewjsSite
4135 dependsOn jalviewjsEclipsePaths
4138 delete "${jalviewDir}/${jalviewjsBuildDir}"
4139 delete "${jalviewDir}/${eclipse_bin_dir}"
4140 if (eclipseWorkspace != null && file(eclipseWorkspace.getAbsolutePath()+"/.metadata").exists()) {
4141 delete file(eclipseWorkspace.getAbsolutePath()+"/.metadata")
4143 delete jalviewjsJ2sAltSettingsFileName
4146 outputs.upToDateWhen( { false } )
4150 task jalviewjsIDE_checkJ2sPlugin {
4151 group "00 JalviewJS in Eclipse"
4152 description "Compare the swingjs/net.sf.j2s.core(-j11)?.jar file with the Eclipse IDE's plugin version (found in the 'dropins' dir)"
4155 def j2sPlugin = string("${jalviewDir}/${jalviewjsJ2sPlugin}")
4156 def j2sPluginFile = file(j2sPlugin)
4157 def eclipseHome = System.properties["eclipse.home.location"]
4158 if (eclipseHome == null || ! IN_ECLIPSE) {
4159 throw new StopExecutionException("Cannot find running Eclipse home from System.properties['eclipse.home.location']. Skipping J2S Plugin Check.")
4161 def eclipseJ2sPluginDirs = [ "${eclipseHome}/dropins" ]
4162 def altPluginsDir = System.properties["org.eclipse.equinox.p2.reconciler.dropins.directory"]
4163 if (altPluginsDir != null && file(altPluginsDir).exists()) {
4164 eclipseJ2sPluginDirs += altPluginsDir
4166 def foundPlugin = false
4167 def j2sPluginFileName = j2sPluginFile.getName()
4168 def eclipseJ2sPlugin
4169 def eclipseJ2sPluginFile
4170 eclipseJ2sPluginDirs.any { dir ->
4171 eclipseJ2sPlugin = "${dir}/${j2sPluginFileName}"
4172 eclipseJ2sPluginFile = file(eclipseJ2sPlugin)
4173 if (eclipseJ2sPluginFile.exists()) {
4179 def msg = "Eclipse J2S Plugin is not installed (could not find '${j2sPluginFileName}' in\n"+eclipseJ2sPluginDirs.join("\n")+"\n)\nTry running task jalviewjsIDE_copyJ2sPlugin"
4180 System.err.println(msg)
4181 throw new StopExecutionException(msg)
4184 def digest = MessageDigest.getInstance("MD5")
4186 digest.update(j2sPluginFile.text.bytes)
4187 def j2sPluginMd5 = new BigInteger(1, digest.digest()).toString(16).padLeft(32, '0')
4189 digest.update(eclipseJ2sPluginFile.text.bytes)
4190 def eclipseJ2sPluginMd5 = new BigInteger(1, digest.digest()).toString(16).padLeft(32, '0')
4192 if (j2sPluginMd5 != eclipseJ2sPluginMd5) {
4193 def msg = "WARNING! Eclipse J2S Plugin '${eclipseJ2sPlugin}' is different to this commit's version '${j2sPlugin}'"
4194 System.err.println(msg)
4195 throw new StopExecutionException(msg)
4197 def msg = "Eclipse J2S Plugin '${eclipseJ2sPlugin}' is the same as '${j2sPlugin}' (this is good)"
4203 task jalviewjsIDE_copyJ2sPlugin {
4204 group "00 JalviewJS in Eclipse"
4205 description "Copy the swingjs/net.sf.j2s.core(-j11)?.jar file into the Eclipse IDE's 'dropins' dir"
4208 def j2sPlugin = string("${jalviewDir}/${jalviewjsJ2sPlugin}")
4209 def j2sPluginFile = file(j2sPlugin)
4210 def eclipseHome = System.properties["eclipse.home.location"]
4211 if (eclipseHome == null || ! IN_ECLIPSE) {
4212 throw new StopExecutionException("Cannot find running Eclipse home from System.properties['eclipse.home.location']. NOT copying J2S Plugin.")
4214 def eclipseJ2sPlugin = "${eclipseHome}/dropins/${j2sPluginFile.getName()}"
4215 def eclipseJ2sPluginFile = file(eclipseJ2sPlugin)
4216 def msg = "WARNING! Copying this commit's j2s plugin '${j2sPlugin}' to Eclipse J2S Plugin '${eclipseJ2sPlugin}'\n* May require an Eclipse restart"
4217 System.err.println(msg)
4220 eclipseJ2sPluginFile.getParentFile().mkdirs()
4221 into eclipseJ2sPluginFile.getParent()
4227 task jalviewjsIDE_j2sFile {
4228 group "00 JalviewJS in Eclipse"
4229 description "Creates the .j2s file"
4230 dependsOn jalviewjsCreateJ2sSettings
4234 task jalviewjsIDE_SyncCore {
4235 group "00 JalviewJS in Eclipse"
4236 description "Build the core js lib closures listed in the classlists dir and publish core html from template"
4237 dependsOn jalviewjsSyncCore
4241 task jalviewjsIDE_SyncSiteAll {
4242 dependsOn jalviewjsSyncAllLibs
4243 dependsOn jalviewjsSyncResources
4244 dependsOn jalviewjsSyncSiteResources
4245 dependsOn jalviewjsSyncBuildProperties
4249 cleanJalviewjsTransferSite.mustRunAfter jalviewjsIDE_SyncSiteAll
4252 task jalviewjsIDE_PrepareSite {
4253 group "00 JalviewJS in Eclipse"
4254 description "Sync libs and resources to site dir, but not closure cores"
4256 dependsOn jalviewjsIDE_SyncSiteAll
4257 //dependsOn cleanJalviewjsTransferSite // not sure why this clean is here -- will slow down a re-run of this task
4261 task jalviewjsIDE_AssembleSite {
4262 group "00 JalviewJS in Eclipse"
4263 description "Assembles unzipped supporting zipfiles, resources, site resources and closure cores into the Eclipse transpiled site"
4264 dependsOn jalviewjsPrepareSite
4268 task jalviewjsIDE_SiteClean {
4269 group "00 JalviewJS in Eclipse"
4270 description "Deletes the Eclipse transpiled site"
4271 dependsOn cleanJalviewjsSite
4275 task jalviewjsIDE_Server {
4276 group "00 JalviewJS in Eclipse"
4277 description "Starts a webserver on localhost to test the website"
4278 dependsOn jalviewjsServer
4282 // buildship runs this at import or gradle refresh
4283 task eclipseSynchronizationTask {
4284 //dependsOn eclipseSetup
4285 dependsOn createBuildProperties
4287 dependsOn jalviewjsIDE_j2sFile
4288 dependsOn jalviewjsIDE_checkJ2sPlugin
4289 dependsOn jalviewjsIDE_PrepareSite
4294 // buildship runs this at build time or project refresh
4295 task eclipseAutoBuildTask {
4296 //dependsOn jalviewjsIDE_checkJ2sPlugin
4297 //dependsOn jalviewjsIDE_PrepareSite
4301 task jalviewjsCopyStderrLaunchFile(type: Copy) {
4302 from file(jalviewjs_stderr_launch)
4303 into jalviewjsSiteDir
4305 inputs.file jalviewjs_stderr_launch
4306 outputs.file jalviewjsStderrLaunchFilename
4309 task cleanJalviewjsChromiumUserDir {
4311 delete jalviewjsChromiumUserDir
4313 outputs.dir jalviewjsChromiumUserDir
4314 // always run when depended on
4315 outputs.upToDateWhen { !file(jalviewjsChromiumUserDir).exists() }
4318 task jalviewjsChromiumProfile {
4319 dependsOn cleanJalviewjsChromiumUserDir
4320 mustRunAfter cleanJalviewjsChromiumUserDir
4322 def firstRun = file("${jalviewjsChromiumUserDir}/First Run")
4325 mkdir jalviewjsChromiumProfileDir
4328 outputs.file firstRun
4331 task jalviewjsLaunchTest {
4333 description "Check JalviewJS opens in a browser"
4334 dependsOn jalviewjsBuildSite
4335 dependsOn jalviewjsCopyStderrLaunchFile
4336 dependsOn jalviewjsChromiumProfile
4338 def macOS = OperatingSystem.current().isMacOsX()
4339 def chromiumBinary = macOS ? jalviewjs_macos_chromium_binary : jalviewjs_chromium_binary
4340 if (chromiumBinary.startsWith("~/")) {
4341 chromiumBinary = System.getProperty("user.home") + chromiumBinary.substring(1)
4347 def timeoutms = Integer.valueOf(jalviewjs_chromium_overall_timeout) * 1000
4349 def binary = file(chromiumBinary)
4350 if (!binary.exists()) {
4351 throw new StopExecutionException("Could not find chromium binary '${chromiumBinary}'. Cannot run task ${name}.")
4353 stdout = new ByteArrayOutputStream()
4354 stderr = new ByteArrayOutputStream()
4357 if (jalviewjs_j2s_to_console.equals("true")) {
4358 execStdout = new org.apache.tools.ant.util.TeeOutputStream(
4361 execStderr = new org.apache.tools.ant.util.TeeOutputStream(
4369 "--no-sandbox", // --no-sandbox IS USED BY THE THORIUM APPIMAGE ON THE BUILDSERVER
4372 "--timeout=${timeoutms}",
4373 "--virtual-time-budget=${timeoutms}",
4374 "--user-data-dir=${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_chromium_user_dir}",
4375 "--profile-directory=${jalviewjs_chromium_profile_name}",
4376 "--allow-file-access-from-files",
4377 "--enable-logging=stderr",
4378 "file://${jalviewDirAbsolutePath}/${jalviewjsStderrLaunchFilename}"
4381 if (true || macOS) {
4382 ScheduledExecutorService executor = Executors.newScheduledThreadPool(3);
4383 Future f1 = executor.submit(
4386 standardOutput = execStdout
4387 errorOutput = execStderr
4388 executable(chromiumBinary)
4390 println "COMMAND: '"+commandLine.join(" ")+"'"
4392 executor.shutdownNow()
4396 def noChangeBytes = 0
4397 def noChangeIterations = 0
4398 executor.scheduleAtFixedRate(
4400 String stderrString = stderr.toString()
4401 // shutdown the task if we have a success string
4402 if (stderrString.contains(jalviewjs_desktop_init_string)) {
4405 executor.shutdownNow()
4407 // if no change in stderr for 10s then also end
4408 if (noChangeIterations >= jalviewjs_chromium_idle_timeout) {
4409 executor.shutdownNow()
4411 if (stderrString.length() == noChangeBytes) {
4412 noChangeIterations++
4414 noChangeBytes = stderrString.length()
4415 noChangeIterations = 0
4418 1, 1, TimeUnit.SECONDS)
4420 executor.schedule(new Runnable(){
4423 executor.shutdownNow()
4425 }, timeoutms, TimeUnit.MILLISECONDS)
4427 executor.awaitTermination(timeoutms+10000, TimeUnit.MILLISECONDS)
4428 executor.shutdownNow()
4435 stderr.toString().eachLine { line ->
4436 if (line.contains(jalviewjs_desktop_init_string)) {
4437 println("Found line '"+line+"'")
4443 throw new GradleException("Could not find evidence of Desktop launch in JalviewJS.")
4451 description "Build the JalviewJS site and run the launch test"
4452 dependsOn jalviewjsBuildSite
4453 dependsOn jalviewjsLaunchTest