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.spotless" version "6.18.0"
55 id 'com.github.johnrengelman.shadow' version '8.1.1'
56 id 'com.install4j.gradle' version '10.0.3'
57 id 'com.dorongold.task-tree' version '2.1.1' // only needed to display task dependency tree with gradle task1 [task2 ...] taskTree
58 id 'com.palantir.git-version' version '0.13.0' apply false
69 // in ext the values are cast to Object. Ensure string values are cast as String (and not GStringImpl) for later use
70 def string(Object o) {
71 return o == null ? "" : o.toString()
74 def overrideProperties(String propsFileName, boolean output = false) {
75 if (propsFileName == null) {
78 def propsFile = file(propsFileName)
79 if (propsFile != null && propsFile.exists()) {
80 println("Using properties from file '${propsFileName}'")
82 def p = new Properties()
83 def localPropsFIS = new FileInputStream(propsFile)
89 if (project.hasProperty(key)) {
90 oldval = project.findProperty(key)
91 project.setProperty(key, val)
93 println("Overriding property '${key}' ('${oldval}') with ${file(propsFile).getName()} value '${val}'")
96 ext.setProperty(key, val)
98 println("Setting ext property '${key}' with ${file(propsFile).getName()}s value '${val}'")
102 } catch (Exception e) {
103 println("Exception reading local.properties")
110 jalviewDirAbsolutePath = file(jalviewDir).getAbsolutePath()
111 jalviewDirRelativePath = jalviewDir
114 getdownChannelName = CHANNEL.toLowerCase()
115 // default to "default". Currently only has different cosmetics for "develop", "release", "default"
116 propertiesChannelName = ["develop", "release", "test-release", "jalviewjs", "jalviewjs-release" ].contains(getdownChannelName) ? getdownChannelName : "default"
117 channelDirName = propertiesChannelName
118 // Import channel_properties
119 if (getdownChannelName.startsWith("develop-")) {
120 channelDirName = "develop-SUFFIX"
122 channelDir = string("${jalviewDir}/${channel_properties_dir}/${channelDirName}")
123 channelGradleProperties = string("${channelDir}/channel_gradle.properties")
124 channelPropsFile = string("${channelDir}/${resource_dir}/${channel_props}")
125 overrideProperties(channelGradleProperties, false)
126 // local build environment properties
127 // can be "projectDir/local.properties"
128 overrideProperties("${projectDir}/local.properties", true)
129 // or "../projectDir_local.properties"
130 overrideProperties(projectDir.getParent() + "/" + projectDir.getName() + "_local.properties", true)
133 // Import releaseProps from the RELEASE file
134 // or a file specified via JALVIEW_RELEASE_FILE if defined
135 // Expect jalview.version and target release branch in jalview.release
136 releaseProps = new Properties();
137 def releasePropFile = findProperty("JALVIEW_RELEASE_FILE");
138 def defaultReleasePropFile = "${jalviewDirAbsolutePath}/RELEASE";
140 (new File(releasePropFile!=null ? releasePropFile : defaultReleasePropFile)).withInputStream {
141 releaseProps.load(it)
143 } catch (Exception fileLoadError) {
144 throw new Error("Couldn't load release properties file "+(releasePropFile==null ? defaultReleasePropFile : "from custom location: releasePropFile"),fileLoadError);
147 // Set JALVIEW_VERSION if it is not already set
148 if (findProperty("JALVIEW_VERSION")==null || "".equals(JALVIEW_VERSION)) {
149 JALVIEW_VERSION = releaseProps.get("jalview.version")
151 println("JALVIEW_VERSION is set to '${JALVIEW_VERSION}'")
153 // this property set when running Eclipse headlessly
154 j2sHeadlessBuildProperty = string("net.sf.j2s.core.headlessbuild")
155 // this property set by Eclipse
156 eclipseApplicationProperty = string("eclipse.application")
157 // CHECK IF RUNNING FROM WITHIN ECLIPSE
158 def eclipseApplicationPropertyVal = System.properties[eclipseApplicationProperty]
159 IN_ECLIPSE = eclipseApplicationPropertyVal != null && eclipseApplicationPropertyVal.startsWith("org.eclipse.ui.")
160 // BUT WITHOUT THE HEADLESS BUILD PROPERTY SET
161 if (System.properties[j2sHeadlessBuildProperty].equals("true")) {
162 println("Setting IN_ECLIPSE to ${IN_ECLIPSE} as System.properties['${j2sHeadlessBuildProperty}'] == '${System.properties[j2sHeadlessBuildProperty]}'")
166 println("WITHIN ECLIPSE IDE")
168 println("HEADLESS BUILD")
171 J2S_ENABLED = (project.hasProperty('j2s.compiler.status') && project['j2s.compiler.status'] != null && project['j2s.compiler.status'] == "enable")
173 println("J2S ENABLED")
176 System.properties.sort { it.key }.each {
177 key, val -> println("SYSTEM PROPERTY ${key}='${val}'")
180 if (false && IN_ECLIPSE) {
181 jalviewDir = jalviewDirAbsolutePath
186 buildDate = new Date().format("yyyyMMdd")
189 bareSourceDir = string(source_dir)
190 sourceDir = string("${jalviewDir}/${bareSourceDir}")
191 resourceDir = string("${jalviewDir}/${resource_dir}")
192 bareTestSourceDir = string(test_source_dir)
193 testDir = string("${jalviewDir}/${bareTestSourceDir}")
195 classesDir = string("${jalviewDir}/${classes_dir}")
196 destinationDirectory = file(classesDir)
199 useClover = clover.equals("true")
200 cloverBuildDir = "${buildDir}/clover"
201 cloverInstrDir = file("${cloverBuildDir}/clover-instr")
202 cloverClassesDir = file("${cloverBuildDir}/clover-classes")
203 cloverReportDir = file("${buildDir}/reports/clover")
204 cloverTestInstrDir = file("${cloverBuildDir}/clover-test-instr")
205 cloverTestClassesDir = file("${cloverBuildDir}/clover-test-classes")
206 //cloverTestClassesDir = cloverClassesDir
207 cloverDb = string("${cloverBuildDir}/clover.db")
209 testSourceDir = useClover ? cloverTestInstrDir : testDir
210 testClassesDir = useClover ? cloverTestClassesDir : "${jalviewDir}/${test_output_dir}"
213 backgroundImageText = BACKGROUNDIMAGETEXT
214 getdownChannelDir = string("${getdown_website_dir}/${propertiesChannelName}")
215 getdownAppBaseDir = string("${jalviewDir}/${getdownChannelDir}/${JAVA_VERSION}")
216 getdownArchiveDir = string("${jalviewDir}/${getdown_archive_dir}")
217 getdownFullArchiveDir = null
218 getdownTextLines = []
219 getdownLaunchJvl = null
220 getdownVersionLaunchJvl = null
222 buildProperties = null
224 // the following values might be overridden by the CHANNEL switch
225 getdownDir = string("${getdownChannelName}/${JAVA_VERSION}")
226 getdownAppBase = string("${getdown_channel_base}/${getdownDir}")
227 getdownArchiveAppBase = getdown_archive_base
228 getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher}")
229 getdownAppDistDir = getdown_app_dir_alt
230 getdownImagesDir = string("${jalviewDir}/${getdown_images_dir}")
231 getdownImagesBuildDir = string("${buildDir}/imagemagick/getdown")
232 getdownSetAppBaseProperty = false // whether to pass the appbase and appdistdir to the application
233 reportRsyncCommand = false
234 jvlChannelName = CHANNEL.toLowerCase()
235 install4jSuffix = CHANNEL.substring(0, 1).toUpperCase() + CHANNEL.substring(1).toLowerCase(); // BUILD -> Build
236 install4jDMGDSStore = "${install4j_images_dir}/${install4j_dmg_ds_store}"
237 install4jDMGBackgroundImageDir = "${install4j_images_dir}"
238 install4jDMGBackgroundImageBuildDir = "build/imagemagick/install4j"
239 install4jDMGBackgroundImageFile = "${install4j_dmg_background}"
240 install4jInstallerName = "${jalview_name} Non-Release Installer"
241 install4jExecutableName = install4j_executable_name
242 install4jExtraScheme = "jalviewx"
243 install4jMacIconsFile = string("${install4j_images_dir}/${install4j_mac_icons_file}")
244 install4jWindowsIconsFile = string("${install4j_images_dir}/${install4j_windows_icons_file}")
245 install4jPngIconFile = string("${install4j_images_dir}/${install4j_png_icon_file}")
246 install4jBackground = string("${install4j_images_dir}/${install4j_background}")
247 install4jBuildDir = "${install4j_build_dir}/${JAVA_VERSION}"
248 install4jCheckSums = true
250 applicationName = "${jalview_name}"
254 // TODO: get bamboo build artifact URL for getdown artifacts
255 getdown_channel_base = bamboo_channelbase
256 getdownChannelName = string("${bamboo_planKey}/${JAVA_VERSION}")
257 getdownAppBase = string("${bamboo_channelbase}/${bamboo_planKey}${bamboo_getdown_channel_suffix}/${JAVA_VERSION}")
258 jvlChannelName += "_${getdownChannelName}"
259 // automatically add the test group Not-bamboo for exclusion
260 if ("".equals(testng_excluded_groups)) {
261 testng_excluded_groups = "Not-bamboo"
263 install4jExtraScheme = "jalviewb"
264 backgroundImageText = true
267 case [ "RELEASE", "JALVIEWJS-RELEASE" ]:
268 getdownAppDistDir = getdown_app_dir_release
269 getdownSetAppBaseProperty = true
270 reportRsyncCommand = true
272 install4jInstallerName = "${jalview_name} Installer"
276 getdownChannelName = CHANNEL.toLowerCase()+"/${JALVIEW_VERSION}"
277 getdownDir = string("${getdownChannelName}/${JAVA_VERSION}")
278 getdownAppBase = string("${getdown_channel_base}/${getdownDir}")
279 if (!file("${ARCHIVEDIR}/${package_dir}").exists()) {
280 throw new GradleException("Must provide an ARCHIVEDIR value to produce an archive distribution")
282 package_dir = string("${ARCHIVEDIR}/${package_dir}")
283 buildProperties = string("${ARCHIVEDIR}/${classes_dir}/${build_properties_file}")
286 reportRsyncCommand = true
287 install4jExtraScheme = "jalviewa"
291 getdownChannelName = string("archive/${JALVIEW_VERSION}")
292 getdownDir = string("${getdownChannelName}/${JAVA_VERSION}")
293 getdownAppBase = file(getdownAppBaseDir).toURI().toString()
294 if (!file("${ARCHIVEDIR}/${package_dir}").exists()) {
295 throw new GradleException("Must provide an ARCHIVEDIR value to produce an archive distribution [did not find '${ARCHIVEDIR}/${package_dir}']")
297 package_dir = string("${ARCHIVEDIR}/${package_dir}")
298 buildProperties = string("${ARCHIVEDIR}/${classes_dir}/${build_properties_file}")
301 reportRsyncCommand = true
302 getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher_local}")
303 install4jSuffix = "Archive"
304 install4jExtraScheme = "jalviewa"
307 case ~/^DEVELOP-([\.\-\w]*)$/:
308 def suffix = Matcher.lastMatcher[0][1]
309 reportRsyncCommand = true
310 getdownSetAppBaseProperty = true
311 JALVIEW_VERSION=JALVIEW_VERSION+"-d${suffix}-${buildDate}"
312 install4jSuffix = "Develop ${suffix}"
313 install4jExtraScheme = "jalviewd"
314 install4jInstallerName = "${jalview_name} Develop ${suffix} Installer"
315 getdownChannelName = string("develop-${suffix}")
316 getdownChannelDir = string("${getdown_website_dir}/${getdownChannelName}")
317 getdownAppBaseDir = string("${jalviewDir}/${getdownChannelDir}/${JAVA_VERSION}")
318 getdownDir = string("${getdownChannelName}/${JAVA_VERSION}")
319 getdownAppBase = string("${getdown_channel_base}/${getdownDir}")
320 channelSuffix = string(suffix)
321 backgroundImageText = true
325 reportRsyncCommand = true
326 getdownSetAppBaseProperty = true
327 // DEVELOP-RELEASE is usually associated with a Jalview release series so set the version
328 JALVIEW_VERSION=JALVIEW_VERSION+"-d${buildDate}"
330 install4jSuffix = "Develop"
331 install4jExtraScheme = "jalviewd"
332 install4jInstallerName = "${jalview_name} Develop Installer"
333 backgroundImageText = true
337 reportRsyncCommand = true
338 getdownSetAppBaseProperty = true
339 // Don't ignore transpile errors for release build
340 if (jalviewjs_ignore_transpile_errors.equals("true")) {
341 jalviewjs_ignore_transpile_errors = "false"
342 println("Setting jalviewjs_ignore_transpile_errors to 'false'")
344 JALVIEW_VERSION = JALVIEW_VERSION+"-test"
345 install4jSuffix = "Test"
346 install4jExtraScheme = "jalviewt"
347 install4jInstallerName = "${jalview_name} Test Installer"
348 backgroundImageText = true
351 case ~/^SCRATCH(|-[-\w]*)$/:
352 getdownChannelName = CHANNEL
353 JALVIEW_VERSION = JALVIEW_VERSION+"-"+CHANNEL
355 getdownDir = string("${getdownChannelName}/${JAVA_VERSION}")
356 getdownAppBase = string("${getdown_channel_base}/${getdownDir}")
357 reportRsyncCommand = true
358 install4jSuffix = "Scratch"
362 if (!file("${LOCALDIR}").exists()) {
363 throw new GradleException("Must provide a LOCALDIR value to produce a local distribution")
365 getdownAppBase = file(file("${LOCALDIR}").getAbsolutePath()).toURI().toString()
366 getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher_local}")
368 JALVIEW_VERSION = "TEST"
369 install4jSuffix = "Test-Local"
370 install4jExtraScheme = "jalviewt"
371 install4jInstallerName = "${jalview_name} Test Installer"
372 backgroundImageText = true
375 case [ "LOCAL", "JALVIEWJS" ]:
376 JALVIEW_VERSION = "TEST"
377 getdownAppBase = file(getdownAppBaseDir).toURI().toString()
378 getdownArchiveAppBase = file("${jalviewDir}/${getdown_archive_dir}").toURI().toString()
379 getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher_local}")
380 install4jExtraScheme = "jalviewl"
381 install4jCheckSums = false
384 default: // something wrong specified
385 throw new GradleException("CHANNEL must be one of BUILD, RELEASE, ARCHIVE, DEVELOP, TEST-RELEASE, SCRATCH-..., LOCAL [default]")
389 JALVIEW_VERSION_UNDERSCORES = JALVIEW_VERSION.replaceAll("\\.", "_")
390 hugoDataJsonFile = file("${jalviewDir}/${hugo_build_dir}/${hugo_data_installers_dir}/installers-${JALVIEW_VERSION_UNDERSCORES}.json")
391 hugoArchiveMdFile = file("${jalviewDir}/${hugo_build_dir}/${hugo_version_archive_dir}/Version-${JALVIEW_VERSION_UNDERSCORES}/_index.md")
392 // override getdownAppBase if requested
393 if (findProperty("getdown_appbase_override") != null) {
394 // revert to LOCAL if empty string
395 if (string(getdown_appbase_override) == "") {
396 getdownAppBase = file(getdownAppBaseDir).toURI().toString()
397 getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher_local}")
398 } else if (string(getdown_appbase_override).startsWith("file://")) {
399 getdownAppBase = string(getdown_appbase_override)
400 getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher_local}")
402 getdownAppBase = string(getdown_appbase_override)
404 println("Overriding getdown appbase with '${getdownAppBase}'")
406 // sanitise file name for jalview launcher file for this channel
407 jvlChannelName = jvlChannelName.replaceAll("[^\\w\\-]+", "_")
408 // install4j application and folder names
409 if (install4jSuffix == "") {
410 install4jBundleId = "${install4j_bundle_id}"
411 install4jWinApplicationId = install4j_release_win_application_id
413 applicationName = "${jalview_name} ${install4jSuffix}"
414 install4jBundleId = "${install4j_bundle_id}-" + install4jSuffix.toLowerCase()
415 // add int hash of install4jSuffix to the last part of the application_id
416 def id = install4j_release_win_application_id
417 def idsplitreverse = id.split("-").reverse()
418 idsplitreverse[0] = idsplitreverse[0].toInteger() + install4jSuffix.hashCode()
419 install4jWinApplicationId = idsplitreverse.reverse().join("-")
421 // sanitise folder and id names
422 // install4jApplicationFolder = e.g. "Jalview Build"
423 install4jApplicationFolder = applicationName
424 .replaceAll("[\"'~:/\\\\\\s]", "_") // replace all awkward filename chars " ' ~ : / \
425 .replaceAll("_+", "_") // collapse __
426 install4jInternalId = applicationName
428 .replaceAll("[^\\w\\-\\.]", "_") // replace other non [alphanumeric,_,-,.]
429 .replaceAll("_+", "") // collapse __
430 //.replaceAll("_*-_*", "-") // collapse _-_
431 install4jUnixApplicationFolder = applicationName
433 .replaceAll("[^\\w\\-\\.]", "_") // replace other non [alphanumeric,_,-,.]
434 .replaceAll("_+", "_") // collapse __
435 .replaceAll("_*-_*", "-") // collapse _-_
438 getdownWrapperLink = install4jUnixApplicationFolder // e.g. "jalview_local"
439 getdownAppDir = string("${getdownAppBaseDir}/${getdownAppDistDir}")
440 //getdownJ11libDir = "${getdownAppBaseDir}/${getdown_j11lib_dir}"
441 getdownResourceDir = string("${getdownAppBaseDir}/${getdown_resource_dir}")
442 getdownInstallDir = string("${getdownAppBaseDir}/${getdown_install_dir}")
443 getdownFilesDir = string("${jalviewDir}/${getdown_files_dir}/${JAVA_VERSION}/")
444 getdownFilesInstallDir = string("${getdownFilesDir}/${getdown_install_dir}")
445 /* compile without modules -- using classpath libraries
446 modules_compileClasspath = fileTree(dir: "${jalviewDir}/${j11modDir}", include: ["*.jar"])
447 modules_runtimeClasspath = modules_compileClasspath
453 apply plugin: "com.palantir.git-version"
454 def details = versionDetails()
455 gitHash = details.gitHash
456 gitBranch = details.branchName
457 } catch(org.gradle.api.internal.plugins.PluginApplicationException e) {
458 println("Not in a git repository. Using git values from RELEASE properties file.")
459 gitHash = releaseProps.getProperty("git.hash")
460 gitBranch = releaseProps.getProperty("git.branch")
461 } catch(java.lang.RuntimeException e1) {
462 throw new GradleException("Error with git-version plugin. Directory '.git' exists but versionDetails() cannot be found.")
465 println("Using a ${CHANNEL} profile.")
467 additional_compiler_args = []
468 // configure classpath/args for j8/j11 compilation
469 if (JAVA_VERSION.equals("1.8")) {
470 JAVA_INTEGER_VERSION = string("8")
473 libDistDir = j8libDir
474 compile_source_compatibility = 1.8
475 compile_target_compatibility = 1.8
476 // these are getdown.txt properties defined dependent on the JAVA_VERSION
477 getdownAltJavaMinVersion = string(findProperty("getdown_alt_java8_min_version"))
478 getdownAltJavaMaxVersion = string(findProperty("getdown_alt_java8_max_version"))
479 // this property is assigned below and expanded to multiple lines in the getdown task
480 getdownAltMultiJavaLocation = string(findProperty("getdown_alt_java8_txt_multi_java_location"))
481 // this property is for the Java library used in eclipse
482 eclipseJavaRuntimeName = string("JavaSE-1.8")
483 } else if (JAVA_VERSION.equals("11")) {
484 JAVA_INTEGER_VERSION = string("11")
486 libDistDir = j11libDir
487 compile_source_compatibility = 11
488 compile_target_compatibility = 11
489 getdownAltJavaMinVersion = string(findProperty("getdown_alt_java11_min_version"))
490 getdownAltJavaMaxVersion = string(findProperty("getdown_alt_java11_max_version"))
491 getdownAltMultiJavaLocation = string(findProperty("getdown_alt_java11_txt_multi_java_location"))
492 eclipseJavaRuntimeName = string("JavaSE-11")
493 /* compile without modules -- using classpath libraries
494 additional_compiler_args += [
495 '--module-path', modules_compileClasspath.asPath,
496 '--add-modules', j11modules
499 } else if (JAVA_VERSION.equals("17")) {
500 JAVA_INTEGER_VERSION = string("17")
502 libDistDir = j17libDir
503 compile_source_compatibility = 17
504 compile_target_compatibility = 17
505 getdownAltJavaMinVersion = string(findProperty("getdown_alt_java11_min_version"))
506 getdownAltJavaMaxVersion = string(findProperty("getdown_alt_java11_max_version"))
507 getdownAltMultiJavaLocation = string(findProperty("getdown_alt_java11_txt_multi_java_location"))
508 eclipseJavaRuntimeName = string("JavaSE-17")
509 /* compile without modules -- using classpath libraries
510 additional_compiler_args += [
511 '--module-path', modules_compileClasspath.asPath,
512 '--add-modules', j11modules
516 throw new GradleException("JAVA_VERSION=${JAVA_VERSION} not currently supported by Jalview")
521 JAVA_MIN_VERSION = JAVA_VERSION
522 JAVA_MAX_VERSION = JAVA_VERSION
523 jreInstallsDir = string(jre_installs_dir)
524 if (jreInstallsDir.startsWith("~/")) {
525 jreInstallsDir = System.getProperty("user.home") + jreInstallsDir.substring(1)
527 install4jDir = string("${jalviewDir}/${install4j_utils_dir}")
528 install4jConfFileName = string("jalview-install4j-conf.install4j")
529 install4jConfFile = file("${install4jDir}/${install4jConfFileName}")
530 install4jHomeDir = install4j_home_dir
531 if (install4jHomeDir.startsWith("~/")) {
532 install4jHomeDir = System.getProperty("user.home") + install4jHomeDir.substring(1)
535 resourceBuildDir = string("${buildDir}/resources")
536 resourcesBuildDir = string("${resourceBuildDir}/resources_build")
537 helpBuildDir = string("${resourceBuildDir}/help_build")
538 docBuildDir = string("${resourceBuildDir}/doc_build")
540 if (buildProperties == null) {
541 buildProperties = string("${resourcesBuildDir}/${build_properties_file}")
543 buildingHTML = string("${jalviewDir}/${doc_dir}/building.html")
544 helpParentDir = string("${jalviewDir}/${help_parent_dir}")
545 helpSourceDir = string("${helpParentDir}/${help_dir}")
546 helpFile = string("${helpBuildDir}/${help_dir}/help.jhm")
549 convertBinaryExpectedLocation = imagemagick_convert
550 if (convertBinaryExpectedLocation.startsWith("~/")) {
551 convertBinaryExpectedLocation = System.getProperty("user.home") + convertBinaryExpectedLocation.substring(1)
553 if (file(convertBinaryExpectedLocation).exists()) {
554 convertBinary = convertBinaryExpectedLocation
557 relativeBuildDir = file(jalviewDirAbsolutePath).toPath().relativize(buildDir.toPath())
558 jalviewjsBuildDir = string("${relativeBuildDir}/jalviewjs")
559 jalviewjsSiteDir = string("${jalviewjsBuildDir}/${jalviewjs_site_dir}")
561 jalviewjsTransferSiteJsDir = string(jalviewjsSiteDir)
563 jalviewjsTransferSiteJsDir = string("${jalviewjsBuildDir}/tmp/${jalviewjs_site_dir}_js")
565 jalviewjsTransferSiteLibDir = string("${jalviewjsBuildDir}/tmp/${jalviewjs_site_dir}_lib")
566 jalviewjsTransferSiteSwingJsDir = string("${jalviewjsBuildDir}/tmp/${jalviewjs_site_dir}_swingjs")
567 jalviewjsTransferSiteCoreDir = string("${jalviewjsBuildDir}/tmp/${jalviewjs_site_dir}_core")
568 jalviewjsJalviewCoreHtmlFile = string("")
569 jalviewjsJalviewCoreName = string(jalviewjs_core_name)
570 jalviewjsCoreClasslists = []
571 jalviewjsJalviewTemplateName = string(jalviewjs_name)
572 jalviewjsJ2sSettingsFileName = string("${jalviewDir}/${jalviewjs_j2s_settings}")
573 jalviewjsJ2sAltSettingsFileName = string("${jalviewDir}/${jalviewjs_j2s_alt_settings}")
574 jalviewjsJ2sProps = null
575 jalviewjsJ2sPlugin = jalviewjs_j2s_plugin
576 jalviewjsStderrLaunchFilename = "${jalviewjsSiteDir}/"+(file(jalviewjs_stderr_launch).getName())
578 eclipseWorkspace = null
579 eclipseBinary = string("")
580 eclipseVersion = string("")
583 jalviewjsChromiumUserDir = "${jalviewjsBuildDir}/${jalviewjs_chromium_user_dir}"
584 jalviewjsChromiumProfileDir = "${ext.jalviewjsChromiumUserDir}/${jalviewjs_chromium_profile_name}"
594 destinationDirectory = file(classesDir)
598 srcDirs = [ resourcesBuildDir, docBuildDir, helpBuildDir ]
601 compileClasspath = files(sourceSets.main.java.destinationDirectory)
602 compileClasspath += fileTree(dir: "${jalviewDir}/${libDir}", include: ["*.jar"])
604 runtimeClasspath = compileClasspath
605 runtimeClasspath += files(sourceSets.main.resources.srcDirs)
610 srcDirs cloverInstrDir
611 destinationDirectory = cloverClassesDir
615 srcDirs = sourceSets.main.resources.srcDirs
618 compileClasspath = files( sourceSets.clover.java.destinationDirectory )
619 //compileClasspath += files( testClassesDir )
620 compileClasspath += fileTree(dir: "${jalviewDir}/${libDir}", include: ["*.jar"])
621 compileClasspath += fileTree(dir: "${jalviewDir}/${clover_lib_dir}", include: ["*.jar"])
622 compileClasspath += fileTree(dir: "${jalviewDir}/${utils_dir}/testnglibs", include: ["**/*.jar"])
624 runtimeClasspath = compileClasspath
629 srcDirs testSourceDir
630 destinationDirectory = file(testClassesDir)
634 srcDirs = useClover ? sourceSets.clover.resources.srcDirs : sourceSets.main.resources.srcDirs
637 compileClasspath = files( sourceSets.test.java.destinationDirectory )
638 compileClasspath += useClover ? sourceSets.clover.compileClasspath : sourceSets.main.compileClasspath
639 compileClasspath += fileTree(dir: "${jalviewDir}/${utils_dir}/testnglibs", include: ["**/*.jar"])
641 runtimeClasspath = compileClasspath
642 runtimeClasspath += files(sourceSets.test.resources.srcDirs)
648 // eclipse project and settings files creation, also used by buildship
651 name = eclipse_project_name
653 natures 'org.eclipse.jdt.core.javanature',
654 'org.eclipse.jdt.groovy.core.groovyNature',
655 'org.eclipse.buildship.core.gradleprojectnature'
657 buildCommand 'org.eclipse.jdt.core.javabuilder'
658 buildCommand 'org.eclipse.buildship.core.gradleprojectbuilder'
662 //defaultOutputDir = sourceSets.main.java.destinationDirectory
663 configurations.each{ c->
664 if (c.isCanBeResolved()) {
665 minusConfigurations += [c]
669 plusConfigurations = [ ]
673 def removeTheseToo = []
674 HashMap<String, Boolean> alreadyAddedSrcPath = new HashMap<>();
675 cp.entries.each { entry ->
676 // This conditional removes all src classpathentries that a) have already been added or b) aren't "src" or "test".
677 // e.g. this removes the resources dir being copied into bin/main, bin/test AND bin/clover
678 // we add the resources and help/help dirs in as libs afterwards (see below)
679 if (entry.kind == 'src') {
680 if (alreadyAddedSrcPath.getAt(entry.path) || !(entry.path == bareSourceDir || entry.path == bareTestSourceDir)) {
681 removeTheseToo += entry
683 alreadyAddedSrcPath.putAt(entry.path, true)
688 cp.entries.removeAll(removeTheseToo)
690 //cp.entries += new Output("${eclipse_bin_dir}/main")
691 if (file(helpParentDir).isDirectory()) {
692 cp.entries += new Library(fileReference(helpParentDir))
694 if (file(resourceDir).isDirectory()) {
695 cp.entries += new Library(fileReference(resourceDir))
698 HashMap<String, Boolean> alreadyAddedLibPath = new HashMap<>();
700 sourceSets.main.compileClasspath.findAll { it.name.endsWith(".jar") }.any {
701 //don't want to add destinationDirectory as eclipse is using its own output dir in bin/main
702 if (it.isDirectory() || ! it.exists()) {
703 // don't add dirs to classpath, especially if they don't exist
704 return false // groovy "continue" in .any closure
706 def itPath = it.toString()
707 if (itPath.startsWith("${jalviewDirAbsolutePath}/")) {
708 // make relative path
709 itPath = itPath.substring(jalviewDirAbsolutePath.length()+1)
711 if (alreadyAddedLibPath.get(itPath)) {
712 //println("Not adding duplicate entry "+itPath)
714 //println("Adding entry "+itPath)
715 cp.entries += new Library(fileReference(itPath))
716 alreadyAddedLibPath.put(itPath, true)
720 sourceSets.test.compileClasspath.findAll { it.name.endsWith(".jar") }.any {
721 //no longer want to add destinationDirectory as eclipse is using its own output dir in bin/main
722 if (it.isDirectory() || ! it.exists()) {
723 // don't add dirs to classpath
724 return false // groovy "continue" in .any closure
727 def itPath = it.toString()
728 if (itPath.startsWith("${jalviewDirAbsolutePath}/")) {
729 itPath = itPath.substring(jalviewDirAbsolutePath.length()+1)
731 if (alreadyAddedLibPath.get(itPath)) {
734 def lib = new Library(fileReference(itPath))
735 lib.entryAttributes["test"] = "true"
737 alreadyAddedLibPath.put(itPath, true)
745 containers 'org.eclipse.buildship.core.gradleclasspathcontainer'
750 // for the IDE, use java 11 compatibility
751 sourceCompatibility = compile_source_compatibility
752 targetCompatibility = compile_target_compatibility
753 javaRuntimeName = eclipseJavaRuntimeName
755 // add in jalview project specific properties/preferences into eclipse core preferences
757 withProperties { props ->
758 def jalview_prefs = new Properties()
759 def ins = new FileInputStream("${jalviewDirAbsolutePath}/${eclipse_extra_jdt_prefs_file}")
760 jalview_prefs.load(ins)
762 jalview_prefs.forEach { t, v ->
763 if (props.getAt(t) == null) {
767 // codestyle file -- overrides previous formatter prefs
768 def csFile = file("${jalviewDirAbsolutePath}/${eclipse_codestyle_file}")
769 if (csFile.exists()) {
770 XmlParser parser = new XmlParser()
771 def profiles = parser.parse(csFile)
772 def profile = profiles.'profile'.find { p -> (p.'@kind' == "CodeFormatterProfile" && p.'@name' == "Jalview") }
773 if (profile != null) {
774 profile.'setting'.each { s ->
776 def value = s.'@value'
777 if (id != null && value != null) {
778 props.putAt(id, value)
789 // Don't want these to be activated if in headless build
790 synchronizationTasks "eclipseSynchronizationTask"
791 //autoBuildTasks "eclipseAutoBuildTask"
797 /* hack to change eclipse prefs in .settings files other than org.eclipse.jdt.core.prefs */
798 // Class to allow updating arbitrary properties files
799 class PropertiesFile extends PropertiesPersistableConfigurationObject {
800 public PropertiesFile(PropertiesTransformer t) { super(t); }
801 @Override protected void load(Properties properties) { }
802 @Override protected void store(Properties properties) { }
803 @Override protected String getDefaultResourceName() { return ""; }
804 // This is necessary, because PropertiesPersistableConfigurationObject fails
805 // if no default properties file exists.
806 @Override public void loadDefaults() { load(new StringBufferInputStream("")); }
809 // Task to update arbitrary properties files (set outputFile)
810 class PropertiesFileTask extends PropertiesGeneratorTask<PropertiesFile> {
811 private final PropertiesFileContentMerger file;
812 public PropertiesFileTask() { file = new PropertiesFileContentMerger(getTransformer()); }
813 protected PropertiesFile create() { return new PropertiesFile(getTransformer()); }
814 protected void configure(PropertiesFile props) {
815 file.getBeforeMerged().execute(props); file.getWhenMerged().execute(props);
817 public void file(Closure closure) { ConfigureUtil.configure(closure, file); }
820 task eclipseUIPreferences(type: PropertiesFileTask) {
821 description = "Generate Eclipse additional settings"
822 def filename = "org.eclipse.jdt.ui.prefs"
823 outputFile = "$projectDir/.settings/${filename}" as File
826 it.load new FileInputStream("$projectDir/utils/eclipse/${filename}" as String)
831 task eclipseGroovyCorePreferences(type: PropertiesFileTask) {
832 description = "Generate Eclipse additional settings"
833 def filename = "org.eclipse.jdt.groovy.core.prefs"
834 outputFile = "$projectDir/.settings/${filename}" as File
837 it.load new FileInputStream("$projectDir/utils/eclipse/${filename}" as String)
842 task eclipseAllPreferences {
844 dependsOn eclipseUIPreferences
845 dependsOn eclipseGroovyCorePreferences
848 eclipseUIPreferences.mustRunAfter eclipseJdt
849 eclipseGroovyCorePreferences.mustRunAfter eclipseJdt
851 /* end of eclipse preferences hack */
859 delete cloverBuildDir
860 delete cloverReportDir
865 task cloverInstrJava(type: JavaExec) {
866 group = "Verification"
867 description = "Create clover instrumented source java files"
869 dependsOn cleanClover
871 inputs.files(sourceSets.main.allJava)
872 outputs.dir(cloverInstrDir)
874 //classpath = fileTree(dir: "${jalviewDir}/${clover_lib_dir}", include: ["*.jar"])
875 classpath = sourceSets.clover.compileClasspath
876 main = "com.atlassian.clover.CloverInstr"
884 cloverInstrDir.getPath(),
886 def srcFiles = sourceSets.main.allJava.files
889 { file -> file.absolutePath }
892 args argsList.toArray()
895 delete cloverInstrDir
896 println("Clover: About to instrument "+srcFiles.size() +" files")
901 task cloverInstrTests(type: JavaExec) {
902 group = "Verification"
903 description = "Create clover instrumented source test files"
905 dependsOn cleanClover
907 inputs.files(testDir)
908 outputs.dir(cloverTestInstrDir)
910 classpath = sourceSets.clover.compileClasspath
911 main = "com.atlassian.clover.CloverInstr"
921 cloverTestInstrDir.getPath(),
923 args argsList.toArray()
926 delete cloverTestInstrDir
927 println("Clover: About to instrument test files")
933 group = "Verification"
934 description = "Create clover instrumented all source files"
936 dependsOn cloverInstrJava
937 dependsOn cloverInstrTests
941 cloverClasses.dependsOn cloverInstr
944 task cloverConsoleReport(type: JavaExec) {
945 group = "Verification"
946 description = "Creates clover console report"
949 file(cloverDb).exists()
952 inputs.dir cloverClassesDir
954 classpath = sourceSets.clover.runtimeClasspath
955 main = "com.atlassian.clover.reporters.console.ConsoleReporter"
957 if (cloverreport_mem.length() > 0) {
958 maxHeapSize = cloverreport_mem
960 if (cloverreport_jvmargs.length() > 0) {
961 jvmArgs Arrays.asList(cloverreport_jvmargs.split(" "))
971 args argsList.toArray()
975 task cloverHtmlReport(type: JavaExec) {
976 group = "Verification"
977 description = "Creates clover HTML report"
980 file(cloverDb).exists()
983 def cloverHtmlDir = cloverReportDir
984 inputs.dir cloverClassesDir
985 outputs.dir cloverHtmlDir
987 classpath = sourceSets.clover.runtimeClasspath
988 main = "com.atlassian.clover.reporters.html.HtmlReporter"
990 if (cloverreport_mem.length() > 0) {
991 maxHeapSize = cloverreport_mem
993 if (cloverreport_jvmargs.length() > 0) {
994 jvmArgs Arrays.asList(cloverreport_jvmargs.split(" "))
1005 if (cloverreport_html_options.length() > 0) {
1006 argsList += cloverreport_html_options.split(" ")
1009 args argsList.toArray()
1013 task cloverXmlReport(type: JavaExec) {
1014 group = "Verification"
1015 description = "Creates clover XML report"
1018 file(cloverDb).exists()
1021 def cloverXmlFile = "${cloverReportDir}/clover.xml"
1022 inputs.dir cloverClassesDir
1023 outputs.file cloverXmlFile
1025 classpath = sourceSets.clover.runtimeClasspath
1026 main = "com.atlassian.clover.reporters.xml.XMLReporter"
1028 if (cloverreport_mem.length() > 0) {
1029 maxHeapSize = cloverreport_mem
1031 if (cloverreport_jvmargs.length() > 0) {
1032 jvmArgs Arrays.asList(cloverreport_jvmargs.split(" "))
1043 if (cloverreport_xml_options.length() > 0) {
1044 argsList += cloverreport_xml_options.split(" ")
1047 args argsList.toArray()
1052 group = "Verification"
1053 description = "Creates clover reports"
1055 dependsOn cloverXmlReport
1056 dependsOn cloverHtmlReport
1063 sourceCompatibility = compile_source_compatibility
1064 targetCompatibility = compile_target_compatibility
1065 options.compilerArgs += additional_compiler_args
1066 print ("Setting target compatibility to "+targetCompatibility+"\n")
1068 //classpath += configurations.cloverRuntime
1074 // JBP->BS should the print statement in doFirst refer to compile_target_compatibility ?
1075 sourceCompatibility = compile_source_compatibility
1076 targetCompatibility = compile_target_compatibility
1077 options.compilerArgs += additional_compiler_args
1078 options.encoding = "UTF-8"
1080 print ("Setting target compatibility to "+compile_target_compatibility+"\n")
1087 sourceCompatibility = compile_source_compatibility
1088 targetCompatibility = compile_target_compatibility
1089 options.compilerArgs += additional_compiler_args
1091 print ("Setting target compatibility to "+targetCompatibility+"\n")
1098 delete sourceSets.main.java.destinationDirectory
1104 dependsOn cleanClover
1106 delete sourceSets.test.java.destinationDirectory
1111 // format is a string like date.format("dd MMMM yyyy")
1112 def getDate(format) {
1113 return date.format(format)
1117 def convertMdToHtml (FileTree mdFiles, File cssFile) {
1118 MutableDataSet options = new MutableDataSet()
1120 def extensions = new ArrayList<>()
1121 extensions.add(AnchorLinkExtension.create())
1122 extensions.add(AutolinkExtension.create())
1123 extensions.add(StrikethroughExtension.create())
1124 extensions.add(TaskListExtension.create())
1125 extensions.add(TablesExtension.create())
1126 extensions.add(TocExtension.create())
1128 options.set(Parser.EXTENSIONS, extensions)
1130 // set GFM table parsing options
1131 options.set(TablesExtension.WITH_CAPTION, false)
1132 options.set(TablesExtension.COLUMN_SPANS, false)
1133 options.set(TablesExtension.MIN_HEADER_ROWS, 1)
1134 options.set(TablesExtension.MAX_HEADER_ROWS, 1)
1135 options.set(TablesExtension.APPEND_MISSING_COLUMNS, true)
1136 options.set(TablesExtension.DISCARD_EXTRA_COLUMNS, true)
1137 options.set(TablesExtension.HEADER_SEPARATOR_COLUMN_MATCH, true)
1139 options.set(AnchorLinkExtension.ANCHORLINKS_SET_ID, false)
1140 options.set(AnchorLinkExtension.ANCHORLINKS_ANCHOR_CLASS, "anchor")
1141 options.set(AnchorLinkExtension.ANCHORLINKS_SET_NAME, true)
1142 options.set(AnchorLinkExtension.ANCHORLINKS_TEXT_PREFIX, "<span class=\"octicon octicon-link\"></span>")
1144 Parser parser = Parser.builder(options).build()
1145 HtmlRenderer renderer = HtmlRenderer.builder(options).build()
1147 mdFiles.each { mdFile ->
1148 // add table of contents
1149 def mdText = "[TOC]\n"+mdFile.text
1151 // grab the first top-level title
1153 def titleRegex = /(?m)^#(\s+|([^#]))(.*)/
1154 def matcher = mdText =~ titleRegex
1155 if (matcher.size() > 0) {
1156 // matcher[0][2] is the first character of the title if there wasn't any whitespace after the #
1157 title = (matcher[0][2] != null ? matcher[0][2] : "")+matcher[0][3]
1159 // or use the filename if none found
1160 if (title == null) {
1161 title = mdFile.getName()
1164 Node document = parser.parse(mdText)
1165 String htmlBody = renderer.render(document)
1166 def htmlText = '''<html>
1167 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
1168 <html xmlns="http://www.w3.org/1999/xhtml">
1170 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
1171 <meta http-equiv="Content-Style-Type" content="text/css" />
1172 <meta name="generator" content="flexmark" />
1174 htmlText += ((title != null) ? " <title>${title}</title>" : '' )
1176 <style type="text/css">code{white-space: pre;}</style>
1178 htmlText += ((cssFile != null) ? cssFile.text : '')
1179 htmlText += '''</head>
1182 htmlText += htmlBody
1188 def htmlFilePath = mdFile.getPath().replaceAll(/\..*?$/, ".html")
1189 def htmlFile = file(htmlFilePath)
1190 println("Creating ${htmlFilePath}")
1191 htmlFile.text = htmlText
1196 task copyDocs(type: Copy) {
1197 def inputDir = "${jalviewDir}/${doc_dir}"
1198 def destinationDirectory = "${docBuildDir}/${doc_dir}"
1202 include('**/*.html')
1204 filter(ReplaceTokens,
1208 'Version-Rel': JALVIEW_VERSION,
1209 'Year-Rel': getDate("yyyy")
1216 exclude('**/*.html')
1219 into destinationDirectory
1221 inputs.dir(inputDir)
1222 outputs.dir(destinationDirectory)
1226 task convertMdFiles {
1228 def mdFiles = fileTree(dir: docBuildDir, include: "**/*.md")
1229 def cssFile = file("${jalviewDir}/${flexmark_css}")
1232 convertMdToHtml(mdFiles, cssFile)
1235 inputs.files(mdFiles)
1236 inputs.file(cssFile)
1239 mdFiles.each { mdFile ->
1240 def htmlFilePath = mdFile.getPath().replaceAll(/\..*?$/, ".html")
1241 htmlFiles.add(file(htmlFilePath))
1243 outputs.files(htmlFiles)
1247 def hugoTemplateSubstitutions(String input, Map extras=null) {
1248 def replacements = [
1249 DATE: getDate("yyyy-MM-dd"),
1250 CHANNEL: propertiesChannelName,
1251 APPLICATION_NAME: applicationName,
1253 GIT_BRANCH: gitBranch,
1254 VERSION: JALVIEW_VERSION,
1255 JAVA_VERSION: JAVA_VERSION,
1256 VERSION_UNDERSCORES: JALVIEW_VERSION_UNDERSCORES,
1261 if (extras != null) {
1262 extras.each{ k, v ->
1263 output = output.replaceAll("__${k}__", ((v == null)?"":v))
1266 replacements.each{ k, v ->
1267 output = output.replaceAll("__${k}__", ((v == null)?"":v))
1272 def mdFileComponents(File mdFile, def dateOnly=false) {
1275 if (mdFile.exists()) {
1276 def inFrontMatter = false
1277 def firstLine = true
1278 mdFile.eachLine { line ->
1279 if (line.matches("---")) {
1280 def prev = inFrontMatter
1281 inFrontMatter = firstLine
1282 if (inFrontMatter != prev)
1285 if (inFrontMatter) {
1287 if (m == line =~ /^date:\s*(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})/) {
1288 map["date"] = new Date().parse("yyyy-MM-dd HH:mm:ss", m[0][1])
1289 } else if (m == line =~ /^date:\s*(\d{4}-\d{2}-\d{2})/) {
1290 map["date"] = new Date().parse("yyyy-MM-dd", m[0][1])
1291 } else if (m == line =~ /^channel:\s*(\S+)/) {
1292 map["channel"] = m[0][1]
1293 } else if (m == line =~ /^version:\s*(\S+)/) {
1294 map["version"] = m[0][1]
1295 } else if (m == line =~ /^\s*([^:]+)\s*:\s*(\S.*)/) {
1296 map[ m[0][1] ] = m[0][2]
1298 if (dateOnly && map["date"] != null) {
1304 content += line+"\n"
1309 return dateOnly ? map["date"] : [map, content]
1312 task hugoTemplates {
1314 description "Create partially populated md pages for hugo website build"
1316 def hugoTemplatesDir = file("${jalviewDir}/${hugo_templates_dir}")
1317 def hugoBuildDir = "${jalviewDir}/${hugo_build_dir}"
1318 def templateFiles = fileTree(dir: hugoTemplatesDir)
1319 def releaseMdFile = file("${jalviewDir}/${releases_dir}/release-${JALVIEW_VERSION_UNDERSCORES}.md")
1320 def whatsnewMdFile = file("${jalviewDir}/${whatsnew_dir}/whatsnew-${JALVIEW_VERSION_UNDERSCORES}.md")
1321 def oldJvlFile = file("${jalviewDir}/${hugo_old_jvl}")
1322 def jalviewjsFile = file("${jalviewDir}/${hugo_jalviewjs}")
1325 // specific release template for version archive
1328 def givenDate = null
1329 def givenChannel = null
1330 def givenVersion = null
1331 if (CHANNEL == "RELEASE") {
1332 def (map, content) = mdFileComponents(releaseMdFile)
1333 givenDate = map.date
1334 givenChannel = map.channel
1335 givenVersion = map.version
1337 if (givenVersion != null && givenVersion != JALVIEW_VERSION) {
1338 throw new GradleException("'version' header (${givenVersion}) found in ${releaseMdFile} does not match JALVIEW_VERSION (${JALVIEW_VERSION})")
1341 if (whatsnewMdFile.exists())
1342 whatsnew = whatsnewMdFile.text
1345 def oldJvl = oldJvlFile.exists() ? oldJvlFile.collect{it} : []
1346 def jalviewjsLink = jalviewjsFile.exists() ? jalviewjsFile.collect{it} : []
1348 def changesHugo = null
1349 if (changes != null) {
1350 changesHugo = '<div class="release_notes">\n\n'
1351 def inSection = false
1352 changes.eachLine { line ->
1354 if (m == line =~ /^##([^#].*)$/) {
1356 changesHugo += "</div>\n\n"
1358 def section = m[0][1].trim()
1359 section = section.toLowerCase()
1360 section = section.replaceAll(/ +/, "_")
1361 section = section.replaceAll(/[^a-z0-9_\-]/, "")
1362 changesHugo += "<div class=\"${section}\">\n\n"
1364 } else if (m == line =~ /^(\s*-\s*)<!--([^>]+)-->(.*?)(<br\/?>)?\s*$/) {
1365 def comment = m[0][2].trim()
1366 if (comment != "") {
1367 comment = comment.replaceAll('"', """)
1369 comment.eachMatch(/JAL-\d+/) { jal -> issuekeys += jal }
1370 def newline = m[0][1]
1371 if (comment.trim() != "")
1372 newline += "{{<comment>}}${comment}{{</comment>}} "
1373 newline += m[0][3].trim()
1374 if (issuekeys.size() > 0)
1375 newline += " {{< jal issue=\"${issuekeys.join(",")}\" alt=\"${comment}\" >}}"
1376 if (m[0][4] != null)
1381 changesHugo += line+"\n"
1384 changesHugo += "\n</div>\n\n"
1386 changesHugo += '</div>'
1389 templateFiles.each{ templateFile ->
1390 def newFileName = string(hugoTemplateSubstitutions(templateFile.getName()))
1391 def relPath = hugoTemplatesDir.toPath().relativize(templateFile.toPath()).getParent()
1392 def newRelPathName = hugoTemplateSubstitutions( relPath.toString() )
1394 def outPathName = string("${hugoBuildDir}/$newRelPathName")
1398 rename(templateFile.getName(), newFileName)
1402 def newFile = file("${outPathName}/${newFileName}".toString())
1403 def content = newFile.text
1404 newFile.text = hugoTemplateSubstitutions(content,
1407 CHANGES: changesHugo,
1408 DATE: givenDate == null ? "" : givenDate.format("yyyy-MM-dd"),
1409 DRAFT: givenDate == null ? "true" : "false",
1410 JALVIEWJSLINK: jalviewjsLink.contains(JALVIEW_VERSION) ? "true" : "false",
1411 JVL_HEADER: oldJvl.contains(JALVIEW_VERSION) ? "jvl: true" : ""
1418 inputs.file(oldJvlFile)
1419 inputs.dir(hugoTemplatesDir)
1420 inputs.property("JALVIEW_VERSION", { JALVIEW_VERSION })
1421 inputs.property("CHANNEL", { CHANNEL })
1424 def getMdDate(File mdFile) {
1425 return mdFileComponents(mdFile, true)
1428 def getMdSections(String content) {
1430 def sectionContent = ""
1431 def sectionName = null
1432 content.eachLine { line ->
1434 if (m == line =~ /^##([^#].*)$/) {
1435 if (sectionName != null) {
1436 sections[sectionName] = sectionContent
1440 sectionName = m[0][1].trim()
1441 sectionName = sectionName.toLowerCase()
1442 sectionName = sectionName.replaceAll(/ +/, "_")
1443 sectionName = sectionName.replaceAll(/[^a-z0-9_\-]/, "")
1444 } else if (sectionName != null) {
1445 sectionContent += line+"\n"
1448 if (sectionContent != null) {
1449 sections[sectionName] = sectionContent
1455 task copyHelp(type: Copy) {
1456 def inputDir = helpSourceDir
1457 def destinationDirectory = "${helpBuildDir}/${help_dir}"
1461 include('**/*.html')
1465 filter(ReplaceTokens,
1469 'Version-Rel': JALVIEW_VERSION,
1470 'Year-Rel': getDate("yyyy")
1477 exclude('**/*.html')
1482 into destinationDirectory
1484 inputs.dir(inputDir)
1485 outputs.files(helpFile)
1486 outputs.dir(destinationDirectory)
1491 task releasesTemplates {
1493 description "Recreate whatsNew.html and releases.html from markdown files and templates in help"
1497 def releasesTemplateFile = file("${jalviewDir}/${releases_template}")
1498 def whatsnewTemplateFile = file("${jalviewDir}/${whatsnew_template}")
1499 def releasesHtmlFile = file("${helpBuildDir}/${help_dir}/${releases_html}")
1500 def whatsnewHtmlFile = file("${helpBuildDir}/${help_dir}/${whatsnew_html}")
1501 def releasesMdDir = "${jalviewDir}/${releases_dir}"
1502 def whatsnewMdDir = "${jalviewDir}/${whatsnew_dir}"
1505 def releaseMdFile = file("${releasesMdDir}/release-${JALVIEW_VERSION_UNDERSCORES}.md")
1506 def whatsnewMdFile = file("${whatsnewMdDir}/whatsnew-${JALVIEW_VERSION_UNDERSCORES}.md")
1508 if (CHANNEL == "RELEASE") {
1509 if (!releaseMdFile.exists()) {
1510 throw new GradleException("File ${releaseMdFile} must be created for RELEASE")
1512 if (!whatsnewMdFile.exists()) {
1513 throw new GradleException("File ${whatsnewMdFile} must be created for RELEASE")
1517 def releaseFiles = fileTree(dir: releasesMdDir, include: "release-*.md")
1518 def releaseFilesDates = releaseFiles.collectEntries {
1519 [(it): getMdDate(it)]
1521 releaseFiles = releaseFiles.sort { a,b -> releaseFilesDates[a].compareTo(releaseFilesDates[b]) }
1523 def releasesTemplate = releasesTemplateFile.text
1524 def m = releasesTemplate =~ /(?s)__VERSION_LOOP_START__(.*)__VERSION_LOOP_END__/
1525 def versionTemplate = m[0][1]
1527 MutableDataSet options = new MutableDataSet()
1529 def extensions = new ArrayList<>()
1530 options.set(Parser.EXTENSIONS, extensions)
1531 options.set(Parser.HTML_BLOCK_COMMENT_ONLY_FULL_LINE, true)
1533 Parser parser = Parser.builder(options).build()
1534 HtmlRenderer renderer = HtmlRenderer.builder(options).build()
1536 def actualVersions = releaseFiles.collect { rf ->
1537 def (rfMap, rfContent) = mdFileComponents(rf)
1538 return rfMap.version
1540 def versionsHtml = ""
1541 def linkedVersions = []
1542 releaseFiles.reverse().each { rFile ->
1543 def (rMap, rContent) = mdFileComponents(rFile)
1545 def versionLink = ""
1546 def partialVersion = ""
1547 def firstPart = true
1548 rMap.version.split("\\.").each { part ->
1549 def displayPart = ( firstPart ? "" : "." ) + part
1550 partialVersion += displayPart
1552 linkedVersions.contains(partialVersion)
1553 || ( actualVersions.contains(partialVersion) && partialVersion != rMap.version )
1555 versionLink += displayPart
1557 versionLink += "<a id=\"Jalview.${partialVersion}\">${displayPart}</a>"
1558 linkedVersions += partialVersion
1562 def displayDate = releaseFilesDates[rFile].format("dd/MM/yyyy")
1565 def rContentProcessed = ""
1566 rContent.eachLine { line ->
1567 if (lm == line =~ /^(\s*-)(\s*<!--[^>]*?-->)(.*)$/) {
1568 line = "${lm[0][1]}${lm[0][3]}${lm[0][2]}"
1569 } else if (lm == line =~ /^###([^#]+.*)$/) {
1570 line = "_${lm[0][1].trim()}_"
1572 rContentProcessed += line + "\n"
1575 def rContentSections = getMdSections(rContentProcessed)
1576 def rVersion = versionTemplate
1577 if (rVersion != "") {
1578 def rNewFeatures = rContentSections["new_features"]
1579 def rIssuesResolved = rContentSections["issues_resolved"]
1580 Node newFeaturesNode = parser.parse(rNewFeatures)
1581 String newFeaturesHtml = renderer.render(newFeaturesNode)
1582 Node issuesResolvedNode = parser.parse(rIssuesResolved)
1583 String issuesResolvedHtml = renderer.render(issuesResolvedNode)
1584 rVersion = hugoTemplateSubstitutions(rVersion,
1586 VERSION: rMap.version,
1587 VERSION_LINK: versionLink,
1588 DISPLAY_DATE: displayDate,
1589 NEW_FEATURES: newFeaturesHtml,
1590 ISSUES_RESOLVED: issuesResolvedHtml
1593 versionsHtml += rVersion
1597 releasesTemplate = releasesTemplate.replaceAll("(?s)__VERSION_LOOP_START__.*__VERSION_LOOP_END__", versionsHtml)
1598 releasesTemplate = hugoTemplateSubstitutions(releasesTemplate)
1599 releasesHtmlFile.text = releasesTemplate
1601 if (whatsnewMdFile.exists()) {
1602 def wnDisplayDate = releaseFilesDates[releaseMdFile] != null ? releaseFilesDates[releaseMdFile].format("dd MMMM yyyy") : ""
1603 def whatsnewMd = hugoTemplateSubstitutions(whatsnewMdFile.text)
1604 Node whatsnewNode = parser.parse(whatsnewMd)
1605 String whatsnewHtml = renderer.render(whatsnewNode)
1606 whatsnewHtml = whatsnewTemplateFile.text.replaceAll("__WHATS_NEW__", whatsnewHtml)
1607 whatsnewHtmlFile.text = hugoTemplateSubstitutions(whatsnewHtml,
1609 VERSION: JALVIEW_VERSION,
1610 DISPLAY_DATE: wnDisplayDate
1613 } else if (gradle.taskGraph.hasTask(":linkCheck")) {
1614 whatsnewHtmlFile.text = "Development build " + getDate("yyyy-MM-dd HH:mm:ss")
1619 inputs.file(releasesTemplateFile)
1620 inputs.file(whatsnewTemplateFile)
1621 inputs.dir(releasesMdDir)
1622 inputs.dir(whatsnewMdDir)
1623 outputs.file(releasesHtmlFile)
1624 outputs.file(whatsnewHtmlFile)
1629 task copyResources(type: Copy) {
1631 description = "Copy (and make text substitutions in) the resources dir to the build area"
1633 def inputDir = resourceDir
1634 def destinationDirectory = resourcesBuildDir
1638 include('**/*.html')
1640 filter(ReplaceTokens,
1644 'Version-Rel': JALVIEW_VERSION,
1645 'Year-Rel': getDate("yyyy")
1652 exclude('**/*.html')
1655 into destinationDirectory
1657 inputs.dir(inputDir)
1658 outputs.dir(destinationDirectory)
1661 task copyChannelResources(type: Copy) {
1662 dependsOn copyResources
1664 description = "Copy the channel resources dir to the build resources area"
1666 def inputDir = "${channelDir}/${resource_dir}"
1667 def outputDir = resourcesBuildDir
1669 include(channel_props)
1670 filter(ReplaceTokens,
1674 'SUFFIX': channelSuffix
1679 exclude(channel_props)
1683 inputs.dir(inputDir)
1684 outputs.dir(outputDir)
1687 task createBuildProperties(type: WriteProperties) {
1688 dependsOn copyResources
1689 dependsOn copyChannelResources
1691 description = "Create the ${buildProperties} file"
1693 inputs.dir(sourceDir)
1694 inputs.dir(resourcesBuildDir)
1695 outputFile (buildProperties)
1696 // taking time specific comment out to allow better incremental builds
1697 comment "--Jalview Build Details--\n"+getDate("yyyy-MM-dd HH:mm:ss")
1698 //comment "--Jalview Build Details--\n"+getDate("yyyy-MM-dd")
1699 property "BUILD_DATE", getDate("HH:mm:ss dd MMMM yyyy")
1700 property "VERSION", JALVIEW_VERSION
1701 property "INSTALLATION", INSTALLATION+" git-commit:"+gitHash+" ["+gitBranch+"]"
1702 property "JAVA_COMPILE_VERSION", JAVA_INTEGER_VERSION
1703 if (getdownSetAppBaseProperty) {
1704 property "GETDOWNAPPBASE", getdownAppBase
1705 property "GETDOWNAPPDISTDIR", getdownAppDistDir
1707 outputs.file(outputFile)
1711 task buildIndices(type: JavaExec) {
1713 //dependsOn releasesTemplates
1714 classpath = sourceSets.main.compileClasspath
1715 main = "com.sun.java.help.search.Indexer"
1716 workingDir = "${helpBuildDir}/${help_dir}"
1719 inputs.dir("${workingDir}/${argDir}")
1721 outputs.dir("${classesDir}/doc")
1722 outputs.dir("${classesDir}/help")
1723 outputs.file("${workingDir}/JavaHelpSearch/DOCS")
1724 outputs.file("${workingDir}/JavaHelpSearch/DOCS.TAB")
1725 outputs.file("${workingDir}/JavaHelpSearch/OFFSETS")
1726 outputs.file("${workingDir}/JavaHelpSearch/POSITIONS")
1727 outputs.file("${workingDir}/JavaHelpSearch/SCHEMA")
1728 outputs.file("${workingDir}/JavaHelpSearch/TMAP")
1731 task buildResources {
1732 dependsOn copyResources
1733 dependsOn copyChannelResources
1734 dependsOn createBuildProperties
1738 dependsOn buildResources
1741 //dependsOn releasesTemplates
1742 dependsOn convertMdFiles
1743 dependsOn buildIndices
1747 compileJava.dependsOn prepare
1748 run.dependsOn compileJava
1749 compileTestJava.dependsOn compileJava
1750 compileTestJava.dependsOn buildIndices
1751 processResources.dependsOn copyChannelResources
1752 processResources.dependsOn copyResources
1753 processResources.dependsOn createBuildProperties
1754 processResources.dependsOn copyDocs
1755 processResources.dependsOn convertMdFiles
1756 processResources.dependsOn copyHelp
1757 processResources.dependsOn buildIndices
1762 group = "Verification"
1763 description = "Runs all testTaskN tasks)"
1766 dependsOn cloverClasses
1768 dependsOn testClasses
1771 // not running tests in this task
1774 /* testTask0 is the main test task */
1775 task testTask0(type: Test) {
1776 group = "Verification"
1777 description = "The main test task. Runs all non-testTaskN-labelled tests (unless excluded)"
1779 includeGroups testng_groups.split(",")
1780 excludeGroups testng_excluded_groups.split(",")
1781 tasks.withType(Test).matching {it.name.startsWith("testTask") && it.name != name}.all {t -> excludeGroups t.name}
1783 useDefaultListeners=true
1785 timeout = Duration.ofMinutes(15)
1788 /* separated tests */
1789 task testTask1(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)
1801 task testTask2(type: Test) {
1802 group = "Verification"
1803 description = "Tests that need to be isolated from the main test run"
1806 excludeGroups testng_excluded_groups.split(",")
1808 useDefaultListeners=true
1810 timeout = Duration.ofMinutes(5)
1812 task testTask3(type: Test) {
1813 group = "Verification"
1814 description = "Tests that need to be isolated from the main test run"
1817 excludeGroups testng_excluded_groups.split(",")
1819 useDefaultListeners=true
1821 timeout = Duration.ofMinutes(5)
1824 /* insert more testTaskNs here -- change N to next digit or other string */
1826 task testTaskN(type: Test) {
1827 group = "Verification"
1828 description = "Tests that need to be isolated from the main test run"
1831 excludeGroups testng_excluded_groups.split(",")
1833 useDefaultListeners=true
1840 * adapted from https://medium.com/@wasyl/pretty-tests-summary-in-gradle-744804dd676c
1841 * to summarise test results from all Test tasks
1843 /* START of test tasks results summary */
1844 import groovy.time.TimeCategory
1845 import org.gradle.api.tasks.testing.logging.TestExceptionFormat
1846 import org.gradle.api.tasks.testing.logging.TestLogEvent
1847 rootProject.ext.testsResults = [] // Container for tests summaries
1849 tasks.withType(Test).matching {t -> t.getName().startsWith("testTask")}.all { testTask ->
1851 // from original test task
1853 dependsOn cloverClasses
1855 dependsOn testClasses //?
1858 // run main tests first
1859 if (!testTask.name.equals("testTask0"))
1860 testTask.mustRunAfter "testTask0"
1862 testTask.testLogging { logging ->
1863 events TestLogEvent.FAILED
1864 // TestLogEvent.SKIPPED,
1865 // TestLogEvent.STANDARD_OUT,
1866 // TestLogEvent.STANDARD_ERROR
1868 exceptionFormat TestExceptionFormat.FULL
1871 showStackTraces true
1873 showStandardStreams true
1875 info.events = [ TestLogEvent.FAILED ]
1878 if (OperatingSystem.current().isMacOsX()) {
1879 testTask.systemProperty "apple.awt.UIElement", "true"
1880 testTask.environment "JAVA_TOOL_OPTIONS", "-Dapple.awt.UIElement=true"
1884 ignoreFailures = true // Always try to run all tests for all modules
1886 afterSuite { desc, result ->
1888 return // Only summarize results for whole modules
1890 def resultsInfo = [testTask.project.name, testTask.name, result, TimeCategory.minus(new Date(result.endTime), new Date(result.startTime)), testTask.reports.html.entryPoint]
1892 rootProject.ext.testsResults.add(resultsInfo)
1895 // from original test task
1896 maxHeapSize = "1024m"
1898 workingDir = jalviewDir
1899 def testLaf = project.findProperty("test_laf")
1900 if (testLaf != null) {
1901 println("Setting Test LaF to '${testLaf}'")
1902 systemProperty "laf", testLaf
1904 def testHiDPIScale = project.findProperty("test_HiDPIScale")
1905 if (testHiDPIScale != null) {
1906 println("Setting Test HiDPI Scale to '${testHiDPIScale}'")
1907 systemProperty "sun.java2d.uiScale", testHiDPIScale
1909 sourceCompatibility = compile_source_compatibility
1910 targetCompatibility = compile_target_compatibility
1911 jvmArgs += additional_compiler_args
1914 // this is not perfect yet -- we should only add the commandLineIncludePatterns to the
1915 // testTasks that include the tests, and exclude all from the others.
1916 // get --test argument
1917 filter.commandLineIncludePatterns = test.filter.commandLineIncludePatterns
1918 // do something with testTask.getCandidateClassFiles() to see if the test should silently finish because of the
1919 // commandLineIncludePatterns not matching anything. Instead we are doing setFailOnNoMatchingTests(false) below
1923 println("Running tests " + (useClover?"WITH":"WITHOUT") + " clover")
1928 /* don't fail on no matching tests (so --tests will run across all testTasks) */
1929 testTask.filter.setFailOnNoMatchingTests(false)
1931 /* ensure the "test" task dependsOn all the testTasks */
1932 test.dependsOn testTask
1935 gradle.buildFinished {
1936 def allResults = rootProject.ext.testsResults
1938 if (!allResults.isEmpty()) {
1939 printResults allResults
1940 allResults.each {r ->
1941 if (r[2].resultType == TestResult.ResultType.FAILURE)
1942 throw new GradleException("Failed tests!")
1947 private static String colString(styler, col, colour, text) {
1948 return col?"${styler[colour](text)}":text
1951 private static String getSummaryLine(s, pn, tn, rt, rc, rs, rf, rsk, t, col) {
1952 def colour = 'black'
1960 case TestResult.ResultType.SUCCESS:
1963 case TestResult.ResultType.FAILURE:
1971 StringBuilder sb = new StringBuilder()
1975 sb.append(" results: ")
1976 sb.append(colString(s, col && !nocol, colour, text))
1978 sb.append("${rc} tests, ")
1979 sb.append(colString(s, col && rs > 0, 'green', rs))
1980 sb.append(" successes, ")
1981 sb.append(colString(s, col && rf > 0, 'red', rf))
1982 sb.append(" failures, ")
1983 sb.append("${rsk} skipped) in ${t}")
1984 return sb.toString()
1987 private static void printResults(allResults) {
1989 // styler from https://stackoverflow.com/a/56139852
1990 def styler = 'black red green yellow blue magenta cyan white'.split().toList().withIndex(30).collectEntries { key, val -> [(key) : { "\033[${val}m${it}\033[0m" }] }
1993 def failedTests = false
1994 def summaryLines = []
1996 def totalsuccess = 0
1999 def totaltime = TimeCategory.getSeconds(0)
2000 // sort on project name then task name
2001 allResults.sort {a, b -> a[0] == b[0]? a[1]<=>b[1]:a[0] <=> b[0]}.each {
2002 def projectName = it[0]
2003 def taskName = it[1]
2007 def summaryCol = getSummaryLine(styler, projectName, taskName, result.resultType, result.testCount, result.successfulTestCount, result.failedTestCount, result.skippedTestCount, time, true)
2008 def summaryPlain = getSummaryLine(styler, projectName, taskName, result.resultType, result.testCount, result.successfulTestCount, result.failedTestCount, result.skippedTestCount, time, false)
2009 def reportLine = "Report file: ${report}"
2010 def ls = summaryPlain.length()
2011 def lr = reportLine.length()
2012 def m = [ls, lr].max()
2015 def info = [ls, summaryCol, reportLine]
2016 summaryLines.add(info)
2017 failedTests |= result.resultType == TestResult.ResultType.FAILURE
2018 totalcount += result.testCount
2019 totalsuccess += result.successfulTestCount
2020 totalfail += result.failedTestCount
2021 totalskip += result.skippedTestCount
2024 def totalSummaryCol = getSummaryLine(styler, "OVERALL", "", failedTests?TestResult.ResultType.FAILURE:TestResult.ResultType.SUCCESS, totalcount, totalsuccess, totalfail, totalskip, totaltime, true)
2025 def totalSummaryPlain = getSummaryLine(styler, "OVERALL", "", failedTests?TestResult.ResultType.FAILURE:TestResult.ResultType.SUCCESS, totalcount, totalsuccess, totalfail, totalskip, totaltime, false)
2026 def tls = totalSummaryPlain.length()
2027 if (tls > maxLength)
2029 def info = [tls, totalSummaryCol, null]
2030 summaryLines.add(info)
2032 def allSummaries = []
2033 for(sInfo : summaryLines) {
2035 def summary = sInfo[1]
2036 def report = sInfo[2]
2038 StringBuilder sb = new StringBuilder()
2039 sb.append("│" + summary + " " * (maxLength - ls) + "│")
2040 if (report != null) {
2041 sb.append("\n│" + report + " " * (maxLength - report.length()) + "│")
2043 allSummaries += sb.toString()
2046 println "┌${"${"─" * maxLength}"}┐"
2047 println allSummaries.join("\n├${"${"─" * maxLength}"}┤\n")
2048 println "└${"${"─" * maxLength}"}┘"
2050 /* END of test tasks results summary */
2054 task compileLinkCheck(type: JavaCompile) {
2056 classpath = files("${jalviewDir}/${utils_dir}")
2057 destinationDir = file("${jalviewDir}/${utils_dir}")
2058 source = fileTree(dir: "${jalviewDir}/${utils_dir}", include: ["HelpLinksChecker.java", "BufferedLineReader.java"])
2060 inputs.file("${jalviewDir}/${utils_dir}/HelpLinksChecker.java")
2061 inputs.file("${jalviewDir}/${utils_dir}/HelpLinksChecker.java")
2062 outputs.file("${jalviewDir}/${utils_dir}/HelpLinksChecker.class")
2063 outputs.file("${jalviewDir}/${utils_dir}/BufferedLineReader.class")
2067 task linkCheck(type: JavaExec) {
2069 dependsOn compileLinkCheck
2071 def helpLinksCheckerOutFile = file("${jalviewDir}/${utils_dir}/HelpLinksChecker.out")
2072 classpath = files("${jalviewDir}/${utils_dir}")
2073 main = "HelpLinksChecker"
2074 workingDir = "${helpBuildDir}"
2075 args = [ "${helpBuildDir}/${help_dir}", "-nointernet" ]
2077 def outFOS = new FileOutputStream(helpLinksCheckerOutFile, false) // false == don't append
2078 standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
2081 errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
2085 inputs.dir(helpBuildDir)
2086 outputs.file(helpLinksCheckerOutFile)
2091 // import the pubhtmlhelp target
2092 ant.properties.basedir = "${jalviewDir}"
2093 ant.properties.helpBuildDir = "${helpBuildDir}/${help_dir}"
2094 ant.importBuild "${utils_dir}/publishHelp.xml"
2097 task cleanPackageDir(type: Delete) {
2099 delete fileTree(dir: "${jalviewDir}/${package_dir}", include: "*.jar")
2103 // block of dependencies
2104 //compileTestJava.dependsOn compileLinkCheck //
2105 //copyChannelResources.dependsOn compileLinkCheck //
2106 //convertMdFiles.dependsOn compileLinkCheck //
2110 dependsOn //linkCheck
2113 attributes "Main-Class": main_class,
2114 "Permissions": "all-permissions",
2115 "Application-Name": applicationName,
2116 "Codebase": application_codebase,
2117 "Implementation-Version": JALVIEW_VERSION
2120 def destinationDirectory = "${jalviewDir}/${package_dir}"
2121 destinationDirectory = file(destinationDirectory)
2122 archiveFileName = rootProject.name+".jar"
2123 duplicatesStrategy "EXCLUDE"
2130 exclude "**/*.jar.*"
2132 inputs.dir(sourceSets.main.java.destinationDirectory)
2133 sourceSets.main.resources.srcDirs.each{ dir ->
2136 outputs.file("${destinationDirectory}/${archiveFileName}")
2140 task copyJars(type: Copy) {
2141 from fileTree(dir: classesDir, include: "**/*.jar").files
2142 into "${jalviewDir}/${package_dir}"
2146 // doing a Sync instead of Copy as Copy doesn't deal with "outputs" very well
2147 task syncJars(type: Sync) {
2149 from fileTree(dir: "${jalviewDir}/${libDistDir}", include: "**/*.jar").files
2150 into "${jalviewDir}/${package_dir}"
2152 include jar.archiveFileName.getOrNull()
2159 description = "Put all required libraries in dist"
2160 // order of "cleanPackageDir", "copyJars", "jar" important!
2161 jar.mustRunAfter cleanPackageDir
2162 syncJars.mustRunAfter cleanPackageDir
2163 dependsOn cleanPackageDir
2166 outputs.dir("${jalviewDir}/${package_dir}")
2171 dependsOn cleanPackageDir
2177 task launcherJar(type: Jar) {
2180 "Main-Class": shadow_jar_main_class,
2181 "Implementation-Version": JALVIEW_VERSION,
2182 "Application-Name": applicationName
2188 group = "distribution"
2189 description = "Create a single jar file with all dependency libraries merged. Can be run with java -jar"
2194 def jarFiles = fileTree(dir: "${jalviewDir}/${libDistDir}", include: "*.jar", exclude: "regex.jar").getFiles()
2195 def groovyJars = jarFiles.findAll {it1 -> file(it1).getName().startsWith("groovy-swing")}
2196 def otherJars = jarFiles.findAll {it2 -> !file(it2).getName().startsWith("groovy-swing")}
2201 // shadowJar manifest must inheritFrom another Jar task. Can't set attributes here.
2202 inheritFrom(project.tasks.launcherJar.manifest)
2204 // we need to include the groovy-swing Include-Package for it to run in the shadowJar
2206 def jarFileManifests = []
2207 groovyJars.each { jarFile ->
2208 def mf = zipTree(jarFile).getFiles().find { it.getName().equals("MANIFEST.MF") }
2210 jarFileManifests += mf
2214 from (jarFileManifests) {
2215 eachEntry { details ->
2216 if (!details.key.equals("Import-Package")) {
2224 duplicatesStrategy "INCLUDE"
2226 // this mainClassName is mandatory but gets ignored due to manifest created in doFirst{}. Set the Main-Class as an attribute in launcherJar instead
2227 mainClassName = shadow_jar_main_class
2229 archiveClassifier = "all-"+JALVIEW_VERSION+"-j"+JAVA_VERSION
2233 task getdownImagesCopy() {
2234 inputs.dir getdownImagesDir
2235 outputs.dir getdownImagesBuildDir
2239 from(getdownImagesDir) {
2240 include("*getdown*.png")
2242 into getdownImagesBuildDir
2247 task getdownImagesProcess() {
2248 dependsOn getdownImagesCopy
2251 if (backgroundImageText) {
2252 if (convertBinary == null) {
2253 throw new StopExecutionException("No ImageMagick convert binary installed at '${convertBinaryExpectedLocation}'")
2255 if (!project.hasProperty("getdown_background_image_text_suffix_cmd")) {
2256 throw new StopExecutionException("No property 'getdown_background_image_text_suffix_cmd' defined. See channel_gradle.properties for channel ${CHANNEL}")
2258 fileTree(dir: getdownImagesBuildDir, include: "*background*.png").getFiles().each { file ->
2260 executable convertBinary
2263 '-font', getdown_background_image_text_font,
2264 '-fill', getdown_background_image_text_colour,
2265 '-draw', sprintf(getdown_background_image_text_suffix_cmd, channelSuffix),
2266 '-draw', sprintf(getdown_background_image_text_commit_cmd, "git-commit: ${gitHash}"),
2267 '-draw', sprintf(getdown_background_image_text_date_cmd, getDate("yyyy-MM-dd HH:mm:ss")),
2276 task getdownImages() {
2277 dependsOn getdownImagesProcess
2280 task getdownWebsiteBuild() {
2281 group = "distribution"
2282 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."
2284 dependsOn getdownImages
2289 def getdownWebsiteResourceFilenames = []
2290 def getdownResourceDir = getdownResourceDir
2291 def getdownResourceFilenames = []
2294 // clean the getdown website and files dir before creating getdown folders
2295 delete getdownAppBaseDir
2296 delete getdownFilesDir
2299 from buildProperties
2300 rename(file(buildProperties).getName(), getdown_build_properties)
2303 getdownWebsiteResourceFilenames += "${getdownAppDistDir}/${getdown_build_properties}"
2306 from channelPropsFile
2307 filter(ReplaceTokens,
2311 'SUFFIX': channelSuffix
2314 into getdownAppBaseDir
2316 getdownWebsiteResourceFilenames += file(channelPropsFile).getName()
2318 // set some getdownTxt_ properties then go through all properties looking for getdownTxt_...
2319 def props = project.properties.sort { it.key }
2320 if (getdownAltJavaMinVersion != null && getdownAltJavaMinVersion.length() > 0) {
2321 props.put("getdown_txt_java_min_version", getdownAltJavaMinVersion)
2323 if (getdownAltJavaMaxVersion != null && getdownAltJavaMaxVersion.length() > 0) {
2324 props.put("getdown_txt_java_max_version", getdownAltJavaMaxVersion)
2326 if (getdownAltMultiJavaLocation != null && getdownAltMultiJavaLocation.length() > 0) {
2327 props.put("getdown_txt_multi_java_location", getdownAltMultiJavaLocation)
2329 if (getdownImagesBuildDir != null && file(getdownImagesBuildDir).exists()) {
2330 props.put("getdown_txt_ui.background_image", "${getdownImagesBuildDir}/${getdown_background_image}")
2331 props.put("getdown_txt_ui.instant_background_image", "${getdownImagesBuildDir}/${getdown_instant_background_image}")
2332 props.put("getdown_txt_ui.error_background", "${getdownImagesBuildDir}/${getdown_error_background}")
2333 props.put("getdown_txt_ui.progress_image", "${getdownImagesBuildDir}/${getdown_progress_image}")
2334 props.put("getdown_txt_ui.icon", "${getdownImagesDir}/${getdown_icon}")
2335 props.put("getdown_txt_ui.mac_dock_icon", "${getdownImagesDir}/${getdown_mac_dock_icon}")
2338 props.put("getdown_txt_title", jalview_name)
2339 props.put("getdown_txt_ui.name", applicationName)
2341 // start with appbase
2342 getdownTextLines += "appbase = ${getdownAppBase}"
2343 props.each{ prop, val ->
2344 if (prop.startsWith("getdown_txt_") && val != null) {
2345 if (prop.startsWith("getdown_txt_multi_")) {
2346 def key = prop.substring(18)
2347 val.split(",").each{ v ->
2348 def line = "${key} = ${v}"
2349 getdownTextLines += line
2352 // file values rationalised
2353 if (val.indexOf('/') > -1 || prop.startsWith("getdown_txt_resource")) {
2355 if (val.indexOf('/') == 0) {
2358 } else if (val.indexOf('/') > 0) {
2359 // relative path (relative to jalviewDir)
2360 r = file( "${jalviewDir}/${val}" )
2363 val = "${getdown_resource_dir}/" + r.getName()
2364 getdownWebsiteResourceFilenames += val
2365 getdownResourceFilenames += r.getPath()
2368 if (! prop.startsWith("getdown_txt_resource")) {
2369 def line = prop.substring(12) + " = ${val}"
2370 getdownTextLines += line
2376 getdownWebsiteResourceFilenames.each{ filename ->
2377 getdownTextLines += "resource = ${filename}"
2379 getdownResourceFilenames.each{ filename ->
2382 into getdownResourceDir
2386 def getdownWrapperScripts = [ getdown_bash_wrapper_script, getdown_powershell_wrapper_script, getdown_batch_wrapper_script ]
2387 getdownWrapperScripts.each{ script ->
2388 def s = file( "${jalviewDir}/utils/getdown/${getdown_wrapper_script_dir}/${script}" )
2392 into "${getdownAppBaseDir}/${getdown_wrapper_script_dir}"
2394 getdownTextLines += "xresource = ${getdown_wrapper_script_dir}/${script}"
2399 fileTree(file(package_dir)).each{ f ->
2400 if (f.isDirectory()) {
2401 def files = fileTree(dir: f, include: ["*"]).getFiles()
2403 } else if (f.exists()) {
2407 def jalviewJar = jar.archiveFileName.getOrNull()
2408 // put jalview.jar first for CLASSPATH and .properties files reasons
2409 codeFiles.sort{a, b -> ( a.getName() == jalviewJar ? -1 : ( b.getName() == jalviewJar ? 1 : a <=> b ) ) }.each{f ->
2410 def name = f.getName()
2411 def line = "code = ${getdownAppDistDir}/${name}"
2412 getdownTextLines += line
2419 // NOT USING MODULES YET, EVERYTHING SHOULD BE IN dist
2421 if (JAVA_VERSION.equals("11")) {
2422 def j11libFiles = fileTree(dir: "${jalviewDir}/${j11libDir}", include: ["*.jar"]).getFiles()
2423 j11libFiles.sort().each{f ->
2424 def name = f.getName()
2425 def line = "code = ${getdown_j11lib_dir}/${name}"
2426 getdownTextLines += line
2429 into getdownJ11libDir
2435 // 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.
2436 //getdownTextLines += "class = " + file(getdownLauncher).getName()
2437 getdownTextLines += "resource = ${getdown_launcher_new}"
2438 getdownTextLines += "class = ${main_class}"
2439 // Not setting these properties in general so that getdownappbase and getdowndistdir will default to release version in jalview.bin.Cache
2440 if (getdownSetAppBaseProperty) {
2441 getdownTextLines += "jvmarg = -Dgetdowndistdir=${getdownAppDistDir}"
2442 getdownTextLines += "jvmarg = -Dgetdownappbase=${getdownAppBase}"
2445 def getdownTxt = file("${getdownAppBaseDir}/getdown.txt")
2446 getdownTxt.write(getdownTextLines.join("\n"))
2448 getdownLaunchJvl = getdown_launch_jvl_name + ( (jvlChannelName != null && jvlChannelName.length() > 0)?"-${jvlChannelName}":"" ) + ".jvl"
2449 def launchJvl = file("${getdownAppBaseDir}/${getdownLaunchJvl}")
2450 launchJvl.write("appbase=${getdownAppBase}")
2452 // files going into the getdown website dir: getdown-launcher.jar
2454 from getdownLauncher
2455 rename(file(getdownLauncher).getName(), getdown_launcher_new)
2456 into getdownAppBaseDir
2459 // files going into the getdown website dir: getdown-launcher(-local).jar
2461 from getdownLauncher
2462 if (file(getdownLauncher).getName() != getdown_launcher) {
2463 rename(file(getdownLauncher).getName(), getdown_launcher)
2465 into getdownAppBaseDir
2468 // files going into the getdown website dir: ./install dir and files
2469 if (! (CHANNEL.startsWith("ARCHIVE") || CHANNEL.startsWith("DEVELOP"))) {
2472 from getdownLauncher
2473 from "${getdownAppDir}/${getdown_build_properties}"
2474 if (file(getdownLauncher).getName() != getdown_launcher) {
2475 rename(file(getdownLauncher).getName(), getdown_launcher)
2477 into getdownInstallDir
2480 // and make a copy in the getdown files dir (these are not downloaded by getdown)
2482 from getdownInstallDir
2483 into getdownFilesInstallDir
2487 // files going into the getdown files dir: getdown.txt, getdown-launcher.jar, channel-launch.jvl, build_properties
2491 from getdownLauncher
2492 from "${getdownAppBaseDir}/${getdown_build_properties}"
2493 from "${getdownAppBaseDir}/${channel_props}"
2494 if (file(getdownLauncher).getName() != getdown_launcher) {
2495 rename(file(getdownLauncher).getName(), getdown_launcher)
2497 into getdownFilesDir
2500 // and ./resource (not all downloaded by getdown)
2502 from getdownResourceDir
2503 into "${getdownFilesDir}/${getdown_resource_dir}"
2508 inputs.dir("${jalviewDir}/${package_dir}")
2510 outputs.dir(getdownAppBaseDir)
2511 outputs.dir(getdownFilesDir)
2515 // a helper task to allow getdown digest of any dir: `gradle getdownDigestDir -PDIGESTDIR=/path/to/my/random/getdown/dir
2516 task getdownDigestDir(type: JavaExec) {
2518 description "A task to run a getdown Digest on a dir with getdown.txt. Provide a DIGESTDIR property via -PDIGESTDIR=..."
2520 def digestDirPropertyName = "DIGESTDIR"
2522 classpath = files(getdownLauncher)
2523 def digestDir = findProperty(digestDirPropertyName)
2524 if (digestDir == null) {
2525 throw new GradleException("Must provide a DIGESTDIR value to produce an alternative getdown digest")
2529 main = "com.threerings.getdown.tools.Digester"
2533 task getdownDigest(type: JavaExec) {
2534 group = "distribution"
2535 description = "Digest the getdown website folder"
2537 dependsOn getdownWebsiteBuild
2540 classpath = files(getdownLauncher)
2542 main = "com.threerings.getdown.tools.Digester"
2543 args getdownAppBaseDir
2544 inputs.dir(getdownAppBaseDir)
2545 outputs.file("${getdownAppBaseDir}/digest2.txt")
2550 group = "distribution"
2551 description = "Create the minimal and full getdown app folder for installers and website and create digest file"
2552 dependsOn getdownDigest
2554 if (reportRsyncCommand) {
2555 def fromDir = getdownAppBaseDir + (getdownAppBaseDir.endsWith('/')?'':'/')
2556 def toDir = "${getdown_rsync_dest}/${getdownDir}" + (getdownDir.endsWith('/')?'':'/')
2557 println "LIKELY RSYNC COMMAND:"
2558 println "mkdir -p '$toDir'\nrsync -avh --delete '$fromDir' '$toDir'"
2559 if (RUNRSYNC == "true") {
2561 commandLine "mkdir", "-p", toDir
2564 commandLine "rsync", "-avh", "--delete", fromDir, toDir
2571 task getdownWebsite {
2572 group = "distribution"
2573 description = "A task to create the whole getdown channel website dir including digest file"
2575 dependsOn getdownWebsiteBuild
2576 dependsOn getdownDigest
2579 task getdownArchiveBuild() {
2580 group = "distribution"
2581 description = "Put files in the archive dir to go on the website"
2583 dependsOn getdownWebsiteBuild
2585 def v = "v${JALVIEW_VERSION_UNDERSCORES}"
2586 def vDir = "${getdownArchiveDir}/${v}"
2587 getdownFullArchiveDir = "${vDir}/getdown"
2588 getdownVersionLaunchJvl = "${vDir}/jalview-${v}.jvl"
2590 def vAltDir = "alt_${v}"
2591 def archiveImagesDir = "${jalviewDir}/${channel_properties_dir}/old/images"
2594 // cleanup old "old" dir
2595 delete getdownArchiveDir
2597 def getdownArchiveTxt = file("${getdownFullArchiveDir}/getdown.txt")
2598 getdownArchiveTxt.getParentFile().mkdirs()
2599 def getdownArchiveTextLines = []
2600 def getdownFullArchiveAppBase = "${getdownArchiveAppBase}${getdownArchiveAppBase.endsWith("/")?"":"/"}${v}/getdown/"
2604 from "${getdownAppBaseDir}/${getdownAppDistDir}"
2605 into "${getdownFullArchiveDir}/${vAltDir}"
2608 getdownTextLines.each { line ->
2609 line = line.replaceAll("^(?<s>appbase\\s*=\\s*).*", '${s}'+getdownFullArchiveAppBase)
2610 line = line.replaceAll("^(?<s>(resource|code)\\s*=\\s*)${getdownAppDistDir}/", '${s}'+vAltDir+"/")
2611 line = line.replaceAll("^(?<s>ui.background_image\\s*=\\s*).*\\.png", '${s}'+"${getdown_resource_dir}/jalview_archive_getdown_background.png")
2612 line = line.replaceAll("^(?<s>ui.instant_background_image\\s*=\\s*).*\\.png", '${s}'+"${getdown_resource_dir}/jalview_archive_getdown_background_initialising.png")
2613 line = line.replaceAll("^(?<s>ui.error_background\\s*=\\s*).*\\.png", '${s}'+"${getdown_resource_dir}/jalview_archive_getdown_background_error.png")
2614 line = line.replaceAll("^(?<s>ui.progress_image\\s*=\\s*).*\\.png", '${s}'+"${getdown_resource_dir}/jalview_archive_getdown_progress_bar.png")
2615 // remove the existing resource = resource/ or bin/ lines
2616 if (! line.matches("resource\\s*=\\s*(resource|bin)/.*")) {
2617 getdownArchiveTextLines += line
2621 // the resource dir -- add these files as resource lines in getdown.txt
2623 from "${archiveImagesDir}"
2624 into "${getdownFullArchiveDir}/${getdown_resource_dir}"
2626 getdownArchiveTextLines += "resource = ${getdown_resource_dir}/${file.getName()}"
2630 getdownArchiveTxt.write(getdownArchiveTextLines.join("\n"))
2632 def vLaunchJvl = file(getdownVersionLaunchJvl)
2633 vLaunchJvl.getParentFile().mkdirs()
2634 vLaunchJvl.write("appbase=${getdownFullArchiveAppBase}\n")
2635 def vLaunchJvlPath = vLaunchJvl.toPath().toAbsolutePath()
2636 def jvlLinkPath = file("${vDir}/jalview.jvl").toPath().toAbsolutePath()
2637 // for some reason filepath.relativize(fileInSameDirPath) gives a path to "../" which is wrong
2638 //java.nio.file.Files.createSymbolicLink(jvlLinkPath, jvlLinkPath.relativize(vLaunchJvlPath));
2639 java.nio.file.Files.createSymbolicLink(jvlLinkPath, java.nio.file.Paths.get(".",vLaunchJvl.getName()));
2641 // files going into the getdown files dir: getdown.txt, getdown-launcher.jar, channel-launch.jvl, build_properties
2643 from getdownLauncher
2644 from "${getdownAppBaseDir}/${getdownLaunchJvl}"
2645 from "${getdownAppBaseDir}/${getdown_launcher_new}"
2646 from "${getdownAppBaseDir}/${channel_props}"
2647 if (file(getdownLauncher).getName() != getdown_launcher) {
2648 rename(file(getdownLauncher).getName(), getdown_launcher)
2650 into getdownFullArchiveDir
2656 task getdownArchiveDigest(type: JavaExec) {
2657 group = "distribution"
2658 description = "Digest the getdown archive folder"
2660 dependsOn getdownArchiveBuild
2663 classpath = files(getdownLauncher)
2664 args getdownFullArchiveDir
2666 main = "com.threerings.getdown.tools.Digester"
2667 inputs.dir(getdownFullArchiveDir)
2668 outputs.file("${getdownFullArchiveDir}/digest2.txt")
2671 task getdownArchive() {
2672 group = "distribution"
2673 description = "Build the website archive dir with getdown digest"
2675 dependsOn getdownArchiveBuild
2676 dependsOn getdownArchiveDigest
2679 tasks.withType(JavaCompile) {
2680 options.encoding = 'UTF-8'
2686 delete getdownAppBaseDir
2687 delete getdownFilesDir
2688 delete getdownArchiveDir
2694 if (file(install4jHomeDir).exists()) {
2696 } else if (file(System.getProperty("user.home")+"/buildtools/install4j").exists()) {
2697 install4jHomeDir = System.getProperty("user.home")+"/buildtools/install4j"
2698 } else if (file("/Applications/install4j.app/Contents/Resources/app").exists()) {
2699 install4jHomeDir = "/Applications/install4j.app/Contents/Resources/app"
2701 installDir(file(install4jHomeDir))
2703 mediaTypes = Arrays.asList(install4j_media_types.split(","))
2707 task copyInstall4jTemplate {
2708 def install4jTemplateFile = file("${install4jDir}/${install4j_template}")
2709 def install4jFileAssociationsFile = file("${install4jDir}/${install4j_installer_file_associations}")
2710 inputs.file(install4jTemplateFile)
2711 inputs.file(install4jFileAssociationsFile)
2712 inputs.property("CHANNEL", { CHANNEL })
2713 outputs.file(install4jConfFile)
2716 def install4jConfigXml = new XmlParser().parse(install4jTemplateFile)
2718 // turn off code signing if no OSX_KEYPASS
2719 if (OSX_KEYPASS == "") {
2720 install4jConfigXml.'**'.codeSigning.each { codeSigning ->
2721 codeSigning.'@macEnabled' = "false"
2723 install4jConfigXml.'**'.windows.each { windows ->
2724 windows.'@runPostProcessor' = "false"
2728 // disable install screen for OSX dmg (for 2.11.2.0)
2729 install4jConfigXml.'**'.macosArchive.each { macosArchive ->
2730 macosArchive.attributes().remove('executeSetupApp')
2731 macosArchive.attributes().remove('setupAppId')
2734 // turn off checksum creation for LOCAL channel
2735 def e = install4jConfigXml.application[0]
2736 e.'@createChecksums' = string(install4jCheckSums)
2738 // put file association actions where placeholder action is
2739 def install4jFileAssociationsText = install4jFileAssociationsFile.text
2740 def fileAssociationActions = new XmlParser().parseText("<actions>${install4jFileAssociationsText}</actions>")
2741 install4jConfigXml.'**'.action.any { a -> // .any{} stops after the first one that returns true
2742 if (a.'@name' == 'EXTENSIONS_REPLACED_BY_GRADLE') {
2743 def parent = a.parent()
2745 fileAssociationActions.each { faa ->
2748 // don't need to continue in .any loop once replacements have been made
2753 // use Windows Program Group with Examples folder for RELEASE, and Program Group without Examples for everything else
2754 // NB we're deleting the /other/ one!
2755 // Also remove the examples subdir from non-release versions
2756 def customizedIdToDelete = "PROGRAM_GROUP_RELEASE"
2757 // 2.11.1.0 NOT releasing with the Examples folder in the Program Group
2758 if (false && CHANNEL=="RELEASE") { // remove 'false && ' to include Examples folder in RELEASE channel
2759 customizedIdToDelete = "PROGRAM_GROUP_NON_RELEASE"
2761 // remove the examples subdir from Full File Set
2762 def files = install4jConfigXml.files[0]
2763 def fileset = files.filesets.fileset.find { fs -> fs.'@customizedId' == "FULL_FILE_SET" }
2764 def root = files.roots.root.find { r -> r.'@fileset' == fileset.'@id' }
2765 def mountPoint = files.mountPoints.mountPoint.find { mp -> mp.'@root' == root.'@id' }
2766 def dirEntry = files.entries.dirEntry.find { de -> de.'@mountPoint' == mountPoint.'@id' && de.'@subDirectory' == "examples" }
2767 dirEntry.parent().remove(dirEntry)
2769 install4jConfigXml.'**'.action.any { a ->
2770 if (a.'@customizedId' == customizedIdToDelete) {
2771 def parent = a.parent()
2777 // write install4j file
2778 install4jConfFile.text = XmlUtil.serialize(install4jConfigXml)
2785 delete install4jConfFile
2789 task cleanInstallersDataFiles {
2790 def installersOutputTxt = file("${jalviewDir}/${install4jBuildDir}/output.txt")
2791 def installersSha256 = file("${jalviewDir}/${install4jBuildDir}/sha256sums")
2792 def hugoDataJsonFile = file("${jalviewDir}/${install4jBuildDir}/installers-${JALVIEW_VERSION_UNDERSCORES}.json")
2794 delete installersOutputTxt
2795 delete installersSha256
2796 delete hugoDataJsonFile
2800 task install4jDMGBackgroundImageCopy {
2801 inputs.file "${install4jDMGBackgroundImageDir}/${install4jDMGBackgroundImageFile}"
2802 outputs.dir "${install4jDMGBackgroundImageBuildDir}"
2805 from(install4jDMGBackgroundImageDir) {
2806 include(install4jDMGBackgroundImageFile)
2808 into install4jDMGBackgroundImageBuildDir
2813 task install4jDMGBackgroundImageProcess {
2814 dependsOn install4jDMGBackgroundImageCopy
2817 if (backgroundImageText) {
2818 if (convertBinary == null) {
2819 throw new StopExecutionException("No ImageMagick convert binary installed at '${convertBinaryExpectedLocation}'")
2821 if (!project.hasProperty("install4j_background_image_text_suffix_cmd")) {
2822 throw new StopExecutionException("No property 'install4j_background_image_text_suffix_cmd' defined. See channel_gradle.properties for channel ${CHANNEL}")
2824 fileTree(dir: install4jDMGBackgroundImageBuildDir, include: "*.png").getFiles().each { file ->
2826 executable convertBinary
2829 '-font', install4j_background_image_text_font,
2830 '-fill', install4j_background_image_text_colour,
2831 '-draw', sprintf(install4j_background_image_text_suffix_cmd, channelSuffix),
2832 '-draw', sprintf(install4j_background_image_text_commit_cmd, "git-commit: ${gitHash}"),
2833 '-draw', sprintf(install4j_background_image_text_date_cmd, getDate("yyyy-MM-dd HH:mm:ss")),
2842 task install4jDMGBackgroundImage {
2843 dependsOn install4jDMGBackgroundImageProcess
2846 task installerFiles(type: com.install4j.gradle.Install4jTask) {
2847 group = "distribution"
2848 description = "Create the install4j installers"
2850 dependsOn copyInstall4jTemplate
2851 dependsOn cleanInstallersDataFiles
2852 dependsOn install4jDMGBackgroundImage
2854 projectFile = install4jConfFile
2856 // create an md5 for the input files to use as version for install4j conf file
2857 def digest = MessageDigest.getInstance("MD5")
2859 (file("${install4jDir}/${install4j_template}").text +
2860 file("${install4jDir}/${install4j_info_plist_file_associations}").text +
2861 file("${install4jDir}/${install4j_installer_file_associations}").text).bytes)
2862 def filesMd5 = new BigInteger(1, digest.digest()).toString(16)
2863 if (filesMd5.length() >= 8) {
2864 filesMd5 = filesMd5.substring(0,8)
2866 def install4jTemplateVersion = "${JALVIEW_VERSION}_F${filesMd5}_C${gitHash}"
2869 'JALVIEW_NAME': jalview_name,
2870 'JALVIEW_APPLICATION_NAME': applicationName,
2871 'JALVIEW_DIR': "../..",
2872 'OSX_KEYSTORE': OSX_KEYSTORE,
2873 'OSX_APPLEID': OSX_APPLEID,
2874 'OSX_ALTOOLPASS': OSX_ALTOOLPASS,
2875 'JSIGN_SH': JSIGN_SH,
2876 'JRE_DIR': getdown_app_dir_java,
2877 'INSTALLER_TEMPLATE_VERSION': install4jTemplateVersion,
2878 'JALVIEW_VERSION': JALVIEW_VERSION,
2879 'JAVA_MIN_VERSION': JAVA_MIN_VERSION,
2880 'JAVA_MAX_VERSION': JAVA_MAX_VERSION,
2881 'JAVA_VERSION': JAVA_VERSION,
2882 'JAVA_INTEGER_VERSION': JAVA_INTEGER_VERSION,
2883 'VERSION': JALVIEW_VERSION,
2884 'COPYRIGHT_MESSAGE': install4j_copyright_message,
2885 'BUNDLE_ID': install4jBundleId,
2886 'INTERNAL_ID': install4jInternalId,
2887 'WINDOWS_APPLICATION_ID': install4jWinApplicationId,
2888 'MACOS_DMG_DS_STORE': install4jDMGDSStore,
2889 'MACOS_DMG_BG_IMAGE': "${install4jDMGBackgroundImageBuildDir}/${install4jDMGBackgroundImageFile}",
2890 'WRAPPER_LINK': getdownWrapperLink,
2891 'BASH_WRAPPER_SCRIPT': getdown_bash_wrapper_script,
2892 'POWERSHELL_WRAPPER_SCRIPT': getdown_powershell_wrapper_script,
2893 'BATCH_WRAPPER_SCRIPT': getdown_batch_wrapper_script,
2894 'WRAPPER_SCRIPT_BIN_DIR': getdown_wrapper_script_dir,
2895 'INSTALLER_NAME': install4jInstallerName,
2896 'INSTALL4J_UTILS_DIR': install4j_utils_dir,
2897 'GETDOWN_CHANNEL_DIR': getdownChannelDir,
2898 'GETDOWN_FILES_DIR': getdown_files_dir,
2899 'GETDOWN_RESOURCE_DIR': getdown_resource_dir,
2900 'GETDOWN_DIST_DIR': getdownAppDistDir,
2901 'GETDOWN_ALT_DIR': getdown_app_dir_alt,
2902 'GETDOWN_INSTALL_DIR': getdown_install_dir,
2903 'INFO_PLIST_FILE_ASSOCIATIONS_FILE': install4j_info_plist_file_associations,
2904 'BUILD_DIR': install4jBuildDir,
2905 'APPLICATION_CATEGORIES': install4j_application_categories,
2906 'APPLICATION_FOLDER': install4jApplicationFolder,
2907 'UNIX_APPLICATION_FOLDER': install4jUnixApplicationFolder,
2908 'EXECUTABLE_NAME': install4jExecutableName,
2909 'EXTRA_SCHEME': install4jExtraScheme,
2910 'MAC_ICONS_FILE': install4jMacIconsFile,
2911 'WINDOWS_ICONS_FILE': install4jWindowsIconsFile,
2912 'PNG_ICON_FILE': install4jPngIconFile,
2913 'BACKGROUND': install4jBackground,
2918 'windows': 'WINDOWS',
2922 // these are the bundled OS/architecture VMs needed by install4j
2925 [ "mac", "aarch64" ],
2926 [ "windows", "x64" ],
2928 [ "linux", "aarch64" ]
2930 osArch.forEach { os, arch ->
2931 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)
2932 // N.B. For some reason install4j requires the below filename to have underscores and not hyphens
2933 // otherwise running `gradle installers` generates a non-useful error:
2934 // `install4j: compilation failed. Reason: java.lang.NumberFormatException: For input string: "windows"`
2935 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)
2938 //println("INSTALL4J VARIABLES:")
2939 //variables.each{k,v->println("${k}=${v}")}
2941 destination = "${jalviewDir}/${install4jBuildDir}"
2942 buildSelected = true
2944 if (install4j_faster.equals("true") || CHANNEL.startsWith("LOCAL")) {
2946 disableSigning = true
2947 disableNotarization = true
2951 macKeystorePassword = OSX_KEYPASS
2954 if (OSX_ALTOOLPASS) {
2955 appleIdPassword = OSX_ALTOOLPASS
2956 disableNotarization = false
2958 disableNotarization = true
2962 println("Using projectFile "+projectFile)
2963 if (!disableNotarization) { println("Will notarize OSX App DMG") }
2967 inputs.dir(getdownAppBaseDir)
2968 inputs.file(install4jConfFile)
2969 inputs.file("${install4jDir}/${install4j_info_plist_file_associations}")
2970 outputs.dir("${jalviewDir}/${install4j_build_dir}/${JAVA_VERSION}")
2973 def getDataHash(File myFile) {
2974 HashCode hash = Files.asByteSource(myFile).hash(Hashing.sha256())
2975 return myFile.exists()
2977 "file" : myFile.getName(),
2978 "filesize" : myFile.length(),
2979 "sha256" : hash.toString()
2984 def writeDataJsonFile(File installersOutputTxt, File installersSha256, File dataJsonFile) {
2986 "channel" : getdownChannelName,
2987 "date" : getDate("yyyy-MM-dd HH:mm:ss"),
2988 "git-commit" : "${gitHash} [${gitBranch}]",
2989 "version" : JALVIEW_VERSION
2991 // install4j installer files
2992 if (installersOutputTxt.exists()) {
2994 installersOutputTxt.readLines().each { def line ->
2995 if (line.startsWith("#")) {
2998 line.replaceAll("\n","")
2999 def vals = line.split("\t")
3000 def filename = vals[3]
3001 def filesize = file(filename).length()
3002 filename = filename.replaceAll(/^.*\//, "")
3003 hash[vals[0]] = [ "id" : vals[0], "os" : vals[1], "name" : vals[2], "file" : filename, "filesize" : filesize ]
3004 idHash."${filename}" = vals[0]
3006 if (install4jCheckSums && installersSha256.exists()) {
3007 installersSha256.readLines().each { def line ->
3008 if (line.startsWith("#")) {
3011 line.replaceAll("\n","")
3012 def vals = line.split(/\s+\*?/)
3013 def filename = vals[1]
3014 def innerHash = (hash.(idHash."${filename}"))."sha256" = vals[0]
3020 "JAR": shadowJar.archiveFile, // executable JAR
3021 "JVL": getdownVersionLaunchJvl, // version JVL
3022 "SOURCE": sourceDist.archiveFile // source TGZ
3023 ].each { key, value ->
3024 def file = file(value)
3025 if (file.exists()) {
3026 def fileHash = getDataHash(file)
3027 if (fileHash != null) {
3028 hash."${key}" = fileHash;
3032 return dataJsonFile.write(new JsonBuilder(hash).toPrettyString())
3035 task staticMakeInstallersJsonFile {
3037 def output = findProperty("i4j_output")
3038 def sha256 = findProperty("i4j_sha256")
3039 def json = findProperty("i4j_json")
3040 if (output == null || sha256 == null || json == null) {
3041 throw new GradleException("Must provide paths to all of output.txt, sha256sums, and output.json with '-Pi4j_output=... -Pi4j_sha256=... -Pi4j_json=...")
3043 writeDataJsonFile(file(output), file(sha256), file(json))
3048 dependsOn installerFiles
3054 eclipse().configFile(eclipse_codestyle_file)
3058 task createSourceReleaseProperties(type: WriteProperties) {
3059 group = "distribution"
3060 description = "Create the source RELEASE properties file"
3062 def sourceTarBuildDir = "${buildDir}/sourceTar"
3063 def sourceReleasePropertiesFile = "${sourceTarBuildDir}/RELEASE"
3064 outputFile (sourceReleasePropertiesFile)
3067 releaseProps.each{ key, val -> property key, val }
3068 property "git.branch", gitBranch
3069 property "git.hash", gitHash
3072 outputs.file(outputFile)
3075 task sourceDist(type: Tar) {
3076 group "distribution"
3077 description "Create a source .tar.gz file for distribution"
3079 dependsOn createBuildProperties
3080 dependsOn convertMdFiles
3081 dependsOn eclipseAllPreferences
3082 dependsOn createSourceReleaseProperties
3085 def outputFileName = "${project.name}_${JALVIEW_VERSION_UNDERSCORES}.tar.gz"
3086 archiveFileName = outputFileName
3088 compression Compression.GZIP
3104 "**/*.class","$j11modDir/**/*.jar","appletlib","**/*locales",
3106 "utils/InstallAnywhere",
3121 "gradle.properties",
3133 ".settings/org.eclipse.buildship.core.prefs",
3134 ".settings/org.eclipse.jdt.core.prefs"
3138 exclude (EXCLUDE_FILES)
3139 include (PROCESS_FILES)
3140 filter(ReplaceTokens,
3144 'Version-Rel': JALVIEW_VERSION,
3145 'Year-Rel': getDate("yyyy")
3150 exclude (EXCLUDE_FILES)
3151 exclude (PROCESS_FILES)
3152 exclude ("appletlib")
3153 exclude ("**/*locales")
3154 exclude ("*locales/**")
3155 exclude ("utils/InstallAnywhere")
3157 exclude (getdown_files_dir)
3158 // getdown_website_dir and getdown_archive_dir moved to build/website/docroot/getdown
3159 //exclude (getdown_website_dir)
3160 //exclude (getdown_archive_dir)
3162 // exluding these as not using jars as modules yet
3163 exclude ("${j11modDir}/**/*.jar")
3166 include(INCLUDE_FILES)
3168 // from (jalviewDir) {
3169 // // explicit includes for stuff that seemed to not get included
3170 // include(fileTree("test/**/*."))
3171 // exclude(EXCLUDE_FILES)
3172 // exclude(PROCESS_FILES)
3175 from(file(buildProperties).getParent()) {
3176 include(file(buildProperties).getName())
3177 rename(file(buildProperties).getName(), "build_properties")
3179 line.replaceAll("^INSTALLATION=.*\$","INSTALLATION=Source Release"+" git-commit\\\\:"+gitHash+" ["+gitBranch+"]")
3183 def sourceTarBuildDir = "${buildDir}/sourceTar"
3184 from(sourceTarBuildDir) {
3185 // this includes the appended RELEASE properties file
3189 task dataInstallersJson {
3191 description "Create the installers-VERSION.json data file for installer files created"
3193 mustRunAfter installers
3194 mustRunAfter shadowJar
3195 mustRunAfter sourceDist
3196 mustRunAfter getdownArchive
3198 def installersOutputTxt = file("${jalviewDir}/${install4jBuildDir}/output.txt")
3199 def installersSha256 = file("${jalviewDir}/${install4jBuildDir}/sha256sums")
3201 if (installersOutputTxt.exists()) {
3202 inputs.file(installersOutputTxt)
3204 if (install4jCheckSums && installersSha256.exists()) {
3205 inputs.file(installersSha256)
3208 shadowJar.archiveFile, // executable JAR
3209 getdownVersionLaunchJvl, // version JVL
3210 sourceDist.archiveFile // source TGZ
3211 ].each { fileName ->
3212 if (file(fileName).exists()) {
3213 inputs.file(fileName)
3217 outputs.file(hugoDataJsonFile)
3220 writeDataJsonFile(installersOutputTxt, installersSha256, hugoDataJsonFile)
3226 description "Copies all help pages to build dir. Runs ant task 'pubhtmlhelp'."
3229 dependsOn pubhtmlhelp
3231 inputs.dir("${helpBuildDir}/${help_dir}")
3232 outputs.dir("${buildDir}/distributions/${help_dir}")
3236 task j2sSetHeadlessBuild {
3243 task jalviewjsEnableAltFileProperty(type: WriteProperties) {
3245 description "Enable the alternative J2S Config file for headless build"
3247 outputFile = jalviewjsJ2sSettingsFileName
3248 def j2sPropsFile = file(jalviewjsJ2sSettingsFileName)
3249 def j2sProps = new Properties()
3250 if (j2sPropsFile.exists()) {
3252 def j2sPropsFileFIS = new FileInputStream(j2sPropsFile)
3253 j2sProps.load(j2sPropsFileFIS)
3254 j2sPropsFileFIS.close()
3256 j2sProps.each { prop, val ->
3259 } catch (Exception e) {
3260 println("Exception reading ${jalviewjsJ2sSettingsFileName}")
3264 if (! j2sProps.stringPropertyNames().contains(jalviewjs_j2s_alt_file_property_config)) {
3265 property(jalviewjs_j2s_alt_file_property_config, jalviewjs_j2s_alt_file_property)
3270 task jalviewjsSetEclipseWorkspace {
3271 def propKey = "jalviewjs_eclipse_workspace"
3273 if (project.hasProperty(propKey)) {
3274 propVal = project.getProperty(propKey)
3275 if (propVal.startsWith("~/")) {
3276 propVal = System.getProperty("user.home") + propVal.substring(1)
3279 def propsFileName = "${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_eclipse_workspace_location_file}"
3280 def propsFile = file(propsFileName)
3281 def eclipseWsDir = propVal
3282 def props = new Properties()
3284 def writeProps = true
3285 if (( eclipseWsDir == null || !file(eclipseWsDir).exists() ) && propsFile.exists()) {
3286 def ins = new FileInputStream(propsFileName)
3289 if (props.getProperty(propKey, null) != null) {
3290 eclipseWsDir = props.getProperty(propKey)
3295 if (eclipseWsDir == null || !file(eclipseWsDir).exists()) {
3296 def tempDir = File.createTempDir()
3297 eclipseWsDir = tempDir.getAbsolutePath()
3300 eclipseWorkspace = file(eclipseWsDir)
3303 // do not run a headless transpile when we claim to be in Eclipse
3305 println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3306 throw new StopExecutionException("Not running headless transpile whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
3308 println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3312 props.setProperty(propKey, eclipseWsDir)
3313 propsFile.parentFile.mkdirs()
3314 def bytes = new ByteArrayOutputStream()
3315 props.store(bytes, null)
3316 def propertiesString = bytes.toString()
3317 propsFile.text = propertiesString
3323 println("ECLIPSE WORKSPACE: "+eclipseWorkspace.getPath())
3326 //inputs.property(propKey, eclipseWsDir) // eclipseWsDir only gets set once this task runs, so will be out-of-date
3327 outputs.file(propsFileName)
3328 outputs.upToDateWhen { eclipseWorkspace.exists() && propsFile.exists() }
3332 task jalviewjsEclipsePaths {
3335 def eclipseRoot = jalviewjs_eclipse_root
3336 if (eclipseRoot.startsWith("~/")) {
3337 eclipseRoot = System.getProperty("user.home") + eclipseRoot.substring(1)
3339 if (OperatingSystem.current().isMacOsX()) {
3340 eclipseRoot += "/Eclipse.app"
3341 eclipseBinary = "${eclipseRoot}/Contents/MacOS/eclipse"
3342 eclipseProduct = "${eclipseRoot}/Contents/Eclipse/.eclipseproduct"
3343 } else if (OperatingSystem.current().isWindows()) { // check these paths!!
3344 if (file("${eclipseRoot}/eclipse").isDirectory() && file("${eclipseRoot}/eclipse/.eclipseproduct").exists()) {
3345 eclipseRoot += "/eclipse"
3347 eclipseBinary = "${eclipseRoot}/eclipse.exe"
3348 eclipseProduct = "${eclipseRoot}/.eclipseproduct"
3349 } else { // linux or unix
3350 if (file("${eclipseRoot}/eclipse").isDirectory() && file("${eclipseRoot}/eclipse/.eclipseproduct").exists()) {
3351 eclipseRoot += "/eclipse"
3352 println("eclipseDir exists")
3354 eclipseBinary = "${eclipseRoot}/eclipse"
3355 eclipseProduct = "${eclipseRoot}/.eclipseproduct"
3358 eclipseVersion = "4.13" // default
3359 def assumedVersion = true
3360 if (file(eclipseProduct).exists()) {
3361 def fis = new FileInputStream(eclipseProduct)
3362 def props = new Properties()
3364 eclipseVersion = props.getProperty("version")
3366 assumedVersion = false
3369 def propKey = "eclipse_debug"
3370 eclipseDebug = (project.hasProperty(propKey) && project.getProperty(propKey).equals("true"))
3373 // do not run a headless transpile when we claim to be in Eclipse
3375 println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3376 throw new StopExecutionException("Not running headless transpile whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
3378 println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3381 if (!assumedVersion) {
3382 println("ECLIPSE VERSION=${eclipseVersion}")
3388 task printProperties {
3390 description "Output to console all System.properties"
3392 System.properties.each { key, val -> System.out.println("Property: ${key}=${val}") }
3398 dependsOn eclipseProject
3399 dependsOn eclipseClasspath
3400 dependsOn eclipseJdt
3404 // this version (type: Copy) will delete anything in the eclipse dropins folder that isn't in fromDropinsDir
3405 task jalviewjsEclipseCopyDropins(type: Copy) {
3406 dependsOn jalviewjsEclipsePaths
3408 def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjs_eclipse_dropins_dir}", include: "*.jar")
3409 inputFiles += file("${jalviewDir}/${jalviewjsJ2sPlugin}")
3410 def destinationDirectory = "${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_eclipse_tmp_dropins_dir}"
3413 into destinationDirectory
3417 // this eclipse -clean doesn't actually work
3418 task jalviewjsCleanEclipse(type: Exec) {
3419 dependsOn eclipseSetup
3420 dependsOn jalviewjsEclipsePaths
3421 dependsOn jalviewjsEclipseCopyDropins
3423 executable(eclipseBinary)
3424 args(["-nosplash", "--launcher.suppressErrors", "-data", eclipseWorkspace.getPath(), "-clean", "-console", "-consoleLog"])
3430 def inputString = """exit
3433 def inputByteStream = new ByteArrayInputStream(inputString.getBytes())
3434 standardInput = inputByteStream
3437 /* not really working yet
3438 jalviewjsEclipseCopyDropins.finalizedBy jalviewjsCleanEclipse
3442 task jalviewjsTransferUnzipSwingJs {
3443 def file_zip = "${jalviewDir}/${jalviewjs_swingjs_zip}"
3447 from zipTree(file_zip)
3448 into "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}"
3452 inputs.file file_zip
3453 outputs.dir "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}"
3457 task jalviewjsTransferUnzipLib {
3458 def zipFiles = fileTree(dir: "${jalviewDir}/${jalviewjs_libjs_dir}", include: "*.zip")
3461 zipFiles.each { file_zip ->
3463 from zipTree(file_zip)
3464 into "${jalviewDir}/${jalviewjsTransferSiteLibDir}"
3469 inputs.files zipFiles
3470 outputs.dir "${jalviewDir}/${jalviewjsTransferSiteLibDir}"
3474 task jalviewjsTransferUnzipAllLibs {
3475 dependsOn jalviewjsTransferUnzipSwingJs
3476 dependsOn jalviewjsTransferUnzipLib
3480 task jalviewjsCreateJ2sSettings(type: WriteProperties) {
3482 description "Create the alternative j2s file from the j2s.* properties"
3484 jalviewjsJ2sProps = project.properties.findAll { it.key.startsWith("j2s.") }.sort { it.key }
3485 def siteDirProperty = "j2s.site.directory"
3486 def setSiteDir = false
3487 jalviewjsJ2sProps.each { prop, val ->
3489 if (prop == siteDirProperty) {
3490 if (!(val.startsWith('/') || val.startsWith("file://") )) {
3491 val = "${jalviewDir}/${jalviewjsTransferSiteJsDir}/${val}"
3497 if (!setSiteDir) { // default site location, don't override specifically set property
3498 property(siteDirProperty,"${jalviewDirRelativePath}/${jalviewjsTransferSiteJsDir}")
3501 outputFile = jalviewjsJ2sAltSettingsFileName
3504 inputs.properties(jalviewjsJ2sProps)
3505 outputs.file(jalviewjsJ2sAltSettingsFileName)
3510 task jalviewjsEclipseSetup {
3511 dependsOn jalviewjsEclipseCopyDropins
3512 dependsOn jalviewjsSetEclipseWorkspace
3513 dependsOn jalviewjsCreateJ2sSettings
3517 task jalviewjsSyncAllLibs (type: Sync) {
3518 dependsOn jalviewjsTransferUnzipAllLibs
3519 def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjsTransferSiteLibDir}")
3520 inputFiles += fileTree(dir: "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}")
3521 def destinationDirectory = "${jalviewDir}/${jalviewjsSiteDir}"
3524 into destinationDirectory
3525 def outputFiles = []
3526 rename { filename ->
3527 outputFiles += "${destinationDirectory}/${filename}"
3534 // should this be exclude really ?
3535 duplicatesStrategy "INCLUDE"
3537 outputs.files outputFiles
3538 inputs.files inputFiles
3542 task jalviewjsSyncResources (type: Sync) {
3543 dependsOn buildResources
3545 def inputFiles = fileTree(dir: resourcesBuildDir)
3546 def destinationDirectory = "${jalviewDir}/${jalviewjsSiteDir}/${jalviewjs_j2s_subdir}"
3549 into destinationDirectory
3550 def outputFiles = []
3551 rename { filename ->
3552 outputFiles += "${destinationDirectory}/${filename}"
3558 outputs.files outputFiles
3559 inputs.files inputFiles
3563 task jalviewjsSyncSiteResources (type: Sync) {
3564 def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjs_site_resource_dir}")
3565 def destinationDirectory = "${jalviewDir}/${jalviewjsSiteDir}"
3568 into destinationDirectory
3569 def outputFiles = []
3570 rename { filename ->
3571 outputFiles += "${destinationDirectory}/${filename}"
3577 outputs.files outputFiles
3578 inputs.files inputFiles
3582 task jalviewjsSyncBuildProperties (type: Sync) {
3583 dependsOn createBuildProperties
3584 def inputFiles = [file(buildProperties)]
3585 def destinationDirectory = "${jalviewDir}/${jalviewjsSiteDir}/${jalviewjs_j2s_subdir}"
3588 into destinationDirectory
3589 def outputFiles = []
3590 rename { filename ->
3591 outputFiles += "${destinationDirectory}/${filename}"
3597 outputs.files outputFiles
3598 inputs.files inputFiles
3602 task jalviewjsProjectImport(type: Exec) {
3603 dependsOn eclipseSetup
3604 dependsOn jalviewjsEclipsePaths
3605 dependsOn jalviewjsEclipseSetup
3608 // do not run a headless import when we claim to be in Eclipse
3610 println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3611 throw new StopExecutionException("Not running headless import whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
3613 println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3617 //def projdir = eclipseWorkspace.getPath()+"/.metadata/.plugins/org.eclipse.core.resources/.projects/jalview/org.eclipse.jdt.core"
3618 def projdir = eclipseWorkspace.getPath()+"/.metadata/.plugins/org.eclipse.core.resources/.projects/jalview"
3619 executable(eclipseBinary)
3620 args(["-nosplash", "--launcher.suppressErrors", "-application", "com.seeq.eclipse.importprojects.headlessimport", "-data", eclipseWorkspace.getPath(), "-import", jalviewDirAbsolutePath])
3624 args += [ "--launcher.appendVmargs", "-vmargs", "-Dorg.eclipse.equinox.p2.reconciler.dropins.directory=${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_eclipse_tmp_dropins_dir}" ]
3626 args += [ "-D${j2sHeadlessBuildProperty}=true" ]
3627 args += [ "-D${jalviewjs_j2s_alt_file_property}=${jalviewjsJ2sAltSettingsFileName}" ]
3630 inputs.file("${jalviewDir}/.project")
3631 outputs.upToDateWhen {
3632 file(projdir).exists()
3637 task jalviewjsTranspile(type: Exec) {
3638 dependsOn jalviewjsEclipseSetup
3639 dependsOn jalviewjsProjectImport
3640 dependsOn jalviewjsEclipsePaths
3642 dependsOn jalviewjsEnableAltFileProperty
3646 // do not run a headless transpile when we claim to be in Eclipse
3648 println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3649 throw new StopExecutionException("Not running headless transpile whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
3651 println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3655 executable(eclipseBinary)
3656 args(["-nosplash", "--launcher.suppressErrors", "-application", "org.eclipse.jdt.apt.core.aptBuild", "-data", eclipseWorkspace, "-${jalviewjs_eclipse_build_arg}", eclipse_project_name ])
3660 args += [ "--launcher.appendVmargs", "-vmargs", "-Dorg.eclipse.equinox.p2.reconciler.dropins.directory=${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_eclipse_tmp_dropins_dir}" ]
3662 args += [ "-D${j2sHeadlessBuildProperty}=true" ]
3663 args += [ "-D${jalviewjs_j2s_alt_file_property}=${jalviewjsJ2sAltSettingsFileName}" ]
3669 stdout = new ByteArrayOutputStream()
3670 stderr = new ByteArrayOutputStream()
3672 def logOutFileName = "${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}"
3673 def logOutFile = file(logOutFileName)
3674 logOutFile.createNewFile()
3675 logOutFile.text = """ROOT: ${jalviewjs_eclipse_root}
3676 BINARY: ${eclipseBinary}
3677 VERSION: ${eclipseVersion}
3678 WORKSPACE: ${eclipseWorkspace}
3679 DEBUG: ${eclipseDebug}
3682 def logOutFOS = new FileOutputStream(logOutFile, true) // true == append
3683 // combine stdout and stderr
3684 def logErrFOS = logOutFOS
3686 if (jalviewjs_j2s_to_console.equals("true")) {
3687 standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
3688 new org.apache.tools.ant.util.TeeOutputStream(
3692 errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
3693 new org.apache.tools.ant.util.TeeOutputStream(
3698 standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
3701 errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
3708 if (stdout.toString().contains("Error processing ")) {
3709 // j2s did not complete transpile
3710 //throw new TaskExecutionException("Error during transpilation:\n${stderr}\nSee eclipse transpile log file '${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}'")
3711 if (jalviewjs_ignore_transpile_errors.equals("true")) {
3712 println("IGNORING TRANSPILE ERRORS")
3713 println("See eclipse transpile log file '${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}'")
3715 throw new GradleException("Error during transpilation:\n${stderr}\nSee eclipse transpile log file '${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}'")
3720 inputs.dir("${jalviewDir}/${sourceDir}")
3721 outputs.dir("${jalviewDir}/${jalviewjsTransferSiteJsDir}")
3722 outputs.upToDateWhen( { file("${jalviewDir}/${jalviewjsTransferSiteJsDir}${jalviewjs_server_resource}").exists() } )
3726 def jalviewjsCallCore(String name, FileCollection list, String prefixFile, String suffixFile, String jsfile, String zjsfile, File logOutFile, Boolean logOutConsole) {
3728 def stdout = new ByteArrayOutputStream()
3729 def stderr = new ByteArrayOutputStream()
3731 def coreFile = file(jsfile)
3733 msg = "Creating core for ${name}...\nGenerating ${jsfile}"
3735 logOutFile.createNewFile()
3736 logOutFile.append(msg+"\n")
3738 def coreTop = file(prefixFile)
3739 def coreBottom = file(suffixFile)
3740 coreFile.getParentFile().mkdirs()
3741 coreFile.createNewFile()
3742 coreFile.write( coreTop.getText("UTF-8") )
3746 def t = f.getText("UTF-8")
3747 t.replaceAll("Clazz\\.([^_])","Clazz_${1}")
3748 coreFile.append( t )
3750 msg = "...file '"+f.getPath()+"' does not exist, skipping"
3752 logOutFile.append(msg+"\n")
3755 coreFile.append( coreBottom.getText("UTF-8") )
3757 msg = "Generating ${zjsfile}"
3759 logOutFile.append(msg+"\n")
3760 def logOutFOS = new FileOutputStream(logOutFile, true) // true == append
3761 def logErrFOS = logOutFOS
3764 classpath = files(["${jalviewDir}/${jalviewjs_closure_compiler}"])
3765 main = "com.google.javascript.jscomp.CommandLineRunner"
3766 jvmArgs = [ "-Dfile.encoding=UTF-8" ]
3767 args = [ "--compilation_level", "SIMPLE_OPTIMIZATIONS", "--warning_level", "QUIET", "--charset", "UTF-8", "--js", jsfile, "--js_output_file", zjsfile ]
3770 msg = "\nRunning '"+commandLine.join(' ')+"'\n"
3772 logOutFile.append(msg+"\n")
3774 if (logOutConsole) {
3775 standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
3776 new org.apache.tools.ant.util.TeeOutputStream(
3780 errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
3781 new org.apache.tools.ant.util.TeeOutputStream(
3786 standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
3789 errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
3796 logOutFile.append(msg+"\n")
3800 task jalviewjsBuildAllCores {
3802 description "Build the core js lib closures listed in the classlists dir"
3803 dependsOn jalviewjsTranspile
3804 dependsOn jalviewjsTransferUnzipSwingJs
3806 def j2sDir = "${jalviewDir}/${jalviewjsTransferSiteJsDir}/${jalviewjs_j2s_subdir}"
3807 def swingJ2sDir = "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}/${jalviewjs_j2s_subdir}"
3808 def libJ2sDir = "${jalviewDir}/${jalviewjsTransferSiteLibDir}/${jalviewjs_j2s_subdir}"
3809 def jsDir = "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}/${jalviewjs_js_subdir}"
3810 def destinationDirectory = "${jalviewDir}/${jalviewjsTransferSiteCoreDir}/${jalviewjs_j2s_subdir}/core"
3811 def prefixFile = "${jsDir}/core/coretop2.js"
3812 def suffixFile = "${jsDir}/core/corebottom2.js"
3814 inputs.file prefixFile
3815 inputs.file suffixFile
3817 def classlistFiles = []
3818 // add the classlists found int the jalviewjs_classlists_dir
3819 fileTree(dir: "${jalviewDir}/${jalviewjs_classlists_dir}", include: "*.txt").each {
3821 def name = file.getName() - ".txt"
3828 // _jmol and _jalview cores. Add any other peculiar classlist.txt files here
3829 //classlistFiles += [ 'file': file("${jalviewDir}/${jalviewjs_classlist_jmol}"), 'name': "_jvjmol" ]
3830 classlistFiles += [ 'file': file("${jalviewDir}/${jalviewjs_classlist_jalview}"), 'name': jalviewjsJalviewCoreName ]
3832 jalviewjsCoreClasslists = []
3834 classlistFiles.each {
3837 def file = hash['file']
3838 if (! file.exists()) {
3839 //println("...classlist file '"+file.getPath()+"' does not exist, skipping")
3840 return false // this is a "continue" in groovy .each closure
3842 def name = hash['name']
3844 name = file.getName() - ".txt"
3852 def list = fileTree(dir: j2sDir, includes: filelist)
3854 def jsfile = "${destinationDirectory}/core${name}.js"
3855 def zjsfile = "${destinationDirectory}/core${name}.z.js"
3857 jalviewjsCoreClasslists += [
3866 outputs.file(jsfile)
3867 outputs.file(zjsfile)
3870 // _stevesoft core. add any cores without a classlist here (and the inputs and outputs)
3871 def stevesoftClasslistName = "_stevesoft"
3872 def stevesoftClasslist = [
3873 'jsfile': "${destinationDirectory}/core${stevesoftClasslistName}.js",
3874 'zjsfile': "${destinationDirectory}/core${stevesoftClasslistName}.z.js",
3875 'list': fileTree(dir: j2sDir, include: "com/stevesoft/pat/**/*.js"),
3876 'name': stevesoftClasslistName
3878 jalviewjsCoreClasslists += stevesoftClasslist
3879 inputs.files(stevesoftClasslist['list'])
3880 outputs.file(stevesoftClasslist['jsfile'])
3881 outputs.file(stevesoftClasslist['zjsfile'])
3884 def allClasslistName = "_all"
3885 def allJsFiles = fileTree(dir: j2sDir, include: "**/*.js")
3886 allJsFiles += fileTree(
3890 // these exlusions are files that the closure-compiler produces errors for. Should fix them
3891 "**/org/jmol/jvxl/readers/IsoIntersectFileReader.js",
3892 "**/org/jmol/export/JSExporter.js"
3895 allJsFiles += fileTree(
3899 // these exlusions are files that the closure-compiler produces errors for. Should fix them
3900 "**/sun/misc/Unsafe.js",
3901 "**/swingjs/jquery/jquery-editable-select.js",
3902 "**/swingjs/jquery/j2sComboBox.js",
3903 "**/sun/misc/FloatingDecimal.js"
3906 def allClasslist = [
3907 'jsfile': "${destinationDirectory}/core${allClasslistName}.js",
3908 'zjsfile': "${destinationDirectory}/core${allClasslistName}.z.js",
3910 'name': allClasslistName
3912 // not including this version of "all" core at the moment
3913 //jalviewjsCoreClasslists += allClasslist
3914 inputs.files(allClasslist['list'])
3915 outputs.file(allClasslist['jsfile'])
3916 outputs.file(allClasslist['zjsfile'])
3919 def logOutFile = file("${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_j2s_closure_stdout}")
3920 logOutFile.getParentFile().mkdirs()
3921 logOutFile.createNewFile()
3922 logOutFile.write(getDate("yyyy-MM-dd HH:mm:ss")+" jalviewjsBuildAllCores\n----\n")
3924 jalviewjsCoreClasslists.each {
3925 jalviewjsCallCore(it.name, it.list, prefixFile, suffixFile, it.jsfile, it.zjsfile, logOutFile, jalviewjs_j2s_to_console.equals("true"))
3932 def jalviewjsPublishCoreTemplate(String coreName, String templateName, File inputFile, String outputFile) {
3935 into file(outputFile).getParentFile()
3936 rename { filename ->
3937 if (filename.equals(inputFile.getName())) {
3938 return file(outputFile).getName()
3942 filter(ReplaceTokens,
3946 'MAIN': '"'+main_class+'"',
3948 'NAME': jalviewjsJalviewTemplateName+" [core ${coreName}]",
3949 'COREKEY': jalviewjs_core_key,
3950 'CORENAME': coreName
3957 task jalviewjsPublishCoreTemplates {
3958 dependsOn jalviewjsBuildAllCores
3959 def inputFileName = "${jalviewDir}/${j2s_coretemplate_html}"
3960 def inputFile = file(inputFileName)
3961 def destinationDirectory = "${jalviewDir}/${jalviewjsTransferSiteCoreDir}"
3963 def outputFiles = []
3964 jalviewjsCoreClasslists.each { cl ->
3965 def outputFile = "${destinationDirectory}/${jalviewjsJalviewTemplateName}_${cl.name}.html"
3966 cl['outputfile'] = outputFile
3967 outputFiles += outputFile
3971 jalviewjsCoreClasslists.each { cl ->
3972 jalviewjsPublishCoreTemplate(cl.name, jalviewjsJalviewTemplateName, inputFile, cl.outputfile)
3975 inputs.file(inputFile)
3976 outputs.files(outputFiles)
3980 task jalviewjsSyncCore (type: Sync) {
3981 dependsOn jalviewjsBuildAllCores
3982 dependsOn jalviewjsPublishCoreTemplates
3983 def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjsTransferSiteCoreDir}")
3984 def destinationDirectory = "${jalviewDir}/${jalviewjsSiteDir}"
3987 into destinationDirectory
3988 def outputFiles = []
3989 rename { filename ->
3990 outputFiles += "${destinationDirectory}/${filename}"
3996 outputs.files outputFiles
3997 inputs.files inputFiles
4001 // this Copy version of TransferSiteJs will delete anything else in the target dir
4002 task jalviewjsCopyTransferSiteJs(type: Copy) {
4003 dependsOn jalviewjsTranspile
4004 from "${jalviewDir}/${jalviewjsTransferSiteJsDir}"
4005 into "${jalviewDir}/${jalviewjsSiteDir}"
4009 // this Sync version of TransferSite is used by buildship to keep the website automatically up to date when a file changes
4010 task jalviewjsSyncTransferSiteJs(type: Sync) {
4011 from "${jalviewDir}/${jalviewjsTransferSiteJsDir}"
4013 into "${jalviewDir}/${jalviewjsSiteDir}"
4020 jalviewjsSyncAllLibs.mustRunAfter jalviewjsCopyTransferSiteJs
4021 jalviewjsSyncResources.mustRunAfter jalviewjsCopyTransferSiteJs
4022 jalviewjsSyncSiteResources.mustRunAfter jalviewjsCopyTransferSiteJs
4023 jalviewjsSyncBuildProperties.mustRunAfter jalviewjsCopyTransferSiteJs
4025 jalviewjsSyncAllLibs.mustRunAfter jalviewjsSyncTransferSiteJs
4026 jalviewjsSyncResources.mustRunAfter jalviewjsSyncTransferSiteJs
4027 jalviewjsSyncSiteResources.mustRunAfter jalviewjsSyncTransferSiteJs
4028 jalviewjsSyncBuildProperties.mustRunAfter jalviewjsSyncTransferSiteJs
4031 task jalviewjsPrepareSite {
4033 description "Prepares the website folder including unzipping files and copying resources"
4034 dependsOn jalviewjsSyncAllLibs
4035 dependsOn jalviewjsSyncResources
4036 dependsOn jalviewjsSyncSiteResources
4037 dependsOn jalviewjsSyncBuildProperties
4038 dependsOn jalviewjsSyncCore
4042 task jalviewjsBuildSite {
4044 description "Builds the whole website including transpiled code"
4045 dependsOn jalviewjsCopyTransferSiteJs
4046 dependsOn jalviewjsPrepareSite
4050 task cleanJalviewjsTransferSite {
4052 delete "${jalviewDir}/${jalviewjsTransferSiteJsDir}"
4053 delete "${jalviewDir}/${jalviewjsTransferSiteLibDir}"
4054 delete "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}"
4055 delete "${jalviewDir}/${jalviewjsTransferSiteCoreDir}"
4060 task cleanJalviewjsSite {
4061 dependsOn cleanJalviewjsTransferSite
4063 delete "${jalviewDir}/${jalviewjsSiteDir}"
4068 task jalviewjsSiteTar(type: Tar) {
4070 description "Creates a tar.gz file for the website"
4071 dependsOn jalviewjsBuildSite
4072 def outputFilename = "jalviewjs-site-${JALVIEW_VERSION}.tar.gz"
4073 archiveFileName = outputFilename
4075 compression Compression.GZIP
4077 from "${jalviewDir}/${jalviewjsSiteDir}"
4078 into jalviewjs_site_dir // this is inside the tar file
4080 inputs.dir("${jalviewDir}/${jalviewjsSiteDir}")
4084 task jalviewjsServer {
4086 def filename = "jalviewjsTest.html"
4087 description "Starts a webserver on localhost to test the website. See ${filename} to access local site on most recently used port."
4088 def htmlFile = "${jalviewDirAbsolutePath}/${filename}"
4093 def f = Class.forName("org.gradle.plugins.javascript.envjs.http.simple.SimpleHttpFileServerFactory")
4094 factory = f.newInstance()
4095 } catch (ClassNotFoundException e) {
4096 throw new GradleException("Unable to create SimpleHttpFileServerFactory")
4098 def port = Integer.valueOf(jalviewjs_server_port)
4103 while(port < start+1000 && !running) {
4105 def doc_root = new File("${jalviewDirAbsolutePath}/${jalviewjsSiteDir}")
4106 jalviewjsServer = factory.start(doc_root, port)
4108 url = jalviewjsServer.getResourceUrl(jalviewjs_server_resource)
4109 println("SERVER STARTED with document root ${doc_root}.")
4110 println("Go to "+url+" . Run gradle --stop to stop (kills all gradle daemons).")
4111 println("For debug: "+url+"?j2sdebug")
4112 println("For verbose: "+url+"?j2sverbose")
4113 } catch (Exception e) {
4118 <p><a href="${url}">JalviewJS Test. <${url}></a></p>
4119 <p><a href="${url}?j2sdebug">JalviewJS Test with debug. <${url}?j2sdebug></a></p>
4120 <p><a href="${url}?j2sverbose">JalviewJS Test with verbose. <${url}?j2sdebug></a></p>
4122 jalviewjsCoreClasslists.each { cl ->
4123 def urlcore = jalviewjsServer.getResourceUrl(file(cl.outputfile).getName())
4125 <p><a href="${urlcore}">${jalviewjsJalviewTemplateName} [core ${cl.name}]. <${urlcore}></a></p>
4127 println("For core ${cl.name}: "+urlcore)
4130 file(htmlFile).text = htmlText
4133 outputs.file(htmlFile)
4134 outputs.upToDateWhen({false})
4138 task cleanJalviewjsAll {
4140 description "Delete all configuration and build artifacts to do with JalviewJS build"
4141 dependsOn cleanJalviewjsSite
4142 dependsOn jalviewjsEclipsePaths
4145 delete "${jalviewDir}/${jalviewjsBuildDir}"
4146 delete "${jalviewDir}/${eclipse_bin_dir}"
4147 if (eclipseWorkspace != null && file(eclipseWorkspace.getAbsolutePath()+"/.metadata").exists()) {
4148 delete file(eclipseWorkspace.getAbsolutePath()+"/.metadata")
4150 delete jalviewjsJ2sAltSettingsFileName
4153 outputs.upToDateWhen( { false } )
4157 task jalviewjsIDE_checkJ2sPlugin {
4158 group "00 JalviewJS in Eclipse"
4159 description "Compare the swingjs/net.sf.j2s.core(-j11)?.jar file with the Eclipse IDE's plugin version (found in the 'dropins' dir)"
4162 def j2sPlugin = string("${jalviewDir}/${jalviewjsJ2sPlugin}")
4163 def j2sPluginFile = file(j2sPlugin)
4164 def eclipseHome = System.properties["eclipse.home.location"]
4165 if (eclipseHome == null || ! IN_ECLIPSE) {
4166 throw new StopExecutionException("Cannot find running Eclipse home from System.properties['eclipse.home.location']. Skipping J2S Plugin Check.")
4168 def eclipseJ2sPluginDirs = [ "${eclipseHome}/dropins" ]
4169 def altPluginsDir = System.properties["org.eclipse.equinox.p2.reconciler.dropins.directory"]
4170 if (altPluginsDir != null && file(altPluginsDir).exists()) {
4171 eclipseJ2sPluginDirs += altPluginsDir
4173 def foundPlugin = false
4174 def j2sPluginFileName = j2sPluginFile.getName()
4175 def eclipseJ2sPlugin
4176 def eclipseJ2sPluginFile
4177 eclipseJ2sPluginDirs.any { dir ->
4178 eclipseJ2sPlugin = "${dir}/${j2sPluginFileName}"
4179 eclipseJ2sPluginFile = file(eclipseJ2sPlugin)
4180 if (eclipseJ2sPluginFile.exists()) {
4186 def msg = "Eclipse J2S Plugin is not installed (could not find '${j2sPluginFileName}' in\n"+eclipseJ2sPluginDirs.join("\n")+"\n)\nTry running task jalviewjsIDE_copyJ2sPlugin"
4187 System.err.println(msg)
4188 throw new StopExecutionException(msg)
4191 def digest = MessageDigest.getInstance("MD5")
4193 digest.update(j2sPluginFile.text.bytes)
4194 def j2sPluginMd5 = new BigInteger(1, digest.digest()).toString(16).padLeft(32, '0')
4196 digest.update(eclipseJ2sPluginFile.text.bytes)
4197 def eclipseJ2sPluginMd5 = new BigInteger(1, digest.digest()).toString(16).padLeft(32, '0')
4199 if (j2sPluginMd5 != eclipseJ2sPluginMd5) {
4200 def msg = "WARNING! Eclipse J2S Plugin '${eclipseJ2sPlugin}' is different to this commit's version '${j2sPlugin}'"
4201 System.err.println(msg)
4202 throw new StopExecutionException(msg)
4204 def msg = "Eclipse J2S Plugin '${eclipseJ2sPlugin}' is the same as '${j2sPlugin}' (this is good)"
4210 task jalviewjsIDE_copyJ2sPlugin {
4211 group "00 JalviewJS in Eclipse"
4212 description "Copy the swingjs/net.sf.j2s.core(-j11)?.jar file into the Eclipse IDE's 'dropins' dir"
4215 def j2sPlugin = string("${jalviewDir}/${jalviewjsJ2sPlugin}")
4216 def j2sPluginFile = file(j2sPlugin)
4217 def eclipseHome = System.properties["eclipse.home.location"]
4218 if (eclipseHome == null || ! IN_ECLIPSE) {
4219 throw new StopExecutionException("Cannot find running Eclipse home from System.properties['eclipse.home.location']. NOT copying J2S Plugin.")
4221 def eclipseJ2sPlugin = "${eclipseHome}/dropins/${j2sPluginFile.getName()}"
4222 def eclipseJ2sPluginFile = file(eclipseJ2sPlugin)
4223 def msg = "WARNING! Copying this commit's j2s plugin '${j2sPlugin}' to Eclipse J2S Plugin '${eclipseJ2sPlugin}'\n* May require an Eclipse restart"
4224 System.err.println(msg)
4227 eclipseJ2sPluginFile.getParentFile().mkdirs()
4228 into eclipseJ2sPluginFile.getParent()
4234 task jalviewjsIDE_j2sFile {
4235 group "00 JalviewJS in Eclipse"
4236 description "Creates the .j2s file"
4237 dependsOn jalviewjsCreateJ2sSettings
4241 task jalviewjsIDE_SyncCore {
4242 group "00 JalviewJS in Eclipse"
4243 description "Build the core js lib closures listed in the classlists dir and publish core html from template"
4244 dependsOn jalviewjsSyncCore
4248 task jalviewjsIDE_SyncSiteAll {
4249 dependsOn jalviewjsSyncAllLibs
4250 dependsOn jalviewjsSyncResources
4251 dependsOn jalviewjsSyncSiteResources
4252 dependsOn jalviewjsSyncBuildProperties
4256 cleanJalviewjsTransferSite.mustRunAfter jalviewjsIDE_SyncSiteAll
4259 task jalviewjsIDE_PrepareSite {
4260 group "00 JalviewJS in Eclipse"
4261 description "Sync libs and resources to site dir, but not closure cores"
4263 dependsOn jalviewjsIDE_SyncSiteAll
4264 //dependsOn cleanJalviewjsTransferSite // not sure why this clean is here -- will slow down a re-run of this task
4268 task jalviewjsIDE_AssembleSite {
4269 group "00 JalviewJS in Eclipse"
4270 description "Assembles unzipped supporting zipfiles, resources, site resources and closure cores into the Eclipse transpiled site"
4271 dependsOn jalviewjsPrepareSite
4275 task jalviewjsIDE_SiteClean {
4276 group "00 JalviewJS in Eclipse"
4277 description "Deletes the Eclipse transpiled site"
4278 dependsOn cleanJalviewjsSite
4282 task jalviewjsIDE_Server {
4283 group "00 JalviewJS in Eclipse"
4284 description "Starts a webserver on localhost to test the website"
4285 dependsOn jalviewjsServer
4289 // buildship runs this at import or gradle refresh
4290 task eclipseSynchronizationTask {
4291 //dependsOn eclipseSetup
4292 dependsOn createBuildProperties
4294 dependsOn jalviewjsIDE_j2sFile
4295 dependsOn jalviewjsIDE_checkJ2sPlugin
4296 dependsOn jalviewjsIDE_PrepareSite
4301 // buildship runs this at build time or project refresh
4302 task eclipseAutoBuildTask {
4303 //dependsOn jalviewjsIDE_checkJ2sPlugin
4304 //dependsOn jalviewjsIDE_PrepareSite
4308 task jalviewjsCopyStderrLaunchFile(type: Copy) {
4309 from file(jalviewjs_stderr_launch)
4310 into jalviewjsSiteDir
4312 inputs.file jalviewjs_stderr_launch
4313 outputs.file jalviewjsStderrLaunchFilename
4316 task cleanJalviewjsChromiumUserDir {
4318 delete jalviewjsChromiumUserDir
4320 outputs.dir jalviewjsChromiumUserDir
4321 // always run when depended on
4322 outputs.upToDateWhen { !file(jalviewjsChromiumUserDir).exists() }
4325 task jalviewjsChromiumProfile {
4326 dependsOn cleanJalviewjsChromiumUserDir
4327 mustRunAfter cleanJalviewjsChromiumUserDir
4329 def firstRun = file("${jalviewjsChromiumUserDir}/First Run")
4332 mkdir jalviewjsChromiumProfileDir
4335 outputs.file firstRun
4338 task jalviewjsLaunchTest {
4340 description "Check JalviewJS opens in a browser"
4341 dependsOn jalviewjsBuildSite
4342 dependsOn jalviewjsCopyStderrLaunchFile
4343 dependsOn jalviewjsChromiumProfile
4345 def macOS = OperatingSystem.current().isMacOsX()
4346 def chromiumBinary = macOS ? jalviewjs_macos_chromium_binary : jalviewjs_chromium_binary
4347 if (chromiumBinary.startsWith("~/")) {
4348 chromiumBinary = System.getProperty("user.home") + chromiumBinary.substring(1)
4354 def timeoutms = Integer.valueOf(jalviewjs_chromium_overall_timeout) * 1000
4356 def binary = file(chromiumBinary)
4357 if (!binary.exists()) {
4358 throw new StopExecutionException("Could not find chromium binary '${chromiumBinary}'. Cannot run task ${name}.")
4360 stdout = new ByteArrayOutputStream()
4361 stderr = new ByteArrayOutputStream()
4364 if (jalviewjs_j2s_to_console.equals("true")) {
4365 execStdout = new org.apache.tools.ant.util.TeeOutputStream(
4368 execStderr = new org.apache.tools.ant.util.TeeOutputStream(
4376 "--no-sandbox", // --no-sandbox IS USED BY THE THORIUM APPIMAGE ON THE BUILDSERVER
4379 "--timeout=${timeoutms}",
4380 "--virtual-time-budget=${timeoutms}",
4381 "--user-data-dir=${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_chromium_user_dir}",
4382 "--profile-directory=${jalviewjs_chromium_profile_name}",
4383 "--allow-file-access-from-files",
4384 "--enable-logging=stderr",
4385 "file://${jalviewDirAbsolutePath}/${jalviewjsStderrLaunchFilename}"
4388 if (true || macOS) {
4389 ScheduledExecutorService executor = Executors.newScheduledThreadPool(3);
4390 Future f1 = executor.submit(
4393 standardOutput = execStdout
4394 errorOutput = execStderr
4395 executable(chromiumBinary)
4397 println "COMMAND: '"+commandLine.join(" ")+"'"
4399 executor.shutdownNow()
4403 def noChangeBytes = 0
4404 def noChangeIterations = 0
4405 executor.scheduleAtFixedRate(
4407 String stderrString = stderr.toString()
4408 // shutdown the task if we have a success string
4409 if (stderrString.contains(jalviewjs_desktop_init_string)) {
4412 executor.shutdownNow()
4414 // if no change in stderr for 10s then also end
4415 if (noChangeIterations >= jalviewjs_chromium_idle_timeout) {
4416 executor.shutdownNow()
4418 if (stderrString.length() == noChangeBytes) {
4419 noChangeIterations++
4421 noChangeBytes = stderrString.length()
4422 noChangeIterations = 0
4425 1, 1, TimeUnit.SECONDS)
4427 executor.schedule(new Runnable(){
4430 executor.shutdownNow()
4432 }, timeoutms, TimeUnit.MILLISECONDS)
4434 executor.awaitTermination(timeoutms+10000, TimeUnit.MILLISECONDS)
4435 executor.shutdownNow()
4442 stderr.toString().eachLine { line ->
4443 if (line.contains(jalviewjs_desktop_init_string)) {
4444 println("Found line '"+line+"'")
4450 throw new GradleException("Could not find evidence of Desktop launch in JalviewJS.")
4458 description "Build the JalviewJS site and run the launch test"
4459 dependsOn jalviewjsBuildSite
4460 dependsOn jalviewjsLaunchTest