1 /* Convention for properties. Read from gradle.properties, use lower_case_underlines for property names.
2 * For properties set within build.gradle, use camelCaseNoSpace.
4 import org.apache.tools.ant.filters.ReplaceTokens
5 import org.gradle.internal.os.OperatingSystem
6 import org.gradle.plugins.ide.internal.generator.PropertiesPersistableConfigurationObject
7 import org.gradle.api.internal.PropertiesTransformer
8 import org.gradle.util.ConfigureUtil
9 import org.gradle.plugins.ide.eclipse.model.Output
10 import org.gradle.plugins.ide.eclipse.model.Library
11 import java.security.MessageDigest
12 import java.util.regex.Matcher
13 import java.util.concurrent.Executors
14 import java.util.concurrent.Future
15 import java.util.concurrent.ScheduledExecutorService
16 import java.util.concurrent.TimeUnit
17 import groovy.transform.ExternalizeMethods
18 import groovy.util.XmlParser
19 import groovy.xml.XmlUtil
20 import groovy.json.JsonBuilder
21 import com.vladsch.flexmark.util.ast.Node
22 import com.vladsch.flexmark.html.HtmlRenderer
23 import com.vladsch.flexmark.parser.Parser
24 import com.vladsch.flexmark.util.data.MutableDataSet
25 import com.vladsch.flexmark.ext.gfm.tasklist.TaskListExtension
26 import com.vladsch.flexmark.ext.tables.TablesExtension
27 import com.vladsch.flexmark.ext.gfm.strikethrough.StrikethroughExtension
28 import com.vladsch.flexmark.ext.autolink.AutolinkExtension
29 import com.vladsch.flexmark.ext.anchorlink.AnchorLinkExtension
30 import com.vladsch.flexmark.ext.toc.TocExtension
31 import com.google.common.hash.HashCode
32 import com.google.common.hash.Hashing
33 import com.google.common.io.Files
34 import org.jsoup.Jsoup
35 import org.jsoup.nodes.Element
43 classpath "com.vladsch.flexmark:flexmark-all:0.62.0"
44 classpath "org.jsoup:jsoup:1.14.3"
45 classpath "com.eowise:gradle-imagemagick:0.5.1"
54 id "com.diffplug.gradle.spotless" version "3.28.0"
55 id 'com.github.johnrengelman.shadow' version '4.0.3'
56 id 'com.install4j.gradle' version '10.0.3'
57 id 'com.dorongold.task-tree' version '2.1.1' // only needed to display task dependency tree with gradle task1 [task2 ...] taskTree
58 id 'com.palantir.git-version' version '0.13.0' apply false
69 // in ext the values are cast to Object. Ensure string values are cast as String (and not GStringImpl) for later use
70 def string(Object o) {
71 return o == null ? "" : o.toString()
74 def overrideProperties(String propsFileName, boolean output = false) {
75 if (propsFileName == null) {
78 def propsFile = file(propsFileName)
79 if (propsFile != null && propsFile.exists()) {
80 println("Using properties from file '${propsFileName}'")
82 def p = new Properties()
83 def localPropsFIS = new FileInputStream(propsFile)
89 if (project.hasProperty(key)) {
90 oldval = project.findProperty(key)
91 project.setProperty(key, val)
93 println("Overriding property '${key}' ('${oldval}') with ${file(propsFile).getName()} value '${val}'")
96 ext.setProperty(key, val)
98 println("Setting ext property '${key}' with ${file(propsFile).getName()}s value '${val}'")
102 } catch (Exception e) {
103 println("Exception reading local.properties")
110 jalviewDirAbsolutePath = file(jalviewDir).getAbsolutePath()
111 jalviewDirRelativePath = jalviewDir
114 getdownChannelName = CHANNEL.toLowerCase()
115 // default to "default". Currently only has different cosmetics for "develop", "release", "default"
116 propertiesChannelName = ["develop", "release", "test-release", "jalviewjs", "jalviewjs-release" ].contains(getdownChannelName) ? getdownChannelName : "default"
117 channelDirName = propertiesChannelName
118 // Import channel_properties
119 if (getdownChannelName.startsWith("develop-")) {
120 channelDirName = "develop-SUFFIX"
122 channelDir = string("${jalviewDir}/${channel_properties_dir}/${channelDirName}")
123 channelGradleProperties = string("${channelDir}/channel_gradle.properties")
124 channelPropsFile = string("${channelDir}/${resource_dir}/${channel_props}")
125 overrideProperties(channelGradleProperties, false)
126 // local build environment properties
127 // can be "projectDir/local.properties"
128 overrideProperties("${projectDir}/local.properties", true)
129 // or "../projectDir_local.properties"
130 overrideProperties(projectDir.getParent() + "/" + projectDir.getName() + "_local.properties", true)
133 // Import releaseProps from the RELEASE file
134 // or a file specified via JALVIEW_RELEASE_FILE if defined
135 // Expect jalview.version and target release branch in jalview.release
136 releaseProps = new Properties();
137 def releasePropFile = findProperty("JALVIEW_RELEASE_FILE");
138 def defaultReleasePropFile = "${jalviewDirAbsolutePath}/RELEASE";
140 (new File(releasePropFile!=null ? releasePropFile : defaultReleasePropFile)).withInputStream {
141 releaseProps.load(it)
143 } catch (Exception fileLoadError) {
144 throw new Error("Couldn't load release properties file "+(releasePropFile==null ? defaultReleasePropFile : "from custom location: releasePropFile"),fileLoadError);
147 // Set JALVIEW_VERSION if it is not already set
148 if (findProperty("JALVIEW_VERSION")==null || "".equals(JALVIEW_VERSION)) {
149 JALVIEW_VERSION = releaseProps.get("jalview.version")
151 println("JALVIEW_VERSION is set to '${JALVIEW_VERSION}'")
153 // this property set when running Eclipse headlessly
154 j2sHeadlessBuildProperty = string("net.sf.j2s.core.headlessbuild")
155 // this property set by Eclipse
156 eclipseApplicationProperty = string("eclipse.application")
157 // CHECK IF RUNNING FROM WITHIN ECLIPSE
158 def eclipseApplicationPropertyVal = System.properties[eclipseApplicationProperty]
159 IN_ECLIPSE = eclipseApplicationPropertyVal != null && eclipseApplicationPropertyVal.startsWith("org.eclipse.ui.")
160 // BUT WITHOUT THE HEADLESS BUILD PROPERTY SET
161 if (System.properties[j2sHeadlessBuildProperty].equals("true")) {
162 println("Setting IN_ECLIPSE to ${IN_ECLIPSE} as System.properties['${j2sHeadlessBuildProperty}'] == '${System.properties[j2sHeadlessBuildProperty]}'")
166 println("WITHIN ECLIPSE IDE")
168 println("HEADLESS BUILD")
171 J2S_ENABLED = (project.hasProperty('j2s.compiler.status') && project['j2s.compiler.status'] != null && project['j2s.compiler.status'] == "enable")
173 println("J2S ENABLED")
176 System.properties.sort { it.key }.each {
177 key, val -> println("SYSTEM PROPERTY ${key}='${val}'")
180 if (false && IN_ECLIPSE) {
181 jalviewDir = jalviewDirAbsolutePath
186 buildDate = new Date().format("yyyyMMdd")
189 bareSourceDir = string(source_dir)
190 sourceDir = string("${jalviewDir}/${bareSourceDir}")
191 resourceDir = string("${jalviewDir}/${resource_dir}")
192 bareTestSourceDir = string(test_source_dir)
193 testDir = string("${jalviewDir}/${bareTestSourceDir}")
195 classesDir = string("${jalviewDir}/${classes_dir}")
198 useClover = clover.equals("true")
199 cloverBuildDir = "${buildDir}/clover"
200 cloverInstrDir = file("${cloverBuildDir}/clover-instr")
201 cloverClassesDir = file("${cloverBuildDir}/clover-classes")
202 cloverReportDir = file("${buildDir}/reports/clover")
203 cloverTestInstrDir = file("${cloverBuildDir}/clover-test-instr")
204 cloverTestClassesDir = file("${cloverBuildDir}/clover-test-classes")
205 //cloverTestClassesDir = cloverClassesDir
206 cloverDb = string("${cloverBuildDir}/clover.db")
208 testSourceDir = useClover ? cloverTestInstrDir : testDir
209 testClassesDir = useClover ? cloverTestClassesDir : "${jalviewDir}/${test_output_dir}"
212 backgroundImageText = BACKGROUNDIMAGETEXT
213 getdownChannelDir = string("${getdown_website_dir}/${propertiesChannelName}")
214 getdownAppBaseDir = string("${jalviewDir}/${getdownChannelDir}/${JAVA_VERSION}")
215 getdownArchiveDir = string("${jalviewDir}/${getdown_archive_dir}")
216 getdownFullArchiveDir = null
217 getdownTextLines = []
218 getdownLaunchJvl = null
219 getdownVersionLaunchJvl = null
221 buildProperties = null
223 // the following values might be overridden by the CHANNEL switch
224 getdownDir = string("${getdownChannelName}/${JAVA_VERSION}")
225 getdownAppBase = string("${getdown_channel_base}/${getdownDir}")
226 getdownArchiveAppBase = getdown_archive_base
227 getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher}")
228 getdownAppDistDir = getdown_app_dir_alt
229 getdownImagesDir = string("${jalviewDir}/${getdown_images_dir}")
230 getdownImagesBuildDir = string("${buildDir}/imagemagick/getdown")
231 getdownSetAppBaseProperty = false // whether to pass the appbase and appdistdir to the application
232 reportRsyncCommand = false
233 jvlChannelName = CHANNEL.toLowerCase()
234 install4jSuffix = CHANNEL.substring(0, 1).toUpperCase() + CHANNEL.substring(1).toLowerCase(); // BUILD -> Build
235 install4jDMGDSStore = "${install4j_images_dir}/${install4j_dmg_ds_store}"
236 install4jDMGBackgroundImageDir = "${install4j_images_dir}"
237 install4jDMGBackgroundImageBuildDir = "build/imagemagick/install4j"
238 install4jDMGBackgroundImageFile = "${install4j_dmg_background}"
239 install4jInstallerName = "${jalview_name} Non-Release Installer"
240 install4jExecutableName = install4j_executable_name
241 install4jExtraScheme = "jalviewx"
242 install4jMacIconsFile = string("${install4j_images_dir}/${install4j_mac_icons_file}")
243 install4jWindowsIconsFile = string("${install4j_images_dir}/${install4j_windows_icons_file}")
244 install4jPngIconFile = string("${install4j_images_dir}/${install4j_png_icon_file}")
245 install4jBackground = string("${install4j_images_dir}/${install4j_background}")
246 install4jBuildDir = "${install4j_build_dir}/${JAVA_VERSION}"
247 install4jCheckSums = true
249 applicationName = "${jalview_name}"
253 // TODO: get bamboo build artifact URL for getdown artifacts
254 getdown_channel_base = bamboo_channelbase
255 getdownChannelName = string("${bamboo_planKey}/${JAVA_VERSION}")
256 getdownAppBase = string("${bamboo_channelbase}/${bamboo_planKey}${bamboo_getdown_channel_suffix}/${JAVA_VERSION}")
257 jvlChannelName += "_${getdownChannelName}"
258 // automatically add the test group Not-bamboo for exclusion
259 if ("".equals(testng_excluded_groups)) {
260 testng_excluded_groups = "Not-bamboo"
262 install4jExtraScheme = "jalviewb"
263 backgroundImageText = true
266 case [ "RELEASE", "JALVIEWJS-RELEASE" ]:
267 getdownAppDistDir = getdown_app_dir_release
268 getdownSetAppBaseProperty = true
269 reportRsyncCommand = true
271 install4jInstallerName = "${jalview_name} Installer"
275 getdownChannelName = CHANNEL.toLowerCase()+"/${JALVIEW_VERSION}"
276 getdownDir = string("${getdownChannelName}/${JAVA_VERSION}")
277 getdownAppBase = string("${getdown_channel_base}/${getdownDir}")
278 if (!file("${ARCHIVEDIR}/${package_dir}").exists()) {
279 throw new GradleException("Must provide an ARCHIVEDIR value to produce an archive distribution")
281 package_dir = string("${ARCHIVEDIR}/${package_dir}")
282 buildProperties = string("${ARCHIVEDIR}/${classes_dir}/${build_properties_file}")
285 reportRsyncCommand = true
286 install4jExtraScheme = "jalviewa"
290 getdownChannelName = string("archive/${JALVIEW_VERSION}")
291 getdownDir = string("${getdownChannelName}/${JAVA_VERSION}")
292 getdownAppBase = file(getdownAppBaseDir).toURI().toString()
293 if (!file("${ARCHIVEDIR}/${package_dir}").exists()) {
294 throw new GradleException("Must provide an ARCHIVEDIR value to produce an archive distribution [did not find '${ARCHIVEDIR}/${package_dir}']")
296 package_dir = string("${ARCHIVEDIR}/${package_dir}")
297 buildProperties = string("${ARCHIVEDIR}/${classes_dir}/${build_properties_file}")
300 reportRsyncCommand = true
301 getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher_local}")
302 install4jSuffix = "Archive"
303 install4jExtraScheme = "jalviewa"
306 case ~/^DEVELOP-([\.\-\w]*)$/:
307 def suffix = Matcher.lastMatcher[0][1]
308 reportRsyncCommand = true
309 getdownSetAppBaseProperty = true
310 JALVIEW_VERSION=JALVIEW_VERSION+"-d${suffix}-${buildDate}"
311 install4jSuffix = "Develop ${suffix}"
312 install4jExtraScheme = "jalviewd"
313 install4jInstallerName = "${jalview_name} Develop ${suffix} Installer"
314 getdownChannelName = string("develop-${suffix}")
315 getdownChannelDir = string("${getdown_website_dir}/${getdownChannelName}")
316 getdownAppBaseDir = string("${jalviewDir}/${getdownChannelDir}/${JAVA_VERSION}")
317 getdownDir = string("${getdownChannelName}/${JAVA_VERSION}")
318 getdownAppBase = string("${getdown_channel_base}/${getdownDir}")
319 channelSuffix = string(suffix)
320 backgroundImageText = true
324 reportRsyncCommand = true
325 getdownSetAppBaseProperty = true
326 // DEVELOP-RELEASE is usually associated with a Jalview release series so set the version
327 JALVIEW_VERSION=JALVIEW_VERSION+"-d${buildDate}"
329 install4jSuffix = "Develop"
330 install4jExtraScheme = "jalviewd"
331 install4jInstallerName = "${jalview_name} Develop Installer"
332 backgroundImageText = true
336 reportRsyncCommand = true
337 getdownSetAppBaseProperty = true
338 // Don't ignore transpile errors for release build
339 if (jalviewjs_ignore_transpile_errors.equals("true")) {
340 jalviewjs_ignore_transpile_errors = "false"
341 println("Setting jalviewjs_ignore_transpile_errors to 'false'")
343 JALVIEW_VERSION = JALVIEW_VERSION+"-test"
344 install4jSuffix = "Test"
345 install4jExtraScheme = "jalviewt"
346 install4jInstallerName = "${jalview_name} Test Installer"
347 backgroundImageText = true
350 case ~/^SCRATCH(|-[-\w]*)$/:
351 getdownChannelName = CHANNEL
352 JALVIEW_VERSION = JALVIEW_VERSION+"-"+CHANNEL
354 getdownDir = string("${getdownChannelName}/${JAVA_VERSION}")
355 getdownAppBase = string("${getdown_channel_base}/${getdownDir}")
356 reportRsyncCommand = true
357 install4jSuffix = "Scratch"
361 if (!file("${LOCALDIR}").exists()) {
362 throw new GradleException("Must provide a LOCALDIR value to produce a local distribution")
364 getdownAppBase = file(file("${LOCALDIR}").getAbsolutePath()).toURI().toString()
365 getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher_local}")
367 JALVIEW_VERSION = "TEST"
368 install4jSuffix = "Test-Local"
369 install4jExtraScheme = "jalviewt"
370 install4jInstallerName = "${jalview_name} Test Installer"
371 backgroundImageText = true
374 case [ "LOCAL", "JALVIEWJS" ]:
375 JALVIEW_VERSION = "TEST"
376 getdownAppBase = file(getdownAppBaseDir).toURI().toString()
377 getdownArchiveAppBase = file("${jalviewDir}/${getdown_archive_dir}").toURI().toString()
378 getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher_local}")
379 install4jExtraScheme = "jalviewl"
380 install4jCheckSums = false
383 default: // something wrong specified
384 throw new GradleException("CHANNEL must be one of BUILD, RELEASE, ARCHIVE, DEVELOP, TEST-RELEASE, SCRATCH-..., LOCAL [default]")
388 JALVIEW_VERSION_UNDERSCORES = JALVIEW_VERSION.replaceAll("\\.", "_")
389 hugoDataJsonFile = file("${jalviewDir}/${hugo_build_dir}/${hugo_data_installers_dir}/installers-${JALVIEW_VERSION_UNDERSCORES}.json")
390 hugoArchiveMdFile = file("${jalviewDir}/${hugo_build_dir}/${hugo_version_archive_dir}/Version-${JALVIEW_VERSION_UNDERSCORES}/_index.md")
391 // override getdownAppBase if requested
392 if (findProperty("getdown_appbase_override") != null) {
393 // revert to LOCAL if empty string
394 if (string(getdown_appbase_override) == "") {
395 getdownAppBase = file(getdownAppBaseDir).toURI().toString()
396 getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher_local}")
397 } else if (string(getdown_appbase_override).startsWith("file://")) {
398 getdownAppBase = string(getdown_appbase_override)
399 getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher_local}")
401 getdownAppBase = string(getdown_appbase_override)
403 println("Overriding getdown appbase with '${getdownAppBase}'")
405 // sanitise file name for jalview launcher file for this channel
406 jvlChannelName = jvlChannelName.replaceAll("[^\\w\\-]+", "_")
407 // install4j application and folder names
408 if (install4jSuffix == "") {
409 install4jBundleId = "${install4j_bundle_id}"
410 install4jWinApplicationId = install4j_release_win_application_id
412 applicationName = "${jalview_name} ${install4jSuffix}"
413 install4jBundleId = "${install4j_bundle_id}-" + install4jSuffix.toLowerCase()
414 // add int hash of install4jSuffix to the last part of the application_id
415 def id = install4j_release_win_application_id
416 def idsplitreverse = id.split("-").reverse()
417 idsplitreverse[0] = idsplitreverse[0].toInteger() + install4jSuffix.hashCode()
418 install4jWinApplicationId = idsplitreverse.reverse().join("-")
420 // sanitise folder and id names
421 // install4jApplicationFolder = e.g. "Jalview Build"
422 install4jApplicationFolder = applicationName
423 .replaceAll("[\"'~:/\\\\\\s]", "_") // replace all awkward filename chars " ' ~ : / \
424 .replaceAll("_+", "_") // collapse __
425 install4jInternalId = applicationName
427 .replaceAll("[^\\w\\-\\.]", "_") // replace other non [alphanumeric,_,-,.]
428 .replaceAll("_+", "") // collapse __
429 //.replaceAll("_*-_*", "-") // collapse _-_
430 install4jUnixApplicationFolder = applicationName
432 .replaceAll("[^\\w\\-\\.]", "_") // replace other non [alphanumeric,_,-,.]
433 .replaceAll("_+", "_") // collapse __
434 .replaceAll("_*-_*", "-") // collapse _-_
437 getdownWrapperLink = install4jUnixApplicationFolder // e.g. "jalview_local"
438 getdownAppDir = string("${getdownAppBaseDir}/${getdownAppDistDir}")
439 //getdownJ11libDir = "${getdownAppBaseDir}/${getdown_j11lib_dir}"
440 getdownResourceDir = string("${getdownAppBaseDir}/${getdown_resource_dir}")
441 getdownInstallDir = string("${getdownAppBaseDir}/${getdown_install_dir}")
442 getdownFilesDir = string("${jalviewDir}/${getdown_files_dir}/${JAVA_VERSION}/")
443 getdownFilesInstallDir = string("${getdownFilesDir}/${getdown_install_dir}")
444 /* compile without modules -- using classpath libraries
445 modules_compileClasspath = fileTree(dir: "${jalviewDir}/${j11modDir}", include: ["*.jar"])
446 modules_runtimeClasspath = modules_compileClasspath
452 apply plugin: "com.palantir.git-version"
453 def details = versionDetails()
454 gitHash = details.gitHash
455 gitBranch = details.branchName
456 } catch(org.gradle.api.internal.plugins.PluginApplicationException e) {
457 println("Not in a git repository. Using git values from RELEASE properties file.")
458 gitHash = releaseProps.getProperty("git.hash")
459 gitBranch = releaseProps.getProperty("git.branch")
460 } catch(java.lang.RuntimeException e1) {
461 throw new GradleException("Error with git-version plugin. Directory '.git' exists but versionDetails() cannot be found.")
464 println("Using a ${CHANNEL} profile.")
466 additional_compiler_args = []
467 // configure classpath/args for j8/j11 compilation
468 if (JAVA_VERSION.equals("1.8")) {
469 JAVA_INTEGER_VERSION = string("8")
472 libDistDir = j8libDir
473 compile_source_compatibility = 1.8
474 compile_target_compatibility = 1.8
475 // these are getdown.txt properties defined dependent on the JAVA_VERSION
476 getdownAltJavaMinVersion = string(findProperty("getdown_alt_java8_min_version"))
477 getdownAltJavaMaxVersion = string(findProperty("getdown_alt_java8_max_version"))
478 // this property is assigned below and expanded to multiple lines in the getdown task
479 getdownAltMultiJavaLocation = string(findProperty("getdown_alt_java8_txt_multi_java_location"))
480 // this property is for the Java library used in eclipse
481 eclipseJavaRuntimeName = string("JavaSE-1.8")
482 } else if (JAVA_VERSION.equals("11")) {
483 JAVA_INTEGER_VERSION = string("11")
485 libDistDir = j11libDir
486 compile_source_compatibility = 11
487 compile_target_compatibility = 11
488 getdownAltJavaMinVersion = string(findProperty("getdown_alt_java11_min_version"))
489 getdownAltJavaMaxVersion = string(findProperty("getdown_alt_java11_max_version"))
490 getdownAltMultiJavaLocation = string(findProperty("getdown_alt_java11_txt_multi_java_location"))
491 eclipseJavaRuntimeName = string("JavaSE-11")
492 /* compile without modules -- using classpath libraries
493 additional_compiler_args += [
494 '--module-path', modules_compileClasspath.asPath,
495 '--add-modules', j11modules
498 } else if (JAVA_VERSION.equals("17")) {
499 JAVA_INTEGER_VERSION = string("17")
501 libDistDir = j17libDir
502 compile_source_compatibility = 17
503 compile_target_compatibility = 17
504 getdownAltJavaMinVersion = string(findProperty("getdown_alt_java11_min_version"))
505 getdownAltJavaMaxVersion = string(findProperty("getdown_alt_java11_max_version"))
506 getdownAltMultiJavaLocation = string(findProperty("getdown_alt_java11_txt_multi_java_location"))
507 eclipseJavaRuntimeName = string("JavaSE-17")
508 /* compile without modules -- using classpath libraries
509 additional_compiler_args += [
510 '--module-path', modules_compileClasspath.asPath,
511 '--add-modules', j11modules
515 throw new GradleException("JAVA_VERSION=${JAVA_VERSION} not currently supported by Jalview")
520 JAVA_MIN_VERSION = JAVA_VERSION
521 JAVA_MAX_VERSION = JAVA_VERSION
522 jreInstallsDir = string(jre_installs_dir)
523 if (jreInstallsDir.startsWith("~/")) {
524 jreInstallsDir = System.getProperty("user.home") + jreInstallsDir.substring(1)
526 install4jDir = string("${jalviewDir}/${install4j_utils_dir}")
527 install4jConfFileName = string("jalview-install4j-conf.install4j")
528 install4jConfFile = file("${install4jDir}/${install4jConfFileName}")
529 install4jHomeDir = install4j_home_dir
530 if (install4jHomeDir.startsWith("~/")) {
531 install4jHomeDir = System.getProperty("user.home") + install4jHomeDir.substring(1)
534 resourceBuildDir = string("${buildDir}/resources")
535 resourcesBuildDir = string("${resourceBuildDir}/resources_build")
536 helpBuildDir = string("${resourceBuildDir}/help_build")
537 docBuildDir = string("${resourceBuildDir}/doc_build")
539 if (buildProperties == null) {
540 buildProperties = string("${resourcesBuildDir}/${build_properties_file}")
542 buildingHTML = string("${jalviewDir}/${doc_dir}/building.html")
543 helpParentDir = string("${jalviewDir}/${help_parent_dir}")
544 helpSourceDir = string("${helpParentDir}/${help_dir}")
545 helpFile = string("${helpBuildDir}/${help_dir}/help.jhm")
548 convertBinaryExpectedLocation = imagemagick_convert
549 if (convertBinaryExpectedLocation.startsWith("~/")) {
550 convertBinaryExpectedLocation = System.getProperty("user.home") + convertBinaryExpectedLocation.substring(1)
552 if (file(convertBinaryExpectedLocation).exists()) {
553 convertBinary = convertBinaryExpectedLocation
556 relativeBuildDir = file(jalviewDirAbsolutePath).toPath().relativize(buildDir.toPath())
557 jalviewjsBuildDir = string("${relativeBuildDir}/jalviewjs")
558 jalviewjsSiteDir = string("${jalviewjsBuildDir}/${jalviewjs_site_dir}")
560 jalviewjsTransferSiteJsDir = string(jalviewjsSiteDir)
562 jalviewjsTransferSiteJsDir = string("${jalviewjsBuildDir}/tmp/${jalviewjs_site_dir}_js")
564 jalviewjsTransferSiteLibDir = string("${jalviewjsBuildDir}/tmp/${jalviewjs_site_dir}_lib")
565 jalviewjsTransferSiteSwingJsDir = string("${jalviewjsBuildDir}/tmp/${jalviewjs_site_dir}_swingjs")
566 jalviewjsTransferSiteCoreDir = string("${jalviewjsBuildDir}/tmp/${jalviewjs_site_dir}_core")
567 jalviewjsJalviewCoreHtmlFile = string("")
568 jalviewjsJalviewCoreName = string(jalviewjs_core_name)
569 jalviewjsCoreClasslists = []
570 jalviewjsJalviewTemplateName = string(jalviewjs_name)
571 jalviewjsJ2sSettingsFileName = string("${jalviewDir}/${jalviewjs_j2s_settings}")
572 jalviewjsJ2sAltSettingsFileName = string("${jalviewDir}/${jalviewjs_j2s_alt_settings}")
573 jalviewjsJ2sProps = null
574 jalviewjsJ2sPlugin = jalviewjs_j2s_plugin
575 jalviewjsStderrLaunchFilename = "${jalviewjsSiteDir}/"+(file(jalviewjs_stderr_launch).getName())
577 eclipseWorkspace = null
578 eclipseBinary = string("")
579 eclipseVersion = string("")
582 jalviewjsChromiumUserDir = "${jalviewjsBuildDir}/${jalviewjs_chromium_user_dir}"
583 jalviewjsChromiumProfileDir = "${ext.jalviewjsChromiumUserDir}/${jalviewjs_chromium_profile_name}"
593 outputDir = file(classesDir)
597 srcDirs = [ resourcesBuildDir, docBuildDir, helpBuildDir ]
600 compileClasspath = files(sourceSets.main.java.outputDir)
601 compileClasspath += fileTree(dir: "${jalviewDir}/${libDir}", include: ["*.jar"])
603 runtimeClasspath = compileClasspath
604 runtimeClasspath += files(sourceSets.main.resources.srcDirs)
609 srcDirs cloverInstrDir
610 outputDir = cloverClassesDir
614 srcDirs = sourceSets.main.resources.srcDirs
617 compileClasspath = files( sourceSets.clover.java.outputDir )
618 //compileClasspath += files( testClassesDir )
619 compileClasspath += fileTree(dir: "${jalviewDir}/${libDir}", include: ["*.jar"])
620 compileClasspath += fileTree(dir: "${jalviewDir}/${clover_lib_dir}", include: ["*.jar"])
621 compileClasspath += fileTree(dir: "${jalviewDir}/${utils_dir}/testnglibs", include: ["**/*.jar"])
623 runtimeClasspath = compileClasspath
628 srcDirs testSourceDir
629 outputDir = file(testClassesDir)
633 srcDirs = useClover ? sourceSets.clover.resources.srcDirs : sourceSets.main.resources.srcDirs
636 compileClasspath = files( sourceSets.test.java.outputDir )
637 compileClasspath += useClover ? sourceSets.clover.compileClasspath : sourceSets.main.compileClasspath
638 compileClasspath += fileTree(dir: "${jalviewDir}/${utils_dir}/testnglibs", include: ["**/*.jar"])
640 runtimeClasspath = compileClasspath
641 runtimeClasspath += files(sourceSets.test.resources.srcDirs)
647 // eclipse project and settings files creation, also used by buildship
650 name = eclipse_project_name
652 natures 'org.eclipse.jdt.core.javanature',
653 'org.eclipse.jdt.groovy.core.groovyNature',
654 'org.eclipse.buildship.core.gradleprojectnature'
656 buildCommand 'org.eclipse.jdt.core.javabuilder'
657 buildCommand 'org.eclipse.buildship.core.gradleprojectbuilder'
661 //defaultOutputDir = sourceSets.main.java.outputDir
662 configurations.each{ c->
663 if (c.isCanBeResolved()) {
664 minusConfigurations += [c]
668 plusConfigurations = [ ]
672 def removeTheseToo = []
673 HashMap<String, Boolean> alreadyAddedSrcPath = new HashMap<>();
674 cp.entries.each { entry ->
675 // This conditional removes all src classpathentries that a) have already been added or b) aren't "src" or "test".
676 // e.g. this removes the resources dir being copied into bin/main, bin/test AND bin/clover
677 // we add the resources and help/help dirs in as libs afterwards (see below)
678 if (entry.kind == 'src') {
679 if (alreadyAddedSrcPath.getAt(entry.path) || !(entry.path == bareSourceDir || entry.path == bareTestSourceDir)) {
680 removeTheseToo += entry
682 alreadyAddedSrcPath.putAt(entry.path, true)
687 cp.entries.removeAll(removeTheseToo)
689 //cp.entries += new Output("${eclipse_bin_dir}/main")
690 if (file(helpParentDir).isDirectory()) {
691 cp.entries += new Library(fileReference(helpParentDir))
693 if (file(resourceDir).isDirectory()) {
694 cp.entries += new Library(fileReference(resourceDir))
697 HashMap<String, Boolean> alreadyAddedLibPath = new HashMap<>();
699 sourceSets.main.compileClasspath.findAll { it.name.endsWith(".jar") }.any {
700 //don't want to add outputDir as eclipse is using its own output dir in bin/main
701 if (it.isDirectory() || ! it.exists()) {
702 // don't add dirs to classpath, especially if they don't exist
703 return false // groovy "continue" in .any closure
705 def itPath = it.toString()
706 if (itPath.startsWith("${jalviewDirAbsolutePath}/")) {
707 // make relative path
708 itPath = itPath.substring(jalviewDirAbsolutePath.length()+1)
710 if (alreadyAddedLibPath.get(itPath)) {
711 //println("Not adding duplicate entry "+itPath)
713 //println("Adding entry "+itPath)
714 cp.entries += new Library(fileReference(itPath))
715 alreadyAddedLibPath.put(itPath, true)
719 sourceSets.test.compileClasspath.findAll { it.name.endsWith(".jar") }.any {
720 //no longer want to add outputDir as eclipse is using its own output dir in bin/main
721 if (it.isDirectory() || ! it.exists()) {
722 // don't add dirs to classpath
723 return false // groovy "continue" in .any closure
726 def itPath = it.toString()
727 if (itPath.startsWith("${jalviewDirAbsolutePath}/")) {
728 itPath = itPath.substring(jalviewDirAbsolutePath.length()+1)
730 if (alreadyAddedLibPath.get(itPath)) {
733 def lib = new Library(fileReference(itPath))
734 lib.entryAttributes["test"] = "true"
736 alreadyAddedLibPath.put(itPath, true)
744 containers 'org.eclipse.buildship.core.gradleclasspathcontainer'
749 // for the IDE, use java 11 compatibility
750 sourceCompatibility = compile_source_compatibility
751 targetCompatibility = compile_target_compatibility
752 javaRuntimeName = eclipseJavaRuntimeName
754 // add in jalview project specific properties/preferences into eclipse core preferences
756 withProperties { props ->
757 def jalview_prefs = new Properties()
758 def ins = new FileInputStream("${jalviewDirAbsolutePath}/${eclipse_extra_jdt_prefs_file}")
759 jalview_prefs.load(ins)
761 jalview_prefs.forEach { t, v ->
762 if (props.getAt(t) == null) {
766 // codestyle file -- overrides previous formatter prefs
767 def csFile = file("${jalviewDirAbsolutePath}/${eclipse_codestyle_file}")
768 if (csFile.exists()) {
769 XmlParser parser = new XmlParser()
770 def profiles = parser.parse(csFile)
771 def profile = profiles.'profile'.find { p -> (p.'@kind' == "CodeFormatterProfile" && p.'@name' == "Jalview") }
772 if (profile != null) {
773 profile.'setting'.each { s ->
775 def value = s.'@value'
776 if (id != null && value != null) {
777 props.putAt(id, value)
788 // Don't want these to be activated if in headless build
789 synchronizationTasks "eclipseSynchronizationTask"
790 //autoBuildTasks "eclipseAutoBuildTask"
796 /* hack to change eclipse prefs in .settings files other than org.eclipse.jdt.core.prefs */
797 // Class to allow updating arbitrary properties files
798 class PropertiesFile extends PropertiesPersistableConfigurationObject {
799 public PropertiesFile(PropertiesTransformer t) { super(t); }
800 @Override protected void load(Properties properties) { }
801 @Override protected void store(Properties properties) { }
802 @Override protected String getDefaultResourceName() { return ""; }
803 // This is necessary, because PropertiesPersistableConfigurationObject fails
804 // if no default properties file exists.
805 @Override public void loadDefaults() { load(new StringBufferInputStream("")); }
808 // Task to update arbitrary properties files (set outputFile)
809 class PropertiesFileTask extends PropertiesGeneratorTask<PropertiesFile> {
810 private final PropertiesFileContentMerger file;
811 public PropertiesFileTask() { file = new PropertiesFileContentMerger(getTransformer()); }
812 protected PropertiesFile create() { return new PropertiesFile(getTransformer()); }
813 protected void configure(PropertiesFile props) {
814 file.getBeforeMerged().execute(props); file.getWhenMerged().execute(props);
816 public void file(Closure closure) { ConfigureUtil.configure(closure, file); }
819 task eclipseUIPreferences(type: PropertiesFileTask) {
820 description = "Generate Eclipse additional settings"
821 def filename = "org.eclipse.jdt.ui.prefs"
822 outputFile = "$projectDir/.settings/${filename}" as File
825 it.load new FileInputStream("$projectDir/utils/eclipse/${filename}" as String)
830 task eclipseGroovyCorePreferences(type: PropertiesFileTask) {
831 description = "Generate Eclipse additional settings"
832 def filename = "org.eclipse.jdt.groovy.core.prefs"
833 outputFile = "$projectDir/.settings/${filename}" as File
836 it.load new FileInputStream("$projectDir/utils/eclipse/${filename}" as String)
841 task eclipseAllPreferences {
843 dependsOn eclipseUIPreferences
844 dependsOn eclipseGroovyCorePreferences
847 eclipseUIPreferences.mustRunAfter eclipseJdt
848 eclipseGroovyCorePreferences.mustRunAfter eclipseJdt
850 /* end of eclipse preferences hack */
858 delete cloverBuildDir
859 delete cloverReportDir
864 task cloverInstrJava(type: JavaExec) {
865 group = "Verification"
866 description = "Create clover instrumented source java files"
868 dependsOn cleanClover
870 inputs.files(sourceSets.main.allJava)
871 outputs.dir(cloverInstrDir)
873 //classpath = fileTree(dir: "${jalviewDir}/${clover_lib_dir}", include: ["*.jar"])
874 classpath = sourceSets.clover.compileClasspath
875 main = "com.atlassian.clover.CloverInstr"
883 cloverInstrDir.getPath(),
885 def srcFiles = sourceSets.main.allJava.files
888 { file -> file.absolutePath }
891 args argsList.toArray()
894 delete cloverInstrDir
895 println("Clover: About to instrument "+srcFiles.size() +" files")
900 task cloverInstrTests(type: JavaExec) {
901 group = "Verification"
902 description = "Create clover instrumented source test files"
904 dependsOn cleanClover
906 inputs.files(testDir)
907 outputs.dir(cloverTestInstrDir)
909 classpath = sourceSets.clover.compileClasspath
910 main = "com.atlassian.clover.CloverInstr"
920 cloverTestInstrDir.getPath(),
922 args argsList.toArray()
925 delete cloverTestInstrDir
926 println("Clover: About to instrument test files")
932 group = "Verification"
933 description = "Create clover instrumented all source files"
935 dependsOn cloverInstrJava
936 dependsOn cloverInstrTests
940 cloverClasses.dependsOn cloverInstr
943 task cloverConsoleReport(type: JavaExec) {
944 group = "Verification"
945 description = "Creates clover console report"
948 file(cloverDb).exists()
951 inputs.dir cloverClassesDir
953 classpath = sourceSets.clover.runtimeClasspath
954 main = "com.atlassian.clover.reporters.console.ConsoleReporter"
956 if (cloverreport_mem.length() > 0) {
957 maxHeapSize = cloverreport_mem
959 if (cloverreport_jvmargs.length() > 0) {
960 jvmArgs Arrays.asList(cloverreport_jvmargs.split(" "))
970 args argsList.toArray()
974 task cloverHtmlReport(type: JavaExec) {
975 group = "Verification"
976 description = "Creates clover HTML report"
979 file(cloverDb).exists()
982 def cloverHtmlDir = cloverReportDir
983 inputs.dir cloverClassesDir
984 outputs.dir cloverHtmlDir
986 classpath = sourceSets.clover.runtimeClasspath
987 main = "com.atlassian.clover.reporters.html.HtmlReporter"
989 if (cloverreport_mem.length() > 0) {
990 maxHeapSize = cloverreport_mem
992 if (cloverreport_jvmargs.length() > 0) {
993 jvmArgs Arrays.asList(cloverreport_jvmargs.split(" "))
1004 if (cloverreport_html_options.length() > 0) {
1005 argsList += cloverreport_html_options.split(" ")
1008 args argsList.toArray()
1012 task cloverXmlReport(type: JavaExec) {
1013 group = "Verification"
1014 description = "Creates clover XML report"
1017 file(cloverDb).exists()
1020 def cloverXmlFile = "${cloverReportDir}/clover.xml"
1021 inputs.dir cloverClassesDir
1022 outputs.file cloverXmlFile
1024 classpath = sourceSets.clover.runtimeClasspath
1025 main = "com.atlassian.clover.reporters.xml.XMLReporter"
1027 if (cloverreport_mem.length() > 0) {
1028 maxHeapSize = cloverreport_mem
1030 if (cloverreport_jvmargs.length() > 0) {
1031 jvmArgs Arrays.asList(cloverreport_jvmargs.split(" "))
1042 if (cloverreport_xml_options.length() > 0) {
1043 argsList += cloverreport_xml_options.split(" ")
1046 args argsList.toArray()
1051 group = "Verification"
1052 description = "Creates clover reports"
1054 dependsOn cloverXmlReport
1055 dependsOn cloverHtmlReport
1062 sourceCompatibility = compile_source_compatibility
1063 targetCompatibility = compile_target_compatibility
1064 options.compilerArgs += additional_compiler_args
1065 print ("Setting target compatibility to "+targetCompatibility+"\n")
1067 //classpath += configurations.cloverRuntime
1073 // JBP->BS should the print statement in doFirst refer to compile_target_compatibility ?
1074 sourceCompatibility = compile_source_compatibility
1075 targetCompatibility = compile_target_compatibility
1076 options.compilerArgs += additional_compiler_args
1077 options.encoding = "UTF-8"
1079 print ("Setting target compatibility to "+compile_target_compatibility+"\n")
1086 sourceCompatibility = compile_source_compatibility
1087 targetCompatibility = compile_target_compatibility
1088 options.compilerArgs += additional_compiler_args
1090 print ("Setting target compatibility to "+targetCompatibility+"\n")
1097 delete sourceSets.main.java.outputDir
1103 dependsOn cleanClover
1105 delete sourceSets.test.java.outputDir
1110 // format is a string like date.format("dd MMMM yyyy")
1111 def getDate(format) {
1112 return date.format(format)
1116 def convertMdToHtml (FileTree mdFiles, File cssFile) {
1117 MutableDataSet options = new MutableDataSet()
1119 def extensions = new ArrayList<>()
1120 extensions.add(AnchorLinkExtension.create())
1121 extensions.add(AutolinkExtension.create())
1122 extensions.add(StrikethroughExtension.create())
1123 extensions.add(TaskListExtension.create())
1124 extensions.add(TablesExtension.create())
1125 extensions.add(TocExtension.create())
1127 options.set(Parser.EXTENSIONS, extensions)
1129 // set GFM table parsing options
1130 options.set(TablesExtension.WITH_CAPTION, false)
1131 options.set(TablesExtension.COLUMN_SPANS, false)
1132 options.set(TablesExtension.MIN_HEADER_ROWS, 1)
1133 options.set(TablesExtension.MAX_HEADER_ROWS, 1)
1134 options.set(TablesExtension.APPEND_MISSING_COLUMNS, true)
1135 options.set(TablesExtension.DISCARD_EXTRA_COLUMNS, true)
1136 options.set(TablesExtension.HEADER_SEPARATOR_COLUMN_MATCH, true)
1138 options.set(AnchorLinkExtension.ANCHORLINKS_SET_ID, false)
1139 options.set(AnchorLinkExtension.ANCHORLINKS_ANCHOR_CLASS, "anchor")
1140 options.set(AnchorLinkExtension.ANCHORLINKS_SET_NAME, true)
1141 options.set(AnchorLinkExtension.ANCHORLINKS_TEXT_PREFIX, "<span class=\"octicon octicon-link\"></span>")
1143 Parser parser = Parser.builder(options).build()
1144 HtmlRenderer renderer = HtmlRenderer.builder(options).build()
1146 mdFiles.each { mdFile ->
1147 // add table of contents
1148 def mdText = "[TOC]\n"+mdFile.text
1150 // grab the first top-level title
1152 def titleRegex = /(?m)^#(\s+|([^#]))(.*)/
1153 def matcher = mdText =~ titleRegex
1154 if (matcher.size() > 0) {
1155 // matcher[0][2] is the first character of the title if there wasn't any whitespace after the #
1156 title = (matcher[0][2] != null ? matcher[0][2] : "")+matcher[0][3]
1158 // or use the filename if none found
1159 if (title == null) {
1160 title = mdFile.getName()
1163 Node document = parser.parse(mdText)
1164 String htmlBody = renderer.render(document)
1165 def htmlText = '''<html>
1166 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
1167 <html xmlns="http://www.w3.org/1999/xhtml">
1169 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
1170 <meta http-equiv="Content-Style-Type" content="text/css" />
1171 <meta name="generator" content="flexmark" />
1173 htmlText += ((title != null) ? " <title>${title}</title>" : '' )
1175 <style type="text/css">code{white-space: pre;}</style>
1177 htmlText += ((cssFile != null) ? cssFile.text : '')
1178 htmlText += '''</head>
1181 htmlText += htmlBody
1187 def htmlFilePath = mdFile.getPath().replaceAll(/\..*?$/, ".html")
1188 def htmlFile = file(htmlFilePath)
1189 println("Creating ${htmlFilePath}")
1190 htmlFile.text = htmlText
1195 task copyDocs(type: Copy) {
1196 def inputDir = "${jalviewDir}/${doc_dir}"
1197 def outputDir = "${docBuildDir}/${doc_dir}"
1201 include('**/*.html')
1203 filter(ReplaceTokens,
1207 'Version-Rel': JALVIEW_VERSION,
1208 'Year-Rel': getDate("yyyy")
1215 exclude('**/*.html')
1220 inputs.dir(inputDir)
1221 outputs.dir(outputDir)
1225 task convertMdFiles {
1227 def mdFiles = fileTree(dir: docBuildDir, include: "**/*.md")
1228 def cssFile = file("${jalviewDir}/${flexmark_css}")
1231 convertMdToHtml(mdFiles, cssFile)
1234 inputs.files(mdFiles)
1235 inputs.file(cssFile)
1238 mdFiles.each { mdFile ->
1239 def htmlFilePath = mdFile.getPath().replaceAll(/\..*?$/, ".html")
1240 htmlFiles.add(file(htmlFilePath))
1242 outputs.files(htmlFiles)
1246 def hugoTemplateSubstitutions(String input, Map extras=null) {
1247 def replacements = [
1248 DATE: getDate("yyyy-MM-dd"),
1249 CHANNEL: propertiesChannelName,
1250 APPLICATION_NAME: applicationName,
1252 GIT_BRANCH: gitBranch,
1253 VERSION: JALVIEW_VERSION,
1254 JAVA_VERSION: JAVA_VERSION,
1255 VERSION_UNDERSCORES: JALVIEW_VERSION_UNDERSCORES,
1260 if (extras != null) {
1261 extras.each{ k, v ->
1262 output = output.replaceAll("__${k}__", ((v == null)?"":v))
1265 replacements.each{ k, v ->
1266 output = output.replaceAll("__${k}__", ((v == null)?"":v))
1271 def mdFileComponents(File mdFile, def dateOnly=false) {
1274 if (mdFile.exists()) {
1275 def inFrontMatter = false
1276 def firstLine = true
1277 mdFile.eachLine { line ->
1278 if (line.matches("---")) {
1279 def prev = inFrontMatter
1280 inFrontMatter = firstLine
1281 if (inFrontMatter != prev)
1284 if (inFrontMatter) {
1286 if (m = line =~ /^date:\s*(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})/) {
1287 map["date"] = new Date().parse("yyyy-MM-dd HH:mm:ss", m[0][1])
1288 } else if (m = line =~ /^date:\s*(\d{4}-\d{2}-\d{2})/) {
1289 map["date"] = new Date().parse("yyyy-MM-dd", m[0][1])
1290 } else if (m = line =~ /^channel:\s*(\S+)/) {
1291 map["channel"] = m[0][1]
1292 } else if (m = line =~ /^version:\s*(\S+)/) {
1293 map["version"] = m[0][1]
1294 } else if (m = line =~ /^\s*([^:]+)\s*:\s*(\S.*)/) {
1295 map[ m[0][1] ] = m[0][2]
1297 if (dateOnly && map["date"] != null) {
1303 content += line+"\n"
1308 return dateOnly ? map["date"] : [map, content]
1311 task hugoTemplates {
1313 description "Create partially populated md pages for hugo website build"
1315 def hugoTemplatesDir = file("${jalviewDir}/${hugo_templates_dir}")
1316 def hugoBuildDir = "${jalviewDir}/${hugo_build_dir}"
1317 def templateFiles = fileTree(dir: hugoTemplatesDir)
1318 def releaseMdFile = file("${jalviewDir}/${releases_dir}/release-${JALVIEW_VERSION_UNDERSCORES}.md")
1319 def whatsnewMdFile = file("${jalviewDir}/${whatsnew_dir}/whatsnew-${JALVIEW_VERSION_UNDERSCORES}.md")
1320 def oldJvlFile = file("${jalviewDir}/${hugo_old_jvl}")
1321 def jalviewjsFile = file("${jalviewDir}/${hugo_jalviewjs}")
1324 // specific release template for version archive
1327 def givenDate = null
1328 def givenChannel = null
1329 def givenVersion = null
1330 if (CHANNEL == "RELEASE") {
1331 def (map, content) = mdFileComponents(releaseMdFile)
1332 givenDate = map.date
1333 givenChannel = map.channel
1334 givenVersion = map.version
1336 if (givenVersion != null && givenVersion != JALVIEW_VERSION) {
1337 throw new GradleException("'version' header (${givenVersion}) found in ${releaseMdFile} does not match JALVIEW_VERSION (${JALVIEW_VERSION})")
1340 if (whatsnewMdFile.exists())
1341 whatsnew = whatsnewMdFile.text
1344 def oldJvl = oldJvlFile.exists() ? oldJvlFile.collect{it} : []
1345 def jalviewjsLink = jalviewjsFile.exists() ? jalviewjsFile.collect{it} : []
1347 def changesHugo = null
1348 if (changes != null) {
1349 changesHugo = '<div class="release_notes">\n\n'
1350 def inSection = false
1351 changes.eachLine { line ->
1353 if (m = line =~ /^##([^#].*)$/) {
1355 changesHugo += "</div>\n\n"
1357 def section = m[0][1].trim()
1358 section = section.toLowerCase()
1359 section = section.replaceAll(/ +/, "_")
1360 section = section.replaceAll(/[^a-z0-9_\-]/, "")
1361 changesHugo += "<div class=\"${section}\">\n\n"
1363 } else if (m = line =~ /^(\s*-\s*)<!--([^>]+)-->(.*?)(<br\/?>)?\s*$/) {
1364 def comment = m[0][2].trim()
1365 if (comment != "") {
1366 comment = comment.replaceAll('"', """)
1368 comment.eachMatch(/JAL-\d+/) { jal -> issuekeys += jal }
1369 def newline = m[0][1]
1370 if (comment.trim() != "")
1371 newline += "{{<comment>}}${comment}{{</comment>}} "
1372 newline += m[0][3].trim()
1373 if (issuekeys.size() > 0)
1374 newline += " {{< jal issue=\"${issuekeys.join(",")}\" alt=\"${comment}\" >}}"
1375 if (m[0][4] != null)
1380 changesHugo += line+"\n"
1383 changesHugo += "\n</div>\n\n"
1385 changesHugo += '</div>'
1388 templateFiles.each{ templateFile ->
1389 def newFileName = string(hugoTemplateSubstitutions(templateFile.getName()))
1390 def relPath = hugoTemplatesDir.toPath().relativize(templateFile.toPath()).getParent()
1391 def newRelPathName = hugoTemplateSubstitutions( relPath.toString() )
1393 def outPathName = string("${hugoBuildDir}/$newRelPathName")
1397 rename(templateFile.getName(), newFileName)
1401 def newFile = file("${outPathName}/${newFileName}".toString())
1402 def content = newFile.text
1403 newFile.text = hugoTemplateSubstitutions(content,
1406 CHANGES: changesHugo,
1407 DATE: givenDate == null ? "" : givenDate.format("yyyy-MM-dd"),
1408 DRAFT: givenDate == null ? "true" : "false",
1409 JALVIEWJSLINK: jalviewjsLink.contains(JALVIEW_VERSION) ? "true" : "false",
1410 JVL_HEADER: oldJvl.contains(JALVIEW_VERSION) ? "jvl: true" : ""
1417 inputs.file(oldJvlFile)
1418 inputs.dir(hugoTemplatesDir)
1419 inputs.property("JALVIEW_VERSION", { JALVIEW_VERSION })
1420 inputs.property("CHANNEL", { CHANNEL })
1423 def getMdDate(File mdFile) {
1424 return mdFileComponents(mdFile, true)
1427 def getMdSections(String content) {
1429 def sectionContent = ""
1430 def sectionName = null
1431 content.eachLine { line ->
1433 if (m = line =~ /^##([^#].*)$/) {
1434 if (sectionName != null) {
1435 sections[sectionName] = sectionContent
1439 sectionName = m[0][1].trim()
1440 sectionName = sectionName.toLowerCase()
1441 sectionName = sectionName.replaceAll(/ +/, "_")
1442 sectionName = sectionName.replaceAll(/[^a-z0-9_\-]/, "")
1443 } else if (sectionName != null) {
1444 sectionContent += line+"\n"
1447 if (sectionContent != null) {
1448 sections[sectionName] = sectionContent
1454 task copyHelp(type: Copy) {
1455 def inputDir = helpSourceDir
1456 def outputDir = "${helpBuildDir}/${help_dir}"
1460 include('**/*.html')
1464 filter(ReplaceTokens,
1468 'Version-Rel': JALVIEW_VERSION,
1469 'Year-Rel': getDate("yyyy")
1476 exclude('**/*.html')
1483 inputs.dir(inputDir)
1484 outputs.files(helpFile)
1485 outputs.dir(outputDir)
1489 task releasesTemplates {
1491 description "Recreate whatsNew.html and releases.html from markdown files and templates in help"
1495 def releasesTemplateFile = file("${jalviewDir}/${releases_template}")
1496 def whatsnewTemplateFile = file("${jalviewDir}/${whatsnew_template}")
1497 def releasesHtmlFile = file("${helpBuildDir}/${help_dir}/${releases_html}")
1498 def whatsnewHtmlFile = file("${helpBuildDir}/${help_dir}/${whatsnew_html}")
1499 def releasesMdDir = "${jalviewDir}/${releases_dir}"
1500 def whatsnewMdDir = "${jalviewDir}/${whatsnew_dir}"
1503 def releaseMdFile = file("${releasesMdDir}/release-${JALVIEW_VERSION_UNDERSCORES}.md")
1504 def whatsnewMdFile = file("${whatsnewMdDir}/whatsnew-${JALVIEW_VERSION_UNDERSCORES}.md")
1506 if (CHANNEL == "RELEASE") {
1507 if (!releaseMdFile.exists()) {
1508 throw new GradleException("File ${releaseMdFile} must be created for RELEASE")
1510 if (!whatsnewMdFile.exists()) {
1511 throw new GradleException("File ${whatsnewMdFile} must be created for RELEASE")
1515 def releaseFiles = fileTree(dir: releasesMdDir, include: "release-*.md")
1516 def releaseFilesDates = releaseFiles.collectEntries {
1517 [(it): getMdDate(it)]
1519 releaseFiles = releaseFiles.sort { a,b -> releaseFilesDates[a].compareTo(releaseFilesDates[b]) }
1521 def releasesTemplate = releasesTemplateFile.text
1522 def m = releasesTemplate =~ /(?s)__VERSION_LOOP_START__(.*)__VERSION_LOOP_END__/
1523 def versionTemplate = m[0][1]
1525 MutableDataSet options = new MutableDataSet()
1527 def extensions = new ArrayList<>()
1528 options.set(Parser.EXTENSIONS, extensions)
1529 options.set(Parser.HTML_BLOCK_COMMENT_ONLY_FULL_LINE, true)
1531 Parser parser = Parser.builder(options).build()
1532 HtmlRenderer renderer = HtmlRenderer.builder(options).build()
1534 def actualVersions = releaseFiles.collect { rf ->
1535 def (rfMap, rfContent) = mdFileComponents(rf)
1536 return rfMap.version
1538 def versionsHtml = ""
1539 def linkedVersions = []
1540 releaseFiles.reverse().each { rFile ->
1541 def (rMap, rContent) = mdFileComponents(rFile)
1543 def versionLink = ""
1544 def partialVersion = ""
1545 def firstPart = true
1546 rMap.version.split("\\.").each { part ->
1547 def displayPart = ( firstPart ? "" : "." ) + part
1548 partialVersion += displayPart
1550 linkedVersions.contains(partialVersion)
1551 || ( actualVersions.contains(partialVersion) && partialVersion != rMap.version )
1553 versionLink += displayPart
1555 versionLink += "<a id=\"Jalview.${partialVersion}\">${displayPart}</a>"
1556 linkedVersions += partialVersion
1560 def displayDate = releaseFilesDates[rFile].format("dd/MM/yyyy")
1563 def rContentProcessed = ""
1564 rContent.eachLine { line ->
1565 if (lm = line =~ /^(\s*-)(\s*<!--[^>]*?-->)(.*)$/) {
1566 line = "${lm[0][1]}${lm[0][3]}${lm[0][2]}"
1567 } else if (lm = line =~ /^###([^#]+.*)$/) {
1568 line = "_${lm[0][1].trim()}_"
1570 rContentProcessed += line + "\n"
1573 def rContentSections = getMdSections(rContentProcessed)
1574 def rVersion = versionTemplate
1575 if (rVersion != "") {
1576 def rNewFeatures = rContentSections["new_features"]
1577 def rIssuesResolved = rContentSections["issues_resolved"]
1578 Node newFeaturesNode = parser.parse(rNewFeatures)
1579 String newFeaturesHtml = renderer.render(newFeaturesNode)
1580 Node issuesResolvedNode = parser.parse(rIssuesResolved)
1581 String issuesResolvedHtml = renderer.render(issuesResolvedNode)
1582 rVersion = hugoTemplateSubstitutions(rVersion,
1584 VERSION: rMap.version,
1585 VERSION_LINK: versionLink,
1586 DISPLAY_DATE: displayDate,
1587 NEW_FEATURES: newFeaturesHtml,
1588 ISSUES_RESOLVED: issuesResolvedHtml
1591 versionsHtml += rVersion
1595 releasesTemplate = releasesTemplate.replaceAll("(?s)__VERSION_LOOP_START__.*__VERSION_LOOP_END__", versionsHtml)
1596 releasesTemplate = hugoTemplateSubstitutions(releasesTemplate)
1597 releasesHtmlFile.text = releasesTemplate
1599 if (whatsnewMdFile.exists()) {
1600 def wnDisplayDate = releaseFilesDates[releaseMdFile] != null ? releaseFilesDates[releaseMdFile].format("dd MMMM yyyy") : ""
1601 def whatsnewMd = hugoTemplateSubstitutions(whatsnewMdFile.text)
1602 Node whatsnewNode = parser.parse(whatsnewMd)
1603 String whatsnewHtml = renderer.render(whatsnewNode)
1604 whatsnewHtml = whatsnewTemplateFile.text.replaceAll("__WHATS_NEW__", whatsnewHtml)
1605 whatsnewHtmlFile.text = hugoTemplateSubstitutions(whatsnewHtml,
1607 VERSION: JALVIEW_VERSION,
1608 DISPLAY_DATE: wnDisplayDate
1611 } else if (gradle.taskGraph.hasTask(":linkCheck")) {
1612 whatsnewHtmlFile.text = "Development build " + getDate("yyyy-MM-dd HH:mm:ss")
1617 inputs.file(releasesTemplateFile)
1618 inputs.file(whatsnewTemplateFile)
1619 inputs.dir(releasesMdDir)
1620 inputs.dir(whatsnewMdDir)
1621 outputs.file(releasesHtmlFile)
1622 outputs.file(whatsnewHtmlFile)
1626 task copyResources(type: Copy) {
1628 description = "Copy (and make text substitutions in) the resources dir to the build area"
1630 def inputDir = resourceDir
1631 def outputDir = resourcesBuildDir
1635 include('**/*.html')
1637 filter(ReplaceTokens,
1641 'Version-Rel': JALVIEW_VERSION,
1642 'Year-Rel': getDate("yyyy")
1649 exclude('**/*.html')
1654 inputs.dir(inputDir)
1655 outputs.dir(outputDir)
1658 task copyChannelResources(type: Copy) {
1659 dependsOn copyResources
1661 description = "Copy the channel resources dir to the build resources area"
1663 def inputDir = "${channelDir}/${resource_dir}"
1664 def outputDir = resourcesBuildDir
1666 include(channel_props)
1667 filter(ReplaceTokens,
1671 'SUFFIX': channelSuffix
1676 exclude(channel_props)
1680 inputs.dir(inputDir)
1681 outputs.dir(outputDir)
1684 task createBuildProperties(type: WriteProperties) {
1685 dependsOn copyResources
1687 description = "Create the ${buildProperties} file"
1689 inputs.dir(sourceDir)
1690 inputs.dir(resourcesBuildDir)
1691 outputFile (buildProperties)
1692 // taking time specific comment out to allow better incremental builds
1693 comment "--Jalview Build Details--\n"+getDate("yyyy-MM-dd HH:mm:ss")
1694 //comment "--Jalview Build Details--\n"+getDate("yyyy-MM-dd")
1695 property "BUILD_DATE", getDate("HH:mm:ss dd MMMM yyyy")
1696 property "VERSION", JALVIEW_VERSION
1697 property "INSTALLATION", INSTALLATION+" git-commit:"+gitHash+" ["+gitBranch+"]"
1698 property "JAVA_COMPILE_VERSION", JAVA_INTEGER_VERSION
1699 if (getdownSetAppBaseProperty) {
1700 property "GETDOWNAPPBASE", getdownAppBase
1701 property "GETDOWNAPPDISTDIR", getdownAppDistDir
1703 outputs.file(outputFile)
1707 task buildIndices(type: JavaExec) {
1709 classpath = sourceSets.main.compileClasspath
1710 main = "com.sun.java.help.search.Indexer"
1711 workingDir = "${helpBuildDir}/${help_dir}"
1714 inputs.dir("${workingDir}/${argDir}")
1716 outputs.dir("${classesDir}/doc")
1717 outputs.dir("${classesDir}/help")
1718 outputs.file("${workingDir}/JavaHelpSearch/DOCS")
1719 outputs.file("${workingDir}/JavaHelpSearch/DOCS.TAB")
1720 outputs.file("${workingDir}/JavaHelpSearch/OFFSETS")
1721 outputs.file("${workingDir}/JavaHelpSearch/POSITIONS")
1722 outputs.file("${workingDir}/JavaHelpSearch/SCHEMA")
1723 outputs.file("${workingDir}/JavaHelpSearch/TMAP")
1726 task buildResources {
1727 dependsOn copyResources
1728 dependsOn copyChannelResources
1729 dependsOn createBuildProperties
1733 dependsOn buildResources
1736 dependsOn releasesTemplates
1737 dependsOn convertMdFiles
1738 dependsOn buildIndices
1742 compileJava.dependsOn prepare
1743 run.dependsOn compileJava
1744 compileTestJava.dependsOn compileJava
1749 group = "Verification"
1750 description = "Runs all testTaskN tasks)"
1753 dependsOn cloverClasses
1755 dependsOn testClasses
1758 // not running tests in this task
1761 /* testTask0 is the main test task */
1762 task testTask0(type: Test) {
1763 group = "Verification"
1764 description = "The main test task. Runs all non-testTaskN-labelled tests (unless excluded)"
1766 includeGroups testng_groups.split(",")
1767 excludeGroups testng_excluded_groups.split(",")
1768 tasks.withType(Test).matching {it.name.startsWith("testTask") && it.name != name}.all {t -> excludeGroups t.name}
1770 useDefaultListeners=true
1774 /* separated tests */
1775 task testTask1(type: Test) {
1776 group = "Verification"
1777 description = "Tests that need to be isolated from the main test run"
1780 excludeGroups testng_excluded_groups.split(",")
1782 useDefaultListeners=true
1786 /* insert more testTaskNs here -- change N to next digit or other string */
1788 task testTaskN(type: Test) {
1789 group = "Verification"
1790 description = "Tests that need to be isolated from the main test run"
1793 excludeGroups testng_excluded_groups.split(",")
1795 useDefaultListeners=true
1801 * adapted from https://medium.com/@wasyl/pretty-tests-summary-in-gradle-744804dd676c
1802 * to summarise test results from all Test tasks
1804 /* START of test tasks results summary */
1805 import groovy.time.TimeCategory
1806 import org.gradle.api.tasks.testing.logging.TestExceptionFormat
1807 import org.gradle.api.tasks.testing.logging.TestLogEvent
1808 rootProject.ext.testsResults = [] // Container for tests summaries
1810 tasks.withType(Test).matching {t -> t.getName().startsWith("testTask")}.all { testTask ->
1812 // from original test task
1814 dependsOn cloverClasses
1816 dependsOn testClasses //?
1819 // run main tests first
1820 if (!testTask.name.equals("testTask0"))
1821 testTask.mustRunAfter "testTask0"
1823 testTask.testLogging { logging ->
1824 events TestLogEvent.FAILED
1825 // TestLogEvent.SKIPPED,
1826 // TestLogEvent.STANDARD_OUT,
1827 // TestLogEvent.STANDARD_ERROR
1829 exceptionFormat TestExceptionFormat.FULL
1832 showStackTraces true
1834 info.events = [ TestLogEvent.FAILED ]
1837 if (OperatingSystem.current().isMacOsX()) {
1838 testTask.systemProperty "apple.awt.UIElement", "true"
1839 testTask.environment "JAVA_TOOL_OPTIONS", "-Dapple.awt.UIElement=true"
1843 ignoreFailures = true // Always try to run all tests for all modules
1845 afterSuite { desc, result ->
1847 return // Only summarize results for whole modules
1849 def resultsInfo = [testTask.project.name, testTask.name, result, TimeCategory.minus(new Date(result.endTime), new Date(result.startTime)), testTask.reports.html.entryPoint]
1851 rootProject.ext.testsResults.add(resultsInfo)
1854 // from original test task
1855 maxHeapSize = "1024m"
1857 workingDir = jalviewDir
1858 def testLaf = project.findProperty("test_laf")
1859 if (testLaf != null) {
1860 println("Setting Test LaF to '${testLaf}'")
1861 systemProperty "laf", testLaf
1863 def testHiDPIScale = project.findProperty("test_HiDPIScale")
1864 if (testHiDPIScale != null) {
1865 println("Setting Test HiDPI Scale to '${testHiDPIScale}'")
1866 systemProperty "sun.java2d.uiScale", testHiDPIScale
1868 sourceCompatibility = compile_source_compatibility
1869 targetCompatibility = compile_target_compatibility
1870 jvmArgs += additional_compiler_args
1873 // this is not perfect yet -- we should only add the commandLineIncludePatterns to the
1874 // testTasks that include the tests, and exclude all from the others.
1875 // get --test argument
1876 filter.commandLineIncludePatterns = test.filter.commandLineIncludePatterns
1877 // do something with testTask.getCandidateClassFiles() to see if the test should silently finish because of the
1878 // commandLineIncludePatterns not matching anything. Instead we are doing setFailOnNoMatchingTests(false) below
1882 println("Running tests " + (useClover?"WITH":"WITHOUT") + " clover")
1887 /* don't fail on no matching tests (so --tests will run across all testTasks) */
1888 testTask.filter.setFailOnNoMatchingTests(false)
1890 /* ensure the "test" task dependsOn all the testTasks */
1891 test.dependsOn testTask
1894 gradle.buildFinished {
1895 def allResults = rootProject.ext.testsResults
1897 if (!allResults.isEmpty()) {
1898 printResults allResults
1899 allResults.each {r ->
1900 if (r[2].resultType == TestResult.ResultType.FAILURE)
1901 throw new GradleException("Failed tests!")
1906 private static String colString(styler, col, colour, text) {
1907 return col?"${styler[colour](text)}":text
1910 private static String getSummaryLine(s, pn, tn, rt, rc, rs, rf, rsk, t, col) {
1911 def colour = 'black'
1919 case TestResult.ResultType.SUCCESS:
1922 case TestResult.ResultType.FAILURE:
1930 StringBuilder sb = new StringBuilder()
1934 sb.append(" results: ")
1935 sb.append(colString(s, col && !nocol, colour, text))
1937 sb.append("${rc} tests, ")
1938 sb.append(colString(s, col && rs > 0, 'green', rs))
1939 sb.append(" successes, ")
1940 sb.append(colString(s, col && rf > 0, 'red', rf))
1941 sb.append(" failures, ")
1942 sb.append("${rsk} skipped) in ${t}")
1943 return sb.toString()
1946 private static void printResults(allResults) {
1948 // styler from https://stackoverflow.com/a/56139852
1949 def styler = 'black red green yellow blue magenta cyan white'.split().toList().withIndex(30).collectEntries { key, val -> [(key) : { "\033[${val}m${it}\033[0m" }] }
1952 def failedTests = false
1953 def summaryLines = []
1955 def totalsuccess = 0
1958 def totaltime = TimeCategory.getSeconds(0)
1959 // sort on project name then task name
1960 allResults.sort {a, b -> a[0] == b[0]? a[1]<=>b[1]:a[0] <=> b[0]}.each {
1961 def projectName = it[0]
1962 def taskName = it[1]
1966 def summaryCol = getSummaryLine(styler, projectName, taskName, result.resultType, result.testCount, result.successfulTestCount, result.failedTestCount, result.skippedTestCount, time, true)
1967 def summaryPlain = getSummaryLine(styler, projectName, taskName, result.resultType, result.testCount, result.successfulTestCount, result.failedTestCount, result.skippedTestCount, time, false)
1968 def reportLine = "Report file: ${report}"
1969 def ls = summaryPlain.length()
1970 def lr = reportLine.length()
1971 def m = [ls, lr].max()
1974 def info = [ls, summaryCol, reportLine]
1975 summaryLines.add(info)
1976 failedTests |= result.resultType == TestResult.ResultType.FAILURE
1977 totalcount += result.testCount
1978 totalsuccess += result.successfulTestCount
1979 totalfail += result.failedTestCount
1980 totalskip += result.skippedTestCount
1983 def totalSummaryCol = getSummaryLine(styler, "OVERALL", "", failedTests?TestResult.ResultType.FAILURE:TestResult.ResultType.SUCCESS, totalcount, totalsuccess, totalfail, totalskip, totaltime, true)
1984 def totalSummaryPlain = getSummaryLine(styler, "OVERALL", "", failedTests?TestResult.ResultType.FAILURE:TestResult.ResultType.SUCCESS, totalcount, totalsuccess, totalfail, totalskip, totaltime, false)
1985 def tls = totalSummaryPlain.length()
1986 if (tls > maxLength)
1988 def info = [tls, totalSummaryCol, null]
1989 summaryLines.add(info)
1991 def allSummaries = []
1992 for(sInfo : summaryLines) {
1994 def summary = sInfo[1]
1995 def report = sInfo[2]
1997 StringBuilder sb = new StringBuilder()
1998 sb.append("│" + summary + " " * (maxLength - ls) + "│")
1999 if (report != null) {
2000 sb.append("\n│" + report + " " * (maxLength - report.length()) + "│")
2002 allSummaries += sb.toString()
2005 println "┌${"${"─" * maxLength}"}┐"
2006 println allSummaries.join("\n├${"${"─" * maxLength}"}┤\n")
2007 println "└${"${"─" * maxLength}"}┘"
2009 /* END of test tasks results summary */
2012 task compileLinkCheck(type: JavaCompile) {
2014 classpath = files("${jalviewDir}/${utils_dir}")
2015 destinationDir = file("${jalviewDir}/${utils_dir}")
2016 source = fileTree(dir: "${jalviewDir}/${utils_dir}", include: ["HelpLinksChecker.java", "BufferedLineReader.java"])
2018 inputs.file("${jalviewDir}/${utils_dir}/HelpLinksChecker.java")
2019 inputs.file("${jalviewDir}/${utils_dir}/HelpLinksChecker.java")
2020 outputs.file("${jalviewDir}/${utils_dir}/HelpLinksChecker.class")
2021 outputs.file("${jalviewDir}/${utils_dir}/BufferedLineReader.class")
2025 task linkCheck(type: JavaExec) {
2027 dependsOn compileLinkCheck
2029 def helpLinksCheckerOutFile = file("${jalviewDir}/${utils_dir}/HelpLinksChecker.out")
2030 classpath = files("${jalviewDir}/${utils_dir}")
2031 main = "HelpLinksChecker"
2032 workingDir = "${helpBuildDir}"
2033 args = [ "${helpBuildDir}/${help_dir}", "-nointernet" ]
2035 def outFOS = new FileOutputStream(helpLinksCheckerOutFile, false) // false == don't append
2036 standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
2039 errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
2043 inputs.dir(helpBuildDir)
2044 outputs.file(helpLinksCheckerOutFile)
2048 // import the pubhtmlhelp target
2049 ant.properties.basedir = "${jalviewDir}"
2050 ant.properties.helpBuildDir = "${helpBuildDir}/${help_dir}"
2051 ant.importBuild "${utils_dir}/publishHelp.xml"
2054 task cleanPackageDir(type: Delete) {
2056 delete fileTree(dir: "${jalviewDir}/${package_dir}", include: "*.jar")
2066 attributes "Main-Class": main_class,
2067 "Permissions": "all-permissions",
2068 "Application-Name": applicationName,
2069 "Codebase": application_codebase,
2070 "Implementation-Version": JALVIEW_VERSION
2073 def outputDir = "${jalviewDir}/${package_dir}"
2074 destinationDirectory = file(outputDir)
2075 archiveFileName = rootProject.name+".jar"
2076 duplicatesStrategy "EXCLUDE"
2083 exclude "**/*.jar.*"
2085 inputs.dir(sourceSets.main.java.outputDir)
2086 sourceSets.main.resources.srcDirs.each{ dir ->
2089 outputs.file("${outputDir}/${archiveFileName}")
2093 task copyJars(type: Copy) {
2094 from fileTree(dir: classesDir, include: "**/*.jar").files
2095 into "${jalviewDir}/${package_dir}"
2099 // doing a Sync instead of Copy as Copy doesn't deal with "outputs" very well
2100 task syncJars(type: Sync) {
2102 from fileTree(dir: "${jalviewDir}/${libDistDir}", include: "**/*.jar").files
2103 into "${jalviewDir}/${package_dir}"
2105 include jar.archiveFileName.getOrNull()
2112 description = "Put all required libraries in dist"
2113 // order of "cleanPackageDir", "copyJars", "jar" important!
2114 jar.mustRunAfter cleanPackageDir
2115 syncJars.mustRunAfter cleanPackageDir
2116 dependsOn cleanPackageDir
2119 outputs.dir("${jalviewDir}/${package_dir}")
2124 dependsOn cleanPackageDir
2131 group = "distribution"
2132 description = "Create a single jar file with all dependency libraries merged. Can be run with java -jar"
2136 from ("${jalviewDir}/${libDistDir}") {
2140 attributes "Implementation-Version": JALVIEW_VERSION,
2141 "Application-Name": applicationName
2144 duplicatesStrategy "INCLUDE"
2146 mainClassName = shadow_jar_main_class
2148 classifier = "all-"+JALVIEW_VERSION+"-j"+JAVA_VERSION
2152 task getdownImagesCopy() {
2153 inputs.dir getdownImagesDir
2154 outputs.dir getdownImagesBuildDir
2158 from(getdownImagesDir) {
2159 include("*getdown*.png")
2161 into getdownImagesBuildDir
2166 task getdownImagesProcess() {
2167 dependsOn getdownImagesCopy
2170 if (backgroundImageText) {
2171 if (convertBinary == null) {
2172 throw new StopExecutionException("No ImageMagick convert binary installed at '${convertBinaryExpectedLocation}'")
2174 if (!project.hasProperty("getdown_background_image_text_suffix_cmd")) {
2175 throw new StopExecutionException("No property 'getdown_background_image_text_suffix_cmd' defined. See channel_gradle.properties for channel ${CHANNEL}")
2177 fileTree(dir: getdownImagesBuildDir, include: "*background*.png").getFiles().each { file ->
2179 executable convertBinary
2182 '-font', getdown_background_image_text_font,
2183 '-fill', getdown_background_image_text_colour,
2184 '-draw', sprintf(getdown_background_image_text_suffix_cmd, channelSuffix),
2185 '-draw', sprintf(getdown_background_image_text_commit_cmd, "git-commit: ${gitHash}"),
2186 '-draw', sprintf(getdown_background_image_text_date_cmd, getDate("yyyy-MM-dd HH:mm:ss")),
2195 task getdownImages() {
2196 dependsOn getdownImagesProcess
2199 task getdownWebsite() {
2200 group = "distribution"
2201 description = "Create the getdown minimal app folder, and website folder for this version of jalview. Website folder also used for offline app installer"
2203 dependsOn getdownImages
2208 def getdownWebsiteResourceFilenames = []
2209 def getdownResourceDir = getdownResourceDir
2210 def getdownResourceFilenames = []
2213 // clean the getdown website and files dir before creating getdown folders
2214 delete getdownAppBaseDir
2215 delete getdownFilesDir
2218 from buildProperties
2219 rename(file(buildProperties).getName(), getdown_build_properties)
2222 getdownWebsiteResourceFilenames += "${getdownAppDistDir}/${getdown_build_properties}"
2225 from channelPropsFile
2226 filter(ReplaceTokens,
2230 'SUFFIX': channelSuffix
2233 into getdownAppBaseDir
2235 getdownWebsiteResourceFilenames += file(channelPropsFile).getName()
2237 // set some getdownTxt_ properties then go through all properties looking for getdownTxt_...
2238 def props = project.properties.sort { it.key }
2239 if (getdownAltJavaMinVersion != null && getdownAltJavaMinVersion.length() > 0) {
2240 props.put("getdown_txt_java_min_version", getdownAltJavaMinVersion)
2242 if (getdownAltJavaMaxVersion != null && getdownAltJavaMaxVersion.length() > 0) {
2243 props.put("getdown_txt_java_max_version", getdownAltJavaMaxVersion)
2245 if (getdownAltMultiJavaLocation != null && getdownAltMultiJavaLocation.length() > 0) {
2246 props.put("getdown_txt_multi_java_location", getdownAltMultiJavaLocation)
2248 if (getdownImagesBuildDir != null && file(getdownImagesBuildDir).exists()) {
2249 props.put("getdown_txt_ui.background_image", "${getdownImagesBuildDir}/${getdown_background_image}")
2250 props.put("getdown_txt_ui.instant_background_image", "${getdownImagesBuildDir}/${getdown_instant_background_image}")
2251 props.put("getdown_txt_ui.error_background", "${getdownImagesBuildDir}/${getdown_error_background}")
2252 props.put("getdown_txt_ui.progress_image", "${getdownImagesBuildDir}/${getdown_progress_image}")
2253 props.put("getdown_txt_ui.icon", "${getdownImagesDir}/${getdown_icon}")
2254 props.put("getdown_txt_ui.mac_dock_icon", "${getdownImagesDir}/${getdown_mac_dock_icon}")
2257 props.put("getdown_txt_title", jalview_name)
2258 props.put("getdown_txt_ui.name", applicationName)
2260 // start with appbase
2261 getdownTextLines += "appbase = ${getdownAppBase}"
2262 props.each{ prop, val ->
2263 if (prop.startsWith("getdown_txt_") && val != null) {
2264 if (prop.startsWith("getdown_txt_multi_")) {
2265 def key = prop.substring(18)
2266 val.split(",").each{ v ->
2267 def line = "${key} = ${v}"
2268 getdownTextLines += line
2271 // file values rationalised
2272 if (val.indexOf('/') > -1 || prop.startsWith("getdown_txt_resource")) {
2274 if (val.indexOf('/') == 0) {
2277 } else if (val.indexOf('/') > 0) {
2278 // relative path (relative to jalviewDir)
2279 r = file( "${jalviewDir}/${val}" )
2282 val = "${getdown_resource_dir}/" + r.getName()
2283 getdownWebsiteResourceFilenames += val
2284 getdownResourceFilenames += r.getPath()
2287 if (! prop.startsWith("getdown_txt_resource")) {
2288 def line = prop.substring(12) + " = ${val}"
2289 getdownTextLines += line
2295 getdownWebsiteResourceFilenames.each{ filename ->
2296 getdownTextLines += "resource = ${filename}"
2298 getdownResourceFilenames.each{ filename ->
2301 into getdownResourceDir
2305 def getdownWrapperScripts = [ getdown_bash_wrapper_script, getdown_powershell_wrapper_script, getdown_batch_wrapper_script ]
2306 getdownWrapperScripts.each{ script ->
2307 def s = file( "${jalviewDir}/utils/getdown/${getdown_wrapper_script_dir}/${script}" )
2311 into "${getdownAppBaseDir}/${getdown_wrapper_script_dir}"
2313 getdownTextLines += "resource = ${getdown_wrapper_script_dir}/${script}"
2318 fileTree(file(package_dir)).each{ f ->
2319 if (f.isDirectory()) {
2320 def files = fileTree(dir: f, include: ["*"]).getFiles()
2322 } else if (f.exists()) {
2326 def jalviewJar = jar.archiveFileName.getOrNull()
2327 // put jalview.jar first for CLASSPATH and .properties files reasons
2328 codeFiles.sort{a, b -> ( a.getName() == jalviewJar ? -1 : ( b.getName() == jalviewJar ? 1 : a <=> b ) ) }.each{f ->
2329 def name = f.getName()
2330 def line = "code = ${getdownAppDistDir}/${name}"
2331 getdownTextLines += line
2338 // NOT USING MODULES YET, EVERYTHING SHOULD BE IN dist
2340 if (JAVA_VERSION.equals("11")) {
2341 def j11libFiles = fileTree(dir: "${jalviewDir}/${j11libDir}", include: ["*.jar"]).getFiles()
2342 j11libFiles.sort().each{f ->
2343 def name = f.getName()
2344 def line = "code = ${getdown_j11lib_dir}/${name}"
2345 getdownTextLines += line
2348 into getdownJ11libDir
2354 // 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.
2355 //getdownTextLines += "class = " + file(getdownLauncher).getName()
2356 getdownTextLines += "resource = ${getdown_launcher_new}"
2357 getdownTextLines += "class = ${main_class}"
2358 // Not setting these properties in general so that getdownappbase and getdowndistdir will default to release version in jalview.bin.Cache
2359 if (getdownSetAppBaseProperty) {
2360 getdownTextLines += "jvmarg = -Dgetdowndistdir=${getdownAppDistDir}"
2361 getdownTextLines += "jvmarg = -Dgetdownappbase=${getdownAppBase}"
2364 def getdownTxt = file("${getdownAppBaseDir}/getdown.txt")
2365 getdownTxt.write(getdownTextLines.join("\n"))
2367 getdownLaunchJvl = getdown_launch_jvl_name + ( (jvlChannelName != null && jvlChannelName.length() > 0)?"-${jvlChannelName}":"" ) + ".jvl"
2368 def launchJvl = file("${getdownAppBaseDir}/${getdownLaunchJvl}")
2369 launchJvl.write("appbase=${getdownAppBase}")
2371 // files going into the getdown website dir: getdown-launcher.jar
2373 from getdownLauncher
2374 rename(file(getdownLauncher).getName(), getdown_launcher_new)
2375 into getdownAppBaseDir
2378 // files going into the getdown website dir: getdown-launcher(-local).jar
2380 from getdownLauncher
2381 if (file(getdownLauncher).getName() != getdown_launcher) {
2382 rename(file(getdownLauncher).getName(), getdown_launcher)
2384 into getdownAppBaseDir
2387 // files going into the getdown website dir: ./install dir and files
2388 if (! (CHANNEL.startsWith("ARCHIVE") || CHANNEL.startsWith("DEVELOP"))) {
2391 from getdownLauncher
2392 from "${getdownAppDir}/${getdown_build_properties}"
2393 if (file(getdownLauncher).getName() != getdown_launcher) {
2394 rename(file(getdownLauncher).getName(), getdown_launcher)
2396 into getdownInstallDir
2399 // and make a copy in the getdown files dir (these are not downloaded by getdown)
2401 from getdownInstallDir
2402 into getdownFilesInstallDir
2406 // files going into the getdown files dir: getdown.txt, getdown-launcher.jar, channel-launch.jvl, build_properties
2410 from getdownLauncher
2411 from "${getdownAppBaseDir}/${getdown_build_properties}"
2412 from "${getdownAppBaseDir}/${channel_props}"
2413 if (file(getdownLauncher).getName() != getdown_launcher) {
2414 rename(file(getdownLauncher).getName(), getdown_launcher)
2416 into getdownFilesDir
2419 // and ./resource (not all downloaded by getdown)
2421 from getdownResourceDir
2422 into "${getdownFilesDir}/${getdown_resource_dir}"
2427 inputs.dir("${jalviewDir}/${package_dir}")
2429 outputs.dir(getdownAppBaseDir)
2430 outputs.dir(getdownFilesDir)
2434 // a helper task to allow getdown digest of any dir: `gradle getdownDigestDir -PDIGESTDIR=/path/to/my/random/getdown/dir
2435 task getdownDigestDir(type: JavaExec) {
2437 description "A task to run a getdown Digest on a dir with getdown.txt. Provide a DIGESTDIR property via -PDIGESTDIR=..."
2439 def digestDirPropertyName = "DIGESTDIR"
2441 classpath = files(getdownLauncher)
2442 def digestDir = findProperty(digestDirPropertyName)
2443 if (digestDir == null) {
2444 throw new GradleException("Must provide a DIGESTDIR value to produce an alternative getdown digest")
2448 main = "com.threerings.getdown.tools.Digester"
2452 task getdownDigest(type: JavaExec) {
2453 group = "distribution"
2454 description = "Digest the getdown website folder"
2455 dependsOn getdownWebsite
2457 classpath = files(getdownLauncher)
2459 main = "com.threerings.getdown.tools.Digester"
2460 args getdownAppBaseDir
2461 inputs.dir(getdownAppBaseDir)
2462 outputs.file("${getdownAppBaseDir}/digest2.txt")
2467 group = "distribution"
2468 description = "Create the minimal and full getdown app folder for installers and website and create digest file"
2469 dependsOn getdownDigest
2471 if (reportRsyncCommand) {
2472 def fromDir = getdownAppBaseDir + (getdownAppBaseDir.endsWith('/')?'':'/')
2473 def toDir = "${getdown_rsync_dest}/${getdownDir}" + (getdownDir.endsWith('/')?'':'/')
2474 println "LIKELY RSYNC COMMAND:"
2475 println "mkdir -p '$toDir'\nrsync -avh --delete '$fromDir' '$toDir'"
2476 if (RUNRSYNC == "true") {
2478 commandLine "mkdir", "-p", toDir
2481 commandLine "rsync", "-avh", "--delete", fromDir, toDir
2489 task getdownArchiveBuild() {
2490 group = "distribution"
2491 description = "Put files in the archive dir to go on the website"
2493 dependsOn getdownWebsite
2495 def v = "v${JALVIEW_VERSION_UNDERSCORES}"
2496 def vDir = "${getdownArchiveDir}/${v}"
2497 getdownFullArchiveDir = "${vDir}/getdown"
2498 getdownVersionLaunchJvl = "${vDir}/jalview-${v}.jvl"
2500 def vAltDir = "alt_${v}"
2501 def archiveImagesDir = "${jalviewDir}/${channel_properties_dir}/old/images"
2504 // cleanup old "old" dir
2505 delete getdownArchiveDir
2507 def getdownArchiveTxt = file("${getdownFullArchiveDir}/getdown.txt")
2508 getdownArchiveTxt.getParentFile().mkdirs()
2509 def getdownArchiveTextLines = []
2510 def getdownFullArchiveAppBase = "${getdownArchiveAppBase}${getdownArchiveAppBase.endsWith("/")?"":"/"}${v}/getdown/"
2514 from "${getdownAppBaseDir}/${getdownAppDistDir}"
2515 into "${getdownFullArchiveDir}/${vAltDir}"
2518 getdownTextLines.each { line ->
2519 line = line.replaceAll("^(?<s>appbase\\s*=\\s*).*", '${s}'+getdownFullArchiveAppBase)
2520 line = line.replaceAll("^(?<s>(resource|code)\\s*=\\s*)${getdownAppDistDir}/", '${s}'+vAltDir+"/")
2521 line = line.replaceAll("^(?<s>ui.background_image\\s*=\\s*).*\\.png", '${s}'+"${getdown_resource_dir}/jalview_archive_getdown_background.png")
2522 line = line.replaceAll("^(?<s>ui.instant_background_image\\s*=\\s*).*\\.png", '${s}'+"${getdown_resource_dir}/jalview_archive_getdown_background_initialising.png")
2523 line = line.replaceAll("^(?<s>ui.error_background\\s*=\\s*).*\\.png", '${s}'+"${getdown_resource_dir}/jalview_archive_getdown_background_error.png")
2524 line = line.replaceAll("^(?<s>ui.progress_image\\s*=\\s*).*\\.png", '${s}'+"${getdown_resource_dir}/jalview_archive_getdown_progress_bar.png")
2525 // remove the existing resource = resource/ or bin/ lines
2526 if (! line.matches("resource\\s*=\\s*(resource|bin)/.*")) {
2527 getdownArchiveTextLines += line
2531 // the resource dir -- add these files as resource lines in getdown.txt
2533 from "${archiveImagesDir}"
2534 into "${getdownFullArchiveDir}/${getdown_resource_dir}"
2536 getdownArchiveTextLines += "resource = ${getdown_resource_dir}/${file.getName()}"
2540 getdownArchiveTxt.write(getdownArchiveTextLines.join("\n"))
2542 def vLaunchJvl = file(getdownVersionLaunchJvl)
2543 vLaunchJvl.getParentFile().mkdirs()
2544 vLaunchJvl.write("appbase=${getdownFullArchiveAppBase}\n")
2545 def vLaunchJvlPath = vLaunchJvl.toPath().toAbsolutePath()
2546 def jvlLinkPath = file("${vDir}/jalview.jvl").toPath().toAbsolutePath()
2547 // for some reason filepath.relativize(fileInSameDirPath) gives a path to "../" which is wrong
2548 //java.nio.file.Files.createSymbolicLink(jvlLinkPath, jvlLinkPath.relativize(vLaunchJvlPath));
2549 java.nio.file.Files.createSymbolicLink(jvlLinkPath, java.nio.file.Paths.get(".",vLaunchJvl.getName()));
2551 // files going into the getdown files dir: getdown.txt, getdown-launcher.jar, channel-launch.jvl, build_properties
2553 from getdownLauncher
2554 from "${getdownAppBaseDir}/${getdownLaunchJvl}"
2555 from "${getdownAppBaseDir}/${getdown_launcher_new}"
2556 from "${getdownAppBaseDir}/${channel_props}"
2557 if (file(getdownLauncher).getName() != getdown_launcher) {
2558 rename(file(getdownLauncher).getName(), getdown_launcher)
2560 into getdownFullArchiveDir
2566 task getdownArchiveDigest(type: JavaExec) {
2567 group = "distribution"
2568 description = "Digest the getdown archive folder"
2570 dependsOn getdownArchiveBuild
2573 classpath = files(getdownLauncher)
2574 args getdownFullArchiveDir
2576 main = "com.threerings.getdown.tools.Digester"
2577 inputs.dir(getdownFullArchiveDir)
2578 outputs.file("${getdownFullArchiveDir}/digest2.txt")
2581 task getdownArchive() {
2582 group = "distribution"
2583 description = "Build the website archive dir with getdown digest"
2585 dependsOn getdownArchiveBuild
2586 dependsOn getdownArchiveDigest
2589 tasks.withType(JavaCompile) {
2590 options.encoding = 'UTF-8'
2596 delete getdownAppBaseDir
2597 delete getdownFilesDir
2598 delete getdownArchiveDir
2604 if (file(install4jHomeDir).exists()) {
2606 } else if (file(System.getProperty("user.home")+"/buildtools/install4j").exists()) {
2607 install4jHomeDir = System.getProperty("user.home")+"/buildtools/install4j"
2608 } else if (file("/Applications/install4j.app/Contents/Resources/app").exists()) {
2609 install4jHomeDir = "/Applications/install4j.app/Contents/Resources/app"
2611 installDir(file(install4jHomeDir))
2613 mediaTypes = Arrays.asList(install4j_media_types.split(","))
2617 task copyInstall4jTemplate {
2618 def install4jTemplateFile = file("${install4jDir}/${install4j_template}")
2619 def install4jFileAssociationsFile = file("${install4jDir}/${install4j_installer_file_associations}")
2620 inputs.file(install4jTemplateFile)
2621 inputs.file(install4jFileAssociationsFile)
2622 inputs.property("CHANNEL", { CHANNEL })
2623 outputs.file(install4jConfFile)
2626 def install4jConfigXml = new XmlParser().parse(install4jTemplateFile)
2628 // turn off code signing if no OSX_KEYPASS
2629 if (OSX_KEYPASS == "") {
2630 install4jConfigXml.'**'.codeSigning.each { codeSigning ->
2631 codeSigning.'@macEnabled' = "false"
2633 install4jConfigXml.'**'.windows.each { windows ->
2634 windows.'@runPostProcessor' = "false"
2638 // disable install screen for OSX dmg (for 2.11.2.0)
2639 install4jConfigXml.'**'.macosArchive.each { macosArchive ->
2640 macosArchive.attributes().remove('executeSetupApp')
2641 macosArchive.attributes().remove('setupAppId')
2644 // turn off checksum creation for LOCAL channel
2645 def e = install4jConfigXml.application[0]
2646 e.'@createChecksums' = string(install4jCheckSums)
2648 // put file association actions where placeholder action is
2649 def install4jFileAssociationsText = install4jFileAssociationsFile.text
2650 def fileAssociationActions = new XmlParser().parseText("<actions>${install4jFileAssociationsText}</actions>")
2651 install4jConfigXml.'**'.action.any { a -> // .any{} stops after the first one that returns true
2652 if (a.'@name' == 'EXTENSIONS_REPLACED_BY_GRADLE') {
2653 def parent = a.parent()
2655 fileAssociationActions.each { faa ->
2658 // don't need to continue in .any loop once replacements have been made
2663 // use Windows Program Group with Examples folder for RELEASE, and Program Group without Examples for everything else
2664 // NB we're deleting the /other/ one!
2665 // Also remove the examples subdir from non-release versions
2666 def customizedIdToDelete = "PROGRAM_GROUP_RELEASE"
2667 // 2.11.1.0 NOT releasing with the Examples folder in the Program Group
2668 if (false && CHANNEL=="RELEASE") { // remove 'false && ' to include Examples folder in RELEASE channel
2669 customizedIdToDelete = "PROGRAM_GROUP_NON_RELEASE"
2671 // remove the examples subdir from Full File Set
2672 def files = install4jConfigXml.files[0]
2673 def fileset = files.filesets.fileset.find { fs -> fs.'@customizedId' == "FULL_FILE_SET" }
2674 def root = files.roots.root.find { r -> r.'@fileset' == fileset.'@id' }
2675 def mountPoint = files.mountPoints.mountPoint.find { mp -> mp.'@root' == root.'@id' }
2676 def dirEntry = files.entries.dirEntry.find { de -> de.'@mountPoint' == mountPoint.'@id' && de.'@subDirectory' == "examples" }
2677 dirEntry.parent().remove(dirEntry)
2679 install4jConfigXml.'**'.action.any { a ->
2680 if (a.'@customizedId' == customizedIdToDelete) {
2681 def parent = a.parent()
2687 // write install4j file
2688 install4jConfFile.text = XmlUtil.serialize(install4jConfigXml)
2695 delete install4jConfFile
2699 task cleanInstallersDataFiles {
2700 def installersOutputTxt = file("${jalviewDir}/${install4jBuildDir}/output.txt")
2701 def installersSha256 = file("${jalviewDir}/${install4jBuildDir}/sha256sums")
2702 def hugoDataJsonFile = file("${jalviewDir}/${install4jBuildDir}/installers-${JALVIEW_VERSION_UNDERSCORES}.json")
2704 delete installersOutputTxt
2705 delete installersSha256
2706 delete hugoDataJsonFile
2710 task install4jDMGBackgroundImageCopy {
2711 inputs.file "${install4jDMGBackgroundImageDir}/${install4jDMGBackgroundImageFile}"
2712 outputs.dir "${install4jDMGBackgroundImageBuildDir}"
2715 from(install4jDMGBackgroundImageDir) {
2716 include(install4jDMGBackgroundImageFile)
2718 into install4jDMGBackgroundImageBuildDir
2723 task install4jDMGBackgroundImageProcess {
2724 dependsOn install4jDMGBackgroundImageCopy
2727 if (backgroundImageText) {
2728 if (convertBinary == null) {
2729 throw new StopExecutionException("No ImageMagick convert binary installed at '${convertBinaryExpectedLocation}'")
2731 if (!project.hasProperty("install4j_background_image_text_suffix_cmd")) {
2732 throw new StopExecutionException("No property 'install4j_background_image_text_suffix_cmd' defined. See channel_gradle.properties for channel ${CHANNEL}")
2734 fileTree(dir: install4jDMGBackgroundImageBuildDir, include: "*.png").getFiles().each { file ->
2736 executable convertBinary
2739 '-font', install4j_background_image_text_font,
2740 '-fill', install4j_background_image_text_colour,
2741 '-draw', sprintf(install4j_background_image_text_suffix_cmd, channelSuffix),
2742 '-draw', sprintf(install4j_background_image_text_commit_cmd, "git-commit: ${gitHash}"),
2743 '-draw', sprintf(install4j_background_image_text_date_cmd, getDate("yyyy-MM-dd HH:mm:ss")),
2752 task install4jDMGBackgroundImage {
2753 dependsOn install4jDMGBackgroundImageProcess
2756 task installerFiles(type: com.install4j.gradle.Install4jTask) {
2757 group = "distribution"
2758 description = "Create the install4j installers"
2760 dependsOn copyInstall4jTemplate
2761 dependsOn cleanInstallersDataFiles
2762 dependsOn install4jDMGBackgroundImage
2764 projectFile = install4jConfFile
2766 // create an md5 for the input files to use as version for install4j conf file
2767 def digest = MessageDigest.getInstance("MD5")
2769 (file("${install4jDir}/${install4j_template}").text +
2770 file("${install4jDir}/${install4j_info_plist_file_associations}").text +
2771 file("${install4jDir}/${install4j_installer_file_associations}").text).bytes)
2772 def filesMd5 = new BigInteger(1, digest.digest()).toString(16)
2773 if (filesMd5.length() >= 8) {
2774 filesMd5 = filesMd5.substring(0,8)
2776 def install4jTemplateVersion = "${JALVIEW_VERSION}_F${filesMd5}_C${gitHash}"
2779 'JALVIEW_NAME': jalview_name,
2780 'JALVIEW_APPLICATION_NAME': applicationName,
2781 'JALVIEW_DIR': "../..",
2782 'OSX_KEYSTORE': OSX_KEYSTORE,
2783 'OSX_APPLEID': OSX_APPLEID,
2784 'OSX_ALTOOLPASS': OSX_ALTOOLPASS,
2785 'JSIGN_SH': JSIGN_SH,
2786 'JRE_DIR': getdown_app_dir_java,
2787 'INSTALLER_TEMPLATE_VERSION': install4jTemplateVersion,
2788 'JALVIEW_VERSION': JALVIEW_VERSION,
2789 'JAVA_MIN_VERSION': JAVA_MIN_VERSION,
2790 'JAVA_MAX_VERSION': JAVA_MAX_VERSION,
2791 'JAVA_VERSION': JAVA_VERSION,
2792 'JAVA_INTEGER_VERSION': JAVA_INTEGER_VERSION,
2793 'VERSION': JALVIEW_VERSION,
2794 'COPYRIGHT_MESSAGE': install4j_copyright_message,
2795 'BUNDLE_ID': install4jBundleId,
2796 'INTERNAL_ID': install4jInternalId,
2797 'WINDOWS_APPLICATION_ID': install4jWinApplicationId,
2798 'MACOS_DMG_DS_STORE': install4jDMGDSStore,
2799 'MACOS_DMG_BG_IMAGE': "${install4jDMGBackgroundImageBuildDir}/${install4jDMGBackgroundImageFile}",
2800 'WRAPPER_LINK': getdownWrapperLink,
2801 'BASH_WRAPPER_SCRIPT': getdown_bash_wrapper_script,
2802 'POWERSHELL_WRAPPER_SCRIPT': getdown_powershell_wrapper_script,
2803 'BATCH_WRAPPER_SCRIPT': getdown_batch_wrapper_script,
2804 'WRAPPER_SCRIPT_BIN_DIR': getdown_wrapper_script_dir,
2805 'INSTALLER_NAME': install4jInstallerName,
2806 'INSTALL4J_UTILS_DIR': install4j_utils_dir,
2807 'GETDOWN_CHANNEL_DIR': getdownChannelDir,
2808 'GETDOWN_FILES_DIR': getdown_files_dir,
2809 'GETDOWN_RESOURCE_DIR': getdown_resource_dir,
2810 'GETDOWN_DIST_DIR': getdownAppDistDir,
2811 'GETDOWN_ALT_DIR': getdown_app_dir_alt,
2812 'GETDOWN_INSTALL_DIR': getdown_install_dir,
2813 'INFO_PLIST_FILE_ASSOCIATIONS_FILE': install4j_info_plist_file_associations,
2814 'BUILD_DIR': install4jBuildDir,
2815 'APPLICATION_CATEGORIES': install4j_application_categories,
2816 'APPLICATION_FOLDER': install4jApplicationFolder,
2817 'UNIX_APPLICATION_FOLDER': install4jUnixApplicationFolder,
2818 'EXECUTABLE_NAME': install4jExecutableName,
2819 'EXTRA_SCHEME': install4jExtraScheme,
2820 'MAC_ICONS_FILE': install4jMacIconsFile,
2821 'WINDOWS_ICONS_FILE': install4jWindowsIconsFile,
2822 'PNG_ICON_FILE': install4jPngIconFile,
2823 'BACKGROUND': install4jBackground,
2828 'windows': 'WINDOWS',
2832 // these are the bundled OS/architecture VMs needed by install4j
2835 [ "mac", "aarch64" ],
2836 [ "windows", "x64" ],
2838 [ "linux", "aarch64" ]
2840 osArch.forEach { os, arch ->
2841 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)
2842 // N.B. For some reason install4j requires the below filename to have underscores and not hyphens
2843 // otherwise running `gradle installers` generates a non-useful error:
2844 // `install4j: compilation failed. Reason: java.lang.NumberFormatException: For input string: "windows"`
2845 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)
2848 //println("INSTALL4J VARIABLES:")
2849 //variables.each{k,v->println("${k}=${v}")}
2851 destination = "${jalviewDir}/${install4jBuildDir}"
2852 buildSelected = true
2854 if (install4j_faster.equals("true") || CHANNEL.startsWith("LOCAL")) {
2856 disableSigning = true
2857 disableNotarization = true
2861 macKeystorePassword = OSX_KEYPASS
2864 if (OSX_ALTOOLPASS) {
2865 appleIdPassword = OSX_ALTOOLPASS
2866 disableNotarization = false
2868 disableNotarization = true
2872 println("Using projectFile "+projectFile)
2873 if (!disableNotarization) { println("Will notarize OSX App DMG") }
2877 inputs.dir(getdownAppBaseDir)
2878 inputs.file(install4jConfFile)
2879 inputs.file("${install4jDir}/${install4j_info_plist_file_associations}")
2880 outputs.dir("${jalviewDir}/${install4j_build_dir}/${JAVA_VERSION}")
2883 def getDataHash(File myFile) {
2884 HashCode hash = Files.asByteSource(myFile).hash(Hashing.sha256())
2885 return myFile.exists()
2887 "file" : myFile.getName(),
2888 "filesize" : myFile.length(),
2889 "sha256" : hash.toString()
2894 def writeDataJsonFile(File installersOutputTxt, File installersSha256, File dataJsonFile) {
2896 "channel" : getdownChannelName,
2897 "date" : getDate("yyyy-MM-dd HH:mm:ss"),
2898 "git-commit" : "${gitHash} [${gitBranch}]",
2899 "version" : JALVIEW_VERSION
2901 // install4j installer files
2902 if (installersOutputTxt.exists()) {
2904 installersOutputTxt.readLines().each { def line ->
2905 if (line.startsWith("#")) {
2908 line.replaceAll("\n","")
2909 def vals = line.split("\t")
2910 def filename = vals[3]
2911 def filesize = file(filename).length()
2912 filename = filename.replaceAll(/^.*\//, "")
2913 hash[vals[0]] = [ "id" : vals[0], "os" : vals[1], "name" : vals[2], "file" : filename, "filesize" : filesize ]
2914 idHash."${filename}" = vals[0]
2916 if (install4jCheckSums && installersSha256.exists()) {
2917 installersSha256.readLines().each { def line ->
2918 if (line.startsWith("#")) {
2921 line.replaceAll("\n","")
2922 def vals = line.split(/\s+\*?/)
2923 def filename = vals[1]
2924 def innerHash = (hash.(idHash."${filename}"))."sha256" = vals[0]
2930 "JAR": shadowJar.archiveFile, // executable JAR
2931 "JVL": getdownVersionLaunchJvl, // version JVL
2932 "SOURCE": sourceDist.archiveFile // source TGZ
2933 ].each { key, value ->
2934 def file = file(value)
2935 if (file.exists()) {
2936 def fileHash = getDataHash(file)
2937 if (fileHash != null) {
2938 hash."${key}" = fileHash;
2942 return dataJsonFile.write(new JsonBuilder(hash).toPrettyString())
2945 task staticMakeInstallersJsonFile {
2947 def output = findProperty("i4j_output")
2948 def sha256 = findProperty("i4j_sha256")
2949 def json = findProperty("i4j_json")
2950 if (output == null || sha256 == null || json == null) {
2951 throw new GradleException("Must provide paths to all of output.txt, sha256sums, and output.json with '-Pi4j_output=... -Pi4j_sha256=... -Pi4j_json=...")
2953 writeDataJsonFile(file(output), file(sha256), file(json))
2958 dependsOn installerFiles
2964 eclipse().configFile(eclipse_codestyle_file)
2968 task createSourceReleaseProperties(type: WriteProperties) {
2969 group = "distribution"
2970 description = "Create the source RELEASE properties file"
2972 def sourceTarBuildDir = "${buildDir}/sourceTar"
2973 def sourceReleasePropertiesFile = "${sourceTarBuildDir}/RELEASE"
2974 outputFile (sourceReleasePropertiesFile)
2977 releaseProps.each{ key, val -> property key, val }
2978 property "git.branch", gitBranch
2979 property "git.hash", gitHash
2982 outputs.file(outputFile)
2985 task sourceDist(type: Tar) {
2986 group "distribution"
2987 description "Create a source .tar.gz file for distribution"
2989 dependsOn createBuildProperties
2990 dependsOn convertMdFiles
2991 dependsOn eclipseAllPreferences
2992 dependsOn createSourceReleaseProperties
2995 def outputFileName = "${project.name}_${JALVIEW_VERSION_UNDERSCORES}.tar.gz"
2996 archiveFileName = outputFileName
2998 compression Compression.GZIP
3013 "**/*.class","$j11modDir/**/*.jar","appletlib","**/*locales",
3015 "utils/InstallAnywhere",
3030 "gradle.properties",
3042 ".settings/org.eclipse.buildship.core.prefs",
3043 ".settings/org.eclipse.jdt.core.prefs"
3047 exclude (EXCLUDE_FILES)
3048 include (PROCESS_FILES)
3049 filter(ReplaceTokens,
3053 'Version-Rel': JALVIEW_VERSION,
3054 'Year-Rel': getDate("yyyy")
3059 exclude (EXCLUDE_FILES)
3060 exclude (PROCESS_FILES)
3061 exclude ("appletlib")
3062 exclude ("**/*locales")
3063 exclude ("*locales/**")
3064 exclude ("utils/InstallAnywhere")
3066 exclude (getdown_files_dir)
3067 // getdown_website_dir and getdown_archive_dir moved to build/website/docroot/getdown
3068 //exclude (getdown_website_dir)
3069 //exclude (getdown_archive_dir)
3071 // exluding these as not using jars as modules yet
3072 exclude ("${j11modDir}/**/*.jar")
3075 include(INCLUDE_FILES)
3077 // from (jalviewDir) {
3078 // // explicit includes for stuff that seemed to not get included
3079 // include(fileTree("test/**/*."))
3080 // exclude(EXCLUDE_FILES)
3081 // exclude(PROCESS_FILES)
3084 from(file(buildProperties).getParent()) {
3085 include(file(buildProperties).getName())
3086 rename(file(buildProperties).getName(), "build_properties")
3088 line.replaceAll("^INSTALLATION=.*\$","INSTALLATION=Source Release"+" git-commit\\\\:"+gitHash+" ["+gitBranch+"]")
3092 def sourceTarBuildDir = "${buildDir}/sourceTar"
3093 from(sourceTarBuildDir) {
3094 // this includes the appended RELEASE properties file
3098 task dataInstallersJson {
3100 description "Create the installers-VERSION.json data file for installer files created"
3102 mustRunAfter installers
3103 mustRunAfter shadowJar
3104 mustRunAfter sourceDist
3105 mustRunAfter getdownArchive
3107 def installersOutputTxt = file("${jalviewDir}/${install4jBuildDir}/output.txt")
3108 def installersSha256 = file("${jalviewDir}/${install4jBuildDir}/sha256sums")
3110 if (installersOutputTxt.exists()) {
3111 inputs.file(installersOutputTxt)
3113 if (install4jCheckSums && installersSha256.exists()) {
3114 inputs.file(installersSha256)
3117 shadowJar.archiveFile, // executable JAR
3118 getdownVersionLaunchJvl, // version JVL
3119 sourceDist.archiveFile // source TGZ
3120 ].each { fileName ->
3121 if (file(fileName).exists()) {
3122 inputs.file(fileName)
3126 outputs.file(hugoDataJsonFile)
3129 writeDataJsonFile(installersOutputTxt, installersSha256, hugoDataJsonFile)
3135 description "Copies all help pages to build dir. Runs ant task 'pubhtmlhelp'."
3138 dependsOn pubhtmlhelp
3140 inputs.dir("${helpBuildDir}/${help_dir}")
3141 outputs.dir("${buildDir}/distributions/${help_dir}")
3145 task j2sSetHeadlessBuild {
3152 task jalviewjsEnableAltFileProperty(type: WriteProperties) {
3154 description "Enable the alternative J2S Config file for headless build"
3156 outputFile = jalviewjsJ2sSettingsFileName
3157 def j2sPropsFile = file(jalviewjsJ2sSettingsFileName)
3158 def j2sProps = new Properties()
3159 if (j2sPropsFile.exists()) {
3161 def j2sPropsFileFIS = new FileInputStream(j2sPropsFile)
3162 j2sProps.load(j2sPropsFileFIS)
3163 j2sPropsFileFIS.close()
3165 j2sProps.each { prop, val ->
3168 } catch (Exception e) {
3169 println("Exception reading ${jalviewjsJ2sSettingsFileName}")
3173 if (! j2sProps.stringPropertyNames().contains(jalviewjs_j2s_alt_file_property_config)) {
3174 property(jalviewjs_j2s_alt_file_property_config, jalviewjs_j2s_alt_file_property)
3179 task jalviewjsSetEclipseWorkspace {
3180 def propKey = "jalviewjs_eclipse_workspace"
3182 if (project.hasProperty(propKey)) {
3183 propVal = project.getProperty(propKey)
3184 if (propVal.startsWith("~/")) {
3185 propVal = System.getProperty("user.home") + propVal.substring(1)
3188 def propsFileName = "${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_eclipse_workspace_location_file}"
3189 def propsFile = file(propsFileName)
3190 def eclipseWsDir = propVal
3191 def props = new Properties()
3193 def writeProps = true
3194 if (( eclipseWsDir == null || !file(eclipseWsDir).exists() ) && propsFile.exists()) {
3195 def ins = new FileInputStream(propsFileName)
3198 if (props.getProperty(propKey, null) != null) {
3199 eclipseWsDir = props.getProperty(propKey)
3204 if (eclipseWsDir == null || !file(eclipseWsDir).exists()) {
3205 def tempDir = File.createTempDir()
3206 eclipseWsDir = tempDir.getAbsolutePath()
3209 eclipseWorkspace = file(eclipseWsDir)
3212 // do not run a headless transpile when we claim to be in Eclipse
3214 println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3215 throw new StopExecutionException("Not running headless transpile whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
3217 println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3221 props.setProperty(propKey, eclipseWsDir)
3222 propsFile.parentFile.mkdirs()
3223 def bytes = new ByteArrayOutputStream()
3224 props.store(bytes, null)
3225 def propertiesString = bytes.toString()
3226 propsFile.text = propertiesString
3232 println("ECLIPSE WORKSPACE: "+eclipseWorkspace.getPath())
3235 //inputs.property(propKey, eclipseWsDir) // eclipseWsDir only gets set once this task runs, so will be out-of-date
3236 outputs.file(propsFileName)
3237 outputs.upToDateWhen { eclipseWorkspace.exists() && propsFile.exists() }
3241 task jalviewjsEclipsePaths {
3244 def eclipseRoot = jalviewjs_eclipse_root
3245 if (eclipseRoot.startsWith("~/")) {
3246 eclipseRoot = System.getProperty("user.home") + eclipseRoot.substring(1)
3248 if (OperatingSystem.current().isMacOsX()) {
3249 eclipseRoot += "/Eclipse.app"
3250 eclipseBinary = "${eclipseRoot}/Contents/MacOS/eclipse"
3251 eclipseProduct = "${eclipseRoot}/Contents/Eclipse/.eclipseproduct"
3252 } else if (OperatingSystem.current().isWindows()) { // check these paths!!
3253 if (file("${eclipseRoot}/eclipse").isDirectory() && file("${eclipseRoot}/eclipse/.eclipseproduct").exists()) {
3254 eclipseRoot += "/eclipse"
3256 eclipseBinary = "${eclipseRoot}/eclipse.exe"
3257 eclipseProduct = "${eclipseRoot}/.eclipseproduct"
3258 } else { // linux or unix
3259 if (file("${eclipseRoot}/eclipse").isDirectory() && file("${eclipseRoot}/eclipse/.eclipseproduct").exists()) {
3260 eclipseRoot += "/eclipse"
3261 println("eclipseDir exists")
3263 eclipseBinary = "${eclipseRoot}/eclipse"
3264 eclipseProduct = "${eclipseRoot}/.eclipseproduct"
3267 eclipseVersion = "4.13" // default
3268 def assumedVersion = true
3269 if (file(eclipseProduct).exists()) {
3270 def fis = new FileInputStream(eclipseProduct)
3271 def props = new Properties()
3273 eclipseVersion = props.getProperty("version")
3275 assumedVersion = false
3278 def propKey = "eclipse_debug"
3279 eclipseDebug = (project.hasProperty(propKey) && project.getProperty(propKey).equals("true"))
3282 // do not run a headless transpile when we claim to be in Eclipse
3284 println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3285 throw new StopExecutionException("Not running headless transpile whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
3287 println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3290 if (!assumedVersion) {
3291 println("ECLIPSE VERSION=${eclipseVersion}")
3297 task printProperties {
3299 description "Output to console all System.properties"
3301 System.properties.each { key, val -> System.out.println("Property: ${key}=${val}") }
3307 dependsOn eclipseProject
3308 dependsOn eclipseClasspath
3309 dependsOn eclipseJdt
3313 // this version (type: Copy) will delete anything in the eclipse dropins folder that isn't in fromDropinsDir
3314 task jalviewjsEclipseCopyDropins(type: Copy) {
3315 dependsOn jalviewjsEclipsePaths
3317 def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjs_eclipse_dropins_dir}", include: "*.jar")
3318 inputFiles += file("${jalviewDir}/${jalviewjsJ2sPlugin}")
3319 def outputDir = "${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_eclipse_tmp_dropins_dir}"
3326 // this eclipse -clean doesn't actually work
3327 task jalviewjsCleanEclipse(type: Exec) {
3328 dependsOn eclipseSetup
3329 dependsOn jalviewjsEclipsePaths
3330 dependsOn jalviewjsEclipseCopyDropins
3332 executable(eclipseBinary)
3333 args(["-nosplash", "--launcher.suppressErrors", "-data", eclipseWorkspace.getPath(), "-clean", "-console", "-consoleLog"])
3339 def inputString = """exit
3342 def inputByteStream = new ByteArrayInputStream(inputString.getBytes())
3343 standardInput = inputByteStream
3346 /* not really working yet
3347 jalviewjsEclipseCopyDropins.finalizedBy jalviewjsCleanEclipse
3351 task jalviewjsTransferUnzipSwingJs {
3352 def file_zip = "${jalviewDir}/${jalviewjs_swingjs_zip}"
3356 from zipTree(file_zip)
3357 into "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}"
3361 inputs.file file_zip
3362 outputs.dir "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}"
3366 task jalviewjsTransferUnzipLib {
3367 def zipFiles = fileTree(dir: "${jalviewDir}/${jalviewjs_libjs_dir}", include: "*.zip")
3370 zipFiles.each { file_zip ->
3372 from zipTree(file_zip)
3373 into "${jalviewDir}/${jalviewjsTransferSiteLibDir}"
3378 inputs.files zipFiles
3379 outputs.dir "${jalviewDir}/${jalviewjsTransferSiteLibDir}"
3383 task jalviewjsTransferUnzipAllLibs {
3384 dependsOn jalviewjsTransferUnzipSwingJs
3385 dependsOn jalviewjsTransferUnzipLib
3389 task jalviewjsCreateJ2sSettings(type: WriteProperties) {
3391 description "Create the alternative j2s file from the j2s.* properties"
3393 jalviewjsJ2sProps = project.properties.findAll { it.key.startsWith("j2s.") }.sort { it.key }
3394 def siteDirProperty = "j2s.site.directory"
3395 def setSiteDir = false
3396 jalviewjsJ2sProps.each { prop, val ->
3398 if (prop == siteDirProperty) {
3399 if (!(val.startsWith('/') || val.startsWith("file://") )) {
3400 val = "${jalviewDir}/${jalviewjsTransferSiteJsDir}/${val}"
3406 if (!setSiteDir) { // default site location, don't override specifically set property
3407 property(siteDirProperty,"${jalviewDirRelativePath}/${jalviewjsTransferSiteJsDir}")
3410 outputFile = jalviewjsJ2sAltSettingsFileName
3413 inputs.properties(jalviewjsJ2sProps)
3414 outputs.file(jalviewjsJ2sAltSettingsFileName)
3419 task jalviewjsEclipseSetup {
3420 dependsOn jalviewjsEclipseCopyDropins
3421 dependsOn jalviewjsSetEclipseWorkspace
3422 dependsOn jalviewjsCreateJ2sSettings
3426 task jalviewjsSyncAllLibs (type: Sync) {
3427 dependsOn jalviewjsTransferUnzipAllLibs
3428 def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjsTransferSiteLibDir}")
3429 inputFiles += fileTree(dir: "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}")
3430 def outputDir = "${jalviewDir}/${jalviewjsSiteDir}"
3434 def outputFiles = []
3435 rename { filename ->
3436 outputFiles += "${outputDir}/${filename}"
3443 // should this be exclude really ?
3444 duplicatesStrategy "INCLUDE"
3446 outputs.files outputFiles
3447 inputs.files inputFiles
3451 task jalviewjsSyncResources (type: Sync) {
3452 dependsOn buildResources
3454 def inputFiles = fileTree(dir: resourcesBuildDir)
3455 def outputDir = "${jalviewDir}/${jalviewjsSiteDir}/${jalviewjs_j2s_subdir}"
3459 def outputFiles = []
3460 rename { filename ->
3461 outputFiles += "${outputDir}/${filename}"
3467 outputs.files outputFiles
3468 inputs.files inputFiles
3472 task jalviewjsSyncSiteResources (type: Sync) {
3473 def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjs_site_resource_dir}")
3474 def outputDir = "${jalviewDir}/${jalviewjsSiteDir}"
3478 def outputFiles = []
3479 rename { filename ->
3480 outputFiles += "${outputDir}/${filename}"
3486 outputs.files outputFiles
3487 inputs.files inputFiles
3491 task jalviewjsSyncBuildProperties (type: Sync) {
3492 dependsOn createBuildProperties
3493 def inputFiles = [file(buildProperties)]
3494 def outputDir = "${jalviewDir}/${jalviewjsSiteDir}/${jalviewjs_j2s_subdir}"
3498 def outputFiles = []
3499 rename { filename ->
3500 outputFiles += "${outputDir}/${filename}"
3506 outputs.files outputFiles
3507 inputs.files inputFiles
3511 task jalviewjsProjectImport(type: Exec) {
3512 dependsOn eclipseSetup
3513 dependsOn jalviewjsEclipsePaths
3514 dependsOn jalviewjsEclipseSetup
3517 // do not run a headless import when we claim to be in Eclipse
3519 println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3520 throw new StopExecutionException("Not running headless import whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
3522 println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3526 //def projdir = eclipseWorkspace.getPath()+"/.metadata/.plugins/org.eclipse.core.resources/.projects/jalview/org.eclipse.jdt.core"
3527 def projdir = eclipseWorkspace.getPath()+"/.metadata/.plugins/org.eclipse.core.resources/.projects/jalview"
3528 executable(eclipseBinary)
3529 args(["-nosplash", "--launcher.suppressErrors", "-application", "com.seeq.eclipse.importprojects.headlessimport", "-data", eclipseWorkspace.getPath(), "-import", jalviewDirAbsolutePath])
3533 args += [ "--launcher.appendVmargs", "-vmargs", "-Dorg.eclipse.equinox.p2.reconciler.dropins.directory=${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_eclipse_tmp_dropins_dir}" ]
3535 args += [ "-D${j2sHeadlessBuildProperty}=true" ]
3536 args += [ "-D${jalviewjs_j2s_alt_file_property}=${jalviewjsJ2sAltSettingsFileName}" ]
3539 inputs.file("${jalviewDir}/.project")
3540 outputs.upToDateWhen {
3541 file(projdir).exists()
3546 task jalviewjsTranspile(type: Exec) {
3547 dependsOn jalviewjsEclipseSetup
3548 dependsOn jalviewjsProjectImport
3549 dependsOn jalviewjsEclipsePaths
3551 dependsOn jalviewjsEnableAltFileProperty
3555 // do not run a headless transpile when we claim to be in Eclipse
3557 println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3558 throw new StopExecutionException("Not running headless transpile whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
3560 println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3564 executable(eclipseBinary)
3565 args(["-nosplash", "--launcher.suppressErrors", "-application", "org.eclipse.jdt.apt.core.aptBuild", "-data", eclipseWorkspace, "-${jalviewjs_eclipse_build_arg}", eclipse_project_name ])
3569 args += [ "--launcher.appendVmargs", "-vmargs", "-Dorg.eclipse.equinox.p2.reconciler.dropins.directory=${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_eclipse_tmp_dropins_dir}" ]
3571 args += [ "-D${j2sHeadlessBuildProperty}=true" ]
3572 args += [ "-D${jalviewjs_j2s_alt_file_property}=${jalviewjsJ2sAltSettingsFileName}" ]
3578 stdout = new ByteArrayOutputStream()
3579 stderr = new ByteArrayOutputStream()
3581 def logOutFileName = "${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}"
3582 def logOutFile = file(logOutFileName)
3583 logOutFile.createNewFile()
3584 logOutFile.text = """ROOT: ${jalviewjs_eclipse_root}
3585 BINARY: ${eclipseBinary}
3586 VERSION: ${eclipseVersion}
3587 WORKSPACE: ${eclipseWorkspace}
3588 DEBUG: ${eclipseDebug}
3591 def logOutFOS = new FileOutputStream(logOutFile, true) // true == append
3592 // combine stdout and stderr
3593 def logErrFOS = logOutFOS
3595 if (jalviewjs_j2s_to_console.equals("true")) {
3596 standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
3597 new org.apache.tools.ant.util.TeeOutputStream(
3601 errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
3602 new org.apache.tools.ant.util.TeeOutputStream(
3607 standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
3610 errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
3617 if (stdout.toString().contains("Error processing ")) {
3618 // j2s did not complete transpile
3619 //throw new TaskExecutionException("Error during transpilation:\n${stderr}\nSee eclipse transpile log file '${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}'")
3620 if (jalviewjs_ignore_transpile_errors.equals("true")) {
3621 println("IGNORING TRANSPILE ERRORS")
3622 println("See eclipse transpile log file '${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}'")
3624 throw new GradleException("Error during transpilation:\n${stderr}\nSee eclipse transpile log file '${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}'")
3629 inputs.dir("${jalviewDir}/${sourceDir}")
3630 outputs.dir("${jalviewDir}/${jalviewjsTransferSiteJsDir}")
3631 outputs.upToDateWhen( { file("${jalviewDir}/${jalviewjsTransferSiteJsDir}${jalviewjs_server_resource}").exists() } )
3635 def jalviewjsCallCore(String name, FileCollection list, String prefixFile, String suffixFile, String jsfile, String zjsfile, File logOutFile, Boolean logOutConsole) {
3637 def stdout = new ByteArrayOutputStream()
3638 def stderr = new ByteArrayOutputStream()
3640 def coreFile = file(jsfile)
3642 msg = "Creating core for ${name}...\nGenerating ${jsfile}"
3644 logOutFile.createNewFile()
3645 logOutFile.append(msg+"\n")
3647 def coreTop = file(prefixFile)
3648 def coreBottom = file(suffixFile)
3649 coreFile.getParentFile().mkdirs()
3650 coreFile.createNewFile()
3651 coreFile.write( coreTop.getText("UTF-8") )
3655 def t = f.getText("UTF-8")
3656 t.replaceAll("Clazz\\.([^_])","Clazz_${1}")
3657 coreFile.append( t )
3659 msg = "...file '"+f.getPath()+"' does not exist, skipping"
3661 logOutFile.append(msg+"\n")
3664 coreFile.append( coreBottom.getText("UTF-8") )
3666 msg = "Generating ${zjsfile}"
3668 logOutFile.append(msg+"\n")
3669 def logOutFOS = new FileOutputStream(logOutFile, true) // true == append
3670 def logErrFOS = logOutFOS
3673 classpath = files(["${jalviewDir}/${jalviewjs_closure_compiler}"])
3674 main = "com.google.javascript.jscomp.CommandLineRunner"
3675 jvmArgs = [ "-Dfile.encoding=UTF-8" ]
3676 args = [ "--compilation_level", "SIMPLE_OPTIMIZATIONS", "--warning_level", "QUIET", "--charset", "UTF-8", "--js", jsfile, "--js_output_file", zjsfile ]
3679 msg = "\nRunning '"+commandLine.join(' ')+"'\n"
3681 logOutFile.append(msg+"\n")
3683 if (logOutConsole) {
3684 standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
3685 new org.apache.tools.ant.util.TeeOutputStream(
3689 errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
3690 new org.apache.tools.ant.util.TeeOutputStream(
3695 standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
3698 errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
3705 logOutFile.append(msg+"\n")
3709 task jalviewjsBuildAllCores {
3711 description "Build the core js lib closures listed in the classlists dir"
3712 dependsOn jalviewjsTranspile
3713 dependsOn jalviewjsTransferUnzipSwingJs
3715 def j2sDir = "${jalviewDir}/${jalviewjsTransferSiteJsDir}/${jalviewjs_j2s_subdir}"
3716 def swingJ2sDir = "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}/${jalviewjs_j2s_subdir}"
3717 def libJ2sDir = "${jalviewDir}/${jalviewjsTransferSiteLibDir}/${jalviewjs_j2s_subdir}"
3718 def jsDir = "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}/${jalviewjs_js_subdir}"
3719 def outputDir = "${jalviewDir}/${jalviewjsTransferSiteCoreDir}/${jalviewjs_j2s_subdir}/core"
3720 def prefixFile = "${jsDir}/core/coretop2.js"
3721 def suffixFile = "${jsDir}/core/corebottom2.js"
3723 inputs.file prefixFile
3724 inputs.file suffixFile
3726 def classlistFiles = []
3727 // add the classlists found int the jalviewjs_classlists_dir
3728 fileTree(dir: "${jalviewDir}/${jalviewjs_classlists_dir}", include: "*.txt").each {
3730 def name = file.getName() - ".txt"
3737 // _jmol and _jalview cores. Add any other peculiar classlist.txt files here
3738 //classlistFiles += [ 'file': file("${jalviewDir}/${jalviewjs_classlist_jmol}"), 'name': "_jvjmol" ]
3739 classlistFiles += [ 'file': file("${jalviewDir}/${jalviewjs_classlist_jalview}"), 'name': jalviewjsJalviewCoreName ]
3741 jalviewjsCoreClasslists = []
3743 classlistFiles.each {
3746 def file = hash['file']
3747 if (! file.exists()) {
3748 //println("...classlist file '"+file.getPath()+"' does not exist, skipping")
3749 return false // this is a "continue" in groovy .each closure
3751 def name = hash['name']
3753 name = file.getName() - ".txt"
3761 def list = fileTree(dir: j2sDir, includes: filelist)
3763 def jsfile = "${outputDir}/core${name}.js"
3764 def zjsfile = "${outputDir}/core${name}.z.js"
3766 jalviewjsCoreClasslists += [
3775 outputs.file(jsfile)
3776 outputs.file(zjsfile)
3779 // _stevesoft core. add any cores without a classlist here (and the inputs and outputs)
3780 def stevesoftClasslistName = "_stevesoft"
3781 def stevesoftClasslist = [
3782 'jsfile': "${outputDir}/core${stevesoftClasslistName}.js",
3783 'zjsfile': "${outputDir}/core${stevesoftClasslistName}.z.js",
3784 'list': fileTree(dir: j2sDir, include: "com/stevesoft/pat/**/*.js"),
3785 'name': stevesoftClasslistName
3787 jalviewjsCoreClasslists += stevesoftClasslist
3788 inputs.files(stevesoftClasslist['list'])
3789 outputs.file(stevesoftClasslist['jsfile'])
3790 outputs.file(stevesoftClasslist['zjsfile'])
3793 def allClasslistName = "_all"
3794 def allJsFiles = fileTree(dir: j2sDir, include: "**/*.js")
3795 allJsFiles += fileTree(
3799 // these exlusions are files that the closure-compiler produces errors for. Should fix them
3800 "**/org/jmol/jvxl/readers/IsoIntersectFileReader.js",
3801 "**/org/jmol/export/JSExporter.js"
3804 allJsFiles += fileTree(
3808 // these exlusions are files that the closure-compiler produces errors for. Should fix them
3809 "**/sun/misc/Unsafe.js",
3810 "**/swingjs/jquery/jquery-editable-select.js",
3811 "**/swingjs/jquery/j2sComboBox.js",
3812 "**/sun/misc/FloatingDecimal.js"
3815 def allClasslist = [
3816 'jsfile': "${outputDir}/core${allClasslistName}.js",
3817 'zjsfile': "${outputDir}/core${allClasslistName}.z.js",
3819 'name': allClasslistName
3821 // not including this version of "all" core at the moment
3822 //jalviewjsCoreClasslists += allClasslist
3823 inputs.files(allClasslist['list'])
3824 outputs.file(allClasslist['jsfile'])
3825 outputs.file(allClasslist['zjsfile'])
3828 def logOutFile = file("${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_j2s_closure_stdout}")
3829 logOutFile.getParentFile().mkdirs()
3830 logOutFile.createNewFile()
3831 logOutFile.write(getDate("yyyy-MM-dd HH:mm:ss")+" jalviewjsBuildAllCores\n----\n")
3833 jalviewjsCoreClasslists.each {
3834 jalviewjsCallCore(it.name, it.list, prefixFile, suffixFile, it.jsfile, it.zjsfile, logOutFile, jalviewjs_j2s_to_console.equals("true"))
3841 def jalviewjsPublishCoreTemplate(String coreName, String templateName, File inputFile, String outputFile) {
3844 into file(outputFile).getParentFile()
3845 rename { filename ->
3846 if (filename.equals(inputFile.getName())) {
3847 return file(outputFile).getName()
3851 filter(ReplaceTokens,
3855 'MAIN': '"'+main_class+'"',
3857 'NAME': jalviewjsJalviewTemplateName+" [core ${coreName}]",
3858 'COREKEY': jalviewjs_core_key,
3859 'CORENAME': coreName
3866 task jalviewjsPublishCoreTemplates {
3867 dependsOn jalviewjsBuildAllCores
3868 def inputFileName = "${jalviewDir}/${j2s_coretemplate_html}"
3869 def inputFile = file(inputFileName)
3870 def outputDir = "${jalviewDir}/${jalviewjsTransferSiteCoreDir}"
3872 def outputFiles = []
3873 jalviewjsCoreClasslists.each { cl ->
3874 def outputFile = "${outputDir}/${jalviewjsJalviewTemplateName}_${cl.name}.html"
3875 cl['outputfile'] = outputFile
3876 outputFiles += outputFile
3880 jalviewjsCoreClasslists.each { cl ->
3881 jalviewjsPublishCoreTemplate(cl.name, jalviewjsJalviewTemplateName, inputFile, cl.outputfile)
3884 inputs.file(inputFile)
3885 outputs.files(outputFiles)
3889 task jalviewjsSyncCore (type: Sync) {
3890 dependsOn jalviewjsBuildAllCores
3891 dependsOn jalviewjsPublishCoreTemplates
3892 def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjsTransferSiteCoreDir}")
3893 def outputDir = "${jalviewDir}/${jalviewjsSiteDir}"
3897 def outputFiles = []
3898 rename { filename ->
3899 outputFiles += "${outputDir}/${filename}"
3905 outputs.files outputFiles
3906 inputs.files inputFiles
3910 // this Copy version of TransferSiteJs will delete anything else in the target dir
3911 task jalviewjsCopyTransferSiteJs(type: Copy) {
3912 dependsOn jalviewjsTranspile
3913 from "${jalviewDir}/${jalviewjsTransferSiteJsDir}"
3914 into "${jalviewDir}/${jalviewjsSiteDir}"
3918 // this Sync version of TransferSite is used by buildship to keep the website automatically up to date when a file changes
3919 task jalviewjsSyncTransferSiteJs(type: Sync) {
3920 from "${jalviewDir}/${jalviewjsTransferSiteJsDir}"
3922 into "${jalviewDir}/${jalviewjsSiteDir}"
3929 jalviewjsSyncAllLibs.mustRunAfter jalviewjsCopyTransferSiteJs
3930 jalviewjsSyncResources.mustRunAfter jalviewjsCopyTransferSiteJs
3931 jalviewjsSyncSiteResources.mustRunAfter jalviewjsCopyTransferSiteJs
3932 jalviewjsSyncBuildProperties.mustRunAfter jalviewjsCopyTransferSiteJs
3934 jalviewjsSyncAllLibs.mustRunAfter jalviewjsSyncTransferSiteJs
3935 jalviewjsSyncResources.mustRunAfter jalviewjsSyncTransferSiteJs
3936 jalviewjsSyncSiteResources.mustRunAfter jalviewjsSyncTransferSiteJs
3937 jalviewjsSyncBuildProperties.mustRunAfter jalviewjsSyncTransferSiteJs
3940 task jalviewjsPrepareSite {
3942 description "Prepares the website folder including unzipping files and copying resources"
3943 dependsOn jalviewjsSyncAllLibs
3944 dependsOn jalviewjsSyncResources
3945 dependsOn jalviewjsSyncSiteResources
3946 dependsOn jalviewjsSyncBuildProperties
3947 dependsOn jalviewjsSyncCore
3951 task jalviewjsBuildSite {
3953 description "Builds the whole website including transpiled code"
3954 dependsOn jalviewjsCopyTransferSiteJs
3955 dependsOn jalviewjsPrepareSite
3959 task cleanJalviewjsTransferSite {
3961 delete "${jalviewDir}/${jalviewjsTransferSiteJsDir}"
3962 delete "${jalviewDir}/${jalviewjsTransferSiteLibDir}"
3963 delete "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}"
3964 delete "${jalviewDir}/${jalviewjsTransferSiteCoreDir}"
3969 task cleanJalviewjsSite {
3970 dependsOn cleanJalviewjsTransferSite
3972 delete "${jalviewDir}/${jalviewjsSiteDir}"
3977 task jalviewjsSiteTar(type: Tar) {
3979 description "Creates a tar.gz file for the website"
3980 dependsOn jalviewjsBuildSite
3981 def outputFilename = "jalviewjs-site-${JALVIEW_VERSION}.tar.gz"
3982 archiveFileName = outputFilename
3984 compression Compression.GZIP
3986 from "${jalviewDir}/${jalviewjsSiteDir}"
3987 into jalviewjs_site_dir // this is inside the tar file
3989 inputs.dir("${jalviewDir}/${jalviewjsSiteDir}")
3993 task jalviewjsServer {
3995 def filename = "jalviewjsTest.html"
3996 description "Starts a webserver on localhost to test the website. See ${filename} to access local site on most recently used port."
3997 def htmlFile = "${jalviewDirAbsolutePath}/${filename}"
4002 def f = Class.forName("org.gradle.plugins.javascript.envjs.http.simple.SimpleHttpFileServerFactory")
4003 factory = f.newInstance()
4004 } catch (ClassNotFoundException e) {
4005 throw new GradleException("Unable to create SimpleHttpFileServerFactory")
4007 def port = Integer.valueOf(jalviewjs_server_port)
4012 while(port < start+1000 && !running) {
4014 def doc_root = new File("${jalviewDirAbsolutePath}/${jalviewjsSiteDir}")
4015 jalviewjsServer = factory.start(doc_root, port)
4017 url = jalviewjsServer.getResourceUrl(jalviewjs_server_resource)
4018 println("SERVER STARTED with document root ${doc_root}.")
4019 println("Go to "+url+" . Run gradle --stop to stop (kills all gradle daemons).")
4020 println("For debug: "+url+"?j2sdebug")
4021 println("For verbose: "+url+"?j2sverbose")
4022 } catch (Exception e) {
4027 <p><a href="${url}">JalviewJS Test. <${url}></a></p>
4028 <p><a href="${url}?j2sdebug">JalviewJS Test with debug. <${url}?j2sdebug></a></p>
4029 <p><a href="${url}?j2sverbose">JalviewJS Test with verbose. <${url}?j2sdebug></a></p>
4031 jalviewjsCoreClasslists.each { cl ->
4032 def urlcore = jalviewjsServer.getResourceUrl(file(cl.outputfile).getName())
4034 <p><a href="${urlcore}">${jalviewjsJalviewTemplateName} [core ${cl.name}]. <${urlcore}></a></p>
4036 println("For core ${cl.name}: "+urlcore)
4039 file(htmlFile).text = htmlText
4042 outputs.file(htmlFile)
4043 outputs.upToDateWhen({false})
4047 task cleanJalviewjsAll {
4049 description "Delete all configuration and build artifacts to do with JalviewJS build"
4050 dependsOn cleanJalviewjsSite
4051 dependsOn jalviewjsEclipsePaths
4054 delete "${jalviewDir}/${jalviewjsBuildDir}"
4055 delete "${jalviewDir}/${eclipse_bin_dir}"
4056 if (eclipseWorkspace != null && file(eclipseWorkspace.getAbsolutePath()+"/.metadata").exists()) {
4057 delete file(eclipseWorkspace.getAbsolutePath()+"/.metadata")
4059 delete jalviewjsJ2sAltSettingsFileName
4062 outputs.upToDateWhen( { false } )
4066 task jalviewjsIDE_checkJ2sPlugin {
4067 group "00 JalviewJS in Eclipse"
4068 description "Compare the swingjs/net.sf.j2s.core(-j11)?.jar file with the Eclipse IDE's plugin version (found in the 'dropins' dir)"
4071 def j2sPlugin = string("${jalviewDir}/${jalviewjsJ2sPlugin}")
4072 def j2sPluginFile = file(j2sPlugin)
4073 def eclipseHome = System.properties["eclipse.home.location"]
4074 if (eclipseHome == null || ! IN_ECLIPSE) {
4075 throw new StopExecutionException("Cannot find running Eclipse home from System.properties['eclipse.home.location']. Skipping J2S Plugin Check.")
4077 def eclipseJ2sPluginDirs = [ "${eclipseHome}/dropins" ]
4078 def altPluginsDir = System.properties["org.eclipse.equinox.p2.reconciler.dropins.directory"]
4079 if (altPluginsDir != null && file(altPluginsDir).exists()) {
4080 eclipseJ2sPluginDirs += altPluginsDir
4082 def foundPlugin = false
4083 def j2sPluginFileName = j2sPluginFile.getName()
4084 def eclipseJ2sPlugin
4085 def eclipseJ2sPluginFile
4086 eclipseJ2sPluginDirs.any { dir ->
4087 eclipseJ2sPlugin = "${dir}/${j2sPluginFileName}"
4088 eclipseJ2sPluginFile = file(eclipseJ2sPlugin)
4089 if (eclipseJ2sPluginFile.exists()) {
4095 def msg = "Eclipse J2S Plugin is not installed (could not find '${j2sPluginFileName}' in\n"+eclipseJ2sPluginDirs.join("\n")+"\n)\nTry running task jalviewjsIDE_copyJ2sPlugin"
4096 System.err.println(msg)
4097 throw new StopExecutionException(msg)
4100 def digest = MessageDigest.getInstance("MD5")
4102 digest.update(j2sPluginFile.text.bytes)
4103 def j2sPluginMd5 = new BigInteger(1, digest.digest()).toString(16).padLeft(32, '0')
4105 digest.update(eclipseJ2sPluginFile.text.bytes)
4106 def eclipseJ2sPluginMd5 = new BigInteger(1, digest.digest()).toString(16).padLeft(32, '0')
4108 if (j2sPluginMd5 != eclipseJ2sPluginMd5) {
4109 def msg = "WARNING! Eclipse J2S Plugin '${eclipseJ2sPlugin}' is different to this commit's version '${j2sPlugin}'"
4110 System.err.println(msg)
4111 throw new StopExecutionException(msg)
4113 def msg = "Eclipse J2S Plugin '${eclipseJ2sPlugin}' is the same as '${j2sPlugin}' (this is good)"
4119 task jalviewjsIDE_copyJ2sPlugin {
4120 group "00 JalviewJS in Eclipse"
4121 description "Copy the swingjs/net.sf.j2s.core(-j11)?.jar file into the Eclipse IDE's 'dropins' dir"
4124 def j2sPlugin = string("${jalviewDir}/${jalviewjsJ2sPlugin}")
4125 def j2sPluginFile = file(j2sPlugin)
4126 def eclipseHome = System.properties["eclipse.home.location"]
4127 if (eclipseHome == null || ! IN_ECLIPSE) {
4128 throw new StopExecutionException("Cannot find running Eclipse home from System.properties['eclipse.home.location']. NOT copying J2S Plugin.")
4130 def eclipseJ2sPlugin = "${eclipseHome}/dropins/${j2sPluginFile.getName()}"
4131 def eclipseJ2sPluginFile = file(eclipseJ2sPlugin)
4132 def msg = "WARNING! Copying this commit's j2s plugin '${j2sPlugin}' to Eclipse J2S Plugin '${eclipseJ2sPlugin}'\n* May require an Eclipse restart"
4133 System.err.println(msg)
4136 eclipseJ2sPluginFile.getParentFile().mkdirs()
4137 into eclipseJ2sPluginFile.getParent()
4143 task jalviewjsIDE_j2sFile {
4144 group "00 JalviewJS in Eclipse"
4145 description "Creates the .j2s file"
4146 dependsOn jalviewjsCreateJ2sSettings
4150 task jalviewjsIDE_SyncCore {
4151 group "00 JalviewJS in Eclipse"
4152 description "Build the core js lib closures listed in the classlists dir and publish core html from template"
4153 dependsOn jalviewjsSyncCore
4157 task jalviewjsIDE_SyncSiteAll {
4158 dependsOn jalviewjsSyncAllLibs
4159 dependsOn jalviewjsSyncResources
4160 dependsOn jalviewjsSyncSiteResources
4161 dependsOn jalviewjsSyncBuildProperties
4165 cleanJalviewjsTransferSite.mustRunAfter jalviewjsIDE_SyncSiteAll
4168 task jalviewjsIDE_PrepareSite {
4169 group "00 JalviewJS in Eclipse"
4170 description "Sync libs and resources to site dir, but not closure cores"
4172 dependsOn jalviewjsIDE_SyncSiteAll
4173 //dependsOn cleanJalviewjsTransferSite // not sure why this clean is here -- will slow down a re-run of this task
4177 task jalviewjsIDE_AssembleSite {
4178 group "00 JalviewJS in Eclipse"
4179 description "Assembles unzipped supporting zipfiles, resources, site resources and closure cores into the Eclipse transpiled site"
4180 dependsOn jalviewjsPrepareSite
4184 task jalviewjsIDE_SiteClean {
4185 group "00 JalviewJS in Eclipse"
4186 description "Deletes the Eclipse transpiled site"
4187 dependsOn cleanJalviewjsSite
4191 task jalviewjsIDE_Server {
4192 group "00 JalviewJS in Eclipse"
4193 description "Starts a webserver on localhost to test the website"
4194 dependsOn jalviewjsServer
4198 // buildship runs this at import or gradle refresh
4199 task eclipseSynchronizationTask {
4200 //dependsOn eclipseSetup
4201 dependsOn createBuildProperties
4203 dependsOn jalviewjsIDE_j2sFile
4204 dependsOn jalviewjsIDE_checkJ2sPlugin
4205 dependsOn jalviewjsIDE_PrepareSite
4210 // buildship runs this at build time or project refresh
4211 task eclipseAutoBuildTask {
4212 //dependsOn jalviewjsIDE_checkJ2sPlugin
4213 //dependsOn jalviewjsIDE_PrepareSite
4217 task jalviewjsCopyStderrLaunchFile(type: Copy) {
4218 from file(jalviewjs_stderr_launch)
4219 into jalviewjsSiteDir
4221 inputs.file jalviewjs_stderr_launch
4222 outputs.file jalviewjsStderrLaunchFilename
4225 task cleanJalviewjsChromiumUserDir {
4227 delete jalviewjsChromiumUserDir
4229 outputs.dir jalviewjsChromiumUserDir
4230 // always run when depended on
4231 outputs.upToDateWhen { !file(jalviewjsChromiumUserDir).exists() }
4234 task jalviewjsChromiumProfile {
4235 dependsOn cleanJalviewjsChromiumUserDir
4236 mustRunAfter cleanJalviewjsChromiumUserDir
4238 def firstRun = file("${jalviewjsChromiumUserDir}/First Run")
4241 mkdir jalviewjsChromiumProfileDir
4244 outputs.file firstRun
4247 task jalviewjsLaunchTest {
4249 description "Check JalviewJS opens in a browser"
4250 dependsOn jalviewjsBuildSite
4251 dependsOn jalviewjsCopyStderrLaunchFile
4252 dependsOn jalviewjsChromiumProfile
4254 def macOS = OperatingSystem.current().isMacOsX()
4255 def chromiumBinary = macOS ? jalviewjs_macos_chromium_binary : jalviewjs_chromium_binary
4256 if (chromiumBinary.startsWith("~/")) {
4257 chromiumBinary = System.getProperty("user.home") + chromiumBinary.substring(1)
4263 def timeoutms = Integer.valueOf(jalviewjs_chromium_overall_timeout) * 1000
4265 def binary = file(chromiumBinary)
4266 if (!binary.exists()) {
4267 throw new StopExecutionException("Could not find chromium binary '${chromiumBinary}'. Cannot run task ${name}.")
4269 stdout = new ByteArrayOutputStream()
4270 stderr = new ByteArrayOutputStream()
4273 if (jalviewjs_j2s_to_console.equals("true")) {
4274 execStdout = new org.apache.tools.ant.util.TeeOutputStream(
4277 execStderr = new org.apache.tools.ant.util.TeeOutputStream(
4285 "--no-sandbox", // --no-sandbox IS USED BY THE THORIUM APPIMAGE ON THE BUILDSERVER
4288 "--timeout=${timeoutms}",
4289 "--virtual-time-budget=${timeoutms}",
4290 "--user-data-dir=${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_chromium_user_dir}",
4291 "--profile-directory=${jalviewjs_chromium_profile_name}",
4292 "--allow-file-access-from-files",
4293 "--enable-logging=stderr",
4294 "file://${jalviewDirAbsolutePath}/${jalviewjsStderrLaunchFilename}"
4297 if (true || macOS) {
4298 ScheduledExecutorService executor = Executors.newScheduledThreadPool(3);
4299 Future f1 = executor.submit(
4302 standardOutput = execStdout
4303 errorOutput = execStderr
4304 executable(chromiumBinary)
4306 println "COMMAND: '"+commandLine.join(" ")+"'"
4308 executor.shutdownNow()
4312 def noChangeBytes = 0
4313 def noChangeIterations = 0
4314 executor.scheduleAtFixedRate(
4316 String stderrString = stderr.toString()
4317 // shutdown the task if we have a success string
4318 if (stderrString.contains(jalviewjs_desktop_init_string)) {
4321 executor.shutdownNow()
4323 // if no change in stderr for 10s then also end
4324 if (noChangeIterations >= jalviewjs_chromium_idle_timeout) {
4325 executor.shutdownNow()
4327 if (stderrString.length() == noChangeBytes) {
4328 noChangeIterations++
4330 noChangeBytes = stderrString.length()
4331 noChangeIterations = 0
4334 1, 1, TimeUnit.SECONDS)
4336 executor.schedule(new Runnable(){
4339 executor.shutdownNow()
4341 }, timeoutms, TimeUnit.MILLISECONDS)
4343 executor.awaitTermination(timeoutms+10000, TimeUnit.MILLISECONDS)
4344 executor.shutdownNow()
4351 stderr.toString().eachLine { line ->
4352 if (line.contains(jalviewjs_desktop_init_string)) {
4353 println("Found line '"+line+"'")
4359 throw new GradleException("Could not find evidence of Desktop launch in JalviewJS.")
4367 description "Build the JalviewJS site and run the launch test"
4368 dependsOn jalviewjsBuildSite
4369 dependsOn jalviewjsLaunchTest