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 '4.0.3'
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("")
582 jalviewjsChromiumUserDir = "${jalviewjsBuildDir}/${jalviewjs_chromium_user_dir}"
583 jalviewjsChromiumProfileDir = "${ext.jalviewjsChromiumUserDir}/${jalviewjs_chromium_profile_name}"
593 outputDir = file(classesDir)
597 srcDirs = [ resourcesBuildDir, docBuildDir, helpBuildDir ]
600 compileClasspath = files(sourceSets.main.java.outputDir)
601 compileClasspath += fileTree(dir: "${jalviewDir}/${libDir}", include: ["*.jar"])
603 runtimeClasspath = compileClasspath
604 runtimeClasspath += files(sourceSets.main.resources.srcDirs)
609 srcDirs cloverInstrDir
610 outputDir = cloverClassesDir
614 srcDirs = sourceSets.main.resources.srcDirs
617 compileClasspath = files( sourceSets.clover.java.outputDir )
618 //compileClasspath += files( testClassesDir )
619 compileClasspath += fileTree(dir: "${jalviewDir}/${libDir}", include: ["*.jar"])
620 compileClasspath += fileTree(dir: "${jalviewDir}/${clover_lib_dir}", include: ["*.jar"])
621 compileClasspath += fileTree(dir: "${jalviewDir}/${utils_dir}/testnglibs", include: ["**/*.jar"])
623 runtimeClasspath = compileClasspath
628 srcDirs testSourceDir
629 outputDir = file(testClassesDir)
633 srcDirs = useClover ? sourceSets.clover.resources.srcDirs : sourceSets.main.resources.srcDirs
636 compileClasspath = files( sourceSets.test.java.outputDir )
637 compileClasspath += useClover ? sourceSets.clover.compileClasspath : sourceSets.main.compileClasspath
638 compileClasspath += fileTree(dir: "${jalviewDir}/${utils_dir}/testnglibs", include: ["**/*.jar"])
640 runtimeClasspath = compileClasspath
641 runtimeClasspath += files(sourceSets.test.resources.srcDirs)
647 // eclipse project and settings files creation, also used by buildship
650 name = eclipse_project_name
652 natures 'org.eclipse.jdt.core.javanature',
653 'org.eclipse.jdt.groovy.core.groovyNature',
654 'org.eclipse.buildship.core.gradleprojectnature'
656 buildCommand 'org.eclipse.jdt.core.javabuilder'
657 buildCommand 'org.eclipse.buildship.core.gradleprojectbuilder'
661 //defaultOutputDir = sourceSets.main.java.outputDir
662 configurations.each{ c->
663 if (c.isCanBeResolved()) {
664 minusConfigurations += [c]
668 plusConfigurations = [ ]
672 def removeTheseToo = []
673 HashMap<String, Boolean> alreadyAddedSrcPath = new HashMap<>();
674 cp.entries.each { entry ->
675 // This conditional removes all src classpathentries that a) have already been added or b) aren't "src" or "test".
676 // e.g. this removes the resources dir being copied into bin/main, bin/test AND bin/clover
677 // we add the resources and help/help dirs in as libs afterwards (see below)
678 if (entry.kind == 'src') {
679 if (alreadyAddedSrcPath.getAt(entry.path) || !(entry.path == bareSourceDir || entry.path == bareTestSourceDir)) {
680 removeTheseToo += entry
682 alreadyAddedSrcPath.putAt(entry.path, true)
687 cp.entries.removeAll(removeTheseToo)
689 //cp.entries += new Output("${eclipse_bin_dir}/main")
690 if (file(helpParentDir).isDirectory()) {
691 cp.entries += new Library(fileReference(helpParentDir))
693 if (file(resourceDir).isDirectory()) {
694 cp.entries += new Library(fileReference(resourceDir))
697 HashMap<String, Boolean> alreadyAddedLibPath = new HashMap<>();
699 sourceSets.main.compileClasspath.findAll { it.name.endsWith(".jar") }.any {
700 //don't want to add outputDir as eclipse is using its own output dir in bin/main
701 if (it.isDirectory() || ! it.exists()) {
702 // don't add dirs to classpath, especially if they don't exist
703 return false // groovy "continue" in .any closure
705 def itPath = it.toString()
706 if (itPath.startsWith("${jalviewDirAbsolutePath}/")) {
707 // make relative path
708 itPath = itPath.substring(jalviewDirAbsolutePath.length()+1)
710 if (alreadyAddedLibPath.get(itPath)) {
711 //println("Not adding duplicate entry "+itPath)
713 //println("Adding entry "+itPath)
714 cp.entries += new Library(fileReference(itPath))
715 alreadyAddedLibPath.put(itPath, true)
719 sourceSets.test.compileClasspath.findAll { it.name.endsWith(".jar") }.any {
720 //no longer want to add outputDir as eclipse is using its own output dir in bin/main
721 if (it.isDirectory() || ! it.exists()) {
722 // don't add dirs to classpath
723 return false // groovy "continue" in .any closure
726 def itPath = it.toString()
727 if (itPath.startsWith("${jalviewDirAbsolutePath}/")) {
728 itPath = itPath.substring(jalviewDirAbsolutePath.length()+1)
730 if (alreadyAddedLibPath.get(itPath)) {
733 def lib = new Library(fileReference(itPath))
734 lib.entryAttributes["test"] = "true"
736 alreadyAddedLibPath.put(itPath, true)
744 containers 'org.eclipse.buildship.core.gradleclasspathcontainer'
749 // for the IDE, use java 11 compatibility
750 sourceCompatibility = compile_source_compatibility
751 targetCompatibility = compile_target_compatibility
752 javaRuntimeName = eclipseJavaRuntimeName
754 // add in jalview project specific properties/preferences into eclipse core preferences
756 withProperties { props ->
757 def jalview_prefs = new Properties()
758 def ins = new FileInputStream("${jalviewDirAbsolutePath}/${eclipse_extra_jdt_prefs_file}")
759 jalview_prefs.load(ins)
761 jalview_prefs.forEach { t, v ->
762 if (props.getAt(t) == null) {
766 // codestyle file -- overrides previous formatter prefs
767 def csFile = file("${jalviewDirAbsolutePath}/${eclipse_codestyle_file}")
768 if (csFile.exists()) {
769 XmlParser parser = new XmlParser()
770 def profiles = parser.parse(csFile)
771 def profile = profiles.'profile'.find { p -> (p.'@kind' == "CodeFormatterProfile" && p.'@name' == "Jalview") }
772 if (profile != null) {
773 profile.'setting'.each { s ->
775 def value = s.'@value'
776 if (id != null && value != null) {
777 props.putAt(id, value)
788 // Don't want these to be activated if in headless build
789 synchronizationTasks "eclipseSynchronizationTask"
790 //autoBuildTasks "eclipseAutoBuildTask"
796 /* hack to change eclipse prefs in .settings files other than org.eclipse.jdt.core.prefs */
797 // Class to allow updating arbitrary properties files
798 class PropertiesFile extends PropertiesPersistableConfigurationObject {
799 public PropertiesFile(PropertiesTransformer t) { super(t); }
800 @Override protected void load(Properties properties) { }
801 @Override protected void store(Properties properties) { }
802 @Override protected String getDefaultResourceName() { return ""; }
803 // This is necessary, because PropertiesPersistableConfigurationObject fails
804 // if no default properties file exists.
805 @Override public void loadDefaults() { load(new StringBufferInputStream("")); }
808 // Task to update arbitrary properties files (set outputFile)
809 class PropertiesFileTask extends PropertiesGeneratorTask<PropertiesFile> {
810 private final PropertiesFileContentMerger file;
811 public PropertiesFileTask() { file = new PropertiesFileContentMerger(getTransformer()); }
812 protected PropertiesFile create() { return new PropertiesFile(getTransformer()); }
813 protected void configure(PropertiesFile props) {
814 file.getBeforeMerged().execute(props); file.getWhenMerged().execute(props);
816 public void file(Closure closure) { ConfigureUtil.configure(closure, file); }
819 task eclipseUIPreferences(type: PropertiesFileTask) {
820 description = "Generate Eclipse additional settings"
821 def filename = "org.eclipse.jdt.ui.prefs"
822 outputFile = "$projectDir/.settings/${filename}" as File
825 it.load new FileInputStream("$projectDir/utils/eclipse/${filename}" as String)
830 task eclipseGroovyCorePreferences(type: PropertiesFileTask) {
831 description = "Generate Eclipse additional settings"
832 def filename = "org.eclipse.jdt.groovy.core.prefs"
833 outputFile = "$projectDir/.settings/${filename}" as File
836 it.load new FileInputStream("$projectDir/utils/eclipse/${filename}" as String)
841 task eclipseBuildshipCorePreferences(type: PropertiesFileTask) {
842 description = "Generate Eclipse additional settings"
843 def filename = "org.eclipse.buildship.core.prefs"
844 outputFile = "$projectDir/.settings/${filename}" as File
847 it.load new FileInputStream("$projectDir/utils/eclipse/${filename}" as String)
852 task eclipseAllPreferences {
854 dependsOn eclipseUIPreferences
855 dependsOn eclipseGroovyCorePreferences
856 dependsOn eclipseBuildshipCorePreferences
859 eclipseUIPreferences.mustRunAfter eclipseJdt
860 eclipseGroovyCorePreferences.mustRunAfter eclipseJdt
861 eclipseBuildshipCorePreferences.mustRunAfter eclipseJdt
863 /* end of eclipse preferences hack */
871 delete cloverBuildDir
872 delete cloverReportDir
877 task cloverInstrJava(type: JavaExec) {
878 group = "Verification"
879 description = "Create clover instrumented source java files"
881 dependsOn cleanClover
883 inputs.files(sourceSets.main.allJava)
884 outputs.dir(cloverInstrDir)
886 //classpath = fileTree(dir: "${jalviewDir}/${clover_lib_dir}", include: ["*.jar"])
887 classpath = sourceSets.clover.compileClasspath
888 main = "com.atlassian.clover.CloverInstr"
896 cloverInstrDir.getPath(),
898 def srcFiles = sourceSets.main.allJava.files
901 { file -> file.absolutePath }
904 args argsList.toArray()
907 delete cloverInstrDir
908 println("Clover: About to instrument "+srcFiles.size() +" files")
913 task cloverInstrTests(type: JavaExec) {
914 group = "Verification"
915 description = "Create clover instrumented source test files"
917 dependsOn cleanClover
919 inputs.files(testDir)
920 outputs.dir(cloverTestInstrDir)
922 classpath = sourceSets.clover.compileClasspath
923 main = "com.atlassian.clover.CloverInstr"
933 cloverTestInstrDir.getPath(),
935 args argsList.toArray()
938 delete cloverTestInstrDir
939 println("Clover: About to instrument test files")
945 group = "Verification"
946 description = "Create clover instrumented all source files"
948 dependsOn cloverInstrJava
949 dependsOn cloverInstrTests
953 cloverClasses.dependsOn cloverInstr
956 task cloverConsoleReport(type: JavaExec) {
957 group = "Verification"
958 description = "Creates clover console report"
961 file(cloverDb).exists()
964 inputs.dir cloverClassesDir
966 classpath = sourceSets.clover.runtimeClasspath
967 main = "com.atlassian.clover.reporters.console.ConsoleReporter"
969 if (cloverreport_mem.length() > 0) {
970 maxHeapSize = cloverreport_mem
972 if (cloverreport_jvmargs.length() > 0) {
973 jvmArgs Arrays.asList(cloverreport_jvmargs.split(" "))
983 args argsList.toArray()
987 task cloverHtmlReport(type: JavaExec) {
988 group = "Verification"
989 description = "Creates clover HTML report"
992 file(cloverDb).exists()
995 def cloverHtmlDir = cloverReportDir
996 inputs.dir cloverClassesDir
997 outputs.dir cloverHtmlDir
999 classpath = sourceSets.clover.runtimeClasspath
1000 main = "com.atlassian.clover.reporters.html.HtmlReporter"
1002 if (cloverreport_mem.length() > 0) {
1003 maxHeapSize = cloverreport_mem
1005 if (cloverreport_jvmargs.length() > 0) {
1006 jvmArgs Arrays.asList(cloverreport_jvmargs.split(" "))
1017 if (cloverreport_html_options.length() > 0) {
1018 argsList += cloverreport_html_options.split(" ")
1021 args argsList.toArray()
1025 task cloverXmlReport(type: JavaExec) {
1026 group = "Verification"
1027 description = "Creates clover XML report"
1030 file(cloverDb).exists()
1033 def cloverXmlFile = "${cloverReportDir}/clover.xml"
1034 inputs.dir cloverClassesDir
1035 outputs.file cloverXmlFile
1037 classpath = sourceSets.clover.runtimeClasspath
1038 main = "com.atlassian.clover.reporters.xml.XMLReporter"
1040 if (cloverreport_mem.length() > 0) {
1041 maxHeapSize = cloverreport_mem
1043 if (cloverreport_jvmargs.length() > 0) {
1044 jvmArgs Arrays.asList(cloverreport_jvmargs.split(" "))
1055 if (cloverreport_xml_options.length() > 0) {
1056 argsList += cloverreport_xml_options.split(" ")
1059 args argsList.toArray()
1064 group = "Verification"
1065 description = "Creates clover reports"
1067 dependsOn cloverXmlReport
1068 dependsOn cloverHtmlReport
1075 sourceCompatibility = compile_source_compatibility
1076 targetCompatibility = compile_target_compatibility
1077 options.compilerArgs += additional_compiler_args
1078 print ("Setting target compatibility to "+targetCompatibility+"\n")
1080 //classpath += configurations.cloverRuntime
1086 // JBP->BS should the print statement in doFirst refer to compile_target_compatibility ?
1087 sourceCompatibility = compile_source_compatibility
1088 targetCompatibility = compile_target_compatibility
1089 options.compilerArgs += additional_compiler_args
1090 options.encoding = "UTF-8"
1092 print ("Setting target compatibility to "+compile_target_compatibility+"\n")
1099 sourceCompatibility = compile_source_compatibility
1100 targetCompatibility = compile_target_compatibility
1101 options.compilerArgs += additional_compiler_args
1103 print ("Setting target compatibility to "+targetCompatibility+"\n")
1110 delete sourceSets.main.java.outputDir
1116 dependsOn cleanClover
1118 delete sourceSets.test.java.outputDir
1123 // format is a string like date.format("dd MMMM yyyy")
1124 def getDate(format) {
1125 return date.format(format)
1129 def convertMdToHtml (FileTree mdFiles, File cssFile) {
1130 MutableDataSet options = new MutableDataSet()
1132 def extensions = new ArrayList<>()
1133 extensions.add(AnchorLinkExtension.create())
1134 extensions.add(AutolinkExtension.create())
1135 extensions.add(StrikethroughExtension.create())
1136 extensions.add(TaskListExtension.create())
1137 extensions.add(TablesExtension.create())
1138 extensions.add(TocExtension.create())
1140 options.set(Parser.EXTENSIONS, extensions)
1142 // set GFM table parsing options
1143 options.set(TablesExtension.WITH_CAPTION, false)
1144 options.set(TablesExtension.COLUMN_SPANS, false)
1145 options.set(TablesExtension.MIN_HEADER_ROWS, 1)
1146 options.set(TablesExtension.MAX_HEADER_ROWS, 1)
1147 options.set(TablesExtension.APPEND_MISSING_COLUMNS, true)
1148 options.set(TablesExtension.DISCARD_EXTRA_COLUMNS, true)
1149 options.set(TablesExtension.HEADER_SEPARATOR_COLUMN_MATCH, true)
1151 options.set(AnchorLinkExtension.ANCHORLINKS_SET_ID, false)
1152 options.set(AnchorLinkExtension.ANCHORLINKS_ANCHOR_CLASS, "anchor")
1153 options.set(AnchorLinkExtension.ANCHORLINKS_SET_NAME, true)
1154 options.set(AnchorLinkExtension.ANCHORLINKS_TEXT_PREFIX, "<span class=\"octicon octicon-link\"></span>")
1156 Parser parser = Parser.builder(options).build()
1157 HtmlRenderer renderer = HtmlRenderer.builder(options).build()
1159 mdFiles.each { mdFile ->
1160 // add table of contents
1161 def mdText = "[TOC]\n"+mdFile.text
1163 // grab the first top-level title
1165 def titleRegex = /(?m)^#(\s+|([^#]))(.*)/
1166 def matcher = mdText =~ titleRegex
1167 if (matcher.size() > 0) {
1168 // matcher[0][2] is the first character of the title if there wasn't any whitespace after the #
1169 title = (matcher[0][2] != null ? matcher[0][2] : "")+matcher[0][3]
1171 // or use the filename if none found
1172 if (title == null) {
1173 title = mdFile.getName()
1176 Node document = parser.parse(mdText)
1177 String htmlBody = renderer.render(document)
1178 def htmlText = '''<html>
1179 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
1180 <html xmlns="http://www.w3.org/1999/xhtml">
1182 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
1183 <meta http-equiv="Content-Style-Type" content="text/css" />
1184 <meta name="generator" content="flexmark" />
1186 htmlText += ((title != null) ? " <title>${title}</title>" : '' )
1188 <style type="text/css">code{white-space: pre;}</style>
1190 htmlText += ((cssFile != null) ? cssFile.text : '')
1191 htmlText += '''</head>
1194 htmlText += htmlBody
1200 def htmlFilePath = mdFile.getPath().replaceAll(/\..*?$/, ".html")
1201 def htmlFile = file(htmlFilePath)
1202 println("Creating ${htmlFilePath}")
1203 htmlFile.text = htmlText
1208 task copyDocs(type: Copy) {
1209 def inputDir = "${jalviewDir}/${doc_dir}"
1210 def outputDir = "${docBuildDir}/${doc_dir}"
1214 include('**/*.html')
1216 filter(ReplaceTokens,
1220 'Version-Rel': JALVIEW_VERSION,
1221 'Year-Rel': getDate("yyyy")
1228 exclude('**/*.html')
1233 inputs.dir(inputDir)
1234 outputs.dir(outputDir)
1238 task convertMdFiles {
1240 def mdFiles = fileTree(dir: docBuildDir, include: "**/*.md")
1241 def cssFile = file("${jalviewDir}/${flexmark_css}")
1244 convertMdToHtml(mdFiles, cssFile)
1247 inputs.files(mdFiles)
1248 inputs.file(cssFile)
1251 mdFiles.each { mdFile ->
1252 def htmlFilePath = mdFile.getPath().replaceAll(/\..*?$/, ".html")
1253 htmlFiles.add(file(htmlFilePath))
1255 outputs.files(htmlFiles)
1259 def hugoTemplateSubstitutions(String input, Map extras=null) {
1260 def replacements = [
1261 DATE: getDate("yyyy-MM-dd"),
1262 CHANNEL: propertiesChannelName,
1263 APPLICATION_NAME: applicationName,
1265 GIT_BRANCH: gitBranch,
1266 VERSION: JALVIEW_VERSION,
1267 JAVA_VERSION: JAVA_VERSION,
1268 VERSION_UNDERSCORES: JALVIEW_VERSION_UNDERSCORES,
1273 if (extras != null) {
1274 extras.each{ k, v ->
1275 output = output.replaceAll("__${k}__", ((v == null)?"":v))
1278 replacements.each{ k, v ->
1279 output = output.replaceAll("__${k}__", ((v == null)?"":v))
1284 def mdFileComponents(File mdFile, def dateOnly=false) {
1287 if (mdFile.exists()) {
1288 def inFrontMatter = false
1289 def firstLine = true
1290 mdFile.eachLine { line ->
1291 if (line.matches("---")) {
1292 def prev = inFrontMatter
1293 inFrontMatter = firstLine
1294 if (inFrontMatter != prev)
1297 if (inFrontMatter) {
1299 if (m = line =~ /^date:\s*(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})/) {
1300 map["date"] = new Date().parse("yyyy-MM-dd HH:mm:ss", m[0][1])
1301 } else if (m = line =~ /^date:\s*(\d{4}-\d{2}-\d{2})/) {
1302 map["date"] = new Date().parse("yyyy-MM-dd", m[0][1])
1303 } else if (m = line =~ /^channel:\s*(\S+)/) {
1304 map["channel"] = m[0][1]
1305 } else if (m = line =~ /^version:\s*(\S+)/) {
1306 map["version"] = m[0][1]
1307 } else if (m = line =~ /^\s*([^:]+)\s*:\s*(\S.*)/) {
1308 map[ m[0][1] ] = m[0][2]
1310 if (dateOnly && map["date"] != null) {
1316 content += line+"\n"
1321 return dateOnly ? map["date"] : [map, content]
1324 task hugoTemplates {
1326 description "Create partially populated md pages for hugo website build"
1328 def hugoTemplatesDir = file("${jalviewDir}/${hugo_templates_dir}")
1329 def hugoBuildDir = "${jalviewDir}/${hugo_build_dir}"
1330 def templateFiles = fileTree(dir: hugoTemplatesDir)
1331 def releaseMdFile = file("${jalviewDir}/${releases_dir}/release-${JALVIEW_VERSION_UNDERSCORES}.md")
1332 def whatsnewMdFile = file("${jalviewDir}/${whatsnew_dir}/whatsnew-${JALVIEW_VERSION_UNDERSCORES}.md")
1333 def oldJvlFile = file("${jalviewDir}/${hugo_old_jvl}")
1334 def jalviewjsFile = file("${jalviewDir}/${hugo_jalviewjs}")
1337 // specific release template for version archive
1340 def givenDate = null
1341 def givenChannel = null
1342 def givenVersion = null
1343 if (CHANNEL == "RELEASE") {
1344 def (map, content) = mdFileComponents(releaseMdFile)
1345 givenDate = map.date
1346 givenChannel = map.channel
1347 givenVersion = map.version
1349 if (givenVersion != null && givenVersion != JALVIEW_VERSION) {
1350 throw new GradleException("'version' header (${givenVersion}) found in ${releaseMdFile} does not match JALVIEW_VERSION (${JALVIEW_VERSION})")
1353 if (whatsnewMdFile.exists())
1354 whatsnew = whatsnewMdFile.text
1357 def oldJvl = oldJvlFile.exists() ? oldJvlFile.collect{it} : []
1358 def jalviewjsLink = jalviewjsFile.exists() ? jalviewjsFile.collect{it} : []
1360 def changesHugo = null
1361 if (changes != null) {
1362 changesHugo = '<div class="release_notes">\n\n'
1363 def inSection = false
1364 changes.eachLine { line ->
1366 if (m = line =~ /^##([^#].*)$/) {
1368 changesHugo += "</div>\n\n"
1370 def section = m[0][1].trim()
1371 section = section.toLowerCase()
1372 section = section.replaceAll(/ +/, "_")
1373 section = section.replaceAll(/[^a-z0-9_\-]/, "")
1374 changesHugo += "<div class=\"${section}\">\n\n"
1376 } else if (m = line =~ /^(\s*-\s*)<!--([^>]+)-->(.*?)(<br\/?>)?\s*$/) {
1377 def comment = m[0][2].trim()
1378 if (comment != "") {
1379 comment = comment.replaceAll('"', """)
1381 comment.eachMatch(/JAL-\d+/) { jal -> issuekeys += jal }
1382 def newline = m[0][1]
1383 if (comment.trim() != "")
1384 newline += "{{<comment>}}${comment}{{</comment>}} "
1385 newline += m[0][3].trim()
1386 if (issuekeys.size() > 0)
1387 newline += " {{< jal issue=\"${issuekeys.join(",")}\" alt=\"${comment}\" >}}"
1388 if (m[0][4] != null)
1393 changesHugo += line+"\n"
1396 changesHugo += "\n</div>\n\n"
1398 changesHugo += '</div>'
1401 templateFiles.each{ templateFile ->
1402 def newFileName = string(hugoTemplateSubstitutions(templateFile.getName()))
1403 def relPath = hugoTemplatesDir.toPath().relativize(templateFile.toPath()).getParent()
1404 def newRelPathName = hugoTemplateSubstitutions( relPath.toString() )
1406 def outPathName = string("${hugoBuildDir}/$newRelPathName")
1410 rename(templateFile.getName(), newFileName)
1414 def newFile = file("${outPathName}/${newFileName}".toString())
1415 def content = newFile.text
1416 newFile.text = hugoTemplateSubstitutions(content,
1419 CHANGES: changesHugo,
1420 DATE: givenDate == null ? "" : givenDate.format("yyyy-MM-dd"),
1421 DRAFT: givenDate == null ? "true" : "false",
1422 JALVIEWJSLINK: jalviewjsLink.contains(JALVIEW_VERSION) ? "true" : "false",
1423 JVL_HEADER: oldJvl.contains(JALVIEW_VERSION) ? "jvl: true" : ""
1430 inputs.file(oldJvlFile)
1431 inputs.dir(hugoTemplatesDir)
1432 inputs.property("JALVIEW_VERSION", { JALVIEW_VERSION })
1433 inputs.property("CHANNEL", { CHANNEL })
1436 def getMdDate(File mdFile) {
1437 return mdFileComponents(mdFile, true)
1440 def getMdSections(String content) {
1442 def sectionContent = ""
1443 def sectionName = null
1444 content.eachLine { line ->
1446 if (m = line =~ /^##([^#].*)$/) {
1447 if (sectionName != null) {
1448 sections[sectionName] = sectionContent
1452 sectionName = m[0][1].trim()
1453 sectionName = sectionName.toLowerCase()
1454 sectionName = sectionName.replaceAll(/ +/, "_")
1455 sectionName = sectionName.replaceAll(/[^a-z0-9_\-]/, "")
1456 } else if (sectionName != null) {
1457 sectionContent += line+"\n"
1460 if (sectionContent != null) {
1461 sections[sectionName] = sectionContent
1467 task copyHelp(type: Copy) {
1468 def inputDir = helpSourceDir
1469 def outputDir = "${helpBuildDir}/${help_dir}"
1473 include('**/*.html')
1477 filter(ReplaceTokens,
1481 'Version-Rel': JALVIEW_VERSION,
1482 'Year-Rel': getDate("yyyy")
1489 exclude('**/*.html')
1496 inputs.dir(inputDir)
1497 outputs.files(helpFile)
1498 outputs.dir(outputDir)
1502 task releasesTemplates {
1504 description "Recreate whatsNew.html and releases.html from markdown files and templates in help"
1508 def releasesTemplateFile = file("${jalviewDir}/${releases_template}")
1509 def whatsnewTemplateFile = file("${jalviewDir}/${whatsnew_template}")
1510 def releasesHtmlFile = file("${helpBuildDir}/${help_dir}/${releases_html}")
1511 def whatsnewHtmlFile = file("${helpBuildDir}/${help_dir}/${whatsnew_html}")
1512 def releasesMdDir = "${jalviewDir}/${releases_dir}"
1513 def whatsnewMdDir = "${jalviewDir}/${whatsnew_dir}"
1516 def releaseMdFile = file("${releasesMdDir}/release-${JALVIEW_VERSION_UNDERSCORES}.md")
1517 def whatsnewMdFile = file("${whatsnewMdDir}/whatsnew-${JALVIEW_VERSION_UNDERSCORES}.md")
1519 if (CHANNEL == "RELEASE") {
1520 if (!releaseMdFile.exists()) {
1521 throw new GradleException("File ${releaseMdFile} must be created for RELEASE")
1523 if (!whatsnewMdFile.exists()) {
1524 throw new GradleException("File ${whatsnewMdFile} must be created for RELEASE")
1528 def releaseFiles = fileTree(dir: releasesMdDir, include: "release-*.md")
1529 def releaseFilesDates = releaseFiles.collectEntries {
1530 [(it): getMdDate(it)]
1532 releaseFiles = releaseFiles.sort { a,b -> releaseFilesDates[a].compareTo(releaseFilesDates[b]) }
1534 def releasesTemplate = releasesTemplateFile.text
1535 def m = releasesTemplate =~ /(?s)__VERSION_LOOP_START__(.*)__VERSION_LOOP_END__/
1536 def versionTemplate = m[0][1]
1538 MutableDataSet options = new MutableDataSet()
1540 def extensions = new ArrayList<>()
1541 options.set(Parser.EXTENSIONS, extensions)
1542 options.set(Parser.HTML_BLOCK_COMMENT_ONLY_FULL_LINE, true)
1544 Parser parser = Parser.builder(options).build()
1545 HtmlRenderer renderer = HtmlRenderer.builder(options).build()
1547 def actualVersions = releaseFiles.collect { rf ->
1548 def (rfMap, rfContent) = mdFileComponents(rf)
1549 return rfMap.version
1551 def versionsHtml = ""
1552 def linkedVersions = []
1553 releaseFiles.reverse().each { rFile ->
1554 def (rMap, rContent) = mdFileComponents(rFile)
1556 def versionLink = ""
1557 def partialVersion = ""
1558 def firstPart = true
1559 rMap.version.split("\\.").each { part ->
1560 def displayPart = ( firstPart ? "" : "." ) + part
1561 partialVersion += displayPart
1563 linkedVersions.contains(partialVersion)
1564 || ( actualVersions.contains(partialVersion) && partialVersion != rMap.version )
1566 versionLink += displayPart
1568 versionLink += "<a id=\"Jalview.${partialVersion}\">${displayPart}</a>"
1569 linkedVersions += partialVersion
1573 def displayDate = releaseFilesDates[rFile].format("dd/MM/yyyy")
1576 def rContentProcessed = ""
1577 rContent.eachLine { line ->
1578 if (lm = line =~ /^(\s*-)(\s*<!--[^>]*?-->)(.*)$/) {
1579 line = "${lm[0][1]}${lm[0][3]}${lm[0][2]}"
1580 } else if (lm = line =~ /^###([^#]+.*)$/) {
1581 line = "_${lm[0][1].trim()}_"
1583 rContentProcessed += line + "\n"
1586 def rContentSections = getMdSections(rContentProcessed)
1587 def rVersion = versionTemplate
1588 if (rVersion != "") {
1589 def rNewFeatures = rContentSections["new_features"]
1590 def rIssuesResolved = rContentSections["issues_resolved"]
1591 Node newFeaturesNode = parser.parse(rNewFeatures)
1592 String newFeaturesHtml = renderer.render(newFeaturesNode)
1593 Node issuesResolvedNode = parser.parse(rIssuesResolved)
1594 String issuesResolvedHtml = renderer.render(issuesResolvedNode)
1595 rVersion = hugoTemplateSubstitutions(rVersion,
1597 VERSION: rMap.version,
1598 VERSION_LINK: versionLink,
1599 DISPLAY_DATE: displayDate,
1600 NEW_FEATURES: newFeaturesHtml,
1601 ISSUES_RESOLVED: issuesResolvedHtml
1604 versionsHtml += rVersion
1608 releasesTemplate = releasesTemplate.replaceAll("(?s)__VERSION_LOOP_START__.*__VERSION_LOOP_END__", versionsHtml)
1609 releasesTemplate = hugoTemplateSubstitutions(releasesTemplate)
1610 releasesHtmlFile.text = releasesTemplate
1612 if (whatsnewMdFile.exists()) {
1613 def wnDisplayDate = releaseFilesDates[releaseMdFile] != null ? releaseFilesDates[releaseMdFile].format("dd MMMM yyyy") : ""
1614 def whatsnewMd = hugoTemplateSubstitutions(whatsnewMdFile.text)
1615 Node whatsnewNode = parser.parse(whatsnewMd)
1616 String whatsnewHtml = renderer.render(whatsnewNode)
1617 whatsnewHtml = whatsnewTemplateFile.text.replaceAll("__WHATS_NEW__", whatsnewHtml)
1618 whatsnewHtmlFile.text = hugoTemplateSubstitutions(whatsnewHtml,
1620 VERSION: JALVIEW_VERSION,
1621 DISPLAY_DATE: wnDisplayDate
1624 } else if (gradle.taskGraph.hasTask(":linkCheck")) {
1625 whatsnewHtmlFile.text = "Development build " + getDate("yyyy-MM-dd HH:mm:ss")
1630 inputs.file(releasesTemplateFile)
1631 inputs.file(whatsnewTemplateFile)
1632 inputs.dir(releasesMdDir)
1633 inputs.dir(whatsnewMdDir)
1634 outputs.file(releasesHtmlFile)
1635 outputs.file(whatsnewHtmlFile)
1639 task copyResources(type: Copy) {
1641 description = "Copy (and make text substitutions in) the resources dir to the build area"
1643 def inputDir = resourceDir
1644 def outputDir = resourcesBuildDir
1648 include('**/*.html')
1650 filter(ReplaceTokens,
1654 'Version-Rel': JALVIEW_VERSION,
1655 'Year-Rel': getDate("yyyy")
1662 exclude('**/*.html')
1667 inputs.dir(inputDir)
1668 outputs.dir(outputDir)
1671 task copyChannelResources(type: Copy) {
1672 dependsOn copyResources
1674 description = "Copy the channel resources dir to the build resources area"
1676 def inputDir = "${channelDir}/${resource_dir}"
1677 def outputDir = resourcesBuildDir
1679 include(channel_props)
1680 filter(ReplaceTokens,
1684 'SUFFIX': channelSuffix
1689 exclude(channel_props)
1693 inputs.dir(inputDir)
1694 outputs.dir(outputDir)
1697 task createBuildProperties(type: WriteProperties) {
1698 dependsOn copyResources
1700 description = "Create the ${buildProperties} file"
1702 inputs.dir(sourceDir)
1703 inputs.dir(resourcesBuildDir)
1704 outputFile (buildProperties)
1705 // taking time specific comment out to allow better incremental builds
1706 comment "--Jalview Build Details--\n"+getDate("yyyy-MM-dd HH:mm:ss")
1707 //comment "--Jalview Build Details--\n"+getDate("yyyy-MM-dd")
1708 property "BUILD_DATE", getDate("HH:mm:ss dd MMMM yyyy")
1709 property "VERSION", JALVIEW_VERSION
1710 property "INSTALLATION", INSTALLATION+" git-commit:"+gitHash+" ["+gitBranch+"]"
1711 property "JAVA_COMPILE_VERSION", JAVA_INTEGER_VERSION
1712 if (getdownSetAppBaseProperty) {
1713 property "GETDOWNAPPBASE", getdownAppBase
1714 property "GETDOWNAPPDISTDIR", getdownAppDistDir
1716 outputs.file(outputFile)
1720 task buildIndices(type: JavaExec) {
1722 classpath = sourceSets.main.compileClasspath
1723 main = "com.sun.java.help.search.Indexer"
1724 workingDir = "${helpBuildDir}/${help_dir}"
1727 inputs.dir("${workingDir}/${argDir}")
1729 outputs.dir("${classesDir}/doc")
1730 outputs.dir("${classesDir}/help")
1731 outputs.file("${workingDir}/JavaHelpSearch/DOCS")
1732 outputs.file("${workingDir}/JavaHelpSearch/DOCS.TAB")
1733 outputs.file("${workingDir}/JavaHelpSearch/OFFSETS")
1734 outputs.file("${workingDir}/JavaHelpSearch/POSITIONS")
1735 outputs.file("${workingDir}/JavaHelpSearch/SCHEMA")
1736 outputs.file("${workingDir}/JavaHelpSearch/TMAP")
1739 task buildResources {
1740 dependsOn copyResources
1741 dependsOn copyChannelResources
1742 dependsOn createBuildProperties
1746 dependsOn buildResources
1749 dependsOn releasesTemplates
1750 dependsOn convertMdFiles
1751 dependsOn buildIndices
1755 compileJava.dependsOn prepare
1756 run.dependsOn compileJava
1757 compileTestJava.dependsOn compileJava
1762 group = "Verification"
1763 description = "Runs all testTaskN tasks)"
1766 dependsOn cloverClasses
1768 dependsOn testClasses
1771 // not running tests in this task
1774 /* testTask0 is the main test task */
1775 task testTask0(type: Test) {
1776 group = "Verification"
1777 description = "The main test task. Runs all non-testTaskN-labelled tests (unless excluded)"
1779 includeGroups testng_groups.split(",")
1780 excludeGroups testng_excluded_groups.split(",")
1781 tasks.withType(Test).matching {it.name.startsWith("testTask") && it.name != name}.all {t -> excludeGroups t.name}
1783 useDefaultListeners=true
1787 /* separated tests */
1788 task testTask1(type: Test) {
1789 group = "Verification"
1790 description = "Tests that need to be isolated from the main test run"
1793 excludeGroups testng_excluded_groups.split(",")
1795 useDefaultListeners=true
1799 /* insert more testTaskNs here -- change N to next digit or other string */
1801 task testTaskN(type: Test) {
1802 group = "Verification"
1803 description = "Tests that need to be isolated from the main test run"
1806 excludeGroups testng_excluded_groups.split(",")
1808 useDefaultListeners=true
1814 * adapted from https://medium.com/@wasyl/pretty-tests-summary-in-gradle-744804dd676c
1815 * to summarise test results from all Test tasks
1817 /* START of test tasks results summary */
1818 import groovy.time.TimeCategory
1819 import org.gradle.api.tasks.testing.logging.TestExceptionFormat
1820 import org.gradle.api.tasks.testing.logging.TestLogEvent
1821 rootProject.ext.testsResults = [] // Container for tests summaries
1823 tasks.withType(Test).matching {t -> t.getName().startsWith("testTask")}.all { testTask ->
1825 // from original test task
1827 dependsOn cloverClasses
1829 dependsOn testClasses //?
1832 // run main tests first
1833 if (!testTask.name.equals("testTask0"))
1834 testTask.mustRunAfter "testTask0"
1836 testTask.testLogging { logging ->
1837 events TestLogEvent.FAILED
1838 // TestLogEvent.SKIPPED,
1839 // TestLogEvent.STANDARD_OUT,
1840 // TestLogEvent.STANDARD_ERROR
1842 exceptionFormat TestExceptionFormat.FULL
1845 showStackTraces true
1847 info.events = [ TestLogEvent.FAILED ]
1852 ignoreFailures = true // Always try to run all tests for all modules
1854 afterSuite { desc, result ->
1856 return // Only summarize results for whole modules
1858 def resultsInfo = [testTask.project.name, testTask.name, result, TimeCategory.minus(new Date(result.endTime), new Date(result.startTime)), testTask.reports.html.entryPoint]
1860 rootProject.ext.testsResults.add(resultsInfo)
1863 // from original test task
1864 maxHeapSize = "1024m"
1866 workingDir = jalviewDir
1867 def testLaf = project.findProperty("test_laf")
1868 if (testLaf != null) {
1869 println("Setting Test LaF to '${testLaf}'")
1870 systemProperty "laf", testLaf
1872 def testHiDPIScale = project.findProperty("test_HiDPIScale")
1873 if (testHiDPIScale != null) {
1874 println("Setting Test HiDPI Scale to '${testHiDPIScale}'")
1875 systemProperty "sun.java2d.uiScale", testHiDPIScale
1877 sourceCompatibility = compile_source_compatibility
1878 targetCompatibility = compile_target_compatibility
1879 jvmArgs += additional_compiler_args
1882 // this is not perfect yet -- we should only add the commandLineIncludePatterns to the
1883 // testTasks that include the tests, and exclude all from the others.
1884 // get --test argument
1885 filter.commandLineIncludePatterns = test.filter.commandLineIncludePatterns
1886 // do something with testTask.getCandidateClassFiles() to see if the test should silently finish because of the
1887 // commandLineIncludePatterns not matching anything. Instead we are doing setFailOnNoMatchingTests(false) below
1891 println("Running tests " + (useClover?"WITH":"WITHOUT") + " clover")
1896 /* don't fail on no matching tests (so --tests will run across all testTasks) */
1897 testTask.filter.setFailOnNoMatchingTests(false)
1899 /* ensure the "test" task dependsOn all the testTasks */
1900 test.dependsOn testTask
1903 gradle.buildFinished {
1904 def allResults = rootProject.ext.testsResults
1906 if (!allResults.isEmpty()) {
1907 printResults allResults
1908 allResults.each {r ->
1909 if (r[2].resultType == TestResult.ResultType.FAILURE)
1910 throw new GradleException("Failed tests!")
1915 private static String colString(styler, col, colour, text) {
1916 return col?"${styler[colour](text)}":text
1919 private static String getSummaryLine(s, pn, tn, rt, rc, rs, rf, rsk, t, col) {
1920 def colour = 'black'
1928 case TestResult.ResultType.SUCCESS:
1931 case TestResult.ResultType.FAILURE:
1939 StringBuilder sb = new StringBuilder()
1943 sb.append(" results: ")
1944 sb.append(colString(s, col && !nocol, colour, text))
1946 sb.append("${rc} tests, ")
1947 sb.append(colString(s, col && rs > 0, 'green', rs))
1948 sb.append(" successes, ")
1949 sb.append(colString(s, col && rf > 0, 'red', rf))
1950 sb.append(" failures, ")
1951 sb.append("${rsk} skipped) in ${t}")
1952 return sb.toString()
1955 private static void printResults(allResults) {
1957 // styler from https://stackoverflow.com/a/56139852
1958 def styler = 'black red green yellow blue magenta cyan white'.split().toList().withIndex(30).collectEntries { key, val -> [(key) : { "\033[${val}m${it}\033[0m" }] }
1961 def failedTests = false
1962 def summaryLines = []
1964 def totalsuccess = 0
1967 def totaltime = TimeCategory.getSeconds(0)
1968 // sort on project name then task name
1969 allResults.sort {a, b -> a[0] == b[0]? a[1]<=>b[1]:a[0] <=> b[0]}.each {
1970 def projectName = it[0]
1971 def taskName = it[1]
1975 def summaryCol = getSummaryLine(styler, projectName, taskName, result.resultType, result.testCount, result.successfulTestCount, result.failedTestCount, result.skippedTestCount, time, true)
1976 def summaryPlain = getSummaryLine(styler, projectName, taskName, result.resultType, result.testCount, result.successfulTestCount, result.failedTestCount, result.skippedTestCount, time, false)
1977 def reportLine = "Report file: ${report}"
1978 def ls = summaryPlain.length()
1979 def lr = reportLine.length()
1980 def m = [ls, lr].max()
1983 def info = [ls, summaryCol, reportLine]
1984 summaryLines.add(info)
1985 failedTests |= result.resultType == TestResult.ResultType.FAILURE
1986 totalcount += result.testCount
1987 totalsuccess += result.successfulTestCount
1988 totalfail += result.failedTestCount
1989 totalskip += result.skippedTestCount
1992 def totalSummaryCol = getSummaryLine(styler, "OVERALL", "", failedTests?TestResult.ResultType.FAILURE:TestResult.ResultType.SUCCESS, totalcount, totalsuccess, totalfail, totalskip, totaltime, true)
1993 def totalSummaryPlain = getSummaryLine(styler, "OVERALL", "", failedTests?TestResult.ResultType.FAILURE:TestResult.ResultType.SUCCESS, totalcount, totalsuccess, totalfail, totalskip, totaltime, false)
1994 def tls = totalSummaryPlain.length()
1995 if (tls > maxLength)
1997 def info = [tls, totalSummaryCol, null]
1998 summaryLines.add(info)
2000 def allSummaries = []
2001 for(sInfo : summaryLines) {
2003 def summary = sInfo[1]
2004 def report = sInfo[2]
2006 StringBuilder sb = new StringBuilder()
2007 sb.append("│" + summary + " " * (maxLength - ls) + "│")
2008 if (report != null) {
2009 sb.append("\n│" + report + " " * (maxLength - report.length()) + "│")
2011 allSummaries += sb.toString()
2014 println "┌${"${"─" * maxLength}"}┐"
2015 println allSummaries.join("\n├${"${"─" * maxLength}"}┤\n")
2016 println "└${"${"─" * maxLength}"}┘"
2018 /* END of test tasks results summary */
2021 task compileLinkCheck(type: JavaCompile) {
2023 classpath = files("${jalviewDir}/${utils_dir}")
2024 destinationDir = file("${jalviewDir}/${utils_dir}")
2025 source = fileTree(dir: "${jalviewDir}/${utils_dir}", include: ["HelpLinksChecker.java", "BufferedLineReader.java"])
2027 inputs.file("${jalviewDir}/${utils_dir}/HelpLinksChecker.java")
2028 inputs.file("${jalviewDir}/${utils_dir}/HelpLinksChecker.java")
2029 outputs.file("${jalviewDir}/${utils_dir}/HelpLinksChecker.class")
2030 outputs.file("${jalviewDir}/${utils_dir}/BufferedLineReader.class")
2034 task linkCheck(type: JavaExec) {
2036 dependsOn compileLinkCheck
2038 def helpLinksCheckerOutFile = file("${jalviewDir}/${utils_dir}/HelpLinksChecker.out")
2039 classpath = files("${jalviewDir}/${utils_dir}")
2040 main = "HelpLinksChecker"
2041 workingDir = "${helpBuildDir}"
2042 args = [ "${helpBuildDir}/${help_dir}", "-nointernet" ]
2044 def outFOS = new FileOutputStream(helpLinksCheckerOutFile, false) // false == don't append
2045 standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
2048 errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
2052 inputs.dir(helpBuildDir)
2053 outputs.file(helpLinksCheckerOutFile)
2057 // import the pubhtmlhelp target
2058 ant.properties.basedir = "${jalviewDir}"
2059 ant.properties.helpBuildDir = "${helpBuildDir}/${help_dir}"
2060 ant.importBuild "${utils_dir}/publishHelp.xml"
2063 task cleanPackageDir(type: Delete) {
2065 delete fileTree(dir: "${jalviewDir}/${package_dir}", include: "*.jar")
2075 attributes "Main-Class": main_class,
2076 "Permissions": "all-permissions",
2077 "Application-Name": applicationName,
2078 "Codebase": application_codebase,
2079 "Implementation-Version": JALVIEW_VERSION
2082 def outputDir = "${jalviewDir}/${package_dir}"
2083 destinationDirectory = file(outputDir)
2084 archiveFileName = rootProject.name+".jar"
2085 duplicatesStrategy "EXCLUDE"
2092 exclude "**/*.jar.*"
2094 inputs.dir(sourceSets.main.java.outputDir)
2095 sourceSets.main.resources.srcDirs.each{ dir ->
2098 outputs.file("${outputDir}/${archiveFileName}")
2102 task copyJars(type: Copy) {
2103 from fileTree(dir: classesDir, include: "**/*.jar").files
2104 into "${jalviewDir}/${package_dir}"
2108 // doing a Sync instead of Copy as Copy doesn't deal with "outputs" very well
2109 task syncJars(type: Sync) {
2111 from fileTree(dir: "${jalviewDir}/${libDistDir}", include: "**/*.jar").files
2112 into "${jalviewDir}/${package_dir}"
2114 include jar.archiveFileName.getOrNull()
2121 description = "Put all required libraries in dist"
2122 // order of "cleanPackageDir", "copyJars", "jar" important!
2123 jar.mustRunAfter cleanPackageDir
2124 syncJars.mustRunAfter cleanPackageDir
2125 dependsOn cleanPackageDir
2128 outputs.dir("${jalviewDir}/${package_dir}")
2133 dependsOn cleanPackageDir
2140 group = "distribution"
2141 description = "Create a single jar file with all dependency libraries merged. Can be run with java -jar"
2145 from ("${jalviewDir}/${libDistDir}") {
2149 attributes "Implementation-Version": JALVIEW_VERSION,
2150 "Application-Name": applicationName
2153 duplicatesStrategy "INCLUDE"
2155 mainClassName = shadow_jar_main_class
2157 classifier = "all-"+JALVIEW_VERSION+"-j"+JAVA_VERSION
2161 task getdownImagesCopy() {
2162 inputs.dir getdownImagesDir
2163 outputs.dir getdownImagesBuildDir
2167 from(getdownImagesDir) {
2168 include("*getdown*.png")
2170 into getdownImagesBuildDir
2175 task getdownImagesProcess() {
2176 dependsOn getdownImagesCopy
2179 if (backgroundImageText) {
2180 if (convertBinary == null) {
2181 throw new StopExecutionException("No ImageMagick convert binary installed at '${convertBinaryExpectedLocation}'")
2183 if (!project.hasProperty("getdown_background_image_text_suffix_cmd")) {
2184 throw new StopExecutionException("No property 'getdown_background_image_text_suffix_cmd' defined. See channel_gradle.properties for channel ${CHANNEL}")
2186 fileTree(dir: getdownImagesBuildDir, include: "*background*.png").getFiles().each { file ->
2188 executable convertBinary
2191 '-font', getdown_background_image_text_font,
2192 '-fill', getdown_background_image_text_colour,
2193 '-draw', sprintf(getdown_background_image_text_suffix_cmd, channelSuffix),
2194 '-draw', sprintf(getdown_background_image_text_commit_cmd, "git-commit: ${gitHash}"),
2195 '-draw', sprintf(getdown_background_image_text_date_cmd, getDate("yyyy-MM-dd HH:mm:ss")),
2204 task getdownImages() {
2205 dependsOn getdownImagesProcess
2208 task getdownWebsite() {
2209 group = "distribution"
2210 description = "Create the getdown minimal app folder, and website folder for this version of jalview. Website folder also used for offline app installer"
2212 dependsOn getdownImages
2217 def getdownWebsiteResourceFilenames = []
2218 def getdownResourceDir = getdownResourceDir
2219 def getdownResourceFilenames = []
2222 // clean the getdown website and files dir before creating getdown folders
2223 delete getdownAppBaseDir
2224 delete getdownFilesDir
2227 from buildProperties
2228 rename(file(buildProperties).getName(), getdown_build_properties)
2231 getdownWebsiteResourceFilenames += "${getdownAppDistDir}/${getdown_build_properties}"
2234 from channelPropsFile
2235 filter(ReplaceTokens,
2239 'SUFFIX': channelSuffix
2242 into getdownAppBaseDir
2244 getdownWebsiteResourceFilenames += file(channelPropsFile).getName()
2246 // set some getdownTxt_ properties then go through all properties looking for getdownTxt_...
2247 def props = project.properties.sort { it.key }
2248 if (getdownAltJavaMinVersion != null && getdownAltJavaMinVersion.length() > 0) {
2249 props.put("getdown_txt_java_min_version", getdownAltJavaMinVersion)
2251 if (getdownAltJavaMaxVersion != null && getdownAltJavaMaxVersion.length() > 0) {
2252 props.put("getdown_txt_java_max_version", getdownAltJavaMaxVersion)
2254 if (getdownAltMultiJavaLocation != null && getdownAltMultiJavaLocation.length() > 0) {
2255 props.put("getdown_txt_multi_java_location", getdownAltMultiJavaLocation)
2257 if (getdownImagesBuildDir != null && file(getdownImagesBuildDir).exists()) {
2258 props.put("getdown_txt_ui.background_image", "${getdownImagesBuildDir}/${getdown_background_image}")
2259 props.put("getdown_txt_ui.instant_background_image", "${getdownImagesBuildDir}/${getdown_instant_background_image}")
2260 props.put("getdown_txt_ui.error_background", "${getdownImagesBuildDir}/${getdown_error_background}")
2261 props.put("getdown_txt_ui.progress_image", "${getdownImagesBuildDir}/${getdown_progress_image}")
2262 props.put("getdown_txt_ui.icon", "${getdownImagesDir}/${getdown_icon}")
2263 props.put("getdown_txt_ui.mac_dock_icon", "${getdownImagesDir}/${getdown_mac_dock_icon}")
2266 props.put("getdown_txt_title", jalview_name)
2267 props.put("getdown_txt_ui.name", applicationName)
2269 // start with appbase
2270 getdownTextLines += "appbase = ${getdownAppBase}"
2271 props.each{ prop, val ->
2272 if (prop.startsWith("getdown_txt_") && val != null) {
2273 if (prop.startsWith("getdown_txt_multi_")) {
2274 def key = prop.substring(18)
2275 val.split(",").each{ v ->
2276 def line = "${key} = ${v}"
2277 getdownTextLines += line
2280 // file values rationalised
2281 if (val.indexOf('/') > -1 || prop.startsWith("getdown_txt_resource")) {
2283 if (val.indexOf('/') == 0) {
2286 } else if (val.indexOf('/') > 0) {
2287 // relative path (relative to jalviewDir)
2288 r = file( "${jalviewDir}/${val}" )
2291 val = "${getdown_resource_dir}/" + r.getName()
2292 getdownWebsiteResourceFilenames += val
2293 getdownResourceFilenames += r.getPath()
2296 if (! prop.startsWith("getdown_txt_resource")) {
2297 def line = prop.substring(12) + " = ${val}"
2298 getdownTextLines += line
2304 getdownWebsiteResourceFilenames.each{ filename ->
2305 getdownTextLines += "resource = ${filename}"
2307 getdownResourceFilenames.each{ filename ->
2310 into getdownResourceDir
2314 def getdownWrapperScripts = [ getdown_bash_wrapper_script, getdown_powershell_wrapper_script, getdown_batch_wrapper_script ]
2315 getdownWrapperScripts.each{ script ->
2316 def s = file( "${jalviewDir}/utils/getdown/${getdown_wrapper_script_dir}/${script}" )
2320 into "${getdownAppBaseDir}/${getdown_wrapper_script_dir}"
2322 getdownTextLines += "resource = ${getdown_wrapper_script_dir}/${script}"
2327 fileTree(file(package_dir)).each{ f ->
2328 if (f.isDirectory()) {
2329 def files = fileTree(dir: f, include: ["*"]).getFiles()
2331 } else if (f.exists()) {
2335 def jalviewJar = jar.archiveFileName.getOrNull()
2336 // put jalview.jar first for CLASSPATH and .properties files reasons
2337 codeFiles.sort{a, b -> ( a.getName() == jalviewJar ? -1 : ( b.getName() == jalviewJar ? 1 : a <=> b ) ) }.each{f ->
2338 def name = f.getName()
2339 def line = "code = ${getdownAppDistDir}/${name}"
2340 getdownTextLines += line
2347 // NOT USING MODULES YET, EVERYTHING SHOULD BE IN dist
2349 if (JAVA_VERSION.equals("11")) {
2350 def j11libFiles = fileTree(dir: "${jalviewDir}/${j11libDir}", include: ["*.jar"]).getFiles()
2351 j11libFiles.sort().each{f ->
2352 def name = f.getName()
2353 def line = "code = ${getdown_j11lib_dir}/${name}"
2354 getdownTextLines += line
2357 into getdownJ11libDir
2363 // 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.
2364 //getdownTextLines += "class = " + file(getdownLauncher).getName()
2365 getdownTextLines += "resource = ${getdown_launcher_new}"
2366 getdownTextLines += "class = ${main_class}"
2367 // Not setting these properties in general so that getdownappbase and getdowndistdir will default to release version in jalview.bin.Cache
2368 if (getdownSetAppBaseProperty) {
2369 getdownTextLines += "jvmarg = -Dgetdowndistdir=${getdownAppDistDir}"
2370 getdownTextLines += "jvmarg = -Dgetdownappbase=${getdownAppBase}"
2373 def getdownTxt = file("${getdownAppBaseDir}/getdown.txt")
2374 getdownTxt.write(getdownTextLines.join("\n"))
2376 getdownLaunchJvl = getdown_launch_jvl_name + ( (jvlChannelName != null && jvlChannelName.length() > 0)?"-${jvlChannelName}":"" ) + ".jvl"
2377 def launchJvl = file("${getdownAppBaseDir}/${getdownLaunchJvl}")
2378 launchJvl.write("appbase=${getdownAppBase}")
2380 // files going into the getdown website dir: getdown-launcher.jar
2382 from getdownLauncher
2383 rename(file(getdownLauncher).getName(), getdown_launcher_new)
2384 into getdownAppBaseDir
2387 // files going into the getdown website dir: getdown-launcher(-local).jar
2389 from getdownLauncher
2390 if (file(getdownLauncher).getName() != getdown_launcher) {
2391 rename(file(getdownLauncher).getName(), getdown_launcher)
2393 into getdownAppBaseDir
2396 // files going into the getdown website dir: ./install dir and files
2397 if (! (CHANNEL.startsWith("ARCHIVE") || CHANNEL.startsWith("DEVELOP"))) {
2400 from getdownLauncher
2401 from "${getdownAppDir}/${getdown_build_properties}"
2402 if (file(getdownLauncher).getName() != getdown_launcher) {
2403 rename(file(getdownLauncher).getName(), getdown_launcher)
2405 into getdownInstallDir
2408 // and make a copy in the getdown files dir (these are not downloaded by getdown)
2410 from getdownInstallDir
2411 into getdownFilesInstallDir
2415 // files going into the getdown files dir: getdown.txt, getdown-launcher.jar, channel-launch.jvl, build_properties
2419 from getdownLauncher
2420 from "${getdownAppBaseDir}/${getdown_build_properties}"
2421 from "${getdownAppBaseDir}/${channel_props}"
2422 if (file(getdownLauncher).getName() != getdown_launcher) {
2423 rename(file(getdownLauncher).getName(), getdown_launcher)
2425 into getdownFilesDir
2428 // and ./resource (not all downloaded by getdown)
2430 from getdownResourceDir
2431 into "${getdownFilesDir}/${getdown_resource_dir}"
2436 inputs.dir("${jalviewDir}/${package_dir}")
2438 outputs.dir(getdownAppBaseDir)
2439 outputs.dir(getdownFilesDir)
2443 // a helper task to allow getdown digest of any dir: `gradle getdownDigestDir -PDIGESTDIR=/path/to/my/random/getdown/dir
2444 task getdownDigestDir(type: JavaExec) {
2446 description "A task to run a getdown Digest on a dir with getdown.txt. Provide a DIGESTDIR property via -PDIGESTDIR=..."
2448 def digestDirPropertyName = "DIGESTDIR"
2450 classpath = files(getdownLauncher)
2451 def digestDir = findProperty(digestDirPropertyName)
2452 if (digestDir == null) {
2453 throw new GradleException("Must provide a DIGESTDIR value to produce an alternative getdown digest")
2457 main = "com.threerings.getdown.tools.Digester"
2461 task getdownDigest(type: JavaExec) {
2462 group = "distribution"
2463 description = "Digest the getdown website folder"
2464 dependsOn getdownWebsite
2466 classpath = files(getdownLauncher)
2468 main = "com.threerings.getdown.tools.Digester"
2469 args getdownAppBaseDir
2470 inputs.dir(getdownAppBaseDir)
2471 outputs.file("${getdownAppBaseDir}/digest2.txt")
2476 group = "distribution"
2477 description = "Create the minimal and full getdown app folder for installers and website and create digest file"
2478 dependsOn getdownDigest
2480 if (reportRsyncCommand) {
2481 def fromDir = getdownAppBaseDir + (getdownAppBaseDir.endsWith('/')?'':'/')
2482 def toDir = "${getdown_rsync_dest}/${getdownDir}" + (getdownDir.endsWith('/')?'':'/')
2483 println "LIKELY RSYNC COMMAND:"
2484 println "mkdir -p '$toDir'\nrsync -avh --delete '$fromDir' '$toDir'"
2485 if (RUNRSYNC == "true") {
2487 commandLine "mkdir", "-p", toDir
2490 commandLine "rsync", "-avh", "--delete", fromDir, toDir
2498 task getdownArchiveBuild() {
2499 group = "distribution"
2500 description = "Put files in the archive dir to go on the website"
2502 dependsOn getdownWebsite
2504 def v = "v${JALVIEW_VERSION_UNDERSCORES}"
2505 def vDir = "${getdownArchiveDir}/${v}"
2506 getdownFullArchiveDir = "${vDir}/getdown"
2507 getdownVersionLaunchJvl = "${vDir}/jalview-${v}.jvl"
2509 def vAltDir = "alt_${v}"
2510 def archiveImagesDir = "${jalviewDir}/${channel_properties_dir}/old/images"
2513 // cleanup old "old" dir
2514 delete getdownArchiveDir
2516 def getdownArchiveTxt = file("${getdownFullArchiveDir}/getdown.txt")
2517 getdownArchiveTxt.getParentFile().mkdirs()
2518 def getdownArchiveTextLines = []
2519 def getdownFullArchiveAppBase = "${getdownArchiveAppBase}${getdownArchiveAppBase.endsWith("/")?"":"/"}${v}/getdown/"
2523 from "${getdownAppBaseDir}/${getdownAppDistDir}"
2524 into "${getdownFullArchiveDir}/${vAltDir}"
2527 getdownTextLines.each { line ->
2528 line = line.replaceAll("^(?<s>appbase\\s*=\\s*).*", '${s}'+getdownFullArchiveAppBase)
2529 line = line.replaceAll("^(?<s>(resource|code)\\s*=\\s*)${getdownAppDistDir}/", '${s}'+vAltDir+"/")
2530 line = line.replaceAll("^(?<s>ui.background_image\\s*=\\s*).*\\.png", '${s}'+"${getdown_resource_dir}/jalview_archive_getdown_background.png")
2531 line = line.replaceAll("^(?<s>ui.instant_background_image\\s*=\\s*).*\\.png", '${s}'+"${getdown_resource_dir}/jalview_archive_getdown_background_initialising.png")
2532 line = line.replaceAll("^(?<s>ui.error_background\\s*=\\s*).*\\.png", '${s}'+"${getdown_resource_dir}/jalview_archive_getdown_background_error.png")
2533 line = line.replaceAll("^(?<s>ui.progress_image\\s*=\\s*).*\\.png", '${s}'+"${getdown_resource_dir}/jalview_archive_getdown_progress_bar.png")
2534 // remove the existing resource = resource/ or bin/ lines
2535 if (! line.matches("resource\\s*=\\s*(resource|bin)/.*")) {
2536 getdownArchiveTextLines += line
2540 // the resource dir -- add these files as resource lines in getdown.txt
2542 from "${archiveImagesDir}"
2543 into "${getdownFullArchiveDir}/${getdown_resource_dir}"
2545 getdownArchiveTextLines += "resource = ${getdown_resource_dir}/${file.getName()}"
2549 getdownArchiveTxt.write(getdownArchiveTextLines.join("\n"))
2551 def vLaunchJvl = file(getdownVersionLaunchJvl)
2552 vLaunchJvl.getParentFile().mkdirs()
2553 vLaunchJvl.write("appbase=${getdownFullArchiveAppBase}\n")
2554 def vLaunchJvlPath = vLaunchJvl.toPath().toAbsolutePath()
2555 def jvlLinkPath = file("${vDir}/jalview.jvl").toPath().toAbsolutePath()
2556 // for some reason filepath.relativize(fileInSameDirPath) gives a path to "../" which is wrong
2557 //java.nio.file.Files.createSymbolicLink(jvlLinkPath, jvlLinkPath.relativize(vLaunchJvlPath));
2558 java.nio.file.Files.createSymbolicLink(jvlLinkPath, java.nio.file.Paths.get(".",vLaunchJvl.getName()));
2560 // files going into the getdown files dir: getdown.txt, getdown-launcher.jar, channel-launch.jvl, build_properties
2562 from getdownLauncher
2563 from "${getdownAppBaseDir}/${getdownLaunchJvl}"
2564 from "${getdownAppBaseDir}/${getdown_launcher_new}"
2565 from "${getdownAppBaseDir}/${channel_props}"
2566 if (file(getdownLauncher).getName() != getdown_launcher) {
2567 rename(file(getdownLauncher).getName(), getdown_launcher)
2569 into getdownFullArchiveDir
2575 task getdownArchiveDigest(type: JavaExec) {
2576 group = "distribution"
2577 description = "Digest the getdown archive folder"
2579 dependsOn getdownArchiveBuild
2582 classpath = files(getdownLauncher)
2583 args getdownFullArchiveDir
2585 main = "com.threerings.getdown.tools.Digester"
2586 inputs.dir(getdownFullArchiveDir)
2587 outputs.file("${getdownFullArchiveDir}/digest2.txt")
2590 task getdownArchive() {
2591 group = "distribution"
2592 description = "Build the website archive dir with getdown digest"
2594 dependsOn getdownArchiveBuild
2595 dependsOn getdownArchiveDigest
2598 tasks.withType(JavaCompile) {
2599 options.encoding = 'UTF-8'
2605 delete getdownAppBaseDir
2606 delete getdownFilesDir
2607 delete getdownArchiveDir
2613 if (file(install4jHomeDir).exists()) {
2615 } else if (file(System.getProperty("user.home")+"/buildtools/install4j").exists()) {
2616 install4jHomeDir = System.getProperty("user.home")+"/buildtools/install4j"
2617 } else if (file("/Applications/install4j.app/Contents/Resources/app").exists()) {
2618 install4jHomeDir = "/Applications/install4j.app/Contents/Resources/app"
2620 installDir(file(install4jHomeDir))
2622 mediaTypes = Arrays.asList(install4j_media_types.split(","))
2626 task copyInstall4jTemplate {
2627 def install4jTemplateFile = file("${install4jDir}/${install4j_template}")
2628 def install4jFileAssociationsFile = file("${install4jDir}/${install4j_installer_file_associations}")
2629 inputs.file(install4jTemplateFile)
2630 inputs.file(install4jFileAssociationsFile)
2631 inputs.property("CHANNEL", { CHANNEL })
2632 outputs.file(install4jConfFile)
2635 def install4jConfigXml = new XmlParser().parse(install4jTemplateFile)
2637 // turn off code signing if no OSX_KEYPASS
2638 if (OSX_KEYPASS == "") {
2639 install4jConfigXml.'**'.codeSigning.each { codeSigning ->
2640 codeSigning.'@macEnabled' = "false"
2642 install4jConfigXml.'**'.windows.each { windows ->
2643 windows.'@runPostProcessor' = "false"
2647 // disable install screen for OSX dmg (for 2.11.2.0)
2648 install4jConfigXml.'**'.macosArchive.each { macosArchive ->
2649 macosArchive.attributes().remove('executeSetupApp')
2650 macosArchive.attributes().remove('setupAppId')
2653 // turn off checksum creation for LOCAL channel
2654 def e = install4jConfigXml.application[0]
2655 e.'@createChecksums' = string(install4jCheckSums)
2657 // put file association actions where placeholder action is
2658 def install4jFileAssociationsText = install4jFileAssociationsFile.text
2659 def fileAssociationActions = new XmlParser().parseText("<actions>${install4jFileAssociationsText}</actions>")
2660 install4jConfigXml.'**'.action.any { a -> // .any{} stops after the first one that returns true
2661 if (a.'@name' == 'EXTENSIONS_REPLACED_BY_GRADLE') {
2662 def parent = a.parent()
2664 fileAssociationActions.each { faa ->
2667 // don't need to continue in .any loop once replacements have been made
2672 // use Windows Program Group with Examples folder for RELEASE, and Program Group without Examples for everything else
2673 // NB we're deleting the /other/ one!
2674 // Also remove the examples subdir from non-release versions
2675 def customizedIdToDelete = "PROGRAM_GROUP_RELEASE"
2676 // 2.11.1.0 NOT releasing with the Examples folder in the Program Group
2677 if (false && CHANNEL=="RELEASE") { // remove 'false && ' to include Examples folder in RELEASE channel
2678 customizedIdToDelete = "PROGRAM_GROUP_NON_RELEASE"
2680 // remove the examples subdir from Full File Set
2681 def files = install4jConfigXml.files[0]
2682 def fileset = files.filesets.fileset.find { fs -> fs.'@customizedId' == "FULL_FILE_SET" }
2683 def root = files.roots.root.find { r -> r.'@fileset' == fileset.'@id' }
2684 def mountPoint = files.mountPoints.mountPoint.find { mp -> mp.'@root' == root.'@id' }
2685 def dirEntry = files.entries.dirEntry.find { de -> de.'@mountPoint' == mountPoint.'@id' && de.'@subDirectory' == "examples" }
2686 dirEntry.parent().remove(dirEntry)
2688 install4jConfigXml.'**'.action.any { a ->
2689 if (a.'@customizedId' == customizedIdToDelete) {
2690 def parent = a.parent()
2696 // write install4j file
2697 install4jConfFile.text = XmlUtil.serialize(install4jConfigXml)
2704 delete install4jConfFile
2708 task cleanInstallersDataFiles {
2709 def installersOutputTxt = file("${jalviewDir}/${install4jBuildDir}/output.txt")
2710 def installersSha256 = file("${jalviewDir}/${install4jBuildDir}/sha256sums")
2711 def hugoDataJsonFile = file("${jalviewDir}/${install4jBuildDir}/installers-${JALVIEW_VERSION_UNDERSCORES}.json")
2713 delete installersOutputTxt
2714 delete installersSha256
2715 delete hugoDataJsonFile
2719 task install4jDMGBackgroundImageCopy {
2720 inputs.file "${install4jDMGBackgroundImageDir}/${install4jDMGBackgroundImageFile}"
2721 outputs.dir "${install4jDMGBackgroundImageBuildDir}"
2724 from(install4jDMGBackgroundImageDir) {
2725 include(install4jDMGBackgroundImageFile)
2727 into install4jDMGBackgroundImageBuildDir
2732 task install4jDMGBackgroundImageProcess {
2733 dependsOn install4jDMGBackgroundImageCopy
2736 if (backgroundImageText) {
2737 if (convertBinary == null) {
2738 throw new StopExecutionException("No ImageMagick convert binary installed at '${convertBinaryExpectedLocation}'")
2740 if (!project.hasProperty("install4j_background_image_text_suffix_cmd")) {
2741 throw new StopExecutionException("No property 'install4j_background_image_text_suffix_cmd' defined. See channel_gradle.properties for channel ${CHANNEL}")
2743 fileTree(dir: install4jDMGBackgroundImageBuildDir, include: "*.png").getFiles().each { file ->
2745 executable convertBinary
2748 '-font', install4j_background_image_text_font,
2749 '-fill', install4j_background_image_text_colour,
2750 '-draw', sprintf(install4j_background_image_text_suffix_cmd, channelSuffix),
2751 '-draw', sprintf(install4j_background_image_text_commit_cmd, "git-commit: ${gitHash}"),
2752 '-draw', sprintf(install4j_background_image_text_date_cmd, getDate("yyyy-MM-dd HH:mm:ss")),
2761 task install4jDMGBackgroundImage {
2762 dependsOn install4jDMGBackgroundImageProcess
2765 task installerFiles(type: com.install4j.gradle.Install4jTask) {
2766 group = "distribution"
2767 description = "Create the install4j installers"
2769 dependsOn copyInstall4jTemplate
2770 dependsOn cleanInstallersDataFiles
2771 dependsOn install4jDMGBackgroundImage
2773 projectFile = install4jConfFile
2775 // create an md5 for the input files to use as version for install4j conf file
2776 def digest = MessageDigest.getInstance("MD5")
2778 (file("${install4jDir}/${install4j_template}").text +
2779 file("${install4jDir}/${install4j_info_plist_file_associations}").text +
2780 file("${install4jDir}/${install4j_installer_file_associations}").text).bytes)
2781 def filesMd5 = new BigInteger(1, digest.digest()).toString(16)
2782 if (filesMd5.length() >= 8) {
2783 filesMd5 = filesMd5.substring(0,8)
2785 def install4jTemplateVersion = "${JALVIEW_VERSION}_F${filesMd5}_C${gitHash}"
2788 'JALVIEW_NAME': jalview_name,
2789 'JALVIEW_APPLICATION_NAME': applicationName,
2790 'JALVIEW_DIR': "../..",
2791 'OSX_KEYSTORE': OSX_KEYSTORE,
2792 'OSX_APPLEID': OSX_APPLEID,
2793 'OSX_ALTOOLPASS': OSX_ALTOOLPASS,
2794 'JSIGN_SH': JSIGN_SH,
2795 'JRE_DIR': getdown_app_dir_java,
2796 'INSTALLER_TEMPLATE_VERSION': install4jTemplateVersion,
2797 'JALVIEW_VERSION': JALVIEW_VERSION,
2798 'JAVA_MIN_VERSION': JAVA_MIN_VERSION,
2799 'JAVA_MAX_VERSION': JAVA_MAX_VERSION,
2800 'JAVA_VERSION': JAVA_VERSION,
2801 'JAVA_INTEGER_VERSION': JAVA_INTEGER_VERSION,
2802 'VERSION': JALVIEW_VERSION,
2803 'COPYRIGHT_MESSAGE': install4j_copyright_message,
2804 'BUNDLE_ID': install4jBundleId,
2805 'INTERNAL_ID': install4jInternalId,
2806 'WINDOWS_APPLICATION_ID': install4jWinApplicationId,
2807 'MACOS_DMG_DS_STORE': install4jDMGDSStore,
2808 'MACOS_DMG_BG_IMAGE': "${install4jDMGBackgroundImageBuildDir}/${install4jDMGBackgroundImageFile}",
2809 'WRAPPER_LINK': getdownWrapperLink,
2810 'BASH_WRAPPER_SCRIPT': getdown_bash_wrapper_script,
2811 'POWERSHELL_WRAPPER_SCRIPT': getdown_powershell_wrapper_script,
2812 'BATCH_WRAPPER_SCRIPT': getdown_batch_wrapper_script,
2813 'WRAPPER_SCRIPT_BIN_DIR': getdown_wrapper_script_dir,
2814 'INSTALLER_NAME': install4jInstallerName,
2815 'INSTALL4J_UTILS_DIR': install4j_utils_dir,
2816 'GETDOWN_CHANNEL_DIR': getdownChannelDir,
2817 'GETDOWN_FILES_DIR': getdown_files_dir,
2818 'GETDOWN_RESOURCE_DIR': getdown_resource_dir,
2819 'GETDOWN_DIST_DIR': getdownAppDistDir,
2820 'GETDOWN_ALT_DIR': getdown_app_dir_alt,
2821 'GETDOWN_INSTALL_DIR': getdown_install_dir,
2822 'INFO_PLIST_FILE_ASSOCIATIONS_FILE': install4j_info_plist_file_associations,
2823 'BUILD_DIR': install4jBuildDir,
2824 'APPLICATION_CATEGORIES': install4j_application_categories,
2825 'APPLICATION_FOLDER': install4jApplicationFolder,
2826 'UNIX_APPLICATION_FOLDER': install4jUnixApplicationFolder,
2827 'EXECUTABLE_NAME': install4jExecutableName,
2828 'EXTRA_SCHEME': install4jExtraScheme,
2829 'MAC_ICONS_FILE': install4jMacIconsFile,
2830 'WINDOWS_ICONS_FILE': install4jWindowsIconsFile,
2831 'PNG_ICON_FILE': install4jPngIconFile,
2832 'BACKGROUND': install4jBackground,
2837 'windows': 'WINDOWS',
2841 // these are the bundled OS/architecture VMs needed by install4j
2844 [ "mac", "aarch64" ],
2845 [ "windows", "x64" ],
2847 [ "linux", "aarch64" ]
2849 osArch.forEach { os, arch ->
2850 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)
2851 // N.B. For some reason install4j requires the below filename to have underscores and not hyphens
2852 // otherwise running `gradle installers` generates a non-useful error:
2853 // `install4j: compilation failed. Reason: java.lang.NumberFormatException: For input string: "windows"`
2854 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)
2857 //println("INSTALL4J VARIABLES:")
2858 //variables.each{k,v->println("${k}=${v}")}
2860 destination = "${jalviewDir}/${install4jBuildDir}"
2861 buildSelected = true
2863 if (install4j_faster.equals("true") || CHANNEL.startsWith("LOCAL")) {
2865 disableSigning = true
2866 disableNotarization = true
2870 macKeystorePassword = OSX_KEYPASS
2873 if (OSX_ALTOOLPASS) {
2874 appleIdPassword = OSX_ALTOOLPASS
2875 disableNotarization = false
2877 disableNotarization = true
2881 println("Using projectFile "+projectFile)
2882 if (!disableNotarization) { println("Will notarize OSX App DMG") }
2886 inputs.dir(getdownAppBaseDir)
2887 inputs.file(install4jConfFile)
2888 inputs.file("${install4jDir}/${install4j_info_plist_file_associations}")
2889 outputs.dir("${jalviewDir}/${install4j_build_dir}/${JAVA_VERSION}")
2892 def getDataHash(File myFile) {
2893 HashCode hash = Files.asByteSource(myFile).hash(Hashing.sha256())
2894 return myFile.exists()
2896 "file" : myFile.getName(),
2897 "filesize" : myFile.length(),
2898 "sha256" : hash.toString()
2903 def writeDataJsonFile(File installersOutputTxt, File installersSha256, File dataJsonFile) {
2905 "channel" : getdownChannelName,
2906 "date" : getDate("yyyy-MM-dd HH:mm:ss"),
2907 "git-commit" : "${gitHash} [${gitBranch}]",
2908 "version" : JALVIEW_VERSION
2910 // install4j installer files
2911 if (installersOutputTxt.exists()) {
2913 installersOutputTxt.readLines().each { def line ->
2914 if (line.startsWith("#")) {
2917 line.replaceAll("\n","")
2918 def vals = line.split("\t")
2919 def filename = vals[3]
2920 def filesize = file(filename).length()
2921 filename = filename.replaceAll(/^.*\//, "")
2922 hash[vals[0]] = [ "id" : vals[0], "os" : vals[1], "name" : vals[2], "file" : filename, "filesize" : filesize ]
2923 idHash."${filename}" = vals[0]
2925 if (install4jCheckSums && installersSha256.exists()) {
2926 installersSha256.readLines().each { def line ->
2927 if (line.startsWith("#")) {
2930 line.replaceAll("\n","")
2931 def vals = line.split(/\s+\*?/)
2932 def filename = vals[1]
2933 def innerHash = (hash.(idHash."${filename}"))."sha256" = vals[0]
2939 "JAR": shadowJar.archiveFile, // executable JAR
2940 "JVL": getdownVersionLaunchJvl, // version JVL
2941 "SOURCE": sourceDist.archiveFile // source TGZ
2942 ].each { key, value ->
2943 def file = file(value)
2944 if (file.exists()) {
2945 def fileHash = getDataHash(file)
2946 if (fileHash != null) {
2947 hash."${key}" = fileHash;
2951 return dataJsonFile.write(new JsonBuilder(hash).toPrettyString())
2954 task staticMakeInstallersJsonFile {
2956 def output = findProperty("i4j_output")
2957 def sha256 = findProperty("i4j_sha256")
2958 def json = findProperty("i4j_json")
2959 if (output == null || sha256 == null || json == null) {
2960 throw new GradleException("Must provide paths to all of output.txt, sha256sums, and output.json with '-Pi4j_output=... -Pi4j_sha256=... -Pi4j_json=...")
2962 writeDataJsonFile(file(output), file(sha256), file(json))
2967 dependsOn installerFiles
2973 eclipse().configFile(eclipse_codestyle_file)
2977 task createSourceReleaseProperties(type: WriteProperties) {
2978 group = "distribution"
2979 description = "Create the source RELEASE properties file"
2981 def sourceTarBuildDir = "${buildDir}/sourceTar"
2982 def sourceReleasePropertiesFile = "${sourceTarBuildDir}/RELEASE"
2983 outputFile (sourceReleasePropertiesFile)
2986 releaseProps.each{ key, val -> property key, val }
2987 property "git.branch", gitBranch
2988 property "git.hash", gitHash
2991 outputs.file(outputFile)
2994 task sourceDist(type: Tar) {
2995 group "distribution"
2996 description "Create a source .tar.gz file for distribution"
2998 dependsOn createBuildProperties
2999 dependsOn convertMdFiles
3000 dependsOn eclipseAllPreferences
3001 dependsOn createSourceReleaseProperties
3004 def outputFileName = "${project.name}_${JALVIEW_VERSION_UNDERSCORES}.tar.gz"
3005 archiveFileName = outputFileName
3007 compression Compression.GZIP
3022 "**/*.class","$j11modDir/**/*.jar","appletlib","**/*locales",
3024 "utils/InstallAnywhere",
3039 "gradle.properties",
3051 ".settings/org.eclipse.buildship.core.prefs",
3052 ".settings/org.eclipse.jdt.core.prefs"
3056 exclude (EXCLUDE_FILES)
3057 include (PROCESS_FILES)
3058 filter(ReplaceTokens,
3062 'Version-Rel': JALVIEW_VERSION,
3063 'Year-Rel': getDate("yyyy")
3068 exclude (EXCLUDE_FILES)
3069 exclude (PROCESS_FILES)
3070 exclude ("appletlib")
3071 exclude ("**/*locales")
3072 exclude ("*locales/**")
3073 exclude ("utils/InstallAnywhere")
3075 exclude (getdown_files_dir)
3076 // getdown_website_dir and getdown_archive_dir moved to build/website/docroot/getdown
3077 //exclude (getdown_website_dir)
3078 //exclude (getdown_archive_dir)
3080 // exluding these as not using jars as modules yet
3081 exclude ("${j11modDir}/**/*.jar")
3084 include(INCLUDE_FILES)
3086 // from (jalviewDir) {
3087 // // explicit includes for stuff that seemed to not get included
3088 // include(fileTree("test/**/*."))
3089 // exclude(EXCLUDE_FILES)
3090 // exclude(PROCESS_FILES)
3093 from(file(buildProperties).getParent()) {
3094 include(file(buildProperties).getName())
3095 rename(file(buildProperties).getName(), "build_properties")
3097 line.replaceAll("^INSTALLATION=.*\$","INSTALLATION=Source Release"+" git-commit\\\\:"+gitHash+" ["+gitBranch+"]")
3101 def sourceTarBuildDir = "${buildDir}/sourceTar"
3102 from(sourceTarBuildDir) {
3103 // this includes the appended RELEASE properties file
3107 task dataInstallersJson {
3109 description "Create the installers-VERSION.json data file for installer files created"
3111 mustRunAfter installers
3112 mustRunAfter shadowJar
3113 mustRunAfter sourceDist
3114 mustRunAfter getdownArchive
3116 def installersOutputTxt = file("${jalviewDir}/${install4jBuildDir}/output.txt")
3117 def installersSha256 = file("${jalviewDir}/${install4jBuildDir}/sha256sums")
3119 if (installersOutputTxt.exists()) {
3120 inputs.file(installersOutputTxt)
3122 if (install4jCheckSums && installersSha256.exists()) {
3123 inputs.file(installersSha256)
3126 shadowJar.archiveFile, // executable JAR
3127 getdownVersionLaunchJvl, // version JVL
3128 sourceDist.archiveFile // source TGZ
3129 ].each { fileName ->
3130 if (file(fileName).exists()) {
3131 inputs.file(fileName)
3135 outputs.file(hugoDataJsonFile)
3138 writeDataJsonFile(installersOutputTxt, installersSha256, hugoDataJsonFile)
3144 description "Copies all help pages to build dir. Runs ant task 'pubhtmlhelp'."
3147 dependsOn pubhtmlhelp
3149 inputs.dir("${helpBuildDir}/${help_dir}")
3150 outputs.dir("${buildDir}/distributions/${help_dir}")
3154 task j2sSetHeadlessBuild {
3161 task jalviewjsEnableAltFileProperty(type: WriteProperties) {
3163 description "Enable the alternative J2S Config file for headless build"
3165 outputFile = jalviewjsJ2sSettingsFileName
3166 def j2sPropsFile = file(jalviewjsJ2sSettingsFileName)
3167 def j2sProps = new Properties()
3168 if (j2sPropsFile.exists()) {
3170 def j2sPropsFileFIS = new FileInputStream(j2sPropsFile)
3171 j2sProps.load(j2sPropsFileFIS)
3172 j2sPropsFileFIS.close()
3174 j2sProps.each { prop, val ->
3177 } catch (Exception e) {
3178 println("Exception reading ${jalviewjsJ2sSettingsFileName}")
3182 if (! j2sProps.stringPropertyNames().contains(jalviewjs_j2s_alt_file_property_config)) {
3183 property(jalviewjs_j2s_alt_file_property_config, jalviewjs_j2s_alt_file_property)
3188 task jalviewjsSetEclipseWorkspace {
3189 def propKey = "jalviewjs_eclipse_workspace"
3191 if (project.hasProperty(propKey)) {
3192 propVal = project.getProperty(propKey)
3193 if (propVal.startsWith("~/")) {
3194 propVal = System.getProperty("user.home") + propVal.substring(1)
3197 def propsFileName = "${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_eclipse_workspace_location_file}"
3198 def propsFile = file(propsFileName)
3199 def eclipseWsDir = propVal
3200 def props = new Properties()
3202 def writeProps = true
3203 if (( eclipseWsDir == null || !file(eclipseWsDir).exists() ) && propsFile.exists()) {
3204 def ins = new FileInputStream(propsFileName)
3207 if (props.getProperty(propKey, null) != null) {
3208 eclipseWsDir = props.getProperty(propKey)
3213 if (eclipseWsDir == null || !file(eclipseWsDir).exists()) {
3214 def tempDir = File.createTempDir()
3215 eclipseWsDir = tempDir.getAbsolutePath()
3218 eclipseWorkspace = file(eclipseWsDir)
3221 // do not run a headless transpile when we claim to be in Eclipse
3223 println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3224 throw new StopExecutionException("Not running headless transpile whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
3226 println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3230 props.setProperty(propKey, eclipseWsDir)
3231 propsFile.parentFile.mkdirs()
3232 def bytes = new ByteArrayOutputStream()
3233 props.store(bytes, null)
3234 def propertiesString = bytes.toString()
3235 propsFile.text = propertiesString
3241 println("ECLIPSE WORKSPACE: "+eclipseWorkspace.getPath())
3244 //inputs.property(propKey, eclipseWsDir) // eclipseWsDir only gets set once this task runs, so will be out-of-date
3245 outputs.file(propsFileName)
3246 outputs.upToDateWhen { eclipseWorkspace.exists() && propsFile.exists() }
3250 task jalviewjsEclipsePaths {
3253 def eclipseRoot = jalviewjs_eclipse_root
3254 if (eclipseRoot.startsWith("~/")) {
3255 eclipseRoot = System.getProperty("user.home") + eclipseRoot.substring(1)
3257 if (OperatingSystem.current().isMacOsX()) {
3258 eclipseRoot += "/Eclipse.app"
3259 eclipseBinary = "${eclipseRoot}/Contents/MacOS/eclipse"
3260 eclipseProduct = "${eclipseRoot}/Contents/Eclipse/.eclipseproduct"
3261 } else if (OperatingSystem.current().isWindows()) { // check these paths!!
3262 if (file("${eclipseRoot}/eclipse").isDirectory() && file("${eclipseRoot}/eclipse/.eclipseproduct").exists()) {
3263 eclipseRoot += "/eclipse"
3265 eclipseBinary = "${eclipseRoot}/eclipse.exe"
3266 eclipseProduct = "${eclipseRoot}/.eclipseproduct"
3267 } else { // linux or unix
3268 if (file("${eclipseRoot}/eclipse").isDirectory() && file("${eclipseRoot}/eclipse/.eclipseproduct").exists()) {
3269 eclipseRoot += "/eclipse"
3270 println("eclipseDir exists")
3272 eclipseBinary = "${eclipseRoot}/eclipse"
3273 eclipseProduct = "${eclipseRoot}/.eclipseproduct"
3276 eclipseVersion = "4.13" // default
3277 def assumedVersion = true
3278 if (file(eclipseProduct).exists()) {
3279 def fis = new FileInputStream(eclipseProduct)
3280 def props = new Properties()
3282 eclipseVersion = props.getProperty("version")
3284 assumedVersion = false
3287 def propKey = "eclipse_debug"
3288 eclipseDebug = (project.hasProperty(propKey) && project.getProperty(propKey).equals("true"))
3291 // do not run a headless transpile when we claim to be in Eclipse
3293 println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3294 throw new StopExecutionException("Not running headless transpile whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
3296 println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3299 if (!assumedVersion) {
3300 println("ECLIPSE VERSION=${eclipseVersion}")
3306 task printProperties {
3308 description "Output to console all System.properties"
3310 System.properties.each { key, val -> System.out.println("Property: ${key}=${val}") }
3316 dependsOn eclipseProject
3317 dependsOn eclipseClasspath
3318 dependsOn eclipseJdt
3322 // this version (type: Copy) will delete anything in the eclipse dropins folder that isn't in fromDropinsDir
3323 task jalviewjsEclipseCopyDropins(type: Copy) {
3324 dependsOn jalviewjsEclipsePaths
3326 def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjs_eclipse_dropins_dir}", include: "*.jar")
3327 inputFiles += file("${jalviewDir}/${jalviewjsJ2sPlugin}")
3328 def outputDir = "${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_eclipse_tmp_dropins_dir}"
3335 // this eclipse -clean doesn't actually work
3336 task jalviewjsCleanEclipse(type: Exec) {
3337 dependsOn eclipseSetup
3338 dependsOn jalviewjsEclipsePaths
3339 dependsOn jalviewjsEclipseCopyDropins
3341 executable(eclipseBinary)
3342 args(["-nosplash", "--launcher.suppressErrors", "-data", eclipseWorkspace.getPath(), "-clean", "-console", "-consoleLog"])
3348 def inputString = """exit
3351 def inputByteStream = new ByteArrayInputStream(inputString.getBytes())
3352 standardInput = inputByteStream
3355 /* not really working yet
3356 jalviewjsEclipseCopyDropins.finalizedBy jalviewjsCleanEclipse
3360 task jalviewjsTransferUnzipSwingJs {
3361 def file_zip = "${jalviewDir}/${jalviewjs_swingjs_zip}"
3365 from zipTree(file_zip)
3366 into "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}"
3370 inputs.file file_zip
3371 outputs.dir "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}"
3375 task jalviewjsTransferUnzipLib {
3376 def zipFiles = fileTree(dir: "${jalviewDir}/${jalviewjs_libjs_dir}", include: "*.zip")
3379 zipFiles.each { file_zip ->
3381 from zipTree(file_zip)
3382 into "${jalviewDir}/${jalviewjsTransferSiteLibDir}"
3387 inputs.files zipFiles
3388 outputs.dir "${jalviewDir}/${jalviewjsTransferSiteLibDir}"
3392 task jalviewjsTransferUnzipAllLibs {
3393 dependsOn jalviewjsTransferUnzipSwingJs
3394 dependsOn jalviewjsTransferUnzipLib
3398 task jalviewjsCreateJ2sSettings(type: WriteProperties) {
3400 description "Create the alternative j2s file from the j2s.* properties"
3402 jalviewjsJ2sProps = project.properties.findAll { it.key.startsWith("j2s.") }.sort { it.key }
3403 def siteDirProperty = "j2s.site.directory"
3404 def setSiteDir = false
3405 jalviewjsJ2sProps.each { prop, val ->
3407 if (prop == siteDirProperty) {
3408 if (!(val.startsWith('/') || val.startsWith("file://") )) {
3409 val = "${jalviewDir}/${jalviewjsTransferSiteJsDir}/${val}"
3415 if (!setSiteDir) { // default site location, don't override specifically set property
3416 property(siteDirProperty,"${jalviewDirRelativePath}/${jalviewjsTransferSiteJsDir}")
3419 outputFile = jalviewjsJ2sAltSettingsFileName
3422 inputs.properties(jalviewjsJ2sProps)
3423 outputs.file(jalviewjsJ2sAltSettingsFileName)
3428 task jalviewjsEclipseSetup {
3429 dependsOn jalviewjsEclipseCopyDropins
3430 dependsOn jalviewjsSetEclipseWorkspace
3431 dependsOn jalviewjsCreateJ2sSettings
3435 task jalviewjsSyncAllLibs (type: Sync) {
3436 dependsOn jalviewjsTransferUnzipAllLibs
3437 def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjsTransferSiteLibDir}")
3438 inputFiles += fileTree(dir: "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}")
3439 def outputDir = "${jalviewDir}/${jalviewjsSiteDir}"
3443 def outputFiles = []
3444 rename { filename ->
3445 outputFiles += "${outputDir}/${filename}"
3452 // should this be exclude really ?
3453 duplicatesStrategy "INCLUDE"
3455 outputs.files outputFiles
3456 inputs.files inputFiles
3460 task jalviewjsSyncResources (type: Sync) {
3461 dependsOn buildResources
3463 def inputFiles = fileTree(dir: resourcesBuildDir)
3464 def outputDir = "${jalviewDir}/${jalviewjsSiteDir}/${jalviewjs_j2s_subdir}"
3468 def outputFiles = []
3469 rename { filename ->
3470 outputFiles += "${outputDir}/${filename}"
3476 outputs.files outputFiles
3477 inputs.files inputFiles
3481 task jalviewjsSyncSiteResources (type: Sync) {
3482 def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjs_site_resource_dir}")
3483 def outputDir = "${jalviewDir}/${jalviewjsSiteDir}"
3487 def outputFiles = []
3488 rename { filename ->
3489 outputFiles += "${outputDir}/${filename}"
3495 outputs.files outputFiles
3496 inputs.files inputFiles
3500 task jalviewjsSyncBuildProperties (type: Sync) {
3501 dependsOn createBuildProperties
3502 def inputFiles = [file(buildProperties)]
3503 def outputDir = "${jalviewDir}/${jalviewjsSiteDir}/${jalviewjs_j2s_subdir}"
3507 def outputFiles = []
3508 rename { filename ->
3509 outputFiles += "${outputDir}/${filename}"
3515 outputs.files outputFiles
3516 inputs.files inputFiles
3520 task jalviewjsProjectImport(type: Exec) {
3521 dependsOn eclipseSetup
3522 dependsOn jalviewjsEclipsePaths
3523 dependsOn jalviewjsEclipseSetup
3526 // do not run a headless import when we claim to be in Eclipse
3528 println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3529 throw new StopExecutionException("Not running headless import whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
3531 println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3535 //def projdir = eclipseWorkspace.getPath()+"/.metadata/.plugins/org.eclipse.core.resources/.projects/jalview/org.eclipse.jdt.core"
3536 def projdir = eclipseWorkspace.getPath()+"/.metadata/.plugins/org.eclipse.core.resources/.projects/jalview"
3537 executable(eclipseBinary)
3538 args(["-nosplash", "--launcher.suppressErrors", "-application", "com.seeq.eclipse.importprojects.headlessimport", "-data", eclipseWorkspace.getPath(), "-import", jalviewDirAbsolutePath])
3542 args += [ "--launcher.appendVmargs", "-vmargs", "-Dorg.eclipse.equinox.p2.reconciler.dropins.directory=${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_eclipse_tmp_dropins_dir}" ]
3544 args += [ "-D${j2sHeadlessBuildProperty}=true" ]
3545 args += [ "-D${jalviewjs_j2s_alt_file_property}=${jalviewjsJ2sAltSettingsFileName}" ]
3548 inputs.file("${jalviewDir}/.project")
3549 outputs.upToDateWhen {
3550 file(projdir).exists()
3555 task jalviewjsTranspile(type: Exec) {
3556 dependsOn jalviewjsEclipseSetup
3557 dependsOn jalviewjsProjectImport
3558 dependsOn jalviewjsEclipsePaths
3560 dependsOn jalviewjsEnableAltFileProperty
3564 // do not run a headless transpile when we claim to be in Eclipse
3566 println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3567 throw new StopExecutionException("Not running headless transpile whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
3569 println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3573 executable(eclipseBinary)
3574 args(["-nosplash", "--launcher.suppressErrors", "-application", "org.eclipse.jdt.apt.core.aptBuild", "-data", eclipseWorkspace, "-${jalviewjs_eclipse_build_arg}", eclipse_project_name ])
3578 args += [ "--launcher.appendVmargs", "-vmargs", "-Dorg.eclipse.equinox.p2.reconciler.dropins.directory=${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_eclipse_tmp_dropins_dir}" ]
3580 args += [ "-D${j2sHeadlessBuildProperty}=true" ]
3581 args += [ "-D${jalviewjs_j2s_alt_file_property}=${jalviewjsJ2sAltSettingsFileName}" ]
3587 stdout = new ByteArrayOutputStream()
3588 stderr = new ByteArrayOutputStream()
3590 def logOutFileName = "${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}"
3591 def logOutFile = file(logOutFileName)
3592 logOutFile.createNewFile()
3593 logOutFile.text = """ROOT: ${jalviewjs_eclipse_root}
3594 BINARY: ${eclipseBinary}
3595 VERSION: ${eclipseVersion}
3596 WORKSPACE: ${eclipseWorkspace}
3597 DEBUG: ${eclipseDebug}
3600 def logOutFOS = new FileOutputStream(logOutFile, true) // true == append
3601 // combine stdout and stderr
3602 def logErrFOS = logOutFOS
3604 if (jalviewjs_j2s_to_console.equals("true")) {
3605 standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
3606 new org.apache.tools.ant.util.TeeOutputStream(
3610 errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
3611 new org.apache.tools.ant.util.TeeOutputStream(
3616 standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
3619 errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
3626 if (stdout.toString().contains("Error processing ")) {
3627 // j2s did not complete transpile
3628 //throw new TaskExecutionException("Error during transpilation:\n${stderr}\nSee eclipse transpile log file '${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}'")
3629 if (jalviewjs_ignore_transpile_errors.equals("true")) {
3630 println("IGNORING TRANSPILE ERRORS")
3631 println("See eclipse transpile log file '${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}'")
3633 throw new GradleException("Error during transpilation:\n${stderr}\nSee eclipse transpile log file '${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}'")
3638 inputs.dir("${jalviewDir}/${sourceDir}")
3639 outputs.dir("${jalviewDir}/${jalviewjsTransferSiteJsDir}")
3640 outputs.upToDateWhen( { file("${jalviewDir}/${jalviewjsTransferSiteJsDir}${jalviewjs_server_resource}").exists() } )
3644 def jalviewjsCallCore(String name, FileCollection list, String prefixFile, String suffixFile, String jsfile, String zjsfile, File logOutFile, Boolean logOutConsole) {
3646 def stdout = new ByteArrayOutputStream()
3647 def stderr = new ByteArrayOutputStream()
3649 def coreFile = file(jsfile)
3651 msg = "Creating core for ${name}...\nGenerating ${jsfile}"
3653 logOutFile.createNewFile()
3654 logOutFile.append(msg+"\n")
3656 def coreTop = file(prefixFile)
3657 def coreBottom = file(suffixFile)
3658 coreFile.getParentFile().mkdirs()
3659 coreFile.createNewFile()
3660 coreFile.write( coreTop.getText("UTF-8") )
3664 def t = f.getText("UTF-8")
3665 t.replaceAll("Clazz\\.([^_])","Clazz_${1}")
3666 coreFile.append( t )
3668 msg = "...file '"+f.getPath()+"' does not exist, skipping"
3670 logOutFile.append(msg+"\n")
3673 coreFile.append( coreBottom.getText("UTF-8") )
3675 msg = "Generating ${zjsfile}"
3677 logOutFile.append(msg+"\n")
3678 def logOutFOS = new FileOutputStream(logOutFile, true) // true == append
3679 def logErrFOS = logOutFOS
3682 classpath = files(["${jalviewDir}/${jalviewjs_closure_compiler}"])
3683 main = "com.google.javascript.jscomp.CommandLineRunner"
3684 jvmArgs = [ "-Dfile.encoding=UTF-8" ]
3685 args = [ "--compilation_level", "SIMPLE_OPTIMIZATIONS", "--warning_level", "QUIET", "--charset", "UTF-8", "--js", jsfile, "--js_output_file", zjsfile ]
3688 msg = "\nRunning '"+commandLine.join(' ')+"'\n"
3690 logOutFile.append(msg+"\n")
3692 if (logOutConsole) {
3693 standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
3694 new org.apache.tools.ant.util.TeeOutputStream(
3698 errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
3699 new org.apache.tools.ant.util.TeeOutputStream(
3704 standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
3707 errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
3714 logOutFile.append(msg+"\n")
3718 task jalviewjsBuildAllCores {
3720 description "Build the core js lib closures listed in the classlists dir"
3721 dependsOn jalviewjsTranspile
3722 dependsOn jalviewjsTransferUnzipSwingJs
3724 def j2sDir = "${jalviewDir}/${jalviewjsTransferSiteJsDir}/${jalviewjs_j2s_subdir}"
3725 def swingJ2sDir = "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}/${jalviewjs_j2s_subdir}"
3726 def libJ2sDir = "${jalviewDir}/${jalviewjsTransferSiteLibDir}/${jalviewjs_j2s_subdir}"
3727 def jsDir = "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}/${jalviewjs_js_subdir}"
3728 def outputDir = "${jalviewDir}/${jalviewjsTransferSiteCoreDir}/${jalviewjs_j2s_subdir}/core"
3729 def prefixFile = "${jsDir}/core/coretop2.js"
3730 def suffixFile = "${jsDir}/core/corebottom2.js"
3732 inputs.file prefixFile
3733 inputs.file suffixFile
3735 def classlistFiles = []
3736 // add the classlists found int the jalviewjs_classlists_dir
3737 fileTree(dir: "${jalviewDir}/${jalviewjs_classlists_dir}", include: "*.txt").each {
3739 def name = file.getName() - ".txt"
3746 // _jmol and _jalview cores. Add any other peculiar classlist.txt files here
3747 //classlistFiles += [ 'file': file("${jalviewDir}/${jalviewjs_classlist_jmol}"), 'name': "_jvjmol" ]
3748 classlistFiles += [ 'file': file("${jalviewDir}/${jalviewjs_classlist_jalview}"), 'name': jalviewjsJalviewCoreName ]
3750 jalviewjsCoreClasslists = []
3752 classlistFiles.each {
3755 def file = hash['file']
3756 if (! file.exists()) {
3757 //println("...classlist file '"+file.getPath()+"' does not exist, skipping")
3758 return false // this is a "continue" in groovy .each closure
3760 def name = hash['name']
3762 name = file.getName() - ".txt"
3770 def list = fileTree(dir: j2sDir, includes: filelist)
3772 def jsfile = "${outputDir}/core${name}.js"
3773 def zjsfile = "${outputDir}/core${name}.z.js"
3775 jalviewjsCoreClasslists += [
3784 outputs.file(jsfile)
3785 outputs.file(zjsfile)
3788 // _stevesoft core. add any cores without a classlist here (and the inputs and outputs)
3789 def stevesoftClasslistName = "_stevesoft"
3790 def stevesoftClasslist = [
3791 'jsfile': "${outputDir}/core${stevesoftClasslistName}.js",
3792 'zjsfile': "${outputDir}/core${stevesoftClasslistName}.z.js",
3793 'list': fileTree(dir: j2sDir, include: "com/stevesoft/pat/**/*.js"),
3794 'name': stevesoftClasslistName
3796 jalviewjsCoreClasslists += stevesoftClasslist
3797 inputs.files(stevesoftClasslist['list'])
3798 outputs.file(stevesoftClasslist['jsfile'])
3799 outputs.file(stevesoftClasslist['zjsfile'])
3802 def allClasslistName = "_all"
3803 def allJsFiles = fileTree(dir: j2sDir, include: "**/*.js")
3804 allJsFiles += fileTree(
3808 // these exlusions are files that the closure-compiler produces errors for. Should fix them
3809 "**/org/jmol/jvxl/readers/IsoIntersectFileReader.js",
3810 "**/org/jmol/export/JSExporter.js"
3813 allJsFiles += fileTree(
3817 // these exlusions are files that the closure-compiler produces errors for. Should fix them
3818 "**/sun/misc/Unsafe.js",
3819 "**/swingjs/jquery/jquery-editable-select.js",
3820 "**/swingjs/jquery/j2sComboBox.js",
3821 "**/sun/misc/FloatingDecimal.js"
3824 def allClasslist = [
3825 'jsfile': "${outputDir}/core${allClasslistName}.js",
3826 'zjsfile': "${outputDir}/core${allClasslistName}.z.js",
3828 'name': allClasslistName
3830 // not including this version of "all" core at the moment
3831 //jalviewjsCoreClasslists += allClasslist
3832 inputs.files(allClasslist['list'])
3833 outputs.file(allClasslist['jsfile'])
3834 outputs.file(allClasslist['zjsfile'])
3837 def logOutFile = file("${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_j2s_closure_stdout}")
3838 logOutFile.getParentFile().mkdirs()
3839 logOutFile.createNewFile()
3840 logOutFile.write(getDate("yyyy-MM-dd HH:mm:ss")+" jalviewjsBuildAllCores\n----\n")
3842 jalviewjsCoreClasslists.each {
3843 jalviewjsCallCore(it.name, it.list, prefixFile, suffixFile, it.jsfile, it.zjsfile, logOutFile, jalviewjs_j2s_to_console.equals("true"))
3850 def jalviewjsPublishCoreTemplate(String coreName, String templateName, File inputFile, String outputFile) {
3853 into file(outputFile).getParentFile()
3854 rename { filename ->
3855 if (filename.equals(inputFile.getName())) {
3856 return file(outputFile).getName()
3860 filter(ReplaceTokens,
3864 'MAIN': '"'+main_class+'"',
3866 'NAME': jalviewjsJalviewTemplateName+" [core ${coreName}]",
3867 'COREKEY': jalviewjs_core_key,
3868 'CORENAME': coreName
3875 task jalviewjsPublishCoreTemplates {
3876 dependsOn jalviewjsBuildAllCores
3877 def inputFileName = "${jalviewDir}/${j2s_coretemplate_html}"
3878 def inputFile = file(inputFileName)
3879 def outputDir = "${jalviewDir}/${jalviewjsTransferSiteCoreDir}"
3881 def outputFiles = []
3882 jalviewjsCoreClasslists.each { cl ->
3883 def outputFile = "${outputDir}/${jalviewjsJalviewTemplateName}_${cl.name}.html"
3884 cl['outputfile'] = outputFile
3885 outputFiles += outputFile
3889 jalviewjsCoreClasslists.each { cl ->
3890 jalviewjsPublishCoreTemplate(cl.name, jalviewjsJalviewTemplateName, inputFile, cl.outputfile)
3893 inputs.file(inputFile)
3894 outputs.files(outputFiles)
3898 task jalviewjsSyncCore (type: Sync) {
3899 dependsOn jalviewjsBuildAllCores
3900 dependsOn jalviewjsPublishCoreTemplates
3901 def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjsTransferSiteCoreDir}")
3902 def outputDir = "${jalviewDir}/${jalviewjsSiteDir}"
3906 def outputFiles = []
3907 rename { filename ->
3908 outputFiles += "${outputDir}/${filename}"
3914 outputs.files outputFiles
3915 inputs.files inputFiles
3919 // this Copy version of TransferSiteJs will delete anything else in the target dir
3920 task jalviewjsCopyTransferSiteJs(type: Copy) {
3921 dependsOn jalviewjsTranspile
3922 from "${jalviewDir}/${jalviewjsTransferSiteJsDir}"
3923 into "${jalviewDir}/${jalviewjsSiteDir}"
3927 // this Sync version of TransferSite is used by buildship to keep the website automatically up to date when a file changes
3928 task jalviewjsSyncTransferSiteJs(type: Sync) {
3929 from "${jalviewDir}/${jalviewjsTransferSiteJsDir}"
3931 into "${jalviewDir}/${jalviewjsSiteDir}"
3938 jalviewjsSyncAllLibs.mustRunAfter jalviewjsCopyTransferSiteJs
3939 jalviewjsSyncResources.mustRunAfter jalviewjsCopyTransferSiteJs
3940 jalviewjsSyncSiteResources.mustRunAfter jalviewjsCopyTransferSiteJs
3941 jalviewjsSyncBuildProperties.mustRunAfter jalviewjsCopyTransferSiteJs
3943 jalviewjsSyncAllLibs.mustRunAfter jalviewjsSyncTransferSiteJs
3944 jalviewjsSyncResources.mustRunAfter jalviewjsSyncTransferSiteJs
3945 jalviewjsSyncSiteResources.mustRunAfter jalviewjsSyncTransferSiteJs
3946 jalviewjsSyncBuildProperties.mustRunAfter jalviewjsSyncTransferSiteJs
3949 task jalviewjsPrepareSite {
3951 description "Prepares the website folder including unzipping files and copying resources"
3952 dependsOn jalviewjsSyncAllLibs
3953 dependsOn jalviewjsSyncResources
3954 dependsOn jalviewjsSyncSiteResources
3955 dependsOn jalviewjsSyncBuildProperties
3956 dependsOn jalviewjsSyncCore
3960 task jalviewjsBuildSite {
3962 description "Builds the whole website including transpiled code"
3963 dependsOn jalviewjsCopyTransferSiteJs
3964 dependsOn jalviewjsPrepareSite
3968 task cleanJalviewjsTransferSite {
3970 delete "${jalviewDir}/${jalviewjsTransferSiteJsDir}"
3971 delete "${jalviewDir}/${jalviewjsTransferSiteLibDir}"
3972 delete "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}"
3973 delete "${jalviewDir}/${jalviewjsTransferSiteCoreDir}"
3978 task cleanJalviewjsSite {
3979 dependsOn cleanJalviewjsTransferSite
3981 delete "${jalviewDir}/${jalviewjsSiteDir}"
3986 task jalviewjsSiteTar(type: Tar) {
3988 description "Creates a tar.gz file for the website"
3989 dependsOn jalviewjsBuildSite
3990 def outputFilename = "jalviewjs-site-${JALVIEW_VERSION}.tar.gz"
3991 archiveFileName = outputFilename
3993 compression Compression.GZIP
3995 from "${jalviewDir}/${jalviewjsSiteDir}"
3996 into jalviewjs_site_dir // this is inside the tar file
3998 inputs.dir("${jalviewDir}/${jalviewjsSiteDir}")
4002 task jalviewjsServer {
4004 def filename = "jalviewjsTest.html"
4005 description "Starts a webserver on localhost to test the website. See ${filename} to access local site on most recently used port."
4006 def htmlFile = "${jalviewDirAbsolutePath}/${filename}"
4011 def f = Class.forName("org.gradle.plugins.javascript.envjs.http.simple.SimpleHttpFileServerFactory")
4012 factory = f.newInstance()
4013 } catch (ClassNotFoundException e) {
4014 throw new GradleException("Unable to create SimpleHttpFileServerFactory")
4016 def port = Integer.valueOf(jalviewjs_server_port)
4021 while(port < start+1000 && !running) {
4023 def doc_root = new File("${jalviewDirAbsolutePath}/${jalviewjsSiteDir}")
4024 jalviewjsServer = factory.start(doc_root, port)
4026 url = jalviewjsServer.getResourceUrl(jalviewjs_server_resource)
4027 println("SERVER STARTED with document root ${doc_root}.")
4028 println("Go to "+url+" . Run gradle --stop to stop (kills all gradle daemons).")
4029 println("For debug: "+url+"?j2sdebug")
4030 println("For verbose: "+url+"?j2sverbose")
4031 } catch (Exception e) {
4036 <p><a href="${url}">JalviewJS Test. <${url}></a></p>
4037 <p><a href="${url}?j2sdebug">JalviewJS Test with debug. <${url}?j2sdebug></a></p>
4038 <p><a href="${url}?j2sverbose">JalviewJS Test with verbose. <${url}?j2sdebug></a></p>
4040 jalviewjsCoreClasslists.each { cl ->
4041 def urlcore = jalviewjsServer.getResourceUrl(file(cl.outputfile).getName())
4043 <p><a href="${urlcore}">${jalviewjsJalviewTemplateName} [core ${cl.name}]. <${urlcore}></a></p>
4045 println("For core ${cl.name}: "+urlcore)
4048 file(htmlFile).text = htmlText
4051 outputs.file(htmlFile)
4052 outputs.upToDateWhen({false})
4056 task cleanJalviewjsAll {
4058 description "Delete all configuration and build artifacts to do with JalviewJS build"
4059 dependsOn cleanJalviewjsSite
4060 dependsOn jalviewjsEclipsePaths
4063 delete "${jalviewDir}/${jalviewjsBuildDir}"
4064 delete "${jalviewDir}/${eclipse_bin_dir}"
4065 if (eclipseWorkspace != null && file(eclipseWorkspace.getAbsolutePath()+"/.metadata").exists()) {
4066 delete file(eclipseWorkspace.getAbsolutePath()+"/.metadata")
4068 delete jalviewjsJ2sAltSettingsFileName
4071 outputs.upToDateWhen( { false } )
4075 task jalviewjsIDE_checkJ2sPlugin {
4076 group "00 JalviewJS in Eclipse"
4077 description "Compare the swingjs/net.sf.j2s.core(-j11)?.jar file with the Eclipse IDE's plugin version (found in the 'dropins' dir)"
4080 def j2sPlugin = string("${jalviewDir}/${jalviewjsJ2sPlugin}")
4081 def j2sPluginFile = file(j2sPlugin)
4082 def eclipseHome = System.properties["eclipse.home.location"]
4083 if (eclipseHome == null || ! IN_ECLIPSE) {
4084 throw new StopExecutionException("Cannot find running Eclipse home from System.properties['eclipse.home.location']. Skipping J2S Plugin Check.")
4086 def eclipseJ2sPluginDirs = [ "${eclipseHome}/dropins" ]
4087 def altPluginsDir = System.properties["org.eclipse.equinox.p2.reconciler.dropins.directory"]
4088 if (altPluginsDir != null && file(altPluginsDir).exists()) {
4089 eclipseJ2sPluginDirs += altPluginsDir
4091 def foundPlugin = false
4092 def j2sPluginFileName = j2sPluginFile.getName()
4093 def eclipseJ2sPlugin
4094 def eclipseJ2sPluginFile
4095 eclipseJ2sPluginDirs.any { dir ->
4096 eclipseJ2sPlugin = "${dir}/${j2sPluginFileName}"
4097 eclipseJ2sPluginFile = file(eclipseJ2sPlugin)
4098 if (eclipseJ2sPluginFile.exists()) {
4104 def msg = "Eclipse J2S Plugin is not installed (could not find '${j2sPluginFileName}' in\n"+eclipseJ2sPluginDirs.join("\n")+"\n)\nTry running task jalviewjsIDE_copyJ2sPlugin"
4105 System.err.println(msg)
4106 throw new StopExecutionException(msg)
4109 def digest = MessageDigest.getInstance("MD5")
4111 digest.update(j2sPluginFile.text.bytes)
4112 def j2sPluginMd5 = new BigInteger(1, digest.digest()).toString(16).padLeft(32, '0')
4114 digest.update(eclipseJ2sPluginFile.text.bytes)
4115 def eclipseJ2sPluginMd5 = new BigInteger(1, digest.digest()).toString(16).padLeft(32, '0')
4117 if (j2sPluginMd5 != eclipseJ2sPluginMd5) {
4118 def msg = "WARNING! Eclipse J2S Plugin '${eclipseJ2sPlugin}' is different to this commit's version '${j2sPlugin}'"
4119 System.err.println(msg)
4120 throw new StopExecutionException(msg)
4122 def msg = "Eclipse J2S Plugin '${eclipseJ2sPlugin}' is the same as '${j2sPlugin}' (this is good)"
4128 task jalviewjsIDE_copyJ2sPlugin {
4129 group "00 JalviewJS in Eclipse"
4130 description "Copy the swingjs/net.sf.j2s.core(-j11)?.jar file into the Eclipse IDE's 'dropins' dir"
4133 def j2sPlugin = string("${jalviewDir}/${jalviewjsJ2sPlugin}")
4134 def j2sPluginFile = file(j2sPlugin)
4135 def eclipseHome = System.properties["eclipse.home.location"]
4136 if (eclipseHome == null || ! IN_ECLIPSE) {
4137 throw new StopExecutionException("Cannot find running Eclipse home from System.properties['eclipse.home.location']. NOT copying J2S Plugin.")
4139 def eclipseJ2sPlugin = "${eclipseHome}/dropins/${j2sPluginFile.getName()}"
4140 def eclipseJ2sPluginFile = file(eclipseJ2sPlugin)
4141 def msg = "WARNING! Copying this commit's j2s plugin '${j2sPlugin}' to Eclipse J2S Plugin '${eclipseJ2sPlugin}'\n* May require an Eclipse restart"
4142 System.err.println(msg)
4145 eclipseJ2sPluginFile.getParentFile().mkdirs()
4146 into eclipseJ2sPluginFile.getParent()
4152 task jalviewjsIDE_j2sFile {
4153 group "00 JalviewJS in Eclipse"
4154 description "Creates the .j2s file"
4155 dependsOn jalviewjsCreateJ2sSettings
4159 task jalviewjsIDE_SyncCore {
4160 group "00 JalviewJS in Eclipse"
4161 description "Build the core js lib closures listed in the classlists dir and publish core html from template"
4162 dependsOn jalviewjsSyncCore
4166 task jalviewjsIDE_SyncSiteAll {
4167 dependsOn jalviewjsSyncAllLibs
4168 dependsOn jalviewjsSyncResources
4169 dependsOn jalviewjsSyncSiteResources
4170 dependsOn jalviewjsSyncBuildProperties
4174 cleanJalviewjsTransferSite.mustRunAfter jalviewjsIDE_SyncSiteAll
4177 task jalviewjsIDE_PrepareSite {
4178 group "00 JalviewJS in Eclipse"
4179 description "Sync libs and resources to site dir, but not closure cores"
4181 dependsOn jalviewjsIDE_SyncSiteAll
4182 //dependsOn cleanJalviewjsTransferSite // not sure why this clean is here -- will slow down a re-run of this task
4186 task jalviewjsIDE_AssembleSite {
4187 group "00 JalviewJS in Eclipse"
4188 description "Assembles unzipped supporting zipfiles, resources, site resources and closure cores into the Eclipse transpiled site"
4189 dependsOn jalviewjsPrepareSite
4193 task jalviewjsIDE_SiteClean {
4194 group "00 JalviewJS in Eclipse"
4195 description "Deletes the Eclipse transpiled site"
4196 dependsOn cleanJalviewjsSite
4200 task jalviewjsIDE_Server {
4201 group "00 JalviewJS in Eclipse"
4202 description "Starts a webserver on localhost to test the website"
4203 dependsOn jalviewjsServer
4207 // buildship runs this at import or gradle refresh
4208 task eclipseSynchronizationTask {
4209 //dependsOn eclipseSetup
4210 dependsOn createBuildProperties
4212 dependsOn jalviewjsIDE_j2sFile
4213 dependsOn jalviewjsIDE_checkJ2sPlugin
4214 dependsOn jalviewjsIDE_PrepareSite
4219 // buildship runs this at build time or project refresh
4220 task eclipseAutoBuildTask {
4221 //dependsOn jalviewjsIDE_checkJ2sPlugin
4222 //dependsOn jalviewjsIDE_PrepareSite
4226 task jalviewjsCopyStderrLaunchFile(type: Copy) {
4227 from file(jalviewjs_stderr_launch)
4228 into jalviewjsSiteDir
4230 inputs.file jalviewjs_stderr_launch
4231 outputs.file jalviewjsStderrLaunchFilename
4234 task cleanJalviewjsChromiumUserDir {
4236 delete jalviewjsChromiumUserDir
4238 outputs.dir jalviewjsChromiumUserDir
4239 // always run when depended on
4240 outputs.upToDateWhen { !file(jalviewjsChromiumUserDir).exists() }
4243 task jalviewjsChromiumProfile {
4244 dependsOn cleanJalviewjsChromiumUserDir
4245 mustRunAfter cleanJalviewjsChromiumUserDir
4247 def firstRun = file("${jalviewjsChromiumUserDir}/First Run")
4250 mkdir jalviewjsChromiumProfileDir
4253 outputs.file firstRun
4256 task jalviewjsLaunchTest {
4258 description "Check JalviewJS opens in a browser"
4259 dependsOn jalviewjsBuildSite
4260 dependsOn jalviewjsCopyStderrLaunchFile
4261 dependsOn jalviewjsChromiumProfile
4263 def macOS = OperatingSystem.current().isMacOsX()
4264 def chromiumBinary = macOS ? jalviewjs_macos_chromium_binary : jalviewjs_chromium_binary
4265 if (chromiumBinary.startsWith("~/")) {
4266 chromiumBinary = System.getProperty("user.home") + chromiumBinary.substring(1)
4272 def timeoutms = Integer.valueOf(jalviewjs_chromium_overall_timeout) * 1000
4274 def binary = file(chromiumBinary)
4275 if (!binary.exists()) {
4276 throw new StopExecutionException("Could not find chromium binary '${chromiumBinary}'. Cannot run task ${name}.")
4278 stdout = new ByteArrayOutputStream()
4279 stderr = new ByteArrayOutputStream()
4282 if (jalviewjs_j2s_to_console.equals("true")) {
4283 execStdout = new org.apache.tools.ant.util.TeeOutputStream(
4286 execStderr = new org.apache.tools.ant.util.TeeOutputStream(
4294 "--no-sandbox", // --no-sandbox IS USED BY THE THORIUM APPIMAGE ON THE BUILDSERVER
4297 "--timeout=${timeoutms}",
4298 "--virtual-time-budget=${timeoutms}",
4299 "--user-data-dir=${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_chromium_user_dir}",
4300 "--profile-directory=${jalviewjs_chromium_profile_name}",
4301 "--allow-file-access-from-files",
4302 "--enable-logging=stderr",
4303 "file://${jalviewDirAbsolutePath}/${jalviewjsStderrLaunchFilename}"
4306 if (true || macOS) {
4307 ScheduledExecutorService executor = Executors.newScheduledThreadPool(3);
4308 Future f1 = executor.submit(
4311 standardOutput = execStdout
4312 errorOutput = execStderr
4313 executable(chromiumBinary)
4315 println "COMMAND: '"+commandLine.join(" ")+"'"
4317 executor.shutdownNow()
4321 def noChangeBytes = 0
4322 def noChangeIterations = 0
4323 executor.scheduleAtFixedRate(
4325 String stderrString = stderr.toString()
4326 // shutdown the task if we have a success string
4327 if (stderrString.contains(jalviewjs_desktop_init_string)) {
4330 executor.shutdownNow()
4332 // if no change in stderr for 10s then also end
4333 if (noChangeIterations >= jalviewjs_chromium_idle_timeout) {
4334 executor.shutdownNow()
4336 if (stderrString.length() == noChangeBytes) {
4337 noChangeIterations++
4339 noChangeBytes = stderrString.length()
4340 noChangeIterations = 0
4343 1, 1, TimeUnit.SECONDS)
4345 executor.schedule(new Runnable(){
4348 executor.shutdownNow()
4350 }, timeoutms, TimeUnit.MILLISECONDS)
4352 executor.awaitTermination(timeoutms+10000, TimeUnit.MILLISECONDS)
4353 executor.shutdownNow()
4360 stderr.toString().eachLine { line ->
4361 if (line.contains(jalviewjs_desktop_init_string)) {
4362 println("Found line '"+line+"'")
4368 throw new GradleException("Could not find evidence of Desktop launch in JalviewJS.")
4376 description "Build the JalviewJS site and run the launch test"
4377 dependsOn jalviewjsBuildSite
4378 dependsOn jalviewjsLaunchTest