1 /* Convention for properties. Read from gradle.properties, use lower_case_underlines for property names.
2 * For properties set within build.gradle, use camelCaseNoSpace.
4 import org.apache.tools.ant.filters.ReplaceTokens
5 import org.gradle.internal.os.OperatingSystem
6 import org.gradle.plugins.ide.internal.generator.PropertiesPersistableConfigurationObject
7 import org.gradle.api.internal.PropertiesTransformer
8 import org.gradle.util.ConfigureUtil
9 import org.gradle.plugins.ide.eclipse.model.Output
10 import org.gradle.plugins.ide.eclipse.model.Library
11 import java.security.MessageDigest
12 import java.util.regex.Matcher
13 import java.util.concurrent.Executors
14 import java.util.concurrent.Future
15 import java.util.concurrent.ScheduledExecutorService
16 import java.util.concurrent.TimeUnit
17 import groovy.transform.ExternalizeMethods
18 import groovy.util.XmlParser
19 import groovy.xml.XmlUtil
20 import groovy.json.JsonBuilder
21 import com.vladsch.flexmark.util.ast.Node
22 import com.vladsch.flexmark.html.HtmlRenderer
23 import com.vladsch.flexmark.parser.Parser
24 import com.vladsch.flexmark.util.data.MutableDataSet
25 import com.vladsch.flexmark.ext.gfm.tasklist.TaskListExtension
26 import com.vladsch.flexmark.ext.tables.TablesExtension
27 import com.vladsch.flexmark.ext.gfm.strikethrough.StrikethroughExtension
28 import com.vladsch.flexmark.ext.autolink.AutolinkExtension
29 import com.vladsch.flexmark.ext.anchorlink.AnchorLinkExtension
30 import com.vladsch.flexmark.ext.toc.TocExtension
31 import com.google.common.hash.HashCode
32 import com.google.common.hash.Hashing
33 import com.google.common.io.Files
34 import org.jsoup.Jsoup
35 import org.jsoup.nodes.Element
43 classpath "com.vladsch.flexmark:flexmark-all:0.62.0"
44 classpath "org.jsoup:jsoup:1.14.3"
45 classpath "com.eowise:gradle-imagemagick:0.5.1"
54 id "com.diffplug.gradle.spotless" version "3.28.0"
55 id 'com.github.johnrengelman.shadow' version '6.0.0'
56 id 'com.install4j.gradle' version '10.0.3'
57 id 'com.dorongold.task-tree' version '2.1.1' // only needed to display task dependency tree with gradle task1 [task2 ...] taskTree
58 id 'com.palantir.git-version' version '0.13.0' apply false
69 // in ext the values are cast to Object. Ensure string values are cast as String (and not GStringImpl) for later use
70 def string(Object o) {
71 return o == null ? "" : o.toString()
74 def overrideProperties(String propsFileName, boolean output = false) {
75 if (propsFileName == null) {
78 def propsFile = file(propsFileName)
79 if (propsFile != null && propsFile.exists()) {
80 println("Using properties from file '${propsFileName}'")
82 def p = new Properties()
83 def localPropsFIS = new FileInputStream(propsFile)
89 if (project.hasProperty(key)) {
90 oldval = project.findProperty(key)
91 project.setProperty(key, val)
93 println("Overriding property '${key}' ('${oldval}') with ${file(propsFile).getName()} value '${val}'")
96 ext.setProperty(key, val)
98 println("Setting ext property '${key}' with ${file(propsFile).getName()}s value '${val}'")
102 } catch (Exception e) {
103 println("Exception reading local.properties")
110 jalviewDirAbsolutePath = file(jalviewDir).getAbsolutePath()
111 jalviewDirRelativePath = jalviewDir
114 getdownChannelName = CHANNEL.toLowerCase()
115 // default to "default". Currently only has different cosmetics for "develop", "release", "default"
116 propertiesChannelName = ["develop", "release", "test-release", "jalviewjs", "jalviewjs-release" ].contains(getdownChannelName) ? getdownChannelName : "default"
117 channelDirName = propertiesChannelName
118 // Import channel_properties
119 if (getdownChannelName.startsWith("develop-")) {
120 channelDirName = "develop-SUFFIX"
122 channelDir = string("${jalviewDir}/${channel_properties_dir}/${channelDirName}")
123 channelGradleProperties = string("${channelDir}/channel_gradle.properties")
124 channelPropsFile = string("${channelDir}/${resource_dir}/${channel_props}")
125 overrideProperties(channelGradleProperties, false)
126 // local build environment properties
127 // can be "projectDir/local.properties"
128 overrideProperties("${projectDir}/local.properties", true)
129 // or "../projectDir_local.properties"
130 overrideProperties(projectDir.getParent() + "/" + projectDir.getName() + "_local.properties", true)
133 // Import releaseProps from the RELEASE file
134 // or a file specified via JALVIEW_RELEASE_FILE if defined
135 // Expect jalview.version and target release branch in jalview.release
136 releaseProps = new Properties();
137 def releasePropFile = findProperty("JALVIEW_RELEASE_FILE");
138 def defaultReleasePropFile = "${jalviewDirAbsolutePath}/RELEASE";
140 (new File(releasePropFile!=null ? releasePropFile : defaultReleasePropFile)).withInputStream {
141 releaseProps.load(it)
143 } catch (Exception fileLoadError) {
144 throw new Error("Couldn't load release properties file "+(releasePropFile==null ? defaultReleasePropFile : "from custom location: releasePropFile"),fileLoadError);
147 // Set JALVIEW_VERSION if it is not already set
148 if (findProperty("JALVIEW_VERSION")==null || "".equals(JALVIEW_VERSION)) {
149 JALVIEW_VERSION = releaseProps.get("jalview.version")
151 println("JALVIEW_VERSION is set to '${JALVIEW_VERSION}'")
153 // this property set when running Eclipse headlessly
154 j2sHeadlessBuildProperty = string("net.sf.j2s.core.headlessbuild")
155 // this property set by Eclipse
156 eclipseApplicationProperty = string("eclipse.application")
157 // CHECK IF RUNNING FROM WITHIN ECLIPSE
158 def eclipseApplicationPropertyVal = System.properties[eclipseApplicationProperty]
159 IN_ECLIPSE = eclipseApplicationPropertyVal != null && eclipseApplicationPropertyVal.startsWith("org.eclipse.ui.")
160 // BUT WITHOUT THE HEADLESS BUILD PROPERTY SET
161 if (System.properties[j2sHeadlessBuildProperty].equals("true")) {
162 println("Setting IN_ECLIPSE to ${IN_ECLIPSE} as System.properties['${j2sHeadlessBuildProperty}'] == '${System.properties[j2sHeadlessBuildProperty]}'")
166 println("WITHIN ECLIPSE IDE")
168 println("HEADLESS BUILD")
171 J2S_ENABLED = (project.hasProperty('j2s.compiler.status') && project['j2s.compiler.status'] != null && project['j2s.compiler.status'] == "enable")
173 println("J2S ENABLED")
176 System.properties.sort { it.key }.each {
177 key, val -> println("SYSTEM PROPERTY ${key}='${val}'")
180 if (false && IN_ECLIPSE) {
181 jalviewDir = jalviewDirAbsolutePath
186 buildDate = new Date().format("yyyyMMdd")
189 bareSourceDir = string(source_dir)
190 sourceDir = string("${jalviewDir}/${bareSourceDir}")
191 resourceDir = string("${jalviewDir}/${resource_dir}")
192 bareTestSourceDir = string(test_source_dir)
193 testDir = string("${jalviewDir}/${bareTestSourceDir}")
195 classesDir = string("${jalviewDir}/${classes_dir}")
198 useClover = clover.equals("true")
199 cloverBuildDir = "${buildDir}/clover"
200 cloverInstrDir = file("${cloverBuildDir}/clover-instr")
201 cloverClassesDir = file("${cloverBuildDir}/clover-classes")
202 cloverReportDir = file("${buildDir}/reports/clover")
203 cloverTestInstrDir = file("${cloverBuildDir}/clover-test-instr")
204 cloverTestClassesDir = file("${cloverBuildDir}/clover-test-classes")
205 //cloverTestClassesDir = cloverClassesDir
206 cloverDb = string("${cloverBuildDir}/clover.db")
208 testSourceDir = useClover ? cloverTestInstrDir : testDir
209 testClassesDir = useClover ? cloverTestClassesDir : "${jalviewDir}/${test_output_dir}"
212 backgroundImageText = BACKGROUNDIMAGETEXT
213 getdownChannelDir = string("${getdown_website_dir}/${propertiesChannelName}")
214 getdownAppBaseDir = string("${jalviewDir}/${getdownChannelDir}/${JAVA_VERSION}")
215 getdownArchiveDir = string("${jalviewDir}/${getdown_archive_dir}")
216 getdownFullArchiveDir = null
217 getdownTextLines = []
218 getdownLaunchJvl = null
219 getdownVersionLaunchJvl = null
221 buildProperties = null
223 // the following values might be overridden by the CHANNEL switch
224 getdownDir = string("${getdownChannelName}/${JAVA_VERSION}")
225 getdownAppBase = string("${getdown_channel_base}/${getdownDir}")
226 getdownArchiveAppBase = getdown_archive_base
227 getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher}")
228 getdownAppDistDir = getdown_app_dir_alt
229 getdownImagesDir = string("${jalviewDir}/${getdown_images_dir}")
230 getdownImagesBuildDir = string("${buildDir}/imagemagick/getdown")
231 getdownSetAppBaseProperty = false // whether to pass the appbase and appdistdir to the application
232 reportRsyncCommand = false
233 jvlChannelName = CHANNEL.toLowerCase()
234 install4jSuffix = CHANNEL.substring(0, 1).toUpperCase() + CHANNEL.substring(1).toLowerCase(); // BUILD -> Build
235 install4jDMGDSStore = "${install4j_images_dir}/${install4j_dmg_ds_store}"
236 install4jDMGBackgroundImageDir = "${install4j_images_dir}"
237 install4jDMGBackgroundImageBuildDir = "build/imagemagick/install4j"
238 install4jDMGBackgroundImageFile = "${install4j_dmg_background}"
239 install4jInstallerName = "${jalview_name} Non-Release Installer"
240 install4jExecutableName = install4j_executable_name
241 install4jExtraScheme = "jalviewx"
242 install4jMacIconsFile = string("${install4j_images_dir}/${install4j_mac_icons_file}")
243 install4jWindowsIconsFile = string("${install4j_images_dir}/${install4j_windows_icons_file}")
244 install4jPngIconFile = string("${install4j_images_dir}/${install4j_png_icon_file}")
245 install4jBackground = string("${install4j_images_dir}/${install4j_background}")
246 install4jBuildDir = "${install4j_build_dir}/${JAVA_VERSION}"
247 install4jCheckSums = true
249 applicationName = "${jalview_name}"
253 // TODO: get bamboo build artifact URL for getdown artifacts
254 getdown_channel_base = bamboo_channelbase
255 getdownChannelName = string("${bamboo_planKey}/${JAVA_VERSION}")
256 getdownAppBase = string("${bamboo_channelbase}/${bamboo_planKey}${bamboo_getdown_channel_suffix}/${JAVA_VERSION}")
257 jvlChannelName += "_${getdownChannelName}"
258 // automatically add the test group Not-bamboo for exclusion
259 if ("".equals(testng_excluded_groups)) {
260 testng_excluded_groups = "Not-bamboo"
262 install4jExtraScheme = "jalviewb"
263 backgroundImageText = true
266 case [ "RELEASE", "JALVIEWJS-RELEASE" ]:
267 getdownAppDistDir = getdown_app_dir_release
268 getdownSetAppBaseProperty = true
269 reportRsyncCommand = true
271 install4jInstallerName = "${jalview_name} Installer"
275 getdownChannelName = CHANNEL.toLowerCase()+"/${JALVIEW_VERSION}"
276 getdownDir = string("${getdownChannelName}/${JAVA_VERSION}")
277 getdownAppBase = string("${getdown_channel_base}/${getdownDir}")
278 if (!file("${ARCHIVEDIR}/${package_dir}").exists()) {
279 throw new GradleException("Must provide an ARCHIVEDIR value to produce an archive distribution")
281 package_dir = string("${ARCHIVEDIR}/${package_dir}")
282 buildProperties = string("${ARCHIVEDIR}/${classes_dir}/${build_properties_file}")
285 reportRsyncCommand = true
286 install4jExtraScheme = "jalviewa"
290 getdownChannelName = string("archive/${JALVIEW_VERSION}")
291 getdownDir = string("${getdownChannelName}/${JAVA_VERSION}")
292 getdownAppBase = file(getdownAppBaseDir).toURI().toString()
293 if (!file("${ARCHIVEDIR}/${package_dir}").exists()) {
294 throw new GradleException("Must provide an ARCHIVEDIR value to produce an archive distribution [did not find '${ARCHIVEDIR}/${package_dir}']")
296 package_dir = string("${ARCHIVEDIR}/${package_dir}")
297 buildProperties = string("${ARCHIVEDIR}/${classes_dir}/${build_properties_file}")
300 reportRsyncCommand = true
301 getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher_local}")
302 install4jSuffix = "Archive"
303 install4jExtraScheme = "jalviewa"
306 case ~/^DEVELOP-([\.\-\w]*)$/:
307 def suffix = Matcher.lastMatcher[0][1]
308 reportRsyncCommand = true
309 getdownSetAppBaseProperty = true
310 JALVIEW_VERSION=JALVIEW_VERSION+"-d${suffix}-${buildDate}"
311 install4jSuffix = "Develop ${suffix}"
312 install4jExtraScheme = "jalviewd"
313 install4jInstallerName = "${jalview_name} Develop ${suffix} Installer"
314 getdownChannelName = string("develop-${suffix}")
315 getdownChannelDir = string("${getdown_website_dir}/${getdownChannelName}")
316 getdownAppBaseDir = string("${jalviewDir}/${getdownChannelDir}/${JAVA_VERSION}")
317 getdownDir = string("${getdownChannelName}/${JAVA_VERSION}")
318 getdownAppBase = string("${getdown_channel_base}/${getdownDir}")
319 channelSuffix = string(suffix)
320 backgroundImageText = true
324 reportRsyncCommand = true
325 getdownSetAppBaseProperty = true
326 // DEVELOP-RELEASE is usually associated with a Jalview release series so set the version
327 JALVIEW_VERSION=JALVIEW_VERSION+"-d${buildDate}"
329 install4jSuffix = "Develop"
330 install4jExtraScheme = "jalviewd"
331 install4jInstallerName = "${jalview_name} Develop Installer"
332 backgroundImageText = true
336 reportRsyncCommand = true
337 getdownSetAppBaseProperty = true
338 // Don't ignore transpile errors for release build
339 if (jalviewjs_ignore_transpile_errors.equals("true")) {
340 jalviewjs_ignore_transpile_errors = "false"
341 println("Setting jalviewjs_ignore_transpile_errors to 'false'")
343 JALVIEW_VERSION = JALVIEW_VERSION+"-test"
344 install4jSuffix = "Test"
345 install4jExtraScheme = "jalviewt"
346 install4jInstallerName = "${jalview_name} Test Installer"
347 backgroundImageText = true
350 case ~/^SCRATCH(|-[-\w]*)$/:
351 getdownChannelName = CHANNEL
352 JALVIEW_VERSION = JALVIEW_VERSION+"-"+CHANNEL
354 getdownDir = string("${getdownChannelName}/${JAVA_VERSION}")
355 getdownAppBase = string("${getdown_channel_base}/${getdownDir}")
356 reportRsyncCommand = true
357 install4jSuffix = "Scratch"
361 if (!file("${LOCALDIR}").exists()) {
362 throw new GradleException("Must provide a LOCALDIR value to produce a local distribution")
364 getdownAppBase = file(file("${LOCALDIR}").getAbsolutePath()).toURI().toString()
365 getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher_local}")
367 JALVIEW_VERSION = "TEST"
368 install4jSuffix = "Test-Local"
369 install4jExtraScheme = "jalviewt"
370 install4jInstallerName = "${jalview_name} Test Installer"
371 backgroundImageText = true
374 case [ "LOCAL", "JALVIEWJS" ]:
375 JALVIEW_VERSION = "TEST"
376 getdownAppBase = file(getdownAppBaseDir).toURI().toString()
377 getdownArchiveAppBase = file("${jalviewDir}/${getdown_archive_dir}").toURI().toString()
378 getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher_local}")
379 install4jExtraScheme = "jalviewl"
380 install4jCheckSums = false
383 default: // something wrong specified
384 throw new GradleException("CHANNEL must be one of BUILD, RELEASE, ARCHIVE, DEVELOP, TEST-RELEASE, SCRATCH-..., LOCAL [default]")
388 JALVIEW_VERSION_UNDERSCORES = JALVIEW_VERSION.replaceAll("\\.", "_")
389 hugoDataJsonFile = file("${jalviewDir}/${hugo_build_dir}/${hugo_data_installers_dir}/installers-${JALVIEW_VERSION_UNDERSCORES}.json")
390 hugoArchiveMdFile = file("${jalviewDir}/${hugo_build_dir}/${hugo_version_archive_dir}/Version-${JALVIEW_VERSION_UNDERSCORES}/_index.md")
391 // override getdownAppBase if requested
392 if (findProperty("getdown_appbase_override") != null) {
393 // revert to LOCAL if empty string
394 if (string(getdown_appbase_override) == "") {
395 getdownAppBase = file(getdownAppBaseDir).toURI().toString()
396 getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher_local}")
397 } else if (string(getdown_appbase_override).startsWith("file://")) {
398 getdownAppBase = string(getdown_appbase_override)
399 getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher_local}")
401 getdownAppBase = string(getdown_appbase_override)
403 println("Overriding getdown appbase with '${getdownAppBase}'")
405 // sanitise file name for jalview launcher file for this channel
406 jvlChannelName = jvlChannelName.replaceAll("[^\\w\\-]+", "_")
407 // install4j application and folder names
408 if (install4jSuffix == "") {
409 install4jBundleId = "${install4j_bundle_id}"
410 install4jWinApplicationId = install4j_release_win_application_id
412 applicationName = "${jalview_name} ${install4jSuffix}"
413 install4jBundleId = "${install4j_bundle_id}-" + install4jSuffix.toLowerCase()
414 // add int hash of install4jSuffix to the last part of the application_id
415 def id = install4j_release_win_application_id
416 def idsplitreverse = id.split("-").reverse()
417 idsplitreverse[0] = idsplitreverse[0].toInteger() + install4jSuffix.hashCode()
418 install4jWinApplicationId = idsplitreverse.reverse().join("-")
420 // sanitise folder and id names
421 // install4jApplicationFolder = e.g. "Jalview Build"
422 install4jApplicationFolder = applicationName
423 .replaceAll("[\"'~:/\\\\\\s]", "_") // replace all awkward filename chars " ' ~ : / \
424 .replaceAll("_+", "_") // collapse __
425 install4jInternalId = applicationName
427 .replaceAll("[^\\w\\-\\.]", "_") // replace other non [alphanumeric,_,-,.]
428 .replaceAll("_+", "") // collapse __
429 //.replaceAll("_*-_*", "-") // collapse _-_
430 install4jUnixApplicationFolder = applicationName
432 .replaceAll("[^\\w\\-\\.]", "_") // replace other non [alphanumeric,_,-,.]
433 .replaceAll("_+", "_") // collapse __
434 .replaceAll("_*-_*", "-") // collapse _-_
437 getdownWrapperLink = install4jUnixApplicationFolder // e.g. "jalview_local"
438 getdownAppDir = string("${getdownAppBaseDir}/${getdownAppDistDir}")
439 //getdownJ11libDir = "${getdownAppBaseDir}/${getdown_j11lib_dir}"
440 getdownResourceDir = string("${getdownAppBaseDir}/${getdown_resource_dir}")
441 getdownInstallDir = string("${getdownAppBaseDir}/${getdown_install_dir}")
442 getdownFilesDir = string("${jalviewDir}/${getdown_files_dir}/${JAVA_VERSION}/")
443 getdownFilesInstallDir = string("${getdownFilesDir}/${getdown_install_dir}")
444 /* compile without modules -- using classpath libraries
445 modules_compileClasspath = fileTree(dir: "${jalviewDir}/${j11modDir}", include: ["*.jar"])
446 modules_runtimeClasspath = modules_compileClasspath
452 apply plugin: "com.palantir.git-version"
453 def details = versionDetails()
454 gitHash = details.gitHash
455 gitBranch = details.branchName
456 } catch(org.gradle.api.internal.plugins.PluginApplicationException e) {
457 println("Not in a git repository. Using git values from RELEASE properties file.")
458 gitHash = releaseProps.getProperty("git.hash")
459 gitBranch = releaseProps.getProperty("git.branch")
460 } catch(java.lang.RuntimeException e1) {
461 throw new GradleException("Error with git-version plugin. Directory '.git' exists but versionDetails() cannot be found.")
464 println("Using a ${CHANNEL} profile.")
466 additional_compiler_args = []
467 // configure classpath/args for j8/j11 compilation
468 if (JAVA_VERSION.equals("1.8")) {
469 JAVA_INTEGER_VERSION = string("8")
472 libDistDir = j8libDir
473 compile_source_compatibility = 1.8
474 compile_target_compatibility = 1.8
475 // these are getdown.txt properties defined dependent on the JAVA_VERSION
476 getdownAltJavaMinVersion = string(findProperty("getdown_alt_java8_min_version"))
477 getdownAltJavaMaxVersion = string(findProperty("getdown_alt_java8_max_version"))
478 // this property is assigned below and expanded to multiple lines in the getdown task
479 getdownAltMultiJavaLocation = string(findProperty("getdown_alt_java8_txt_multi_java_location"))
480 // this property is for the Java library used in eclipse
481 eclipseJavaRuntimeName = string("JavaSE-1.8")
482 } else if (JAVA_VERSION.equals("11")) {
483 JAVA_INTEGER_VERSION = string("11")
485 libDistDir = j11libDir
486 compile_source_compatibility = 11
487 compile_target_compatibility = 11
488 getdownAltJavaMinVersion = string(findProperty("getdown_alt_java11_min_version"))
489 getdownAltJavaMaxVersion = string(findProperty("getdown_alt_java11_max_version"))
490 getdownAltMultiJavaLocation = string(findProperty("getdown_alt_java11_txt_multi_java_location"))
491 eclipseJavaRuntimeName = string("JavaSE-11")
492 /* compile without modules -- using classpath libraries
493 additional_compiler_args += [
494 '--module-path', modules_compileClasspath.asPath,
495 '--add-modules', j11modules
498 } else if (JAVA_VERSION.equals("17")) {
499 JAVA_INTEGER_VERSION = string("17")
501 libDistDir = j17libDir
502 compile_source_compatibility = 17
503 compile_target_compatibility = 17
504 getdownAltJavaMinVersion = string(findProperty("getdown_alt_java11_min_version"))
505 getdownAltJavaMaxVersion = string(findProperty("getdown_alt_java11_max_version"))
506 getdownAltMultiJavaLocation = string(findProperty("getdown_alt_java11_txt_multi_java_location"))
507 eclipseJavaRuntimeName = string("JavaSE-17")
508 /* compile without modules -- using classpath libraries
509 additional_compiler_args += [
510 '--module-path', modules_compileClasspath.asPath,
511 '--add-modules', j11modules
515 throw new GradleException("JAVA_VERSION=${JAVA_VERSION} not currently supported by Jalview")
520 JAVA_MIN_VERSION = JAVA_VERSION
521 JAVA_MAX_VERSION = JAVA_VERSION
522 jreInstallsDir = string(jre_installs_dir)
523 if (jreInstallsDir.startsWith("~/")) {
524 jreInstallsDir = System.getProperty("user.home") + jreInstallsDir.substring(1)
526 install4jDir = string("${jalviewDir}/${install4j_utils_dir}")
527 install4jConfFileName = string("jalview-install4j-conf.install4j")
528 install4jConfFile = file("${install4jDir}/${install4jConfFileName}")
529 install4jHomeDir = install4j_home_dir
530 if (install4jHomeDir.startsWith("~/")) {
531 install4jHomeDir = System.getProperty("user.home") + install4jHomeDir.substring(1)
534 resourceBuildDir = string("${buildDir}/resources")
535 resourcesBuildDir = string("${resourceBuildDir}/resources_build")
536 helpBuildDir = string("${resourceBuildDir}/help_build")
537 docBuildDir = string("${resourceBuildDir}/doc_build")
539 if (buildProperties == null) {
540 buildProperties = string("${resourcesBuildDir}/${build_properties_file}")
542 buildingHTML = string("${jalviewDir}/${doc_dir}/building.html")
543 helpParentDir = string("${jalviewDir}/${help_parent_dir}")
544 helpSourceDir = string("${helpParentDir}/${help_dir}")
545 helpFile = string("${helpBuildDir}/${help_dir}/help.jhm")
548 convertBinaryExpectedLocation = imagemagick_convert
549 if (convertBinaryExpectedLocation.startsWith("~/")) {
550 convertBinaryExpectedLocation = System.getProperty("user.home") + convertBinaryExpectedLocation.substring(1)
552 if (file(convertBinaryExpectedLocation).exists()) {
553 convertBinary = convertBinaryExpectedLocation
556 relativeBuildDir = file(jalviewDirAbsolutePath).toPath().relativize(buildDir.toPath())
557 jalviewjsBuildDir = string("${relativeBuildDir}/jalviewjs")
558 jalviewjsSiteDir = string("${jalviewjsBuildDir}/${jalviewjs_site_dir}")
560 jalviewjsTransferSiteJsDir = string(jalviewjsSiteDir)
562 jalviewjsTransferSiteJsDir = string("${jalviewjsBuildDir}/tmp/${jalviewjs_site_dir}_js")
564 jalviewjsTransferSiteLibDir = string("${jalviewjsBuildDir}/tmp/${jalviewjs_site_dir}_lib")
565 jalviewjsTransferSiteSwingJsDir = string("${jalviewjsBuildDir}/tmp/${jalviewjs_site_dir}_swingjs")
566 jalviewjsTransferSiteCoreDir = string("${jalviewjsBuildDir}/tmp/${jalviewjs_site_dir}_core")
567 jalviewjsJalviewCoreHtmlFile = string("")
568 jalviewjsJalviewCoreName = string(jalviewjs_core_name)
569 jalviewjsCoreClasslists = []
570 jalviewjsJalviewTemplateName = string(jalviewjs_name)
571 jalviewjsJ2sSettingsFileName = string("${jalviewDir}/${jalviewjs_j2s_settings}")
572 jalviewjsJ2sAltSettingsFileName = string("${jalviewDir}/${jalviewjs_j2s_alt_settings}")
573 jalviewjsJ2sProps = null
574 jalviewjsJ2sPlugin = jalviewjs_j2s_plugin
575 jalviewjsStderrLaunchFilename = "${jalviewjsSiteDir}/"+(file(jalviewjs_stderr_launch).getName())
577 eclipseWorkspace = null
578 eclipseBinary = string("")
579 eclipseVersion = string("")
580 eclipseProductVersion = string("")
583 jalviewjsChromiumUserDir = "${jalviewjsBuildDir}/${jalviewjs_chromium_user_dir}"
584 jalviewjsChromiumProfileDir = "${ext.jalviewjsChromiumUserDir}/${jalviewjs_chromium_profile_name}"
594 outputDir = file(classesDir)
598 srcDirs = [ resourcesBuildDir, docBuildDir, helpBuildDir ]
601 compileClasspath = files(sourceSets.main.java.outputDir)
602 compileClasspath += fileTree(dir: "${jalviewDir}/${libDir}", include: ["*.jar"])
604 runtimeClasspath = compileClasspath
605 runtimeClasspath += files(sourceSets.main.resources.srcDirs)
610 srcDirs cloverInstrDir
611 outputDir = cloverClassesDir
615 srcDirs = sourceSets.main.resources.srcDirs
618 compileClasspath = files( sourceSets.clover.java.outputDir )
619 //compileClasspath += files( testClassesDir )
620 compileClasspath += fileTree(dir: "${jalviewDir}/${libDir}", include: ["*.jar"])
621 compileClasspath += fileTree(dir: "${jalviewDir}/${clover_lib_dir}", include: ["*.jar"])
622 compileClasspath += fileTree(dir: "${jalviewDir}/${utils_dir}/testnglibs", include: ["**/*.jar"])
624 runtimeClasspath = compileClasspath
629 srcDirs testSourceDir
630 outputDir = file(testClassesDir)
634 srcDirs = useClover ? sourceSets.clover.resources.srcDirs : sourceSets.main.resources.srcDirs
637 compileClasspath = files( sourceSets.test.java.outputDir )
638 compileClasspath += useClover ? sourceSets.clover.compileClasspath : sourceSets.main.compileClasspath
639 compileClasspath += fileTree(dir: "${jalviewDir}/${utils_dir}/testnglibs", include: ["**/*.jar"])
641 runtimeClasspath = compileClasspath
642 runtimeClasspath += files(sourceSets.test.resources.srcDirs)
648 // eclipse project and settings files creation, also used by buildship
651 name = eclipse_project_name
653 natures 'org.eclipse.jdt.core.javanature',
654 'org.eclipse.jdt.groovy.core.groovyNature',
655 'org.eclipse.buildship.core.gradleprojectnature'
657 buildCommand 'org.eclipse.jdt.core.javabuilder'
658 buildCommand 'org.eclipse.buildship.core.gradleprojectbuilder'
662 //defaultOutputDir = sourceSets.main.java.outputDir
663 configurations.each{ c->
664 if (c.isCanBeResolved()) {
665 minusConfigurations += [c]
669 plusConfigurations = [ ]
673 def removeTheseToo = []
674 HashMap<String, Boolean> alreadyAddedSrcPath = new HashMap<>();
675 cp.entries.each { entry ->
676 // This conditional removes all src classpathentries that a) have already been added or b) aren't "src" or "test".
677 // e.g. this removes the resources dir being copied into bin/main, bin/test AND bin/clover
678 // we add the resources and help/help dirs in as libs afterwards (see below)
679 if (entry.kind == 'src') {
680 if (alreadyAddedSrcPath.getAt(entry.path) || !(entry.path == bareSourceDir || entry.path == bareTestSourceDir)) {
681 removeTheseToo += entry
683 alreadyAddedSrcPath.putAt(entry.path, true)
688 cp.entries.removeAll(removeTheseToo)
690 //cp.entries += new Output("${eclipse_bin_dir}/main")
691 if (file(helpParentDir).isDirectory()) {
692 cp.entries += new Library(fileReference(helpParentDir))
694 if (file(resourceDir).isDirectory()) {
695 cp.entries += new Library(fileReference(resourceDir))
698 HashMap<String, Boolean> alreadyAddedLibPath = new HashMap<>();
700 sourceSets.main.compileClasspath.findAll { it.name.endsWith(".jar") }.any {
701 //don't want to add outputDir as eclipse is using its own output dir in bin/main
702 if (it.isDirectory() || ! it.exists()) {
703 // don't add dirs to classpath, especially if they don't exist
704 return false // groovy "continue" in .any closure
706 def itPath = it.toString()
707 if (itPath.startsWith("${jalviewDirAbsolutePath}/")) {
708 // make relative path
709 itPath = itPath.substring(jalviewDirAbsolutePath.length()+1)
711 if (alreadyAddedLibPath.get(itPath)) {
712 //println("Not adding duplicate entry "+itPath)
714 //println("Adding entry "+itPath)
715 cp.entries += new Library(fileReference(itPath))
716 alreadyAddedLibPath.put(itPath, true)
720 sourceSets.test.compileClasspath.findAll { it.name.endsWith(".jar") }.any {
721 //no longer want to add outputDir as eclipse is using its own output dir in bin/main
722 if (it.isDirectory() || ! it.exists()) {
723 // don't add dirs to classpath
724 return false // groovy "continue" in .any closure
727 def itPath = it.toString()
728 if (itPath.startsWith("${jalviewDirAbsolutePath}/")) {
729 itPath = itPath.substring(jalviewDirAbsolutePath.length()+1)
731 if (alreadyAddedLibPath.get(itPath)) {
734 def lib = new Library(fileReference(itPath))
735 lib.entryAttributes["test"] = "true"
737 alreadyAddedLibPath.put(itPath, true)
745 containers 'org.eclipse.buildship.core.gradleclasspathcontainer'
750 // for the IDE, use java 11 compatibility
751 sourceCompatibility = compile_source_compatibility
752 targetCompatibility = compile_target_compatibility
753 javaRuntimeName = eclipseJavaRuntimeName
755 // add in jalview project specific properties/preferences into eclipse core preferences
757 withProperties { props ->
758 def jalview_prefs = new Properties()
759 def ins = new FileInputStream("${jalviewDirAbsolutePath}/${eclipse_extra_jdt_prefs_file}")
760 jalview_prefs.load(ins)
762 jalview_prefs.forEach { t, v ->
763 if (props.getAt(t) == null) {
767 // codestyle file -- overrides previous formatter prefs
768 def csFile = file("${jalviewDirAbsolutePath}/${eclipse_codestyle_file}")
769 if (csFile.exists()) {
770 XmlParser parser = new XmlParser()
771 def profiles = parser.parse(csFile)
772 def profile = profiles.'profile'.find { p -> (p.'@kind' == "CodeFormatterProfile" && p.'@name' == "Jalview") }
773 if (profile != null) {
774 profile.'setting'.each { s ->
776 def value = s.'@value'
777 if (id != null && value != null) {
778 props.putAt(id, value)
789 // Don't want these to be activated if in headless build
790 synchronizationTasks "eclipseSynchronizationTask"
791 //autoBuildTasks "eclipseAutoBuildTask"
797 /* hack to change eclipse prefs in .settings files other than org.eclipse.jdt.core.prefs */
798 // Class to allow updating arbitrary properties files
799 class PropertiesFile extends PropertiesPersistableConfigurationObject {
800 public PropertiesFile(PropertiesTransformer t) { super(t); }
801 @Override protected void load(Properties properties) { }
802 @Override protected void store(Properties properties) { }
803 @Override protected String getDefaultResourceName() { return ""; }
804 // This is necessary, because PropertiesPersistableConfigurationObject fails
805 // if no default properties file exists.
806 @Override public void loadDefaults() { load(new StringBufferInputStream("")); }
809 // Task to update arbitrary properties files (set outputFile)
810 class PropertiesFileTask extends PropertiesGeneratorTask<PropertiesFile> {
811 private final PropertiesFileContentMerger file;
812 public PropertiesFileTask() { file = new PropertiesFileContentMerger(getTransformer()); }
813 protected PropertiesFile create() { return new PropertiesFile(getTransformer()); }
814 protected void configure(PropertiesFile props) {
815 file.getBeforeMerged().execute(props); file.getWhenMerged().execute(props);
817 public void file(Closure closure) { ConfigureUtil.configure(closure, file); }
820 task eclipseUIPreferences(type: PropertiesFileTask) {
821 description = "Generate Eclipse additional settings"
822 def filename = "org.eclipse.jdt.ui.prefs"
823 outputFile = "$projectDir/.settings/${filename}" as File
826 it.load new FileInputStream("$projectDir/utils/eclipse/${filename}" as String)
831 task eclipseGroovyCorePreferences(type: PropertiesFileTask) {
832 description = "Generate Eclipse additional settings"
833 def filename = "org.eclipse.jdt.groovy.core.prefs"
834 outputFile = "$projectDir/.settings/${filename}" as File
837 it.load new FileInputStream("$projectDir/utils/eclipse/${filename}" as String)
842 task eclipseAllPreferences {
844 dependsOn eclipseUIPreferences
845 dependsOn eclipseGroovyCorePreferences
848 eclipseUIPreferences.mustRunAfter eclipseJdt
849 eclipseGroovyCorePreferences.mustRunAfter eclipseJdt
851 /* end of eclipse preferences hack */
859 delete cloverBuildDir
860 delete cloverReportDir
865 task cloverInstrJava(type: JavaExec) {
866 group = "Verification"
867 description = "Create clover instrumented source java files"
869 dependsOn cleanClover
871 inputs.files(sourceSets.main.allJava)
872 outputs.dir(cloverInstrDir)
874 //classpath = fileTree(dir: "${jalviewDir}/${clover_lib_dir}", include: ["*.jar"])
875 classpath = sourceSets.clover.compileClasspath
876 main = "com.atlassian.clover.CloverInstr"
884 cloverInstrDir.getPath(),
886 def srcFiles = sourceSets.main.allJava.files
889 { file -> file.absolutePath }
892 args argsList.toArray()
895 delete cloverInstrDir
896 println("Clover: About to instrument "+srcFiles.size() +" files")
901 task cloverInstrTests(type: JavaExec) {
902 group = "Verification"
903 description = "Create clover instrumented source test files"
905 dependsOn cleanClover
907 inputs.files(testDir)
908 outputs.dir(cloverTestInstrDir)
910 classpath = sourceSets.clover.compileClasspath
911 main = "com.atlassian.clover.CloverInstr"
921 cloverTestInstrDir.getPath(),
923 args argsList.toArray()
926 delete cloverTestInstrDir
927 println("Clover: About to instrument test files")
933 group = "Verification"
934 description = "Create clover instrumented all source files"
936 dependsOn cloverInstrJava
937 dependsOn cloverInstrTests
941 cloverClasses.dependsOn cloverInstr
944 task cloverConsoleReport(type: JavaExec) {
945 group = "Verification"
946 description = "Creates clover console report"
949 file(cloverDb).exists()
952 inputs.dir cloverClassesDir
954 classpath = sourceSets.clover.runtimeClasspath
955 main = "com.atlassian.clover.reporters.console.ConsoleReporter"
957 if (cloverreport_mem.length() > 0) {
958 maxHeapSize = cloverreport_mem
960 if (cloverreport_jvmargs.length() > 0) {
961 jvmArgs Arrays.asList(cloverreport_jvmargs.split(" "))
971 args argsList.toArray()
975 task cloverHtmlReport(type: JavaExec) {
976 group = "Verification"
977 description = "Creates clover HTML report"
980 file(cloverDb).exists()
983 def cloverHtmlDir = cloverReportDir
984 inputs.dir cloverClassesDir
985 outputs.dir cloverHtmlDir
987 classpath = sourceSets.clover.runtimeClasspath
988 main = "com.atlassian.clover.reporters.html.HtmlReporter"
990 if (cloverreport_mem.length() > 0) {
991 maxHeapSize = cloverreport_mem
993 if (cloverreport_jvmargs.length() > 0) {
994 jvmArgs Arrays.asList(cloverreport_jvmargs.split(" "))
1005 if (cloverreport_html_options.length() > 0) {
1006 argsList += cloverreport_html_options.split(" ")
1009 args argsList.toArray()
1013 task cloverXmlReport(type: JavaExec) {
1014 group = "Verification"
1015 description = "Creates clover XML report"
1018 file(cloverDb).exists()
1021 def cloverXmlFile = "${cloverReportDir}/clover.xml"
1022 inputs.dir cloverClassesDir
1023 outputs.file cloverXmlFile
1025 classpath = sourceSets.clover.runtimeClasspath
1026 main = "com.atlassian.clover.reporters.xml.XMLReporter"
1028 if (cloverreport_mem.length() > 0) {
1029 maxHeapSize = cloverreport_mem
1031 if (cloverreport_jvmargs.length() > 0) {
1032 jvmArgs Arrays.asList(cloverreport_jvmargs.split(" "))
1043 if (cloverreport_xml_options.length() > 0) {
1044 argsList += cloverreport_xml_options.split(" ")
1047 args argsList.toArray()
1052 group = "Verification"
1053 description = "Creates clover reports"
1055 dependsOn cloverXmlReport
1056 dependsOn cloverHtmlReport
1063 sourceCompatibility = compile_source_compatibility
1064 targetCompatibility = compile_target_compatibility
1065 options.compilerArgs += additional_compiler_args
1066 print ("Setting target compatibility to "+targetCompatibility+"\n")
1068 //classpath += configurations.cloverRuntime
1074 // JBP->BS should the print statement in doFirst refer to compile_target_compatibility ?
1075 sourceCompatibility = compile_source_compatibility
1076 targetCompatibility = compile_target_compatibility
1077 options.compilerArgs += additional_compiler_args
1078 options.encoding = "UTF-8"
1080 print ("Setting target compatibility to "+compile_target_compatibility+"\n")
1087 sourceCompatibility = compile_source_compatibility
1088 targetCompatibility = compile_target_compatibility
1089 options.compilerArgs += additional_compiler_args
1091 print ("Setting target compatibility to "+targetCompatibility+"\n")
1098 delete sourceSets.main.java.outputDir
1104 dependsOn cleanClover
1106 delete sourceSets.test.java.outputDir
1111 // format is a string like date.format("dd MMMM yyyy")
1112 def getDate(format) {
1113 return date.format(format)
1117 def convertMdToHtml (FileTree mdFiles, File cssFile) {
1118 MutableDataSet options = new MutableDataSet()
1120 def extensions = new ArrayList<>()
1121 extensions.add(AnchorLinkExtension.create())
1122 extensions.add(AutolinkExtension.create())
1123 extensions.add(StrikethroughExtension.create())
1124 extensions.add(TaskListExtension.create())
1125 extensions.add(TablesExtension.create())
1126 extensions.add(TocExtension.create())
1128 options.set(Parser.EXTENSIONS, extensions)
1130 // set GFM table parsing options
1131 options.set(TablesExtension.WITH_CAPTION, false)
1132 options.set(TablesExtension.COLUMN_SPANS, false)
1133 options.set(TablesExtension.MIN_HEADER_ROWS, 1)
1134 options.set(TablesExtension.MAX_HEADER_ROWS, 1)
1135 options.set(TablesExtension.APPEND_MISSING_COLUMNS, true)
1136 options.set(TablesExtension.DISCARD_EXTRA_COLUMNS, true)
1137 options.set(TablesExtension.HEADER_SEPARATOR_COLUMN_MATCH, true)
1139 options.set(AnchorLinkExtension.ANCHORLINKS_SET_ID, false)
1140 options.set(AnchorLinkExtension.ANCHORLINKS_ANCHOR_CLASS, "anchor")
1141 options.set(AnchorLinkExtension.ANCHORLINKS_SET_NAME, true)
1142 options.set(AnchorLinkExtension.ANCHORLINKS_TEXT_PREFIX, "<span class=\"octicon octicon-link\"></span>")
1144 Parser parser = Parser.builder(options).build()
1145 HtmlRenderer renderer = HtmlRenderer.builder(options).build()
1147 mdFiles.each { mdFile ->
1148 // add table of contents
1149 def mdText = "[TOC]\n"+mdFile.text
1151 // grab the first top-level title
1153 def titleRegex = /(?m)^#(\s+|([^#]))(.*)/
1154 def matcher = mdText =~ titleRegex
1155 if (matcher.size() > 0) {
1156 // matcher[0][2] is the first character of the title if there wasn't any whitespace after the #
1157 title = (matcher[0][2] != null ? matcher[0][2] : "")+matcher[0][3]
1159 // or use the filename if none found
1160 if (title == null) {
1161 title = mdFile.getName()
1164 Node document = parser.parse(mdText)
1165 String htmlBody = renderer.render(document)
1166 def htmlText = '''<html>
1167 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
1168 <html xmlns="http://www.w3.org/1999/xhtml">
1170 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
1171 <meta http-equiv="Content-Style-Type" content="text/css" />
1172 <meta name="generator" content="flexmark" />
1174 htmlText += ((title != null) ? " <title>${title}</title>" : '' )
1176 <style type="text/css">code{white-space: pre;}</style>
1178 htmlText += ((cssFile != null) ? cssFile.text : '')
1179 htmlText += '''</head>
1182 htmlText += htmlBody
1188 def htmlFilePath = mdFile.getPath().replaceAll(/\..*?$/, ".html")
1189 def htmlFile = file(htmlFilePath)
1190 println("Creating ${htmlFilePath}")
1191 htmlFile.text = htmlText
1196 task copyDocs(type: Copy) {
1197 def inputDir = "${jalviewDir}/${doc_dir}"
1198 def outputDir = "${docBuildDir}/${doc_dir}"
1202 include('**/*.html')
1204 filter(ReplaceTokens,
1208 'Version-Rel': JALVIEW_VERSION,
1209 'Year-Rel': getDate("yyyy")
1216 exclude('**/*.html')
1221 inputs.dir(inputDir)
1222 outputs.dir(outputDir)
1226 task convertMdFiles {
1228 def mdFiles = fileTree(dir: docBuildDir, include: "**/*.md")
1229 def cssFile = file("${jalviewDir}/${flexmark_css}")
1232 convertMdToHtml(mdFiles, cssFile)
1235 inputs.files(mdFiles)
1236 inputs.file(cssFile)
1239 mdFiles.each { mdFile ->
1240 def htmlFilePath = mdFile.getPath().replaceAll(/\..*?$/, ".html")
1241 htmlFiles.add(file(htmlFilePath))
1243 outputs.files(htmlFiles)
1247 def hugoTemplateSubstitutions(String input, Map extras=null) {
1248 def replacements = [
1249 DATE: getDate("yyyy-MM-dd"),
1250 CHANNEL: propertiesChannelName,
1251 APPLICATION_NAME: applicationName,
1253 GIT_BRANCH: gitBranch,
1254 VERSION: JALVIEW_VERSION,
1255 JAVA_VERSION: JAVA_VERSION,
1256 VERSION_UNDERSCORES: JALVIEW_VERSION_UNDERSCORES,
1261 if (extras != null) {
1262 extras.each{ k, v ->
1263 output = output.replaceAll("__${k}__", ((v == null)?"":v))
1266 replacements.each{ k, v ->
1267 output = output.replaceAll("__${k}__", ((v == null)?"":v))
1272 def mdFileComponents(File mdFile, def dateOnly=false) {
1275 if (mdFile.exists()) {
1276 def inFrontMatter = false
1277 def firstLine = true
1278 mdFile.eachLine { line ->
1279 if (line.matches("---")) {
1280 def prev = inFrontMatter
1281 inFrontMatter = firstLine
1282 if (inFrontMatter != prev)
1285 if (inFrontMatter) {
1287 if (m = line =~ /^date:\s*(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})/) {
1288 map["date"] = new Date().parse("yyyy-MM-dd HH:mm:ss", m[0][1])
1289 } else if (m = line =~ /^date:\s*(\d{4}-\d{2}-\d{2})/) {
1290 map["date"] = new Date().parse("yyyy-MM-dd", m[0][1])
1291 } else if (m = line =~ /^channel:\s*(\S+)/) {
1292 map["channel"] = m[0][1]
1293 } else if (m = line =~ /^version:\s*(\S+)/) {
1294 map["version"] = m[0][1]
1295 } else if (m = line =~ /^\s*([^:]+)\s*:\s*(\S.*)/) {
1296 map[ m[0][1] ] = m[0][2]
1298 if (dateOnly && map["date"] != null) {
1304 content += line+"\n"
1309 return dateOnly ? map["date"] : [map, content]
1312 task hugoTemplates {
1314 description "Create partially populated md pages for hugo website build"
1316 def hugoTemplatesDir = file("${jalviewDir}/${hugo_templates_dir}")
1317 def hugoBuildDir = "${jalviewDir}/${hugo_build_dir}"
1318 def templateFiles = fileTree(dir: hugoTemplatesDir)
1319 def releaseMdFile = file("${jalviewDir}/${releases_dir}/release-${JALVIEW_VERSION_UNDERSCORES}.md")
1320 def whatsnewMdFile = file("${jalviewDir}/${whatsnew_dir}/whatsnew-${JALVIEW_VERSION_UNDERSCORES}.md")
1321 def oldJvlFile = file("${jalviewDir}/${hugo_old_jvl}")
1322 def jalviewjsFile = file("${jalviewDir}/${hugo_jalviewjs}")
1325 // specific release template for version archive
1328 def givenDate = null
1329 def givenChannel = null
1330 def givenVersion = null
1331 if (CHANNEL == "RELEASE") {
1332 def (map, content) = mdFileComponents(releaseMdFile)
1333 givenDate = map.date
1334 givenChannel = map.channel
1335 givenVersion = map.version
1337 if (givenVersion != null && givenVersion != JALVIEW_VERSION) {
1338 throw new GradleException("'version' header (${givenVersion}) found in ${releaseMdFile} does not match JALVIEW_VERSION (${JALVIEW_VERSION})")
1341 if (whatsnewMdFile.exists())
1342 whatsnew = whatsnewMdFile.text
1345 def oldJvl = oldJvlFile.exists() ? oldJvlFile.collect{it} : []
1346 def jalviewjsLink = jalviewjsFile.exists() ? jalviewjsFile.collect{it} : []
1348 def changesHugo = null
1349 if (changes != null) {
1350 changesHugo = '<div class="release_notes">\n\n'
1351 def inSection = false
1352 changes.eachLine { line ->
1354 if (m = line =~ /^##([^#].*)$/) {
1356 changesHugo += "</div>\n\n"
1358 def section = m[0][1].trim()
1359 section = section.toLowerCase()
1360 section = section.replaceAll(/ +/, "_")
1361 section = section.replaceAll(/[^a-z0-9_\-]/, "")
1362 changesHugo += "<div class=\"${section}\">\n\n"
1364 } else if (m = line =~ /^(\s*-\s*)<!--([^>]+)-->(.*?)(<br\/?>)?\s*$/) {
1365 def comment = m[0][2].trim()
1366 if (comment != "") {
1367 comment = comment.replaceAll('"', """)
1369 comment.eachMatch(/JAL-\d+/) { jal -> issuekeys += jal }
1370 def newline = m[0][1]
1371 if (comment.trim() != "")
1372 newline += "{{<comment>}}${comment}{{</comment>}} "
1373 newline += m[0][3].trim()
1374 if (issuekeys.size() > 0)
1375 newline += " {{< jal issue=\"${issuekeys.join(",")}\" alt=\"${comment}\" >}}"
1376 if (m[0][4] != null)
1381 changesHugo += line+"\n"
1384 changesHugo += "\n</div>\n\n"
1386 changesHugo += '</div>'
1389 templateFiles.each{ templateFile ->
1390 def newFileName = string(hugoTemplateSubstitutions(templateFile.getName()))
1391 def relPath = hugoTemplatesDir.toPath().relativize(templateFile.toPath()).getParent()
1392 def newRelPathName = hugoTemplateSubstitutions( relPath.toString() )
1394 def outPathName = string("${hugoBuildDir}/$newRelPathName")
1398 rename(templateFile.getName(), newFileName)
1402 def newFile = file("${outPathName}/${newFileName}".toString())
1403 def content = newFile.text
1404 newFile.text = hugoTemplateSubstitutions(content,
1407 CHANGES: changesHugo,
1408 DATE: givenDate == null ? "" : givenDate.format("yyyy-MM-dd"),
1409 DRAFT: givenDate == null ? "true" : "false",
1410 JALVIEWJSLINK: jalviewjsLink.contains(JALVIEW_VERSION) ? "true" : "false",
1411 JVL_HEADER: oldJvl.contains(JALVIEW_VERSION) ? "jvl: true" : ""
1418 inputs.file(oldJvlFile)
1419 inputs.dir(hugoTemplatesDir)
1420 inputs.property("JALVIEW_VERSION", { JALVIEW_VERSION })
1421 inputs.property("CHANNEL", { CHANNEL })
1424 def getMdDate(File mdFile) {
1425 return mdFileComponents(mdFile, true)
1428 def getMdSections(String content) {
1430 def sectionContent = ""
1431 def sectionName = null
1432 content.eachLine { line ->
1434 if (m = line =~ /^##([^#].*)$/) {
1435 if (sectionName != null) {
1436 sections[sectionName] = sectionContent
1440 sectionName = m[0][1].trim()
1441 sectionName = sectionName.toLowerCase()
1442 sectionName = sectionName.replaceAll(/ +/, "_")
1443 sectionName = sectionName.replaceAll(/[^a-z0-9_\-]/, "")
1444 } else if (sectionName != null) {
1445 sectionContent += line+"\n"
1448 if (sectionContent != null) {
1449 sections[sectionName] = sectionContent
1455 task copyHelp(type: Copy) {
1456 def inputDir = helpSourceDir
1457 def outputDir = "${helpBuildDir}/${help_dir}"
1461 include('**/*.html')
1465 filter(ReplaceTokens,
1469 'Version-Rel': JALVIEW_VERSION,
1470 'Year-Rel': getDate("yyyy")
1477 exclude('**/*.html')
1484 inputs.dir(inputDir)
1485 outputs.files(helpFile)
1486 outputs.dir(outputDir)
1490 task releasesTemplates {
1492 description "Recreate whatsNew.html and releases.html from markdown files and templates in help"
1496 def releasesTemplateFile = file("${jalviewDir}/${releases_template}")
1497 def whatsnewTemplateFile = file("${jalviewDir}/${whatsnew_template}")
1498 def releasesHtmlFile = file("${helpBuildDir}/${help_dir}/${releases_html}")
1499 def whatsnewHtmlFile = file("${helpBuildDir}/${help_dir}/${whatsnew_html}")
1500 def releasesMdDir = "${jalviewDir}/${releases_dir}"
1501 def whatsnewMdDir = "${jalviewDir}/${whatsnew_dir}"
1504 def releaseMdFile = file("${releasesMdDir}/release-${JALVIEW_VERSION_UNDERSCORES}.md")
1505 def whatsnewMdFile = file("${whatsnewMdDir}/whatsnew-${JALVIEW_VERSION_UNDERSCORES}.md")
1507 if (CHANNEL == "RELEASE") {
1508 if (!releaseMdFile.exists()) {
1509 throw new GradleException("File ${releaseMdFile} must be created for RELEASE")
1511 if (!whatsnewMdFile.exists()) {
1512 throw new GradleException("File ${whatsnewMdFile} must be created for RELEASE")
1516 def releaseFiles = fileTree(dir: releasesMdDir, include: "release-*.md")
1517 def releaseFilesDates = releaseFiles.collectEntries {
1518 [(it): getMdDate(it)]
1520 releaseFiles = releaseFiles.sort { a,b -> releaseFilesDates[a].compareTo(releaseFilesDates[b]) }
1522 def releasesTemplate = releasesTemplateFile.text
1523 def m = releasesTemplate =~ /(?s)__VERSION_LOOP_START__(.*)__VERSION_LOOP_END__/
1524 def versionTemplate = m[0][1]
1526 MutableDataSet options = new MutableDataSet()
1528 def extensions = new ArrayList<>()
1529 options.set(Parser.EXTENSIONS, extensions)
1530 options.set(Parser.HTML_BLOCK_COMMENT_ONLY_FULL_LINE, true)
1532 Parser parser = Parser.builder(options).build()
1533 HtmlRenderer renderer = HtmlRenderer.builder(options).build()
1535 def actualVersions = releaseFiles.collect { rf ->
1536 def (rfMap, rfContent) = mdFileComponents(rf)
1537 return rfMap.version
1539 def versionsHtml = ""
1540 def linkedVersions = []
1541 releaseFiles.reverse().each { rFile ->
1542 def (rMap, rContent) = mdFileComponents(rFile)
1544 def versionLink = ""
1545 def partialVersion = ""
1546 def firstPart = true
1547 rMap.version.split("\\.").each { part ->
1548 def displayPart = ( firstPart ? "" : "." ) + part
1549 partialVersion += displayPart
1551 linkedVersions.contains(partialVersion)
1552 || ( actualVersions.contains(partialVersion) && partialVersion != rMap.version )
1554 versionLink += displayPart
1556 versionLink += "<a id=\"Jalview.${partialVersion}\">${displayPart}</a>"
1557 linkedVersions += partialVersion
1561 def displayDate = releaseFilesDates[rFile].format("dd/MM/yyyy")
1564 def rContentProcessed = ""
1565 rContent.eachLine { line ->
1566 if (lm = line =~ /^(\s*-)(\s*<!--[^>]*?-->)(.*)$/) {
1567 line = "${lm[0][1]}${lm[0][3]}${lm[0][2]}"
1568 } else if (lm = line =~ /^###([^#]+.*)$/) {
1569 line = "_${lm[0][1].trim()}_"
1571 rContentProcessed += line + "\n"
1574 def rContentSections = getMdSections(rContentProcessed)
1575 def rVersion = versionTemplate
1576 if (rVersion != "") {
1577 def rNewFeatures = rContentSections["new_features"]
1578 def rIssuesResolved = rContentSections["issues_resolved"]
1579 Node newFeaturesNode = parser.parse(rNewFeatures)
1580 String newFeaturesHtml = renderer.render(newFeaturesNode)
1581 Node issuesResolvedNode = parser.parse(rIssuesResolved)
1582 String issuesResolvedHtml = renderer.render(issuesResolvedNode)
1583 rVersion = hugoTemplateSubstitutions(rVersion,
1585 VERSION: rMap.version,
1586 VERSION_LINK: versionLink,
1587 DISPLAY_DATE: displayDate,
1588 NEW_FEATURES: newFeaturesHtml,
1589 ISSUES_RESOLVED: issuesResolvedHtml
1592 versionsHtml += rVersion
1596 releasesTemplate = releasesTemplate.replaceAll("(?s)__VERSION_LOOP_START__.*__VERSION_LOOP_END__", versionsHtml)
1597 releasesTemplate = hugoTemplateSubstitutions(releasesTemplate)
1598 releasesHtmlFile.text = releasesTemplate
1600 if (whatsnewMdFile.exists()) {
1601 def wnDisplayDate = releaseFilesDates[releaseMdFile] != null ? releaseFilesDates[releaseMdFile].format("dd MMMM yyyy") : ""
1602 def whatsnewMd = hugoTemplateSubstitutions(whatsnewMdFile.text)
1603 Node whatsnewNode = parser.parse(whatsnewMd)
1604 String whatsnewHtml = renderer.render(whatsnewNode)
1605 whatsnewHtml = whatsnewTemplateFile.text.replaceAll("__WHATS_NEW__", whatsnewHtml)
1606 whatsnewHtmlFile.text = hugoTemplateSubstitutions(whatsnewHtml,
1608 VERSION: JALVIEW_VERSION,
1609 DISPLAY_DATE: wnDisplayDate
1612 } else if (gradle.taskGraph.hasTask(":linkCheck")) {
1613 whatsnewHtmlFile.text = "Development build " + getDate("yyyy-MM-dd HH:mm:ss")
1618 inputs.file(releasesTemplateFile)
1619 inputs.file(whatsnewTemplateFile)
1620 inputs.dir(releasesMdDir)
1621 inputs.dir(whatsnewMdDir)
1622 outputs.file(releasesHtmlFile)
1623 outputs.file(whatsnewHtmlFile)
1627 task copyResources(type: Copy) {
1629 description = "Copy (and make text substitutions in) the resources dir to the build area"
1631 def inputDir = resourceDir
1632 def outputDir = resourcesBuildDir
1636 include('**/*.html')
1638 filter(ReplaceTokens,
1642 'Version-Rel': JALVIEW_VERSION,
1643 'Year-Rel': getDate("yyyy")
1650 exclude('**/*.html')
1655 inputs.dir(inputDir)
1656 outputs.dir(outputDir)
1659 task copyChannelResources(type: Copy) {
1660 dependsOn copyResources
1662 description = "Copy the channel resources dir to the build resources area"
1664 def inputDir = "${channelDir}/${resource_dir}"
1665 def outputDir = resourcesBuildDir
1667 include(channel_props)
1668 filter(ReplaceTokens,
1672 'SUFFIX': channelSuffix
1677 exclude(channel_props)
1681 inputs.dir(inputDir)
1682 outputs.dir(outputDir)
1685 task createBuildProperties(type: WriteProperties) {
1686 dependsOn copyResources
1688 description = "Create the ${buildProperties} file"
1690 inputs.dir(sourceDir)
1691 inputs.dir(resourcesBuildDir)
1692 outputFile (buildProperties)
1693 // taking time specific comment out to allow better incremental builds
1694 comment "--Jalview Build Details--\n"+getDate("yyyy-MM-dd HH:mm:ss")
1695 //comment "--Jalview Build Details--\n"+getDate("yyyy-MM-dd")
1696 property "BUILD_DATE", getDate("HH:mm:ss dd MMMM yyyy")
1697 property "VERSION", JALVIEW_VERSION
1698 property "INSTALLATION", INSTALLATION+" git-commit:"+gitHash+" ["+gitBranch+"]"
1699 property "JAVA_COMPILE_VERSION", JAVA_INTEGER_VERSION
1700 if (getdownSetAppBaseProperty) {
1701 property "GETDOWNAPPBASE", getdownAppBase
1702 property "GETDOWNAPPDISTDIR", getdownAppDistDir
1704 outputs.file(outputFile)
1708 task buildIndices(type: JavaExec) {
1710 classpath = sourceSets.main.compileClasspath
1711 main = "com.sun.java.help.search.Indexer"
1712 workingDir = "${helpBuildDir}/${help_dir}"
1715 inputs.dir("${workingDir}/${argDir}")
1717 outputs.dir("${classesDir}/doc")
1718 outputs.dir("${classesDir}/help")
1719 outputs.file("${workingDir}/JavaHelpSearch/DOCS")
1720 outputs.file("${workingDir}/JavaHelpSearch/DOCS.TAB")
1721 outputs.file("${workingDir}/JavaHelpSearch/OFFSETS")
1722 outputs.file("${workingDir}/JavaHelpSearch/POSITIONS")
1723 outputs.file("${workingDir}/JavaHelpSearch/SCHEMA")
1724 outputs.file("${workingDir}/JavaHelpSearch/TMAP")
1727 task buildResources {
1728 dependsOn copyResources
1729 dependsOn copyChannelResources
1730 dependsOn createBuildProperties
1734 dependsOn buildResources
1737 dependsOn releasesTemplates
1738 dependsOn convertMdFiles
1739 dependsOn buildIndices
1743 compileJava.dependsOn prepare
1744 run.dependsOn compileJava
1745 compileTestJava.dependsOn compileJava
1750 group = "Verification"
1751 description = "Runs all testTaskN tasks)"
1754 dependsOn cloverClasses
1756 dependsOn testClasses
1759 // not running tests in this task
1762 /* testTask0 is the main test task */
1763 task testTask0(type: Test) {
1764 group = "Verification"
1765 description = "The main test task. Runs all non-testTaskN-labelled tests (unless excluded)"
1767 includeGroups testng_groups.split(",")
1768 excludeGroups testng_excluded_groups.split(",")
1769 tasks.withType(Test).matching {it.name.startsWith("testTask") && it.name != name}.all {t -> excludeGroups t.name}
1771 useDefaultListeners=true
1775 /* separated tests */
1776 task testTask1(type: Test) {
1777 group = "Verification"
1778 description = "Tests that need to be isolated from the main test run"
1781 excludeGroups testng_excluded_groups.split(",")
1783 useDefaultListeners=true
1787 task testTask2(type: Test) {
1788 group = "Verification"
1789 description = "Tests that need to be isolated from the main test run"
1792 excludeGroups testng_excluded_groups.split(",")
1794 useDefaultListeners=true
1797 task testTask3(type: Test) {
1798 group = "Verification"
1799 description = "Tests that need to be isolated from the main test run"
1802 excludeGroups testng_excluded_groups.split(",")
1804 useDefaultListeners=true
1808 /* insert more testTaskNs here -- change N to next digit or other string */
1810 task testTaskN(type: Test) {
1811 group = "Verification"
1812 description = "Tests that need to be isolated from the main test run"
1815 excludeGroups testng_excluded_groups.split(",")
1817 useDefaultListeners=true
1823 * adapted from https://medium.com/@wasyl/pretty-tests-summary-in-gradle-744804dd676c
1824 * to summarise test results from all Test tasks
1826 /* START of test tasks results summary */
1827 import groovy.time.TimeCategory
1828 import org.gradle.api.tasks.testing.logging.TestExceptionFormat
1829 import org.gradle.api.tasks.testing.logging.TestLogEvent
1830 rootProject.ext.testsResults = [] // Container for tests summaries
1832 tasks.withType(Test).matching {t -> t.getName().startsWith("testTask")}.all { testTask ->
1834 // from original test task
1836 dependsOn cloverClasses
1838 dependsOn testClasses //?
1841 // run main tests first
1842 if (!testTask.name.equals("testTask0"))
1843 testTask.mustRunAfter "testTask0"
1845 testTask.testLogging { logging ->
1846 events TestLogEvent.FAILED
1847 // TestLogEvent.SKIPPED,
1848 // TestLogEvent.STANDARD_OUT,
1849 // TestLogEvent.STANDARD_ERROR
1851 exceptionFormat TestExceptionFormat.FULL
1854 showStackTraces true
1856 showStandardStreams true
1858 info.events = [ TestLogEvent.FAILED ]
1861 if (OperatingSystem.current().isMacOsX()) {
1862 testTask.systemProperty "apple.awt.UIElement", "true"
1863 testTask.environment "JAVA_TOOL_OPTIONS", "-Dapple.awt.UIElement=true"
1867 ignoreFailures = true // Always try to run all tests for all modules
1869 afterSuite { desc, result ->
1871 return // Only summarize results for whole modules
1873 def resultsInfo = [testTask.project.name, testTask.name, result, TimeCategory.minus(new Date(result.endTime), new Date(result.startTime)), testTask.reports.html.entryPoint]
1875 rootProject.ext.testsResults.add(resultsInfo)
1878 // from original test task
1879 maxHeapSize = "1024m"
1881 workingDir = jalviewDir
1882 def testLaf = project.findProperty("test_laf")
1883 if (testLaf != null) {
1884 println("Setting Test LaF to '${testLaf}'")
1885 systemProperty "laf", testLaf
1887 def testHiDPIScale = project.findProperty("test_HiDPIScale")
1888 if (testHiDPIScale != null) {
1889 println("Setting Test HiDPI Scale to '${testHiDPIScale}'")
1890 systemProperty "sun.java2d.uiScale", testHiDPIScale
1892 sourceCompatibility = compile_source_compatibility
1893 targetCompatibility = compile_target_compatibility
1894 jvmArgs += additional_compiler_args
1897 // this is not perfect yet -- we should only add the commandLineIncludePatterns to the
1898 // testTasks that include the tests, and exclude all from the others.
1899 // get --test argument
1900 filter.commandLineIncludePatterns = test.filter.commandLineIncludePatterns
1901 // do something with testTask.getCandidateClassFiles() to see if the test should silently finish because of the
1902 // commandLineIncludePatterns not matching anything. Instead we are doing setFailOnNoMatchingTests(false) below
1906 println("Running tests " + (useClover?"WITH":"WITHOUT") + " clover")
1911 /* don't fail on no matching tests (so --tests will run across all testTasks) */
1912 testTask.filter.setFailOnNoMatchingTests(false)
1914 /* ensure the "test" task dependsOn all the testTasks */
1915 test.dependsOn testTask
1918 gradle.buildFinished {
1919 def allResults = rootProject.ext.testsResults
1921 if (!allResults.isEmpty()) {
1922 printResults allResults
1923 allResults.each {r ->
1924 if (r[2].resultType == TestResult.ResultType.FAILURE)
1925 throw new GradleException("Failed tests!")
1930 private static String colString(styler, col, colour, text) {
1931 return col?"${styler[colour](text)}":text
1934 private static String getSummaryLine(s, pn, tn, rt, rc, rs, rf, rsk, t, col) {
1935 def colour = 'black'
1943 case TestResult.ResultType.SUCCESS:
1946 case TestResult.ResultType.FAILURE:
1954 StringBuilder sb = new StringBuilder()
1958 sb.append(" results: ")
1959 sb.append(colString(s, col && !nocol, colour, text))
1961 sb.append("${rc} tests, ")
1962 sb.append(colString(s, col && rs > 0, 'green', rs))
1963 sb.append(" successes, ")
1964 sb.append(colString(s, col && rf > 0, 'red', rf))
1965 sb.append(" failures, ")
1966 sb.append("${rsk} skipped) in ${t}")
1967 return sb.toString()
1970 private static void printResults(allResults) {
1972 // styler from https://stackoverflow.com/a/56139852
1973 def styler = 'black red green yellow blue magenta cyan white'.split().toList().withIndex(30).collectEntries { key, val -> [(key) : { "\033[${val}m${it}\033[0m" }] }
1976 def failedTests = false
1977 def summaryLines = []
1979 def totalsuccess = 0
1982 def totaltime = TimeCategory.getSeconds(0)
1983 // sort on project name then task name
1984 allResults.sort {a, b -> a[0] == b[0]? a[1]<=>b[1]:a[0] <=> b[0]}.each {
1985 def projectName = it[0]
1986 def taskName = it[1]
1990 def summaryCol = getSummaryLine(styler, projectName, taskName, result.resultType, result.testCount, result.successfulTestCount, result.failedTestCount, result.skippedTestCount, time, true)
1991 def summaryPlain = getSummaryLine(styler, projectName, taskName, result.resultType, result.testCount, result.successfulTestCount, result.failedTestCount, result.skippedTestCount, time, false)
1992 def reportLine = "Report file: ${report}"
1993 def ls = summaryPlain.length()
1994 def lr = reportLine.length()
1995 def m = [ls, lr].max()
1998 def info = [ls, summaryCol, reportLine]
1999 summaryLines.add(info)
2000 failedTests |= result.resultType == TestResult.ResultType.FAILURE
2001 totalcount += result.testCount
2002 totalsuccess += result.successfulTestCount
2003 totalfail += result.failedTestCount
2004 totalskip += result.skippedTestCount
2007 def totalSummaryCol = getSummaryLine(styler, "OVERALL", "", failedTests?TestResult.ResultType.FAILURE:TestResult.ResultType.SUCCESS, totalcount, totalsuccess, totalfail, totalskip, totaltime, true)
2008 def totalSummaryPlain = getSummaryLine(styler, "OVERALL", "", failedTests?TestResult.ResultType.FAILURE:TestResult.ResultType.SUCCESS, totalcount, totalsuccess, totalfail, totalskip, totaltime, false)
2009 def tls = totalSummaryPlain.length()
2010 if (tls > maxLength)
2012 def info = [tls, totalSummaryCol, null]
2013 summaryLines.add(info)
2015 def allSummaries = []
2016 for(sInfo : summaryLines) {
2018 def summary = sInfo[1]
2019 def report = sInfo[2]
2021 StringBuilder sb = new StringBuilder()
2022 sb.append("│" + summary + " " * (maxLength - ls) + "│")
2023 if (report != null) {
2024 sb.append("\n│" + report + " " * (maxLength - report.length()) + "│")
2026 allSummaries += sb.toString()
2029 println "┌${"${"─" * maxLength}"}┐"
2030 println allSummaries.join("\n├${"${"─" * maxLength}"}┤\n")
2031 println "└${"${"─" * maxLength}"}┘"
2033 /* END of test tasks results summary */
2036 task compileLinkCheck(type: JavaCompile) {
2038 classpath = files("${jalviewDir}/${utils_dir}")
2039 destinationDir = file("${jalviewDir}/${utils_dir}")
2040 source = fileTree(dir: "${jalviewDir}/${utils_dir}", include: ["HelpLinksChecker.java", "BufferedLineReader.java"])
2042 inputs.file("${jalviewDir}/${utils_dir}/HelpLinksChecker.java")
2043 inputs.file("${jalviewDir}/${utils_dir}/HelpLinksChecker.java")
2044 outputs.file("${jalviewDir}/${utils_dir}/HelpLinksChecker.class")
2045 outputs.file("${jalviewDir}/${utils_dir}/BufferedLineReader.class")
2049 task linkCheck(type: JavaExec) {
2051 dependsOn compileLinkCheck
2053 def helpLinksCheckerOutFile = file("${jalviewDir}/${utils_dir}/HelpLinksChecker.out")
2054 classpath = files("${jalviewDir}/${utils_dir}")
2055 main = "HelpLinksChecker"
2056 workingDir = "${helpBuildDir}"
2057 args = [ "${helpBuildDir}/${help_dir}", "-nointernet" ]
2059 def outFOS = new FileOutputStream(helpLinksCheckerOutFile, false) // false == don't append
2060 standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
2063 errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
2067 inputs.dir(helpBuildDir)
2068 outputs.file(helpLinksCheckerOutFile)
2072 // import the pubhtmlhelp target
2073 ant.properties.basedir = "${jalviewDir}"
2074 ant.properties.helpBuildDir = "${helpBuildDir}/${help_dir}"
2075 ant.importBuild "${utils_dir}/publishHelp.xml"
2078 task cleanPackageDir(type: Delete) {
2080 delete fileTree(dir: "${jalviewDir}/${package_dir}", include: "*.jar")
2090 attributes "Main-Class": main_class,
2091 "Permissions": "all-permissions",
2092 "Application-Name": applicationName,
2093 "Codebase": application_codebase,
2094 "Implementation-Version": JALVIEW_VERSION
2097 def outputDir = "${jalviewDir}/${package_dir}"
2098 destinationDirectory = file(outputDir)
2099 archiveFileName = rootProject.name+".jar"
2100 duplicatesStrategy "EXCLUDE"
2107 exclude "**/*.jar.*"
2109 inputs.dir(sourceSets.main.java.outputDir)
2110 sourceSets.main.resources.srcDirs.each{ dir ->
2113 outputs.file("${outputDir}/${archiveFileName}")
2117 task copyJars(type: Copy) {
2118 from fileTree(dir: classesDir, include: "**/*.jar").files
2119 into "${jalviewDir}/${package_dir}"
2123 // doing a Sync instead of Copy as Copy doesn't deal with "outputs" very well
2124 task syncJars(type: Sync) {
2126 from fileTree(dir: "${jalviewDir}/${libDistDir}", include: "**/*.jar").files
2127 into "${jalviewDir}/${package_dir}"
2129 include jar.archiveFileName.getOrNull()
2136 description = "Put all required libraries in dist"
2137 // order of "cleanPackageDir", "copyJars", "jar" important!
2138 jar.mustRunAfter cleanPackageDir
2139 syncJars.mustRunAfter cleanPackageDir
2140 dependsOn cleanPackageDir
2143 outputs.dir("${jalviewDir}/${package_dir}")
2148 dependsOn cleanPackageDir
2154 task launcherJar(type: Jar) {
2157 "Main-Class": shadow_jar_main_class,
2158 "Implementation-Version": JALVIEW_VERSION,
2159 "Application-Name": applicationName
2165 group = "distribution"
2166 description = "Create a single jar file with all dependency libraries merged. Can be run with java -jar"
2171 def jarFiles = fileTree(dir: "${jalviewDir}/${libDistDir}", include: "*.jar", exclude: "regex.jar").getFiles()
2172 def groovyJars = jarFiles.findAll {it1 -> file(it1).getName().startsWith("groovy-swing")}
2173 def otherJars = jarFiles.findAll {it2 -> !file(it2).getName().startsWith("groovy-swing")}
2178 // shadowJar manifest must inheritFrom another Jar task. Can't set attributes here.
2179 inheritFrom(project.tasks.launcherJar.manifest)
2181 // we need to include the groovy-swing Include-Package for it to run in the shadowJar
2183 def jarFileManifests = []
2184 groovyJars.each { jarFile ->
2185 def mf = zipTree(jarFile).getFiles().find { it.getName().equals("MANIFEST.MF") }
2187 jarFileManifests += mf
2191 from (jarFileManifests) {
2192 eachEntry { details ->
2193 if (!details.key.equals("Import-Package")) {
2201 duplicatesStrategy "INCLUDE"
2203 // this mainClassName is mandatory but gets ignored due to manifest created in doFirst{}. Set the Main-Class as an attribute in launcherJar instead
2204 mainClassName = shadow_jar_main_class
2206 classifier = "all-"+JALVIEW_VERSION+"-j"+JAVA_VERSION
2210 task getdownImagesCopy() {
2211 inputs.dir getdownImagesDir
2212 outputs.dir getdownImagesBuildDir
2216 from(getdownImagesDir) {
2217 include("*getdown*.png")
2219 into getdownImagesBuildDir
2224 task getdownImagesProcess() {
2225 dependsOn getdownImagesCopy
2228 if (backgroundImageText) {
2229 if (convertBinary == null) {
2230 throw new StopExecutionException("No ImageMagick convert binary installed at '${convertBinaryExpectedLocation}'")
2232 if (!project.hasProperty("getdown_background_image_text_suffix_cmd")) {
2233 throw new StopExecutionException("No property 'getdown_background_image_text_suffix_cmd' defined. See channel_gradle.properties for channel ${CHANNEL}")
2235 fileTree(dir: getdownImagesBuildDir, include: "*background*.png").getFiles().each { file ->
2237 executable convertBinary
2240 '-font', getdown_background_image_text_font,
2241 '-fill', getdown_background_image_text_colour,
2242 '-draw', sprintf(getdown_background_image_text_suffix_cmd, channelSuffix),
2243 '-draw', sprintf(getdown_background_image_text_commit_cmd, "git-commit: ${gitHash}"),
2244 '-draw', sprintf(getdown_background_image_text_date_cmd, getDate("yyyy-MM-dd HH:mm:ss")),
2253 task getdownImages() {
2254 dependsOn getdownImagesProcess
2257 task getdownWebsiteBuild() {
2258 group = "distribution"
2259 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."
2261 dependsOn getdownImages
2266 def getdownWebsiteResourceFilenames = []
2267 def getdownResourceDir = getdownResourceDir
2268 def getdownResourceFilenames = []
2271 // clean the getdown website and files dir before creating getdown folders
2272 delete getdownAppBaseDir
2273 delete getdownFilesDir
2276 from buildProperties
2277 rename(file(buildProperties).getName(), getdown_build_properties)
2280 getdownWebsiteResourceFilenames += "${getdownAppDistDir}/${getdown_build_properties}"
2283 from channelPropsFile
2284 filter(ReplaceTokens,
2288 'SUFFIX': channelSuffix
2291 into getdownAppBaseDir
2293 getdownWebsiteResourceFilenames += file(channelPropsFile).getName()
2295 // set some getdownTxt_ properties then go through all properties looking for getdownTxt_...
2296 def props = project.properties.sort { it.key }
2297 if (getdownAltJavaMinVersion != null && getdownAltJavaMinVersion.length() > 0) {
2298 props.put("getdown_txt_java_min_version", getdownAltJavaMinVersion)
2300 if (getdownAltJavaMaxVersion != null && getdownAltJavaMaxVersion.length() > 0) {
2301 props.put("getdown_txt_java_max_version", getdownAltJavaMaxVersion)
2303 if (getdownAltMultiJavaLocation != null && getdownAltMultiJavaLocation.length() > 0) {
2304 props.put("getdown_txt_multi_java_location", getdownAltMultiJavaLocation)
2306 if (getdownImagesBuildDir != null && file(getdownImagesBuildDir).exists()) {
2307 props.put("getdown_txt_ui.background_image", "${getdownImagesBuildDir}/${getdown_background_image}")
2308 props.put("getdown_txt_ui.instant_background_image", "${getdownImagesBuildDir}/${getdown_instant_background_image}")
2309 props.put("getdown_txt_ui.error_background", "${getdownImagesBuildDir}/${getdown_error_background}")
2310 props.put("getdown_txt_ui.progress_image", "${getdownImagesBuildDir}/${getdown_progress_image}")
2311 props.put("getdown_txt_ui.icon", "${getdownImagesDir}/${getdown_icon}")
2312 props.put("getdown_txt_ui.mac_dock_icon", "${getdownImagesDir}/${getdown_mac_dock_icon}")
2315 props.put("getdown_txt_title", jalview_name)
2316 props.put("getdown_txt_ui.name", applicationName)
2318 // start with appbase
2319 getdownTextLines += "appbase = ${getdownAppBase}"
2320 props.each{ prop, val ->
2321 if (prop.startsWith("getdown_txt_") && val != null) {
2322 if (prop.startsWith("getdown_txt_multi_")) {
2323 def key = prop.substring(18)
2324 val.split(",").each{ v ->
2325 def line = "${key} = ${v}"
2326 getdownTextLines += line
2329 // file values rationalised
2330 if (val.indexOf('/') > -1 || prop.startsWith("getdown_txt_resource")) {
2332 if (val.indexOf('/') == 0) {
2335 } else if (val.indexOf('/') > 0) {
2336 // relative path (relative to jalviewDir)
2337 r = file( "${jalviewDir}/${val}" )
2340 val = "${getdown_resource_dir}/" + r.getName()
2341 getdownWebsiteResourceFilenames += val
2342 getdownResourceFilenames += r.getPath()
2345 if (! prop.startsWith("getdown_txt_resource")) {
2346 def line = prop.substring(12) + " = ${val}"
2347 getdownTextLines += line
2353 getdownWebsiteResourceFilenames.each{ filename ->
2354 getdownTextLines += "resource = ${filename}"
2356 getdownResourceFilenames.each{ filename ->
2359 into getdownResourceDir
2363 def getdownWrapperScripts = [ getdown_bash_wrapper_script, getdown_powershell_wrapper_script, getdown_batch_wrapper_script ]
2364 getdownWrapperScripts.each{ script ->
2365 def s = file( "${jalviewDir}/utils/getdown/${getdown_wrapper_script_dir}/${script}" )
2369 into "${getdownAppBaseDir}/${getdown_wrapper_script_dir}"
2371 getdownTextLines += "xresource = ${getdown_wrapper_script_dir}/${script}"
2376 fileTree(file(package_dir)).each{ f ->
2377 if (f.isDirectory()) {
2378 def files = fileTree(dir: f, include: ["*"]).getFiles()
2380 } else if (f.exists()) {
2384 def jalviewJar = jar.archiveFileName.getOrNull()
2385 // put jalview.jar first for CLASSPATH and .properties files reasons
2386 codeFiles.sort{a, b -> ( a.getName() == jalviewJar ? -1 : ( b.getName() == jalviewJar ? 1 : a <=> b ) ) }.each{f ->
2387 def name = f.getName()
2388 def line = "code = ${getdownAppDistDir}/${name}"
2389 getdownTextLines += line
2396 // NOT USING MODULES YET, EVERYTHING SHOULD BE IN dist
2398 if (JAVA_VERSION.equals("11")) {
2399 def j11libFiles = fileTree(dir: "${jalviewDir}/${j11libDir}", include: ["*.jar"]).getFiles()
2400 j11libFiles.sort().each{f ->
2401 def name = f.getName()
2402 def line = "code = ${getdown_j11lib_dir}/${name}"
2403 getdownTextLines += line
2406 into getdownJ11libDir
2412 // 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.
2413 //getdownTextLines += "class = " + file(getdownLauncher).getName()
2414 getdownTextLines += "resource = ${getdown_launcher_new}"
2415 getdownTextLines += "class = ${main_class}"
2416 // Not setting these properties in general so that getdownappbase and getdowndistdir will default to release version in jalview.bin.Cache
2417 if (getdownSetAppBaseProperty) {
2418 getdownTextLines += "jvmarg = -Dgetdowndistdir=${getdownAppDistDir}"
2419 getdownTextLines += "jvmarg = -Dgetdownappbase=${getdownAppBase}"
2422 def getdownTxt = file("${getdownAppBaseDir}/getdown.txt")
2423 getdownTxt.write(getdownTextLines.join("\n"))
2425 getdownLaunchJvl = getdown_launch_jvl_name + ( (jvlChannelName != null && jvlChannelName.length() > 0)?"-${jvlChannelName}":"" ) + ".jvl"
2426 def launchJvl = file("${getdownAppBaseDir}/${getdownLaunchJvl}")
2427 launchJvl.write("appbase=${getdownAppBase}")
2429 // files going into the getdown website dir: getdown-launcher.jar
2431 from getdownLauncher
2432 rename(file(getdownLauncher).getName(), getdown_launcher_new)
2433 into getdownAppBaseDir
2436 // files going into the getdown website dir: getdown-launcher(-local).jar
2438 from getdownLauncher
2439 if (file(getdownLauncher).getName() != getdown_launcher) {
2440 rename(file(getdownLauncher).getName(), getdown_launcher)
2442 into getdownAppBaseDir
2445 // files going into the getdown website dir: ./install dir and files
2446 if (! (CHANNEL.startsWith("ARCHIVE") || CHANNEL.startsWith("DEVELOP"))) {
2449 from getdownLauncher
2450 from "${getdownAppDir}/${getdown_build_properties}"
2451 if (file(getdownLauncher).getName() != getdown_launcher) {
2452 rename(file(getdownLauncher).getName(), getdown_launcher)
2454 into getdownInstallDir
2457 // and make a copy in the getdown files dir (these are not downloaded by getdown)
2459 from getdownInstallDir
2460 into getdownFilesInstallDir
2464 // files going into the getdown files dir: getdown.txt, getdown-launcher.jar, channel-launch.jvl, build_properties
2468 from getdownLauncher
2469 from "${getdownAppBaseDir}/${getdown_build_properties}"
2470 from "${getdownAppBaseDir}/${channel_props}"
2471 if (file(getdownLauncher).getName() != getdown_launcher) {
2472 rename(file(getdownLauncher).getName(), getdown_launcher)
2474 into getdownFilesDir
2477 // and ./resource (not all downloaded by getdown)
2479 from getdownResourceDir
2480 into "${getdownFilesDir}/${getdown_resource_dir}"
2485 inputs.dir("${jalviewDir}/${package_dir}")
2487 outputs.dir(getdownAppBaseDir)
2488 outputs.dir(getdownFilesDir)
2492 // a helper task to allow getdown digest of any dir: `gradle getdownDigestDir -PDIGESTDIR=/path/to/my/random/getdown/dir
2493 task getdownDigestDir(type: JavaExec) {
2495 description "A task to run a getdown Digest on a dir with getdown.txt. Provide a DIGESTDIR property via -PDIGESTDIR=..."
2497 def digestDirPropertyName = "DIGESTDIR"
2499 classpath = files(getdownLauncher)
2500 def digestDir = findProperty(digestDirPropertyName)
2501 if (digestDir == null) {
2502 throw new GradleException("Must provide a DIGESTDIR value to produce an alternative getdown digest")
2506 main = "com.threerings.getdown.tools.Digester"
2510 task getdownDigest(type: JavaExec) {
2511 group = "distribution"
2512 description = "Digest the getdown website folder"
2514 dependsOn getdownWebsiteBuild
2517 classpath = files(getdownLauncher)
2519 main = "com.threerings.getdown.tools.Digester"
2520 args getdownAppBaseDir
2521 inputs.dir(getdownAppBaseDir)
2522 outputs.file("${getdownAppBaseDir}/digest2.txt")
2527 group = "distribution"
2528 description = "Create the minimal and full getdown app folder for installers and website and create digest file"
2529 dependsOn getdownDigest
2531 if (reportRsyncCommand) {
2532 def fromDir = getdownAppBaseDir + (getdownAppBaseDir.endsWith('/')?'':'/')
2533 def toDir = "${getdown_rsync_dest}/${getdownDir}" + (getdownDir.endsWith('/')?'':'/')
2534 println "LIKELY RSYNC COMMAND:"
2535 println "mkdir -p '$toDir'\nrsync -avh --delete '$fromDir' '$toDir'"
2536 if (RUNRSYNC == "true") {
2538 commandLine "mkdir", "-p", toDir
2541 commandLine "rsync", "-avh", "--delete", fromDir, toDir
2548 task getdownWebsite {
2549 group = "distribution"
2550 description = "A task to create the whole getdown channel website dir including digest file"
2552 dependsOn getdownWebsiteBuild
2553 dependsOn getdownDigest
2556 task getdownArchiveBuild() {
2557 group = "distribution"
2558 description = "Put files in the archive dir to go on the website"
2560 dependsOn getdownWebsiteBuild
2562 def v = "v${JALVIEW_VERSION_UNDERSCORES}"
2563 def vDir = "${getdownArchiveDir}/${v}"
2564 getdownFullArchiveDir = "${vDir}/getdown"
2565 getdownVersionLaunchJvl = "${vDir}/jalview-${v}.jvl"
2567 def vAltDir = "alt_${v}"
2568 def archiveImagesDir = "${jalviewDir}/${channel_properties_dir}/old/images"
2571 // cleanup old "old" dir
2572 delete getdownArchiveDir
2574 def getdownArchiveTxt = file("${getdownFullArchiveDir}/getdown.txt")
2575 getdownArchiveTxt.getParentFile().mkdirs()
2576 def getdownArchiveTextLines = []
2577 def getdownFullArchiveAppBase = "${getdownArchiveAppBase}${getdownArchiveAppBase.endsWith("/")?"":"/"}${v}/getdown/"
2581 from "${getdownAppBaseDir}/${getdownAppDistDir}"
2582 into "${getdownFullArchiveDir}/${vAltDir}"
2585 getdownTextLines.each { line ->
2586 line = line.replaceAll("^(?<s>appbase\\s*=\\s*).*", '${s}'+getdownFullArchiveAppBase)
2587 line = line.replaceAll("^(?<s>(resource|code)\\s*=\\s*)${getdownAppDistDir}/", '${s}'+vAltDir+"/")
2588 line = line.replaceAll("^(?<s>ui.background_image\\s*=\\s*).*\\.png", '${s}'+"${getdown_resource_dir}/jalview_archive_getdown_background.png")
2589 line = line.replaceAll("^(?<s>ui.instant_background_image\\s*=\\s*).*\\.png", '${s}'+"${getdown_resource_dir}/jalview_archive_getdown_background_initialising.png")
2590 line = line.replaceAll("^(?<s>ui.error_background\\s*=\\s*).*\\.png", '${s}'+"${getdown_resource_dir}/jalview_archive_getdown_background_error.png")
2591 line = line.replaceAll("^(?<s>ui.progress_image\\s*=\\s*).*\\.png", '${s}'+"${getdown_resource_dir}/jalview_archive_getdown_progress_bar.png")
2592 // remove the existing resource = resource/ or bin/ lines
2593 if (! line.matches("resource\\s*=\\s*(resource|bin)/.*")) {
2594 getdownArchiveTextLines += line
2598 // the resource dir -- add these files as resource lines in getdown.txt
2600 from "${archiveImagesDir}"
2601 into "${getdownFullArchiveDir}/${getdown_resource_dir}"
2603 getdownArchiveTextLines += "resource = ${getdown_resource_dir}/${file.getName()}"
2607 getdownArchiveTxt.write(getdownArchiveTextLines.join("\n"))
2609 def vLaunchJvl = file(getdownVersionLaunchJvl)
2610 vLaunchJvl.getParentFile().mkdirs()
2611 vLaunchJvl.write("appbase=${getdownFullArchiveAppBase}\n")
2612 def vLaunchJvlPath = vLaunchJvl.toPath().toAbsolutePath()
2613 def jvlLinkPath = file("${vDir}/jalview.jvl").toPath().toAbsolutePath()
2614 // for some reason filepath.relativize(fileInSameDirPath) gives a path to "../" which is wrong
2615 //java.nio.file.Files.createSymbolicLink(jvlLinkPath, jvlLinkPath.relativize(vLaunchJvlPath));
2616 java.nio.file.Files.createSymbolicLink(jvlLinkPath, java.nio.file.Paths.get(".",vLaunchJvl.getName()));
2618 // files going into the getdown files dir: getdown.txt, getdown-launcher.jar, channel-launch.jvl, build_properties
2620 from getdownLauncher
2621 from "${getdownAppBaseDir}/${getdownLaunchJvl}"
2622 from "${getdownAppBaseDir}/${getdown_launcher_new}"
2623 from "${getdownAppBaseDir}/${channel_props}"
2624 if (file(getdownLauncher).getName() != getdown_launcher) {
2625 rename(file(getdownLauncher).getName(), getdown_launcher)
2627 into getdownFullArchiveDir
2633 task getdownArchiveDigest(type: JavaExec) {
2634 group = "distribution"
2635 description = "Digest the getdown archive folder"
2637 dependsOn getdownArchiveBuild
2640 classpath = files(getdownLauncher)
2641 args getdownFullArchiveDir
2643 main = "com.threerings.getdown.tools.Digester"
2644 inputs.dir(getdownFullArchiveDir)
2645 outputs.file("${getdownFullArchiveDir}/digest2.txt")
2648 task getdownArchive() {
2649 group = "distribution"
2650 description = "Build the website archive dir with getdown digest"
2652 dependsOn getdownArchiveBuild
2653 dependsOn getdownArchiveDigest
2656 tasks.withType(JavaCompile) {
2657 options.encoding = 'UTF-8'
2663 delete getdownAppBaseDir
2664 delete getdownFilesDir
2665 delete getdownArchiveDir
2671 if (file(install4jHomeDir).exists()) {
2673 } else if (file(System.getProperty("user.home")+"/buildtools/install4j").exists()) {
2674 install4jHomeDir = System.getProperty("user.home")+"/buildtools/install4j"
2675 } else if (file("/Applications/install4j.app/Contents/Resources/app").exists()) {
2676 install4jHomeDir = "/Applications/install4j.app/Contents/Resources/app"
2678 installDir(file(install4jHomeDir))
2680 mediaTypes = Arrays.asList(install4j_media_types.split(","))
2684 task copyInstall4jTemplate {
2685 def install4jTemplateFile = file("${install4jDir}/${install4j_template}")
2686 def install4jFileAssociationsFile = file("${install4jDir}/${install4j_installer_file_associations}")
2687 inputs.file(install4jTemplateFile)
2688 inputs.file(install4jFileAssociationsFile)
2689 inputs.property("CHANNEL", { CHANNEL })
2690 outputs.file(install4jConfFile)
2693 def install4jConfigXml = new XmlParser().parse(install4jTemplateFile)
2695 // turn off code signing if no OSX_KEYPASS
2696 if (OSX_KEYPASS == "") {
2697 install4jConfigXml.'**'.codeSigning.each { codeSigning ->
2698 codeSigning.'@macEnabled' = "false"
2700 install4jConfigXml.'**'.windows.each { windows ->
2701 windows.'@runPostProcessor' = "false"
2705 // disable install screen for OSX dmg (for 2.11.2.0)
2706 install4jConfigXml.'**'.macosArchive.each { macosArchive ->
2707 macosArchive.attributes().remove('executeSetupApp')
2708 macosArchive.attributes().remove('setupAppId')
2711 // turn off checksum creation for LOCAL channel
2712 def e = install4jConfigXml.application[0]
2713 e.'@createChecksums' = string(install4jCheckSums)
2715 // put file association actions where placeholder action is
2716 def install4jFileAssociationsText = install4jFileAssociationsFile.text
2717 def fileAssociationActions = new XmlParser().parseText("<actions>${install4jFileAssociationsText}</actions>")
2718 install4jConfigXml.'**'.action.any { a -> // .any{} stops after the first one that returns true
2719 if (a.'@name' == 'EXTENSIONS_REPLACED_BY_GRADLE') {
2720 def parent = a.parent()
2722 fileAssociationActions.each { faa ->
2725 // don't need to continue in .any loop once replacements have been made
2730 // use Windows Program Group with Examples folder for RELEASE, and Program Group without Examples for everything else
2731 // NB we're deleting the /other/ one!
2732 // Also remove the examples subdir from non-release versions
2733 def customizedIdToDelete = "PROGRAM_GROUP_RELEASE"
2734 // 2.11.1.0 NOT releasing with the Examples folder in the Program Group
2735 if (false && CHANNEL=="RELEASE") { // remove 'false && ' to include Examples folder in RELEASE channel
2736 customizedIdToDelete = "PROGRAM_GROUP_NON_RELEASE"
2738 // remove the examples subdir from Full File Set
2739 def files = install4jConfigXml.files[0]
2740 def fileset = files.filesets.fileset.find { fs -> fs.'@customizedId' == "FULL_FILE_SET" }
2741 def root = files.roots.root.find { r -> r.'@fileset' == fileset.'@id' }
2742 def mountPoint = files.mountPoints.mountPoint.find { mp -> mp.'@root' == root.'@id' }
2743 def dirEntry = files.entries.dirEntry.find { de -> de.'@mountPoint' == mountPoint.'@id' && de.'@subDirectory' == "examples" }
2744 dirEntry.parent().remove(dirEntry)
2746 install4jConfigXml.'**'.action.any { a ->
2747 if (a.'@customizedId' == customizedIdToDelete) {
2748 def parent = a.parent()
2754 // write install4j file
2755 install4jConfFile.text = XmlUtil.serialize(install4jConfigXml)
2762 delete install4jConfFile
2766 task cleanInstallersDataFiles {
2767 def installersOutputTxt = file("${jalviewDir}/${install4jBuildDir}/output.txt")
2768 def installersSha256 = file("${jalviewDir}/${install4jBuildDir}/sha256sums")
2769 def hugoDataJsonFile = file("${jalviewDir}/${install4jBuildDir}/installers-${JALVIEW_VERSION_UNDERSCORES}.json")
2771 delete installersOutputTxt
2772 delete installersSha256
2773 delete hugoDataJsonFile
2777 task install4jDMGBackgroundImageCopy {
2778 inputs.file "${install4jDMGBackgroundImageDir}/${install4jDMGBackgroundImageFile}"
2779 outputs.dir "${install4jDMGBackgroundImageBuildDir}"
2782 from(install4jDMGBackgroundImageDir) {
2783 include(install4jDMGBackgroundImageFile)
2785 into install4jDMGBackgroundImageBuildDir
2790 task install4jDMGBackgroundImageProcess {
2791 dependsOn install4jDMGBackgroundImageCopy
2794 if (backgroundImageText) {
2795 if (convertBinary == null) {
2796 throw new StopExecutionException("No ImageMagick convert binary installed at '${convertBinaryExpectedLocation}'")
2798 if (!project.hasProperty("install4j_background_image_text_suffix_cmd")) {
2799 throw new StopExecutionException("No property 'install4j_background_image_text_suffix_cmd' defined. See channel_gradle.properties for channel ${CHANNEL}")
2801 fileTree(dir: install4jDMGBackgroundImageBuildDir, include: "*.png").getFiles().each { file ->
2803 executable convertBinary
2806 '-font', install4j_background_image_text_font,
2807 '-fill', install4j_background_image_text_colour,
2808 '-draw', sprintf(install4j_background_image_text_suffix_cmd, channelSuffix),
2809 '-draw', sprintf(install4j_background_image_text_commit_cmd, "git-commit: ${gitHash}"),
2810 '-draw', sprintf(install4j_background_image_text_date_cmd, getDate("yyyy-MM-dd HH:mm:ss")),
2819 task install4jDMGBackgroundImage {
2820 dependsOn install4jDMGBackgroundImageProcess
2823 task installerFiles(type: com.install4j.gradle.Install4jTask) {
2824 group = "distribution"
2825 description = "Create the install4j installers"
2827 dependsOn copyInstall4jTemplate
2828 dependsOn cleanInstallersDataFiles
2829 dependsOn install4jDMGBackgroundImage
2831 projectFile = install4jConfFile
2833 // create an md5 for the input files to use as version for install4j conf file
2834 def digest = MessageDigest.getInstance("MD5")
2836 (file("${install4jDir}/${install4j_template}").text +
2837 file("${install4jDir}/${install4j_info_plist_file_associations}").text +
2838 file("${install4jDir}/${install4j_installer_file_associations}").text).bytes)
2839 def filesMd5 = new BigInteger(1, digest.digest()).toString(16)
2840 if (filesMd5.length() >= 8) {
2841 filesMd5 = filesMd5.substring(0,8)
2843 def install4jTemplateVersion = "${JALVIEW_VERSION}_F${filesMd5}_C${gitHash}"
2846 'JALVIEW_NAME': jalview_name,
2847 'JALVIEW_APPLICATION_NAME': applicationName,
2848 'JALVIEW_DIR': "../..",
2849 'OSX_KEYSTORE': OSX_KEYSTORE,
2850 'OSX_APPLEID': OSX_APPLEID,
2851 'OSX_ALTOOLPASS': OSX_ALTOOLPASS,
2852 'JSIGN_SH': JSIGN_SH,
2853 'JRE_DIR': getdown_app_dir_java,
2854 'INSTALLER_TEMPLATE_VERSION': install4jTemplateVersion,
2855 'JALVIEW_VERSION': JALVIEW_VERSION,
2856 'JAVA_MIN_VERSION': JAVA_MIN_VERSION,
2857 'JAVA_MAX_VERSION': JAVA_MAX_VERSION,
2858 'JAVA_VERSION': JAVA_VERSION,
2859 'JAVA_INTEGER_VERSION': JAVA_INTEGER_VERSION,
2860 'VERSION': JALVIEW_VERSION,
2861 'COPYRIGHT_MESSAGE': install4j_copyright_message,
2862 'BUNDLE_ID': install4jBundleId,
2863 'INTERNAL_ID': install4jInternalId,
2864 'WINDOWS_APPLICATION_ID': install4jWinApplicationId,
2865 'MACOS_DMG_DS_STORE': install4jDMGDSStore,
2866 'MACOS_DMG_BG_IMAGE': "${install4jDMGBackgroundImageBuildDir}/${install4jDMGBackgroundImageFile}",
2867 'WRAPPER_LINK': getdownWrapperLink,
2868 'BASH_WRAPPER_SCRIPT': getdown_bash_wrapper_script,
2869 'POWERSHELL_WRAPPER_SCRIPT': getdown_powershell_wrapper_script,
2870 'BATCH_WRAPPER_SCRIPT': getdown_batch_wrapper_script,
2871 'WRAPPER_SCRIPT_BIN_DIR': getdown_wrapper_script_dir,
2872 'INSTALLER_NAME': install4jInstallerName,
2873 'INSTALL4J_UTILS_DIR': install4j_utils_dir,
2874 'GETDOWN_CHANNEL_DIR': getdownChannelDir,
2875 'GETDOWN_FILES_DIR': getdown_files_dir,
2876 'GETDOWN_RESOURCE_DIR': getdown_resource_dir,
2877 'GETDOWN_DIST_DIR': getdownAppDistDir,
2878 'GETDOWN_ALT_DIR': getdown_app_dir_alt,
2879 'GETDOWN_INSTALL_DIR': getdown_install_dir,
2880 'INFO_PLIST_FILE_ASSOCIATIONS_FILE': install4j_info_plist_file_associations,
2881 'BUILD_DIR': install4jBuildDir,
2882 'APPLICATION_CATEGORIES': install4j_application_categories,
2883 'APPLICATION_FOLDER': install4jApplicationFolder,
2884 'UNIX_APPLICATION_FOLDER': install4jUnixApplicationFolder,
2885 'EXECUTABLE_NAME': install4jExecutableName,
2886 'EXTRA_SCHEME': install4jExtraScheme,
2887 'MAC_ICONS_FILE': install4jMacIconsFile,
2888 'WINDOWS_ICONS_FILE': install4jWindowsIconsFile,
2889 'PNG_ICON_FILE': install4jPngIconFile,
2890 'BACKGROUND': install4jBackground,
2895 'windows': 'WINDOWS',
2899 // these are the bundled OS/architecture VMs needed by install4j
2902 [ "mac", "aarch64" ],
2903 [ "windows", "x64" ],
2905 [ "linux", "aarch64" ]
2907 osArch.forEach { os, arch ->
2908 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)
2909 // N.B. For some reason install4j requires the below filename to have underscores and not hyphens
2910 // otherwise running `gradle installers` generates a non-useful error:
2911 // `install4j: compilation failed. Reason: java.lang.NumberFormatException: For input string: "windows"`
2912 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)
2915 //println("INSTALL4J VARIABLES:")
2916 //variables.each{k,v->println("${k}=${v}")}
2918 destination = "${jalviewDir}/${install4jBuildDir}"
2919 buildSelected = true
2921 if (install4j_faster.equals("true") || CHANNEL.startsWith("LOCAL")) {
2923 disableSigning = true
2924 disableNotarization = true
2928 macKeystorePassword = OSX_KEYPASS
2931 if (OSX_ALTOOLPASS) {
2932 appleIdPassword = OSX_ALTOOLPASS
2933 disableNotarization = false
2935 disableNotarization = true
2939 println("Using projectFile "+projectFile)
2940 if (!disableNotarization) { println("Will notarize OSX App DMG") }
2944 inputs.dir(getdownAppBaseDir)
2945 inputs.file(install4jConfFile)
2946 inputs.file("${install4jDir}/${install4j_info_plist_file_associations}")
2947 outputs.dir("${jalviewDir}/${install4j_build_dir}/${JAVA_VERSION}")
2950 def getDataHash(File myFile) {
2951 HashCode hash = Files.asByteSource(myFile).hash(Hashing.sha256())
2952 return myFile.exists()
2954 "file" : myFile.getName(),
2955 "filesize" : myFile.length(),
2956 "sha256" : hash.toString()
2961 def writeDataJsonFile(File installersOutputTxt, File installersSha256, File dataJsonFile) {
2963 "channel" : getdownChannelName,
2964 "date" : getDate("yyyy-MM-dd HH:mm:ss"),
2965 "git-commit" : "${gitHash} [${gitBranch}]",
2966 "version" : JALVIEW_VERSION
2968 // install4j installer files
2969 if (installersOutputTxt.exists()) {
2971 installersOutputTxt.readLines().each { def line ->
2972 if (line.startsWith("#")) {
2975 line.replaceAll("\n","")
2976 def vals = line.split("\t")
2977 def filename = vals[3]
2978 def filesize = file(filename).length()
2979 filename = filename.replaceAll(/^.*\//, "")
2980 hash[vals[0]] = [ "id" : vals[0], "os" : vals[1], "name" : vals[2], "file" : filename, "filesize" : filesize ]
2981 idHash."${filename}" = vals[0]
2983 if (install4jCheckSums && installersSha256.exists()) {
2984 installersSha256.readLines().each { def line ->
2985 if (line.startsWith("#")) {
2988 line.replaceAll("\n","")
2989 def vals = line.split(/\s+\*?/)
2990 def filename = vals[1]
2991 def innerHash = (hash.(idHash."${filename}"))."sha256" = vals[0]
2997 "JAR": shadowJar.archiveFile, // executable JAR
2998 "JVL": getdownVersionLaunchJvl, // version JVL
2999 "SOURCE": sourceDist.archiveFile // source TGZ
3000 ].each { key, value ->
3001 def file = file(value)
3002 if (file.exists()) {
3003 def fileHash = getDataHash(file)
3004 if (fileHash != null) {
3005 hash."${key}" = fileHash;
3009 return dataJsonFile.write(new JsonBuilder(hash).toPrettyString())
3012 task staticMakeInstallersJsonFile {
3014 def output = findProperty("i4j_output")
3015 def sha256 = findProperty("i4j_sha256")
3016 def json = findProperty("i4j_json")
3017 if (output == null || sha256 == null || json == null) {
3018 throw new GradleException("Must provide paths to all of output.txt, sha256sums, and output.json with '-Pi4j_output=... -Pi4j_sha256=... -Pi4j_json=...")
3020 writeDataJsonFile(file(output), file(sha256), file(json))
3025 dependsOn installerFiles
3031 eclipse().configFile(eclipse_codestyle_file)
3035 task createSourceReleaseProperties(type: WriteProperties) {
3036 group = "distribution"
3037 description = "Create the source RELEASE properties file"
3039 def sourceTarBuildDir = "${buildDir}/sourceTar"
3040 def sourceReleasePropertiesFile = "${sourceTarBuildDir}/RELEASE"
3041 outputFile (sourceReleasePropertiesFile)
3044 releaseProps.each{ key, val -> property key, val }
3045 property "git.branch", gitBranch
3046 property "git.hash", gitHash
3049 outputs.file(outputFile)
3052 task sourceDist(type: Tar) {
3053 group "distribution"
3054 description "Create a source .tar.gz file for distribution"
3056 dependsOn createBuildProperties
3057 dependsOn convertMdFiles
3058 dependsOn eclipseAllPreferences
3059 dependsOn createSourceReleaseProperties
3062 def outputFileName = "${project.name}_${JALVIEW_VERSION_UNDERSCORES}.tar.gz"
3063 archiveFileName = outputFileName
3065 compression Compression.GZIP
3081 "**/*.class","$j11modDir/**/*.jar","appletlib","**/*locales",
3083 "utils/InstallAnywhere",
3098 "gradle.properties",
3110 ".settings/org.eclipse.buildship.core.prefs",
3111 ".settings/org.eclipse.jdt.core.prefs"
3115 exclude (EXCLUDE_FILES)
3116 include (PROCESS_FILES)
3117 filter(ReplaceTokens,
3121 'Version-Rel': JALVIEW_VERSION,
3122 'Year-Rel': getDate("yyyy")
3127 exclude (EXCLUDE_FILES)
3128 exclude (PROCESS_FILES)
3129 exclude ("appletlib")
3130 exclude ("**/*locales")
3131 exclude ("*locales/**")
3132 exclude ("utils/InstallAnywhere")
3134 exclude (getdown_files_dir)
3135 // getdown_website_dir and getdown_archive_dir moved to build/website/docroot/getdown
3136 //exclude (getdown_website_dir)
3137 //exclude (getdown_archive_dir)
3139 // exluding these as not using jars as modules yet
3140 exclude ("${j11modDir}/**/*.jar")
3143 include(INCLUDE_FILES)
3145 // from (jalviewDir) {
3146 // // explicit includes for stuff that seemed to not get included
3147 // include(fileTree("test/**/*."))
3148 // exclude(EXCLUDE_FILES)
3149 // exclude(PROCESS_FILES)
3152 from(file(buildProperties).getParent()) {
3153 include(file(buildProperties).getName())
3154 rename(file(buildProperties).getName(), "build_properties")
3156 line.replaceAll("^INSTALLATION=.*\$","INSTALLATION=Source Release"+" git-commit\\\\:"+gitHash+" ["+gitBranch+"]")
3160 def sourceTarBuildDir = "${buildDir}/sourceTar"
3161 from(sourceTarBuildDir) {
3162 // this includes the appended RELEASE properties file
3166 task dataInstallersJson {
3168 description "Create the installers-VERSION.json data file for installer files created"
3170 mustRunAfter installers
3171 mustRunAfter shadowJar
3172 mustRunAfter sourceDist
3173 mustRunAfter getdownArchive
3175 def installersOutputTxt = file("${jalviewDir}/${install4jBuildDir}/output.txt")
3176 def installersSha256 = file("${jalviewDir}/${install4jBuildDir}/sha256sums")
3178 if (installersOutputTxt.exists()) {
3179 inputs.file(installersOutputTxt)
3181 if (install4jCheckSums && installersSha256.exists()) {
3182 inputs.file(installersSha256)
3185 shadowJar.archiveFile, // executable JAR
3186 getdownVersionLaunchJvl, // version JVL
3187 sourceDist.archiveFile // source TGZ
3188 ].each { fileName ->
3189 if (file(fileName).exists()) {
3190 inputs.file(fileName)
3194 outputs.file(hugoDataJsonFile)
3197 writeDataJsonFile(installersOutputTxt, installersSha256, hugoDataJsonFile)
3203 description "Copies all help pages to build dir. Runs ant task 'pubhtmlhelp'."
3206 dependsOn pubhtmlhelp
3208 inputs.dir("${helpBuildDir}/${help_dir}")
3209 outputs.dir("${buildDir}/distributions/${help_dir}")
3213 task j2sSetHeadlessBuild {
3220 task jalviewjsEnableAltFileProperty(type: WriteProperties) {
3222 description "Enable the alternative J2S Config file for headless build"
3224 outputFile = jalviewjsJ2sSettingsFileName
3225 def j2sPropsFile = file(jalviewjsJ2sSettingsFileName)
3226 def j2sProps = new Properties()
3227 if (j2sPropsFile.exists()) {
3229 def j2sPropsFileFIS = new FileInputStream(j2sPropsFile)
3230 j2sProps.load(j2sPropsFileFIS)
3231 j2sPropsFileFIS.close()
3233 j2sProps.each { prop, val ->
3236 } catch (Exception e) {
3237 println("Exception reading ${jalviewjsJ2sSettingsFileName}")
3241 if (! j2sProps.stringPropertyNames().contains(jalviewjs_j2s_alt_file_property_config)) {
3242 property(jalviewjs_j2s_alt_file_property_config, jalviewjs_j2s_alt_file_property)
3247 task jalviewjsSetEclipseWorkspace {
3248 def propKey = "jalviewjs_eclipse_workspace"
3250 if (project.hasProperty(propKey)) {
3251 propVal = project.getProperty(propKey)
3252 if (propVal.startsWith("~/")) {
3253 propVal = System.getProperty("user.home") + propVal.substring(1)
3256 def propsFileName = "${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_eclipse_workspace_location_file}"
3257 def propsFile = file(propsFileName)
3258 def eclipseWsDir = propVal
3259 def props = new Properties()
3261 def writeProps = true
3262 if (( eclipseWsDir == null || !file(eclipseWsDir).exists() ) && propsFile.exists()) {
3263 def ins = new FileInputStream(propsFileName)
3266 if (props.getProperty(propKey, null) != null) {
3267 eclipseWsDir = props.getProperty(propKey)
3272 if (eclipseWsDir == null || !file(eclipseWsDir).exists()) {
3273 def tempDir = File.createTempDir()
3274 eclipseWsDir = tempDir.getAbsolutePath()
3277 eclipseWorkspace = file(eclipseWsDir)
3280 // do not run a headless transpile when we claim to be in Eclipse
3282 println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3283 throw new StopExecutionException("Not running headless transpile whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
3285 println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3289 props.setProperty(propKey, eclipseWsDir)
3290 propsFile.parentFile.mkdirs()
3291 def bytes = new ByteArrayOutputStream()
3292 props.store(bytes, null)
3293 def propertiesString = bytes.toString()
3294 propsFile.text = propertiesString
3300 println("ECLIPSE WORKSPACE: "+eclipseWorkspace.getPath())
3303 //inputs.property(propKey, eclipseWsDir) // eclipseWsDir only gets set once this task runs, so will be out-of-date
3304 outputs.file(propsFileName)
3305 outputs.upToDateWhen { eclipseWorkspace.exists() && propsFile.exists() }
3309 task jalviewjsEclipsePaths {
3310 def eclipseProductFile
3313 def eclipseRoot = jalviewjs_eclipse_root
3314 if (eclipseRoot.startsWith("~/")) {
3315 eclipseRoot = System.getProperty("user.home") + eclipseRoot.substring(1)
3317 if (OperatingSystem.current().isMacOsX()) {
3318 eclipseRoot += "/Eclipse.app"
3319 eclipseBinary = "${eclipseRoot}/Contents/MacOS/eclipse"
3320 eclipseProductFile = "${eclipseRoot}/Contents/Eclipse/.eclipseproduct"
3321 eclipseSetupLog = "${eclipseRoot}/Contents/Eclipse/configuration/org.eclipse.oomph.setup/setup.log"
3322 } else if (OperatingSystem.current().isWindows()) { // check these paths!!
3323 if (file("${eclipseRoot}/eclipse").isDirectory() && file("${eclipseRoot}/eclipse/.eclipseproduct").exists()) {
3324 eclipseRoot += "/eclipse"
3326 eclipseBinary = "${eclipseRoot}/eclipse.exe"
3327 eclipseProductFile = "${eclipseRoot}/.eclipseproduct"
3328 eclipseSetupLog = "${eclipseRoot}/configuration/org.eclipse.oomph.setup/setup.log"
3329 } else { // linux or unix
3330 if (file("${eclipseRoot}/eclipse").isDirectory() && file("${eclipseRoot}/eclipse/.eclipseproduct").exists()) {
3331 eclipseRoot += "/eclipse"
3333 eclipseBinary = "${eclipseRoot}/eclipse"
3334 eclipseProductFile = "${eclipseRoot}/.eclipseproduct"
3335 eclipseSetupLog = "${eclipseRoot}/configuration/org.eclipse.oomph.setup/setup.log"
3338 eclipseVersion = "unknown" // default
3339 def assumedVersion = true
3340 if (file(eclipseProductFile).exists()) {
3341 def fis = new FileInputStream(eclipseProductFile)
3342 def props = new Properties()
3344 eclipseVersion = props.getProperty("version")
3346 assumedVersion = false
3348 if (file(eclipseSetupLog).exists()) {
3349 def productRegex = /(?m)^\[[^\]]+\]\s+Product\s+(org\.eclipse.\S*)/
3351 file(eclipseSetupLog).eachLine { String line ->
3352 def matcher = line =~ productRegex
3353 if (matcher.size() > 0) {
3354 eclipseProductVersion = matcher[0][1]
3357 if (lineCount >= 100) {
3364 def propKey = "eclipse_debug"
3365 eclipseDebug = (project.hasProperty(propKey) && project.getProperty(propKey).equals("true"))
3368 // do not run a headless transpile when we claim to be in Eclipse
3370 println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3371 throw new StopExecutionException("Not running headless transpile whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
3373 println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3376 if (!assumedVersion) {
3377 println("ECLIPSE VERSION=${eclipseVersion}")
3378 if (eclipseProductVersion.length() != 0) {
3379 println("ECLIPSE PRODUCT=${eclipseProductVersion}")
3386 task printProperties {
3388 description "Output to console all System.properties"
3390 System.properties.each { key, val -> System.out.println("Property: ${key}=${val}") }
3396 dependsOn eclipseProject
3397 dependsOn eclipseClasspath
3398 dependsOn eclipseJdt
3402 // this version (type: Copy) will delete anything in the eclipse dropins folder that isn't in fromDropinsDir
3403 task jalviewjsEclipseCopyDropins(type: Copy) {
3404 dependsOn jalviewjsEclipsePaths
3406 def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjs_eclipse_dropins_dir}", include: "*.jar")
3407 inputFiles += file("${jalviewDir}/${jalviewjsJ2sPlugin}")
3408 def outputDir = "${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_eclipse_tmp_dropins_dir}"
3415 // this eclipse -clean doesn't actually work
3416 task jalviewjsCleanEclipse(type: Exec) {
3417 dependsOn eclipseSetup
3418 dependsOn jalviewjsEclipsePaths
3419 dependsOn jalviewjsEclipseCopyDropins
3421 executable(eclipseBinary)
3422 args(["-nosplash", "--launcher.suppressErrors", "-data", eclipseWorkspace.getPath(), "-clean", "-console", "-consoleLog"])
3428 def inputString = """exit
3431 def inputByteStream = new ByteArrayInputStream(inputString.getBytes())
3432 standardInput = inputByteStream
3435 /* not really working yet
3436 jalviewjsEclipseCopyDropins.finalizedBy jalviewjsCleanEclipse
3440 task jalviewjsTransferUnzipSwingJs {
3441 def file_zip = "${jalviewDir}/${jalviewjs_swingjs_zip}"
3445 from zipTree(file_zip)
3446 into "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}"
3450 inputs.file file_zip
3451 outputs.dir "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}"
3455 task jalviewjsTransferUnzipLib {
3456 def zipFiles = fileTree(dir: "${jalviewDir}/${jalviewjs_libjs_dir}", include: "*.zip")
3459 zipFiles.each { file_zip ->
3461 from zipTree(file_zip)
3462 into "${jalviewDir}/${jalviewjsTransferSiteLibDir}"
3467 inputs.files zipFiles
3468 outputs.dir "${jalviewDir}/${jalviewjsTransferSiteLibDir}"
3472 task jalviewjsTransferUnzipAllLibs {
3473 dependsOn jalviewjsTransferUnzipSwingJs
3474 dependsOn jalviewjsTransferUnzipLib
3478 task jalviewjsCreateJ2sSettings(type: WriteProperties) {
3480 description "Create the alternative j2s file from the j2s.* properties"
3482 jalviewjsJ2sProps = project.properties.findAll { it.key.startsWith("j2s.") }.sort { it.key }
3483 def siteDirProperty = "j2s.site.directory"
3484 def setSiteDir = false
3485 jalviewjsJ2sProps.each { prop, val ->
3487 if (prop == siteDirProperty) {
3488 if (!(val.startsWith('/') || val.startsWith("file://") )) {
3489 val = "${jalviewDir}/${jalviewjsTransferSiteJsDir}/${val}"
3495 if (!setSiteDir) { // default site location, don't override specifically set property
3496 property(siteDirProperty,"${jalviewDirRelativePath}/${jalviewjsTransferSiteJsDir}")
3499 outputFile = jalviewjsJ2sAltSettingsFileName
3502 inputs.properties(jalviewjsJ2sProps)
3503 outputs.file(jalviewjsJ2sAltSettingsFileName)
3508 task jalviewjsEclipseSetup {
3509 dependsOn jalviewjsEclipseCopyDropins
3510 dependsOn jalviewjsSetEclipseWorkspace
3511 dependsOn jalviewjsCreateJ2sSettings
3515 task jalviewjsSyncAllLibs (type: Sync) {
3516 dependsOn jalviewjsTransferUnzipAllLibs
3517 def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjsTransferSiteLibDir}")
3518 inputFiles += fileTree(dir: "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}")
3519 def outputDir = "${jalviewDir}/${jalviewjsSiteDir}"
3523 def outputFiles = []
3524 rename { filename ->
3525 outputFiles += "${outputDir}/${filename}"
3532 // should this be exclude really ?
3533 duplicatesStrategy "INCLUDE"
3535 outputs.files outputFiles
3536 inputs.files inputFiles
3540 task jalviewjsSyncResources (type: Sync) {
3541 dependsOn buildResources
3543 def inputFiles = fileTree(dir: resourcesBuildDir)
3544 def outputDir = "${jalviewDir}/${jalviewjsSiteDir}/${jalviewjs_j2s_subdir}"
3548 def outputFiles = []
3549 rename { filename ->
3550 outputFiles += "${outputDir}/${filename}"
3556 outputs.files outputFiles
3557 inputs.files inputFiles
3561 task jalviewjsSyncSiteResources (type: Sync) {
3562 def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjs_site_resource_dir}")
3563 def outputDir = "${jalviewDir}/${jalviewjsSiteDir}"
3567 def outputFiles = []
3568 rename { filename ->
3569 outputFiles += "${outputDir}/${filename}"
3575 outputs.files outputFiles
3576 inputs.files inputFiles
3580 task jalviewjsSyncBuildProperties (type: Sync) {
3581 dependsOn createBuildProperties
3582 def inputFiles = [file(buildProperties)]
3583 def outputDir = "${jalviewDir}/${jalviewjsSiteDir}/${jalviewjs_j2s_subdir}"
3587 def outputFiles = []
3588 rename { filename ->
3589 outputFiles += "${outputDir}/${filename}"
3595 outputs.files outputFiles
3596 inputs.files inputFiles
3600 task jalviewjsProjectImport(type: Exec) {
3601 dependsOn eclipseSetup
3602 dependsOn jalviewjsEclipsePaths
3603 dependsOn jalviewjsEclipseSetup
3606 // do not run a headless import when we claim to be in Eclipse
3608 println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3609 throw new StopExecutionException("Not running headless import whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
3611 println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3615 //def projdir = eclipseWorkspace.getPath()+"/.metadata/.plugins/org.eclipse.core.resources/.projects/jalview/org.eclipse.jdt.core"
3616 def projdir = eclipseWorkspace.getPath()+"/.metadata/.plugins/org.eclipse.core.resources/.projects/jalview"
3617 executable(eclipseBinary)
3618 args(["-nosplash", "--launcher.suppressErrors", "-application", "com.seeq.eclipse.importprojects.headlessimport", "-data", eclipseWorkspace.getPath(), "-import", jalviewDirAbsolutePath])
3622 args += [ "--launcher.appendVmargs", "-vmargs", "-Dorg.eclipse.equinox.p2.reconciler.dropins.directory=${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_eclipse_tmp_dropins_dir}" ]
3624 args += [ "-D${j2sHeadlessBuildProperty}=true" ]
3625 args += [ "-D${jalviewjs_j2s_alt_file_property}=${jalviewjsJ2sAltSettingsFileName}" ]
3628 inputs.file("${jalviewDir}/.project")
3629 outputs.upToDateWhen {
3630 file(projdir).exists()
3635 task jalviewjsTranspile(type: Exec) {
3636 dependsOn jalviewjsEclipseSetup
3637 dependsOn jalviewjsProjectImport
3638 dependsOn jalviewjsEclipsePaths
3640 dependsOn jalviewjsEnableAltFileProperty
3644 // do not run a headless transpile when we claim to be in Eclipse
3646 println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3647 throw new StopExecutionException("Not running headless transpile whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
3649 println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3653 executable(eclipseBinary)
3654 args(["-nosplash", "--launcher.suppressErrors", "-application", "org.eclipse.jdt.apt.core.aptBuild", "-data", eclipseWorkspace, "-${jalviewjs_eclipse_build_arg}", eclipse_project_name ])
3658 args += [ "--launcher.appendVmargs", "-vmargs", "-Dorg.eclipse.equinox.p2.reconciler.dropins.directory=${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_eclipse_tmp_dropins_dir}" ]
3660 args += [ "-D${j2sHeadlessBuildProperty}=true" ]
3661 args += [ "-D${jalviewjs_j2s_alt_file_property}=${jalviewjsJ2sAltSettingsFileName}" ]
3667 stdout = new ByteArrayOutputStream()
3668 stderr = new ByteArrayOutputStream()
3670 def logOutFileName = "${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}"
3671 def logOutFile = file(logOutFileName)
3672 logOutFile.createNewFile()
3673 def info = """ROOT: ${jalviewjs_eclipse_root}
3674 ECLIPSE BINARY: ${eclipseBinary}
3675 ECLIPSE VERSION: ${eclipseVersion}
3676 ECLIPSE PRODUCT: ${eclipseProductVersion}
3677 ECLIPSE WORKSPACE: ${eclipseWorkspace}
3678 ECLIPSE DEBUG: ${eclipseDebug}
3681 def logOutFOS = new FileOutputStream(logOutFile, true) // true == append
3682 // combine stdout and stderr
3683 def logErrFOS = logOutFOS
3685 if (jalviewjs_j2s_to_console.equals("true")) {
3686 standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
3687 new org.apache.tools.ant.util.TeeOutputStream(
3691 errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
3692 new org.apache.tools.ant.util.TeeOutputStream(
3697 standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
3700 errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
3704 standardOutput.write(string(info).getBytes("UTF-8"))
3708 def transpileError = false
3709 def j2sIsActive = false
3710 def j2sBuildStarting = false
3711 def compilingLines = 0
3712 def j2sBuildingJavascript = false
3713 def j2sBuildingJavascriptRegex = /(?m)^J2S building JavaScript for (\d+) files/
3715 def transpilingLines = 0
3716 stdout.toString().eachLine { String line ->
3717 if (line.startsWith("J2S isActive true")) {
3720 if (line.startsWith("J2S buildStarting")) {
3721 j2sBuildStarting = true
3723 if (line =~ / Compiling /) {
3726 if (!j2sBuildingJavascript) {
3727 def matcher = line =~ j2sBuildingJavascriptRegex
3728 if (matcher.size() > 0) {
3729 numFiles = Integer.valueOf(matcher[0][1])
3730 j2sBuildingJavascript = true
3733 if (line.startsWith("J2S transpiling ")) {
3736 if (line.contains("Error processing ")) {
3737 transpileError = true
3741 println("J2S IS ACTIVE=${j2sIsActive}")
3742 println("J2S BUILD STARTING=${j2sBuildStarting}")
3743 println("J2S BUILDING JAVASCRIPT=${j2sBuildingJavascript}")
3744 println("NUM FILES=${numFiles}")
3745 println("COMPILING LINES=${compilingLines}")
3746 println("TRANSPILING LINES=${transpilingLines}")
3747 println("TRANSPILE ERROR=${transpileError}")
3751 || (j2sBuildStarting && transpilingLines == 0)
3752 || (transpilingLines < compilingLines)
3753 || (transpilingLines != numFiles)
3755 // j2s did not complete transpile
3756 if (jalviewjs_ignore_transpile_errors.equals("true")) {
3757 println("IGNORING TRANSPILE ERRORS")
3758 println("See eclipse transpile log file '${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}'")
3760 throw new GradleException("Error during transpilation:\n${stderr}\nSee eclipse transpile log file '${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}'")
3765 inputs.dir("${jalviewDir}/${sourceDir}")
3766 outputs.dir("${jalviewDir}/${jalviewjsTransferSiteJsDir}")
3767 outputs.upToDateWhen( { file("${jalviewDir}/${jalviewjsTransferSiteJsDir}${jalviewjs_server_resource}").exists() } )
3771 def jalviewjsCallCore(String name, FileCollection list, String prefixFile, String suffixFile, String jsfile, String zjsfile, File logOutFile, Boolean logOutConsole) {
3773 def stdout = new ByteArrayOutputStream()
3774 def stderr = new ByteArrayOutputStream()
3776 def coreFile = file(jsfile)
3778 msg = "Creating core for ${name}...\nGenerating ${jsfile}"
3780 logOutFile.createNewFile()
3781 logOutFile.append(msg+"\n")
3783 def coreTop = file(prefixFile)
3784 def coreBottom = file(suffixFile)
3785 coreFile.getParentFile().mkdirs()
3786 coreFile.createNewFile()
3787 coreFile.write( coreTop.getText("UTF-8") )
3791 def t = f.getText("UTF-8")
3792 t.replaceAll("Clazz\\.([^_])","Clazz_${1}")
3793 coreFile.append( t )
3795 msg = "...file '"+f.getPath()+"' does not exist, skipping"
3797 logOutFile.append(msg+"\n")
3800 coreFile.append( coreBottom.getText("UTF-8") )
3802 msg = "Generating ${zjsfile}"
3804 logOutFile.append(msg+"\n")
3805 def logOutFOS = new FileOutputStream(logOutFile, true) // true == append
3806 def logErrFOS = logOutFOS
3809 classpath = files(["${jalviewDir}/${jalviewjs_closure_compiler}"])
3810 main = "com.google.javascript.jscomp.CommandLineRunner"
3811 jvmArgs = [ "-Dfile.encoding=UTF-8" ]
3812 args = [ "--compilation_level", "SIMPLE_OPTIMIZATIONS", "--warning_level", "QUIET", "--charset", "UTF-8", "--js", jsfile, "--js_output_file", zjsfile ]
3815 msg = "\nRunning '"+commandLine.join(' ')+"'\n"
3817 logOutFile.append(msg+"\n")
3819 if (logOutConsole) {
3820 standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
3821 new org.apache.tools.ant.util.TeeOutputStream(
3825 errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
3826 new org.apache.tools.ant.util.TeeOutputStream(
3831 standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
3834 errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
3841 logOutFile.append(msg+"\n")
3845 task jalviewjsBuildAllCores {
3847 description "Build the core js lib closures listed in the classlists dir"
3848 dependsOn jalviewjsTranspile
3849 dependsOn jalviewjsTransferUnzipSwingJs
3851 def j2sDir = "${jalviewDir}/${jalviewjsTransferSiteJsDir}/${jalviewjs_j2s_subdir}"
3852 def swingJ2sDir = "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}/${jalviewjs_j2s_subdir}"
3853 def libJ2sDir = "${jalviewDir}/${jalviewjsTransferSiteLibDir}/${jalviewjs_j2s_subdir}"
3854 def jsDir = "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}/${jalviewjs_js_subdir}"
3855 def outputDir = "${jalviewDir}/${jalviewjsTransferSiteCoreDir}/${jalviewjs_j2s_subdir}/core"
3856 def prefixFile = "${jsDir}/core/coretop2.js"
3857 def suffixFile = "${jsDir}/core/corebottom2.js"
3859 inputs.file prefixFile
3860 inputs.file suffixFile
3862 def classlistFiles = []
3863 // add the classlists found int the jalviewjs_classlists_dir
3864 fileTree(dir: "${jalviewDir}/${jalviewjs_classlists_dir}", include: "*.txt").each {
3866 def name = file.getName() - ".txt"
3873 // _jmol and _jalview cores. Add any other peculiar classlist.txt files here
3874 //classlistFiles += [ 'file': file("${jalviewDir}/${jalviewjs_classlist_jmol}"), 'name': "_jvjmol" ]
3875 classlistFiles += [ 'file': file("${jalviewDir}/${jalviewjs_classlist_jalview}"), 'name': jalviewjsJalviewCoreName ]
3877 jalviewjsCoreClasslists = []
3879 classlistFiles.each {
3882 def file = hash['file']
3883 if (! file.exists()) {
3884 //println("...classlist file '"+file.getPath()+"' does not exist, skipping")
3885 return false // this is a "continue" in groovy .each closure
3887 def name = hash['name']
3889 name = file.getName() - ".txt"
3897 def list = fileTree(dir: j2sDir, includes: filelist)
3899 def jsfile = "${outputDir}/core${name}.js"
3900 def zjsfile = "${outputDir}/core${name}.z.js"
3902 jalviewjsCoreClasslists += [
3911 outputs.file(jsfile)
3912 outputs.file(zjsfile)
3915 // _stevesoft core. add any cores without a classlist here (and the inputs and outputs)
3916 def stevesoftClasslistName = "_stevesoft"
3917 def stevesoftClasslist = [
3918 'jsfile': "${outputDir}/core${stevesoftClasslistName}.js",
3919 'zjsfile': "${outputDir}/core${stevesoftClasslistName}.z.js",
3920 'list': fileTree(dir: j2sDir, include: "com/stevesoft/pat/**/*.js"),
3921 'name': stevesoftClasslistName
3923 jalviewjsCoreClasslists += stevesoftClasslist
3924 inputs.files(stevesoftClasslist['list'])
3925 outputs.file(stevesoftClasslist['jsfile'])
3926 outputs.file(stevesoftClasslist['zjsfile'])
3929 def allClasslistName = "_all"
3930 def allJsFiles = fileTree(dir: j2sDir, include: "**/*.js")
3931 allJsFiles += fileTree(
3935 // these exlusions are files that the closure-compiler produces errors for. Should fix them
3936 "**/org/jmol/jvxl/readers/IsoIntersectFileReader.js",
3937 "**/org/jmol/export/JSExporter.js"
3940 allJsFiles += fileTree(
3944 // these exlusions are files that the closure-compiler produces errors for. Should fix them
3945 "**/sun/misc/Unsafe.js",
3946 "**/swingjs/jquery/jquery-editable-select.js",
3947 "**/swingjs/jquery/j2sComboBox.js",
3948 "**/sun/misc/FloatingDecimal.js"
3951 def allClasslist = [
3952 'jsfile': "${outputDir}/core${allClasslistName}.js",
3953 'zjsfile': "${outputDir}/core${allClasslistName}.z.js",
3955 'name': allClasslistName
3957 // not including this version of "all" core at the moment
3958 //jalviewjsCoreClasslists += allClasslist
3959 inputs.files(allClasslist['list'])
3960 outputs.file(allClasslist['jsfile'])
3961 outputs.file(allClasslist['zjsfile'])
3964 def logOutFile = file("${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_j2s_closure_stdout}")
3965 logOutFile.getParentFile().mkdirs()
3966 logOutFile.createNewFile()
3967 logOutFile.write(getDate("yyyy-MM-dd HH:mm:ss")+" jalviewjsBuildAllCores\n----\n")
3969 jalviewjsCoreClasslists.each {
3970 jalviewjsCallCore(it.name, it.list, prefixFile, suffixFile, it.jsfile, it.zjsfile, logOutFile, jalviewjs_j2s_to_console.equals("true"))
3977 def jalviewjsPublishCoreTemplate(String coreName, String templateName, File inputFile, String outputFile) {
3980 into file(outputFile).getParentFile()
3981 rename { filename ->
3982 if (filename.equals(inputFile.getName())) {
3983 return file(outputFile).getName()
3987 filter(ReplaceTokens,
3991 'MAIN': '"'+main_class+'"',
3993 'NAME': jalviewjsJalviewTemplateName+" [core ${coreName}]",
3994 'COREKEY': jalviewjs_core_key,
3995 'CORENAME': coreName
4002 task jalviewjsPublishCoreTemplates {
4003 dependsOn jalviewjsBuildAllCores
4004 def inputFileName = "${jalviewDir}/${j2s_coretemplate_html}"
4005 def inputFile = file(inputFileName)
4006 def outputDir = "${jalviewDir}/${jalviewjsTransferSiteCoreDir}"
4008 def outputFiles = []
4009 jalviewjsCoreClasslists.each { cl ->
4010 def outputFile = "${outputDir}/${jalviewjsJalviewTemplateName}_${cl.name}.html"
4011 cl['outputfile'] = outputFile
4012 outputFiles += outputFile
4016 jalviewjsCoreClasslists.each { cl ->
4017 jalviewjsPublishCoreTemplate(cl.name, jalviewjsJalviewTemplateName, inputFile, cl.outputfile)
4020 inputs.file(inputFile)
4021 outputs.files(outputFiles)
4025 task jalviewjsSyncCore (type: Sync) {
4026 dependsOn jalviewjsBuildAllCores
4027 dependsOn jalviewjsPublishCoreTemplates
4028 def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjsTransferSiteCoreDir}")
4029 def outputDir = "${jalviewDir}/${jalviewjsSiteDir}"
4033 def outputFiles = []
4034 rename { filename ->
4035 outputFiles += "${outputDir}/${filename}"
4041 outputs.files outputFiles
4042 inputs.files inputFiles
4046 // this Copy version of TransferSiteJs will delete anything else in the target dir
4047 task jalviewjsCopyTransferSiteJs(type: Copy) {
4048 dependsOn jalviewjsTranspile
4049 from "${jalviewDir}/${jalviewjsTransferSiteJsDir}"
4050 into "${jalviewDir}/${jalviewjsSiteDir}"
4054 // this Sync version of TransferSite is used by buildship to keep the website automatically up to date when a file changes
4055 task jalviewjsSyncTransferSiteJs(type: Sync) {
4056 from "${jalviewDir}/${jalviewjsTransferSiteJsDir}"
4058 into "${jalviewDir}/${jalviewjsSiteDir}"
4065 jalviewjsSyncAllLibs.mustRunAfter jalviewjsCopyTransferSiteJs
4066 jalviewjsSyncResources.mustRunAfter jalviewjsCopyTransferSiteJs
4067 jalviewjsSyncSiteResources.mustRunAfter jalviewjsCopyTransferSiteJs
4068 jalviewjsSyncBuildProperties.mustRunAfter jalviewjsCopyTransferSiteJs
4070 jalviewjsSyncAllLibs.mustRunAfter jalviewjsSyncTransferSiteJs
4071 jalviewjsSyncResources.mustRunAfter jalviewjsSyncTransferSiteJs
4072 jalviewjsSyncSiteResources.mustRunAfter jalviewjsSyncTransferSiteJs
4073 jalviewjsSyncBuildProperties.mustRunAfter jalviewjsSyncTransferSiteJs
4076 task jalviewjsPrepareSite {
4078 description "Prepares the website folder including unzipping files and copying resources"
4079 dependsOn jalviewjsSyncAllLibs
4080 dependsOn jalviewjsSyncResources
4081 dependsOn jalviewjsSyncSiteResources
4082 dependsOn jalviewjsSyncBuildProperties
4083 dependsOn jalviewjsSyncCore
4087 task jalviewjsBuildSite {
4089 description "Builds the whole website including transpiled code"
4090 dependsOn jalviewjsCopyTransferSiteJs
4091 dependsOn jalviewjsPrepareSite
4095 task cleanJalviewjsTransferSite {
4097 delete "${jalviewDir}/${jalviewjsTransferSiteJsDir}"
4098 delete "${jalviewDir}/${jalviewjsTransferSiteLibDir}"
4099 delete "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}"
4100 delete "${jalviewDir}/${jalviewjsTransferSiteCoreDir}"
4105 task cleanJalviewjsSite {
4106 dependsOn cleanJalviewjsTransferSite
4108 delete "${jalviewDir}/${jalviewjsSiteDir}"
4113 task jalviewjsSiteTar(type: Tar) {
4115 description "Creates a tar.gz file for the website"
4116 dependsOn jalviewjsBuildSite
4117 def outputFilename = "jalviewjs-site-${JALVIEW_VERSION}.tar.gz"
4118 archiveFileName = outputFilename
4120 compression Compression.GZIP
4122 from "${jalviewDir}/${jalviewjsSiteDir}"
4123 into jalviewjs_site_dir // this is inside the tar file
4125 inputs.dir("${jalviewDir}/${jalviewjsSiteDir}")
4129 task jalviewjsServer {
4131 def filename = "jalviewjsTest.html"
4132 description "Starts a webserver on localhost to test the website. See ${filename} to access local site on most recently used port."
4133 def htmlFile = "${jalviewDirAbsolutePath}/${filename}"
4138 def f = Class.forName("org.gradle.plugins.javascript.envjs.http.simple.SimpleHttpFileServerFactory")
4139 factory = f.newInstance()
4140 } catch (ClassNotFoundException e) {
4141 throw new GradleException("Unable to create SimpleHttpFileServerFactory")
4143 def port = Integer.valueOf(jalviewjs_server_port)
4148 while(port < start+1000 && !running) {
4150 def doc_root = new File("${jalviewDirAbsolutePath}/${jalviewjsSiteDir}")
4151 jalviewjsServer = factory.start(doc_root, port)
4153 url = jalviewjsServer.getResourceUrl(jalviewjs_server_resource)
4154 println("SERVER STARTED with document root ${doc_root}.")
4155 println("Go to "+url+" . Run gradle --stop to stop (kills all gradle daemons).")
4156 println("For debug: "+url+"?j2sdebug")
4157 println("For verbose: "+url+"?j2sverbose")
4158 } catch (Exception e) {
4163 <p><a href="${url}">JalviewJS Test. <${url}></a></p>
4164 <p><a href="${url}?j2sdebug">JalviewJS Test with debug. <${url}?j2sdebug></a></p>
4165 <p><a href="${url}?j2sverbose">JalviewJS Test with verbose. <${url}?j2sdebug></a></p>
4167 jalviewjsCoreClasslists.each { cl ->
4168 def urlcore = jalviewjsServer.getResourceUrl(file(cl.outputfile).getName())
4170 <p><a href="${urlcore}">${jalviewjsJalviewTemplateName} [core ${cl.name}]. <${urlcore}></a></p>
4172 println("For core ${cl.name}: "+urlcore)
4175 file(htmlFile).text = htmlText
4178 outputs.file(htmlFile)
4179 outputs.upToDateWhen({false})
4183 task cleanJalviewjsAll {
4185 description "Delete all configuration and build artifacts to do with JalviewJS build"
4186 dependsOn cleanJalviewjsSite
4187 dependsOn jalviewjsEclipsePaths
4190 delete "${jalviewDir}/${jalviewjsBuildDir}"
4191 delete "${jalviewDir}/${eclipse_bin_dir}"
4192 if (eclipseWorkspace != null && file(eclipseWorkspace.getAbsolutePath()+"/.metadata").exists()) {
4193 delete file(eclipseWorkspace.getAbsolutePath()+"/.metadata")
4195 delete jalviewjsJ2sAltSettingsFileName
4198 outputs.upToDateWhen( { false } )
4202 task jalviewjsIDE_checkJ2sPlugin {
4203 group "00 JalviewJS in Eclipse"
4204 description "Compare the swingjs/net.sf.j2s.core(-j11)?.jar file with the Eclipse IDE's plugin version (found in the 'dropins' dir)"
4207 def j2sPlugin = string("${jalviewDir}/${jalviewjsJ2sPlugin}")
4208 def j2sPluginFile = file(j2sPlugin)
4209 def eclipseHome = System.properties["eclipse.home.location"]
4210 if (eclipseHome == null || ! IN_ECLIPSE) {
4211 throw new StopExecutionException("Cannot find running Eclipse home from System.properties['eclipse.home.location']. Skipping J2S Plugin Check.")
4213 def eclipseJ2sPluginDirs = [ "${eclipseHome}/dropins" ]
4214 def altPluginsDir = System.properties["org.eclipse.equinox.p2.reconciler.dropins.directory"]
4215 if (altPluginsDir != null && file(altPluginsDir).exists()) {
4216 eclipseJ2sPluginDirs += altPluginsDir
4218 def foundPlugin = false
4219 def j2sPluginFileName = j2sPluginFile.getName()
4220 def eclipseJ2sPlugin
4221 def eclipseJ2sPluginFile
4222 eclipseJ2sPluginDirs.any { dir ->
4223 eclipseJ2sPlugin = "${dir}/${j2sPluginFileName}"
4224 eclipseJ2sPluginFile = file(eclipseJ2sPlugin)
4225 if (eclipseJ2sPluginFile.exists()) {
4231 def msg = "Eclipse J2S Plugin is not installed (could not find '${j2sPluginFileName}' in\n"+eclipseJ2sPluginDirs.join("\n")+"\n)\nTry running task jalviewjsIDE_copyJ2sPlugin"
4232 System.err.println(msg)
4233 throw new StopExecutionException(msg)
4236 def digest = MessageDigest.getInstance("MD5")
4238 digest.update(j2sPluginFile.text.bytes)
4239 def j2sPluginMd5 = new BigInteger(1, digest.digest()).toString(16).padLeft(32, '0')
4241 digest.update(eclipseJ2sPluginFile.text.bytes)
4242 def eclipseJ2sPluginMd5 = new BigInteger(1, digest.digest()).toString(16).padLeft(32, '0')
4244 if (j2sPluginMd5 != eclipseJ2sPluginMd5) {
4245 def msg = "WARNING! Eclipse J2S Plugin '${eclipseJ2sPlugin}' is different to this commit's version '${j2sPlugin}'"
4246 System.err.println(msg)
4247 throw new StopExecutionException(msg)
4249 def msg = "Eclipse J2S Plugin '${eclipseJ2sPlugin}' is the same as '${j2sPlugin}' (this is good)"
4255 task jalviewjsIDE_copyJ2sPlugin {
4256 group "00 JalviewJS in Eclipse"
4257 description "Copy the swingjs/net.sf.j2s.core(-j11)?.jar file into the Eclipse IDE's 'dropins' dir"
4260 def j2sPlugin = string("${jalviewDir}/${jalviewjsJ2sPlugin}")
4261 def j2sPluginFile = file(j2sPlugin)
4262 def eclipseHome = System.properties["eclipse.home.location"]
4263 if (eclipseHome == null || ! IN_ECLIPSE) {
4264 throw new StopExecutionException("Cannot find running Eclipse home from System.properties['eclipse.home.location']. NOT copying J2S Plugin.")
4266 def eclipseJ2sPlugin = "${eclipseHome}/dropins/${j2sPluginFile.getName()}"
4267 def eclipseJ2sPluginFile = file(eclipseJ2sPlugin)
4268 def msg = "WARNING! Copying this commit's j2s plugin '${j2sPlugin}' to Eclipse J2S Plugin '${eclipseJ2sPlugin}'\n* May require an Eclipse restart"
4269 System.err.println(msg)
4272 eclipseJ2sPluginFile.getParentFile().mkdirs()
4273 into eclipseJ2sPluginFile.getParent()
4279 task jalviewjsIDE_j2sFile {
4280 group "00 JalviewJS in Eclipse"
4281 description "Creates the .j2s file"
4282 dependsOn jalviewjsCreateJ2sSettings
4286 task jalviewjsIDE_SyncCore {
4287 group "00 JalviewJS in Eclipse"
4288 description "Build the core js lib closures listed in the classlists dir and publish core html from template"
4289 dependsOn jalviewjsSyncCore
4293 task jalviewjsIDE_SyncSiteAll {
4294 dependsOn jalviewjsSyncAllLibs
4295 dependsOn jalviewjsSyncResources
4296 dependsOn jalviewjsSyncSiteResources
4297 dependsOn jalviewjsSyncBuildProperties
4301 cleanJalviewjsTransferSite.mustRunAfter jalviewjsIDE_SyncSiteAll
4304 task jalviewjsIDE_PrepareSite {
4305 group "00 JalviewJS in Eclipse"
4306 description "Sync libs and resources to site dir, but not closure cores"
4308 dependsOn jalviewjsIDE_SyncSiteAll
4309 //dependsOn cleanJalviewjsTransferSite // not sure why this clean is here -- will slow down a re-run of this task
4313 task jalviewjsIDE_AssembleSite {
4314 group "00 JalviewJS in Eclipse"
4315 description "Assembles unzipped supporting zipfiles, resources, site resources and closure cores into the Eclipse transpiled site"
4316 dependsOn jalviewjsPrepareSite
4320 task jalviewjsIDE_SiteClean {
4321 group "00 JalviewJS in Eclipse"
4322 description "Deletes the Eclipse transpiled site"
4323 dependsOn cleanJalviewjsSite
4327 task jalviewjsIDE_Server {
4328 group "00 JalviewJS in Eclipse"
4329 description "Starts a webserver on localhost to test the website"
4330 dependsOn jalviewjsServer
4334 // buildship runs this at import or gradle refresh
4335 task eclipseSynchronizationTask {
4336 //dependsOn eclipseSetup
4337 dependsOn createBuildProperties
4339 dependsOn jalviewjsIDE_j2sFile
4340 dependsOn jalviewjsIDE_checkJ2sPlugin
4341 dependsOn jalviewjsIDE_PrepareSite
4346 // buildship runs this at build time or project refresh
4347 task eclipseAutoBuildTask {
4348 //dependsOn jalviewjsIDE_checkJ2sPlugin
4349 //dependsOn jalviewjsIDE_PrepareSite
4353 task jalviewjsCopyStderrLaunchFile(type: Copy) {
4354 from file(jalviewjs_stderr_launch)
4355 into jalviewjsSiteDir
4357 inputs.file jalviewjs_stderr_launch
4358 outputs.file jalviewjsStderrLaunchFilename
4361 task cleanJalviewjsChromiumUserDir {
4363 delete jalviewjsChromiumUserDir
4365 outputs.dir jalviewjsChromiumUserDir
4366 // always run when depended on
4367 outputs.upToDateWhen { !file(jalviewjsChromiumUserDir).exists() }
4370 task jalviewjsChromiumProfile {
4371 dependsOn cleanJalviewjsChromiumUserDir
4372 mustRunAfter cleanJalviewjsChromiumUserDir
4374 def firstRun = file("${jalviewjsChromiumUserDir}/First Run")
4377 mkdir jalviewjsChromiumProfileDir
4380 outputs.file firstRun
4383 task jalviewjsLaunchTest {
4385 description "Check JalviewJS opens in a browser"
4386 dependsOn jalviewjsBuildSite
4387 dependsOn jalviewjsCopyStderrLaunchFile
4388 dependsOn jalviewjsChromiumProfile
4390 def macOS = OperatingSystem.current().isMacOsX()
4391 def chromiumBinary = macOS ? jalviewjs_macos_chromium_binary : jalviewjs_chromium_binary
4392 if (chromiumBinary.startsWith("~/")) {
4393 chromiumBinary = System.getProperty("user.home") + chromiumBinary.substring(1)
4399 def timeoutms = Integer.valueOf(jalviewjs_chromium_overall_timeout) * 1000
4401 def binary = file(chromiumBinary)
4402 if (!binary.exists()) {
4403 throw new StopExecutionException("Could not find chromium binary '${chromiumBinary}'. Cannot run task ${name}.")
4405 stdout = new ByteArrayOutputStream()
4406 stderr = new ByteArrayOutputStream()
4409 if (jalviewjs_j2s_to_console.equals("true")) {
4410 execStdout = new org.apache.tools.ant.util.TeeOutputStream(
4413 execStderr = new org.apache.tools.ant.util.TeeOutputStream(
4421 "--no-sandbox", // --no-sandbox IS USED BY THE THORIUM APPIMAGE ON THE BUILDSERVER
4424 "--timeout=${timeoutms}",
4425 "--virtual-time-budget=${timeoutms}",
4426 "--user-data-dir=${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_chromium_user_dir}",
4427 "--profile-directory=${jalviewjs_chromium_profile_name}",
4428 "--allow-file-access-from-files",
4429 "--enable-logging=stderr",
4430 "file://${jalviewDirAbsolutePath}/${jalviewjsStderrLaunchFilename}"
4433 if (true || macOS) {
4434 ScheduledExecutorService executor = Executors.newScheduledThreadPool(3);
4435 Future f1 = executor.submit(
4438 standardOutput = execStdout
4439 errorOutput = execStderr
4440 executable(chromiumBinary)
4442 println "COMMAND: '"+commandLine.join(" ")+"'"
4444 executor.shutdownNow()
4448 def noChangeBytes = 0
4449 def noChangeIterations = 0
4450 executor.scheduleAtFixedRate(
4452 String stderrString = stderr.toString()
4453 // shutdown the task if we have a success string
4454 if (stderrString.contains(jalviewjs_desktop_init_string)) {
4457 executor.shutdownNow()
4459 // if no change in stderr for 10s then also end
4460 if (noChangeIterations >= jalviewjs_chromium_idle_timeout) {
4461 executor.shutdownNow()
4463 if (stderrString.length() == noChangeBytes) {
4464 noChangeIterations++
4466 noChangeBytes = stderrString.length()
4467 noChangeIterations = 0
4470 1, 1, TimeUnit.SECONDS)
4472 executor.schedule(new Runnable(){
4475 executor.shutdownNow()
4477 }, timeoutms, TimeUnit.MILLISECONDS)
4479 executor.awaitTermination(timeoutms+10000, TimeUnit.MILLISECONDS)
4480 executor.shutdownNow()
4487 stderr.toString().eachLine { line ->
4488 if (line.contains(jalviewjs_desktop_init_string)) {
4489 println("Found line '"+line+"'")
4495 throw new GradleException("Could not find evidence of Desktop launch in JalviewJS.")
4503 description "Build the JalviewJS site and run the launch test"
4504 dependsOn jalviewjsBuildSite
4505 dependsOn jalviewjsLaunchTest