1 /* Convention for properties. Read from gradle.properties, use lower_case_underlines for property names.
2 * For properties set within build.gradle, use camelCaseNoSpace.
4 import org.apache.tools.ant.filters.ReplaceTokens
5 import org.gradle.internal.os.OperatingSystem
6 import org.gradle.plugins.ide.internal.generator.PropertiesPersistableConfigurationObject
7 import org.gradle.api.internal.PropertiesTransformer
8 import org.gradle.util.ConfigureUtil
9 import org.gradle.plugins.ide.eclipse.model.Output
10 import org.gradle.plugins.ide.eclipse.model.Library
11 import java.security.MessageDigest
12 import java.util.regex.Matcher
13 import java.util.concurrent.Executors
14 import java.util.concurrent.Future
15 import java.util.concurrent.ScheduledExecutorService
16 import java.util.concurrent.TimeUnit
17 import groovy.transform.ExternalizeMethods
18 import groovy.util.XmlParser
19 import groovy.xml.XmlUtil
20 import groovy.json.JsonBuilder
21 import com.vladsch.flexmark.util.ast.Node
22 import com.vladsch.flexmark.html.HtmlRenderer
23 import com.vladsch.flexmark.parser.Parser
24 import com.vladsch.flexmark.util.data.MutableDataSet
25 import com.vladsch.flexmark.ext.gfm.tasklist.TaskListExtension
26 import com.vladsch.flexmark.ext.tables.TablesExtension
27 import com.vladsch.flexmark.ext.gfm.strikethrough.StrikethroughExtension
28 import com.vladsch.flexmark.ext.autolink.AutolinkExtension
29 import com.vladsch.flexmark.ext.anchorlink.AnchorLinkExtension
30 import com.vladsch.flexmark.ext.toc.TocExtension
31 import com.google.common.hash.HashCode
32 import com.google.common.hash.Hashing
33 import com.google.common.io.Files
34 import org.jsoup.Jsoup
35 import org.jsoup.nodes.Element
43 classpath "com.vladsch.flexmark:flexmark-all:0.62.0"
44 classpath "org.jsoup:jsoup:1.14.3"
45 classpath "com.eowise:gradle-imagemagick:0.5.1"
54 id "com.diffplug.spotless" version "6.18.0" //.gradle.spotless" "3.28.0"
55 id 'com.github.johnrengelman.shadow' version '8.1.1' // was 4.0.3
56 id "com.diffplug.gradle.spotless" version "3.28.0"
57 id 'com.install4j.gradle' version '10.0.3'
58 id 'com.dorongold.task-tree' version '2.1.1' // only needed to display task dependency tree with gradle task1 [task2 ...] taskTree
59 id 'com.palantir.git-version' version '0.13.0' apply false
70 // in ext the values are cast to Object. Ensure string values are cast as String (and not GStringImpl) for later use
71 def string(Object o) {
72 return o == null ? "" : o.toString()
75 def overrideProperties(String propsFileName, boolean output = false) {
76 if (propsFileName == null) {
79 def propsFile = file(propsFileName)
80 if (propsFile != null && propsFile.exists()) {
81 println("Using properties from file '${propsFileName}'")
83 def p = new Properties()
84 def localPropsFIS = new FileInputStream(propsFile)
90 if (project.hasProperty(key)) {
91 oldval = project.findProperty(key)
92 project.setProperty(key, val)
94 println("Overriding property '${key}' ('${oldval}') with ${file(propsFile).getName()} value '${val}'")
97 ext.setProperty(key, val)
99 println("Setting ext property '${key}' with ${file(propsFile).getName()}s value '${val}'")
103 } catch (Exception e) {
104 println("Exception reading local.properties")
111 jalviewDirAbsolutePath = file(jalviewDir).getAbsolutePath()
112 jalviewDirRelativePath = jalviewDir
115 getdownChannelName = CHANNEL.toLowerCase()
116 // default to "default". Currently only has different cosmetics for "develop", "release", "default"
117 propertiesChannelName = ["develop", "release", "test-release", "jalviewjs", "jalviewjs-release" ].contains(getdownChannelName) ? getdownChannelName : "default"
118 channelDirName = propertiesChannelName
119 // Import channel_properties
120 if (getdownChannelName.startsWith("develop-")) {
121 channelDirName = "develop-SUFFIX"
123 channelDir = string("${jalviewDir}/${channel_properties_dir}/${channelDirName}")
124 channelGradleProperties = string("${channelDir}/channel_gradle.properties")
125 channelPropsFile = string("${channelDir}/${resource_dir}/${channel_props}")
126 overrideProperties(channelGradleProperties, false)
127 // local build environment properties
128 // can be "projectDir/local.properties"
129 overrideProperties("${projectDir}/local.properties", true)
130 // or "../projectDir_local.properties"
131 overrideProperties(projectDir.getParent() + "/" + projectDir.getName() + "_local.properties", true)
134 // Import releaseProps from the RELEASE file
135 // or a file specified via JALVIEW_RELEASE_FILE if defined
136 // Expect jalview.version and target release branch in jalview.release
137 releaseProps = new Properties();
138 def releasePropFile = findProperty("JALVIEW_RELEASE_FILE");
139 def defaultReleasePropFile = "${jalviewDirAbsolutePath}/RELEASE";
141 (new File(releasePropFile!=null ? releasePropFile : defaultReleasePropFile)).withInputStream {
142 releaseProps.load(it)
144 } catch (Exception fileLoadError) {
145 throw new Error("Couldn't load release properties file "+(releasePropFile==null ? defaultReleasePropFile : "from custom location: releasePropFile"),fileLoadError);
148 // Set JALVIEW_VERSION if it is not already set
149 if (findProperty("JALVIEW_VERSION")==null || "".equals(JALVIEW_VERSION)) {
150 JALVIEW_VERSION = releaseProps.get("jalview.version")
152 println("JALVIEW_VERSION is set to '${JALVIEW_VERSION}'")
154 // this property set when running Eclipse headlessly
155 j2sHeadlessBuildProperty = string("net.sf.j2s.core.headlessbuild")
156 // this property set by Eclipse
157 eclipseApplicationProperty = string("eclipse.application")
158 // CHECK IF RUNNING FROM WITHIN ECLIPSE
159 def eclipseApplicationPropertyVal = System.properties[eclipseApplicationProperty]
160 IN_ECLIPSE = eclipseApplicationPropertyVal != null && eclipseApplicationPropertyVal.startsWith("org.eclipse.ui.")
161 // BUT WITHOUT THE HEADLESS BUILD PROPERTY SET
162 if (System.properties[j2sHeadlessBuildProperty].equals("true")) {
163 println("Setting IN_ECLIPSE to ${IN_ECLIPSE} as System.properties['${j2sHeadlessBuildProperty}'] == '${System.properties[j2sHeadlessBuildProperty]}'")
167 println("WITHIN ECLIPSE IDE")
169 println("HEADLESS BUILD")
172 J2S_ENABLED = (project.hasProperty('j2s.compiler.status') && project['j2s.compiler.status'] != null && project['j2s.compiler.status'] == "enable")
174 println("J2S ENABLED")
177 System.properties.sort { it.key }.each {
178 key, val -> println("SYSTEM PROPERTY ${key}='${val}'")
181 if (false && IN_ECLIPSE) {
182 jalviewDir = jalviewDirAbsolutePath
187 buildDate = new Date().format("yyyyMMdd")
190 bareSourceDir = string(source_dir)
191 sourceDir = string("${jalviewDir}/${bareSourceDir}")
192 resourceDir = string("${jalviewDir}/${resource_dir}")
193 bareTestSourceDir = string(test_source_dir)
194 testDir = string("${jalviewDir}/${bareTestSourceDir}")
196 classesDir = string("${jalviewDir}/${classes_dir}")
197 outputDir = file(classesDir)
200 useClover = clover.equals("true")
201 cloverBuildDir = "${buildDir}/clover"
202 cloverInstrDir = file("${cloverBuildDir}/clover-instr")
203 cloverClassesDir = file("${cloverBuildDir}/clover-classes")
204 cloverReportDir = file("${buildDir}/reports/clover")
205 cloverTestInstrDir = file("${cloverBuildDir}/clover-test-instr")
206 cloverTestClassesDir = file("${cloverBuildDir}/clover-test-classes")
207 //cloverTestClassesDir = cloverClassesDir
208 cloverDb = string("${cloverBuildDir}/clover.db")
210 testSourceDir = useClover ? cloverTestInstrDir : testDir
211 testClassesDir = useClover ? cloverTestClassesDir : "${jalviewDir}/${test_output_dir}"
214 backgroundImageText = BACKGROUNDIMAGETEXT
215 getdownChannelDir = string("${getdown_website_dir}/${propertiesChannelName}")
216 getdownAppBaseDir = string("${jalviewDir}/${getdownChannelDir}/${JAVA_VERSION}")
217 getdownArchiveDir = string("${jalviewDir}/${getdown_archive_dir}")
218 getdownFullArchiveDir = null
219 getdownTextLines = []
220 getdownLaunchJvl = null
221 getdownVersionLaunchJvl = null
223 buildProperties = null
225 // the following values might be overridden by the CHANNEL switch
226 getdownDir = string("${getdownChannelName}/${JAVA_VERSION}")
227 getdownAppBase = string("${getdown_channel_base}/${getdownDir}")
228 getdownArchiveAppBase = getdown_archive_base
229 getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher}")
230 getdownAppDistDir = getdown_app_dir_alt
231 getdownImagesDir = string("${jalviewDir}/${getdown_images_dir}")
232 getdownImagesBuildDir = string("${buildDir}/imagemagick/getdown")
233 getdownSetAppBaseProperty = false // whether to pass the appbase and appdistdir to the application
234 reportRsyncCommand = false
235 jvlChannelName = CHANNEL.toLowerCase()
236 install4jSuffix = CHANNEL.substring(0, 1).toUpperCase() + CHANNEL.substring(1).toLowerCase(); // BUILD -> Build
237 install4jDMGDSStore = "${install4j_images_dir}/${install4j_dmg_ds_store}"
238 install4jDMGBackgroundImageDir = "${install4j_images_dir}"
239 install4jDMGBackgroundImageBuildDir = "build/imagemagick/install4j"
240 install4jDMGBackgroundImageFile = "${install4j_dmg_background}"
241 install4jInstallerName = "${jalview_name} Non-Release Installer"
242 install4jExecutableName = install4j_executable_name
243 install4jExtraScheme = "jalviewx"
244 install4jMacIconsFile = string("${install4j_images_dir}/${install4j_mac_icons_file}")
245 install4jWindowsIconsFile = string("${install4j_images_dir}/${install4j_windows_icons_file}")
246 install4jPngIconFile = string("${install4j_images_dir}/${install4j_png_icon_file}")
247 install4jBackground = string("${install4j_images_dir}/${install4j_background}")
248 install4jBuildDir = "${install4j_build_dir}/${JAVA_VERSION}"
249 install4jCheckSums = true
251 applicationName = "${jalview_name}"
255 // TODO: get bamboo build artifact URL for getdown artifacts
256 getdown_channel_base = bamboo_channelbase
257 getdownChannelName = string("${bamboo_planKey}/${JAVA_VERSION}")
258 getdownAppBase = string("${bamboo_channelbase}/${bamboo_planKey}${bamboo_getdown_channel_suffix}/${JAVA_VERSION}")
259 jvlChannelName += "_${getdownChannelName}"
260 // automatically add the test group Not-bamboo for exclusion
261 if ("".equals(testng_excluded_groups)) {
262 testng_excluded_groups = "Not-bamboo"
264 install4jExtraScheme = "jalviewb"
265 backgroundImageText = true
268 case [ "RELEASE", "JALVIEWJS-RELEASE" ]:
269 getdownAppDistDir = getdown_app_dir_release
270 getdownSetAppBaseProperty = true
271 reportRsyncCommand = true
273 install4jInstallerName = "${jalview_name} Installer"
277 getdownChannelName = CHANNEL.toLowerCase()+"/${JALVIEW_VERSION}"
278 getdownDir = string("${getdownChannelName}/${JAVA_VERSION}")
279 getdownAppBase = string("${getdown_channel_base}/${getdownDir}")
280 if (!file("${ARCHIVEDIR}/${package_dir}").exists()) {
281 throw new GradleException("Must provide an ARCHIVEDIR value to produce an archive distribution")
283 package_dir = string("${ARCHIVEDIR}/${package_dir}")
284 buildProperties = string("${ARCHIVEDIR}/${classes_dir}/${build_properties_file}")
287 reportRsyncCommand = true
288 install4jExtraScheme = "jalviewa"
292 getdownChannelName = string("archive/${JALVIEW_VERSION}")
293 getdownDir = string("${getdownChannelName}/${JAVA_VERSION}")
294 getdownAppBase = file(getdownAppBaseDir).toURI().toString()
295 if (!file("${ARCHIVEDIR}/${package_dir}").exists()) {
296 throw new GradleException("Must provide an ARCHIVEDIR value to produce an archive distribution [did not find '${ARCHIVEDIR}/${package_dir}']")
298 package_dir = string("${ARCHIVEDIR}/${package_dir}")
299 buildProperties = string("${ARCHIVEDIR}/${classes_dir}/${build_properties_file}")
302 reportRsyncCommand = true
303 getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher_local}")
304 install4jSuffix = "Archive"
305 install4jExtraScheme = "jalviewa"
308 case ~/^DEVELOP-([\.\-\w]*)$/:
309 def suffix = Matcher.lastMatcher[0][1]
310 reportRsyncCommand = true
311 getdownSetAppBaseProperty = true
312 JALVIEW_VERSION=JALVIEW_VERSION+"-d${suffix}-${buildDate}"
313 install4jSuffix = "Develop ${suffix}"
314 install4jExtraScheme = "jalviewd"
315 install4jInstallerName = "${jalview_name} Develop ${suffix} Installer"
316 getdownChannelName = string("develop-${suffix}")
317 getdownChannelDir = string("${getdown_website_dir}/${getdownChannelName}")
318 getdownAppBaseDir = string("${jalviewDir}/${getdownChannelDir}/${JAVA_VERSION}")
319 getdownDir = string("${getdownChannelName}/${JAVA_VERSION}")
320 getdownAppBase = string("${getdown_channel_base}/${getdownDir}")
321 channelSuffix = string(suffix)
322 backgroundImageText = true
326 reportRsyncCommand = true
327 getdownSetAppBaseProperty = true
328 // DEVELOP-RELEASE is usually associated with a Jalview release series so set the version
329 JALVIEW_VERSION=JALVIEW_VERSION+"-d${buildDate}"
331 install4jSuffix = "Develop"
332 install4jExtraScheme = "jalviewd"
333 install4jInstallerName = "${jalview_name} Develop Installer"
334 backgroundImageText = true
338 reportRsyncCommand = true
339 getdownSetAppBaseProperty = true
340 // Don't ignore transpile errors for release build
341 if (jalviewjs_ignore_transpile_errors.equals("true")) {
342 jalviewjs_ignore_transpile_errors = "false"
343 println("Setting jalviewjs_ignore_transpile_errors to 'false'")
345 JALVIEW_VERSION = JALVIEW_VERSION+"-test"
346 install4jSuffix = "Test"
347 install4jExtraScheme = "jalviewt"
348 install4jInstallerName = "${jalview_name} Test Installer"
349 backgroundImageText = true
352 case ~/^SCRATCH(|-[-\w]*)$/:
353 getdownChannelName = CHANNEL
354 JALVIEW_VERSION = JALVIEW_VERSION+"-"+CHANNEL
356 getdownDir = string("${getdownChannelName}/${JAVA_VERSION}")
357 getdownAppBase = string("${getdown_channel_base}/${getdownDir}")
358 reportRsyncCommand = true
359 install4jSuffix = "Scratch"
363 if (!file("${LOCALDIR}").exists()) {
364 throw new GradleException("Must provide a LOCALDIR value to produce a local distribution")
366 getdownAppBase = file(file("${LOCALDIR}").getAbsolutePath()).toURI().toString()
367 getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher_local}")
369 JALVIEW_VERSION = "TEST"
370 install4jSuffix = "Test-Local"
371 install4jExtraScheme = "jalviewt"
372 install4jInstallerName = "${jalview_name} Test Installer"
373 backgroundImageText = true
376 case [ "LOCAL", "JALVIEWJS" ]:
377 JALVIEW_VERSION = "TEST"
378 getdownAppBase = file(getdownAppBaseDir).toURI().toString()
379 getdownArchiveAppBase = file("${jalviewDir}/${getdown_archive_dir}").toURI().toString()
380 getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher_local}")
381 install4jExtraScheme = "jalviewl"
382 install4jCheckSums = false
385 default: // something wrong specified
386 throw new GradleException("CHANNEL must be one of BUILD, RELEASE, ARCHIVE, DEVELOP, TEST-RELEASE, SCRATCH-..., LOCAL [default]")
390 JALVIEW_VERSION_UNDERSCORES = JALVIEW_VERSION.replaceAll("\\.", "_")
391 hugoDataJsonFile = file("${jalviewDir}/${hugo_build_dir}/${hugo_data_installers_dir}/installers-${JALVIEW_VERSION_UNDERSCORES}.json")
392 hugoArchiveMdFile = file("${jalviewDir}/${hugo_build_dir}/${hugo_version_archive_dir}/Version-${JALVIEW_VERSION_UNDERSCORES}/_index.md")
393 // override getdownAppBase if requested
394 if (findProperty("getdown_appbase_override") != null) {
395 // revert to LOCAL if empty string
396 if (string(getdown_appbase_override) == "") {
397 getdownAppBase = file(getdownAppBaseDir).toURI().toString()
398 getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher_local}")
399 } else if (string(getdown_appbase_override).startsWith("file://")) {
400 getdownAppBase = string(getdown_appbase_override)
401 getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher_local}")
403 getdownAppBase = string(getdown_appbase_override)
405 println("Overriding getdown appbase with '${getdownAppBase}'")
407 // sanitise file name for jalview launcher file for this channel
408 jvlChannelName = jvlChannelName.replaceAll("[^\\w\\-]+", "_")
409 // install4j application and folder names
410 if (install4jSuffix == "") {
411 install4jBundleId = "${install4j_bundle_id}"
412 install4jWinApplicationId = install4j_release_win_application_id
414 applicationName = "${jalview_name} ${install4jSuffix}"
415 install4jBundleId = "${install4j_bundle_id}-" + install4jSuffix.toLowerCase()
416 // add int hash of install4jSuffix to the last part of the application_id
417 def id = install4j_release_win_application_id
418 def idsplitreverse = id.split("-").reverse()
419 idsplitreverse[0] = idsplitreverse[0].toInteger() + install4jSuffix.hashCode()
420 install4jWinApplicationId = idsplitreverse.reverse().join("-")
422 // sanitise folder and id names
423 // install4jApplicationFolder = e.g. "Jalview Build"
424 install4jApplicationFolder = applicationName
425 .replaceAll("[\"'~:/\\\\\\s]", "_") // replace all awkward filename chars " ' ~ : / \
426 .replaceAll("_+", "_") // collapse __
427 install4jInternalId = applicationName
429 .replaceAll("[^\\w\\-\\.]", "_") // replace other non [alphanumeric,_,-,.]
430 .replaceAll("_+", "") // collapse __
431 //.replaceAll("_*-_*", "-") // collapse _-_
432 install4jUnixApplicationFolder = applicationName
434 .replaceAll("[^\\w\\-\\.]", "_") // replace other non [alphanumeric,_,-,.]
435 .replaceAll("_+", "_") // collapse __
436 .replaceAll("_*-_*", "-") // collapse _-_
439 getdownWrapperLink = install4jUnixApplicationFolder // e.g. "jalview_local"
440 getdownAppDir = string("${getdownAppBaseDir}/${getdownAppDistDir}")
441 //getdownJ11libDir = "${getdownAppBaseDir}/${getdown_j11lib_dir}"
442 getdownResourceDir = string("${getdownAppBaseDir}/${getdown_resource_dir}")
443 getdownInstallDir = string("${getdownAppBaseDir}/${getdown_install_dir}")
444 getdownFilesDir = string("${jalviewDir}/${getdown_files_dir}/${JAVA_VERSION}/")
445 getdownFilesInstallDir = string("${getdownFilesDir}/${getdown_install_dir}")
446 /* compile without modules -- using classpath libraries
447 modules_compileClasspath = fileTree(dir: "${jalviewDir}/${j11modDir}", include: ["*.jar"])
448 modules_runtimeClasspath = modules_compileClasspath
454 apply plugin: "com.palantir.git-version"
455 def details = versionDetails()
456 gitHash = details.gitHash
457 gitBranch = details.branchName
458 } catch(org.gradle.api.internal.plugins.PluginApplicationException e) {
459 println("Not in a git repository. Using git values from RELEASE properties file.")
460 gitHash = releaseProps.getProperty("git.hash")
461 gitBranch = releaseProps.getProperty("git.branch")
462 } catch(java.lang.RuntimeException e1) {
463 throw new GradleException("Error with git-version plugin. Directory '.git' exists but versionDetails() cannot be found.")
466 println("Using a ${CHANNEL} profile.")
468 additional_compiler_args = []
469 // configure classpath/args for j8/j11 compilation
470 if (JAVA_VERSION.equals("1.8")) {
471 JAVA_INTEGER_VERSION = string("8")
474 libDistDir = j8libDir
475 compile_source_compatibility = 1.8
476 compile_target_compatibility = 1.8
477 // these are getdown.txt properties defined dependent on the JAVA_VERSION
478 getdownAltJavaMinVersion = string(findProperty("getdown_alt_java8_min_version"))
479 getdownAltJavaMaxVersion = string(findProperty("getdown_alt_java8_max_version"))
480 // this property is assigned below and expanded to multiple lines in the getdown task
481 getdownAltMultiJavaLocation = string(findProperty("getdown_alt_java8_txt_multi_java_location"))
482 // this property is for the Java library used in eclipse
483 eclipseJavaRuntimeName = string("JavaSE-1.8")
484 } else if (JAVA_VERSION.equals("11")) {
485 JAVA_INTEGER_VERSION = string("11")
487 libDistDir = j11libDir
488 compile_source_compatibility = 11
489 compile_target_compatibility = 11
490 getdownAltJavaMinVersion = string(findProperty("getdown_alt_java11_min_version"))
491 getdownAltJavaMaxVersion = string(findProperty("getdown_alt_java11_max_version"))
492 getdownAltMultiJavaLocation = string(findProperty("getdown_alt_java11_txt_multi_java_location"))
493 eclipseJavaRuntimeName = string("JavaSE-11")
494 /* compile without modules -- using classpath libraries
495 additional_compiler_args += [
496 '--module-path', modules_compileClasspath.asPath,
497 '--add-modules', j11modules
500 } else if (JAVA_VERSION.equals("17")) {
501 JAVA_INTEGER_VERSION = string("17")
503 libDistDir = j17libDir
504 compile_source_compatibility = 17
505 compile_target_compatibility = 17
506 getdownAltJavaMinVersion = string(findProperty("getdown_alt_java11_min_version"))
507 getdownAltJavaMaxVersion = string(findProperty("getdown_alt_java11_max_version"))
508 getdownAltMultiJavaLocation = string(findProperty("getdown_alt_java11_txt_multi_java_location"))
509 eclipseJavaRuntimeName = string("JavaSE-17")
510 /* compile without modules -- using classpath libraries
511 additional_compiler_args += [
512 '--module-path', modules_compileClasspath.asPath,
513 '--add-modules', j11modules
517 throw new GradleException("JAVA_VERSION=${JAVA_VERSION} not currently supported by Jalview")
522 JAVA_MIN_VERSION = JAVA_VERSION
523 JAVA_MAX_VERSION = JAVA_VERSION
524 jreInstallsDir = string(jre_installs_dir)
525 if (jreInstallsDir.startsWith("~/")) {
526 jreInstallsDir = System.getProperty("user.home") + jreInstallsDir.substring(1)
528 install4jDir = string("${jalviewDir}/${install4j_utils_dir}")
529 install4jConfFileName = string("jalview-install4j-conf.install4j")
530 install4jConfFile = file("${install4jDir}/${install4jConfFileName}")
531 install4jHomeDir = install4j_home_dir
532 if (install4jHomeDir.startsWith("~/")) {
533 install4jHomeDir = System.getProperty("user.home") + install4jHomeDir.substring(1)
536 resourceBuildDir = string("${buildDir}/resources")
537 resourcesBuildDir = string("${resourceBuildDir}/resources_build")
538 helpBuildDir = string("${resourceBuildDir}/help_build")
539 docBuildDir = string("${resourceBuildDir}/doc_build")
541 if (buildProperties == null) {
542 buildProperties = string("${resourcesBuildDir}/${build_properties_file}")
544 buildingHTML = string("${jalviewDir}/${doc_dir}/building.html")
545 helpParentDir = string("${jalviewDir}/${help_parent_dir}")
546 helpSourceDir = string("${helpParentDir}/${help_dir}")
547 helpFile = string("${helpBuildDir}/${help_dir}/help.jhm")
550 convertBinaryExpectedLocation = imagemagick_convert
551 if (convertBinaryExpectedLocation.startsWith("~/")) {
552 convertBinaryExpectedLocation = System.getProperty("user.home") + convertBinaryExpectedLocation.substring(1)
554 if (file(convertBinaryExpectedLocation).exists()) {
555 convertBinary = convertBinaryExpectedLocation
558 relativeBuildDir = file(jalviewDirAbsolutePath).toPath().relativize(buildDir.toPath())
559 jalviewjsBuildDir = string("${relativeBuildDir}/jalviewjs")
560 jalviewjsSiteDir = string("${jalviewjsBuildDir}/${jalviewjs_site_dir}")
562 jalviewjsTransferSiteJsDir = string(jalviewjsSiteDir)
564 jalviewjsTransferSiteJsDir = string("${jalviewjsBuildDir}/tmp/${jalviewjs_site_dir}_js")
566 jalviewjsTransferSiteLibDir = string("${jalviewjsBuildDir}/tmp/${jalviewjs_site_dir}_lib")
567 jalviewjsTransferSiteSwingJsDir = string("${jalviewjsBuildDir}/tmp/${jalviewjs_site_dir}_swingjs")
568 jalviewjsTransferSiteCoreDir = string("${jalviewjsBuildDir}/tmp/${jalviewjs_site_dir}_core")
569 jalviewjsJalviewCoreHtmlFile = string("")
570 jalviewjsJalviewCoreName = string(jalviewjs_core_name)
571 jalviewjsCoreClasslists = []
572 jalviewjsJalviewTemplateName = string(jalviewjs_name)
573 jalviewjsJ2sSettingsFileName = string("${jalviewDir}/${jalviewjs_j2s_settings}")
574 jalviewjsJ2sAltSettingsFileName = string("${jalviewDir}/${jalviewjs_j2s_alt_settings}")
575 jalviewjsJ2sProps = null
576 jalviewjsJ2sPlugin = jalviewjs_j2s_plugin
577 jalviewjsStderrLaunchFilename = "${jalviewjsSiteDir}/"+(file(jalviewjs_stderr_launch).getName())
579 eclipseWorkspace = null
580 eclipseBinary = string("")
581 eclipseVersion = string("")
584 jalviewjsChromiumUserDir = "${jalviewjsBuildDir}/${jalviewjs_chromium_user_dir}"
585 jalviewjsChromiumProfileDir = "${ext.jalviewjsChromiumUserDir}/${jalviewjs_chromium_profile_name}"
595 outputDir = file(classesDir)
599 srcDirs = [ resourcesBuildDir, docBuildDir, helpBuildDir ]
602 compileClasspath = files(sourceSets.main.java.outputDir)
603 compileClasspath += fileTree(dir: "${jalviewDir}/${libDir}", include: ["*.jar"])
605 runtimeClasspath = compileClasspath
606 runtimeClasspath += files(sourceSets.main.resources.srcDirs)
611 srcDirs cloverInstrDir
612 outputDir = cloverClassesDir
616 srcDirs = sourceSets.main.resources.srcDirs
619 compileClasspath = files( sourceSets.clover.java.outputDir )
620 //compileClasspath += files( testClassesDir )
621 compileClasspath += fileTree(dir: "${jalviewDir}/${libDir}", include: ["*.jar"])
622 compileClasspath += fileTree(dir: "${jalviewDir}/${clover_lib_dir}", include: ["*.jar"])
623 compileClasspath += fileTree(dir: "${jalviewDir}/${utils_dir}/testnglibs", include: ["**/*.jar"])
625 runtimeClasspath = compileClasspath
630 srcDirs testSourceDir
631 outputDir = file(testClassesDir)
635 srcDirs = useClover ? sourceSets.clover.resources.srcDirs : sourceSets.main.resources.srcDirs
638 compileClasspath = files( sourceSets.test.java.outputDir )
639 compileClasspath += useClover ? sourceSets.clover.compileClasspath : sourceSets.main.compileClasspath
640 compileClasspath += fileTree(dir: "${jalviewDir}/${utils_dir}/testnglibs", include: ["**/*.jar"])
642 runtimeClasspath = compileClasspath
643 runtimeClasspath += files(sourceSets.test.resources.srcDirs)
649 // eclipse project and settings files creation, also used by buildship
652 name = eclipse_project_name
654 natures 'org.eclipse.jdt.core.javanature',
655 'org.eclipse.jdt.groovy.core.groovyNature',
656 'org.eclipse.buildship.core.gradleprojectnature'
658 buildCommand 'org.eclipse.jdt.core.javabuilder'
659 buildCommand 'org.eclipse.buildship.core.gradleprojectbuilder'
663 //defaultOutputDir = sourceSets.main.java.outputDir
664 configurations.each{ c->
665 if (c.isCanBeResolved()) {
666 minusConfigurations += [c]
670 plusConfigurations = [ ]
674 def removeTheseToo = []
675 HashMap<String, Boolean> alreadyAddedSrcPath = new HashMap<>();
676 cp.entries.each { entry ->
677 // This conditional removes all src classpathentries that a) have already been added or b) aren't "src" or "test".
678 // e.g. this removes the resources dir being copied into bin/main, bin/test AND bin/clover
679 // we add the resources and help/help dirs in as libs afterwards (see below)
680 if (entry.kind == 'src') {
681 if (alreadyAddedSrcPath.getAt(entry.path) || !(entry.path == bareSourceDir || entry.path == bareTestSourceDir)) {
682 removeTheseToo += entry
684 alreadyAddedSrcPath.putAt(entry.path, true)
689 cp.entries.removeAll(removeTheseToo)
691 //cp.entries += new Output("${eclipse_bin_dir}/main")
692 if (file(helpParentDir).isDirectory()) {
693 cp.entries += new Library(fileReference(helpParentDir))
695 if (file(resourceDir).isDirectory()) {
696 cp.entries += new Library(fileReference(resourceDir))
699 HashMap<String, Boolean> alreadyAddedLibPath = new HashMap<>();
701 sourceSets.main.compileClasspath.findAll { it.name.endsWith(".jar") }.any {
702 //don't want to add outputDir as eclipse is using its own output dir in bin/main
703 if (it.isDirectory() || ! it.exists()) {
704 // don't add dirs to classpath, especially if they don't exist
705 return false // groovy "continue" in .any closure
707 def itPath = it.toString()
708 if (itPath.startsWith("${jalviewDirAbsolutePath}/")) {
709 // make relative path
710 itPath = itPath.substring(jalviewDirAbsolutePath.length()+1)
712 if (alreadyAddedLibPath.get(itPath)) {
713 //println("Not adding duplicate entry "+itPath)
715 //println("Adding entry "+itPath)
716 cp.entries += new Library(fileReference(itPath))
717 alreadyAddedLibPath.put(itPath, true)
721 sourceSets.test.compileClasspath.findAll { it.name.endsWith(".jar") }.any {
722 //no longer want to add outputDir as eclipse is using its own output dir in bin/main
723 if (it.isDirectory() || ! it.exists()) {
724 // don't add dirs to classpath
725 return false // groovy "continue" in .any closure
728 def itPath = it.toString()
729 if (itPath.startsWith("${jalviewDirAbsolutePath}/")) {
730 itPath = itPath.substring(jalviewDirAbsolutePath.length()+1)
732 if (alreadyAddedLibPath.get(itPath)) {
735 def lib = new Library(fileReference(itPath))
736 lib.entryAttributes["test"] = "true"
738 alreadyAddedLibPath.put(itPath, true)
746 containers 'org.eclipse.buildship.core.gradleclasspathcontainer'
751 // for the IDE, use java 11 compatibility
752 sourceCompatibility = compile_source_compatibility
753 targetCompatibility = compile_target_compatibility
754 javaRuntimeName = eclipseJavaRuntimeName
756 // add in jalview project specific properties/preferences into eclipse core preferences
758 withProperties { props ->
759 def jalview_prefs = new Properties()
760 def ins = new FileInputStream("${jalviewDirAbsolutePath}/${eclipse_extra_jdt_prefs_file}")
761 jalview_prefs.load(ins)
763 jalview_prefs.forEach { t, v ->
764 if (props.getAt(t) == null) {
768 // codestyle file -- overrides previous formatter prefs
769 def csFile = file("${jalviewDirAbsolutePath}/${eclipse_codestyle_file}")
770 if (csFile.exists()) {
771 XmlParser parser = new XmlParser()
772 def profiles = parser.parse(csFile)
773 def profile = profiles.'profile'.find { p -> (p.'@kind' == "CodeFormatterProfile" && p.'@name' == "Jalview") }
774 if (profile != null) {
775 profile.'setting'.each { s ->
777 def value = s.'@value'
778 if (id != null && value != null) {
779 props.putAt(id, value)
790 // Don't want these to be activated if in headless build
791 synchronizationTasks "eclipseSynchronizationTask"
792 //autoBuildTasks "eclipseAutoBuildTask"
798 /* hack to change eclipse prefs in .settings files other than org.eclipse.jdt.core.prefs */
799 // Class to allow updating arbitrary properties files
800 class PropertiesFile extends PropertiesPersistableConfigurationObject {
801 public PropertiesFile(PropertiesTransformer t) { super(t); }
802 @Override protected void load(Properties properties) { }
803 @Override protected void store(Properties properties) { }
804 @Override protected String getDefaultResourceName() { return ""; }
805 // This is necessary, because PropertiesPersistableConfigurationObject fails
806 // if no default properties file exists.
807 @Override public void loadDefaults() { load(new StringBufferInputStream("")); }
810 // Task to update arbitrary properties files (set outputFile)
811 class PropertiesFileTask extends PropertiesGeneratorTask<PropertiesFile> {
812 private final PropertiesFileContentMerger file;
813 public PropertiesFileTask() { file = new PropertiesFileContentMerger(getTransformer()); }
814 protected PropertiesFile create() { return new PropertiesFile(getTransformer()); }
815 protected void configure(PropertiesFile props) {
816 file.getBeforeMerged().execute(props); file.getWhenMerged().execute(props);
818 public void file(Closure closure) { ConfigureUtil.configure(closure, file); }
821 task eclipseUIPreferences(type: PropertiesFileTask) {
822 description = "Generate Eclipse additional settings"
823 def filename = "org.eclipse.jdt.ui.prefs"
824 outputFile = "$projectDir/.settings/${filename}" as File
827 it.load new FileInputStream("$projectDir/utils/eclipse/${filename}" as String)
832 task eclipseGroovyCorePreferences(type: PropertiesFileTask) {
833 description = "Generate Eclipse additional settings"
834 def filename = "org.eclipse.jdt.groovy.core.prefs"
835 outputFile = "$projectDir/.settings/${filename}" as File
838 it.load new FileInputStream("$projectDir/utils/eclipse/${filename}" as String)
843 task eclipseAllPreferences {
845 dependsOn eclipseUIPreferences
846 dependsOn eclipseGroovyCorePreferences
849 eclipseUIPreferences.mustRunAfter eclipseJdt
850 eclipseGroovyCorePreferences.mustRunAfter eclipseJdt
852 /* end of eclipse preferences hack */
860 delete cloverBuildDir
861 delete cloverReportDir
866 task cloverInstrJava(type: JavaExec) {
867 group = "Verification"
868 description = "Create clover instrumented source java files"
870 dependsOn cleanClover
872 inputs.files(sourceSets.main.allJava)
873 outputs.dir(cloverInstrDir)
875 //classpath = fileTree(dir: "${jalviewDir}/${clover_lib_dir}", include: ["*.jar"])
876 classpath = sourceSets.clover.compileClasspath
877 main = "com.atlassian.clover.CloverInstr"
885 cloverInstrDir.getPath(),
887 def srcFiles = sourceSets.main.allJava.files
890 { file -> file.absolutePath }
893 args argsList.toArray()
896 delete cloverInstrDir
897 println("Clover: About to instrument "+srcFiles.size() +" files")
902 task cloverInstrTests(type: JavaExec) {
903 group = "Verification"
904 description = "Create clover instrumented source test files"
906 dependsOn cleanClover
908 inputs.files(testDir)
909 outputs.dir(cloverTestInstrDir)
911 classpath = sourceSets.clover.compileClasspath
912 main = "com.atlassian.clover.CloverInstr"
922 cloverTestInstrDir.getPath(),
924 args argsList.toArray()
927 delete cloverTestInstrDir
928 println("Clover: About to instrument test files")
934 group = "Verification"
935 description = "Create clover instrumented all source files"
937 dependsOn cloverInstrJava
938 dependsOn cloverInstrTests
942 cloverClasses.dependsOn cloverInstr
945 task cloverConsoleReport(type: JavaExec) {
946 group = "Verification"
947 description = "Creates clover console report"
950 file(cloverDb).exists()
953 inputs.dir cloverClassesDir
955 classpath = sourceSets.clover.runtimeClasspath
956 main = "com.atlassian.clover.reporters.console.ConsoleReporter"
958 if (cloverreport_mem.length() > 0) {
959 maxHeapSize = cloverreport_mem
961 if (cloverreport_jvmargs.length() > 0) {
962 jvmArgs Arrays.asList(cloverreport_jvmargs.split(" "))
972 args argsList.toArray()
976 task cloverHtmlReport(type: JavaExec) {
977 group = "Verification"
978 description = "Creates clover HTML report"
981 file(cloverDb).exists()
984 def cloverHtmlDir = cloverReportDir
985 inputs.dir cloverClassesDir
986 outputs.dir cloverHtmlDir
988 classpath = sourceSets.clover.runtimeClasspath
989 main = "com.atlassian.clover.reporters.html.HtmlReporter"
991 if (cloverreport_mem.length() > 0) {
992 maxHeapSize = cloverreport_mem
994 if (cloverreport_jvmargs.length() > 0) {
995 jvmArgs Arrays.asList(cloverreport_jvmargs.split(" "))
1006 if (cloverreport_html_options.length() > 0) {
1007 argsList += cloverreport_html_options.split(" ")
1010 args argsList.toArray()
1014 task cloverXmlReport(type: JavaExec) {
1015 group = "Verification"
1016 description = "Creates clover XML report"
1019 file(cloverDb).exists()
1022 def cloverXmlFile = "${cloverReportDir}/clover.xml"
1023 inputs.dir cloverClassesDir
1024 outputs.file cloverXmlFile
1026 classpath = sourceSets.clover.runtimeClasspath
1027 main = "com.atlassian.clover.reporters.xml.XMLReporter"
1029 if (cloverreport_mem.length() > 0) {
1030 maxHeapSize = cloverreport_mem
1032 if (cloverreport_jvmargs.length() > 0) {
1033 jvmArgs Arrays.asList(cloverreport_jvmargs.split(" "))
1044 if (cloverreport_xml_options.length() > 0) {
1045 argsList += cloverreport_xml_options.split(" ")
1048 args argsList.toArray()
1053 group = "Verification"
1054 description = "Creates clover reports"
1056 dependsOn cloverXmlReport
1057 dependsOn cloverHtmlReport
1064 sourceCompatibility = compile_source_compatibility
1065 targetCompatibility = compile_target_compatibility
1066 options.compilerArgs += additional_compiler_args
1067 print ("Setting target compatibility to "+targetCompatibility+"\n")
1069 //classpath += configurations.cloverRuntime
1075 // JBP->BS should the print statement in doFirst refer to compile_target_compatibility ?
1076 sourceCompatibility = compile_source_compatibility
1077 targetCompatibility = compile_target_compatibility
1078 options.compilerArgs += additional_compiler_args
1079 options.encoding = "UTF-8"
1081 print ("Setting target compatibility to "+compile_target_compatibility+"\n")
1088 sourceCompatibility = compile_source_compatibility
1089 targetCompatibility = compile_target_compatibility
1090 options.compilerArgs += additional_compiler_args
1092 print ("Setting target compatibility to "+targetCompatibility+"\n")
1099 delete sourceSets.main.java.outputDir
1105 dependsOn cleanClover
1107 delete sourceSets.test.java.outputDir
1112 // format is a string like date.format("dd MMMM yyyy")
1113 def getDate(format) {
1114 return date.format(format)
1118 def convertMdToHtml (FileTree mdFiles, File cssFile) {
1119 MutableDataSet options = new MutableDataSet()
1121 def extensions = new ArrayList<>()
1122 extensions.add(AnchorLinkExtension.create())
1123 extensions.add(AutolinkExtension.create())
1124 extensions.add(StrikethroughExtension.create())
1125 extensions.add(TaskListExtension.create())
1126 extensions.add(TablesExtension.create())
1127 extensions.add(TocExtension.create())
1129 options.set(Parser.EXTENSIONS, extensions)
1131 // set GFM table parsing options
1132 options.set(TablesExtension.WITH_CAPTION, false)
1133 options.set(TablesExtension.COLUMN_SPANS, false)
1134 options.set(TablesExtension.MIN_HEADER_ROWS, 1)
1135 options.set(TablesExtension.MAX_HEADER_ROWS, 1)
1136 options.set(TablesExtension.APPEND_MISSING_COLUMNS, true)
1137 options.set(TablesExtension.DISCARD_EXTRA_COLUMNS, true)
1138 options.set(TablesExtension.HEADER_SEPARATOR_COLUMN_MATCH, true)
1140 options.set(AnchorLinkExtension.ANCHORLINKS_SET_ID, false)
1141 options.set(AnchorLinkExtension.ANCHORLINKS_ANCHOR_CLASS, "anchor")
1142 options.set(AnchorLinkExtension.ANCHORLINKS_SET_NAME, true)
1143 options.set(AnchorLinkExtension.ANCHORLINKS_TEXT_PREFIX, "<span class=\"octicon octicon-link\"></span>")
1145 Parser parser = Parser.builder(options).build()
1146 HtmlRenderer renderer = HtmlRenderer.builder(options).build()
1148 mdFiles.each { mdFile ->
1149 // add table of contents
1150 def mdText = "[TOC]\n"+mdFile.text
1152 // grab the first top-level title
1154 def titleRegex = /(?m)^#(\s+|([^#]))(.*)/
1155 def matcher = mdText =~ titleRegex
1156 if (matcher.size() > 0) {
1157 // matcher[0][2] is the first character of the title if there wasn't any whitespace after the #
1158 title = (matcher[0][2] != null ? matcher[0][2] : "")+matcher[0][3]
1160 // or use the filename if none found
1161 if (title == null) {
1162 title = mdFile.getName()
1165 Node document = parser.parse(mdText)
1166 String htmlBody = renderer.render(document)
1167 def htmlText = '''<html>
1168 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
1169 <html xmlns="http://www.w3.org/1999/xhtml">
1171 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
1172 <meta http-equiv="Content-Style-Type" content="text/css" />
1173 <meta name="generator" content="flexmark" />
1175 htmlText += ((title != null) ? " <title>${title}</title>" : '' )
1177 <style type="text/css">code{white-space: pre;}</style>
1179 htmlText += ((cssFile != null) ? cssFile.text : '')
1180 htmlText += '''</head>
1183 htmlText += htmlBody
1189 def htmlFilePath = mdFile.getPath().replaceAll(/\..*?$/, ".html")
1190 def htmlFile = file(htmlFilePath)
1191 println("Creating ${htmlFilePath}")
1192 htmlFile.text = htmlText
1197 task copyDocs(type: Copy) {
1198 def inputDir = "${jalviewDir}/${doc_dir}"
1199 def outputDir = "${docBuildDir}/${doc_dir}"
1203 include('**/*.html')
1205 filter(ReplaceTokens,
1209 'Version-Rel': JALVIEW_VERSION,
1210 'Year-Rel': getDate("yyyy")
1217 exclude('**/*.html')
1222 inputs.dir(inputDir)
1223 outputs.dir(outputDir)
1227 task convertMdFiles {
1229 def mdFiles = fileTree(dir: docBuildDir, include: "**/*.md")
1230 def cssFile = file("${jalviewDir}/${flexmark_css}")
1233 convertMdToHtml(mdFiles, cssFile)
1236 inputs.files(mdFiles)
1237 inputs.file(cssFile)
1240 mdFiles.each { mdFile ->
1241 def htmlFilePath = mdFile.getPath().replaceAll(/\..*?$/, ".html")
1242 htmlFiles.add(file(htmlFilePath))
1244 outputs.files(htmlFiles)
1248 def hugoTemplateSubstitutions(String input, Map extras=null) {
1249 def replacements = [
1250 DATE: getDate("yyyy-MM-dd"),
1251 CHANNEL: propertiesChannelName,
1252 APPLICATION_NAME: applicationName,
1254 GIT_BRANCH: gitBranch,
1255 VERSION: JALVIEW_VERSION,
1256 JAVA_VERSION: JAVA_VERSION,
1257 VERSION_UNDERSCORES: JALVIEW_VERSION_UNDERSCORES,
1262 if (extras != null) {
1263 extras.each{ k, v ->
1264 output = output.replaceAll("__${k}__", ((v == null)?"":v))
1267 replacements.each{ k, v ->
1268 output = output.replaceAll("__${k}__", ((v == null)?"":v))
1273 def mdFileComponents(File mdFile, def dateOnly=false) {
1276 if (mdFile.exists()) {
1277 def inFrontMatter = false
1278 def firstLine = true
1279 mdFile.eachLine { line ->
1280 if (line.matches("---")) {
1281 def prev = inFrontMatter
1282 inFrontMatter = firstLine
1283 if (inFrontMatter != prev)
1286 if (inFrontMatter) {
1288 if (m == line =~ /^date:\s*(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})/) {
1289 map["date"] = new Date().parse("yyyy-MM-dd HH:mm:ss", m[0][1])
1290 } else if (m == line =~ /^date:\s*(\d{4}-\d{2}-\d{2})/) {
1291 map["date"] = new Date().parse("yyyy-MM-dd", m[0][1])
1292 } else if (m == line =~ /^channel:\s*(\S+)/) {
1293 map["channel"] = m[0][1]
1294 } else if (m == line =~ /^version:\s*(\S+)/) {
1295 map["version"] = m[0][1]
1296 } else if (m == line =~ /^\s*([^:]+)\s*:\s*(\S.*)/) {
1297 map[ m[0][1] ] = m[0][2]
1299 if (dateOnly && map["date"] != null) {
1305 content += line+"\n"
1310 return dateOnly ? map["date"] : [map, content]
1313 task hugoTemplates {
1315 description "Create partially populated md pages for hugo website build"
1317 def hugoTemplatesDir = file("${jalviewDir}/${hugo_templates_dir}")
1318 def hugoBuildDir = "${jalviewDir}/${hugo_build_dir}"
1319 def templateFiles = fileTree(dir: hugoTemplatesDir)
1320 def releaseMdFile = file("${jalviewDir}/${releases_dir}/release-${JALVIEW_VERSION_UNDERSCORES}.md")
1321 def whatsnewMdFile = file("${jalviewDir}/${whatsnew_dir}/whatsnew-${JALVIEW_VERSION_UNDERSCORES}.md")
1322 def oldJvlFile = file("${jalviewDir}/${hugo_old_jvl}")
1323 def jalviewjsFile = file("${jalviewDir}/${hugo_jalviewjs}")
1326 // specific release template for version archive
1329 def givenDate = null
1330 def givenChannel = null
1331 def givenVersion = null
1332 if (CHANNEL == "RELEASE") {
1333 def (map, content) = mdFileComponents(releaseMdFile)
1334 givenDate = map.date
1335 givenChannel = map.channel
1336 givenVersion = map.version
1338 if (givenVersion != null && givenVersion != JALVIEW_VERSION) {
1339 throw new GradleException("'version' header (${givenVersion}) found in ${releaseMdFile} does not match JALVIEW_VERSION (${JALVIEW_VERSION})")
1342 if (whatsnewMdFile.exists())
1343 whatsnew = whatsnewMdFile.text
1346 def oldJvl = oldJvlFile.exists() ? oldJvlFile.collect{it} : []
1347 def jalviewjsLink = jalviewjsFile.exists() ? jalviewjsFile.collect{it} : []
1349 def changesHugo = null
1350 if (changes != null) {
1351 changesHugo = '<div class="release_notes">\n\n'
1352 def inSection = false
1353 changes.eachLine { line ->
1355 if (m == line =~ /^##([^#].*)$/) {
1357 changesHugo += "</div>\n\n"
1359 def section = m[0][1].trim()
1360 section = section.toLowerCase()
1361 section = section.replaceAll(/ +/, "_")
1362 section = section.replaceAll(/[^a-z0-9_\-]/, "")
1363 changesHugo += "<div class=\"${section}\">\n\n"
1365 } else if (m == line =~ /^(\s*-\s*)<!--([^>]+)-->(.*?)(<br\/?>)?\s*$/) {
1366 def comment = m[0][2].trim()
1367 if (comment != "") {
1368 comment = comment.replaceAll('"', """)
1370 comment.eachMatch(/JAL-\d+/) { jal -> issuekeys += jal }
1371 def newline = m[0][1]
1372 if (comment.trim() != "")
1373 newline += "{{<comment>}}${comment}{{</comment>}} "
1374 newline += m[0][3].trim()
1375 if (issuekeys.size() > 0)
1376 newline += " {{< jal issue=\"${issuekeys.join(",")}\" alt=\"${comment}\" >}}"
1377 if (m[0][4] != null)
1382 changesHugo += line+"\n"
1385 changesHugo += "\n</div>\n\n"
1387 changesHugo += '</div>'
1390 templateFiles.each{ templateFile ->
1391 def newFileName = string(hugoTemplateSubstitutions(templateFile.getName()))
1392 def relPath = hugoTemplatesDir.toPath().relativize(templateFile.toPath()).getParent()
1393 def newRelPathName = hugoTemplateSubstitutions( relPath.toString() )
1395 def outPathName = string("${hugoBuildDir}/$newRelPathName")
1399 rename(templateFile.getName(), newFileName)
1403 def newFile = file("${outPathName}/${newFileName}".toString())
1404 def content = newFile.text
1405 newFile.text = hugoTemplateSubstitutions(content,
1408 CHANGES: changesHugo,
1409 DATE: givenDate == null ? "" : givenDate.format("yyyy-MM-dd"),
1410 DRAFT: givenDate == null ? "true" : "false",
1411 JALVIEWJSLINK: jalviewjsLink.contains(JALVIEW_VERSION) ? "true" : "false",
1412 JVL_HEADER: oldJvl.contains(JALVIEW_VERSION) ? "jvl: true" : ""
1419 inputs.file(oldJvlFile)
1420 inputs.dir(hugoTemplatesDir)
1421 inputs.property("JALVIEW_VERSION", { JALVIEW_VERSION })
1422 inputs.property("CHANNEL", { CHANNEL })
1425 def getMdDate(File mdFile) {
1426 return mdFileComponents(mdFile, true)
1429 def getMdSections(String content) {
1431 def sectionContent = ""
1432 def sectionName = null
1433 content.eachLine { line ->
1435 if (m == line =~ /^##([^#].*)$/) {
1436 if (sectionName != null) {
1437 sections[sectionName] = sectionContent
1441 sectionName = m[0][1].trim()
1442 sectionName = sectionName.toLowerCase()
1443 sectionName = sectionName.replaceAll(/ +/, "_")
1444 sectionName = sectionName.replaceAll(/[^a-z0-9_\-]/, "")
1445 } else if (sectionName != null) {
1446 sectionContent += line+"\n"
1449 if (sectionContent != null) {
1450 sections[sectionName] = sectionContent
1456 task copyHelp(type: Copy) {
1457 def inputDir = helpSourceDir
1458 def outputDir = "${helpBuildDir}/${help_dir}"
1462 include('**/*.html')
1466 filter(ReplaceTokens,
1470 'Version-Rel': JALVIEW_VERSION,
1471 'Year-Rel': getDate("yyyy")
1478 exclude('**/*.html')
1485 inputs.dir(inputDir)
1486 outputs.files(helpFile)
1487 outputs.dir(outputDir)
1492 task releasesTemplates {
1494 description "Recreate whatsNew.html and releases.html from markdown files and templates in help"
1498 def releasesTemplateFile = file("${jalviewDir}/${releases_template}")
1499 def whatsnewTemplateFile = file("${jalviewDir}/${whatsnew_template}")
1500 def releasesHtmlFile = file("${helpBuildDir}/${help_dir}/${releases_html}")
1501 def whatsnewHtmlFile = file("${helpBuildDir}/${help_dir}/${whatsnew_html}")
1502 def releasesMdDir = "${jalviewDir}/${releases_dir}"
1503 def whatsnewMdDir = "${jalviewDir}/${whatsnew_dir}"
1506 def releaseMdFile = file("${releasesMdDir}/release-${JALVIEW_VERSION_UNDERSCORES}.md")
1507 def whatsnewMdFile = file("${whatsnewMdDir}/whatsnew-${JALVIEW_VERSION_UNDERSCORES}.md")
1509 if (CHANNEL == "RELEASE") {
1510 if (!releaseMdFile.exists()) {
1511 throw new GradleException("File ${releaseMdFile} must be created for RELEASE")
1513 if (!whatsnewMdFile.exists()) {
1514 throw new GradleException("File ${whatsnewMdFile} must be created for RELEASE")
1518 def releaseFiles = fileTree(dir: releasesMdDir, include: "release-*.md")
1519 def releaseFilesDates = releaseFiles.collectEntries {
1520 [(it): getMdDate(it)]
1522 releaseFiles = releaseFiles.sort { a,b -> releaseFilesDates[a].compareTo(releaseFilesDates[b]) }
1524 def releasesTemplate = releasesTemplateFile.text
1525 def m = releasesTemplate =~ /(?s)__VERSION_LOOP_START__(.*)__VERSION_LOOP_END__/
1526 def versionTemplate = m[0][1]
1528 MutableDataSet options = new MutableDataSet()
1530 def extensions = new ArrayList<>()
1531 options.set(Parser.EXTENSIONS, extensions)
1532 options.set(Parser.HTML_BLOCK_COMMENT_ONLY_FULL_LINE, true)
1534 Parser parser = Parser.builder(options).build()
1535 HtmlRenderer renderer = HtmlRenderer.builder(options).build()
1537 def actualVersions = releaseFiles.collect { rf ->
1538 def (rfMap, rfContent) = mdFileComponents(rf)
1539 return rfMap.version
1541 def versionsHtml = ""
1542 def linkedVersions = []
1543 releaseFiles.reverse().each { rFile ->
1544 def (rMap, rContent) = mdFileComponents(rFile)
1546 def versionLink = ""
1547 def partialVersion = ""
1548 def firstPart = true
1549 rMap.version.split("\\.").each { part ->
1550 def displayPart = ( firstPart ? "" : "." ) + part
1551 partialVersion += displayPart
1553 linkedVersions.contains(partialVersion)
1554 || ( actualVersions.contains(partialVersion) && partialVersion != rMap.version )
1556 versionLink += displayPart
1558 versionLink += "<a id=\"Jalview.${partialVersion}\">${displayPart}</a>"
1559 linkedVersions += partialVersion
1563 def displayDate = releaseFilesDates[rFile].format("dd/MM/yyyy")
1566 def rContentProcessed = ""
1567 rContent.eachLine { line ->
1568 if (lm == line =~ /^(\s*-)(\s*<!--[^>]*?-->)(.*)$/) {
1569 line = "${lm[0][1]}${lm[0][3]}${lm[0][2]}"
1570 } else if (lm == line =~ /^###([^#]+.*)$/) {
1571 line = "_${lm[0][1].trim()}_"
1573 rContentProcessed += line + "\n"
1576 def rContentSections = getMdSections(rContentProcessed)
1577 def rVersion = versionTemplate
1578 if (rVersion != "") {
1579 def rNewFeatures = rContentSections["new_features"]
1580 def rIssuesResolved = rContentSections["issues_resolved"]
1581 Node newFeaturesNode = parser.parse(rNewFeatures)
1582 String newFeaturesHtml = renderer.render(newFeaturesNode)
1583 Node issuesResolvedNode = parser.parse(rIssuesResolved)
1584 String issuesResolvedHtml = renderer.render(issuesResolvedNode)
1585 rVersion = hugoTemplateSubstitutions(rVersion,
1587 VERSION: rMap.version,
1588 VERSION_LINK: versionLink,
1589 DISPLAY_DATE: displayDate,
1590 NEW_FEATURES: newFeaturesHtml,
1591 ISSUES_RESOLVED: issuesResolvedHtml
1594 versionsHtml += rVersion
1598 releasesTemplate = releasesTemplate.replaceAll("(?s)__VERSION_LOOP_START__.*__VERSION_LOOP_END__", versionsHtml)
1599 releasesTemplate = hugoTemplateSubstitutions(releasesTemplate)
1600 releasesHtmlFile.text = releasesTemplate
1602 if (whatsnewMdFile.exists()) {
1603 def wnDisplayDate = releaseFilesDates[releaseMdFile] != null ? releaseFilesDates[releaseMdFile].format("dd MMMM yyyy") : ""
1604 def whatsnewMd = hugoTemplateSubstitutions(whatsnewMdFile.text)
1605 Node whatsnewNode = parser.parse(whatsnewMd)
1606 String whatsnewHtml = renderer.render(whatsnewNode)
1607 whatsnewHtml = whatsnewTemplateFile.text.replaceAll("__WHATS_NEW__", whatsnewHtml)
1608 whatsnewHtmlFile.text = hugoTemplateSubstitutions(whatsnewHtml,
1610 VERSION: JALVIEW_VERSION,
1611 DISPLAY_DATE: wnDisplayDate
1614 } else if (gradle.taskGraph.hasTask(":linkCheck")) {
1615 whatsnewHtmlFile.text = "Development build " + getDate("yyyy-MM-dd HH:mm:ss")
1620 inputs.file(releasesTemplateFile)
1621 inputs.file(whatsnewTemplateFile)
1622 inputs.dir(releasesMdDir)
1623 inputs.dir(whatsnewMdDir)
1624 outputs.file(releasesHtmlFile)
1625 outputs.file(whatsnewHtmlFile)
1630 task copyResources(type: Copy) {
1632 description = "Copy (and make text substitutions in) the resources dir to the build area"
1634 def inputDir = resourceDir
1635 def outputDir = resourcesBuildDir
1639 include('**/*.html')
1641 filter(ReplaceTokens,
1645 'Version-Rel': JALVIEW_VERSION,
1646 'Year-Rel': getDate("yyyy")
1653 exclude('**/*.html')
1658 inputs.dir(inputDir)
1659 outputs.dir(outputDir)
1662 task copyChannelResources(type: Copy) {
1663 dependsOn copyResources
1665 description = "Copy the channel resources dir to the build resources area"
1667 def inputDir = "${channelDir}/${resource_dir}"
1668 def outputDir = resourcesBuildDir
1670 include(channel_props)
1671 filter(ReplaceTokens,
1675 'SUFFIX': channelSuffix
1680 exclude(channel_props)
1684 inputs.dir(inputDir)
1685 outputs.dir(outputDir)
1688 task createBuildProperties(type: WriteProperties) {
1689 dependsOn copyResources
1690 dependsOn copyChannelResources
1692 description = "Create the ${buildProperties} file"
1694 inputs.dir(sourceDir)
1695 inputs.dir(resourcesBuildDir)
1696 outputFile (buildProperties)
1697 // taking time specific comment out to allow better incremental builds
1698 comment "--Jalview Build Details--\n"+getDate("yyyy-MM-dd HH:mm:ss")
1699 //comment "--Jalview Build Details--\n"+getDate("yyyy-MM-dd")
1700 property "BUILD_DATE", getDate("HH:mm:ss dd MMMM yyyy")
1701 property "VERSION", JALVIEW_VERSION
1702 property "INSTALLATION", INSTALLATION+" git-commit:"+gitHash+" ["+gitBranch+"]"
1703 property "JAVA_COMPILE_VERSION", JAVA_INTEGER_VERSION
1704 if (getdownSetAppBaseProperty) {
1705 property "GETDOWNAPPBASE", getdownAppBase
1706 property "GETDOWNAPPDISTDIR", getdownAppDistDir
1708 outputs.file(outputFile)
1712 task buildIndices(type: JavaExec) {
1714 //dependsOn releasesTemplates
1715 classpath = sourceSets.main.compileClasspath
1716 main = "com.sun.java.help.search.Indexer"
1717 workingDir = "${helpBuildDir}/${help_dir}"
1720 inputs.dir("${workingDir}/${argDir}")
1722 outputs.dir("${classesDir}/doc")
1723 outputs.dir("${classesDir}/help")
1724 outputs.file("${workingDir}/JavaHelpSearch/DOCS")
1725 outputs.file("${workingDir}/JavaHelpSearch/DOCS.TAB")
1726 outputs.file("${workingDir}/JavaHelpSearch/OFFSETS")
1727 outputs.file("${workingDir}/JavaHelpSearch/POSITIONS")
1728 outputs.file("${workingDir}/JavaHelpSearch/SCHEMA")
1729 outputs.file("${workingDir}/JavaHelpSearch/TMAP")
1732 task buildResources {
1733 dependsOn copyResources
1734 dependsOn copyChannelResources
1735 dependsOn createBuildProperties
1739 dependsOn buildResources
1742 //dependsOn releasesTemplates
1743 dependsOn convertMdFiles
1744 dependsOn buildIndices
1748 // random block of dependencies
1749 compileJava.dependsOn prepare
1750 run.dependsOn compileJava
1751 //run.dependsOn prepare
1752 compileTestJava.dependsOn compileJava //
1753 compileTestJava.dependsOn buildIndices //
1754 processResources.dependsOn copyChannelResources //
1755 processResources.dependsOn copyResources //
1756 processResources.dependsOn createBuildProperties //
1757 processResources.dependsOn copyDocs //
1758 processResources.dependsOn convertMdFiles //
1759 processResources.dependsOn copyHelp //
1760 processResources.dependsOn buildIndices //
1762 group = "Verification"
1763 description = "Runs all testTaskN tasks)"
1766 dependsOn cloverClasses
1768 dependsOn testClasses
1771 // not running tests in this task
1774 /* testTask0 is the main test task */
1775 task testTask0(type: Test) {
1776 group = "Verification"
1777 description = "The main test task. Runs all non-testTaskN-labelled tests (unless excluded)"
1779 includeGroups testng_groups.split(",")
1780 excludeGroups testng_excluded_groups.split(",")
1781 tasks.withType(Test).matching {it.name.startsWith("testTask") && it.name != name}.all {t -> excludeGroups t.name}
1783 useDefaultListeners=true
1787 /* separated tests */
1788 task testTask1(type: Test) {
1789 group = "Verification"
1790 description = "Tests that need to be isolated from the main test run"
1793 excludeGroups testng_excluded_groups.split(",")
1795 useDefaultListeners=true
1799 /* insert more testTaskNs here -- change N to next digit or other string */
1801 task testTaskN(type: Test) {
1802 group = "Verification"
1803 description = "Tests that need to be isolated from the main test run"
1806 excludeGroups testng_excluded_groups.split(",")
1808 useDefaultListeners=true
1814 * adapted from https://medium.com/@wasyl/pretty-tests-summary-in-gradle-744804dd676c
1815 * to summarise test results from all Test tasks
1817 /* START of test tasks results summary */
1818 import groovy.time.TimeCategory
1819 import org.gradle.api.tasks.testing.logging.TestExceptionFormat
1820 import org.gradle.api.tasks.testing.logging.TestLogEvent
1821 rootProject.ext.testsResults = [] // Container for tests summaries
1823 tasks.withType(Test).matching {t -> t.getName().startsWith("testTask")}.all { testTask ->
1825 // from original test task
1827 dependsOn cloverClasses
1829 dependsOn testClasses //?
1832 // run main tests first
1833 if (!testTask.name.equals("testTask0"))
1834 testTask.mustRunAfter "testTask0"
1836 testTask.testLogging { logging ->
1837 events TestLogEvent.FAILED
1838 // TestLogEvent.SKIPPED,
1839 // TestLogEvent.STANDARD_OUT,
1840 // TestLogEvent.STANDARD_ERROR
1842 exceptionFormat TestExceptionFormat.FULL
1845 showStackTraces true
1847 info.events = [ TestLogEvent.FAILED ]
1852 ignoreFailures = true // Always try to run all tests for all modules
1854 afterSuite { desc, result ->
1856 return // Only summarize results for whole modules
1858 def resultsInfo = [testTask.project.name, testTask.name, result, TimeCategory.minus(new Date(result.endTime), new Date(result.startTime)), testTask.reports.html.entryPoint]
1860 rootProject.ext.testsResults.add(resultsInfo)
1863 // from original test task
1864 maxHeapSize = "1024m"
1866 workingDir = jalviewDir
1867 def testLaf = project.findProperty("test_laf")
1868 if (testLaf != null) {
1869 println("Setting Test LaF to '${testLaf}'")
1870 systemProperty "laf", testLaf
1872 def testHiDPIScale = project.findProperty("test_HiDPIScale")
1873 if (testHiDPIScale != null) {
1874 println("Setting Test HiDPI Scale to '${testHiDPIScale}'")
1875 systemProperty "sun.java2d.uiScale", testHiDPIScale
1877 sourceCompatibility = compile_source_compatibility
1878 targetCompatibility = compile_target_compatibility
1879 jvmArgs += additional_compiler_args
1882 // this is not perfect yet -- we should only add the commandLineIncludePatterns to the
1883 // testTasks that include the tests, and exclude all from the others.
1884 // get --test argument
1885 filter.commandLineIncludePatterns = test.filter.commandLineIncludePatterns
1886 // do something with testTask.getCandidateClassFiles() to see if the test should silently finish because of the
1887 // commandLineIncludePatterns not matching anything. Instead we are doing setFailOnNoMatchingTests(false) below
1891 println("Running tests " + (useClover?"WITH":"WITHOUT") + " clover")
1896 /* don't fail on no matching tests (so --tests will run across all testTasks) */
1897 testTask.filter.setFailOnNoMatchingTests(false)
1899 /* ensure the "test" task dependsOn all the testTasks */
1900 test.dependsOn testTask
1903 gradle.buildFinished {
1904 def allResults = rootProject.ext.testsResults
1906 if (!allResults.isEmpty()) {
1907 printResults allResults
1908 allResults.each {r ->
1909 if (r[2].resultType == TestResult.ResultType.FAILURE)
1910 throw new GradleException("Failed tests!")
1915 private static String colString(styler, col, colour, text) {
1916 return col?"${styler[colour](text)}":text
1919 private static String getSummaryLine(s, pn, tn, rt, rc, rs, rf, rsk, t, col) {
1920 def colour = 'black'
1928 case TestResult.ResultType.SUCCESS:
1931 case TestResult.ResultType.FAILURE:
1939 StringBuilder sb = new StringBuilder()
1943 sb.append(" results: ")
1944 sb.append(colString(s, col && !nocol, colour, text))
1946 sb.append("${rc} tests, ")
1947 sb.append(colString(s, col && rs > 0, 'green', rs))
1948 sb.append(" successes, ")
1949 sb.append(colString(s, col && rf > 0, 'red', rf))
1950 sb.append(" failures, ")
1951 sb.append("${rsk} skipped) in ${t}")
1952 return sb.toString()
1955 private static void printResults(allResults) {
1957 // styler from https://stackoverflow.com/a/56139852
1958 def styler = 'black red green yellow blue magenta cyan white'.split().toList().withIndex(30).collectEntries { key, val -> [(key) : { "\033[${val}m${it}\033[0m" }] }
1961 def failedTests = false
1962 def summaryLines = []
1964 def totalsuccess = 0
1967 def totaltime = TimeCategory.getSeconds(0)
1968 // sort on project name then task name
1969 allResults.sort {a, b -> a[0] == b[0]? a[1]<=>b[1]:a[0] <=> b[0]}.each {
1970 def projectName = it[0]
1971 def taskName = it[1]
1975 def summaryCol = getSummaryLine(styler, projectName, taskName, result.resultType, result.testCount, result.successfulTestCount, result.failedTestCount, result.skippedTestCount, time, true)
1976 def summaryPlain = getSummaryLine(styler, projectName, taskName, result.resultType, result.testCount, result.successfulTestCount, result.failedTestCount, result.skippedTestCount, time, false)
1977 def reportLine = "Report file: ${report}"
1978 def ls = summaryPlain.length()
1979 def lr = reportLine.length()
1980 def m = [ls, lr].max()
1983 def info = [ls, summaryCol, reportLine]
1984 summaryLines.add(info)
1985 failedTests |= result.resultType == TestResult.ResultType.FAILURE
1986 totalcount += result.testCount
1987 totalsuccess += result.successfulTestCount
1988 totalfail += result.failedTestCount
1989 totalskip += result.skippedTestCount
1992 def totalSummaryCol = getSummaryLine(styler, "OVERALL", "", failedTests?TestResult.ResultType.FAILURE:TestResult.ResultType.SUCCESS, totalcount, totalsuccess, totalfail, totalskip, totaltime, true)
1993 def totalSummaryPlain = getSummaryLine(styler, "OVERALL", "", failedTests?TestResult.ResultType.FAILURE:TestResult.ResultType.SUCCESS, totalcount, totalsuccess, totalfail, totalskip, totaltime, false)
1994 def tls = totalSummaryPlain.length()
1995 if (tls > maxLength)
1997 def info = [tls, totalSummaryCol, null]
1998 summaryLines.add(info)
2000 def allSummaries = []
2001 for(sInfo : summaryLines) {
2003 def summary = sInfo[1]
2004 def report = sInfo[2]
2006 StringBuilder sb = new StringBuilder()
2007 sb.append("│" + summary + " " * (maxLength - ls) + "│")
2008 if (report != null) {
2009 sb.append("\n│" + report + " " * (maxLength - report.length()) + "│")
2011 allSummaries += sb.toString()
2014 println "┌${"${"─" * maxLength}"}┐"
2015 println allSummaries.join("\n├${"${"─" * maxLength}"}┤\n")
2016 println "└${"${"─" * maxLength}"}┘"
2018 /* END of test tasks results summary */
2022 task compileLinkCheck(type: JavaCompile) {
2024 classpath = files("${jalviewDir}/${utils_dir}")
2025 destinationDir = file("${jalviewDir}/${utils_dir}")
2026 source = fileTree(dir: "${jalviewDir}/${utils_dir}", include: ["HelpLinksChecker.java", "BufferedLineReader.java"])
2028 inputs.file("${jalviewDir}/${utils_dir}/HelpLinksChecker.java")
2029 inputs.file("${jalviewDir}/${utils_dir}/HelpLinksChecker.java")
2030 outputs.file("${jalviewDir}/${utils_dir}/HelpLinksChecker.class")
2031 outputs.file("${jalviewDir}/${utils_dir}/BufferedLineReader.class")
2035 task linkCheck(type: JavaExec) {
2037 dependsOn compileLinkCheck
2039 def helpLinksCheckerOutFile = file("${jalviewDir}/${utils_dir}/HelpLinksChecker.out")
2040 classpath = files("${jalviewDir}/${utils_dir}")
2041 main = "HelpLinksChecker"
2042 workingDir = "${helpBuildDir}"
2043 args = [ "${helpBuildDir}/${help_dir}", "-nointernet" ]
2045 def outFOS = new FileOutputStream(helpLinksCheckerOutFile, false) // false == don't append
2046 standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
2049 errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
2053 inputs.dir(helpBuildDir)
2054 outputs.file(helpLinksCheckerOutFile)
2059 // import the pubhtmlhelp target
2060 ant.properties.basedir = "${jalviewDir}"
2061 ant.properties.helpBuildDir = "${helpBuildDir}/${help_dir}"
2062 ant.importBuild "${utils_dir}/publishHelp.xml"
2065 task cleanPackageDir(type: Delete) {
2067 delete fileTree(dir: "${jalviewDir}/${package_dir}", include: "*.jar")
2071 // block of dependencies
2072 //compileTestJava.dependsOn compileLinkCheck //
2073 //copyChannelResources.dependsOn compileLinkCheck //
2074 //convertMdFiles.dependsOn compileLinkCheck //
2078 dependsOn //linkCheck
2081 attributes "Main-Class": main_class,
2082 "Permissions": "all-permissions",
2083 "Application-Name": applicationName,
2084 "Codebase": application_codebase,
2085 "Implementation-Version": JALVIEW_VERSION
2088 def outputDir = "${jalviewDir}/${package_dir}"
2089 outputDir = file(outputDir)
2090 archiveFileName = rootProject.name+".jar"
2091 duplicatesStrategy "EXCLUDE"
2098 exclude "**/*.jar.*"
2100 inputs.dir(sourceSets.main.java.outputDir)
2101 sourceSets.main.resources.srcDirs.each{ dir ->
2104 outputs.file("${outputDir}/${archiveFileName}")
2108 task copyJars(type: Copy) {
2109 from fileTree(dir: classesDir, include: "**/*.jar").files
2110 into "${jalviewDir}/${package_dir}"
2114 // doing a Sync instead of Copy as Copy doesn't deal with "outputs" very well
2115 task syncJars(type: Sync) {
2117 from fileTree(dir: "${jalviewDir}/${libDistDir}", include: "**/*.jar").files
2118 into "${jalviewDir}/${package_dir}"
2120 include jar.archiveFileName.getOrNull()
2127 description = "Put all required libraries in dist"
2128 // order of "cleanPackageDir", "copyJars", "jar" important!
2129 jar.mustRunAfter cleanPackageDir
2130 syncJars.mustRunAfter cleanPackageDir
2131 dependsOn cleanPackageDir
2134 outputs.dir("${jalviewDir}/${package_dir}")
2139 dependsOn cleanPackageDir
2146 group = "distribution"
2147 description = "Create a single jar file with all dependency libraries merged. Can be run with java -jar"
2151 from ("${jalviewDir}/${libDistDir}") {
2155 attributes "Implementation-Version": JALVIEW_VERSION,
2156 "Application-Name": applicationName
2159 duplicatesStrategy "INCLUDE"
2161 mainClassName = shadow_jar_main_class
2163 archiveClassifier = "all-"+JALVIEW_VERSION+"-j"+JAVA_VERSION
2167 task getdownImagesCopy() {
2168 inputs.dir getdownImagesDir
2169 outputs.dir getdownImagesBuildDir
2173 from(getdownImagesDir) {
2174 include("*getdown*.png")
2176 into getdownImagesBuildDir
2181 task getdownImagesProcess() {
2182 dependsOn getdownImagesCopy
2185 if (backgroundImageText) {
2186 if (convertBinary == null) {
2187 throw new StopExecutionException("No ImageMagick convert binary installed at '${convertBinaryExpectedLocation}'")
2189 if (!project.hasProperty("getdown_background_image_text_suffix_cmd")) {
2190 throw new StopExecutionException("No property 'getdown_background_image_text_suffix_cmd' defined. See channel_gradle.properties for channel ${CHANNEL}")
2192 fileTree(dir: getdownImagesBuildDir, include: "*background*.png").getFiles().each { file ->
2194 executable convertBinary
2197 '-font', getdown_background_image_text_font,
2198 '-fill', getdown_background_image_text_colour,
2199 '-draw', sprintf(getdown_background_image_text_suffix_cmd, channelSuffix),
2200 '-draw', sprintf(getdown_background_image_text_commit_cmd, "git-commit: ${gitHash}"),
2201 '-draw', sprintf(getdown_background_image_text_date_cmd, getDate("yyyy-MM-dd HH:mm:ss")),
2210 task getdownImages() {
2211 dependsOn getdownImagesProcess
2214 task getdownWebsite() {
2215 group = "distribution"
2216 description = "Create the getdown minimal app folder, and website folder for this version of jalview. Website folder also used for offline app installer"
2218 dependsOn getdownImages
2223 def getdownWebsiteResourceFilenames = []
2224 def getdownResourceDir = getdownResourceDir
2225 def getdownResourceFilenames = []
2228 // clean the getdown website and files dir before creating getdown folders
2229 delete getdownAppBaseDir
2230 delete getdownFilesDir
2233 from buildProperties
2234 rename(file(buildProperties).getName(), getdown_build_properties)
2237 getdownWebsiteResourceFilenames += "${getdownAppDistDir}/${getdown_build_properties}"
2240 from channelPropsFile
2241 filter(ReplaceTokens,
2245 'SUFFIX': channelSuffix
2248 into getdownAppBaseDir
2250 getdownWebsiteResourceFilenames += file(channelPropsFile).getName()
2252 // set some getdownTxt_ properties then go through all properties looking for getdownTxt_...
2253 def props = project.properties.sort { it.key }
2254 if (getdownAltJavaMinVersion != null && getdownAltJavaMinVersion.length() > 0) {
2255 props.put("getdown_txt_java_min_version", getdownAltJavaMinVersion)
2257 if (getdownAltJavaMaxVersion != null && getdownAltJavaMaxVersion.length() > 0) {
2258 props.put("getdown_txt_java_max_version", getdownAltJavaMaxVersion)
2260 if (getdownAltMultiJavaLocation != null && getdownAltMultiJavaLocation.length() > 0) {
2261 props.put("getdown_txt_multi_java_location", getdownAltMultiJavaLocation)
2263 if (getdownImagesBuildDir != null && file(getdownImagesBuildDir).exists()) {
2264 props.put("getdown_txt_ui.background_image", "${getdownImagesBuildDir}/${getdown_background_image}")
2265 props.put("getdown_txt_ui.instant_background_image", "${getdownImagesBuildDir}/${getdown_instant_background_image}")
2266 props.put("getdown_txt_ui.error_background", "${getdownImagesBuildDir}/${getdown_error_background}")
2267 props.put("getdown_txt_ui.progress_image", "${getdownImagesBuildDir}/${getdown_progress_image}")
2268 props.put("getdown_txt_ui.icon", "${getdownImagesDir}/${getdown_icon}")
2269 props.put("getdown_txt_ui.mac_dock_icon", "${getdownImagesDir}/${getdown_mac_dock_icon}")
2272 props.put("getdown_txt_title", jalview_name)
2273 props.put("getdown_txt_ui.name", applicationName)
2275 // start with appbase
2276 getdownTextLines += "appbase = ${getdownAppBase}"
2277 props.each{ prop, val ->
2278 if (prop.startsWith("getdown_txt_") && val != null) {
2279 if (prop.startsWith("getdown_txt_multi_")) {
2280 def key = prop.substring(18)
2281 val.split(",").each{ v ->
2282 def line = "${key} = ${v}"
2283 getdownTextLines += line
2286 // file values rationalised
2287 if (val.indexOf('/') > -1 || prop.startsWith("getdown_txt_resource")) {
2289 if (val.indexOf('/') == 0) {
2292 } else if (val.indexOf('/') > 0) {
2293 // relative path (relative to jalviewDir)
2294 r = file( "${jalviewDir}/${val}" )
2297 val = "${getdown_resource_dir}/" + r.getName()
2298 getdownWebsiteResourceFilenames += val
2299 getdownResourceFilenames += r.getPath()
2302 if (! prop.startsWith("getdown_txt_resource")) {
2303 def line = prop.substring(12) + " = ${val}"
2304 getdownTextLines += line
2310 getdownWebsiteResourceFilenames.each{ filename ->
2311 getdownTextLines += "resource = ${filename}"
2313 getdownResourceFilenames.each{ filename ->
2316 into getdownResourceDir
2320 def getdownWrapperScripts = [ getdown_bash_wrapper_script, getdown_powershell_wrapper_script, getdown_batch_wrapper_script ]
2321 getdownWrapperScripts.each{ script ->
2322 def s = file( "${jalviewDir}/utils/getdown/${getdown_wrapper_script_dir}/${script}" )
2326 into "${getdownAppBaseDir}/${getdown_wrapper_script_dir}"
2328 getdownTextLines += "resource = ${getdown_wrapper_script_dir}/${script}"
2333 fileTree(file(package_dir)).each{ f ->
2334 if (f.isDirectory()) {
2335 def files = fileTree(dir: f, include: ["*"]).getFiles()
2337 } else if (f.exists()) {
2341 def jalviewJar = jar.archiveFileName.getOrNull()
2342 // put jalview.jar first for CLASSPATH and .properties files reasons
2343 codeFiles.sort{a, b -> ( a.getName() == jalviewJar ? -1 : ( b.getName() == jalviewJar ? 1 : a <=> b ) ) }.each{f ->
2344 def name = f.getName()
2345 def line = "code = ${getdownAppDistDir}/${name}"
2346 getdownTextLines += line
2353 // NOT USING MODULES YET, EVERYTHING SHOULD BE IN dist
2355 if (JAVA_VERSION.equals("11")) {
2356 def j11libFiles = fileTree(dir: "${jalviewDir}/${j11libDir}", include: ["*.jar"]).getFiles()
2357 j11libFiles.sort().each{f ->
2358 def name = f.getName()
2359 def line = "code = ${getdown_j11lib_dir}/${name}"
2360 getdownTextLines += line
2363 into getdownJ11libDir
2369 // 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.
2370 //getdownTextLines += "class = " + file(getdownLauncher).getName()
2371 getdownTextLines += "resource = ${getdown_launcher_new}"
2372 getdownTextLines += "class = ${main_class}"
2373 // Not setting these properties in general so that getdownappbase and getdowndistdir will default to release version in jalview.bin.Cache
2374 if (getdownSetAppBaseProperty) {
2375 getdownTextLines += "jvmarg = -Dgetdowndistdir=${getdownAppDistDir}"
2376 getdownTextLines += "jvmarg = -Dgetdownappbase=${getdownAppBase}"
2379 def getdownTxt = file("${getdownAppBaseDir}/getdown.txt")
2380 getdownTxt.write(getdownTextLines.join("\n"))
2382 getdownLaunchJvl = getdown_launch_jvl_name + ( (jvlChannelName != null && jvlChannelName.length() > 0)?"-${jvlChannelName}":"" ) + ".jvl"
2383 def launchJvl = file("${getdownAppBaseDir}/${getdownLaunchJvl}")
2384 launchJvl.write("appbase=${getdownAppBase}")
2386 // files going into the getdown website dir: getdown-launcher.jar
2388 from getdownLauncher
2389 rename(file(getdownLauncher).getName(), getdown_launcher_new)
2390 into getdownAppBaseDir
2393 // files going into the getdown website dir: getdown-launcher(-local).jar
2395 from getdownLauncher
2396 if (file(getdownLauncher).getName() != getdown_launcher) {
2397 rename(file(getdownLauncher).getName(), getdown_launcher)
2399 into getdownAppBaseDir
2402 // files going into the getdown website dir: ./install dir and files
2403 if (! (CHANNEL.startsWith("ARCHIVE") || CHANNEL.startsWith("DEVELOP"))) {
2406 from getdownLauncher
2407 from "${getdownAppDir}/${getdown_build_properties}"
2408 if (file(getdownLauncher).getName() != getdown_launcher) {
2409 rename(file(getdownLauncher).getName(), getdown_launcher)
2411 into getdownInstallDir
2414 // and make a copy in the getdown files dir (these are not downloaded by getdown)
2416 from getdownInstallDir
2417 into getdownFilesInstallDir
2421 // files going into the getdown files dir: getdown.txt, getdown-launcher.jar, channel-launch.jvl, build_properties
2425 from getdownLauncher
2426 from "${getdownAppBaseDir}/${getdown_build_properties}"
2427 from "${getdownAppBaseDir}/${channel_props}"
2428 if (file(getdownLauncher).getName() != getdown_launcher) {
2429 rename(file(getdownLauncher).getName(), getdown_launcher)
2431 into getdownFilesDir
2434 // and ./resource (not all downloaded by getdown)
2436 from getdownResourceDir
2437 into "${getdownFilesDir}/${getdown_resource_dir}"
2442 inputs.dir("${jalviewDir}/${package_dir}")
2444 outputs.dir(getdownAppBaseDir)
2445 outputs.dir(getdownFilesDir)
2449 // a helper task to allow getdown digest of any dir: `gradle getdownDigestDir -PDIGESTDIR=/path/to/my/random/getdown/dir
2450 task getdownDigestDir(type: JavaExec) {
2452 description "A task to run a getdown Digest on a dir with getdown.txt. Provide a DIGESTDIR property via -PDIGESTDIR=..."
2454 def digestDirPropertyName = "DIGESTDIR"
2456 classpath = files(getdownLauncher)
2457 def digestDir = findProperty(digestDirPropertyName)
2458 if (digestDir == null) {
2459 throw new GradleException("Must provide a DIGESTDIR value to produce an alternative getdown digest")
2463 main = "com.threerings.getdown.tools.Digester"
2467 task getdownDigest(type: JavaExec) {
2468 group = "distribution"
2469 description = "Digest the getdown website folder"
2470 dependsOn getdownWebsite
2472 classpath = files(getdownLauncher)
2474 main = "com.threerings.getdown.tools.Digester"
2475 args getdownAppBaseDir
2476 inputs.dir(getdownAppBaseDir)
2477 outputs.file("${getdownAppBaseDir}/digest2.txt")
2482 group = "distribution"
2483 description = "Create the minimal and full getdown app folder for installers and website and create digest file"
2484 dependsOn getdownDigest
2486 if (reportRsyncCommand) {
2487 def fromDir = getdownAppBaseDir + (getdownAppBaseDir.endsWith('/')?'':'/')
2488 def toDir = "${getdown_rsync_dest}/${getdownDir}" + (getdownDir.endsWith('/')?'':'/')
2489 println "LIKELY RSYNC COMMAND:"
2490 println "mkdir -p '$toDir'\nrsync -avh --delete '$fromDir' '$toDir'"
2491 if (RUNRSYNC == "true") {
2493 commandLine "mkdir", "-p", toDir
2496 commandLine "rsync", "-avh", "--delete", fromDir, toDir
2504 task getdownArchiveBuild() {
2505 group = "distribution"
2506 description = "Put files in the archive dir to go on the website"
2508 dependsOn getdownWebsite
2510 def v = "v${JALVIEW_VERSION_UNDERSCORES}"
2511 def vDir = "${getdownArchiveDir}/${v}"
2512 getdownFullArchiveDir = "${vDir}/getdown"
2513 getdownVersionLaunchJvl = "${vDir}/jalview-${v}.jvl"
2515 def vAltDir = "alt_${v}"
2516 def archiveImagesDir = "${jalviewDir}/${channel_properties_dir}/old/images"
2519 // cleanup old "old" dir
2520 delete getdownArchiveDir
2522 def getdownArchiveTxt = file("${getdownFullArchiveDir}/getdown.txt")
2523 getdownArchiveTxt.getParentFile().mkdirs()
2524 def getdownArchiveTextLines = []
2525 def getdownFullArchiveAppBase = "${getdownArchiveAppBase}${getdownArchiveAppBase.endsWith("/")?"":"/"}${v}/getdown/"
2529 from "${getdownAppBaseDir}/${getdownAppDistDir}"
2530 into "${getdownFullArchiveDir}/${vAltDir}"
2533 getdownTextLines.each { line ->
2534 line = line.replaceAll("^(?<s>appbase\\s*=\\s*).*", '${s}'+getdownFullArchiveAppBase)
2535 line = line.replaceAll("^(?<s>(resource|code)\\s*=\\s*)${getdownAppDistDir}/", '${s}'+vAltDir+"/")
2536 line = line.replaceAll("^(?<s>ui.background_image\\s*=\\s*).*\\.png", '${s}'+"${getdown_resource_dir}/jalview_archive_getdown_background.png")
2537 line = line.replaceAll("^(?<s>ui.instant_background_image\\s*=\\s*).*\\.png", '${s}'+"${getdown_resource_dir}/jalview_archive_getdown_background_initialising.png")
2538 line = line.replaceAll("^(?<s>ui.error_background\\s*=\\s*).*\\.png", '${s}'+"${getdown_resource_dir}/jalview_archive_getdown_background_error.png")
2539 line = line.replaceAll("^(?<s>ui.progress_image\\s*=\\s*).*\\.png", '${s}'+"${getdown_resource_dir}/jalview_archive_getdown_progress_bar.png")
2540 // remove the existing resource = resource/ or bin/ lines
2541 if (! line.matches("resource\\s*=\\s*(resource|bin)/.*")) {
2542 getdownArchiveTextLines += line
2546 // the resource dir -- add these files as resource lines in getdown.txt
2548 from "${archiveImagesDir}"
2549 into "${getdownFullArchiveDir}/${getdown_resource_dir}"
2551 getdownArchiveTextLines += "resource = ${getdown_resource_dir}/${file.getName()}"
2555 getdownArchiveTxt.write(getdownArchiveTextLines.join("\n"))
2557 def vLaunchJvl = file(getdownVersionLaunchJvl)
2558 vLaunchJvl.getParentFile().mkdirs()
2559 vLaunchJvl.write("appbase=${getdownFullArchiveAppBase}\n")
2560 def vLaunchJvlPath = vLaunchJvl.toPath().toAbsolutePath()
2561 def jvlLinkPath = file("${vDir}/jalview.jvl").toPath().toAbsolutePath()
2562 // for some reason filepath.relativize(fileInSameDirPath) gives a path to "../" which is wrong
2563 //java.nio.file.Files.createSymbolicLink(jvlLinkPath, jvlLinkPath.relativize(vLaunchJvlPath));
2564 java.nio.file.Files.createSymbolicLink(jvlLinkPath, java.nio.file.Paths.get(".",vLaunchJvl.getName()));
2566 // files going into the getdown files dir: getdown.txt, getdown-launcher.jar, channel-launch.jvl, build_properties
2568 from getdownLauncher
2569 from "${getdownAppBaseDir}/${getdownLaunchJvl}"
2570 from "${getdownAppBaseDir}/${getdown_launcher_new}"
2571 from "${getdownAppBaseDir}/${channel_props}"
2572 if (file(getdownLauncher).getName() != getdown_launcher) {
2573 rename(file(getdownLauncher).getName(), getdown_launcher)
2575 into getdownFullArchiveDir
2581 task getdownArchiveDigest(type: JavaExec) {
2582 group = "distribution"
2583 description = "Digest the getdown archive folder"
2585 dependsOn getdownArchiveBuild
2588 classpath = files(getdownLauncher)
2589 args getdownFullArchiveDir
2591 main = "com.threerings.getdown.tools.Digester"
2592 inputs.dir(getdownFullArchiveDir)
2593 outputs.file("${getdownFullArchiveDir}/digest2.txt")
2596 task getdownArchive() {
2597 group = "distribution"
2598 description = "Build the website archive dir with getdown digest"
2600 dependsOn getdownArchiveBuild
2601 dependsOn getdownArchiveDigest
2604 tasks.withType(JavaCompile) {
2605 options.encoding = 'UTF-8'
2611 delete getdownAppBaseDir
2612 delete getdownFilesDir
2613 delete getdownArchiveDir
2619 if (file(install4jHomeDir).exists()) {
2621 } else if (file(System.getProperty("user.home")+"/buildtools/install4j").exists()) {
2622 install4jHomeDir = System.getProperty("user.home")+"/buildtools/install4j"
2623 } else if (file("/Applications/install4j.app/Contents/Resources/app").exists()) {
2624 install4jHomeDir = "/Applications/install4j.app/Contents/Resources/app"
2626 installDir(file(install4jHomeDir))
2628 mediaTypes = Arrays.asList(install4j_media_types.split(","))
2632 task copyInstall4jTemplate {
2633 def install4jTemplateFile = file("${install4jDir}/${install4j_template}")
2634 def install4jFileAssociationsFile = file("${install4jDir}/${install4j_installer_file_associations}")
2635 inputs.file(install4jTemplateFile)
2636 inputs.file(install4jFileAssociationsFile)
2637 inputs.property("CHANNEL", { CHANNEL })
2638 outputs.file(install4jConfFile)
2641 def install4jConfigXml = new XmlParser().parse(install4jTemplateFile)
2643 // turn off code signing if no OSX_KEYPASS
2644 if (OSX_KEYPASS == "") {
2645 install4jConfigXml.'**'.codeSigning.each { codeSigning ->
2646 codeSigning.'@macEnabled' = "false"
2648 install4jConfigXml.'**'.windows.each { windows ->
2649 windows.'@runPostProcessor' = "false"
2653 // disable install screen for OSX dmg (for 2.11.2.0)
2654 install4jConfigXml.'**'.macosArchive.each { macosArchive ->
2655 macosArchive.attributes().remove('executeSetupApp')
2656 macosArchive.attributes().remove('setupAppId')
2659 // turn off checksum creation for LOCAL channel
2660 def e = install4jConfigXml.application[0]
2661 e.'@createChecksums' = string(install4jCheckSums)
2663 // put file association actions where placeholder action is
2664 def install4jFileAssociationsText = install4jFileAssociationsFile.text
2665 def fileAssociationActions = new XmlParser().parseText("<actions>${install4jFileAssociationsText}</actions>")
2666 install4jConfigXml.'**'.action.any { a -> // .any{} stops after the first one that returns true
2667 if (a.'@name' == 'EXTENSIONS_REPLACED_BY_GRADLE') {
2668 def parent = a.parent()
2670 fileAssociationActions.each { faa ->
2673 // don't need to continue in .any loop once replacements have been made
2678 // use Windows Program Group with Examples folder for RELEASE, and Program Group without Examples for everything else
2679 // NB we're deleting the /other/ one!
2680 // Also remove the examples subdir from non-release versions
2681 def customizedIdToDelete = "PROGRAM_GROUP_RELEASE"
2682 // 2.11.1.0 NOT releasing with the Examples folder in the Program Group
2683 if (false && CHANNEL=="RELEASE") { // remove 'false && ' to include Examples folder in RELEASE channel
2684 customizedIdToDelete = "PROGRAM_GROUP_NON_RELEASE"
2686 // remove the examples subdir from Full File Set
2687 def files = install4jConfigXml.files[0]
2688 def fileset = files.filesets.fileset.find { fs -> fs.'@customizedId' == "FULL_FILE_SET" }
2689 def root = files.roots.root.find { r -> r.'@fileset' == fileset.'@id' }
2690 def mountPoint = files.mountPoints.mountPoint.find { mp -> mp.'@root' == root.'@id' }
2691 def dirEntry = files.entries.dirEntry.find { de -> de.'@mountPoint' == mountPoint.'@id' && de.'@subDirectory' == "examples" }
2692 dirEntry.parent().remove(dirEntry)
2694 install4jConfigXml.'**'.action.any { a ->
2695 if (a.'@customizedId' == customizedIdToDelete) {
2696 def parent = a.parent()
2702 // write install4j file
2703 install4jConfFile.text = XmlUtil.serialize(install4jConfigXml)
2710 delete install4jConfFile
2714 task cleanInstallersDataFiles {
2715 def installersOutputTxt = file("${jalviewDir}/${install4jBuildDir}/output.txt")
2716 def installersSha256 = file("${jalviewDir}/${install4jBuildDir}/sha256sums")
2717 def hugoDataJsonFile = file("${jalviewDir}/${install4jBuildDir}/installers-${JALVIEW_VERSION_UNDERSCORES}.json")
2719 delete installersOutputTxt
2720 delete installersSha256
2721 delete hugoDataJsonFile
2725 task install4jDMGBackgroundImageCopy {
2726 inputs.file "${install4jDMGBackgroundImageDir}/${install4jDMGBackgroundImageFile}"
2727 outputs.dir "${install4jDMGBackgroundImageBuildDir}"
2730 from(install4jDMGBackgroundImageDir) {
2731 include(install4jDMGBackgroundImageFile)
2733 into install4jDMGBackgroundImageBuildDir
2738 task install4jDMGBackgroundImageProcess {
2739 dependsOn install4jDMGBackgroundImageCopy
2742 if (backgroundImageText) {
2743 if (convertBinary == null) {
2744 throw new StopExecutionException("No ImageMagick convert binary installed at '${convertBinaryExpectedLocation}'")
2746 if (!project.hasProperty("install4j_background_image_text_suffix_cmd")) {
2747 throw new StopExecutionException("No property 'install4j_background_image_text_suffix_cmd' defined. See channel_gradle.properties for channel ${CHANNEL}")
2749 fileTree(dir: install4jDMGBackgroundImageBuildDir, include: "*.png").getFiles().each { file ->
2751 executable convertBinary
2754 '-font', install4j_background_image_text_font,
2755 '-fill', install4j_background_image_text_colour,
2756 '-draw', sprintf(install4j_background_image_text_suffix_cmd, channelSuffix),
2757 '-draw', sprintf(install4j_background_image_text_commit_cmd, "git-commit: ${gitHash}"),
2758 '-draw', sprintf(install4j_background_image_text_date_cmd, getDate("yyyy-MM-dd HH:mm:ss")),
2767 task install4jDMGBackgroundImage {
2768 dependsOn install4jDMGBackgroundImageProcess
2771 task installerFiles(type: com.install4j.gradle.Install4jTask) {
2772 group = "distribution"
2773 description = "Create the install4j installers"
2775 dependsOn copyInstall4jTemplate
2776 dependsOn cleanInstallersDataFiles
2777 dependsOn install4jDMGBackgroundImage
2779 projectFile = install4jConfFile
2781 // create an md5 for the input files to use as version for install4j conf file
2782 def digest = MessageDigest.getInstance("MD5")
2784 (file("${install4jDir}/${install4j_template}").text +
2785 file("${install4jDir}/${install4j_info_plist_file_associations}").text +
2786 file("${install4jDir}/${install4j_installer_file_associations}").text).bytes)
2787 def filesMd5 = new BigInteger(1, digest.digest()).toString(16)
2788 if (filesMd5.length() >= 8) {
2789 filesMd5 = filesMd5.substring(0,8)
2791 def install4jTemplateVersion = "${JALVIEW_VERSION}_F${filesMd5}_C${gitHash}"
2794 'JALVIEW_NAME': jalview_name,
2795 'JALVIEW_APPLICATION_NAME': applicationName,
2796 'JALVIEW_DIR': "../..",
2797 'OSX_KEYSTORE': OSX_KEYSTORE,
2798 'OSX_APPLEID': OSX_APPLEID,
2799 'OSX_ALTOOLPASS': OSX_ALTOOLPASS,
2800 'JSIGN_SH': JSIGN_SH,
2801 'JRE_DIR': getdown_app_dir_java,
2802 'INSTALLER_TEMPLATE_VERSION': install4jTemplateVersion,
2803 'JALVIEW_VERSION': JALVIEW_VERSION,
2804 'JAVA_MIN_VERSION': JAVA_MIN_VERSION,
2805 'JAVA_MAX_VERSION': JAVA_MAX_VERSION,
2806 'JAVA_VERSION': JAVA_VERSION,
2807 'JAVA_INTEGER_VERSION': JAVA_INTEGER_VERSION,
2808 'VERSION': JALVIEW_VERSION,
2809 'COPYRIGHT_MESSAGE': install4j_copyright_message,
2810 'BUNDLE_ID': install4jBundleId,
2811 'INTERNAL_ID': install4jInternalId,
2812 'WINDOWS_APPLICATION_ID': install4jWinApplicationId,
2813 'MACOS_DMG_DS_STORE': install4jDMGDSStore,
2814 'MACOS_DMG_BG_IMAGE': "${install4jDMGBackgroundImageBuildDir}/${install4jDMGBackgroundImageFile}",
2815 'WRAPPER_LINK': getdownWrapperLink,
2816 'BASH_WRAPPER_SCRIPT': getdown_bash_wrapper_script,
2817 'POWERSHELL_WRAPPER_SCRIPT': getdown_powershell_wrapper_script,
2818 'BATCH_WRAPPER_SCRIPT': getdown_batch_wrapper_script,
2819 'WRAPPER_SCRIPT_BIN_DIR': getdown_wrapper_script_dir,
2820 'INSTALLER_NAME': install4jInstallerName,
2821 'INSTALL4J_UTILS_DIR': install4j_utils_dir,
2822 'GETDOWN_CHANNEL_DIR': getdownChannelDir,
2823 'GETDOWN_FILES_DIR': getdown_files_dir,
2824 'GETDOWN_RESOURCE_DIR': getdown_resource_dir,
2825 'GETDOWN_DIST_DIR': getdownAppDistDir,
2826 'GETDOWN_ALT_DIR': getdown_app_dir_alt,
2827 'GETDOWN_INSTALL_DIR': getdown_install_dir,
2828 'INFO_PLIST_FILE_ASSOCIATIONS_FILE': install4j_info_plist_file_associations,
2829 'BUILD_DIR': install4jBuildDir,
2830 'APPLICATION_CATEGORIES': install4j_application_categories,
2831 'APPLICATION_FOLDER': install4jApplicationFolder,
2832 'UNIX_APPLICATION_FOLDER': install4jUnixApplicationFolder,
2833 'EXECUTABLE_NAME': install4jExecutableName,
2834 'EXTRA_SCHEME': install4jExtraScheme,
2835 'MAC_ICONS_FILE': install4jMacIconsFile,
2836 'WINDOWS_ICONS_FILE': install4jWindowsIconsFile,
2837 'PNG_ICON_FILE': install4jPngIconFile,
2838 'BACKGROUND': install4jBackground,
2843 'windows': 'WINDOWS',
2847 // these are the bundled OS/architecture VMs needed by install4j
2850 [ "mac", "aarch64" ],
2851 [ "windows", "x64" ],
2853 [ "linux", "aarch64" ]
2855 osArch.forEach { os, arch ->
2856 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)
2857 // N.B. For some reason install4j requires the below filename to have underscores and not hyphens
2858 // otherwise running `gradle installers` generates a non-useful error:
2859 // `install4j: compilation failed. Reason: java.lang.NumberFormatException: For input string: "windows"`
2860 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)
2863 //println("INSTALL4J VARIABLES:")
2864 //variables.each{k,v->println("${k}=${v}")}
2866 destination = "${jalviewDir}/${install4jBuildDir}"
2867 buildSelected = true
2869 if (install4j_faster.equals("true") || CHANNEL.startsWith("LOCAL")) {
2871 disableSigning = true
2872 disableNotarization = true
2876 macKeystorePassword = OSX_KEYPASS
2879 if (OSX_ALTOOLPASS) {
2880 appleIdPassword = OSX_ALTOOLPASS
2881 disableNotarization = false
2883 disableNotarization = true
2887 println("Using projectFile "+projectFile)
2888 if (!disableNotarization) { println("Will notarize OSX App DMG") }
2892 inputs.dir(getdownAppBaseDir)
2893 inputs.file(install4jConfFile)
2894 inputs.file("${install4jDir}/${install4j_info_plist_file_associations}")
2895 outputs.dir("${jalviewDir}/${install4j_build_dir}/${JAVA_VERSION}")
2898 def getDataHash(File myFile) {
2899 HashCode hash = Files.asByteSource(myFile).hash(Hashing.sha256())
2900 return myFile.exists()
2902 "file" : myFile.getName(),
2903 "filesize" : myFile.length(),
2904 "sha256" : hash.toString()
2909 def writeDataJsonFile(File installersOutputTxt, File installersSha256, File dataJsonFile) {
2911 "channel" : getdownChannelName,
2912 "date" : getDate("yyyy-MM-dd HH:mm:ss"),
2913 "git-commit" : "${gitHash} [${gitBranch}]",
2914 "version" : JALVIEW_VERSION
2916 // install4j installer files
2917 if (installersOutputTxt.exists()) {
2919 installersOutputTxt.readLines().each { def line ->
2920 if (line.startsWith("#")) {
2923 line.replaceAll("\n","")
2924 def vals = line.split("\t")
2925 def filename = vals[3]
2926 def filesize = file(filename).length()
2927 filename = filename.replaceAll(/^.*\//, "")
2928 hash[vals[0]] = [ "id" : vals[0], "os" : vals[1], "name" : vals[2], "file" : filename, "filesize" : filesize ]
2929 idHash."${filename}" = vals[0]
2931 if (install4jCheckSums && installersSha256.exists()) {
2932 installersSha256.readLines().each { def line ->
2933 if (line.startsWith("#")) {
2936 line.replaceAll("\n","")
2937 def vals = line.split(/\s+\*?/)
2938 def filename = vals[1]
2939 def innerHash = (hash.(idHash."${filename}"))."sha256" = vals[0]
2945 "JAR": shadowJar.archiveFile, // executable JAR
2946 "JVL": getdownVersionLaunchJvl, // version JVL
2947 "SOURCE": sourceDist.archiveFile // source TGZ
2948 ].each { key, value ->
2949 def file = file(value)
2950 if (file.exists()) {
2951 def fileHash = getDataHash(file)
2952 if (fileHash != null) {
2953 hash."${key}" = fileHash;
2957 return dataJsonFile.write(new JsonBuilder(hash).toPrettyString())
2960 task staticMakeInstallersJsonFile {
2962 def output = findProperty("i4j_output")
2963 def sha256 = findProperty("i4j_sha256")
2964 def json = findProperty("i4j_json")
2965 if (output == null || sha256 == null || json == null) {
2966 throw new GradleException("Must provide paths to all of output.txt, sha256sums, and output.json with '-Pi4j_output=... -Pi4j_sha256=... -Pi4j_json=...")
2968 writeDataJsonFile(file(output), file(sha256), file(json))
2973 dependsOn installerFiles
2979 eclipse().configFile(eclipse_codestyle_file)
2983 task createSourceReleaseProperties(type: WriteProperties) {
2984 group = "distribution"
2985 description = "Create the source RELEASE properties file"
2987 def sourceTarBuildDir = "${buildDir}/sourceTar"
2988 def sourceReleasePropertiesFile = "${sourceTarBuildDir}/RELEASE"
2989 outputFile (sourceReleasePropertiesFile)
2992 releaseProps.each{ key, val -> property key, val }
2993 property "git.branch", gitBranch
2994 property "git.hash", gitHash
2997 outputs.file(outputFile)
3000 task sourceDist(type: Tar) {
3001 group "distribution"
3002 description "Create a source .tar.gz file for distribution"
3004 dependsOn createBuildProperties
3005 dependsOn convertMdFiles
3006 dependsOn eclipseAllPreferences
3007 dependsOn createSourceReleaseProperties
3010 def outputFileName = "${project.name}_${JALVIEW_VERSION_UNDERSCORES}.tar.gz"
3011 archiveFileName = outputFileName
3013 compression Compression.GZIP
3028 "**/*.class","$j11modDir/**/*.jar","appletlib","**/*locales",
3030 "utils/InstallAnywhere",
3045 "gradle.properties",
3057 ".settings/org.eclipse.buildship.core.prefs",
3058 ".settings/org.eclipse.jdt.core.prefs"
3062 exclude (EXCLUDE_FILES)
3063 include (PROCESS_FILES)
3064 filter(ReplaceTokens,
3068 'Version-Rel': JALVIEW_VERSION,
3069 'Year-Rel': getDate("yyyy")
3074 exclude (EXCLUDE_FILES)
3075 exclude (PROCESS_FILES)
3076 exclude ("appletlib")
3077 exclude ("**/*locales")
3078 exclude ("*locales/**")
3079 exclude ("utils/InstallAnywhere")
3081 exclude (getdown_files_dir)
3082 // getdown_website_dir and getdown_archive_dir moved to build/website/docroot/getdown
3083 //exclude (getdown_website_dir)
3084 //exclude (getdown_archive_dir)
3086 // exluding these as not using jars as modules yet
3087 exclude ("${j11modDir}/**/*.jar")
3090 include(INCLUDE_FILES)
3092 // from (jalviewDir) {
3093 // // explicit includes for stuff that seemed to not get included
3094 // include(fileTree("test/**/*."))
3095 // exclude(EXCLUDE_FILES)
3096 // exclude(PROCESS_FILES)
3099 from(file(buildProperties).getParent()) {
3100 include(file(buildProperties).getName())
3101 rename(file(buildProperties).getName(), "build_properties")
3103 line.replaceAll("^INSTALLATION=.*\$","INSTALLATION=Source Release"+" git-commit\\\\:"+gitHash+" ["+gitBranch+"]")
3107 def sourceTarBuildDir = "${buildDir}/sourceTar"
3108 from(sourceTarBuildDir) {
3109 // this includes the appended RELEASE properties file
3113 task dataInstallersJson {
3115 description "Create the installers-VERSION.json data file for installer files created"
3117 mustRunAfter installers
3118 mustRunAfter shadowJar
3119 mustRunAfter sourceDist
3120 mustRunAfter getdownArchive
3122 def installersOutputTxt = file("${jalviewDir}/${install4jBuildDir}/output.txt")
3123 def installersSha256 = file("${jalviewDir}/${install4jBuildDir}/sha256sums")
3125 if (installersOutputTxt.exists()) {
3126 inputs.file(installersOutputTxt)
3128 if (install4jCheckSums && installersSha256.exists()) {
3129 inputs.file(installersSha256)
3132 shadowJar.archiveFile, // executable JAR
3133 getdownVersionLaunchJvl, // version JVL
3134 sourceDist.archiveFile // source TGZ
3135 ].each { fileName ->
3136 if (file(fileName).exists()) {
3137 inputs.file(fileName)
3141 outputs.file(hugoDataJsonFile)
3144 writeDataJsonFile(installersOutputTxt, installersSha256, hugoDataJsonFile)
3150 description "Copies all help pages to build dir. Runs ant task 'pubhtmlhelp'."
3153 dependsOn pubhtmlhelp
3155 inputs.dir("${helpBuildDir}/${help_dir}")
3156 outputs.dir("${buildDir}/distributions/${help_dir}")
3160 task j2sSetHeadlessBuild {
3167 task jalviewjsEnableAltFileProperty(type: WriteProperties) {
3169 description "Enable the alternative J2S Config file for headless build"
3171 outputFile = jalviewjsJ2sSettingsFileName
3172 def j2sPropsFile = file(jalviewjsJ2sSettingsFileName)
3173 def j2sProps = new Properties()
3174 if (j2sPropsFile.exists()) {
3176 def j2sPropsFileFIS = new FileInputStream(j2sPropsFile)
3177 j2sProps.load(j2sPropsFileFIS)
3178 j2sPropsFileFIS.close()
3180 j2sProps.each { prop, val ->
3183 } catch (Exception e) {
3184 println("Exception reading ${jalviewjsJ2sSettingsFileName}")
3188 if (! j2sProps.stringPropertyNames().contains(jalviewjs_j2s_alt_file_property_config)) {
3189 property(jalviewjs_j2s_alt_file_property_config, jalviewjs_j2s_alt_file_property)
3194 task jalviewjsSetEclipseWorkspace {
3195 def propKey = "jalviewjs_eclipse_workspace"
3197 if (project.hasProperty(propKey)) {
3198 propVal = project.getProperty(propKey)
3199 if (propVal.startsWith("~/")) {
3200 propVal = System.getProperty("user.home") + propVal.substring(1)
3203 def propsFileName = "${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_eclipse_workspace_location_file}"
3204 def propsFile = file(propsFileName)
3205 def eclipseWsDir = propVal
3206 def props = new Properties()
3208 def writeProps = true
3209 if (( eclipseWsDir == null || !file(eclipseWsDir).exists() ) && propsFile.exists()) {
3210 def ins = new FileInputStream(propsFileName)
3213 if (props.getProperty(propKey, null) != null) {
3214 eclipseWsDir = props.getProperty(propKey)
3219 if (eclipseWsDir == null || !file(eclipseWsDir).exists()) {
3220 def tempDir = File.createTempDir()
3221 eclipseWsDir = tempDir.getAbsolutePath()
3224 eclipseWorkspace = file(eclipseWsDir)
3227 // do not run a headless transpile when we claim to be in Eclipse
3229 println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3230 throw new StopExecutionException("Not running headless transpile whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
3232 println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3236 props.setProperty(propKey, eclipseWsDir)
3237 propsFile.parentFile.mkdirs()
3238 def bytes = new ByteArrayOutputStream()
3239 props.store(bytes, null)
3240 def propertiesString = bytes.toString()
3241 propsFile.text = propertiesString
3247 println("ECLIPSE WORKSPACE: "+eclipseWorkspace.getPath())
3250 //inputs.property(propKey, eclipseWsDir) // eclipseWsDir only gets set once this task runs, so will be out-of-date
3251 outputs.file(propsFileName)
3252 outputs.upToDateWhen { eclipseWorkspace.exists() && propsFile.exists() }
3256 task jalviewjsEclipsePaths {
3259 def eclipseRoot = jalviewjs_eclipse_root
3260 if (eclipseRoot.startsWith("~/")) {
3261 eclipseRoot = System.getProperty("user.home") + eclipseRoot.substring(1)
3263 if (OperatingSystem.current().isMacOsX()) {
3264 eclipseRoot += "/Eclipse.app"
3265 eclipseBinary = "${eclipseRoot}/Contents/MacOS/eclipse"
3266 eclipseProduct = "${eclipseRoot}/Contents/Eclipse/.eclipseproduct"
3267 } else if (OperatingSystem.current().isWindows()) { // check these paths!!
3268 if (file("${eclipseRoot}/eclipse").isDirectory() && file("${eclipseRoot}/eclipse/.eclipseproduct").exists()) {
3269 eclipseRoot += "/eclipse"
3271 eclipseBinary = "${eclipseRoot}/eclipse.exe"
3272 eclipseProduct = "${eclipseRoot}/.eclipseproduct"
3273 } else { // linux or unix
3274 if (file("${eclipseRoot}/eclipse").isDirectory() && file("${eclipseRoot}/eclipse/.eclipseproduct").exists()) {
3275 eclipseRoot += "/eclipse"
3276 println("eclipseDir exists")
3278 eclipseBinary = "${eclipseRoot}/eclipse"
3279 eclipseProduct = "${eclipseRoot}/.eclipseproduct"
3282 eclipseVersion = "4.13" // default
3283 def assumedVersion = true
3284 if (file(eclipseProduct).exists()) {
3285 def fis = new FileInputStream(eclipseProduct)
3286 def props = new Properties()
3288 eclipseVersion = props.getProperty("version")
3290 assumedVersion = false
3293 def propKey = "eclipse_debug"
3294 eclipseDebug = (project.hasProperty(propKey) && project.getProperty(propKey).equals("true"))
3297 // do not run a headless transpile when we claim to be in Eclipse
3299 println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3300 throw new StopExecutionException("Not running headless transpile whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
3302 println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3305 if (!assumedVersion) {
3306 println("ECLIPSE VERSION=${eclipseVersion}")
3312 task printProperties {
3314 description "Output to console all System.properties"
3316 System.properties.each { key, val -> System.out.println("Property: ${key}=${val}") }
3322 dependsOn eclipseProject
3323 dependsOn eclipseClasspath
3324 dependsOn eclipseJdt
3328 // this version (type: Copy) will delete anything in the eclipse dropins folder that isn't in fromDropinsDir
3329 task jalviewjsEclipseCopyDropins(type: Copy) {
3330 dependsOn jalviewjsEclipsePaths
3332 def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjs_eclipse_dropins_dir}", include: "*.jar")
3333 inputFiles += file("${jalviewDir}/${jalviewjsJ2sPlugin}")
3334 def outputDir = "${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_eclipse_tmp_dropins_dir}"
3341 // this eclipse -clean doesn't actually work
3342 task jalviewjsCleanEclipse(type: Exec) {
3343 dependsOn eclipseSetup
3344 dependsOn jalviewjsEclipsePaths
3345 dependsOn jalviewjsEclipseCopyDropins
3347 executable(eclipseBinary)
3348 args(["-nosplash", "--launcher.suppressErrors", "-data", eclipseWorkspace.getPath(), "-clean", "-console", "-consoleLog"])
3354 def inputString = """exit
3357 def inputByteStream = new ByteArrayInputStream(inputString.getBytes())
3358 standardInput = inputByteStream
3361 /* not really working yet
3362 jalviewjsEclipseCopyDropins.finalizedBy jalviewjsCleanEclipse
3366 task jalviewjsTransferUnzipSwingJs {
3367 def file_zip = "${jalviewDir}/${jalviewjs_swingjs_zip}"
3371 from zipTree(file_zip)
3372 into "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}"
3376 inputs.file file_zip
3377 outputs.dir "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}"
3381 task jalviewjsTransferUnzipLib {
3382 def zipFiles = fileTree(dir: "${jalviewDir}/${jalviewjs_libjs_dir}", include: "*.zip")
3385 zipFiles.each { file_zip ->
3387 from zipTree(file_zip)
3388 into "${jalviewDir}/${jalviewjsTransferSiteLibDir}"
3393 inputs.files zipFiles
3394 outputs.dir "${jalviewDir}/${jalviewjsTransferSiteLibDir}"
3398 task jalviewjsTransferUnzipAllLibs {
3399 dependsOn jalviewjsTransferUnzipSwingJs
3400 dependsOn jalviewjsTransferUnzipLib
3404 task jalviewjsCreateJ2sSettings(type: WriteProperties) {
3406 description "Create the alternative j2s file from the j2s.* properties"
3408 jalviewjsJ2sProps = project.properties.findAll { it.key.startsWith("j2s.") }.sort { it.key }
3409 def siteDirProperty = "j2s.site.directory"
3410 def setSiteDir = false
3411 jalviewjsJ2sProps.each { prop, val ->
3413 if (prop == siteDirProperty) {
3414 if (!(val.startsWith('/') || val.startsWith("file://") )) {
3415 val = "${jalviewDir}/${jalviewjsTransferSiteJsDir}/${val}"
3421 if (!setSiteDir) { // default site location, don't override specifically set property
3422 property(siteDirProperty,"${jalviewDirRelativePath}/${jalviewjsTransferSiteJsDir}")
3425 outputFile = jalviewjsJ2sAltSettingsFileName
3428 inputs.properties(jalviewjsJ2sProps)
3429 outputs.file(jalviewjsJ2sAltSettingsFileName)
3434 task jalviewjsEclipseSetup {
3435 dependsOn jalviewjsEclipseCopyDropins
3436 dependsOn jalviewjsSetEclipseWorkspace
3437 dependsOn jalviewjsCreateJ2sSettings
3441 task jalviewjsSyncAllLibs (type: Sync) {
3442 dependsOn jalviewjsTransferUnzipAllLibs
3443 def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjsTransferSiteLibDir}")
3444 inputFiles += fileTree(dir: "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}")
3445 def outputDir = "${jalviewDir}/${jalviewjsSiteDir}"
3449 def outputFiles = []
3450 rename { filename ->
3451 outputFiles += "${outputDir}/${filename}"
3458 // should this be exclude really ?
3459 duplicatesStrategy "INCLUDE"
3461 outputs.files outputFiles
3462 inputs.files inputFiles
3466 task jalviewjsSyncResources (type: Sync) {
3467 dependsOn buildResources
3469 def inputFiles = fileTree(dir: resourcesBuildDir)
3470 def outputDir = "${jalviewDir}/${jalviewjsSiteDir}/${jalviewjs_j2s_subdir}"
3474 def outputFiles = []
3475 rename { filename ->
3476 outputFiles += "${outputDir}/${filename}"
3482 outputs.files outputFiles
3483 inputs.files inputFiles
3487 task jalviewjsSyncSiteResources (type: Sync) {
3488 def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjs_site_resource_dir}")
3489 def outputDir = "${jalviewDir}/${jalviewjsSiteDir}"
3493 def outputFiles = []
3494 rename { filename ->
3495 outputFiles += "${outputDir}/${filename}"
3501 outputs.files outputFiles
3502 inputs.files inputFiles
3506 task jalviewjsSyncBuildProperties (type: Sync) {
3507 dependsOn createBuildProperties
3508 def inputFiles = [file(buildProperties)]
3509 def outputDir = "${jalviewDir}/${jalviewjsSiteDir}/${jalviewjs_j2s_subdir}"
3513 def outputFiles = []
3514 rename { filename ->
3515 outputFiles += "${outputDir}/${filename}"
3521 outputs.files outputFiles
3522 inputs.files inputFiles
3526 task jalviewjsProjectImport(type: Exec) {
3527 dependsOn eclipseSetup
3528 dependsOn jalviewjsEclipsePaths
3529 dependsOn jalviewjsEclipseSetup
3532 // do not run a headless import when we claim to be in Eclipse
3534 println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3535 throw new StopExecutionException("Not running headless import whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
3537 println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3541 //def projdir = eclipseWorkspace.getPath()+"/.metadata/.plugins/org.eclipse.core.resources/.projects/jalview/org.eclipse.jdt.core"
3542 def projdir = eclipseWorkspace.getPath()+"/.metadata/.plugins/org.eclipse.core.resources/.projects/jalview"
3543 executable(eclipseBinary)
3544 args(["-nosplash", "--launcher.suppressErrors", "-application", "com.seeq.eclipse.importprojects.headlessimport", "-data", eclipseWorkspace.getPath(), "-import", jalviewDirAbsolutePath])
3548 args += [ "--launcher.appendVmargs", "-vmargs", "-Dorg.eclipse.equinox.p2.reconciler.dropins.directory=${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_eclipse_tmp_dropins_dir}" ]
3550 args += [ "-D${j2sHeadlessBuildProperty}=true" ]
3551 args += [ "-D${jalviewjs_j2s_alt_file_property}=${jalviewjsJ2sAltSettingsFileName}" ]
3554 inputs.file("${jalviewDir}/.project")
3555 outputs.upToDateWhen {
3556 file(projdir).exists()
3561 task jalviewjsTranspile(type: Exec) {
3562 dependsOn jalviewjsEclipseSetup
3563 dependsOn jalviewjsProjectImport
3564 dependsOn jalviewjsEclipsePaths
3566 dependsOn jalviewjsEnableAltFileProperty
3570 // do not run a headless transpile when we claim to be in Eclipse
3572 println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3573 throw new StopExecutionException("Not running headless transpile whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
3575 println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3579 executable(eclipseBinary)
3580 args(["-nosplash", "--launcher.suppressErrors", "-application", "org.eclipse.jdt.apt.core.aptBuild", "-data", eclipseWorkspace, "-${jalviewjs_eclipse_build_arg}", eclipse_project_name ])
3584 args += [ "--launcher.appendVmargs", "-vmargs", "-Dorg.eclipse.equinox.p2.reconciler.dropins.directory=${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_eclipse_tmp_dropins_dir}" ]
3586 args += [ "-D${j2sHeadlessBuildProperty}=true" ]
3587 args += [ "-D${jalviewjs_j2s_alt_file_property}=${jalviewjsJ2sAltSettingsFileName}" ]
3593 stdout = new ByteArrayOutputStream()
3594 stderr = new ByteArrayOutputStream()
3596 def logOutFileName = "${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}"
3597 def logOutFile = file(logOutFileName)
3598 logOutFile.createNewFile()
3599 logOutFile.text = """ROOT: ${jalviewjs_eclipse_root}
3600 BINARY: ${eclipseBinary}
3601 VERSION: ${eclipseVersion}
3602 WORKSPACE: ${eclipseWorkspace}
3603 DEBUG: ${eclipseDebug}
3606 def logOutFOS = new FileOutputStream(logOutFile, true) // true == append
3607 // combine stdout and stderr
3608 def logErrFOS = logOutFOS
3610 if (jalviewjs_j2s_to_console.equals("true")) {
3611 standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
3612 new org.apache.tools.ant.util.TeeOutputStream(
3616 errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
3617 new org.apache.tools.ant.util.TeeOutputStream(
3622 standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
3625 errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
3632 if (stdout.toString().contains("Error processing ")) {
3633 // j2s did not complete transpile
3634 //throw new TaskExecutionException("Error during transpilation:\n${stderr}\nSee eclipse transpile log file '${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}'")
3635 if (jalviewjs_ignore_transpile_errors.equals("true")) {
3636 println("IGNORING TRANSPILE ERRORS")
3637 println("See eclipse transpile log file '${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}'")
3639 throw new GradleException("Error during transpilation:\n${stderr}\nSee eclipse transpile log file '${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}'")
3644 inputs.dir("${jalviewDir}/${sourceDir}")
3645 outputs.dir("${jalviewDir}/${jalviewjsTransferSiteJsDir}")
3646 outputs.upToDateWhen( { file("${jalviewDir}/${jalviewjsTransferSiteJsDir}${jalviewjs_server_resource}").exists() } )
3650 def jalviewjsCallCore(String name, FileCollection list, String prefixFile, String suffixFile, String jsfile, String zjsfile, File logOutFile, Boolean logOutConsole) {
3652 def stdout = new ByteArrayOutputStream()
3653 def stderr = new ByteArrayOutputStream()
3655 def coreFile = file(jsfile)
3657 msg = "Creating core for ${name}...\nGenerating ${jsfile}"
3659 logOutFile.createNewFile()
3660 logOutFile.append(msg+"\n")
3662 def coreTop = file(prefixFile)
3663 def coreBottom = file(suffixFile)
3664 coreFile.getParentFile().mkdirs()
3665 coreFile.createNewFile()
3666 coreFile.write( coreTop.getText("UTF-8") )
3670 def t = f.getText("UTF-8")
3671 t.replaceAll("Clazz\\.([^_])","Clazz_${1}")
3672 coreFile.append( t )
3674 msg = "...file '"+f.getPath()+"' does not exist, skipping"
3676 logOutFile.append(msg+"\n")
3679 coreFile.append( coreBottom.getText("UTF-8") )
3681 msg = "Generating ${zjsfile}"
3683 logOutFile.append(msg+"\n")
3684 def logOutFOS = new FileOutputStream(logOutFile, true) // true == append
3685 def logErrFOS = logOutFOS
3688 classpath = files(["${jalviewDir}/${jalviewjs_closure_compiler}"])
3689 main = "com.google.javascript.jscomp.CommandLineRunner"
3690 jvmArgs = [ "-Dfile.encoding=UTF-8" ]
3691 args = [ "--compilation_level", "SIMPLE_OPTIMIZATIONS", "--warning_level", "QUIET", "--charset", "UTF-8", "--js", jsfile, "--js_output_file", zjsfile ]
3694 msg = "\nRunning '"+commandLine.join(' ')+"'\n"
3696 logOutFile.append(msg+"\n")
3698 if (logOutConsole) {
3699 standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
3700 new org.apache.tools.ant.util.TeeOutputStream(
3704 errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
3705 new org.apache.tools.ant.util.TeeOutputStream(
3710 standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
3713 errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
3720 logOutFile.append(msg+"\n")
3724 task jalviewjsBuildAllCores {
3726 description "Build the core js lib closures listed in the classlists dir"
3727 dependsOn jalviewjsTranspile
3728 dependsOn jalviewjsTransferUnzipSwingJs
3730 def j2sDir = "${jalviewDir}/${jalviewjsTransferSiteJsDir}/${jalviewjs_j2s_subdir}"
3731 def swingJ2sDir = "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}/${jalviewjs_j2s_subdir}"
3732 def libJ2sDir = "${jalviewDir}/${jalviewjsTransferSiteLibDir}/${jalviewjs_j2s_subdir}"
3733 def jsDir = "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}/${jalviewjs_js_subdir}"
3734 def outputDir = "${jalviewDir}/${jalviewjsTransferSiteCoreDir}/${jalviewjs_j2s_subdir}/core"
3735 def prefixFile = "${jsDir}/core/coretop2.js"
3736 def suffixFile = "${jsDir}/core/corebottom2.js"
3738 inputs.file prefixFile
3739 inputs.file suffixFile
3741 def classlistFiles = []
3742 // add the classlists found int the jalviewjs_classlists_dir
3743 fileTree(dir: "${jalviewDir}/${jalviewjs_classlists_dir}", include: "*.txt").each {
3745 def name = file.getName() - ".txt"
3752 // _jmol and _jalview cores. Add any other peculiar classlist.txt files here
3753 //classlistFiles += [ 'file': file("${jalviewDir}/${jalviewjs_classlist_jmol}"), 'name': "_jvjmol" ]
3754 classlistFiles += [ 'file': file("${jalviewDir}/${jalviewjs_classlist_jalview}"), 'name': jalviewjsJalviewCoreName ]
3756 jalviewjsCoreClasslists = []
3758 classlistFiles.each {
3761 def file = hash['file']
3762 if (! file.exists()) {
3763 //println("...classlist file '"+file.getPath()+"' does not exist, skipping")
3764 return false // this is a "continue" in groovy .each closure
3766 def name = hash['name']
3768 name = file.getName() - ".txt"
3776 def list = fileTree(dir: j2sDir, includes: filelist)
3778 def jsfile = "${outputDir}/core${name}.js"
3779 def zjsfile = "${outputDir}/core${name}.z.js"
3781 jalviewjsCoreClasslists += [
3790 outputs.file(jsfile)
3791 outputs.file(zjsfile)
3794 // _stevesoft core. add any cores without a classlist here (and the inputs and outputs)
3795 def stevesoftClasslistName = "_stevesoft"
3796 def stevesoftClasslist = [
3797 'jsfile': "${outputDir}/core${stevesoftClasslistName}.js",
3798 'zjsfile': "${outputDir}/core${stevesoftClasslistName}.z.js",
3799 'list': fileTree(dir: j2sDir, include: "com/stevesoft/pat/**/*.js"),
3800 'name': stevesoftClasslistName
3802 jalviewjsCoreClasslists += stevesoftClasslist
3803 inputs.files(stevesoftClasslist['list'])
3804 outputs.file(stevesoftClasslist['jsfile'])
3805 outputs.file(stevesoftClasslist['zjsfile'])
3808 def allClasslistName = "_all"
3809 def allJsFiles = fileTree(dir: j2sDir, include: "**/*.js")
3810 allJsFiles += fileTree(
3814 // these exlusions are files that the closure-compiler produces errors for. Should fix them
3815 "**/org/jmol/jvxl/readers/IsoIntersectFileReader.js",
3816 "**/org/jmol/export/JSExporter.js"
3819 allJsFiles += fileTree(
3823 // these exlusions are files that the closure-compiler produces errors for. Should fix them
3824 "**/sun/misc/Unsafe.js",
3825 "**/swingjs/jquery/jquery-editable-select.js",
3826 "**/swingjs/jquery/j2sComboBox.js",
3827 "**/sun/misc/FloatingDecimal.js"
3830 def allClasslist = [
3831 'jsfile': "${outputDir}/core${allClasslistName}.js",
3832 'zjsfile': "${outputDir}/core${allClasslistName}.z.js",
3834 'name': allClasslistName
3836 // not including this version of "all" core at the moment
3837 //jalviewjsCoreClasslists += allClasslist
3838 inputs.files(allClasslist['list'])
3839 outputs.file(allClasslist['jsfile'])
3840 outputs.file(allClasslist['zjsfile'])
3843 def logOutFile = file("${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_j2s_closure_stdout}")
3844 logOutFile.getParentFile().mkdirs()
3845 logOutFile.createNewFile()
3846 logOutFile.write(getDate("yyyy-MM-dd HH:mm:ss")+" jalviewjsBuildAllCores\n----\n")
3848 jalviewjsCoreClasslists.each {
3849 jalviewjsCallCore(it.name, it.list, prefixFile, suffixFile, it.jsfile, it.zjsfile, logOutFile, jalviewjs_j2s_to_console.equals("true"))
3856 def jalviewjsPublishCoreTemplate(String coreName, String templateName, File inputFile, String outputFile) {
3859 into file(outputFile).getParentFile()
3860 rename { filename ->
3861 if (filename.equals(inputFile.getName())) {
3862 return file(outputFile).getName()
3866 filter(ReplaceTokens,
3870 'MAIN': '"'+main_class+'"',
3872 'NAME': jalviewjsJalviewTemplateName+" [core ${coreName}]",
3873 'COREKEY': jalviewjs_core_key,
3874 'CORENAME': coreName
3881 task jalviewjsPublishCoreTemplates {
3882 dependsOn jalviewjsBuildAllCores
3883 def inputFileName = "${jalviewDir}/${j2s_coretemplate_html}"
3884 def inputFile = file(inputFileName)
3885 def outputDir = "${jalviewDir}/${jalviewjsTransferSiteCoreDir}"
3887 def outputFiles = []
3888 jalviewjsCoreClasslists.each { cl ->
3889 def outputFile = "${outputDir}/${jalviewjsJalviewTemplateName}_${cl.name}.html"
3890 cl['outputfile'] = outputFile
3891 outputFiles += outputFile
3895 jalviewjsCoreClasslists.each { cl ->
3896 jalviewjsPublishCoreTemplate(cl.name, jalviewjsJalviewTemplateName, inputFile, cl.outputfile)
3899 inputs.file(inputFile)
3900 outputs.files(outputFiles)
3904 task jalviewjsSyncCore (type: Sync) {
3905 dependsOn jalviewjsBuildAllCores
3906 dependsOn jalviewjsPublishCoreTemplates
3907 def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjsTransferSiteCoreDir}")
3908 def outputDir = "${jalviewDir}/${jalviewjsSiteDir}"
3912 def outputFiles = []
3913 rename { filename ->
3914 outputFiles += "${outputDir}/${filename}"
3920 outputs.files outputFiles
3921 inputs.files inputFiles
3925 // this Copy version of TransferSiteJs will delete anything else in the target dir
3926 task jalviewjsCopyTransferSiteJs(type: Copy) {
3927 dependsOn jalviewjsTranspile
3928 from "${jalviewDir}/${jalviewjsTransferSiteJsDir}"
3929 into "${jalviewDir}/${jalviewjsSiteDir}"
3933 // this Sync version of TransferSite is used by buildship to keep the website automatically up to date when a file changes
3934 task jalviewjsSyncTransferSiteJs(type: Sync) {
3935 from "${jalviewDir}/${jalviewjsTransferSiteJsDir}"
3937 into "${jalviewDir}/${jalviewjsSiteDir}"
3944 jalviewjsSyncAllLibs.mustRunAfter jalviewjsCopyTransferSiteJs
3945 jalviewjsSyncResources.mustRunAfter jalviewjsCopyTransferSiteJs
3946 jalviewjsSyncSiteResources.mustRunAfter jalviewjsCopyTransferSiteJs
3947 jalviewjsSyncBuildProperties.mustRunAfter jalviewjsCopyTransferSiteJs
3949 jalviewjsSyncAllLibs.mustRunAfter jalviewjsSyncTransferSiteJs
3950 jalviewjsSyncResources.mustRunAfter jalviewjsSyncTransferSiteJs
3951 jalviewjsSyncSiteResources.mustRunAfter jalviewjsSyncTransferSiteJs
3952 jalviewjsSyncBuildProperties.mustRunAfter jalviewjsSyncTransferSiteJs
3955 task jalviewjsPrepareSite {
3957 description "Prepares the website folder including unzipping files and copying resources"
3958 dependsOn jalviewjsSyncAllLibs
3959 dependsOn jalviewjsSyncResources
3960 dependsOn jalviewjsSyncSiteResources
3961 dependsOn jalviewjsSyncBuildProperties
3962 dependsOn jalviewjsSyncCore
3966 task jalviewjsBuildSite {
3968 description "Builds the whole website including transpiled code"
3969 dependsOn jalviewjsCopyTransferSiteJs
3970 dependsOn jalviewjsPrepareSite
3974 task cleanJalviewjsTransferSite {
3976 delete "${jalviewDir}/${jalviewjsTransferSiteJsDir}"
3977 delete "${jalviewDir}/${jalviewjsTransferSiteLibDir}"
3978 delete "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}"
3979 delete "${jalviewDir}/${jalviewjsTransferSiteCoreDir}"
3984 task cleanJalviewjsSite {
3985 dependsOn cleanJalviewjsTransferSite
3987 delete "${jalviewDir}/${jalviewjsSiteDir}"
3992 task jalviewjsSiteTar(type: Tar) {
3994 description "Creates a tar.gz file for the website"
3995 dependsOn jalviewjsBuildSite
3996 def outputFilename = "jalviewjs-site-${JALVIEW_VERSION}.tar.gz"
3997 archiveFileName = outputFilename
3999 compression Compression.GZIP
4001 from "${jalviewDir}/${jalviewjsSiteDir}"
4002 into jalviewjs_site_dir // this is inside the tar file
4004 inputs.dir("${jalviewDir}/${jalviewjsSiteDir}")
4008 task jalviewjsServer {
4010 def filename = "jalviewjsTest.html"
4011 description "Starts a webserver on localhost to test the website. See ${filename} to access local site on most recently used port."
4012 def htmlFile = "${jalviewDirAbsolutePath}/${filename}"
4017 def f = Class.forName("org.gradle.plugins.javascript.envjs.http.simple.SimpleHttpFileServerFactory")
4018 factory = f.newInstance()
4019 } catch (ClassNotFoundException e) {
4020 throw new GradleException("Unable to create SimpleHttpFileServerFactory")
4022 def port = Integer.valueOf(jalviewjs_server_port)
4027 while(port < start+1000 && !running) {
4029 def doc_root = new File("${jalviewDirAbsolutePath}/${jalviewjsSiteDir}")
4030 jalviewjsServer = factory.start(doc_root, port)
4032 url = jalviewjsServer.getResourceUrl(jalviewjs_server_resource)
4033 println("SERVER STARTED with document root ${doc_root}.")
4034 println("Go to "+url+" . Run gradle --stop to stop (kills all gradle daemons).")
4035 println("For debug: "+url+"?j2sdebug")
4036 println("For verbose: "+url+"?j2sverbose")
4037 } catch (Exception e) {
4042 <p><a href="${url}">JalviewJS Test. <${url}></a></p>
4043 <p><a href="${url}?j2sdebug">JalviewJS Test with debug. <${url}?j2sdebug></a></p>
4044 <p><a href="${url}?j2sverbose">JalviewJS Test with verbose. <${url}?j2sdebug></a></p>
4046 jalviewjsCoreClasslists.each { cl ->
4047 def urlcore = jalviewjsServer.getResourceUrl(file(cl.outputfile).getName())
4049 <p><a href="${urlcore}">${jalviewjsJalviewTemplateName} [core ${cl.name}]. <${urlcore}></a></p>
4051 println("For core ${cl.name}: "+urlcore)
4054 file(htmlFile).text = htmlText
4057 outputs.file(htmlFile)
4058 outputs.upToDateWhen({false})
4062 task cleanJalviewjsAll {
4064 description "Delete all configuration and build artifacts to do with JalviewJS build"
4065 dependsOn cleanJalviewjsSite
4066 dependsOn jalviewjsEclipsePaths
4069 delete "${jalviewDir}/${jalviewjsBuildDir}"
4070 delete "${jalviewDir}/${eclipse_bin_dir}"
4071 if (eclipseWorkspace != null && file(eclipseWorkspace.getAbsolutePath()+"/.metadata").exists()) {
4072 delete file(eclipseWorkspace.getAbsolutePath()+"/.metadata")
4074 delete jalviewjsJ2sAltSettingsFileName
4077 outputs.upToDateWhen( { false } )
4081 task jalviewjsIDE_checkJ2sPlugin {
4082 group "00 JalviewJS in Eclipse"
4083 description "Compare the swingjs/net.sf.j2s.core(-j11)?.jar file with the Eclipse IDE's plugin version (found in the 'dropins' dir)"
4086 def j2sPlugin = string("${jalviewDir}/${jalviewjsJ2sPlugin}")
4087 def j2sPluginFile = file(j2sPlugin)
4088 def eclipseHome = System.properties["eclipse.home.location"]
4089 if (eclipseHome == null || ! IN_ECLIPSE) {
4090 throw new StopExecutionException("Cannot find running Eclipse home from System.properties['eclipse.home.location']. Skipping J2S Plugin Check.")
4092 def eclipseJ2sPluginDirs = [ "${eclipseHome}/dropins" ]
4093 def altPluginsDir = System.properties["org.eclipse.equinox.p2.reconciler.dropins.directory"]
4094 if (altPluginsDir != null && file(altPluginsDir).exists()) {
4095 eclipseJ2sPluginDirs += altPluginsDir
4097 def foundPlugin = false
4098 def j2sPluginFileName = j2sPluginFile.getName()
4099 def eclipseJ2sPlugin
4100 def eclipseJ2sPluginFile
4101 eclipseJ2sPluginDirs.any { dir ->
4102 eclipseJ2sPlugin = "${dir}/${j2sPluginFileName}"
4103 eclipseJ2sPluginFile = file(eclipseJ2sPlugin)
4104 if (eclipseJ2sPluginFile.exists()) {
4110 def msg = "Eclipse J2S Plugin is not installed (could not find '${j2sPluginFileName}' in\n"+eclipseJ2sPluginDirs.join("\n")+"\n)\nTry running task jalviewjsIDE_copyJ2sPlugin"
4111 System.err.println(msg)
4112 throw new StopExecutionException(msg)
4115 def digest = MessageDigest.getInstance("MD5")
4117 digest.update(j2sPluginFile.text.bytes)
4118 def j2sPluginMd5 = new BigInteger(1, digest.digest()).toString(16).padLeft(32, '0')
4120 digest.update(eclipseJ2sPluginFile.text.bytes)
4121 def eclipseJ2sPluginMd5 = new BigInteger(1, digest.digest()).toString(16).padLeft(32, '0')
4123 if (j2sPluginMd5 != eclipseJ2sPluginMd5) {
4124 def msg = "WARNING! Eclipse J2S Plugin '${eclipseJ2sPlugin}' is different to this commit's version '${j2sPlugin}'"
4125 System.err.println(msg)
4126 throw new StopExecutionException(msg)
4128 def msg = "Eclipse J2S Plugin '${eclipseJ2sPlugin}' is the same as '${j2sPlugin}' (this is good)"
4134 task jalviewjsIDE_copyJ2sPlugin {
4135 group "00 JalviewJS in Eclipse"
4136 description "Copy the swingjs/net.sf.j2s.core(-j11)?.jar file into the Eclipse IDE's 'dropins' dir"
4139 def j2sPlugin = string("${jalviewDir}/${jalviewjsJ2sPlugin}")
4140 def j2sPluginFile = file(j2sPlugin)
4141 def eclipseHome = System.properties["eclipse.home.location"]
4142 if (eclipseHome == null || ! IN_ECLIPSE) {
4143 throw new StopExecutionException("Cannot find running Eclipse home from System.properties['eclipse.home.location']. NOT copying J2S Plugin.")
4145 def eclipseJ2sPlugin = "${eclipseHome}/dropins/${j2sPluginFile.getName()}"
4146 def eclipseJ2sPluginFile = file(eclipseJ2sPlugin)
4147 def msg = "WARNING! Copying this commit's j2s plugin '${j2sPlugin}' to Eclipse J2S Plugin '${eclipseJ2sPlugin}'\n* May require an Eclipse restart"
4148 System.err.println(msg)
4151 eclipseJ2sPluginFile.getParentFile().mkdirs()
4152 into eclipseJ2sPluginFile.getParent()
4158 task jalviewjsIDE_j2sFile {
4159 group "00 JalviewJS in Eclipse"
4160 description "Creates the .j2s file"
4161 dependsOn jalviewjsCreateJ2sSettings
4165 task jalviewjsIDE_SyncCore {
4166 group "00 JalviewJS in Eclipse"
4167 description "Build the core js lib closures listed in the classlists dir and publish core html from template"
4168 dependsOn jalviewjsSyncCore
4172 task jalviewjsIDE_SyncSiteAll {
4173 dependsOn jalviewjsSyncAllLibs
4174 dependsOn jalviewjsSyncResources
4175 dependsOn jalviewjsSyncSiteResources
4176 dependsOn jalviewjsSyncBuildProperties
4180 cleanJalviewjsTransferSite.mustRunAfter jalviewjsIDE_SyncSiteAll
4183 task jalviewjsIDE_PrepareSite {
4184 group "00 JalviewJS in Eclipse"
4185 description "Sync libs and resources to site dir, but not closure cores"
4187 dependsOn jalviewjsIDE_SyncSiteAll
4188 //dependsOn cleanJalviewjsTransferSite // not sure why this clean is here -- will slow down a re-run of this task
4192 task jalviewjsIDE_AssembleSite {
4193 group "00 JalviewJS in Eclipse"
4194 description "Assembles unzipped supporting zipfiles, resources, site resources and closure cores into the Eclipse transpiled site"
4195 dependsOn jalviewjsPrepareSite
4199 task jalviewjsIDE_SiteClean {
4200 group "00 JalviewJS in Eclipse"
4201 description "Deletes the Eclipse transpiled site"
4202 dependsOn cleanJalviewjsSite
4206 task jalviewjsIDE_Server {
4207 group "00 JalviewJS in Eclipse"
4208 description "Starts a webserver on localhost to test the website"
4209 dependsOn jalviewjsServer
4213 // buildship runs this at import or gradle refresh
4214 task eclipseSynchronizationTask {
4215 //dependsOn eclipseSetup
4216 dependsOn createBuildProperties
4218 dependsOn jalviewjsIDE_j2sFile
4219 dependsOn jalviewjsIDE_checkJ2sPlugin
4220 dependsOn jalviewjsIDE_PrepareSite
4225 // buildship runs this at build time or project refresh
4226 task eclipseAutoBuildTask {
4227 //dependsOn jalviewjsIDE_checkJ2sPlugin
4228 //dependsOn jalviewjsIDE_PrepareSite
4232 task jalviewjsCopyStderrLaunchFile(type: Copy) {
4233 from file(jalviewjs_stderr_launch)
4234 into jalviewjsSiteDir
4236 inputs.file jalviewjs_stderr_launch
4237 outputs.file jalviewjsStderrLaunchFilename
4240 task cleanJalviewjsChromiumUserDir {
4242 delete jalviewjsChromiumUserDir
4244 outputs.dir jalviewjsChromiumUserDir
4245 // always run when depended on
4246 outputs.upToDateWhen { !file(jalviewjsChromiumUserDir).exists() }
4249 task jalviewjsChromiumProfile {
4250 dependsOn cleanJalviewjsChromiumUserDir
4251 mustRunAfter cleanJalviewjsChromiumUserDir
4253 def firstRun = file("${jalviewjsChromiumUserDir}/First Run")
4256 mkdir jalviewjsChromiumProfileDir
4259 outputs.file firstRun
4262 task jalviewjsLaunchTest {
4264 description "Check JalviewJS opens in a browser"
4265 dependsOn jalviewjsBuildSite
4266 dependsOn jalviewjsCopyStderrLaunchFile
4267 dependsOn jalviewjsChromiumProfile
4269 def macOS = OperatingSystem.current().isMacOsX()
4270 def chromiumBinary = macOS ? jalviewjs_macos_chromium_binary : jalviewjs_chromium_binary
4271 if (chromiumBinary.startsWith("~/")) {
4272 chromiumBinary = System.getProperty("user.home") + chromiumBinary.substring(1)
4278 def timeoutms = Integer.valueOf(jalviewjs_chromium_overall_timeout) * 1000
4280 def binary = file(chromiumBinary)
4281 if (!binary.exists()) {
4282 throw new StopExecutionException("Could not find chromium binary '${chromiumBinary}'. Cannot run task ${name}.")
4284 stdout = new ByteArrayOutputStream()
4285 stderr = new ByteArrayOutputStream()
4288 if (jalviewjs_j2s_to_console.equals("true")) {
4289 execStdout = new org.apache.tools.ant.util.TeeOutputStream(
4292 execStderr = new org.apache.tools.ant.util.TeeOutputStream(
4300 "--no-sandbox", // --no-sandbox IS USED BY THE THORIUM APPIMAGE ON THE BUILDSERVER
4303 "--timeout=${timeoutms}",
4304 "--virtual-time-budget=${timeoutms}",
4305 "--user-data-dir=${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_chromium_user_dir}",
4306 "--profile-directory=${jalviewjs_chromium_profile_name}",
4307 "--allow-file-access-from-files",
4308 "--enable-logging=stderr",
4309 "file://${jalviewDirAbsolutePath}/${jalviewjsStderrLaunchFilename}"
4312 if (true || macOS) {
4313 ScheduledExecutorService executor = Executors.newScheduledThreadPool(3);
4314 Future f1 = executor.submit(
4317 standardOutput = execStdout
4318 errorOutput = execStderr
4319 executable(chromiumBinary)
4321 println "COMMAND: '"+commandLine.join(" ")+"'"
4323 executor.shutdownNow()
4327 def noChangeBytes = 0
4328 def noChangeIterations = 0
4329 executor.scheduleAtFixedRate(
4331 String stderrString = stderr.toString()
4332 // shutdown the task if we have a success string
4333 if (stderrString.contains(jalviewjs_desktop_init_string)) {
4336 executor.shutdownNow()
4338 // if no change in stderr for 10s then also end
4339 if (noChangeIterations >= jalviewjs_chromium_idle_timeout) {
4340 executor.shutdownNow()
4342 if (stderrString.length() == noChangeBytes) {
4343 noChangeIterations++
4345 noChangeBytes = stderrString.length()
4346 noChangeIterations = 0
4349 1, 1, TimeUnit.SECONDS)
4351 executor.schedule(new Runnable(){
4354 executor.shutdownNow()
4356 }, timeoutms, TimeUnit.MILLISECONDS)
4358 executor.awaitTermination(timeoutms+10000, TimeUnit.MILLISECONDS)
4359 executor.shutdownNow()
4366 stderr.toString().eachLine { line ->
4367 if (line.contains(jalviewjs_desktop_init_string)) {
4368 println("Found line '"+line+"'")
4374 throw new GradleException("Could not find evidence of Desktop launch in JalviewJS.")
4382 description "Build the JalviewJS site and run the launch test"
4383 dependsOn jalviewjsBuildSite
4384 dependsOn jalviewjsLaunchTest