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 groovy.transform.ExternalizeMethods
14 import groovy.util.XmlParser
15 import groovy.xml.XmlUtil
16 import groovy.json.JsonBuilder
17 import com.vladsch.flexmark.util.ast.Node
18 import com.vladsch.flexmark.html.HtmlRenderer
19 import com.vladsch.flexmark.parser.Parser
20 import com.vladsch.flexmark.util.data.MutableDataSet
21 import com.vladsch.flexmark.ext.gfm.tasklist.TaskListExtension
22 import com.vladsch.flexmark.ext.tables.TablesExtension
23 import com.vladsch.flexmark.ext.gfm.strikethrough.StrikethroughExtension
24 import com.vladsch.flexmark.ext.autolink.AutolinkExtension
25 import com.vladsch.flexmark.ext.anchorlink.AnchorLinkExtension
26 import com.vladsch.flexmark.ext.toc.TocExtension
27 import com.google.common.hash.HashCode
28 import com.google.common.hash.Hashing
29 import com.google.common.io.Files
30 import org.jsoup.Jsoup
31 import org.jsoup.nodes.Element
39 classpath "com.vladsch.flexmark:flexmark-all:0.62.0"
40 classpath "org.jsoup:jsoup:1.14.3"
41 classpath "com.eowise:gradle-imagemagick:0.5.1"
50 id "com.diffplug.gradle.spotless" version "3.28.0"
51 id 'com.github.johnrengelman.shadow' version '4.0.3'
52 id 'com.install4j.gradle' version '10.0.3'
53 id 'com.dorongold.task-tree' version '2.1.1' // only needed to display task dependency tree with gradle task1 [task2 ...] taskTree
54 id 'com.palantir.git-version' version '0.13.0' apply false
65 // in ext the values are cast to Object. Ensure string values are cast as String (and not GStringImpl) for later use
66 def string(Object o) {
67 return o == null ? "" : o.toString()
70 def overrideProperties(String propsFileName, boolean output = false) {
71 if (propsFileName == null) {
74 def propsFile = file(propsFileName)
75 if (propsFile != null && propsFile.exists()) {
76 println("Using properties from file '${propsFileName}'")
78 def p = new Properties()
79 def localPropsFIS = new FileInputStream(propsFile)
85 if (project.hasProperty(key)) {
86 oldval = project.findProperty(key)
87 project.setProperty(key, val)
89 println("Overriding property '${key}' ('${oldval}') with ${file(propsFile).getName()} value '${val}'")
92 ext.setProperty(key, val)
94 println("Setting ext property '${key}' with ${file(propsFile).getName()}s value '${val}'")
98 } catch (Exception e) {
99 println("Exception reading local.properties")
106 jalviewDirAbsolutePath = file(jalviewDir).getAbsolutePath()
107 jalviewDirRelativePath = jalviewDir
110 getdownChannelName = CHANNEL.toLowerCase()
111 // default to "default". Currently only has different cosmetics for "develop", "release", "default"
112 propertiesChannelName = ["develop", "release", "test-release", "jalviewjs", "jalviewjs-release" ].contains(getdownChannelName) ? getdownChannelName : "default"
113 channelDirName = propertiesChannelName
114 // Import channel_properties
115 if (getdownChannelName.startsWith("develop-")) {
116 channelDirName = "develop-SUFFIX"
118 channelDir = string("${jalviewDir}/${channel_properties_dir}/${channelDirName}")
119 channelGradleProperties = string("${channelDir}/channel_gradle.properties")
120 channelPropsFile = string("${channelDir}/${resource_dir}/${channel_props}")
121 overrideProperties(channelGradleProperties, false)
122 // local build environment properties
123 // can be "projectDir/local.properties"
124 overrideProperties("${projectDir}/local.properties", true)
125 // or "../projectDir_local.properties"
126 overrideProperties(projectDir.getParent() + "/" + projectDir.getName() + "_local.properties", true)
129 // Import releaseProps from the RELEASE file
130 // or a file specified via JALVIEW_RELEASE_FILE if defined
131 // Expect jalview.version and target release branch in jalview.release
132 releaseProps = new Properties();
133 def releasePropFile = findProperty("JALVIEW_RELEASE_FILE");
134 def defaultReleasePropFile = "${jalviewDirAbsolutePath}/RELEASE";
136 (new File(releasePropFile!=null ? releasePropFile : defaultReleasePropFile)).withInputStream {
137 releaseProps.load(it)
139 } catch (Exception fileLoadError) {
140 throw new Error("Couldn't load release properties file "+(releasePropFile==null ? defaultReleasePropFile : "from custom location: releasePropFile"),fileLoadError);
143 // Set JALVIEW_VERSION if it is not already set
144 if (findProperty("JALVIEW_VERSION")==null || "".equals(JALVIEW_VERSION)) {
145 JALVIEW_VERSION = releaseProps.get("jalview.version")
147 println("JALVIEW_VERSION is set to '${JALVIEW_VERSION}'")
149 // this property set when running Eclipse headlessly
150 j2sHeadlessBuildProperty = string("net.sf.j2s.core.headlessbuild")
151 // this property set by Eclipse
152 eclipseApplicationProperty = string("eclipse.application")
153 // CHECK IF RUNNING FROM WITHIN ECLIPSE
154 def eclipseApplicationPropertyVal = System.properties[eclipseApplicationProperty]
155 IN_ECLIPSE = eclipseApplicationPropertyVal != null && eclipseApplicationPropertyVal.startsWith("org.eclipse.ui.")
156 // BUT WITHOUT THE HEADLESS BUILD PROPERTY SET
157 if (System.properties[j2sHeadlessBuildProperty].equals("true")) {
158 println("Setting IN_ECLIPSE to ${IN_ECLIPSE} as System.properties['${j2sHeadlessBuildProperty}'] == '${System.properties[j2sHeadlessBuildProperty]}'")
162 println("WITHIN ECLIPSE IDE")
164 println("HEADLESS BUILD")
167 J2S_ENABLED = (project.hasProperty('j2s.compiler.status') && project['j2s.compiler.status'] != null && project['j2s.compiler.status'] == "enable")
169 println("J2S ENABLED")
172 System.properties.sort { it.key }.each {
173 key, val -> println("SYSTEM PROPERTY ${key}='${val}'")
176 if (false && IN_ECLIPSE) {
177 jalviewDir = jalviewDirAbsolutePath
182 buildDate = new Date().format("yyyyMMdd")
185 bareSourceDir = string(source_dir)
186 sourceDir = string("${jalviewDir}/${bareSourceDir}")
187 resourceDir = string("${jalviewDir}/${resource_dir}")
188 bareTestSourceDir = string(test_source_dir)
189 testDir = string("${jalviewDir}/${bareTestSourceDir}")
191 classesDir = string("${jalviewDir}/${classes_dir}")
194 useClover = clover.equals("true")
195 cloverBuildDir = "${buildDir}/clover"
196 cloverInstrDir = file("${cloverBuildDir}/clover-instr")
197 cloverClassesDir = file("${cloverBuildDir}/clover-classes")
198 cloverReportDir = file("${buildDir}/reports/clover")
199 cloverTestInstrDir = file("${cloverBuildDir}/clover-test-instr")
200 cloverTestClassesDir = file("${cloverBuildDir}/clover-test-classes")
201 //cloverTestClassesDir = cloverClassesDir
202 cloverDb = string("${cloverBuildDir}/clover.db")
204 testSourceDir = useClover ? cloverTestInstrDir : testDir
205 testClassesDir = useClover ? cloverTestClassesDir : "${jalviewDir}/${test_output_dir}"
208 backgroundImageText = BACKGROUNDIMAGETEXT
209 getdownChannelDir = string("${getdown_website_dir}/${propertiesChannelName}")
210 getdownAppBaseDir = string("${jalviewDir}/${getdownChannelDir}/${JAVA_VERSION}")
211 getdownArchiveDir = string("${jalviewDir}/${getdown_archive_dir}")
212 getdownFullArchiveDir = null
213 getdownTextLines = []
214 getdownLaunchJvl = null
215 getdownVersionLaunchJvl = null
217 buildProperties = null
219 // the following values might be overridden by the CHANNEL switch
220 getdownDir = string("${getdownChannelName}/${JAVA_VERSION}")
221 getdownAppBase = string("${getdown_channel_base}/${getdownDir}")
222 getdownArchiveAppBase = getdown_archive_base
223 getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher}")
224 getdownAppDistDir = getdown_app_dir_alt
225 getdownImagesDir = string("${jalviewDir}/${getdown_images_dir}")
226 getdownImagesBuildDir = string("${buildDir}/imagemagick/getdown")
227 getdownSetAppBaseProperty = false // whether to pass the appbase and appdistdir to the application
228 reportRsyncCommand = false
229 jvlChannelName = CHANNEL.toLowerCase()
230 install4jSuffix = CHANNEL.substring(0, 1).toUpperCase() + CHANNEL.substring(1).toLowerCase(); // BUILD -> Build
231 install4jDMGDSStore = "${install4j_images_dir}/${install4j_dmg_ds_store}"
232 install4jDMGBackgroundImageDir = "${install4j_images_dir}"
233 install4jDMGBackgroundImageBuildDir = "build/imagemagick/install4j"
234 install4jDMGBackgroundImageFile = "${install4j_dmg_background}"
235 install4jInstallerName = "${jalview_name} Non-Release Installer"
236 install4jExecutableName = install4j_executable_name
237 install4jExtraScheme = "jalviewx"
238 install4jMacIconsFile = string("${install4j_images_dir}/${install4j_mac_icons_file}")
239 install4jWindowsIconsFile = string("${install4j_images_dir}/${install4j_windows_icons_file}")
240 install4jPngIconFile = string("${install4j_images_dir}/${install4j_png_icon_file}")
241 install4jBackground = string("${install4j_images_dir}/${install4j_background}")
242 install4jBuildDir = "${install4j_build_dir}/${JAVA_VERSION}"
243 install4jCheckSums = true
245 applicationName = "${jalview_name}"
249 // TODO: get bamboo build artifact URL for getdown artifacts
250 getdown_channel_base = bamboo_channelbase
251 getdownChannelName = string("${bamboo_planKey}/${JAVA_VERSION}")
252 getdownAppBase = string("${bamboo_channelbase}/${bamboo_planKey}${bamboo_getdown_channel_suffix}/${JAVA_VERSION}")
253 jvlChannelName += "_${getdownChannelName}"
254 // automatically add the test group Not-bamboo for exclusion
255 if ("".equals(testng_excluded_groups)) {
256 testng_excluded_groups = "Not-bamboo"
258 install4jExtraScheme = "jalviewb"
259 backgroundImageText = true
262 case [ "RELEASE", "JALVIEWJS-RELEASE" ]:
263 getdownAppDistDir = getdown_app_dir_release
264 getdownSetAppBaseProperty = true
265 reportRsyncCommand = true
267 install4jInstallerName = "${jalview_name} Installer"
271 getdownChannelName = CHANNEL.toLowerCase()+"/${JALVIEW_VERSION}"
272 getdownDir = string("${getdownChannelName}/${JAVA_VERSION}")
273 getdownAppBase = string("${getdown_channel_base}/${getdownDir}")
274 if (!file("${ARCHIVEDIR}/${package_dir}").exists()) {
275 throw new GradleException("Must provide an ARCHIVEDIR value to produce an archive distribution")
277 package_dir = string("${ARCHIVEDIR}/${package_dir}")
278 buildProperties = string("${ARCHIVEDIR}/${classes_dir}/${build_properties_file}")
281 reportRsyncCommand = true
282 install4jExtraScheme = "jalviewa"
286 getdownChannelName = string("archive/${JALVIEW_VERSION}")
287 getdownDir = string("${getdownChannelName}/${JAVA_VERSION}")
288 getdownAppBase = file(getdownAppBaseDir).toURI().toString()
289 if (!file("${ARCHIVEDIR}/${package_dir}").exists()) {
290 throw new GradleException("Must provide an ARCHIVEDIR value to produce an archive distribution [did not find '${ARCHIVEDIR}/${package_dir}']")
292 package_dir = string("${ARCHIVEDIR}/${package_dir}")
293 buildProperties = string("${ARCHIVEDIR}/${classes_dir}/${build_properties_file}")
296 reportRsyncCommand = true
297 getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher_local}")
298 install4jSuffix = "Archive"
299 install4jExtraScheme = "jalviewa"
302 case ~/^DEVELOP-([\.\-\w]*)$/:
303 def suffix = Matcher.lastMatcher[0][1]
304 reportRsyncCommand = true
305 getdownSetAppBaseProperty = true
306 JALVIEW_VERSION=JALVIEW_VERSION+"-d${suffix}-${buildDate}"
307 install4jSuffix = "Develop ${suffix}"
308 install4jExtraScheme = "jalviewd"
309 install4jInstallerName = "${jalview_name} Develop ${suffix} Installer"
310 getdownChannelName = string("develop-${suffix}")
311 getdownChannelDir = string("${getdown_website_dir}/${getdownChannelName}")
312 getdownAppBaseDir = string("${jalviewDir}/${getdownChannelDir}/${JAVA_VERSION}")
313 getdownDir = string("${getdownChannelName}/${JAVA_VERSION}")
314 getdownAppBase = string("${getdown_channel_base}/${getdownDir}")
315 channelSuffix = string(suffix)
316 backgroundImageText = true
320 reportRsyncCommand = true
321 getdownSetAppBaseProperty = true
322 // DEVELOP-RELEASE is usually associated with a Jalview release series so set the version
323 JALVIEW_VERSION=JALVIEW_VERSION+"-d${buildDate}"
325 install4jSuffix = "Develop"
326 install4jExtraScheme = "jalviewd"
327 install4jInstallerName = "${jalview_name} Develop Installer"
328 backgroundImageText = true
332 reportRsyncCommand = true
333 getdownSetAppBaseProperty = true
334 // Don't ignore transpile errors for release build
335 if (jalviewjs_ignore_transpile_errors.equals("true")) {
336 jalviewjs_ignore_transpile_errors = "false"
337 println("Setting jalviewjs_ignore_transpile_errors to 'false'")
339 JALVIEW_VERSION = JALVIEW_VERSION+"-test"
340 install4jSuffix = "Test"
341 install4jExtraScheme = "jalviewt"
342 install4jInstallerName = "${jalview_name} Test Installer"
343 backgroundImageText = true
346 case ~/^SCRATCH(|-[-\w]*)$/:
347 getdownChannelName = CHANNEL
348 JALVIEW_VERSION = JALVIEW_VERSION+"-"+CHANNEL
350 getdownDir = string("${getdownChannelName}/${JAVA_VERSION}")
351 getdownAppBase = string("${getdown_channel_base}/${getdownDir}")
352 reportRsyncCommand = true
353 install4jSuffix = "Scratch"
357 if (!file("${LOCALDIR}").exists()) {
358 throw new GradleException("Must provide a LOCALDIR value to produce a local distribution")
360 getdownAppBase = file(file("${LOCALDIR}").getAbsolutePath()).toURI().toString()
361 getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher_local}")
363 JALVIEW_VERSION = "TEST"
364 install4jSuffix = "Test-Local"
365 install4jExtraScheme = "jalviewt"
366 install4jInstallerName = "${jalview_name} Test Installer"
367 backgroundImageText = true
370 case [ "LOCAL", "JALVIEWJS" ]:
371 JALVIEW_VERSION = "TEST"
372 getdownAppBase = file(getdownAppBaseDir).toURI().toString()
373 getdownArchiveAppBase = file("${jalviewDir}/${getdown_archive_dir}").toURI().toString()
374 getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher_local}")
375 install4jExtraScheme = "jalviewl"
376 install4jCheckSums = false
379 default: // something wrong specified
380 throw new GradleException("CHANNEL must be one of BUILD, RELEASE, ARCHIVE, DEVELOP, TEST-RELEASE, SCRATCH-..., LOCAL [default]")
384 JALVIEW_VERSION_UNDERSCORES = JALVIEW_VERSION.replaceAll("\\.", "_")
385 hugoDataJsonFile = file("${jalviewDir}/${hugo_build_dir}/${hugo_data_installers_dir}/installers-${JALVIEW_VERSION_UNDERSCORES}.json")
386 hugoArchiveMdFile = file("${jalviewDir}/${hugo_build_dir}/${hugo_version_archive_dir}/Version-${JALVIEW_VERSION_UNDERSCORES}/_index.md")
387 // override getdownAppBase if requested
388 if (findProperty("getdown_appbase_override") != null) {
389 // revert to LOCAL if empty string
390 if (string(getdown_appbase_override) == "") {
391 getdownAppBase = file(getdownAppBaseDir).toURI().toString()
392 getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher_local}")
393 } else if (string(getdown_appbase_override).startsWith("file://")) {
394 getdownAppBase = string(getdown_appbase_override)
395 getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher_local}")
397 getdownAppBase = string(getdown_appbase_override)
399 println("Overriding getdown appbase with '${getdownAppBase}'")
401 // sanitise file name for jalview launcher file for this channel
402 jvlChannelName = jvlChannelName.replaceAll("[^\\w\\-]+", "_")
403 // install4j application and folder names
404 if (install4jSuffix == "") {
405 install4jBundleId = "${install4j_bundle_id}"
406 install4jWinApplicationId = install4j_release_win_application_id
408 applicationName = "${jalview_name} ${install4jSuffix}"
409 install4jBundleId = "${install4j_bundle_id}-" + install4jSuffix.toLowerCase()
410 // add int hash of install4jSuffix to the last part of the application_id
411 def id = install4j_release_win_application_id
412 def idsplitreverse = id.split("-").reverse()
413 idsplitreverse[0] = idsplitreverse[0].toInteger() + install4jSuffix.hashCode()
414 install4jWinApplicationId = idsplitreverse.reverse().join("-")
416 // sanitise folder and id names
417 // install4jApplicationFolder = e.g. "Jalview Build"
418 install4jApplicationFolder = applicationName
419 .replaceAll("[\"'~:/\\\\\\s]", "_") // replace all awkward filename chars " ' ~ : / \
420 .replaceAll("_+", "_") // collapse __
421 install4jInternalId = applicationName
423 .replaceAll("[^\\w\\-\\.]", "_") // replace other non [alphanumeric,_,-,.]
424 .replaceAll("_+", "") // collapse __
425 //.replaceAll("_*-_*", "-") // collapse _-_
426 install4jUnixApplicationFolder = applicationName
428 .replaceAll("[^\\w\\-\\.]", "_") // replace other non [alphanumeric,_,-,.]
429 .replaceAll("_+", "_") // collapse __
430 .replaceAll("_*-_*", "-") // collapse _-_
433 getdownWrapperLink = install4jUnixApplicationFolder // e.g. "jalview_local"
434 getdownAppDir = string("${getdownAppBaseDir}/${getdownAppDistDir}")
435 //getdownJ11libDir = "${getdownAppBaseDir}/${getdown_j11lib_dir}"
436 getdownResourceDir = string("${getdownAppBaseDir}/${getdown_resource_dir}")
437 getdownInstallDir = string("${getdownAppBaseDir}/${getdown_install_dir}")
438 getdownFilesDir = string("${jalviewDir}/${getdown_files_dir}/${JAVA_VERSION}/")
439 getdownFilesInstallDir = string("${getdownFilesDir}/${getdown_install_dir}")
440 /* compile without modules -- using classpath libraries
441 modules_compileClasspath = fileTree(dir: "${jalviewDir}/${j11modDir}", include: ["*.jar"])
442 modules_runtimeClasspath = modules_compileClasspath
448 apply plugin: "com.palantir.git-version"
449 def details = versionDetails()
450 gitHash = details.gitHash
451 gitBranch = details.branchName
452 } catch(org.gradle.api.internal.plugins.PluginApplicationException e) {
453 println("Not in a git repository. Using git values from RELEASE properties file.")
454 gitHash = releaseProps.getProperty("git.hash")
455 gitBranch = releaseProps.getProperty("git.branch")
456 } catch(java.lang.RuntimeException e1) {
457 throw new GradleException("Error with git-version plugin. Directory '.git' exists but versionDetails() cannot be found.")
460 println("Using a ${CHANNEL} profile.")
462 additional_compiler_args = []
463 // configure classpath/args for j8/j11 compilation
464 if (JAVA_VERSION.equals("1.8")) {
465 JAVA_INTEGER_VERSION = string("8")
468 libDistDir = j8libDir
469 compile_source_compatibility = 1.8
470 compile_target_compatibility = 1.8
471 // these are getdown.txt properties defined dependent on the JAVA_VERSION
472 getdownAltJavaMinVersion = string(findProperty("getdown_alt_java8_min_version"))
473 getdownAltJavaMaxVersion = string(findProperty("getdown_alt_java8_max_version"))
474 // this property is assigned below and expanded to multiple lines in the getdown task
475 getdownAltMultiJavaLocation = string(findProperty("getdown_alt_java8_txt_multi_java_location"))
476 // this property is for the Java library used in eclipse
477 eclipseJavaRuntimeName = string("JavaSE-1.8")
478 } else if (JAVA_VERSION.equals("11")) {
479 JAVA_INTEGER_VERSION = string("11")
481 libDistDir = j11libDir
482 compile_source_compatibility = 11
483 compile_target_compatibility = 11
484 getdownAltJavaMinVersion = string(findProperty("getdown_alt_java11_min_version"))
485 getdownAltJavaMaxVersion = string(findProperty("getdown_alt_java11_max_version"))
486 getdownAltMultiJavaLocation = string(findProperty("getdown_alt_java11_txt_multi_java_location"))
487 eclipseJavaRuntimeName = string("JavaSE-11")
488 /* compile without modules -- using classpath libraries
489 additional_compiler_args += [
490 '--module-path', modules_compileClasspath.asPath,
491 '--add-modules', j11modules
494 } else if (JAVA_VERSION.equals("17")) {
495 JAVA_INTEGER_VERSION = string("17")
497 libDistDir = j17libDir
498 compile_source_compatibility = 17
499 compile_target_compatibility = 17
500 getdownAltJavaMinVersion = string(findProperty("getdown_alt_java11_min_version"))
501 getdownAltJavaMaxVersion = string(findProperty("getdown_alt_java11_max_version"))
502 getdownAltMultiJavaLocation = string(findProperty("getdown_alt_java11_txt_multi_java_location"))
503 eclipseJavaRuntimeName = string("JavaSE-17")
504 /* compile without modules -- using classpath libraries
505 additional_compiler_args += [
506 '--module-path', modules_compileClasspath.asPath,
507 '--add-modules', j11modules
511 throw new GradleException("JAVA_VERSION=${JAVA_VERSION} not currently supported by Jalview")
516 JAVA_MIN_VERSION = JAVA_VERSION
517 JAVA_MAX_VERSION = JAVA_VERSION
518 jreInstallsDir = string(jre_installs_dir)
519 if (jreInstallsDir.startsWith("~/")) {
520 jreInstallsDir = System.getProperty("user.home") + jreInstallsDir.substring(1)
522 install4jDir = string("${jalviewDir}/${install4j_utils_dir}")
523 install4jConfFileName = string("jalview-install4j-conf.install4j")
524 install4jConfFile = file("${install4jDir}/${install4jConfFileName}")
525 install4jHomeDir = install4j_home_dir
526 if (install4jHomeDir.startsWith("~/")) {
527 install4jHomeDir = System.getProperty("user.home") + install4jHomeDir.substring(1)
530 resourceBuildDir = string("${buildDir}/resources")
531 resourcesBuildDir = string("${resourceBuildDir}/resources_build")
532 helpBuildDir = string("${resourceBuildDir}/help_build")
533 docBuildDir = string("${resourceBuildDir}/doc_build")
535 if (buildProperties == null) {
536 buildProperties = string("${resourcesBuildDir}/${build_properties_file}")
538 buildingHTML = string("${jalviewDir}/${doc_dir}/building.html")
539 helpParentDir = string("${jalviewDir}/${help_parent_dir}")
540 helpSourceDir = string("${helpParentDir}/${help_dir}")
541 helpFile = string("${helpBuildDir}/${help_dir}/help.jhm")
544 convertBinaryExpectedLocation = imagemagick_convert
545 if (convertBinaryExpectedLocation.startsWith("~/")) {
546 convertBinaryExpectedLocation = System.getProperty("user.home") + convertBinaryExpectedLocation.substring(1)
548 if (file(convertBinaryExpectedLocation).exists()) {
549 convertBinary = convertBinaryExpectedLocation
552 relativeBuildDir = file(jalviewDirAbsolutePath).toPath().relativize(buildDir.toPath())
553 jalviewjsBuildDir = string("${relativeBuildDir}/jalviewjs")
554 jalviewjsSiteDir = string("${jalviewjsBuildDir}/${jalviewjs_site_dir}")
556 jalviewjsTransferSiteJsDir = string(jalviewjsSiteDir)
558 jalviewjsTransferSiteJsDir = string("${jalviewjsBuildDir}/tmp/${jalviewjs_site_dir}_js")
560 jalviewjsTransferSiteLibDir = string("${jalviewjsBuildDir}/tmp/${jalviewjs_site_dir}_lib")
561 jalviewjsTransferSiteSwingJsDir = string("${jalviewjsBuildDir}/tmp/${jalviewjs_site_dir}_swingjs")
562 jalviewjsTransferSiteCoreDir = string("${jalviewjsBuildDir}/tmp/${jalviewjs_site_dir}_core")
563 jalviewjsJalviewCoreHtmlFile = string("")
564 jalviewjsJalviewCoreName = string(jalviewjs_core_name)
565 jalviewjsCoreClasslists = []
566 jalviewjsJalviewTemplateName = string(jalviewjs_name)
567 jalviewjsJ2sSettingsFileName = string("${jalviewDir}/${jalviewjs_j2s_settings}")
568 jalviewjsJ2sAltSettingsFileName = string("${jalviewDir}/${jalviewjs_j2s_alt_settings}")
569 jalviewjsJ2sProps = null
570 jalviewjsJ2sPlugin = jalviewjs_j2s_plugin
571 jalviewjsStderrLaunchFilename = "${jalviewjsSiteDir}/"+(file(jalviewjs_stderr_launch).getName())
573 eclipseWorkspace = null
574 eclipseBinary = string("")
575 eclipseVersion = string("")
586 outputDir = file(classesDir)
590 srcDirs = [ resourcesBuildDir, docBuildDir, helpBuildDir ]
593 compileClasspath = files(sourceSets.main.java.outputDir)
594 compileClasspath += fileTree(dir: "${jalviewDir}/${libDir}", include: ["*.jar"])
596 runtimeClasspath = compileClasspath
597 runtimeClasspath += files(sourceSets.main.resources.srcDirs)
602 srcDirs cloverInstrDir
603 outputDir = cloverClassesDir
607 srcDirs = sourceSets.main.resources.srcDirs
610 compileClasspath = files( sourceSets.clover.java.outputDir )
611 //compileClasspath += files( testClassesDir )
612 compileClasspath += fileTree(dir: "${jalviewDir}/${libDir}", include: ["*.jar"])
613 compileClasspath += fileTree(dir: "${jalviewDir}/${clover_lib_dir}", include: ["*.jar"])
614 compileClasspath += fileTree(dir: "${jalviewDir}/${utils_dir}/testnglibs", include: ["**/*.jar"])
616 runtimeClasspath = compileClasspath
621 srcDirs testSourceDir
622 outputDir = file(testClassesDir)
626 srcDirs = useClover ? sourceSets.clover.resources.srcDirs : sourceSets.main.resources.srcDirs
629 compileClasspath = files( sourceSets.test.java.outputDir )
630 compileClasspath += useClover ? sourceSets.clover.compileClasspath : sourceSets.main.compileClasspath
631 compileClasspath += fileTree(dir: "${jalviewDir}/${utils_dir}/testnglibs", include: ["**/*.jar"])
633 runtimeClasspath = compileClasspath
634 runtimeClasspath += files(sourceSets.test.resources.srcDirs)
640 // eclipse project and settings files creation, also used by buildship
643 name = eclipse_project_name
645 natures 'org.eclipse.jdt.core.javanature',
646 'org.eclipse.jdt.groovy.core.groovyNature',
647 'org.eclipse.buildship.core.gradleprojectnature'
649 buildCommand 'org.eclipse.jdt.core.javabuilder'
650 buildCommand 'org.eclipse.buildship.core.gradleprojectbuilder'
654 //defaultOutputDir = sourceSets.main.java.outputDir
655 configurations.each{ c->
656 if (c.isCanBeResolved()) {
657 minusConfigurations += [c]
661 plusConfigurations = [ ]
665 def removeTheseToo = []
666 HashMap<String, Boolean> alreadyAddedSrcPath = new HashMap<>();
667 cp.entries.each { entry ->
668 // This conditional removes all src classpathentries that a) have already been added or b) aren't "src" or "test".
669 // e.g. this removes the resources dir being copied into bin/main, bin/test AND bin/clover
670 // we add the resources and help/help dirs in as libs afterwards (see below)
671 if (entry.kind == 'src') {
672 if (alreadyAddedSrcPath.getAt(entry.path) || !(entry.path == bareSourceDir || entry.path == bareTestSourceDir)) {
673 removeTheseToo += entry
675 alreadyAddedSrcPath.putAt(entry.path, true)
680 cp.entries.removeAll(removeTheseToo)
682 //cp.entries += new Output("${eclipse_bin_dir}/main")
683 if (file(helpParentDir).isDirectory()) {
684 cp.entries += new Library(fileReference(helpParentDir))
686 if (file(resourceDir).isDirectory()) {
687 cp.entries += new Library(fileReference(resourceDir))
690 HashMap<String, Boolean> alreadyAddedLibPath = new HashMap<>();
692 sourceSets.main.compileClasspath.findAll { it.name.endsWith(".jar") }.any {
693 //don't want to add outputDir as eclipse is using its own output dir in bin/main
694 if (it.isDirectory() || ! it.exists()) {
695 // don't add dirs to classpath, especially if they don't exist
696 return false // groovy "continue" in .any closure
698 def itPath = it.toString()
699 if (itPath.startsWith("${jalviewDirAbsolutePath}/")) {
700 // make relative path
701 itPath = itPath.substring(jalviewDirAbsolutePath.length()+1)
703 if (alreadyAddedLibPath.get(itPath)) {
704 //println("Not adding duplicate entry "+itPath)
706 //println("Adding entry "+itPath)
707 cp.entries += new Library(fileReference(itPath))
708 alreadyAddedLibPath.put(itPath, true)
712 sourceSets.test.compileClasspath.findAll { it.name.endsWith(".jar") }.any {
713 //no longer want to add outputDir as eclipse is using its own output dir in bin/main
714 if (it.isDirectory() || ! it.exists()) {
715 // don't add dirs to classpath
716 return false // groovy "continue" in .any closure
719 def itPath = it.toString()
720 if (itPath.startsWith("${jalviewDirAbsolutePath}/")) {
721 itPath = itPath.substring(jalviewDirAbsolutePath.length()+1)
723 if (alreadyAddedLibPath.get(itPath)) {
726 def lib = new Library(fileReference(itPath))
727 lib.entryAttributes["test"] = "true"
729 alreadyAddedLibPath.put(itPath, true)
737 containers 'org.eclipse.buildship.core.gradleclasspathcontainer'
742 // for the IDE, use java 11 compatibility
743 sourceCompatibility = compile_source_compatibility
744 targetCompatibility = compile_target_compatibility
745 javaRuntimeName = eclipseJavaRuntimeName
747 // add in jalview project specific properties/preferences into eclipse core preferences
749 withProperties { props ->
750 def jalview_prefs = new Properties()
751 def ins = new FileInputStream("${jalviewDirAbsolutePath}/${eclipse_extra_jdt_prefs_file}")
752 jalview_prefs.load(ins)
754 jalview_prefs.forEach { t, v ->
755 if (props.getAt(t) == null) {
759 // codestyle file -- overrides previous formatter prefs
760 def csFile = file("${jalviewDirAbsolutePath}/${eclipse_codestyle_file}")
761 if (csFile.exists()) {
762 XmlParser parser = new XmlParser()
763 def profiles = parser.parse(csFile)
764 def profile = profiles.'profile'.find { p -> (p.'@kind' == "CodeFormatterProfile" && p.'@name' == "Jalview") }
765 if (profile != null) {
766 profile.'setting'.each { s ->
768 def value = s.'@value'
769 if (id != null && value != null) {
770 props.putAt(id, value)
781 // Don't want these to be activated if in headless build
782 synchronizationTasks "eclipseSynchronizationTask"
783 //autoBuildTasks "eclipseAutoBuildTask"
789 /* hack to change eclipse prefs in .settings files other than org.eclipse.jdt.core.prefs */
790 // Class to allow updating arbitrary properties files
791 class PropertiesFile extends PropertiesPersistableConfigurationObject {
792 public PropertiesFile(PropertiesTransformer t) { super(t); }
793 @Override protected void load(Properties properties) { }
794 @Override protected void store(Properties properties) { }
795 @Override protected String getDefaultResourceName() { return ""; }
796 // This is necessary, because PropertiesPersistableConfigurationObject fails
797 // if no default properties file exists.
798 @Override public void loadDefaults() { load(new StringBufferInputStream("")); }
801 // Task to update arbitrary properties files (set outputFile)
802 class PropertiesFileTask extends PropertiesGeneratorTask<PropertiesFile> {
803 private final PropertiesFileContentMerger file;
804 public PropertiesFileTask() { file = new PropertiesFileContentMerger(getTransformer()); }
805 protected PropertiesFile create() { return new PropertiesFile(getTransformer()); }
806 protected void configure(PropertiesFile props) {
807 file.getBeforeMerged().execute(props); file.getWhenMerged().execute(props);
809 public void file(Closure closure) { ConfigureUtil.configure(closure, file); }
812 task eclipseUIPreferences(type: PropertiesFileTask) {
813 description = "Generate Eclipse additional settings"
814 def filename = "org.eclipse.jdt.ui.prefs"
815 outputFile = "$projectDir/.settings/${filename}" as File
818 it.load new FileInputStream("$projectDir/utils/eclipse/${filename}" as String)
823 task eclipseGroovyCorePreferences(type: PropertiesFileTask) {
824 description = "Generate Eclipse additional settings"
825 def filename = "org.eclipse.jdt.groovy.core.prefs"
826 outputFile = "$projectDir/.settings/${filename}" as File
829 it.load new FileInputStream("$projectDir/utils/eclipse/${filename}" as String)
834 task eclipseAllPreferences {
836 dependsOn eclipseUIPreferences
837 dependsOn eclipseGroovyCorePreferences
840 eclipseUIPreferences.mustRunAfter eclipseJdt
841 eclipseGroovyCorePreferences.mustRunAfter eclipseJdt
843 /* end of eclipse preferences hack */
851 delete cloverBuildDir
852 delete cloverReportDir
857 task cloverInstrJava(type: JavaExec) {
858 group = "Verification"
859 description = "Create clover instrumented source java files"
861 dependsOn cleanClover
863 inputs.files(sourceSets.main.allJava)
864 outputs.dir(cloverInstrDir)
866 //classpath = fileTree(dir: "${jalviewDir}/${clover_lib_dir}", include: ["*.jar"])
867 classpath = sourceSets.clover.compileClasspath
868 main = "com.atlassian.clover.CloverInstr"
876 cloverInstrDir.getPath(),
878 def srcFiles = sourceSets.main.allJava.files
881 { file -> file.absolutePath }
884 args argsList.toArray()
887 delete cloverInstrDir
888 println("Clover: About to instrument "+srcFiles.size() +" files")
893 task cloverInstrTests(type: JavaExec) {
894 group = "Verification"
895 description = "Create clover instrumented source test files"
897 dependsOn cleanClover
899 inputs.files(testDir)
900 outputs.dir(cloverTestInstrDir)
902 classpath = sourceSets.clover.compileClasspath
903 main = "com.atlassian.clover.CloverInstr"
913 cloverTestInstrDir.getPath(),
915 args argsList.toArray()
918 delete cloverTestInstrDir
919 println("Clover: About to instrument test files")
925 group = "Verification"
926 description = "Create clover instrumented all source files"
928 dependsOn cloverInstrJava
929 dependsOn cloverInstrTests
933 cloverClasses.dependsOn cloverInstr
936 task cloverConsoleReport(type: JavaExec) {
937 group = "Verification"
938 description = "Creates clover console report"
941 file(cloverDb).exists()
944 inputs.dir cloverClassesDir
946 classpath = sourceSets.clover.runtimeClasspath
947 main = "com.atlassian.clover.reporters.console.ConsoleReporter"
949 if (cloverreport_mem.length() > 0) {
950 maxHeapSize = cloverreport_mem
952 if (cloverreport_jvmargs.length() > 0) {
953 jvmArgs Arrays.asList(cloverreport_jvmargs.split(" "))
963 args argsList.toArray()
967 task cloverHtmlReport(type: JavaExec) {
968 group = "Verification"
969 description = "Creates clover HTML report"
972 file(cloverDb).exists()
975 def cloverHtmlDir = cloverReportDir
976 inputs.dir cloverClassesDir
977 outputs.dir cloverHtmlDir
979 classpath = sourceSets.clover.runtimeClasspath
980 main = "com.atlassian.clover.reporters.html.HtmlReporter"
982 if (cloverreport_mem.length() > 0) {
983 maxHeapSize = cloverreport_mem
985 if (cloverreport_jvmargs.length() > 0) {
986 jvmArgs Arrays.asList(cloverreport_jvmargs.split(" "))
997 if (cloverreport_html_options.length() > 0) {
998 argsList += cloverreport_html_options.split(" ")
1001 args argsList.toArray()
1005 task cloverXmlReport(type: JavaExec) {
1006 group = "Verification"
1007 description = "Creates clover XML report"
1010 file(cloverDb).exists()
1013 def cloverXmlFile = "${cloverReportDir}/clover.xml"
1014 inputs.dir cloverClassesDir
1015 outputs.file cloverXmlFile
1017 classpath = sourceSets.clover.runtimeClasspath
1018 main = "com.atlassian.clover.reporters.xml.XMLReporter"
1020 if (cloverreport_mem.length() > 0) {
1021 maxHeapSize = cloverreport_mem
1023 if (cloverreport_jvmargs.length() > 0) {
1024 jvmArgs Arrays.asList(cloverreport_jvmargs.split(" "))
1035 if (cloverreport_xml_options.length() > 0) {
1036 argsList += cloverreport_xml_options.split(" ")
1039 args argsList.toArray()
1044 group = "Verification"
1045 description = "Creates clover reports"
1047 dependsOn cloverXmlReport
1048 dependsOn cloverHtmlReport
1055 sourceCompatibility = compile_source_compatibility
1056 targetCompatibility = compile_target_compatibility
1057 options.compilerArgs += additional_compiler_args
1058 print ("Setting target compatibility to "+targetCompatibility+"\n")
1060 //classpath += configurations.cloverRuntime
1066 // JBP->BS should the print statement in doFirst refer to compile_target_compatibility ?
1067 sourceCompatibility = compile_source_compatibility
1068 targetCompatibility = compile_target_compatibility
1069 options.compilerArgs += additional_compiler_args
1070 options.encoding = "UTF-8"
1072 print ("Setting target compatibility to "+compile_target_compatibility+"\n")
1079 sourceCompatibility = compile_source_compatibility
1080 targetCompatibility = compile_target_compatibility
1081 options.compilerArgs += additional_compiler_args
1083 print ("Setting target compatibility to "+targetCompatibility+"\n")
1090 delete sourceSets.main.java.outputDir
1096 dependsOn cleanClover
1098 delete sourceSets.test.java.outputDir
1103 // format is a string like date.format("dd MMMM yyyy")
1104 def getDate(format) {
1105 return date.format(format)
1109 def convertMdToHtml (FileTree mdFiles, File cssFile) {
1110 MutableDataSet options = new MutableDataSet()
1112 def extensions = new ArrayList<>()
1113 extensions.add(AnchorLinkExtension.create())
1114 extensions.add(AutolinkExtension.create())
1115 extensions.add(StrikethroughExtension.create())
1116 extensions.add(TaskListExtension.create())
1117 extensions.add(TablesExtension.create())
1118 extensions.add(TocExtension.create())
1120 options.set(Parser.EXTENSIONS, extensions)
1122 // set GFM table parsing options
1123 options.set(TablesExtension.WITH_CAPTION, false)
1124 options.set(TablesExtension.COLUMN_SPANS, false)
1125 options.set(TablesExtension.MIN_HEADER_ROWS, 1)
1126 options.set(TablesExtension.MAX_HEADER_ROWS, 1)
1127 options.set(TablesExtension.APPEND_MISSING_COLUMNS, true)
1128 options.set(TablesExtension.DISCARD_EXTRA_COLUMNS, true)
1129 options.set(TablesExtension.HEADER_SEPARATOR_COLUMN_MATCH, true)
1131 options.set(AnchorLinkExtension.ANCHORLINKS_SET_ID, false)
1132 options.set(AnchorLinkExtension.ANCHORLINKS_ANCHOR_CLASS, "anchor")
1133 options.set(AnchorLinkExtension.ANCHORLINKS_SET_NAME, true)
1134 options.set(AnchorLinkExtension.ANCHORLINKS_TEXT_PREFIX, "<span class=\"octicon octicon-link\"></span>")
1136 Parser parser = Parser.builder(options).build()
1137 HtmlRenderer renderer = HtmlRenderer.builder(options).build()
1139 mdFiles.each { mdFile ->
1140 // add table of contents
1141 def mdText = "[TOC]\n"+mdFile.text
1143 // grab the first top-level title
1145 def titleRegex = /(?m)^#(\s+|([^#]))(.*)/
1146 def matcher = mdText =~ titleRegex
1147 if (matcher.size() > 0) {
1148 // matcher[0][2] is the first character of the title if there wasn't any whitespace after the #
1149 title = (matcher[0][2] != null ? matcher[0][2] : "")+matcher[0][3]
1151 // or use the filename if none found
1152 if (title == null) {
1153 title = mdFile.getName()
1156 Node document = parser.parse(mdText)
1157 String htmlBody = renderer.render(document)
1158 def htmlText = '''<html>
1159 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
1160 <html xmlns="http://www.w3.org/1999/xhtml">
1162 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
1163 <meta http-equiv="Content-Style-Type" content="text/css" />
1164 <meta name="generator" content="flexmark" />
1166 htmlText += ((title != null) ? " <title>${title}</title>" : '' )
1168 <style type="text/css">code{white-space: pre;}</style>
1170 htmlText += ((cssFile != null) ? cssFile.text : '')
1171 htmlText += '''</head>
1174 htmlText += htmlBody
1180 def htmlFilePath = mdFile.getPath().replaceAll(/\..*?$/, ".html")
1181 def htmlFile = file(htmlFilePath)
1182 println("Creating ${htmlFilePath}")
1183 htmlFile.text = htmlText
1188 task copyDocs(type: Copy) {
1189 def inputDir = "${jalviewDir}/${doc_dir}"
1190 def outputDir = "${docBuildDir}/${doc_dir}"
1194 include('**/*.html')
1196 filter(ReplaceTokens,
1200 'Version-Rel': JALVIEW_VERSION,
1201 'Year-Rel': getDate("yyyy")
1208 exclude('**/*.html')
1213 inputs.dir(inputDir)
1214 outputs.dir(outputDir)
1218 task convertMdFiles {
1220 def mdFiles = fileTree(dir: docBuildDir, include: "**/*.md")
1221 def cssFile = file("${jalviewDir}/${flexmark_css}")
1224 convertMdToHtml(mdFiles, cssFile)
1227 inputs.files(mdFiles)
1228 inputs.file(cssFile)
1231 mdFiles.each { mdFile ->
1232 def htmlFilePath = mdFile.getPath().replaceAll(/\..*?$/, ".html")
1233 htmlFiles.add(file(htmlFilePath))
1235 outputs.files(htmlFiles)
1239 def hugoTemplateSubstitutions(String input, Map extras=null) {
1240 def replacements = [
1241 DATE: getDate("yyyy-MM-dd"),
1242 CHANNEL: propertiesChannelName,
1243 APPLICATION_NAME: applicationName,
1245 GIT_BRANCH: gitBranch,
1246 VERSION: JALVIEW_VERSION,
1247 JAVA_VERSION: JAVA_VERSION,
1248 VERSION_UNDERSCORES: JALVIEW_VERSION_UNDERSCORES,
1253 if (extras != null) {
1254 extras.each{ k, v ->
1255 output = output.replaceAll("__${k}__", ((v == null)?"":v))
1258 replacements.each{ k, v ->
1259 output = output.replaceAll("__${k}__", ((v == null)?"":v))
1264 def mdFileComponents(File mdFile, def dateOnly=false) {
1267 if (mdFile.exists()) {
1268 def inFrontMatter = false
1269 def firstLine = true
1270 mdFile.eachLine { line ->
1271 if (line.matches("---")) {
1272 def prev = inFrontMatter
1273 inFrontMatter = firstLine
1274 if (inFrontMatter != prev)
1277 if (inFrontMatter) {
1279 if (m = line =~ /^date:\s*(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})/) {
1280 map["date"] = new Date().parse("yyyy-MM-dd HH:mm:ss", m[0][1])
1281 } else if (m = line =~ /^date:\s*(\d{4}-\d{2}-\d{2})/) {
1282 map["date"] = new Date().parse("yyyy-MM-dd", m[0][1])
1283 } else if (m = line =~ /^channel:\s*(\S+)/) {
1284 map["channel"] = m[0][1]
1285 } else if (m = line =~ /^version:\s*(\S+)/) {
1286 map["version"] = m[0][1]
1287 } else if (m = line =~ /^\s*([^:]+)\s*:\s*(\S.*)/) {
1288 map[ m[0][1] ] = m[0][2]
1290 if (dateOnly && map["date"] != null) {
1296 content += line+"\n"
1301 return dateOnly ? map["date"] : [map, content]
1304 task hugoTemplates {
1306 description "Create partially populated md pages for hugo website build"
1308 def hugoTemplatesDir = file("${jalviewDir}/${hugo_templates_dir}")
1309 def hugoBuildDir = "${jalviewDir}/${hugo_build_dir}"
1310 def templateFiles = fileTree(dir: hugoTemplatesDir)
1311 def releaseMdFile = file("${jalviewDir}/${releases_dir}/release-${JALVIEW_VERSION_UNDERSCORES}.md")
1312 def whatsnewMdFile = file("${jalviewDir}/${whatsnew_dir}/whatsnew-${JALVIEW_VERSION_UNDERSCORES}.md")
1313 def oldJvlFile = file("${jalviewDir}/${hugo_old_jvl}")
1314 def jalviewjsFile = file("${jalviewDir}/${hugo_jalviewjs}")
1317 // specific release template for version archive
1320 def givenDate = null
1321 def givenChannel = null
1322 def givenVersion = null
1323 if (CHANNEL == "RELEASE") {
1324 def (map, content) = mdFileComponents(releaseMdFile)
1325 givenDate = map.date
1326 givenChannel = map.channel
1327 givenVersion = map.version
1329 if (givenVersion != null && givenVersion != JALVIEW_VERSION) {
1330 throw new GradleException("'version' header (${givenVersion}) found in ${releaseMdFile} does not match JALVIEW_VERSION (${JALVIEW_VERSION})")
1333 if (whatsnewMdFile.exists())
1334 whatsnew = whatsnewMdFile.text
1337 def oldJvl = oldJvlFile.exists() ? oldJvlFile.collect{it} : []
1338 def jalviewjsLink = jalviewjsFile.exists() ? jalviewjsFile.collect{it} : []
1340 def changesHugo = null
1341 if (changes != null) {
1342 changesHugo = '<div class="release_notes">\n\n'
1343 def inSection = false
1344 changes.eachLine { line ->
1346 if (m = line =~ /^##([^#].*)$/) {
1348 changesHugo += "</div>\n\n"
1350 def section = m[0][1].trim()
1351 section = section.toLowerCase()
1352 section = section.replaceAll(/ +/, "_")
1353 section = section.replaceAll(/[^a-z0-9_\-]/, "")
1354 changesHugo += "<div class=\"${section}\">\n\n"
1356 } else if (m = line =~ /^(\s*-\s*)<!--([^>]+)-->(.*?)(<br\/?>)?\s*$/) {
1357 def comment = m[0][2].trim()
1358 if (comment != "") {
1359 comment = comment.replaceAll('"', """)
1361 comment.eachMatch(/JAL-\d+/) { jal -> issuekeys += jal }
1362 def newline = m[0][1]
1363 if (comment.trim() != "")
1364 newline += "{{<comment>}}${comment}{{</comment>}} "
1365 newline += m[0][3].trim()
1366 if (issuekeys.size() > 0)
1367 newline += " {{< jal issue=\"${issuekeys.join(",")}\" alt=\"${comment}\" >}}"
1368 if (m[0][4] != null)
1373 changesHugo += line+"\n"
1376 changesHugo += "\n</div>\n\n"
1378 changesHugo += '</div>'
1381 templateFiles.each{ templateFile ->
1382 def newFileName = string(hugoTemplateSubstitutions(templateFile.getName()))
1383 def relPath = hugoTemplatesDir.toPath().relativize(templateFile.toPath()).getParent()
1384 def newRelPathName = hugoTemplateSubstitutions( relPath.toString() )
1386 def outPathName = string("${hugoBuildDir}/$newRelPathName")
1390 rename(templateFile.getName(), newFileName)
1394 def newFile = file("${outPathName}/${newFileName}".toString())
1395 def content = newFile.text
1396 newFile.text = hugoTemplateSubstitutions(content,
1399 CHANGES: changesHugo,
1400 DATE: givenDate == null ? "" : givenDate.format("yyyy-MM-dd"),
1401 DRAFT: givenDate == null ? "true" : "false",
1402 JALVIEWJSLINK: jalviewjsLink.contains(JALVIEW_VERSION) ? "true" : "false",
1403 JVL_HEADER: oldJvl.contains(JALVIEW_VERSION) ? "jvl: true" : ""
1410 inputs.file(oldJvlFile)
1411 inputs.dir(hugoTemplatesDir)
1412 inputs.property("JALVIEW_VERSION", { JALVIEW_VERSION })
1413 inputs.property("CHANNEL", { CHANNEL })
1416 def getMdDate(File mdFile) {
1417 return mdFileComponents(mdFile, true)
1420 def getMdSections(String content) {
1422 def sectionContent = ""
1423 def sectionName = null
1424 content.eachLine { line ->
1426 if (m = line =~ /^##([^#].*)$/) {
1427 if (sectionName != null) {
1428 sections[sectionName] = sectionContent
1432 sectionName = m[0][1].trim()
1433 sectionName = sectionName.toLowerCase()
1434 sectionName = sectionName.replaceAll(/ +/, "_")
1435 sectionName = sectionName.replaceAll(/[^a-z0-9_\-]/, "")
1436 } else if (sectionName != null) {
1437 sectionContent += line+"\n"
1440 if (sectionContent != null) {
1441 sections[sectionName] = sectionContent
1447 task copyHelp(type: Copy) {
1448 def inputDir = helpSourceDir
1449 def outputDir = "${helpBuildDir}/${help_dir}"
1453 include('**/*.html')
1457 filter(ReplaceTokens,
1461 'Version-Rel': JALVIEW_VERSION,
1462 'Year-Rel': getDate("yyyy")
1469 exclude('**/*.html')
1476 inputs.dir(inputDir)
1477 outputs.files(helpFile)
1478 outputs.dir(outputDir)
1482 task releasesTemplates {
1484 description "Recreate whatsNew.html and releases.html from markdown files and templates in help"
1488 def releasesTemplateFile = file("${jalviewDir}/${releases_template}")
1489 def whatsnewTemplateFile = file("${jalviewDir}/${whatsnew_template}")
1490 def releasesHtmlFile = file("${helpBuildDir}/${help_dir}/${releases_html}")
1491 def whatsnewHtmlFile = file("${helpBuildDir}/${help_dir}/${whatsnew_html}")
1492 def releasesMdDir = "${jalviewDir}/${releases_dir}"
1493 def whatsnewMdDir = "${jalviewDir}/${whatsnew_dir}"
1496 def releaseMdFile = file("${releasesMdDir}/release-${JALVIEW_VERSION_UNDERSCORES}.md")
1497 def whatsnewMdFile = file("${whatsnewMdDir}/whatsnew-${JALVIEW_VERSION_UNDERSCORES}.md")
1499 if (CHANNEL == "RELEASE") {
1500 if (!releaseMdFile.exists()) {
1501 throw new GradleException("File ${releaseMdFile} must be created for RELEASE")
1503 if (!whatsnewMdFile.exists()) {
1504 throw new GradleException("File ${whatsnewMdFile} must be created for RELEASE")
1508 def releaseFiles = fileTree(dir: releasesMdDir, include: "release-*.md")
1509 def releaseFilesDates = releaseFiles.collectEntries {
1510 [(it): getMdDate(it)]
1512 releaseFiles = releaseFiles.sort { a,b -> releaseFilesDates[a].compareTo(releaseFilesDates[b]) }
1514 def releasesTemplate = releasesTemplateFile.text
1515 def m = releasesTemplate =~ /(?s)__VERSION_LOOP_START__(.*)__VERSION_LOOP_END__/
1516 def versionTemplate = m[0][1]
1518 MutableDataSet options = new MutableDataSet()
1520 def extensions = new ArrayList<>()
1521 options.set(Parser.EXTENSIONS, extensions)
1522 options.set(Parser.HTML_BLOCK_COMMENT_ONLY_FULL_LINE, true)
1524 Parser parser = Parser.builder(options).build()
1525 HtmlRenderer renderer = HtmlRenderer.builder(options).build()
1527 def actualVersions = releaseFiles.collect { rf ->
1528 def (rfMap, rfContent) = mdFileComponents(rf)
1529 return rfMap.version
1531 def versionsHtml = ""
1532 def linkedVersions = []
1533 releaseFiles.reverse().each { rFile ->
1534 def (rMap, rContent) = mdFileComponents(rFile)
1536 def versionLink = ""
1537 def partialVersion = ""
1538 def firstPart = true
1539 rMap.version.split("\\.").each { part ->
1540 def displayPart = ( firstPart ? "" : "." ) + part
1541 partialVersion += displayPart
1543 linkedVersions.contains(partialVersion)
1544 || ( actualVersions.contains(partialVersion) && partialVersion != rMap.version )
1546 versionLink += displayPart
1548 versionLink += "<a id=\"Jalview.${partialVersion}\">${displayPart}</a>"
1549 linkedVersions += partialVersion
1553 def displayDate = releaseFilesDates[rFile].format("dd/MM/yyyy")
1556 def rContentProcessed = ""
1557 rContent.eachLine { line ->
1558 if (lm = line =~ /^(\s*-)(\s*<!--[^>]*?-->)(.*)$/) {
1559 line = "${lm[0][1]}${lm[0][3]}${lm[0][2]}"
1560 } else if (lm = line =~ /^###([^#]+.*)$/) {
1561 line = "_${lm[0][1].trim()}_"
1563 rContentProcessed += line + "\n"
1566 def rContentSections = getMdSections(rContentProcessed)
1567 def rVersion = versionTemplate
1568 if (rVersion != "") {
1569 def rNewFeatures = rContentSections["new_features"]
1570 def rIssuesResolved = rContentSections["issues_resolved"]
1571 Node newFeaturesNode = parser.parse(rNewFeatures)
1572 String newFeaturesHtml = renderer.render(newFeaturesNode)
1573 Node issuesResolvedNode = parser.parse(rIssuesResolved)
1574 String issuesResolvedHtml = renderer.render(issuesResolvedNode)
1575 rVersion = hugoTemplateSubstitutions(rVersion,
1577 VERSION: rMap.version,
1578 VERSION_LINK: versionLink,
1579 DISPLAY_DATE: displayDate,
1580 NEW_FEATURES: newFeaturesHtml,
1581 ISSUES_RESOLVED: issuesResolvedHtml
1584 versionsHtml += rVersion
1588 releasesTemplate = releasesTemplate.replaceAll("(?s)__VERSION_LOOP_START__.*__VERSION_LOOP_END__", versionsHtml)
1589 releasesTemplate = hugoTemplateSubstitutions(releasesTemplate)
1590 releasesHtmlFile.text = releasesTemplate
1592 if (whatsnewMdFile.exists()) {
1593 def wnDisplayDate = releaseFilesDates[releaseMdFile] != null ? releaseFilesDates[releaseMdFile].format("dd MMMM yyyy") : ""
1594 def whatsnewMd = hugoTemplateSubstitutions(whatsnewMdFile.text)
1595 Node whatsnewNode = parser.parse(whatsnewMd)
1596 String whatsnewHtml = renderer.render(whatsnewNode)
1597 whatsnewHtml = whatsnewTemplateFile.text.replaceAll("__WHATS_NEW__", whatsnewHtml)
1598 whatsnewHtmlFile.text = hugoTemplateSubstitutions(whatsnewHtml,
1600 VERSION: JALVIEW_VERSION,
1601 DISPLAY_DATE: wnDisplayDate
1604 } else if (gradle.taskGraph.hasTask(":linkCheck")) {
1605 whatsnewHtmlFile.text = "Development build " + getDate("yyyy-MM-dd HH:mm:ss")
1610 inputs.file(releasesTemplateFile)
1611 inputs.file(whatsnewTemplateFile)
1612 inputs.dir(releasesMdDir)
1613 inputs.dir(whatsnewMdDir)
1614 outputs.file(releasesHtmlFile)
1615 outputs.file(whatsnewHtmlFile)
1619 task copyResources(type: Copy) {
1621 description = "Copy (and make text substitutions in) the resources dir to the build area"
1623 def inputDir = resourceDir
1624 def outputDir = resourcesBuildDir
1628 include('**/*.html')
1630 filter(ReplaceTokens,
1634 'Version-Rel': JALVIEW_VERSION,
1635 'Year-Rel': getDate("yyyy")
1642 exclude('**/*.html')
1647 inputs.dir(inputDir)
1648 outputs.dir(outputDir)
1651 task copyChannelResources(type: Copy) {
1652 dependsOn copyResources
1654 description = "Copy the channel resources dir to the build resources area"
1656 def inputDir = "${channelDir}/${resource_dir}"
1657 def outputDir = resourcesBuildDir
1659 include(channel_props)
1660 filter(ReplaceTokens,
1664 'SUFFIX': channelSuffix
1669 exclude(channel_props)
1673 inputs.dir(inputDir)
1674 outputs.dir(outputDir)
1677 task createBuildProperties(type: WriteProperties) {
1678 dependsOn copyResources
1680 description = "Create the ${buildProperties} file"
1682 inputs.dir(sourceDir)
1683 inputs.dir(resourcesBuildDir)
1684 outputFile (buildProperties)
1685 // taking time specific comment out to allow better incremental builds
1686 comment "--Jalview Build Details--\n"+getDate("yyyy-MM-dd HH:mm:ss")
1687 //comment "--Jalview Build Details--\n"+getDate("yyyy-MM-dd")
1688 property "BUILD_DATE", getDate("HH:mm:ss dd MMMM yyyy")
1689 property "VERSION", JALVIEW_VERSION
1690 property "INSTALLATION", INSTALLATION+" git-commit:"+gitHash+" ["+gitBranch+"]"
1691 property "JAVA_COMPILE_VERSION", JAVA_INTEGER_VERSION
1692 if (getdownSetAppBaseProperty) {
1693 property "GETDOWNAPPBASE", getdownAppBase
1694 property "GETDOWNAPPDISTDIR", getdownAppDistDir
1696 outputs.file(outputFile)
1700 task buildIndices(type: JavaExec) {
1702 classpath = sourceSets.main.compileClasspath
1703 main = "com.sun.java.help.search.Indexer"
1704 workingDir = "${helpBuildDir}/${help_dir}"
1707 inputs.dir("${workingDir}/${argDir}")
1709 outputs.dir("${classesDir}/doc")
1710 outputs.dir("${classesDir}/help")
1711 outputs.file("${workingDir}/JavaHelpSearch/DOCS")
1712 outputs.file("${workingDir}/JavaHelpSearch/DOCS.TAB")
1713 outputs.file("${workingDir}/JavaHelpSearch/OFFSETS")
1714 outputs.file("${workingDir}/JavaHelpSearch/POSITIONS")
1715 outputs.file("${workingDir}/JavaHelpSearch/SCHEMA")
1716 outputs.file("${workingDir}/JavaHelpSearch/TMAP")
1719 task buildResources {
1720 dependsOn copyResources
1721 dependsOn copyChannelResources
1722 dependsOn createBuildProperties
1726 dependsOn buildResources
1729 dependsOn releasesTemplates
1730 dependsOn convertMdFiles
1731 dependsOn buildIndices
1735 compileJava.dependsOn prepare
1736 run.dependsOn compileJava
1737 compileTestJava.dependsOn compileJava
1742 group = "Verification"
1743 description = "Runs all testTaskN tasks)"
1746 dependsOn cloverClasses
1748 dependsOn testClasses
1751 // not running tests in this task
1754 /* testTask0 is the main test task */
1755 task testTask0(type: Test) {
1756 group = "Verification"
1757 description = "The main test task. Runs all non-testTaskN-labelled tests (unless excluded)"
1759 includeGroups testng_groups.split(",")
1760 excludeGroups testng_excluded_groups.split(",")
1761 tasks.withType(Test).matching {it.name.startsWith("testTask") && it.name != name}.all {t -> excludeGroups t.name}
1763 useDefaultListeners=true
1767 /* separated tests */
1768 task testTask1(type: Test) {
1769 group = "Verification"
1770 description = "Tests that need to be isolated from the main test run"
1773 excludeGroups testng_excluded_groups.split(",")
1775 useDefaultListeners=true
1779 /* insert more testTaskNs here -- change N to next digit or other string */
1781 task testTaskN(type: Test) {
1782 group = "Verification"
1783 description = "Tests that need to be isolated from the main test run"
1786 excludeGroups testng_excluded_groups.split(",")
1788 useDefaultListeners=true
1794 * adapted from https://medium.com/@wasyl/pretty-tests-summary-in-gradle-744804dd676c
1795 * to summarise test results from all Test tasks
1797 /* START of test tasks results summary */
1798 import groovy.time.TimeCategory
1799 import org.gradle.api.tasks.testing.logging.TestExceptionFormat
1800 import org.gradle.api.tasks.testing.logging.TestLogEvent
1801 rootProject.ext.testsResults = [] // Container for tests summaries
1803 tasks.withType(Test).matching {t -> t.getName().startsWith("testTask")}.all { testTask ->
1805 // from original test task
1807 dependsOn cloverClasses
1809 dependsOn testClasses //?
1812 // run main tests first
1813 if (!testTask.name.equals("testTask0"))
1814 testTask.mustRunAfter "testTask0"
1816 testTask.testLogging { logging ->
1817 events TestLogEvent.FAILED
1818 // TestLogEvent.SKIPPED,
1819 // TestLogEvent.STANDARD_OUT,
1820 // TestLogEvent.STANDARD_ERROR
1822 exceptionFormat TestExceptionFormat.FULL
1825 showStackTraces true
1827 info.events = [ TestLogEvent.FAILED ]
1832 ignoreFailures = true // Always try to run all tests for all modules
1834 afterSuite { desc, result ->
1836 return // Only summarize results for whole modules
1838 def resultsInfo = [testTask.project.name, testTask.name, result, TimeCategory.minus(new Date(result.endTime), new Date(result.startTime)), testTask.reports.html.entryPoint]
1840 rootProject.ext.testsResults.add(resultsInfo)
1843 // from original test task
1844 maxHeapSize = "1024m"
1846 workingDir = jalviewDir
1847 def testLaf = project.findProperty("test_laf")
1848 if (testLaf != null) {
1849 println("Setting Test LaF to '${testLaf}'")
1850 systemProperty "laf", testLaf
1852 def testHiDPIScale = project.findProperty("test_HiDPIScale")
1853 if (testHiDPIScale != null) {
1854 println("Setting Test HiDPI Scale to '${testHiDPIScale}'")
1855 systemProperty "sun.java2d.uiScale", testHiDPIScale
1857 sourceCompatibility = compile_source_compatibility
1858 targetCompatibility = compile_target_compatibility
1859 jvmArgs += additional_compiler_args
1862 // this is not perfect yet -- we should only add the commandLineIncludePatterns to the
1863 // testTasks that include the tests, and exclude all from the others.
1864 // get --test argument
1865 filter.commandLineIncludePatterns = test.filter.commandLineIncludePatterns
1866 // do something with testTask.getCandidateClassFiles() to see if the test should silently finish because of the
1867 // commandLineIncludePatterns not matching anything. Instead we are doing setFailOnNoMatchingTests(false) below
1871 println("Running tests " + (useClover?"WITH":"WITHOUT") + " clover")
1876 /* don't fail on no matching tests (so --tests will run across all testTasks) */
1877 testTask.filter.setFailOnNoMatchingTests(false)
1879 /* ensure the "test" task dependsOn all the testTasks */
1880 test.dependsOn testTask
1883 gradle.buildFinished {
1884 def allResults = rootProject.ext.testsResults
1886 if (!allResults.isEmpty()) {
1887 printResults allResults
1888 allResults.each {r ->
1889 if (r[2].resultType == TestResult.ResultType.FAILURE)
1890 throw new GradleException("Failed tests!")
1895 private static String colString(styler, col, colour, text) {
1896 return col?"${styler[colour](text)}":text
1899 private static String getSummaryLine(s, pn, tn, rt, rc, rs, rf, rsk, t, col) {
1900 def colour = 'black'
1908 case TestResult.ResultType.SUCCESS:
1911 case TestResult.ResultType.FAILURE:
1919 StringBuilder sb = new StringBuilder()
1923 sb.append(" results: ")
1924 sb.append(colString(s, col && !nocol, colour, text))
1926 sb.append("${rc} tests, ")
1927 sb.append(colString(s, col && rs > 0, 'green', rs))
1928 sb.append(" successes, ")
1929 sb.append(colString(s, col && rf > 0, 'red', rf))
1930 sb.append(" failures, ")
1931 sb.append("${rsk} skipped) in ${t}")
1932 return sb.toString()
1935 private static void printResults(allResults) {
1937 // styler from https://stackoverflow.com/a/56139852
1938 def styler = 'black red green yellow blue magenta cyan white'.split().toList().withIndex(30).collectEntries { key, val -> [(key) : { "\033[${val}m${it}\033[0m" }] }
1941 def failedTests = false
1942 def summaryLines = []
1944 def totalsuccess = 0
1947 def totaltime = TimeCategory.getSeconds(0)
1948 // sort on project name then task name
1949 allResults.sort {a, b -> a[0] == b[0]? a[1]<=>b[1]:a[0] <=> b[0]}.each {
1950 def projectName = it[0]
1951 def taskName = it[1]
1955 def summaryCol = getSummaryLine(styler, projectName, taskName, result.resultType, result.testCount, result.successfulTestCount, result.failedTestCount, result.skippedTestCount, time, true)
1956 def summaryPlain = getSummaryLine(styler, projectName, taskName, result.resultType, result.testCount, result.successfulTestCount, result.failedTestCount, result.skippedTestCount, time, false)
1957 def reportLine = "Report file: ${report}"
1958 def ls = summaryPlain.length()
1959 def lr = reportLine.length()
1960 def m = [ls, lr].max()
1963 def info = [ls, summaryCol, reportLine]
1964 summaryLines.add(info)
1965 failedTests |= result.resultType == TestResult.ResultType.FAILURE
1966 totalcount += result.testCount
1967 totalsuccess += result.successfulTestCount
1968 totalfail += result.failedTestCount
1969 totalskip += result.skippedTestCount
1972 def totalSummaryCol = getSummaryLine(styler, "OVERALL", "", failedTests?TestResult.ResultType.FAILURE:TestResult.ResultType.SUCCESS, totalcount, totalsuccess, totalfail, totalskip, totaltime, true)
1973 def totalSummaryPlain = getSummaryLine(styler, "OVERALL", "", failedTests?TestResult.ResultType.FAILURE:TestResult.ResultType.SUCCESS, totalcount, totalsuccess, totalfail, totalskip, totaltime, false)
1974 def tls = totalSummaryPlain.length()
1975 if (tls > maxLength)
1977 def info = [tls, totalSummaryCol, null]
1978 summaryLines.add(info)
1980 def allSummaries = []
1981 for(sInfo : summaryLines) {
1983 def summary = sInfo[1]
1984 def report = sInfo[2]
1986 StringBuilder sb = new StringBuilder()
1987 sb.append("│" + summary + " " * (maxLength - ls) + "│")
1988 if (report != null) {
1989 sb.append("\n│" + report + " " * (maxLength - report.length()) + "│")
1991 allSummaries += sb.toString()
1994 println "┌${"${"─" * maxLength}"}┐"
1995 println allSummaries.join("\n├${"${"─" * maxLength}"}┤\n")
1996 println "└${"${"─" * maxLength}"}┘"
1998 /* END of test tasks results summary */
2001 task compileLinkCheck(type: JavaCompile) {
2003 classpath = files("${jalviewDir}/${utils_dir}")
2004 destinationDir = file("${jalviewDir}/${utils_dir}")
2005 source = fileTree(dir: "${jalviewDir}/${utils_dir}", include: ["HelpLinksChecker.java", "BufferedLineReader.java"])
2007 inputs.file("${jalviewDir}/${utils_dir}/HelpLinksChecker.java")
2008 inputs.file("${jalviewDir}/${utils_dir}/HelpLinksChecker.java")
2009 outputs.file("${jalviewDir}/${utils_dir}/HelpLinksChecker.class")
2010 outputs.file("${jalviewDir}/${utils_dir}/BufferedLineReader.class")
2014 task linkCheck(type: JavaExec) {
2016 dependsOn compileLinkCheck
2018 def helpLinksCheckerOutFile = file("${jalviewDir}/${utils_dir}/HelpLinksChecker.out")
2019 classpath = files("${jalviewDir}/${utils_dir}")
2020 main = "HelpLinksChecker"
2021 workingDir = "${helpBuildDir}"
2022 args = [ "${helpBuildDir}/${help_dir}", "-nointernet" ]
2024 def outFOS = new FileOutputStream(helpLinksCheckerOutFile, false) // false == don't append
2025 standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
2028 errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
2032 inputs.dir(helpBuildDir)
2033 outputs.file(helpLinksCheckerOutFile)
2037 // import the pubhtmlhelp target
2038 ant.properties.basedir = "${jalviewDir}"
2039 ant.properties.helpBuildDir = "${helpBuildDir}/${help_dir}"
2040 ant.importBuild "${utils_dir}/publishHelp.xml"
2043 task cleanPackageDir(type: Delete) {
2045 delete fileTree(dir: "${jalviewDir}/${package_dir}", include: "*.jar")
2055 attributes "Main-Class": main_class,
2056 "Permissions": "all-permissions",
2057 "Application-Name": applicationName,
2058 "Codebase": application_codebase,
2059 "Implementation-Version": JALVIEW_VERSION
2062 def outputDir = "${jalviewDir}/${package_dir}"
2063 destinationDirectory = file(outputDir)
2064 archiveFileName = rootProject.name+".jar"
2065 duplicatesStrategy "EXCLUDE"
2072 exclude "**/*.jar.*"
2074 inputs.dir(sourceSets.main.java.outputDir)
2075 sourceSets.main.resources.srcDirs.each{ dir ->
2078 outputs.file("${outputDir}/${archiveFileName}")
2082 task copyJars(type: Copy) {
2083 from fileTree(dir: classesDir, include: "**/*.jar").files
2084 into "${jalviewDir}/${package_dir}"
2088 // doing a Sync instead of Copy as Copy doesn't deal with "outputs" very well
2089 task syncJars(type: Sync) {
2091 from fileTree(dir: "${jalviewDir}/${libDistDir}", include: "**/*.jar").files
2092 into "${jalviewDir}/${package_dir}"
2094 include jar.archiveFileName.getOrNull()
2101 description = "Put all required libraries in dist"
2102 // order of "cleanPackageDir", "copyJars", "jar" important!
2103 jar.mustRunAfter cleanPackageDir
2104 syncJars.mustRunAfter cleanPackageDir
2105 dependsOn cleanPackageDir
2108 outputs.dir("${jalviewDir}/${package_dir}")
2113 dependsOn cleanPackageDir
2120 group = "distribution"
2121 description = "Create a single jar file with all dependency libraries merged. Can be run with java -jar"
2125 from ("${jalviewDir}/${libDistDir}") {
2129 attributes "Implementation-Version": JALVIEW_VERSION,
2130 "Application-Name": applicationName
2133 duplicatesStrategy "INCLUDE"
2135 mainClassName = shadow_jar_main_class
2137 classifier = "all-"+JALVIEW_VERSION+"-j"+JAVA_VERSION
2141 task getdownImagesCopy() {
2142 inputs.dir getdownImagesDir
2143 outputs.dir getdownImagesBuildDir
2147 from(getdownImagesDir) {
2148 include("*getdown*.png")
2150 into getdownImagesBuildDir
2155 task getdownImagesProcess() {
2156 dependsOn getdownImagesCopy
2159 if (backgroundImageText) {
2160 if (convertBinary == null) {
2161 throw new StopExecutionException("No ImageMagick convert binary installed at '${convertBinaryExpectedLocation}'")
2163 if (!project.hasProperty("getdown_background_image_text_suffix_cmd")) {
2164 throw new StopExecutionException("No property 'getdown_background_image_text_suffix_cmd' defined. See channel_gradle.properties for channel ${CHANNEL}")
2166 fileTree(dir: getdownImagesBuildDir, include: "*background*.png").getFiles().each { file ->
2168 executable convertBinary
2171 '-font', getdown_background_image_text_font,
2172 '-fill', getdown_background_image_text_colour,
2173 '-draw', sprintf(getdown_background_image_text_suffix_cmd, channelSuffix),
2174 '-draw', sprintf(getdown_background_image_text_commit_cmd, "git-commit: ${gitHash}"),
2175 '-draw', sprintf(getdown_background_image_text_date_cmd, getDate("yyyy-MM-dd HH:mm:ss")),
2184 task getdownImages() {
2185 dependsOn getdownImagesProcess
2188 task getdownWebsite() {
2189 group = "distribution"
2190 description = "Create the getdown minimal app folder, and website folder for this version of jalview. Website folder also used for offline app installer"
2192 dependsOn getdownImages
2197 def getdownWebsiteResourceFilenames = []
2198 def getdownResourceDir = getdownResourceDir
2199 def getdownResourceFilenames = []
2202 // clean the getdown website and files dir before creating getdown folders
2203 delete getdownAppBaseDir
2204 delete getdownFilesDir
2207 from buildProperties
2208 rename(file(buildProperties).getName(), getdown_build_properties)
2211 getdownWebsiteResourceFilenames += "${getdownAppDistDir}/${getdown_build_properties}"
2214 from channelPropsFile
2215 filter(ReplaceTokens,
2219 'SUFFIX': channelSuffix
2222 into getdownAppBaseDir
2224 getdownWebsiteResourceFilenames += file(channelPropsFile).getName()
2226 // set some getdownTxt_ properties then go through all properties looking for getdownTxt_...
2227 def props = project.properties.sort { it.key }
2228 if (getdownAltJavaMinVersion != null && getdownAltJavaMinVersion.length() > 0) {
2229 props.put("getdown_txt_java_min_version", getdownAltJavaMinVersion)
2231 if (getdownAltJavaMaxVersion != null && getdownAltJavaMaxVersion.length() > 0) {
2232 props.put("getdown_txt_java_max_version", getdownAltJavaMaxVersion)
2234 if (getdownAltMultiJavaLocation != null && getdownAltMultiJavaLocation.length() > 0) {
2235 props.put("getdown_txt_multi_java_location", getdownAltMultiJavaLocation)
2237 if (getdownImagesBuildDir != null && file(getdownImagesBuildDir).exists()) {
2238 props.put("getdown_txt_ui.background_image", "${getdownImagesBuildDir}/${getdown_background_image}")
2239 props.put("getdown_txt_ui.instant_background_image", "${getdownImagesBuildDir}/${getdown_instant_background_image}")
2240 props.put("getdown_txt_ui.error_background", "${getdownImagesBuildDir}/${getdown_error_background}")
2241 props.put("getdown_txt_ui.progress_image", "${getdownImagesBuildDir}/${getdown_progress_image}")
2242 props.put("getdown_txt_ui.icon", "${getdownImagesDir}/${getdown_icon}")
2243 props.put("getdown_txt_ui.mac_dock_icon", "${getdownImagesDir}/${getdown_mac_dock_icon}")
2246 props.put("getdown_txt_title", jalview_name)
2247 props.put("getdown_txt_ui.name", applicationName)
2249 // start with appbase
2250 getdownTextLines += "appbase = ${getdownAppBase}"
2251 props.each{ prop, val ->
2252 if (prop.startsWith("getdown_txt_") && val != null) {
2253 if (prop.startsWith("getdown_txt_multi_")) {
2254 def key = prop.substring(18)
2255 val.split(",").each{ v ->
2256 def line = "${key} = ${v}"
2257 getdownTextLines += line
2260 // file values rationalised
2261 if (val.indexOf('/') > -1 || prop.startsWith("getdown_txt_resource")) {
2263 if (val.indexOf('/') == 0) {
2266 } else if (val.indexOf('/') > 0) {
2267 // relative path (relative to jalviewDir)
2268 r = file( "${jalviewDir}/${val}" )
2271 val = "${getdown_resource_dir}/" + r.getName()
2272 getdownWebsiteResourceFilenames += val
2273 getdownResourceFilenames += r.getPath()
2276 if (! prop.startsWith("getdown_txt_resource")) {
2277 def line = prop.substring(12) + " = ${val}"
2278 getdownTextLines += line
2284 getdownWebsiteResourceFilenames.each{ filename ->
2285 getdownTextLines += "resource = ${filename}"
2287 getdownResourceFilenames.each{ filename ->
2290 into getdownResourceDir
2294 def getdownWrapperScripts = [ getdown_bash_wrapper_script, getdown_powershell_wrapper_script, getdown_batch_wrapper_script ]
2295 getdownWrapperScripts.each{ script ->
2296 def s = file( "${jalviewDir}/utils/getdown/${getdown_wrapper_script_dir}/${script}" )
2300 into "${getdownAppBaseDir}/${getdown_wrapper_script_dir}"
2302 getdownTextLines += "resource = ${getdown_wrapper_script_dir}/${script}"
2307 fileTree(file(package_dir)).each{ f ->
2308 if (f.isDirectory()) {
2309 def files = fileTree(dir: f, include: ["*"]).getFiles()
2311 } else if (f.exists()) {
2315 def jalviewJar = jar.archiveFileName.getOrNull()
2316 // put jalview.jar first for CLASSPATH and .properties files reasons
2317 codeFiles.sort{a, b -> ( a.getName() == jalviewJar ? -1 : ( b.getName() == jalviewJar ? 1 : a <=> b ) ) }.each{f ->
2318 def name = f.getName()
2319 def line = "code = ${getdownAppDistDir}/${name}"
2320 getdownTextLines += line
2327 // NOT USING MODULES YET, EVERYTHING SHOULD BE IN dist
2329 if (JAVA_VERSION.equals("11")) {
2330 def j11libFiles = fileTree(dir: "${jalviewDir}/${j11libDir}", include: ["*.jar"]).getFiles()
2331 j11libFiles.sort().each{f ->
2332 def name = f.getName()
2333 def line = "code = ${getdown_j11lib_dir}/${name}"
2334 getdownTextLines += line
2337 into getdownJ11libDir
2343 // 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.
2344 //getdownTextLines += "class = " + file(getdownLauncher).getName()
2345 getdownTextLines += "resource = ${getdown_launcher_new}"
2346 getdownTextLines += "class = ${main_class}"
2347 // Not setting these properties in general so that getdownappbase and getdowndistdir will default to release version in jalview.bin.Cache
2348 if (getdownSetAppBaseProperty) {
2349 getdownTextLines += "jvmarg = -Dgetdowndistdir=${getdownAppDistDir}"
2350 getdownTextLines += "jvmarg = -Dgetdownappbase=${getdownAppBase}"
2353 def getdownTxt = file("${getdownAppBaseDir}/getdown.txt")
2354 getdownTxt.write(getdownTextLines.join("\n"))
2356 getdownLaunchJvl = getdown_launch_jvl_name + ( (jvlChannelName != null && jvlChannelName.length() > 0)?"-${jvlChannelName}":"" ) + ".jvl"
2357 def launchJvl = file("${getdownAppBaseDir}/${getdownLaunchJvl}")
2358 launchJvl.write("appbase=${getdownAppBase}")
2360 // files going into the getdown website dir: getdown-launcher.jar
2362 from getdownLauncher
2363 rename(file(getdownLauncher).getName(), getdown_launcher_new)
2364 into getdownAppBaseDir
2367 // files going into the getdown website dir: getdown-launcher(-local).jar
2369 from getdownLauncher
2370 if (file(getdownLauncher).getName() != getdown_launcher) {
2371 rename(file(getdownLauncher).getName(), getdown_launcher)
2373 into getdownAppBaseDir
2376 // files going into the getdown website dir: ./install dir and files
2377 if (! (CHANNEL.startsWith("ARCHIVE") || CHANNEL.startsWith("DEVELOP"))) {
2380 from getdownLauncher
2381 from "${getdownAppDir}/${getdown_build_properties}"
2382 if (file(getdownLauncher).getName() != getdown_launcher) {
2383 rename(file(getdownLauncher).getName(), getdown_launcher)
2385 into getdownInstallDir
2388 // and make a copy in the getdown files dir (these are not downloaded by getdown)
2390 from getdownInstallDir
2391 into getdownFilesInstallDir
2395 // files going into the getdown files dir: getdown.txt, getdown-launcher.jar, channel-launch.jvl, build_properties
2399 from getdownLauncher
2400 from "${getdownAppBaseDir}/${getdown_build_properties}"
2401 from "${getdownAppBaseDir}/${channel_props}"
2402 if (file(getdownLauncher).getName() != getdown_launcher) {
2403 rename(file(getdownLauncher).getName(), getdown_launcher)
2405 into getdownFilesDir
2408 // and ./resource (not all downloaded by getdown)
2410 from getdownResourceDir
2411 into "${getdownFilesDir}/${getdown_resource_dir}"
2416 inputs.dir("${jalviewDir}/${package_dir}")
2418 outputs.dir(getdownAppBaseDir)
2419 outputs.dir(getdownFilesDir)
2423 // a helper task to allow getdown digest of any dir: `gradle getdownDigestDir -PDIGESTDIR=/path/to/my/random/getdown/dir
2424 task getdownDigestDir(type: JavaExec) {
2426 description "A task to run a getdown Digest on a dir with getdown.txt. Provide a DIGESTDIR property via -PDIGESTDIR=..."
2428 def digestDirPropertyName = "DIGESTDIR"
2430 classpath = files(getdownLauncher)
2431 def digestDir = findProperty(digestDirPropertyName)
2432 if (digestDir == null) {
2433 throw new GradleException("Must provide a DIGESTDIR value to produce an alternative getdown digest")
2437 main = "com.threerings.getdown.tools.Digester"
2441 task getdownDigest(type: JavaExec) {
2442 group = "distribution"
2443 description = "Digest the getdown website folder"
2444 dependsOn getdownWebsite
2446 classpath = files(getdownLauncher)
2448 main = "com.threerings.getdown.tools.Digester"
2449 args getdownAppBaseDir
2450 inputs.dir(getdownAppBaseDir)
2451 outputs.file("${getdownAppBaseDir}/digest2.txt")
2456 group = "distribution"
2457 description = "Create the minimal and full getdown app folder for installers and website and create digest file"
2458 dependsOn getdownDigest
2460 if (reportRsyncCommand) {
2461 def fromDir = getdownAppBaseDir + (getdownAppBaseDir.endsWith('/')?'':'/')
2462 def toDir = "${getdown_rsync_dest}/${getdownDir}" + (getdownDir.endsWith('/')?'':'/')
2463 println "LIKELY RSYNC COMMAND:"
2464 println "mkdir -p '$toDir'\nrsync -avh --delete '$fromDir' '$toDir'"
2465 if (RUNRSYNC == "true") {
2467 commandLine "mkdir", "-p", toDir
2470 commandLine "rsync", "-avh", "--delete", fromDir, toDir
2478 task getdownArchiveBuild() {
2479 group = "distribution"
2480 description = "Put files in the archive dir to go on the website"
2482 dependsOn getdownWebsite
2484 def v = "v${JALVIEW_VERSION_UNDERSCORES}"
2485 def vDir = "${getdownArchiveDir}/${v}"
2486 getdownFullArchiveDir = "${vDir}/getdown"
2487 getdownVersionLaunchJvl = "${vDir}/jalview-${v}.jvl"
2489 def vAltDir = "alt_${v}"
2490 def archiveImagesDir = "${jalviewDir}/${channel_properties_dir}/old/images"
2493 // cleanup old "old" dir
2494 delete getdownArchiveDir
2496 def getdownArchiveTxt = file("${getdownFullArchiveDir}/getdown.txt")
2497 getdownArchiveTxt.getParentFile().mkdirs()
2498 def getdownArchiveTextLines = []
2499 def getdownFullArchiveAppBase = "${getdownArchiveAppBase}${getdownArchiveAppBase.endsWith("/")?"":"/"}${v}/getdown/"
2503 from "${getdownAppBaseDir}/${getdownAppDistDir}"
2504 into "${getdownFullArchiveDir}/${vAltDir}"
2507 getdownTextLines.each { line ->
2508 line = line.replaceAll("^(?<s>appbase\\s*=\\s*).*", '${s}'+getdownFullArchiveAppBase)
2509 line = line.replaceAll("^(?<s>(resource|code)\\s*=\\s*)${getdownAppDistDir}/", '${s}'+vAltDir+"/")
2510 line = line.replaceAll("^(?<s>ui.background_image\\s*=\\s*).*\\.png", '${s}'+"${getdown_resource_dir}/jalview_archive_getdown_background.png")
2511 line = line.replaceAll("^(?<s>ui.instant_background_image\\s*=\\s*).*\\.png", '${s}'+"${getdown_resource_dir}/jalview_archive_getdown_background_initialising.png")
2512 line = line.replaceAll("^(?<s>ui.error_background\\s*=\\s*).*\\.png", '${s}'+"${getdown_resource_dir}/jalview_archive_getdown_background_error.png")
2513 line = line.replaceAll("^(?<s>ui.progress_image\\s*=\\s*).*\\.png", '${s}'+"${getdown_resource_dir}/jalview_archive_getdown_progress_bar.png")
2514 // remove the existing resource = resource/ or bin/ lines
2515 if (! line.matches("resource\\s*=\\s*(resource|bin)/.*")) {
2516 getdownArchiveTextLines += line
2520 // the resource dir -- add these files as resource lines in getdown.txt
2522 from "${archiveImagesDir}"
2523 into "${getdownFullArchiveDir}/${getdown_resource_dir}"
2525 getdownArchiveTextLines += "resource = ${getdown_resource_dir}/${file.getName()}"
2529 getdownArchiveTxt.write(getdownArchiveTextLines.join("\n"))
2531 def vLaunchJvl = file(getdownVersionLaunchJvl)
2532 vLaunchJvl.getParentFile().mkdirs()
2533 vLaunchJvl.write("appbase=${getdownFullArchiveAppBase}\n")
2534 def vLaunchJvlPath = vLaunchJvl.toPath().toAbsolutePath()
2535 def jvlLinkPath = file("${vDir}/jalview.jvl").toPath().toAbsolutePath()
2536 // for some reason filepath.relativize(fileInSameDirPath) gives a path to "../" which is wrong
2537 //java.nio.file.Files.createSymbolicLink(jvlLinkPath, jvlLinkPath.relativize(vLaunchJvlPath));
2538 java.nio.file.Files.createSymbolicLink(jvlLinkPath, java.nio.file.Paths.get(".",vLaunchJvl.getName()));
2540 // files going into the getdown files dir: getdown.txt, getdown-launcher.jar, channel-launch.jvl, build_properties
2542 from getdownLauncher
2543 from "${getdownAppBaseDir}/${getdownLaunchJvl}"
2544 from "${getdownAppBaseDir}/${getdown_launcher_new}"
2545 from "${getdownAppBaseDir}/${channel_props}"
2546 if (file(getdownLauncher).getName() != getdown_launcher) {
2547 rename(file(getdownLauncher).getName(), getdown_launcher)
2549 into getdownFullArchiveDir
2555 task getdownArchiveDigest(type: JavaExec) {
2556 group = "distribution"
2557 description = "Digest the getdown archive folder"
2559 dependsOn getdownArchiveBuild
2562 classpath = files(getdownLauncher)
2563 args getdownFullArchiveDir
2565 main = "com.threerings.getdown.tools.Digester"
2566 inputs.dir(getdownFullArchiveDir)
2567 outputs.file("${getdownFullArchiveDir}/digest2.txt")
2570 task getdownArchive() {
2571 group = "distribution"
2572 description = "Build the website archive dir with getdown digest"
2574 dependsOn getdownArchiveBuild
2575 dependsOn getdownArchiveDigest
2578 tasks.withType(JavaCompile) {
2579 options.encoding = 'UTF-8'
2585 delete getdownAppBaseDir
2586 delete getdownFilesDir
2587 delete getdownArchiveDir
2593 if (file(install4jHomeDir).exists()) {
2595 } else if (file(System.getProperty("user.home")+"/buildtools/install4j").exists()) {
2596 install4jHomeDir = System.getProperty("user.home")+"/buildtools/install4j"
2597 } else if (file("/Applications/install4j.app/Contents/Resources/app").exists()) {
2598 install4jHomeDir = "/Applications/install4j.app/Contents/Resources/app"
2600 installDir(file(install4jHomeDir))
2602 mediaTypes = Arrays.asList(install4j_media_types.split(","))
2606 task copyInstall4jTemplate {
2607 def install4jTemplateFile = file("${install4jDir}/${install4j_template}")
2608 def install4jFileAssociationsFile = file("${install4jDir}/${install4j_installer_file_associations}")
2609 inputs.file(install4jTemplateFile)
2610 inputs.file(install4jFileAssociationsFile)
2611 inputs.property("CHANNEL", { CHANNEL })
2612 outputs.file(install4jConfFile)
2615 def install4jConfigXml = new XmlParser().parse(install4jTemplateFile)
2617 // turn off code signing if no OSX_KEYPASS
2618 if (OSX_KEYPASS == "") {
2619 install4jConfigXml.'**'.codeSigning.each { codeSigning ->
2620 codeSigning.'@macEnabled' = "false"
2622 install4jConfigXml.'**'.windows.each { windows ->
2623 windows.'@runPostProcessor' = "false"
2627 // disable install screen for OSX dmg (for 2.11.2.0)
2628 install4jConfigXml.'**'.macosArchive.each { macosArchive ->
2629 macosArchive.attributes().remove('executeSetupApp')
2630 macosArchive.attributes().remove('setupAppId')
2633 // turn off checksum creation for LOCAL channel
2634 def e = install4jConfigXml.application[0]
2635 e.'@createChecksums' = string(install4jCheckSums)
2637 // put file association actions where placeholder action is
2638 def install4jFileAssociationsText = install4jFileAssociationsFile.text
2639 def fileAssociationActions = new XmlParser().parseText("<actions>${install4jFileAssociationsText}</actions>")
2640 install4jConfigXml.'**'.action.any { a -> // .any{} stops after the first one that returns true
2641 if (a.'@name' == 'EXTENSIONS_REPLACED_BY_GRADLE') {
2642 def parent = a.parent()
2644 fileAssociationActions.each { faa ->
2647 // don't need to continue in .any loop once replacements have been made
2652 // use Windows Program Group with Examples folder for RELEASE, and Program Group without Examples for everything else
2653 // NB we're deleting the /other/ one!
2654 // Also remove the examples subdir from non-release versions
2655 def customizedIdToDelete = "PROGRAM_GROUP_RELEASE"
2656 // 2.11.1.0 NOT releasing with the Examples folder in the Program Group
2657 if (false && CHANNEL=="RELEASE") { // remove 'false && ' to include Examples folder in RELEASE channel
2658 customizedIdToDelete = "PROGRAM_GROUP_NON_RELEASE"
2660 // remove the examples subdir from Full File Set
2661 def files = install4jConfigXml.files[0]
2662 def fileset = files.filesets.fileset.find { fs -> fs.'@customizedId' == "FULL_FILE_SET" }
2663 def root = files.roots.root.find { r -> r.'@fileset' == fileset.'@id' }
2664 def mountPoint = files.mountPoints.mountPoint.find { mp -> mp.'@root' == root.'@id' }
2665 def dirEntry = files.entries.dirEntry.find { de -> de.'@mountPoint' == mountPoint.'@id' && de.'@subDirectory' == "examples" }
2666 dirEntry.parent().remove(dirEntry)
2668 install4jConfigXml.'**'.action.any { a ->
2669 if (a.'@customizedId' == customizedIdToDelete) {
2670 def parent = a.parent()
2676 // write install4j file
2677 install4jConfFile.text = XmlUtil.serialize(install4jConfigXml)
2684 delete install4jConfFile
2688 task cleanInstallersDataFiles {
2689 def installersOutputTxt = file("${jalviewDir}/${install4jBuildDir}/output.txt")
2690 def installersSha256 = file("${jalviewDir}/${install4jBuildDir}/sha256sums")
2691 def hugoDataJsonFile = file("${jalviewDir}/${install4jBuildDir}/installers-${JALVIEW_VERSION_UNDERSCORES}.json")
2693 delete installersOutputTxt
2694 delete installersSha256
2695 delete hugoDataJsonFile
2699 task install4jDMGBackgroundImageCopy {
2700 inputs.file "${install4jDMGBackgroundImageDir}/${install4jDMGBackgroundImageFile}"
2701 outputs.dir "${install4jDMGBackgroundImageBuildDir}"
2704 from(install4jDMGBackgroundImageDir) {
2705 include(install4jDMGBackgroundImageFile)
2707 into install4jDMGBackgroundImageBuildDir
2712 task install4jDMGBackgroundImageProcess {
2713 dependsOn install4jDMGBackgroundImageCopy
2716 if (backgroundImageText) {
2717 if (convertBinary == null) {
2718 throw new StopExecutionException("No ImageMagick convert binary installed at '${convertBinaryExpectedLocation}'")
2720 if (!project.hasProperty("install4j_background_image_text_suffix_cmd")) {
2721 throw new StopExecutionException("No property 'install4j_background_image_text_suffix_cmd' defined. See channel_gradle.properties for channel ${CHANNEL}")
2723 fileTree(dir: install4jDMGBackgroundImageBuildDir, include: "*.png").getFiles().each { file ->
2725 executable convertBinary
2728 '-font', install4j_background_image_text_font,
2729 '-fill', install4j_background_image_text_colour,
2730 '-draw', sprintf(install4j_background_image_text_suffix_cmd, channelSuffix),
2731 '-draw', sprintf(install4j_background_image_text_commit_cmd, "git-commit: ${gitHash}"),
2732 '-draw', sprintf(install4j_background_image_text_date_cmd, getDate("yyyy-MM-dd HH:mm:ss")),
2741 task install4jDMGBackgroundImage {
2742 dependsOn install4jDMGBackgroundImageProcess
2745 task installerFiles(type: com.install4j.gradle.Install4jTask) {
2746 group = "distribution"
2747 description = "Create the install4j installers"
2749 dependsOn copyInstall4jTemplate
2750 dependsOn cleanInstallersDataFiles
2751 dependsOn install4jDMGBackgroundImage
2753 projectFile = install4jConfFile
2755 // create an md5 for the input files to use as version for install4j conf file
2756 def digest = MessageDigest.getInstance("MD5")
2758 (file("${install4jDir}/${install4j_template}").text +
2759 file("${install4jDir}/${install4j_info_plist_file_associations}").text +
2760 file("${install4jDir}/${install4j_installer_file_associations}").text).bytes)
2761 def filesMd5 = new BigInteger(1, digest.digest()).toString(16)
2762 if (filesMd5.length() >= 8) {
2763 filesMd5 = filesMd5.substring(0,8)
2765 def install4jTemplateVersion = "${JALVIEW_VERSION}_F${filesMd5}_C${gitHash}"
2768 'JALVIEW_NAME': jalview_name,
2769 'JALVIEW_APPLICATION_NAME': applicationName,
2770 'JALVIEW_DIR': "../..",
2771 'OSX_KEYSTORE': OSX_KEYSTORE,
2772 'OSX_APPLEID': OSX_APPLEID,
2773 'OSX_ALTOOLPASS': OSX_ALTOOLPASS,
2774 'JSIGN_SH': JSIGN_SH,
2775 'JRE_DIR': getdown_app_dir_java,
2776 'INSTALLER_TEMPLATE_VERSION': install4jTemplateVersion,
2777 'JALVIEW_VERSION': JALVIEW_VERSION,
2778 'JAVA_MIN_VERSION': JAVA_MIN_VERSION,
2779 'JAVA_MAX_VERSION': JAVA_MAX_VERSION,
2780 'JAVA_VERSION': JAVA_VERSION,
2781 'JAVA_INTEGER_VERSION': JAVA_INTEGER_VERSION,
2782 'VERSION': JALVIEW_VERSION,
2783 'COPYRIGHT_MESSAGE': install4j_copyright_message,
2784 'BUNDLE_ID': install4jBundleId,
2785 'INTERNAL_ID': install4jInternalId,
2786 'WINDOWS_APPLICATION_ID': install4jWinApplicationId,
2787 'MACOS_DMG_DS_STORE': install4jDMGDSStore,
2788 'MACOS_DMG_BG_IMAGE': "${install4jDMGBackgroundImageBuildDir}/${install4jDMGBackgroundImageFile}",
2789 'WRAPPER_LINK': getdownWrapperLink,
2790 'BASH_WRAPPER_SCRIPT': getdown_bash_wrapper_script,
2791 'POWERSHELL_WRAPPER_SCRIPT': getdown_powershell_wrapper_script,
2792 'BATCH_WRAPPER_SCRIPT': getdown_batch_wrapper_script,
2793 'WRAPPER_SCRIPT_BIN_DIR': getdown_wrapper_script_dir,
2794 'INSTALLER_NAME': install4jInstallerName,
2795 'INSTALL4J_UTILS_DIR': install4j_utils_dir,
2796 'GETDOWN_CHANNEL_DIR': getdownChannelDir,
2797 'GETDOWN_FILES_DIR': getdown_files_dir,
2798 'GETDOWN_RESOURCE_DIR': getdown_resource_dir,
2799 'GETDOWN_DIST_DIR': getdownAppDistDir,
2800 'GETDOWN_ALT_DIR': getdown_app_dir_alt,
2801 'GETDOWN_INSTALL_DIR': getdown_install_dir,
2802 'INFO_PLIST_FILE_ASSOCIATIONS_FILE': install4j_info_plist_file_associations,
2803 'BUILD_DIR': install4jBuildDir,
2804 'APPLICATION_CATEGORIES': install4j_application_categories,
2805 'APPLICATION_FOLDER': install4jApplicationFolder,
2806 'UNIX_APPLICATION_FOLDER': install4jUnixApplicationFolder,
2807 'EXECUTABLE_NAME': install4jExecutableName,
2808 'EXTRA_SCHEME': install4jExtraScheme,
2809 'MAC_ICONS_FILE': install4jMacIconsFile,
2810 'WINDOWS_ICONS_FILE': install4jWindowsIconsFile,
2811 'PNG_ICON_FILE': install4jPngIconFile,
2812 'BACKGROUND': install4jBackground,
2817 'windows': 'WINDOWS',
2821 // these are the bundled OS/architecture VMs needed by install4j
2824 [ "mac", "aarch64" ],
2825 [ "windows", "x64" ],
2827 [ "linux", "aarch64" ]
2829 osArch.forEach { os, arch ->
2830 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)
2831 // N.B. For some reason install4j requires the below filename to have underscores and not hyphens
2832 // otherwise running `gradle installers` generates a non-useful error:
2833 // `install4j: compilation failed. Reason: java.lang.NumberFormatException: For input string: "windows"`
2834 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)
2837 //println("INSTALL4J VARIABLES:")
2838 //variables.each{k,v->println("${k}=${v}")}
2840 destination = "${jalviewDir}/${install4jBuildDir}"
2841 buildSelected = true
2843 if (install4j_faster.equals("true") || CHANNEL.startsWith("LOCAL")) {
2845 disableSigning = true
2846 disableNotarization = true
2850 macKeystorePassword = OSX_KEYPASS
2853 if (OSX_ALTOOLPASS) {
2854 appleIdPassword = OSX_ALTOOLPASS
2855 disableNotarization = false
2857 disableNotarization = true
2861 println("Using projectFile "+projectFile)
2862 if (!disableNotarization) { println("Will notarize OSX App DMG") }
2866 inputs.dir(getdownAppBaseDir)
2867 inputs.file(install4jConfFile)
2868 inputs.file("${install4jDir}/${install4j_info_plist_file_associations}")
2869 outputs.dir("${jalviewDir}/${install4j_build_dir}/${JAVA_VERSION}")
2872 def getDataHash(File myFile) {
2873 HashCode hash = Files.asByteSource(myFile).hash(Hashing.sha256())
2874 return myFile.exists()
2876 "file" : myFile.getName(),
2877 "filesize" : myFile.length(),
2878 "sha256" : hash.toString()
2883 def writeDataJsonFile(File installersOutputTxt, File installersSha256, File dataJsonFile) {
2885 "channel" : getdownChannelName,
2886 "date" : getDate("yyyy-MM-dd HH:mm:ss"),
2887 "git-commit" : "${gitHash} [${gitBranch}]",
2888 "version" : JALVIEW_VERSION
2890 // install4j installer files
2891 if (installersOutputTxt.exists()) {
2893 installersOutputTxt.readLines().each { def line ->
2894 if (line.startsWith("#")) {
2897 line.replaceAll("\n","")
2898 def vals = line.split("\t")
2899 def filename = vals[3]
2900 def filesize = file(filename).length()
2901 filename = filename.replaceAll(/^.*\//, "")
2902 hash[vals[0]] = [ "id" : vals[0], "os" : vals[1], "name" : vals[2], "file" : filename, "filesize" : filesize ]
2903 idHash."${filename}" = vals[0]
2905 if (install4jCheckSums && installersSha256.exists()) {
2906 installersSha256.readLines().each { def line ->
2907 if (line.startsWith("#")) {
2910 line.replaceAll("\n","")
2911 def vals = line.split(/\s+\*?/)
2912 def filename = vals[1]
2913 def innerHash = (hash.(idHash."${filename}"))."sha256" = vals[0]
2919 "JAR": shadowJar.archiveFile, // executable JAR
2920 "JVL": getdownVersionLaunchJvl, // version JVL
2921 "SOURCE": sourceDist.archiveFile // source TGZ
2922 ].each { key, value ->
2923 def file = file(value)
2924 if (file.exists()) {
2925 def fileHash = getDataHash(file)
2926 if (fileHash != null) {
2927 hash."${key}" = fileHash;
2931 return dataJsonFile.write(new JsonBuilder(hash).toPrettyString())
2934 task staticMakeInstallersJsonFile {
2936 def output = findProperty("i4j_output")
2937 def sha256 = findProperty("i4j_sha256")
2938 def json = findProperty("i4j_json")
2939 if (output == null || sha256 == null || json == null) {
2940 throw new GradleException("Must provide paths to all of output.txt, sha256sums, and output.json with '-Pi4j_output=... -Pi4j_sha256=... -Pi4j_json=...")
2942 writeDataJsonFile(file(output), file(sha256), file(json))
2947 dependsOn installerFiles
2953 eclipse().configFile(eclipse_codestyle_file)
2957 task createSourceReleaseProperties(type: WriteProperties) {
2958 group = "distribution"
2959 description = "Create the source RELEASE properties file"
2961 def sourceTarBuildDir = "${buildDir}/sourceTar"
2962 def sourceReleasePropertiesFile = "${sourceTarBuildDir}/RELEASE"
2963 outputFile (sourceReleasePropertiesFile)
2966 releaseProps.each{ key, val -> property key, val }
2967 property "git.branch", gitBranch
2968 property "git.hash", gitHash
2971 outputs.file(outputFile)
2974 task sourceDist(type: Tar) {
2975 group "distribution"
2976 description "Create a source .tar.gz file for distribution"
2978 dependsOn createBuildProperties
2979 dependsOn convertMdFiles
2980 dependsOn eclipseAllPreferences
2981 dependsOn createSourceReleaseProperties
2984 def outputFileName = "${project.name}_${JALVIEW_VERSION_UNDERSCORES}.tar.gz"
2985 archiveFileName = outputFileName
2987 compression Compression.GZIP
3002 "**/*.class","$j11modDir/**/*.jar","appletlib","**/*locales",
3004 "utils/InstallAnywhere",
3019 "gradle.properties",
3031 ".settings/org.eclipse.buildship.core.prefs",
3032 ".settings/org.eclipse.jdt.core.prefs"
3036 exclude (EXCLUDE_FILES)
3037 include (PROCESS_FILES)
3038 filter(ReplaceTokens,
3042 'Version-Rel': JALVIEW_VERSION,
3043 'Year-Rel': getDate("yyyy")
3048 exclude (EXCLUDE_FILES)
3049 exclude (PROCESS_FILES)
3050 exclude ("appletlib")
3051 exclude ("**/*locales")
3052 exclude ("*locales/**")
3053 exclude ("utils/InstallAnywhere")
3055 exclude (getdown_files_dir)
3056 // getdown_website_dir and getdown_archive_dir moved to build/website/docroot/getdown
3057 //exclude (getdown_website_dir)
3058 //exclude (getdown_archive_dir)
3060 // exluding these as not using jars as modules yet
3061 exclude ("${j11modDir}/**/*.jar")
3064 include(INCLUDE_FILES)
3066 // from (jalviewDir) {
3067 // // explicit includes for stuff that seemed to not get included
3068 // include(fileTree("test/**/*."))
3069 // exclude(EXCLUDE_FILES)
3070 // exclude(PROCESS_FILES)
3073 from(file(buildProperties).getParent()) {
3074 include(file(buildProperties).getName())
3075 rename(file(buildProperties).getName(), "build_properties")
3077 line.replaceAll("^INSTALLATION=.*\$","INSTALLATION=Source Release"+" git-commit\\\\:"+gitHash+" ["+gitBranch+"]")
3081 def sourceTarBuildDir = "${buildDir}/sourceTar"
3082 from(sourceTarBuildDir) {
3083 // this includes the appended RELEASE properties file
3087 task dataInstallersJson {
3089 description "Create the installers-VERSION.json data file for installer files created"
3091 mustRunAfter installers
3092 mustRunAfter shadowJar
3093 mustRunAfter sourceDist
3094 mustRunAfter getdownArchive
3096 def installersOutputTxt = file("${jalviewDir}/${install4jBuildDir}/output.txt")
3097 def installersSha256 = file("${jalviewDir}/${install4jBuildDir}/sha256sums")
3099 if (installersOutputTxt.exists()) {
3100 inputs.file(installersOutputTxt)
3102 if (install4jCheckSums && installersSha256.exists()) {
3103 inputs.file(installersSha256)
3106 shadowJar.archiveFile, // executable JAR
3107 getdownVersionLaunchJvl, // version JVL
3108 sourceDist.archiveFile // source TGZ
3109 ].each { fileName ->
3110 if (file(fileName).exists()) {
3111 inputs.file(fileName)
3115 outputs.file(hugoDataJsonFile)
3118 writeDataJsonFile(installersOutputTxt, installersSha256, hugoDataJsonFile)
3124 description "Copies all help pages to build dir. Runs ant task 'pubhtmlhelp'."
3127 dependsOn pubhtmlhelp
3129 inputs.dir("${helpBuildDir}/${help_dir}")
3130 outputs.dir("${buildDir}/distributions/${help_dir}")
3134 task j2sSetHeadlessBuild {
3141 task jalviewjsEnableAltFileProperty(type: WriteProperties) {
3143 description "Enable the alternative J2S Config file for headless build"
3145 outputFile = jalviewjsJ2sSettingsFileName
3146 def j2sPropsFile = file(jalviewjsJ2sSettingsFileName)
3147 def j2sProps = new Properties()
3148 if (j2sPropsFile.exists()) {
3150 def j2sPropsFileFIS = new FileInputStream(j2sPropsFile)
3151 j2sProps.load(j2sPropsFileFIS)
3152 j2sPropsFileFIS.close()
3154 j2sProps.each { prop, val ->
3157 } catch (Exception e) {
3158 println("Exception reading ${jalviewjsJ2sSettingsFileName}")
3162 if (! j2sProps.stringPropertyNames().contains(jalviewjs_j2s_alt_file_property_config)) {
3163 property(jalviewjs_j2s_alt_file_property_config, jalviewjs_j2s_alt_file_property)
3168 task jalviewjsSetEclipseWorkspace {
3169 def propKey = "jalviewjs_eclipse_workspace"
3171 if (project.hasProperty(propKey)) {
3172 propVal = project.getProperty(propKey)
3173 if (propVal.startsWith("~/")) {
3174 propVal = System.getProperty("user.home") + propVal.substring(1)
3177 def propsFileName = "${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_eclipse_workspace_location_file}"
3178 def propsFile = file(propsFileName)
3179 def eclipseWsDir = propVal
3180 def props = new Properties()
3182 def writeProps = true
3183 if (( eclipseWsDir == null || !file(eclipseWsDir).exists() ) && propsFile.exists()) {
3184 def ins = new FileInputStream(propsFileName)
3187 if (props.getProperty(propKey, null) != null) {
3188 eclipseWsDir = props.getProperty(propKey)
3193 if (eclipseWsDir == null || !file(eclipseWsDir).exists()) {
3194 def tempDir = File.createTempDir()
3195 eclipseWsDir = tempDir.getAbsolutePath()
3198 eclipseWorkspace = file(eclipseWsDir)
3201 // do not run a headless transpile when we claim to be in Eclipse
3203 println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3204 throw new StopExecutionException("Not running headless transpile whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
3206 println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3210 props.setProperty(propKey, eclipseWsDir)
3211 propsFile.parentFile.mkdirs()
3212 def bytes = new ByteArrayOutputStream()
3213 props.store(bytes, null)
3214 def propertiesString = bytes.toString()
3215 propsFile.text = propertiesString
3221 println("ECLIPSE WORKSPACE: "+eclipseWorkspace.getPath())
3224 //inputs.property(propKey, eclipseWsDir) // eclipseWsDir only gets set once this task runs, so will be out-of-date
3225 outputs.file(propsFileName)
3226 outputs.upToDateWhen { eclipseWorkspace.exists() && propsFile.exists() }
3230 task jalviewjsEclipsePaths {
3233 def eclipseRoot = jalviewjs_eclipse_root
3234 if (eclipseRoot.startsWith("~/")) {
3235 eclipseRoot = System.getProperty("user.home") + eclipseRoot.substring(1)
3237 if (OperatingSystem.current().isMacOsX()) {
3238 eclipseRoot += "/Eclipse.app"
3239 eclipseBinary = "${eclipseRoot}/Contents/MacOS/eclipse"
3240 eclipseProduct = "${eclipseRoot}/Contents/Eclipse/.eclipseproduct"
3241 } else if (OperatingSystem.current().isWindows()) { // check these paths!!
3242 if (file("${eclipseRoot}/eclipse").isDirectory() && file("${eclipseRoot}/eclipse/.eclipseproduct").exists()) {
3243 eclipseRoot += "/eclipse"
3245 eclipseBinary = "${eclipseRoot}/eclipse.exe"
3246 eclipseProduct = "${eclipseRoot}/.eclipseproduct"
3247 } else { // linux or unix
3248 if (file("${eclipseRoot}/eclipse").isDirectory() && file("${eclipseRoot}/eclipse/.eclipseproduct").exists()) {
3249 eclipseRoot += "/eclipse"
3250 println("eclipseDir exists")
3252 eclipseBinary = "${eclipseRoot}/eclipse"
3253 eclipseProduct = "${eclipseRoot}/.eclipseproduct"
3256 eclipseVersion = "4.13" // default
3257 def assumedVersion = true
3258 if (file(eclipseProduct).exists()) {
3259 def fis = new FileInputStream(eclipseProduct)
3260 def props = new Properties()
3262 eclipseVersion = props.getProperty("version")
3264 assumedVersion = false
3267 def propKey = "eclipse_debug"
3268 eclipseDebug = (project.hasProperty(propKey) && project.getProperty(propKey).equals("true"))
3271 // do not run a headless transpile when we claim to be in Eclipse
3273 println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3274 throw new StopExecutionException("Not running headless transpile whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
3276 println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3279 if (!assumedVersion) {
3280 println("ECLIPSE VERSION=${eclipseVersion}")
3286 task printProperties {
3288 description "Output to console all System.properties"
3290 System.properties.each { key, val -> System.out.println("Property: ${key}=${val}") }
3296 dependsOn eclipseProject
3297 dependsOn eclipseClasspath
3298 dependsOn eclipseJdt
3302 // this version (type: Copy) will delete anything in the eclipse dropins folder that isn't in fromDropinsDir
3303 task jalviewjsEclipseCopyDropins(type: Copy) {
3304 dependsOn jalviewjsEclipsePaths
3306 def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjs_eclipse_dropins_dir}", include: "*.jar")
3307 inputFiles += file("${jalviewDir}/${jalviewjsJ2sPlugin}")
3308 def outputDir = "${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_eclipse_tmp_dropins_dir}"
3315 // this eclipse -clean doesn't actually work
3316 task jalviewjsCleanEclipse(type: Exec) {
3317 dependsOn eclipseSetup
3318 dependsOn jalviewjsEclipsePaths
3319 dependsOn jalviewjsEclipseCopyDropins
3321 executable(eclipseBinary)
3322 args(["-nosplash", "--launcher.suppressErrors", "-data", eclipseWorkspace.getPath(), "-clean", "-console", "-consoleLog"])
3328 def inputString = """exit
3331 def inputByteStream = new ByteArrayInputStream(inputString.getBytes())
3332 standardInput = inputByteStream
3335 /* not really working yet
3336 jalviewjsEclipseCopyDropins.finalizedBy jalviewjsCleanEclipse
3340 task jalviewjsTransferUnzipSwingJs {
3341 def file_zip = "${jalviewDir}/${jalviewjs_swingjs_zip}"
3345 from zipTree(file_zip)
3346 into "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}"
3350 inputs.file file_zip
3351 outputs.dir "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}"
3355 task jalviewjsTransferUnzipLib {
3356 def zipFiles = fileTree(dir: "${jalviewDir}/${jalviewjs_libjs_dir}", include: "*.zip")
3359 zipFiles.each { file_zip ->
3361 from zipTree(file_zip)
3362 into "${jalviewDir}/${jalviewjsTransferSiteLibDir}"
3367 inputs.files zipFiles
3368 outputs.dir "${jalviewDir}/${jalviewjsTransferSiteLibDir}"
3372 task jalviewjsTransferUnzipAllLibs {
3373 dependsOn jalviewjsTransferUnzipSwingJs
3374 dependsOn jalviewjsTransferUnzipLib
3378 task jalviewjsCreateJ2sSettings(type: WriteProperties) {
3380 description "Create the alternative j2s file from the j2s.* properties"
3382 jalviewjsJ2sProps = project.properties.findAll { it.key.startsWith("j2s.") }.sort { it.key }
3383 def siteDirProperty = "j2s.site.directory"
3384 def setSiteDir = false
3385 jalviewjsJ2sProps.each { prop, val ->
3387 if (prop == siteDirProperty) {
3388 if (!(val.startsWith('/') || val.startsWith("file://") )) {
3389 val = "${jalviewDir}/${jalviewjsTransferSiteJsDir}/${val}"
3395 if (!setSiteDir) { // default site location, don't override specifically set property
3396 property(siteDirProperty,"${jalviewDirRelativePath}/${jalviewjsTransferSiteJsDir}")
3399 outputFile = jalviewjsJ2sAltSettingsFileName
3402 inputs.properties(jalviewjsJ2sProps)
3403 outputs.file(jalviewjsJ2sAltSettingsFileName)
3408 task jalviewjsEclipseSetup {
3409 dependsOn jalviewjsEclipseCopyDropins
3410 dependsOn jalviewjsSetEclipseWorkspace
3411 dependsOn jalviewjsCreateJ2sSettings
3415 task jalviewjsSyncAllLibs (type: Sync) {
3416 dependsOn jalviewjsTransferUnzipAllLibs
3417 def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjsTransferSiteLibDir}")
3418 inputFiles += fileTree(dir: "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}")
3419 def outputDir = "${jalviewDir}/${jalviewjsSiteDir}"
3423 def outputFiles = []
3424 rename { filename ->
3425 outputFiles += "${outputDir}/${filename}"
3432 // should this be exclude really ?
3433 duplicatesStrategy "INCLUDE"
3435 outputs.files outputFiles
3436 inputs.files inputFiles
3440 task jalviewjsSyncResources (type: Sync) {
3441 dependsOn buildResources
3443 def inputFiles = fileTree(dir: resourcesBuildDir)
3444 def outputDir = "${jalviewDir}/${jalviewjsSiteDir}/${jalviewjs_j2s_subdir}"
3448 def outputFiles = []
3449 rename { filename ->
3450 outputFiles += "${outputDir}/${filename}"
3456 outputs.files outputFiles
3457 inputs.files inputFiles
3461 task jalviewjsSyncSiteResources (type: Sync) {
3462 def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjs_site_resource_dir}")
3463 def outputDir = "${jalviewDir}/${jalviewjsSiteDir}"
3467 def outputFiles = []
3468 rename { filename ->
3469 outputFiles += "${outputDir}/${filename}"
3475 outputs.files outputFiles
3476 inputs.files inputFiles
3480 task jalviewjsSyncBuildProperties (type: Sync) {
3481 dependsOn createBuildProperties
3482 def inputFiles = [file(buildProperties)]
3483 def outputDir = "${jalviewDir}/${jalviewjsSiteDir}/${jalviewjs_j2s_subdir}"
3487 def outputFiles = []
3488 rename { filename ->
3489 outputFiles += "${outputDir}/${filename}"
3495 outputs.files outputFiles
3496 inputs.files inputFiles
3500 task jalviewjsProjectImport(type: Exec) {
3501 dependsOn eclipseSetup
3502 dependsOn jalviewjsEclipsePaths
3503 dependsOn jalviewjsEclipseSetup
3506 // do not run a headless import when we claim to be in Eclipse
3508 println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3509 throw new StopExecutionException("Not running headless import whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
3511 println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3515 //def projdir = eclipseWorkspace.getPath()+"/.metadata/.plugins/org.eclipse.core.resources/.projects/jalview/org.eclipse.jdt.core"
3516 def projdir = eclipseWorkspace.getPath()+"/.metadata/.plugins/org.eclipse.core.resources/.projects/jalview"
3517 executable(eclipseBinary)
3518 args(["-nosplash", "--launcher.suppressErrors", "-application", "com.seeq.eclipse.importprojects.headlessimport", "-data", eclipseWorkspace.getPath(), "-import", jalviewDirAbsolutePath])
3522 args += [ "--launcher.appendVmargs", "-vmargs", "-Dorg.eclipse.equinox.p2.reconciler.dropins.directory=${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_eclipse_tmp_dropins_dir}" ]
3524 args += [ "-D${j2sHeadlessBuildProperty}=true" ]
3525 args += [ "-D${jalviewjs_j2s_alt_file_property}=${jalviewjsJ2sAltSettingsFileName}" ]
3528 inputs.file("${jalviewDir}/.project")
3529 outputs.upToDateWhen {
3530 file(projdir).exists()
3535 task jalviewjsTranspile(type: Exec) {
3536 dependsOn jalviewjsEclipseSetup
3537 dependsOn jalviewjsProjectImport
3538 dependsOn jalviewjsEclipsePaths
3540 dependsOn jalviewjsEnableAltFileProperty
3544 // do not run a headless transpile when we claim to be in Eclipse
3546 println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3547 throw new StopExecutionException("Not running headless transpile whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
3549 println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3553 executable(eclipseBinary)
3554 args(["-nosplash", "--launcher.suppressErrors", "-application", "org.eclipse.jdt.apt.core.aptBuild", "-data", eclipseWorkspace, "-${jalviewjs_eclipse_build_arg}", eclipse_project_name ])
3558 args += [ "--launcher.appendVmargs", "-vmargs", "-Dorg.eclipse.equinox.p2.reconciler.dropins.directory=${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_eclipse_tmp_dropins_dir}" ]
3560 args += [ "-D${j2sHeadlessBuildProperty}=true" ]
3561 args += [ "-D${jalviewjs_j2s_alt_file_property}=${jalviewjsJ2sAltSettingsFileName}" ]
3567 stdout = new ByteArrayOutputStream()
3568 stderr = new ByteArrayOutputStream()
3570 def logOutFileName = "${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}"
3571 def logOutFile = file(logOutFileName)
3572 logOutFile.createNewFile()
3573 logOutFile.text = """ROOT: ${jalviewjs_eclipse_root}
3574 BINARY: ${eclipseBinary}
3575 VERSION: ${eclipseVersion}
3576 WORKSPACE: ${eclipseWorkspace}
3577 DEBUG: ${eclipseDebug}
3580 def logOutFOS = new FileOutputStream(logOutFile, true) // true == append
3581 // combine stdout and stderr
3582 def logErrFOS = logOutFOS
3584 if (jalviewjs_j2s_to_console.equals("true")) {
3585 standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
3586 new org.apache.tools.ant.util.TeeOutputStream(
3590 errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
3591 new org.apache.tools.ant.util.TeeOutputStream(
3596 standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
3599 errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
3606 if (stdout.toString().contains("Error processing ")) {
3607 // j2s did not complete transpile
3608 //throw new TaskExecutionException("Error during transpilation:\n${stderr}\nSee eclipse transpile log file '${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}'")
3609 if (jalviewjs_ignore_transpile_errors.equals("true")) {
3610 println("IGNORING TRANSPILE ERRORS")
3611 println("See eclipse transpile log file '${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}'")
3613 throw new GradleException("Error during transpilation:\n${stderr}\nSee eclipse transpile log file '${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}'")
3618 inputs.dir("${jalviewDir}/${sourceDir}")
3619 outputs.dir("${jalviewDir}/${jalviewjsTransferSiteJsDir}")
3620 outputs.upToDateWhen( { file("${jalviewDir}/${jalviewjsTransferSiteJsDir}${jalviewjs_server_resource}").exists() } )
3624 def jalviewjsCallCore(String name, FileCollection list, String prefixFile, String suffixFile, String jsfile, String zjsfile, File logOutFile, Boolean logOutConsole) {
3626 def stdout = new ByteArrayOutputStream()
3627 def stderr = new ByteArrayOutputStream()
3629 def coreFile = file(jsfile)
3631 msg = "Creating core for ${name}...\nGenerating ${jsfile}"
3633 logOutFile.createNewFile()
3634 logOutFile.append(msg+"\n")
3636 def coreTop = file(prefixFile)
3637 def coreBottom = file(suffixFile)
3638 coreFile.getParentFile().mkdirs()
3639 coreFile.createNewFile()
3640 coreFile.write( coreTop.getText("UTF-8") )
3644 def t = f.getText("UTF-8")
3645 t.replaceAll("Clazz\\.([^_])","Clazz_${1}")
3646 coreFile.append( t )
3648 msg = "...file '"+f.getPath()+"' does not exist, skipping"
3650 logOutFile.append(msg+"\n")
3653 coreFile.append( coreBottom.getText("UTF-8") )
3655 msg = "Generating ${zjsfile}"
3657 logOutFile.append(msg+"\n")
3658 def logOutFOS = new FileOutputStream(logOutFile, true) // true == append
3659 def logErrFOS = logOutFOS
3662 classpath = files(["${jalviewDir}/${jalviewjs_closure_compiler}"])
3663 main = "com.google.javascript.jscomp.CommandLineRunner"
3664 jvmArgs = [ "-Dfile.encoding=UTF-8" ]
3665 args = [ "--compilation_level", "SIMPLE_OPTIMIZATIONS", "--warning_level", "QUIET", "--charset", "UTF-8", "--js", jsfile, "--js_output_file", zjsfile ]
3668 msg = "\nRunning '"+commandLine.join(' ')+"'\n"
3670 logOutFile.append(msg+"\n")
3672 if (logOutConsole) {
3673 standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
3674 new org.apache.tools.ant.util.TeeOutputStream(
3678 errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
3679 new org.apache.tools.ant.util.TeeOutputStream(
3684 standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
3687 errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
3694 logOutFile.append(msg+"\n")
3698 task jalviewjsBuildAllCores {
3700 description "Build the core js lib closures listed in the classlists dir"
3701 dependsOn jalviewjsTranspile
3702 dependsOn jalviewjsTransferUnzipSwingJs
3704 def j2sDir = "${jalviewDir}/${jalviewjsTransferSiteJsDir}/${jalviewjs_j2s_subdir}"
3705 def swingJ2sDir = "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}/${jalviewjs_j2s_subdir}"
3706 def libJ2sDir = "${jalviewDir}/${jalviewjsTransferSiteLibDir}/${jalviewjs_j2s_subdir}"
3707 def jsDir = "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}/${jalviewjs_js_subdir}"
3708 def outputDir = "${jalviewDir}/${jalviewjsTransferSiteCoreDir}/${jalviewjs_j2s_subdir}/core"
3709 def prefixFile = "${jsDir}/core/coretop2.js"
3710 def suffixFile = "${jsDir}/core/corebottom2.js"
3712 inputs.file prefixFile
3713 inputs.file suffixFile
3715 def classlistFiles = []
3716 // add the classlists found int the jalviewjs_classlists_dir
3717 fileTree(dir: "${jalviewDir}/${jalviewjs_classlists_dir}", include: "*.txt").each {
3719 def name = file.getName() - ".txt"
3726 // _jmol and _jalview cores. Add any other peculiar classlist.txt files here
3727 //classlistFiles += [ 'file': file("${jalviewDir}/${jalviewjs_classlist_jmol}"), 'name': "_jvjmol" ]
3728 classlistFiles += [ 'file': file("${jalviewDir}/${jalviewjs_classlist_jalview}"), 'name': jalviewjsJalviewCoreName ]
3730 jalviewjsCoreClasslists = []
3732 classlistFiles.each {
3735 def file = hash['file']
3736 if (! file.exists()) {
3737 //println("...classlist file '"+file.getPath()+"' does not exist, skipping")
3738 return false // this is a "continue" in groovy .each closure
3740 def name = hash['name']
3742 name = file.getName() - ".txt"
3750 def list = fileTree(dir: j2sDir, includes: filelist)
3752 def jsfile = "${outputDir}/core${name}.js"
3753 def zjsfile = "${outputDir}/core${name}.z.js"
3755 jalviewjsCoreClasslists += [
3764 outputs.file(jsfile)
3765 outputs.file(zjsfile)
3768 // _stevesoft core. add any cores without a classlist here (and the inputs and outputs)
3769 def stevesoftClasslistName = "_stevesoft"
3770 def stevesoftClasslist = [
3771 'jsfile': "${outputDir}/core${stevesoftClasslistName}.js",
3772 'zjsfile': "${outputDir}/core${stevesoftClasslistName}.z.js",
3773 'list': fileTree(dir: j2sDir, include: "com/stevesoft/pat/**/*.js"),
3774 'name': stevesoftClasslistName
3776 jalviewjsCoreClasslists += stevesoftClasslist
3777 inputs.files(stevesoftClasslist['list'])
3778 outputs.file(stevesoftClasslist['jsfile'])
3779 outputs.file(stevesoftClasslist['zjsfile'])
3782 def allClasslistName = "_all"
3783 def allJsFiles = fileTree(dir: j2sDir, include: "**/*.js")
3784 allJsFiles += fileTree(
3788 // these exlusions are files that the closure-compiler produces errors for. Should fix them
3789 "**/org/jmol/jvxl/readers/IsoIntersectFileReader.js",
3790 "**/org/jmol/export/JSExporter.js"
3793 allJsFiles += fileTree(
3797 // these exlusions are files that the closure-compiler produces errors for. Should fix them
3798 "**/sun/misc/Unsafe.js",
3799 "**/swingjs/jquery/jquery-editable-select.js",
3800 "**/swingjs/jquery/j2sComboBox.js",
3801 "**/sun/misc/FloatingDecimal.js"
3804 def allClasslist = [
3805 'jsfile': "${outputDir}/core${allClasslistName}.js",
3806 'zjsfile': "${outputDir}/core${allClasslistName}.z.js",
3808 'name': allClasslistName
3810 // not including this version of "all" core at the moment
3811 //jalviewjsCoreClasslists += allClasslist
3812 inputs.files(allClasslist['list'])
3813 outputs.file(allClasslist['jsfile'])
3814 outputs.file(allClasslist['zjsfile'])
3817 def logOutFile = file("${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_j2s_closure_stdout}")
3818 logOutFile.getParentFile().mkdirs()
3819 logOutFile.createNewFile()
3820 logOutFile.write(getDate("yyyy-MM-dd HH:mm:ss")+" jalviewjsBuildAllCores\n----\n")
3822 jalviewjsCoreClasslists.each {
3823 jalviewjsCallCore(it.name, it.list, prefixFile, suffixFile, it.jsfile, it.zjsfile, logOutFile, jalviewjs_j2s_to_console.equals("true"))
3830 def jalviewjsPublishCoreTemplate(String coreName, String templateName, File inputFile, String outputFile) {
3833 into file(outputFile).getParentFile()
3834 rename { filename ->
3835 if (filename.equals(inputFile.getName())) {
3836 return file(outputFile).getName()
3840 filter(ReplaceTokens,
3844 'MAIN': '"'+main_class+'"',
3846 'NAME': jalviewjsJalviewTemplateName+" [core ${coreName}]",
3847 'COREKEY': jalviewjs_core_key,
3848 'CORENAME': coreName
3855 task jalviewjsPublishCoreTemplates {
3856 dependsOn jalviewjsBuildAllCores
3857 def inputFileName = "${jalviewDir}/${j2s_coretemplate_html}"
3858 def inputFile = file(inputFileName)
3859 def outputDir = "${jalviewDir}/${jalviewjsTransferSiteCoreDir}"
3861 def outputFiles = []
3862 jalviewjsCoreClasslists.each { cl ->
3863 def outputFile = "${outputDir}/${jalviewjsJalviewTemplateName}_${cl.name}.html"
3864 cl['outputfile'] = outputFile
3865 outputFiles += outputFile
3869 jalviewjsCoreClasslists.each { cl ->
3870 jalviewjsPublishCoreTemplate(cl.name, jalviewjsJalviewTemplateName, inputFile, cl.outputfile)
3873 inputs.file(inputFile)
3874 outputs.files(outputFiles)
3878 task jalviewjsSyncCore (type: Sync) {
3879 dependsOn jalviewjsBuildAllCores
3880 dependsOn jalviewjsPublishCoreTemplates
3881 def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjsTransferSiteCoreDir}")
3882 def outputDir = "${jalviewDir}/${jalviewjsSiteDir}"
3886 def outputFiles = []
3887 rename { filename ->
3888 outputFiles += "${outputDir}/${filename}"
3894 outputs.files outputFiles
3895 inputs.files inputFiles
3899 // this Copy version of TransferSiteJs will delete anything else in the target dir
3900 task jalviewjsCopyTransferSiteJs(type: Copy) {
3901 dependsOn jalviewjsTranspile
3902 from "${jalviewDir}/${jalviewjsTransferSiteJsDir}"
3903 into "${jalviewDir}/${jalviewjsSiteDir}"
3907 // this Sync version of TransferSite is used by buildship to keep the website automatically up to date when a file changes
3908 task jalviewjsSyncTransferSiteJs(type: Sync) {
3909 from "${jalviewDir}/${jalviewjsTransferSiteJsDir}"
3911 into "${jalviewDir}/${jalviewjsSiteDir}"
3918 jalviewjsSyncAllLibs.mustRunAfter jalviewjsCopyTransferSiteJs
3919 jalviewjsSyncResources.mustRunAfter jalviewjsCopyTransferSiteJs
3920 jalviewjsSyncSiteResources.mustRunAfter jalviewjsCopyTransferSiteJs
3921 jalviewjsSyncBuildProperties.mustRunAfter jalviewjsCopyTransferSiteJs
3923 jalviewjsSyncAllLibs.mustRunAfter jalviewjsSyncTransferSiteJs
3924 jalviewjsSyncResources.mustRunAfter jalviewjsSyncTransferSiteJs
3925 jalviewjsSyncSiteResources.mustRunAfter jalviewjsSyncTransferSiteJs
3926 jalviewjsSyncBuildProperties.mustRunAfter jalviewjsSyncTransferSiteJs
3929 task jalviewjsPrepareSite {
3931 description "Prepares the website folder including unzipping files and copying resources"
3932 dependsOn jalviewjsSyncAllLibs
3933 dependsOn jalviewjsSyncResources
3934 dependsOn jalviewjsSyncSiteResources
3935 dependsOn jalviewjsSyncBuildProperties
3936 dependsOn jalviewjsSyncCore
3940 task jalviewjsBuildSite {
3942 description "Builds the whole website including transpiled code"
3943 dependsOn jalviewjsCopyTransferSiteJs
3944 dependsOn jalviewjsPrepareSite
3948 task cleanJalviewjsTransferSite {
3950 delete "${jalviewDir}/${jalviewjsTransferSiteJsDir}"
3951 delete "${jalviewDir}/${jalviewjsTransferSiteLibDir}"
3952 delete "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}"
3953 delete "${jalviewDir}/${jalviewjsTransferSiteCoreDir}"
3958 task cleanJalviewjsSite {
3959 dependsOn cleanJalviewjsTransferSite
3961 delete "${jalviewDir}/${jalviewjsSiteDir}"
3966 task jalviewjsSiteTar(type: Tar) {
3968 description "Creates a tar.gz file for the website"
3969 dependsOn jalviewjsBuildSite
3970 def outputFilename = "jalviewjs-site-${JALVIEW_VERSION}.tar.gz"
3971 archiveFileName = outputFilename
3973 compression Compression.GZIP
3975 from "${jalviewDir}/${jalviewjsSiteDir}"
3976 into jalviewjs_site_dir // this is inside the tar file
3978 inputs.dir("${jalviewDir}/${jalviewjsSiteDir}")
3982 task jalviewjsServer {
3984 def filename = "jalviewjsTest.html"
3985 description "Starts a webserver on localhost to test the website. See ${filename} to access local site on most recently used port."
3986 def htmlFile = "${jalviewDirAbsolutePath}/${filename}"
3991 def f = Class.forName("org.gradle.plugins.javascript.envjs.http.simple.SimpleHttpFileServerFactory")
3992 factory = f.newInstance()
3993 } catch (ClassNotFoundException e) {
3994 throw new GradleException("Unable to create SimpleHttpFileServerFactory")
3996 def port = Integer.valueOf(jalviewjs_server_port)
4001 while(port < start+1000 && !running) {
4003 def doc_root = new File("${jalviewDirAbsolutePath}/${jalviewjsSiteDir}")
4004 jalviewjsServer = factory.start(doc_root, port)
4006 url = jalviewjsServer.getResourceUrl(jalviewjs_server_resource)
4007 println("SERVER STARTED with document root ${doc_root}.")
4008 println("Go to "+url+" . Run gradle --stop to stop (kills all gradle daemons).")
4009 println("For debug: "+url+"?j2sdebug")
4010 println("For verbose: "+url+"?j2sverbose")
4011 } catch (Exception e) {
4016 <p><a href="${url}">JalviewJS Test. <${url}></a></p>
4017 <p><a href="${url}?j2sdebug">JalviewJS Test with debug. <${url}?j2sdebug></a></p>
4018 <p><a href="${url}?j2sverbose">JalviewJS Test with verbose. <${url}?j2sdebug></a></p>
4020 jalviewjsCoreClasslists.each { cl ->
4021 def urlcore = jalviewjsServer.getResourceUrl(file(cl.outputfile).getName())
4023 <p><a href="${urlcore}">${jalviewjsJalviewTemplateName} [core ${cl.name}]. <${urlcore}></a></p>
4025 println("For core ${cl.name}: "+urlcore)
4028 file(htmlFile).text = htmlText
4031 outputs.file(htmlFile)
4032 outputs.upToDateWhen({false})
4036 task cleanJalviewjsAll {
4038 description "Delete all configuration and build artifacts to do with JalviewJS build"
4039 dependsOn cleanJalviewjsSite
4040 dependsOn jalviewjsEclipsePaths
4043 delete "${jalviewDir}/${jalviewjsBuildDir}"
4044 delete "${jalviewDir}/${eclipse_bin_dir}"
4045 if (eclipseWorkspace != null && file(eclipseWorkspace.getAbsolutePath()+"/.metadata").exists()) {
4046 delete file(eclipseWorkspace.getAbsolutePath()+"/.metadata")
4048 delete jalviewjsJ2sAltSettingsFileName
4051 outputs.upToDateWhen( { false } )
4055 task jalviewjsIDE_checkJ2sPlugin {
4056 group "00 JalviewJS in Eclipse"
4057 description "Compare the swingjs/net.sf.j2s.core(-j11)?.jar file with the Eclipse IDE's plugin version (found in the 'dropins' dir)"
4060 def j2sPlugin = string("${jalviewDir}/${jalviewjsJ2sPlugin}")
4061 def j2sPluginFile = file(j2sPlugin)
4062 def eclipseHome = System.properties["eclipse.home.location"]
4063 if (eclipseHome == null || ! IN_ECLIPSE) {
4064 throw new StopExecutionException("Cannot find running Eclipse home from System.properties['eclipse.home.location']. Skipping J2S Plugin Check.")
4066 def eclipseJ2sPluginDirs = [ "${eclipseHome}/dropins" ]
4067 def altPluginsDir = System.properties["org.eclipse.equinox.p2.reconciler.dropins.directory"]
4068 if (altPluginsDir != null && file(altPluginsDir).exists()) {
4069 eclipseJ2sPluginDirs += altPluginsDir
4071 def foundPlugin = false
4072 def j2sPluginFileName = j2sPluginFile.getName()
4073 def eclipseJ2sPlugin
4074 def eclipseJ2sPluginFile
4075 eclipseJ2sPluginDirs.any { dir ->
4076 eclipseJ2sPlugin = "${dir}/${j2sPluginFileName}"
4077 eclipseJ2sPluginFile = file(eclipseJ2sPlugin)
4078 if (eclipseJ2sPluginFile.exists()) {
4084 def msg = "Eclipse J2S Plugin is not installed (could not find '${j2sPluginFileName}' in\n"+eclipseJ2sPluginDirs.join("\n")+"\n)\nTry running task jalviewjsIDE_copyJ2sPlugin"
4085 System.err.println(msg)
4086 throw new StopExecutionException(msg)
4089 def digest = MessageDigest.getInstance("MD5")
4091 digest.update(j2sPluginFile.text.bytes)
4092 def j2sPluginMd5 = new BigInteger(1, digest.digest()).toString(16).padLeft(32, '0')
4094 digest.update(eclipseJ2sPluginFile.text.bytes)
4095 def eclipseJ2sPluginMd5 = new BigInteger(1, digest.digest()).toString(16).padLeft(32, '0')
4097 if (j2sPluginMd5 != eclipseJ2sPluginMd5) {
4098 def msg = "WARNING! Eclipse J2S Plugin '${eclipseJ2sPlugin}' is different to this commit's version '${j2sPlugin}'"
4099 System.err.println(msg)
4100 throw new StopExecutionException(msg)
4102 def msg = "Eclipse J2S Plugin '${eclipseJ2sPlugin}' is the same as '${j2sPlugin}' (this is good)"
4108 task jalviewjsIDE_copyJ2sPlugin {
4109 group "00 JalviewJS in Eclipse"
4110 description "Copy the swingjs/net.sf.j2s.core(-j11)?.jar file into the Eclipse IDE's 'dropins' dir"
4113 def j2sPlugin = string("${jalviewDir}/${jalviewjsJ2sPlugin}")
4114 def j2sPluginFile = file(j2sPlugin)
4115 def eclipseHome = System.properties["eclipse.home.location"]
4116 if (eclipseHome == null || ! IN_ECLIPSE) {
4117 throw new StopExecutionException("Cannot find running Eclipse home from System.properties['eclipse.home.location']. NOT copying J2S Plugin.")
4119 def eclipseJ2sPlugin = "${eclipseHome}/dropins/${j2sPluginFile.getName()}"
4120 def eclipseJ2sPluginFile = file(eclipseJ2sPlugin)
4121 def msg = "WARNING! Copying this commit's j2s plugin '${j2sPlugin}' to Eclipse J2S Plugin '${eclipseJ2sPlugin}'\n* May require an Eclipse restart"
4122 System.err.println(msg)
4125 eclipseJ2sPluginFile.getParentFile().mkdirs()
4126 into eclipseJ2sPluginFile.getParent()
4132 task jalviewjsIDE_j2sFile {
4133 group "00 JalviewJS in Eclipse"
4134 description "Creates the .j2s file"
4135 dependsOn jalviewjsCreateJ2sSettings
4139 task jalviewjsIDE_SyncCore {
4140 group "00 JalviewJS in Eclipse"
4141 description "Build the core js lib closures listed in the classlists dir and publish core html from template"
4142 dependsOn jalviewjsSyncCore
4146 task jalviewjsIDE_SyncSiteAll {
4147 dependsOn jalviewjsSyncAllLibs
4148 dependsOn jalviewjsSyncResources
4149 dependsOn jalviewjsSyncSiteResources
4150 dependsOn jalviewjsSyncBuildProperties
4154 cleanJalviewjsTransferSite.mustRunAfter jalviewjsIDE_SyncSiteAll
4157 task jalviewjsIDE_PrepareSite {
4158 group "00 JalviewJS in Eclipse"
4159 description "Sync libs and resources to site dir, but not closure cores"
4161 dependsOn jalviewjsIDE_SyncSiteAll
4162 //dependsOn cleanJalviewjsTransferSite // not sure why this clean is here -- will slow down a re-run of this task
4166 task jalviewjsIDE_AssembleSite {
4167 group "00 JalviewJS in Eclipse"
4168 description "Assembles unzipped supporting zipfiles, resources, site resources and closure cores into the Eclipse transpiled site"
4169 dependsOn jalviewjsPrepareSite
4173 task jalviewjsIDE_SiteClean {
4174 group "00 JalviewJS in Eclipse"
4175 description "Deletes the Eclipse transpiled site"
4176 dependsOn cleanJalviewjsSite
4180 task jalviewjsIDE_Server {
4181 group "00 JalviewJS in Eclipse"
4182 description "Starts a webserver on localhost to test the website"
4183 dependsOn jalviewjsServer
4187 // buildship runs this at import or gradle refresh
4188 task eclipseSynchronizationTask {
4189 //dependsOn eclipseSetup
4190 dependsOn createBuildProperties
4192 dependsOn jalviewjsIDE_j2sFile
4193 dependsOn jalviewjsIDE_checkJ2sPlugin
4194 dependsOn jalviewjsIDE_PrepareSite
4199 // buildship runs this at build time or project refresh
4200 task eclipseAutoBuildTask {
4201 //dependsOn jalviewjsIDE_checkJ2sPlugin
4202 //dependsOn jalviewjsIDE_PrepareSite
4208 description "Build the site"
4209 dependsOn jalviewjsBuildSite
4213 task jalviewjsCopyStderrLaunchFile(type: Copy) {
4214 from file(jalviewjs_stderr_launch)
4215 into jalviewjsSiteDir
4217 inputs.file jalviewjs_stderr_launch
4218 outputs.file jalviewjsStderrLaunchFilename
4221 task jalviewjsChromiumProfile {
4222 def profileDir = "${jalviewjsBuildDir}/${jalviewjs_chromium_user_dir}/${jalviewjs_chromium_profile_name}"
4223 def firstRun = file("${profileDir}/First Run")
4230 outputs.file firstRun
4233 task jalviewjsLaunchTest(type: Exec) {
4235 description "Check JalviewJS opens in a browser"
4236 dependsOn jalviewjsBuildSite
4237 dependsOn jalviewjsCopyStderrLaunchFile
4238 dependsOn jalviewjsChromiumProfile
4240 def chromiumBinary = jalviewjs_chromium_binary
4241 if (chromiumBinary.startsWith("~/")) {
4242 chromiumBinary = System.getProperty("user.home") + chromiumBinary.substring(1)
4246 def exec = file(chromiumBinary)
4247 if (!exec.exists()) {
4248 throw new GradleException("Could not find chromium binary '${chromiumBinary}'. Cannot run task ${name}.")
4252 executable(chromiumBinary)
4256 "--virtual-time-budget=60000",
4257 "--user-data-dir=${jalviewjsBuildDir}/${jalviewjs_chromium_user_dir}",
4258 "--profile-directory=${jalviewjs_chromium_profile_name}",
4259 "--allow-file-access-from-files",
4260 "--enable-logging=stderr",
4261 jalviewjsStderrLaunchFilename
4264 standardOutput = new ByteArrayOutputStream()
4265 errorOutput = new ByteArrayOutputStream()
4269 def stderr = errorOutput.toString()
4270 stderr.eachLine { line ->
4271 if (line.contains(jalviewjs_desktop_init_string)) {
4272 println("Found line '"+line+"'")
4278 throw new GradleException("Could not find evidence of Desktop launch in JalviewJS.")