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"
46 classpath 'ru.vyarus:gradle-use-python-plugin:4.0.0'
55 id "com.diffplug.gradle.spotless" version "3.28.0"
56 id 'com.github.johnrengelman.shadow' version '6.0.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
60 id 'ru.vyarus.use-python' version '4.0.0'
71 // in ext the values are cast to Object. Ensure string values are cast as String (and not GStringImpl) for later use
72 def string(Object o) {
73 return o == null ? "" : o.toString()
76 def overrideProperties(String propsFileName, boolean output = false) {
77 if (propsFileName == null) {
80 def propsFile = file(propsFileName)
81 if (propsFile != null && propsFile.exists()) {
82 println("Using properties from file '${propsFileName}'")
84 def p = new Properties()
85 def localPropsFIS = new FileInputStream(propsFile)
91 if (project.hasProperty(key)) {
92 oldval = project.findProperty(key)
93 project.setProperty(key, val)
95 println("Overriding property '${key}' ('${oldval}') with ${file(propsFile).getName()} value '${val}'")
98 ext.setProperty(key, val)
100 println("Setting ext property '${key}' with ${file(propsFile).getName()}s value '${val}'")
104 } catch (Exception e) {
105 println("Exception reading local.properties")
112 jalviewDirAbsolutePath = file(jalviewDir).getAbsolutePath()
113 jalviewDirRelativePath = jalviewDir
116 getdownChannelName = CHANNEL.toLowerCase()
117 // default to "default". Currently only has different cosmetics for "develop", "release", "default"
118 propertiesChannelName = ["develop", "release", "test-release", "jalviewjs", "jalviewjs-release" ].contains(getdownChannelName) ? getdownChannelName : "default"
119 channelDirName = propertiesChannelName
120 // Import channel_properties
121 if (getdownChannelName.startsWith("develop-")) {
122 channelDirName = "develop-SUFFIX"
124 channelDir = string("${jalviewDir}/${channel_properties_dir}/${channelDirName}")
125 channelGradleProperties = string("${channelDir}/channel_gradle.properties")
126 channelPropsFile = string("${channelDir}/${resource_dir}/${channel_props}")
127 overrideProperties(channelGradleProperties, false)
128 // local build environment properties
129 // can be "projectDir/local.properties"
130 overrideProperties("${projectDir}/local.properties", true)
131 // or "../projectDir_local.properties"
132 overrideProperties(projectDir.getParent() + "/" + projectDir.getName() + "_local.properties", true)
135 // Import releaseProps from the RELEASE file
136 // or a file specified via JALVIEW_RELEASE_FILE if defined
137 // Expect jalview.version and target release branch in jalview.release
138 releaseProps = new Properties();
139 def releasePropFile = findProperty("JALVIEW_RELEASE_FILE");
140 def defaultReleasePropFile = "${jalviewDirAbsolutePath}/RELEASE";
142 (new File(releasePropFile!=null ? releasePropFile : defaultReleasePropFile)).withInputStream {
143 releaseProps.load(it)
145 } catch (Exception fileLoadError) {
146 throw new Error("Couldn't load release properties file "+(releasePropFile==null ? defaultReleasePropFile : "from custom location: releasePropFile"),fileLoadError);
149 // Set JALVIEW_VERSION if it is not already set
150 if (findProperty("JALVIEW_VERSION")==null || "".equals(JALVIEW_VERSION)) {
151 JALVIEW_VERSION = releaseProps.get("jalview.version")
153 println("JALVIEW_VERSION is set to '${JALVIEW_VERSION}'")
155 // this property set when running Eclipse headlessly
156 j2sHeadlessBuildProperty = string("net.sf.j2s.core.headlessbuild")
157 // this property set by Eclipse
158 eclipseApplicationProperty = string("eclipse.application")
159 // CHECK IF RUNNING FROM WITHIN ECLIPSE
160 def eclipseApplicationPropertyVal = System.properties[eclipseApplicationProperty]
161 IN_ECLIPSE = eclipseApplicationPropertyVal != null && eclipseApplicationPropertyVal.startsWith("org.eclipse.ui.")
162 // BUT WITHOUT THE HEADLESS BUILD PROPERTY SET
163 if (System.properties[j2sHeadlessBuildProperty].equals("true")) {
164 println("Setting IN_ECLIPSE to ${IN_ECLIPSE} as System.properties['${j2sHeadlessBuildProperty}'] == '${System.properties[j2sHeadlessBuildProperty]}'")
168 println("WITHIN ECLIPSE IDE")
170 println("HEADLESS BUILD")
173 J2S_ENABLED = (project.hasProperty('j2s.compiler.status') && project['j2s.compiler.status'] != null && project['j2s.compiler.status'] == "enable")
175 println("J2S ENABLED")
178 System.properties.sort { it.key }.each {
179 key, val -> println("SYSTEM PROPERTY ${key}='${val}'")
182 if (false && IN_ECLIPSE) {
183 jalviewDir = jalviewDirAbsolutePath
188 buildDate = new Date().format("yyyyMMdd")
191 bareSourceDir = string(source_dir)
192 sourceDir = string("${jalviewDir}/${bareSourceDir}")
193 resourceDir = string("${jalviewDir}/${resource_dir}")
194 bareTestSourceDir = string(test_source_dir)
195 testDir = string("${jalviewDir}/${bareTestSourceDir}")
197 classesDir = string("${jalviewDir}/${classes_dir}")
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 install4jmacOSArchiveName = "${jalview_name} Non-Release ${JALVIEW_VERSION} Installer"
242 install4jExecutableName = install4j_executable_name
243 install4jExtraScheme = "jalviewextra"
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 install4jDMGFixedDSStore = "${install4jBuildDir}/${install4j_dmg_ds_store}"
250 install4jCheckSums = true
252 applicationName = "${jalview_name}"
256 // TODO: get bamboo build artifact URL for getdown artifacts
257 getdown_channel_base = bamboo_channelbase
258 getdownChannelName = string("${bamboo_planKey}/${JAVA_VERSION}")
259 getdownAppBase = string("${bamboo_channelbase}/${bamboo_planKey}${bamboo_getdown_channel_suffix}/${JAVA_VERSION}")
260 jvlChannelName += "_${getdownChannelName}"
261 // automatically add the test group Not-bamboo for exclusion
262 if ("".equals(testng_excluded_groups)) {
263 testng_excluded_groups = "Not-bamboo"
265 install4jExtraScheme = "jalviewb"
266 backgroundImageText = true
269 case [ "RELEASE", "JALVIEWJS-RELEASE" ]:
270 getdownAppDistDir = getdown_app_dir_release
271 getdownSetAppBaseProperty = true
272 reportRsyncCommand = true
274 install4jmacOSArchiveName = "Install ${jalview_name} ${JALVIEW_VERSION}"
275 install4jExtraScheme = (CHANNEL=="RELEASE")?"jalviewx":"jalviewjs"
279 getdownChannelName = CHANNEL.toLowerCase()+"/${JALVIEW_VERSION}"
280 getdownDir = string("${getdownChannelName}/${JAVA_VERSION}")
281 getdownAppBase = string("${getdown_channel_base}/${getdownDir}")
282 if (!file("${ARCHIVEDIR}/${package_dir}").exists()) {
283 throw new GradleException("Must provide an ARCHIVEDIR value to produce an archive distribution")
285 package_dir = string("${ARCHIVEDIR}/${package_dir}")
286 buildProperties = string("${ARCHIVEDIR}/${classes_dir}/${build_properties_file}")
289 reportRsyncCommand = true
290 install4jExtraScheme = "jalviewa"
294 getdownChannelName = string("archive/${JALVIEW_VERSION}")
295 getdownDir = string("${getdownChannelName}/${JAVA_VERSION}")
296 getdownAppBase = file(getdownAppBaseDir).toURI().toString()
297 if (!file("${ARCHIVEDIR}/${package_dir}").exists()) {
298 throw new GradleException("Must provide an ARCHIVEDIR value to produce an archive distribution [did not find '${ARCHIVEDIR}/${package_dir}']")
300 package_dir = string("${ARCHIVEDIR}/${package_dir}")
301 buildProperties = string("${ARCHIVEDIR}/${classes_dir}/${build_properties_file}")
304 reportRsyncCommand = true
305 getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher_local}")
306 install4jSuffix = "Archive"
307 install4jExtraScheme = "jalviewa"
310 case ~/^DEVELOP-([\.\-\w]*)$/:
311 def suffix = Matcher.lastMatcher[0][1]
312 reportRsyncCommand = true
313 getdownSetAppBaseProperty = true
314 JALVIEW_VERSION=JALVIEW_VERSION+"-d${suffix}-${buildDate}"
315 install4jSuffix = "Develop ${suffix}"
316 install4jExtraScheme = "jalviewd"
317 install4jmacOSArchiveName = "Install ${jalview_name} Develop ${suffix} ${JALVIEW_VERSION}"
318 getdownChannelName = string("develop-${suffix}")
319 getdownChannelDir = string("${getdown_website_dir}/${getdownChannelName}")
320 getdownAppBaseDir = string("${jalviewDir}/${getdownChannelDir}/${JAVA_VERSION}")
321 getdownDir = string("${getdownChannelName}/${JAVA_VERSION}")
322 getdownAppBase = string("${getdown_channel_base}/${getdownDir}")
323 channelSuffix = string(suffix)
324 backgroundImageText = true
328 reportRsyncCommand = true
329 getdownSetAppBaseProperty = true
330 // DEVELOP-RELEASE is usually associated with a Jalview release series so set the version
331 JALVIEW_VERSION=JALVIEW_VERSION+"-d${buildDate}"
333 install4jSuffix = "Develop"
334 install4jExtraScheme = "jalviewd"
335 install4jmacOSArchiveName = "Install ${jalview_name} Develop ${JALVIEW_VERSION}"
336 backgroundImageText = true
340 reportRsyncCommand = true
341 getdownSetAppBaseProperty = true
342 // Don't ignore transpile errors for release build
343 if (jalviewjs_ignore_transpile_errors.equals("true")) {
344 jalviewjs_ignore_transpile_errors = "false"
345 println("Setting jalviewjs_ignore_transpile_errors to 'false'")
347 JALVIEW_VERSION = JALVIEW_VERSION+"-test"
348 install4jSuffix = "Test"
349 install4jExtraScheme = "jalviewt"
350 install4jmacOSArchiveName = "Install ${jalview_name} Test ${JALVIEW_VERSION}"
351 backgroundImageText = true
354 case ~/^SCRATCH(|-[-\w]*)$/:
355 getdownChannelName = CHANNEL
356 JALVIEW_VERSION = JALVIEW_VERSION+"-"+CHANNEL
358 getdownDir = string("${getdownChannelName}/${JAVA_VERSION}")
359 getdownAppBase = string("${getdown_channel_base}/${getdownDir}")
360 reportRsyncCommand = true
361 install4jSuffix = "Scratch"
365 if (!file("${LOCALDIR}").exists()) {
366 throw new GradleException("Must provide a LOCALDIR value to produce a local distribution")
368 getdownAppBase = file(file("${LOCALDIR}").getAbsolutePath()).toURI().toString()
369 getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher_local}")
371 JALVIEW_VERSION = "TEST"
372 install4jSuffix = "Test-Local"
373 install4jExtraScheme = "jalviewt"
374 install4jmacOSArchiveName = "Install ${jalview_name} Test ${JALVIEW_VERSION}"
375 backgroundImageText = true
378 case [ "LOCAL", "JALVIEWJS" ]:
379 JALVIEW_VERSION = "TEST"
380 getdownAppBase = file(getdownAppBaseDir).toURI().toString()
381 getdownArchiveAppBase = file("${jalviewDir}/${getdown_archive_dir}").toURI().toString()
382 getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher_local}")
383 install4jExtraScheme = "jalviewl"
384 install4jCheckSums = false
387 default: // something wrong specified
388 throw new GradleException("CHANNEL must be one of BUILD, RELEASE, ARCHIVE, DEVELOP, TEST-RELEASE, SCRATCH-..., LOCAL [default]")
392 JALVIEW_VERSION_UNDERSCORES = JALVIEW_VERSION.replaceAll("\\.", "_")
393 hugoDataJsonFile = file("${jalviewDir}/${hugo_build_dir}/${hugo_data_installers_dir}/installers-${JALVIEW_VERSION_UNDERSCORES}.json")
394 hugoArchiveMdFile = file("${jalviewDir}/${hugo_build_dir}/${hugo_version_archive_dir}/Version-${JALVIEW_VERSION_UNDERSCORES}/_index.md")
395 // override getdownAppBase if requested
396 if (findProperty("getdown_appbase_override") != null) {
397 // revert to LOCAL if empty string
398 if (string(getdown_appbase_override) == "") {
399 getdownAppBase = file(getdownAppBaseDir).toURI().toString()
400 getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher_local}")
401 } else if (string(getdown_appbase_override).startsWith("file://")) {
402 getdownAppBase = string(getdown_appbase_override)
403 getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher_local}")
405 getdownAppBase = string(getdown_appbase_override)
407 println("Overriding getdown appbase with '${getdownAppBase}'")
409 // sanitise file name for jalview launcher file for this channel
410 jvlChannelName = jvlChannelName.replaceAll("[^\\w\\-]+", "_")
411 // install4j application and folder names
412 if (install4jSuffix == "") {
413 install4jBundleId = "${install4j_bundle_id}"
414 install4jWinApplicationId = install4j_release_win_application_id
416 applicationName = "${jalview_name} ${install4jSuffix}"
417 install4jBundleId = "${install4j_bundle_id}-" + install4jSuffix.toLowerCase()
418 // add int hash of install4jSuffix to the last part of the application_id
419 def id = install4j_release_win_application_id
420 def idsplitreverse = id.split("-").reverse()
421 idsplitreverse[0] = idsplitreverse[0].toInteger() + install4jSuffix.hashCode()
422 install4jWinApplicationId = idsplitreverse.reverse().join("-")
424 // sanitise folder and id names
425 // install4jApplicationFolder = e.g. "Jalview Build"
426 install4jApplicationFolder = applicationName
427 .replaceAll("[\"'~:/\\\\\\s]", "_") // replace all awkward filename chars " ' ~ : / \
428 .replaceAll("_+", "_") // collapse __
429 install4jInternalId = applicationName
431 .replaceAll("[^\\w\\-\\.]", "_") // replace other non [alphanumeric,_,-,.]
432 .replaceAll("_+", "") // collapse __
433 //.replaceAll("_*-_*", "-") // collapse _-_
434 install4jUnixApplicationFolder = applicationName
436 .replaceAll("[^\\w\\-\\.]", "_") // replace other non [alphanumeric,_,-,.]
437 .replaceAll("_+", "_") // collapse __
438 .replaceAll("_*-_*", "-") // collapse _-_
440 install4jmacOSArchiveX86Name = "${install4jmacOSArchiveName} (Intel)"
441 install4jmacOSArchiveAarch64Name = "${install4jmacOSArchiveName} (Apple Silicon)"
443 getdownWrapperLink = install4jUnixApplicationFolder // e.g. "jalview_local"
444 getdownAppDir = string("${getdownAppBaseDir}/${getdownAppDistDir}")
445 //getdownJ11libDir = "${getdownAppBaseDir}/${getdown_j11lib_dir}"
446 getdownResourceDir = string("${getdownAppBaseDir}/${getdown_resource_dir}")
447 getdownInstallDir = string("${getdownAppBaseDir}/${getdown_install_dir}")
448 getdownFilesDir = string("${jalviewDir}/${getdown_files_dir}/${JAVA_VERSION}/")
449 getdownFilesInstallDir = string("${getdownFilesDir}/${getdown_install_dir}")
450 /* compile without modules -- using classpath libraries
451 modules_compileClasspath = fileTree(dir: "${jalviewDir}/${j11modDir}", include: ["*.jar"])
452 modules_runtimeClasspath = modules_compileClasspath
458 apply plugin: "com.palantir.git-version"
459 def details = versionDetails()
460 gitHash = details.gitHash
461 gitBranch = details.branchName
462 } catch(org.gradle.api.internal.plugins.PluginApplicationException e) {
463 println("Not in a git repository. Using git values from RELEASE properties file.")
464 gitHash = releaseProps.getProperty("git.hash")
465 gitBranch = releaseProps.getProperty("git.branch")
466 } catch(java.lang.RuntimeException e1) {
467 throw new GradleException("Error with git-version plugin. Directory '.git' exists but versionDetails() cannot be found.")
470 println("Using a ${CHANNEL} profile.")
472 additional_compiler_args = []
473 // configure classpath/args for j8/j11 compilation
474 if (JAVA_VERSION.equals("1.8")) {
475 JAVA_INTEGER_VERSION = string("8")
478 libDistDir = j8libDir
479 compile_source_compatibility = 1.8
480 compile_target_compatibility = 1.8
481 // these are getdown.txt properties defined dependent on the JAVA_VERSION
482 getdownAltJavaMinVersion = string(findProperty("getdown_alt_java8_min_version"))
483 getdownAltJavaMaxVersion = string(findProperty("getdown_alt_java8_max_version"))
484 // this property is assigned below and expanded to multiple lines in the getdown task
485 getdownAltMultiJavaLocation = string(findProperty("getdown_alt_java8_txt_multi_java_location"))
486 // this property is for the Java library used in eclipse
487 eclipseJavaRuntimeName = string("JavaSE-1.8")
488 } else if (JAVA_VERSION.equals("11")) {
489 JAVA_INTEGER_VERSION = string("11")
491 libDistDir = j11libDir
492 compile_source_compatibility = 11
493 compile_target_compatibility = 11
494 getdownAltJavaMinVersion = string(findProperty("getdown_alt_java11_min_version"))
495 getdownAltJavaMaxVersion = string(findProperty("getdown_alt_java11_max_version"))
496 getdownAltMultiJavaLocation = string(findProperty("getdown_alt_java11_txt_multi_java_location"))
497 eclipseJavaRuntimeName = string("JavaSE-11")
498 /* compile without modules -- using classpath libraries
499 additional_compiler_args += [
500 '--module-path', modules_compileClasspath.asPath,
501 '--add-modules', j11modules
504 } else if (JAVA_VERSION.equals("17")) {
505 JAVA_INTEGER_VERSION = string("17")
507 libDistDir = j17libDir
508 compile_source_compatibility = 17
509 compile_target_compatibility = 17
510 getdownAltJavaMinVersion = string(findProperty("getdown_alt_java11_min_version"))
511 getdownAltJavaMaxVersion = string(findProperty("getdown_alt_java11_max_version"))
512 getdownAltMultiJavaLocation = string(findProperty("getdown_alt_java11_txt_multi_java_location"))
513 eclipseJavaRuntimeName = string("JavaSE-17")
514 /* compile without modules -- using classpath libraries
515 additional_compiler_args += [
516 '--module-path', modules_compileClasspath.asPath,
517 '--add-modules', j11modules
521 throw new GradleException("JAVA_VERSION=${JAVA_VERSION} not currently supported by Jalview")
526 JAVA_MIN_VERSION = JAVA_VERSION
527 JAVA_MAX_VERSION = JAVA_VERSION
528 jreInstallsDir = string(jre_installs_dir)
529 if (jreInstallsDir.startsWith("~/")) {
530 jreInstallsDir = System.getProperty("user.home") + jreInstallsDir.substring(1)
532 install4jDir = string("${jalviewDir}/${install4j_utils_dir}")
533 install4jConfFileName = string("jalview-install4j-conf.install4j")
534 install4jConfFile = file("${install4jDir}/${install4jConfFileName}")
535 install4jHomeDir = install4j_home_dir
536 if (install4jHomeDir.startsWith("~/")) {
537 install4jHomeDir = System.getProperty("user.home") + install4jHomeDir.substring(1)
540 resourceBuildDir = string("${buildDir}/resources")
541 resourcesBuildDir = string("${resourceBuildDir}/resources_build")
542 helpBuildDir = string("${resourceBuildDir}/help_build")
543 docBuildDir = string("${resourceBuildDir}/doc_build")
545 if (buildProperties == null) {
546 buildProperties = string("${resourcesBuildDir}/${build_properties_file}")
548 buildingHTML = string("${jalviewDir}/${doc_dir}/building.html")
549 helpParentDir = string("${jalviewDir}/${help_parent_dir}")
550 helpSourceDir = string("${helpParentDir}/${help_dir}")
551 helpFile = string("${helpBuildDir}/${help_dir}/help.jhm")
554 convertBinaryExpectedLocation = imagemagick_convert
555 if (convertBinaryExpectedLocation.startsWith("~/")) {
556 convertBinaryExpectedLocation = System.getProperty("user.home") + convertBinaryExpectedLocation.substring(1)
558 if (file(convertBinaryExpectedLocation).exists()) {
559 convertBinary = convertBinaryExpectedLocation
562 relativeBuildDir = file(jalviewDirAbsolutePath).toPath().relativize(buildDir.toPath())
563 jalviewjsBuildDir = string("${relativeBuildDir}/jalviewjs")
564 jalviewjsSiteDir = string("${jalviewjsBuildDir}/${jalviewjs_site_dir}")
566 jalviewjsTransferSiteJsDir = string(jalviewjsSiteDir)
568 jalviewjsTransferSiteJsDir = string("${jalviewjsBuildDir}/tmp/${jalviewjs_site_dir}_js")
570 jalviewjsTransferSiteLibDir = string("${jalviewjsBuildDir}/tmp/${jalviewjs_site_dir}_lib")
571 jalviewjsTransferSiteSwingJsDir = string("${jalviewjsBuildDir}/tmp/${jalviewjs_site_dir}_swingjs")
572 jalviewjsTransferSiteCoreDir = string("${jalviewjsBuildDir}/tmp/${jalviewjs_site_dir}_core")
573 jalviewjsJalviewCoreHtmlFile = string("")
574 jalviewjsJalviewCoreName = string(jalviewjs_core_name)
575 jalviewjsCoreClasslists = []
576 jalviewjsJalviewTemplateName = string(jalviewjs_name)
577 jalviewjsJ2sSettingsFileName = string("${jalviewDir}/${jalviewjs_j2s_settings}")
578 jalviewjsJ2sAltSettingsFileName = string("${jalviewDir}/${jalviewjs_j2s_alt_settings}")
579 jalviewjsJ2sProps = null
580 jalviewjsJ2sPlugin = jalviewjs_j2s_plugin
581 jalviewjsStderrLaunchFilename = "${jalviewjsSiteDir}/"+(file(jalviewjs_stderr_launch).getName())
583 eclipseWorkspace = null
584 eclipseBinary = string("")
585 eclipseVersion = string("")
588 jalviewjsChromiumUserDir = "${jalviewjsBuildDir}/${jalviewjs_chromium_user_dir}"
589 jalviewjsChromiumProfileDir = "${ext.jalviewjsChromiumUserDir}/${jalviewjs_chromium_profile_name}"
599 outputDir = file(classesDir)
603 srcDirs = [ resourcesBuildDir, docBuildDir, helpBuildDir ]
606 compileClasspath = files(sourceSets.main.java.outputDir)
607 compileClasspath += fileTree(dir: "${jalviewDir}/${libDir}", include: ["*.jar"])
609 runtimeClasspath = compileClasspath
610 runtimeClasspath += files(sourceSets.main.resources.srcDirs)
615 srcDirs cloverInstrDir
616 outputDir = cloverClassesDir
620 srcDirs = sourceSets.main.resources.srcDirs
623 compileClasspath = files( sourceSets.clover.java.outputDir )
624 //compileClasspath += files( testClassesDir )
625 compileClasspath += fileTree(dir: "${jalviewDir}/${libDir}", include: ["*.jar"])
626 compileClasspath += fileTree(dir: "${jalviewDir}/${clover_lib_dir}", include: ["*.jar"])
627 compileClasspath += fileTree(dir: "${jalviewDir}/${utils_dir}/testnglibs", include: ["**/*.jar"])
629 runtimeClasspath = compileClasspath
634 srcDirs testSourceDir
635 outputDir = file(testClassesDir)
639 srcDirs = useClover ? sourceSets.clover.resources.srcDirs : sourceSets.main.resources.srcDirs
642 compileClasspath = files( sourceSets.test.java.outputDir )
643 compileClasspath += useClover ? sourceSets.clover.compileClasspath : sourceSets.main.compileClasspath
644 compileClasspath += fileTree(dir: "${jalviewDir}/${utils_dir}/testnglibs", include: ["**/*.jar"])
646 runtimeClasspath = compileClasspath
647 runtimeClasspath += files(sourceSets.test.resources.srcDirs)
653 // eclipse project and settings files creation, also used by buildship
656 name = eclipse_project_name
658 natures 'org.eclipse.jdt.core.javanature',
659 'org.eclipse.jdt.groovy.core.groovyNature',
660 'org.eclipse.buildship.core.gradleprojectnature'
662 buildCommand 'org.eclipse.jdt.core.javabuilder'
663 buildCommand 'org.eclipse.buildship.core.gradleprojectbuilder'
667 //defaultOutputDir = sourceSets.main.java.outputDir
668 configurations.each{ c->
669 if (c.isCanBeResolved()) {
670 minusConfigurations += [c]
674 plusConfigurations = [ ]
678 def removeTheseToo = []
679 HashMap<String, Boolean> alreadyAddedSrcPath = new HashMap<>();
680 cp.entries.each { entry ->
681 // This conditional removes all src classpathentries that a) have already been added or b) aren't "src" or "test".
682 // e.g. this removes the resources dir being copied into bin/main, bin/test AND bin/clover
683 // we add the resources and help/help dirs in as libs afterwards (see below)
684 if (entry.kind == 'src') {
685 if (alreadyAddedSrcPath.getAt(entry.path) || !(entry.path == bareSourceDir || entry.path == bareTestSourceDir)) {
686 removeTheseToo += entry
688 alreadyAddedSrcPath.putAt(entry.path, true)
693 cp.entries.removeAll(removeTheseToo)
695 //cp.entries += new Output("${eclipse_bin_dir}/main")
696 if (file(helpParentDir).isDirectory()) {
697 cp.entries += new Library(fileReference(helpParentDir))
699 if (file(resourceDir).isDirectory()) {
700 cp.entries += new Library(fileReference(resourceDir))
703 HashMap<String, Boolean> alreadyAddedLibPath = new HashMap<>();
705 sourceSets.main.compileClasspath.findAll { it.name.endsWith(".jar") }.any {
706 //don't want to add outputDir as eclipse is using its own output dir in bin/main
707 if (it.isDirectory() || ! it.exists()) {
708 // don't add dirs to classpath, especially if they don't exist
709 return false // groovy "continue" in .any closure
711 def itPath = it.toString()
712 if (itPath.startsWith("${jalviewDirAbsolutePath}/")) {
713 // make relative path
714 itPath = itPath.substring(jalviewDirAbsolutePath.length()+1)
716 if (alreadyAddedLibPath.get(itPath)) {
717 //println("Not adding duplicate entry "+itPath)
719 //println("Adding entry "+itPath)
720 cp.entries += new Library(fileReference(itPath))
721 alreadyAddedLibPath.put(itPath, true)
725 sourceSets.test.compileClasspath.findAll { it.name.endsWith(".jar") }.any {
726 //no longer want to add outputDir as eclipse is using its own output dir in bin/main
727 if (it.isDirectory() || ! it.exists()) {
728 // don't add dirs to classpath
729 return false // groovy "continue" in .any closure
732 def itPath = it.toString()
733 if (itPath.startsWith("${jalviewDirAbsolutePath}/")) {
734 itPath = itPath.substring(jalviewDirAbsolutePath.length()+1)
736 if (alreadyAddedLibPath.get(itPath)) {
739 def lib = new Library(fileReference(itPath))
740 lib.entryAttributes["test"] = "true"
742 alreadyAddedLibPath.put(itPath, true)
750 containers 'org.eclipse.buildship.core.gradleclasspathcontainer'
755 // for the IDE, use java 11 compatibility
756 sourceCompatibility = compile_source_compatibility
757 targetCompatibility = compile_target_compatibility
758 javaRuntimeName = eclipseJavaRuntimeName
760 // add in jalview project specific properties/preferences into eclipse core preferences
762 withProperties { props ->
763 def jalview_prefs = new Properties()
764 def ins = new FileInputStream("${jalviewDirAbsolutePath}/${eclipse_extra_jdt_prefs_file}")
765 jalview_prefs.load(ins)
767 jalview_prefs.forEach { t, v ->
768 if (props.getAt(t) == null) {
772 // codestyle file -- overrides previous formatter prefs
773 def csFile = file("${jalviewDirAbsolutePath}/${eclipse_codestyle_file}")
774 if (csFile.exists()) {
775 XmlParser parser = new XmlParser()
776 def profiles = parser.parse(csFile)
777 def profile = profiles.'profile'.find { p -> (p.'@kind' == "CodeFormatterProfile" && p.'@name' == "Jalview") }
778 if (profile != null) {
779 profile.'setting'.each { s ->
781 def value = s.'@value'
782 if (id != null && value != null) {
783 props.putAt(id, value)
794 // Don't want these to be activated if in headless build
795 synchronizationTasks "eclipseSynchronizationTask"
796 //autoBuildTasks "eclipseAutoBuildTask"
802 /* hack to change eclipse prefs in .settings files other than org.eclipse.jdt.core.prefs */
803 // Class to allow updating arbitrary properties files
804 class PropertiesFile extends PropertiesPersistableConfigurationObject {
805 public PropertiesFile(PropertiesTransformer t) { super(t); }
806 @Override protected void load(Properties properties) { }
807 @Override protected void store(Properties properties) { }
808 @Override protected String getDefaultResourceName() { return ""; }
809 // This is necessary, because PropertiesPersistableConfigurationObject fails
810 // if no default properties file exists.
811 @Override public void loadDefaults() { load(new StringBufferInputStream("")); }
814 // Task to update arbitrary properties files (set outputFile)
815 class PropertiesFileTask extends PropertiesGeneratorTask<PropertiesFile> {
816 private final PropertiesFileContentMerger file;
817 public PropertiesFileTask() { file = new PropertiesFileContentMerger(getTransformer()); }
818 protected PropertiesFile create() { return new PropertiesFile(getTransformer()); }
819 protected void configure(PropertiesFile props) {
820 file.getBeforeMerged().execute(props); file.getWhenMerged().execute(props);
822 public void file(Closure closure) { ConfigureUtil.configure(closure, file); }
825 task eclipseUIPreferences(type: PropertiesFileTask) {
826 description = "Generate Eclipse additional settings"
827 def filename = "org.eclipse.jdt.ui.prefs"
828 outputFile = "$projectDir/.settings/${filename}" as File
831 it.load new FileInputStream("$projectDir/utils/eclipse/${filename}" as String)
836 task eclipseGroovyCorePreferences(type: PropertiesFileTask) {
837 description = "Generate Eclipse additional settings"
838 def filename = "org.eclipse.jdt.groovy.core.prefs"
839 outputFile = "$projectDir/.settings/${filename}" as File
842 it.load new FileInputStream("$projectDir/utils/eclipse/${filename}" as String)
847 task eclipseAllPreferences {
849 dependsOn eclipseUIPreferences
850 dependsOn eclipseGroovyCorePreferences
853 eclipseUIPreferences.mustRunAfter eclipseJdt
854 eclipseGroovyCorePreferences.mustRunAfter eclipseJdt
856 /* end of eclipse preferences hack */
864 delete cloverBuildDir
865 delete cloverReportDir
870 task cloverInstrJava(type: JavaExec) {
871 group = "Verification"
872 description = "Create clover instrumented source java files"
874 dependsOn cleanClover
876 inputs.files(sourceSets.main.allJava)
877 outputs.dir(cloverInstrDir)
879 //classpath = fileTree(dir: "${jalviewDir}/${clover_lib_dir}", include: ["*.jar"])
880 classpath = sourceSets.clover.compileClasspath
881 main = "com.atlassian.clover.CloverInstr"
889 cloverInstrDir.getPath(),
891 def srcFiles = sourceSets.main.allJava.files
894 { file -> file.absolutePath }
897 args argsList.toArray()
900 delete cloverInstrDir
901 println("Clover: About to instrument "+srcFiles.size() +" files")
906 task cloverInstrTests(type: JavaExec) {
907 group = "Verification"
908 description = "Create clover instrumented source test files"
910 dependsOn cleanClover
912 inputs.files(testDir)
913 outputs.dir(cloverTestInstrDir)
915 classpath = sourceSets.clover.compileClasspath
916 main = "com.atlassian.clover.CloverInstr"
926 cloverTestInstrDir.getPath(),
928 args argsList.toArray()
931 delete cloverTestInstrDir
932 println("Clover: About to instrument test files")
938 group = "Verification"
939 description = "Create clover instrumented all source files"
941 dependsOn cloverInstrJava
942 dependsOn cloverInstrTests
946 cloverClasses.dependsOn cloverInstr
949 task cloverConsoleReport(type: JavaExec) {
950 group = "Verification"
951 description = "Creates clover console report"
954 file(cloverDb).exists()
957 inputs.dir cloverClassesDir
959 classpath = sourceSets.clover.runtimeClasspath
960 main = "com.atlassian.clover.reporters.console.ConsoleReporter"
962 if (cloverreport_mem.length() > 0) {
963 maxHeapSize = cloverreport_mem
965 if (cloverreport_jvmargs.length() > 0) {
966 jvmArgs Arrays.asList(cloverreport_jvmargs.split(" "))
976 args argsList.toArray()
980 task cloverHtmlReport(type: JavaExec) {
981 group = "Verification"
982 description = "Creates clover HTML report"
985 file(cloverDb).exists()
988 def cloverHtmlDir = cloverReportDir
989 inputs.dir cloverClassesDir
990 outputs.dir cloverHtmlDir
992 classpath = sourceSets.clover.runtimeClasspath
993 main = "com.atlassian.clover.reporters.html.HtmlReporter"
995 if (cloverreport_mem.length() > 0) {
996 maxHeapSize = cloverreport_mem
998 if (cloverreport_jvmargs.length() > 0) {
999 jvmArgs Arrays.asList(cloverreport_jvmargs.split(" "))
1010 if (cloverreport_html_options.length() > 0) {
1011 argsList += cloverreport_html_options.split(" ")
1014 args argsList.toArray()
1018 task cloverXmlReport(type: JavaExec) {
1019 group = "Verification"
1020 description = "Creates clover XML report"
1023 file(cloverDb).exists()
1026 def cloverXmlFile = "${cloverReportDir}/clover.xml"
1027 inputs.dir cloverClassesDir
1028 outputs.file cloverXmlFile
1030 classpath = sourceSets.clover.runtimeClasspath
1031 main = "com.atlassian.clover.reporters.xml.XMLReporter"
1033 if (cloverreport_mem.length() > 0) {
1034 maxHeapSize = cloverreport_mem
1036 if (cloverreport_jvmargs.length() > 0) {
1037 jvmArgs Arrays.asList(cloverreport_jvmargs.split(" "))
1048 if (cloverreport_xml_options.length() > 0) {
1049 argsList += cloverreport_xml_options.split(" ")
1052 args argsList.toArray()
1057 group = "Verification"
1058 description = "Creates clover reports"
1060 dependsOn cloverXmlReport
1061 dependsOn cloverHtmlReport
1068 sourceCompatibility = compile_source_compatibility
1069 targetCompatibility = compile_target_compatibility
1070 options.compilerArgs += additional_compiler_args
1071 print ("Setting target compatibility to "+targetCompatibility+"\n")
1073 //classpath += configurations.cloverRuntime
1079 // JBP->BS should the print statement in doFirst refer to compile_target_compatibility ?
1080 sourceCompatibility = compile_source_compatibility
1081 targetCompatibility = compile_target_compatibility
1082 options.compilerArgs += additional_compiler_args
1083 options.encoding = "UTF-8"
1085 print ("Setting target compatibility to "+compile_target_compatibility+"\n")
1092 sourceCompatibility = compile_source_compatibility
1093 targetCompatibility = compile_target_compatibility
1094 options.compilerArgs += additional_compiler_args
1096 print ("Setting target compatibility to "+targetCompatibility+"\n")
1103 delete sourceSets.main.java.outputDir
1109 dependsOn cleanClover
1111 delete sourceSets.test.java.outputDir
1116 // format is a string like date.format("dd MMMM yyyy")
1117 def getDate(format) {
1118 return date.format(format)
1122 def convertMdToHtml (FileTree mdFiles, File cssFile) {
1123 MutableDataSet options = new MutableDataSet()
1125 def extensions = new ArrayList<>()
1126 extensions.add(AnchorLinkExtension.create())
1127 extensions.add(AutolinkExtension.create())
1128 extensions.add(StrikethroughExtension.create())
1129 extensions.add(TaskListExtension.create())
1130 extensions.add(TablesExtension.create())
1131 extensions.add(TocExtension.create())
1133 options.set(Parser.EXTENSIONS, extensions)
1135 // set GFM table parsing options
1136 options.set(TablesExtension.WITH_CAPTION, false)
1137 options.set(TablesExtension.COLUMN_SPANS, false)
1138 options.set(TablesExtension.MIN_HEADER_ROWS, 1)
1139 options.set(TablesExtension.MAX_HEADER_ROWS, 1)
1140 options.set(TablesExtension.APPEND_MISSING_COLUMNS, true)
1141 options.set(TablesExtension.DISCARD_EXTRA_COLUMNS, true)
1142 options.set(TablesExtension.HEADER_SEPARATOR_COLUMN_MATCH, true)
1144 options.set(AnchorLinkExtension.ANCHORLINKS_SET_ID, false)
1145 options.set(AnchorLinkExtension.ANCHORLINKS_ANCHOR_CLASS, "anchor")
1146 options.set(AnchorLinkExtension.ANCHORLINKS_SET_NAME, true)
1147 options.set(AnchorLinkExtension.ANCHORLINKS_TEXT_PREFIX, "<span class=\"octicon octicon-link\"></span>")
1149 Parser parser = Parser.builder(options).build()
1150 HtmlRenderer renderer = HtmlRenderer.builder(options).build()
1152 mdFiles.each { mdFile ->
1153 // add table of contents
1154 def mdText = "[TOC]\n"+mdFile.text
1156 // grab the first top-level title
1158 def titleRegex = /(?m)^#(\s+|([^#]))(.*)/
1159 def matcher = mdText =~ titleRegex
1160 if (matcher.size() > 0) {
1161 // matcher[0][2] is the first character of the title if there wasn't any whitespace after the #
1162 title = (matcher[0][2] != null ? matcher[0][2] : "")+matcher[0][3]
1164 // or use the filename if none found
1165 if (title == null) {
1166 title = mdFile.getName()
1169 Node document = parser.parse(mdText)
1170 String htmlBody = renderer.render(document)
1171 def htmlText = '''<html>
1172 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
1173 <html xmlns="http://www.w3.org/1999/xhtml">
1175 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
1176 <meta http-equiv="Content-Style-Type" content="text/css" />
1177 <meta name="generator" content="flexmark" />
1179 htmlText += ((title != null) ? " <title>${title}</title>" : '' )
1181 <style type="text/css">code{white-space: pre;}</style>
1183 htmlText += ((cssFile != null) ? cssFile.text : '')
1184 htmlText += '''</head>
1187 htmlText += htmlBody
1193 def htmlFilePath = mdFile.getPath().replaceAll(/\..*?$/, ".html")
1194 def htmlFile = file(htmlFilePath)
1195 println("Creating ${htmlFilePath}")
1196 htmlFile.text = htmlText
1201 task copyDocs(type: Copy) {
1202 def inputDir = "${jalviewDir}/${doc_dir}"
1203 def outputDir = "${docBuildDir}/${doc_dir}"
1207 include('**/*.html')
1209 filter(ReplaceTokens,
1213 'Version-Rel': JALVIEW_VERSION,
1214 'Year-Rel': getDate("yyyy")
1221 exclude('**/*.html')
1226 inputs.dir(inputDir)
1227 outputs.dir(outputDir)
1231 task convertMdFiles {
1233 def mdFiles = fileTree(dir: docBuildDir, include: "**/*.md")
1234 def cssFile = file("${jalviewDir}/${flexmark_css}")
1237 convertMdToHtml(mdFiles, cssFile)
1240 inputs.files(mdFiles)
1241 inputs.file(cssFile)
1244 mdFiles.each { mdFile ->
1245 def htmlFilePath = mdFile.getPath().replaceAll(/\..*?$/, ".html")
1246 htmlFiles.add(file(htmlFilePath))
1248 outputs.files(htmlFiles)
1252 def hugoTemplateSubstitutions(String input, Map extras=null) {
1253 def replacements = [
1254 DATE: getDate("yyyy-MM-dd"),
1255 CHANNEL: propertiesChannelName,
1256 APPLICATION_NAME: applicationName,
1258 GIT_BRANCH: gitBranch,
1259 VERSION: JALVIEW_VERSION,
1260 JAVA_VERSION: JAVA_VERSION,
1261 VERSION_UNDERSCORES: JALVIEW_VERSION_UNDERSCORES,
1266 if (extras != null) {
1267 extras.each{ k, v ->
1268 output = output.replaceAll("__${k}__", ((v == null)?"":v))
1271 replacements.each{ k, v ->
1272 output = output.replaceAll("__${k}__", ((v == null)?"":v))
1277 def mdFileComponents(File mdFile, def dateOnly=false) {
1280 if (mdFile.exists()) {
1281 def inFrontMatter = false
1282 def firstLine = true
1283 mdFile.eachLine { line ->
1284 if (line.matches("---")) {
1285 def prev = inFrontMatter
1286 inFrontMatter = firstLine
1287 if (inFrontMatter != prev)
1290 if (inFrontMatter) {
1292 if (m = line =~ /^date:\s*(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})/) {
1293 map["date"] = new Date().parse("yyyy-MM-dd HH:mm:ss", m[0][1])
1294 } else if (m = line =~ /^date:\s*(\d{4}-\d{2}-\d{2})/) {
1295 map["date"] = new Date().parse("yyyy-MM-dd", m[0][1])
1296 } else if (m = line =~ /^channel:\s*(\S+)/) {
1297 map["channel"] = m[0][1]
1298 } else if (m = line =~ /^version:\s*(\S+)/) {
1299 map["version"] = m[0][1]
1300 } else if (m = line =~ /^\s*([^:]+)\s*:\s*(\S.*)/) {
1301 map[ m[0][1] ] = m[0][2]
1303 if (dateOnly && map["date"] != null) {
1309 content += line+"\n"
1314 return dateOnly ? map["date"] : [map, content]
1317 task hugoTemplates {
1319 description "Create partially populated md pages for hugo website build"
1321 def hugoTemplatesDir = file("${jalviewDir}/${hugo_templates_dir}")
1322 def hugoBuildDir = "${jalviewDir}/${hugo_build_dir}"
1323 def templateFiles = fileTree(dir: hugoTemplatesDir)
1324 def releaseMdFile = file("${jalviewDir}/${releases_dir}/release-${JALVIEW_VERSION_UNDERSCORES}.md")
1325 def whatsnewMdFile = file("${jalviewDir}/${whatsnew_dir}/whatsnew-${JALVIEW_VERSION_UNDERSCORES}.md")
1326 def oldJvlFile = file("${jalviewDir}/${hugo_old_jvl}")
1327 def jalviewjsFile = file("${jalviewDir}/${hugo_jalviewjs}")
1330 // specific release template for version archive
1333 def givenDate = null
1334 def givenChannel = null
1335 def givenVersion = null
1336 if (CHANNEL == "RELEASE") {
1337 def (map, content) = mdFileComponents(releaseMdFile)
1338 givenDate = map.date
1339 givenChannel = map.channel
1340 givenVersion = map.version
1342 if (givenVersion != null && givenVersion != JALVIEW_VERSION) {
1343 throw new GradleException("'version' header (${givenVersion}) found in ${releaseMdFile} does not match JALVIEW_VERSION (${JALVIEW_VERSION})")
1346 if (whatsnewMdFile.exists())
1347 whatsnew = whatsnewMdFile.text
1350 def oldJvl = oldJvlFile.exists() ? oldJvlFile.collect{it} : []
1351 def jalviewjsLink = jalviewjsFile.exists() ? jalviewjsFile.collect{it} : []
1353 def changesHugo = null
1354 if (changes != null) {
1355 changesHugo = '<div class="release_notes">\n\n'
1356 def inSection = false
1357 changes.eachLine { line ->
1359 if (m = line =~ /^##([^#].*)$/) {
1361 changesHugo += "</div>\n\n"
1363 def section = m[0][1].trim()
1364 section = section.toLowerCase()
1365 section = section.replaceAll(/ +/, "_")
1366 section = section.replaceAll(/[^a-z0-9_\-]/, "")
1367 changesHugo += "<div class=\"${section}\">\n\n"
1369 } else if (m = line =~ /^(\s*-\s*)<!--([^>]+)-->(.*?)(<br\/?>)?\s*$/) {
1370 def comment = m[0][2].trim()
1371 if (comment != "") {
1372 comment = comment.replaceAll('"', """)
1374 comment.eachMatch(/JAL-\d+/) { jal -> issuekeys += jal }
1375 def newline = m[0][1]
1376 if (comment.trim() != "")
1377 newline += "{{<comment>}}${comment}{{</comment>}} "
1378 newline += m[0][3].trim()
1379 if (issuekeys.size() > 0)
1380 newline += " {{< jal issue=\"${issuekeys.join(",")}\" alt=\"${comment}\" >}}"
1381 if (m[0][4] != null)
1386 changesHugo += line+"\n"
1389 changesHugo += "\n</div>\n\n"
1391 changesHugo += '</div>'
1394 templateFiles.each{ templateFile ->
1395 def newFileName = string(hugoTemplateSubstitutions(templateFile.getName()))
1396 def relPath = hugoTemplatesDir.toPath().relativize(templateFile.toPath()).getParent()
1397 def newRelPathName = hugoTemplateSubstitutions( relPath.toString() )
1399 def outPathName = string("${hugoBuildDir}/$newRelPathName")
1403 rename(templateFile.getName(), newFileName)
1407 def newFile = file("${outPathName}/${newFileName}".toString())
1408 def content = newFile.text
1409 newFile.text = hugoTemplateSubstitutions(content,
1412 CHANGES: changesHugo,
1413 DATE: givenDate == null ? "" : givenDate.format("yyyy-MM-dd"),
1414 DRAFT: givenDate == null ? "true" : "false",
1415 JALVIEWJSLINK: jalviewjsLink.contains(JALVIEW_VERSION) ? "true" : "false",
1416 JVL_HEADER: oldJvl.contains(JALVIEW_VERSION) ? "jvl: true" : ""
1423 inputs.file(oldJvlFile)
1424 inputs.dir(hugoTemplatesDir)
1425 inputs.property("JALVIEW_VERSION", { JALVIEW_VERSION })
1426 inputs.property("CHANNEL", { CHANNEL })
1429 def getMdDate(File mdFile) {
1430 return mdFileComponents(mdFile, true)
1433 def getMdSections(String content) {
1435 def sectionContent = ""
1436 def sectionName = null
1437 content.eachLine { line ->
1439 if (m = line =~ /^##([^#].*)$/) {
1440 if (sectionName != null) {
1441 sections[sectionName] = sectionContent
1445 sectionName = m[0][1].trim()
1446 sectionName = sectionName.toLowerCase()
1447 sectionName = sectionName.replaceAll(/ +/, "_")
1448 sectionName = sectionName.replaceAll(/[^a-z0-9_\-]/, "")
1449 } else if (sectionName != null) {
1450 sectionContent += line+"\n"
1453 if (sectionContent != null) {
1454 sections[sectionName] = sectionContent
1460 task copyHelp(type: Copy) {
1461 def inputDir = helpSourceDir
1462 def outputDir = "${helpBuildDir}/${help_dir}"
1466 include('**/*.html')
1470 filter(ReplaceTokens,
1474 'Version-Rel': JALVIEW_VERSION,
1475 'Year-Rel': getDate("yyyy")
1482 exclude('**/*.html')
1489 inputs.dir(inputDir)
1490 outputs.files(helpFile)
1491 outputs.dir(outputDir)
1495 task releasesTemplates {
1497 description "Recreate whatsNew.html and releases.html from markdown files and templates in help"
1501 def releasesTemplateFile = file("${jalviewDir}/${releases_template}")
1502 def whatsnewTemplateFile = file("${jalviewDir}/${whatsnew_template}")
1503 def releasesHtmlFile = file("${helpBuildDir}/${help_dir}/${releases_html}")
1504 def whatsnewHtmlFile = file("${helpBuildDir}/${help_dir}/${whatsnew_html}")
1505 def releasesMdDir = "${jalviewDir}/${releases_dir}"
1506 def whatsnewMdDir = "${jalviewDir}/${whatsnew_dir}"
1509 def releaseMdFile = file("${releasesMdDir}/release-${JALVIEW_VERSION_UNDERSCORES}.md")
1510 def whatsnewMdFile = file("${whatsnewMdDir}/whatsnew-${JALVIEW_VERSION_UNDERSCORES}.md")
1512 if (CHANNEL == "RELEASE") {
1513 if (!releaseMdFile.exists()) {
1514 throw new GradleException("File ${releaseMdFile} must be created for RELEASE")
1516 if (!whatsnewMdFile.exists()) {
1517 throw new GradleException("File ${whatsnewMdFile} must be created for RELEASE")
1521 def releaseFiles = fileTree(dir: releasesMdDir, include: "release-*.md")
1522 def releaseFilesDates = releaseFiles.collectEntries {
1523 [(it): getMdDate(it)]
1525 releaseFiles = releaseFiles.sort { a,b -> releaseFilesDates[a].compareTo(releaseFilesDates[b]) }
1527 def releasesTemplate = releasesTemplateFile.text
1528 def m = releasesTemplate =~ /(?s)__VERSION_LOOP_START__(.*)__VERSION_LOOP_END__/
1529 def versionTemplate = m[0][1]
1531 MutableDataSet options = new MutableDataSet()
1533 def extensions = new ArrayList<>()
1534 options.set(Parser.EXTENSIONS, extensions)
1535 options.set(Parser.HTML_BLOCK_COMMENT_ONLY_FULL_LINE, true)
1537 Parser parser = Parser.builder(options).build()
1538 HtmlRenderer renderer = HtmlRenderer.builder(options).build()
1540 def actualVersions = releaseFiles.collect { rf ->
1541 def (rfMap, rfContent) = mdFileComponents(rf)
1542 return rfMap.version
1544 def versionsHtml = ""
1545 def linkedVersions = []
1546 releaseFiles.reverse().each { rFile ->
1547 def (rMap, rContent) = mdFileComponents(rFile)
1549 def versionLink = ""
1550 def partialVersion = ""
1551 def firstPart = true
1552 rMap.version.split("\\.").each { part ->
1553 def displayPart = ( firstPart ? "" : "." ) + part
1554 partialVersion += displayPart
1556 linkedVersions.contains(partialVersion)
1557 || ( actualVersions.contains(partialVersion) && partialVersion != rMap.version )
1559 versionLink += displayPart
1561 versionLink += "<a id=\"Jalview.${partialVersion}\">${displayPart}</a>"
1562 linkedVersions += partialVersion
1566 def displayDate = releaseFilesDates[rFile].format("dd/MM/yyyy")
1569 def rContentProcessed = ""
1570 rContent.eachLine { line ->
1571 if (lm = line =~ /^(\s*-)(\s*<!--[^>]*?-->)(.*)$/) {
1572 line = "${lm[0][1]}${lm[0][3]}${lm[0][2]}"
1573 } else if (lm = line =~ /^###([^#]+.*)$/) {
1574 line = "_${lm[0][1].trim()}_"
1576 rContentProcessed += line + "\n"
1579 def rContentSections = getMdSections(rContentProcessed)
1580 def rVersion = versionTemplate
1581 if (rVersion != "") {
1582 def rNewFeatures = rContentSections["new_features"]
1583 def rIssuesResolved = rContentSections["issues_resolved"]
1584 Node newFeaturesNode = parser.parse(rNewFeatures)
1585 String newFeaturesHtml = renderer.render(newFeaturesNode)
1586 Node issuesResolvedNode = parser.parse(rIssuesResolved)
1587 String issuesResolvedHtml = renderer.render(issuesResolvedNode)
1588 rVersion = hugoTemplateSubstitutions(rVersion,
1590 VERSION: rMap.version,
1591 VERSION_LINK: versionLink,
1592 DISPLAY_DATE: displayDate,
1593 NEW_FEATURES: newFeaturesHtml,
1594 ISSUES_RESOLVED: issuesResolvedHtml
1597 versionsHtml += rVersion
1601 releasesTemplate = releasesTemplate.replaceAll("(?s)__VERSION_LOOP_START__.*__VERSION_LOOP_END__", versionsHtml)
1602 releasesTemplate = hugoTemplateSubstitutions(releasesTemplate)
1603 releasesHtmlFile.text = releasesTemplate
1605 if (whatsnewMdFile.exists()) {
1606 def wnDisplayDate = releaseFilesDates[releaseMdFile] != null ? releaseFilesDates[releaseMdFile].format("dd MMMM yyyy") : ""
1607 def whatsnewMd = hugoTemplateSubstitutions(whatsnewMdFile.text)
1608 Node whatsnewNode = parser.parse(whatsnewMd)
1609 String whatsnewHtml = renderer.render(whatsnewNode)
1610 whatsnewHtml = whatsnewTemplateFile.text.replaceAll("__WHATS_NEW__", whatsnewHtml)
1611 whatsnewHtmlFile.text = hugoTemplateSubstitutions(whatsnewHtml,
1613 VERSION: JALVIEW_VERSION,
1614 DISPLAY_DATE: wnDisplayDate
1617 } else if (gradle.taskGraph.hasTask(":linkCheck")) {
1618 whatsnewHtmlFile.text = "Development build " + getDate("yyyy-MM-dd HH:mm:ss")
1623 inputs.file(releasesTemplateFile)
1624 inputs.file(whatsnewTemplateFile)
1625 inputs.dir(releasesMdDir)
1626 inputs.dir(whatsnewMdDir)
1627 outputs.file(releasesHtmlFile)
1628 outputs.file(whatsnewHtmlFile)
1632 task copyResources(type: Copy) {
1634 description = "Copy (and make text substitutions in) the resources dir to the build area"
1636 def inputDir = resourceDir
1637 def outputDir = resourcesBuildDir
1641 include('**/*.html')
1643 filter(ReplaceTokens,
1647 'Version-Rel': JALVIEW_VERSION,
1648 'Year-Rel': getDate("yyyy")
1655 exclude('**/*.html')
1660 inputs.dir(inputDir)
1661 outputs.dir(outputDir)
1664 task copyChannelResources(type: Copy) {
1665 dependsOn copyResources
1667 description = "Copy the channel resources dir to the build resources area"
1669 def inputDir = "${channelDir}/${resource_dir}"
1670 def outputDir = resourcesBuildDir
1672 include(channel_props)
1673 filter(ReplaceTokens,
1677 'SUFFIX': channelSuffix
1682 exclude(channel_props)
1686 inputs.dir(inputDir)
1687 outputs.dir(outputDir)
1690 task createBuildProperties(type: WriteProperties) {
1691 dependsOn copyResources
1693 description = "Create the ${buildProperties} file"
1695 inputs.dir(sourceDir)
1696 inputs.dir(resourcesBuildDir)
1697 outputFile (buildProperties)
1698 // taking time specific comment out to allow better incremental builds
1699 comment "--Jalview Build Details--\n"+getDate("yyyy-MM-dd HH:mm:ss")
1700 //comment "--Jalview Build Details--\n"+getDate("yyyy-MM-dd")
1701 property "BUILD_DATE", getDate("HH:mm:ss dd MMMM yyyy")
1702 property "VERSION", JALVIEW_VERSION
1703 property "INSTALLATION", INSTALLATION+" git-commit:"+gitHash+" ["+gitBranch+"]"
1704 property "JAVA_COMPILE_VERSION", JAVA_INTEGER_VERSION
1705 if (getdownSetAppBaseProperty) {
1706 property "GETDOWNAPPBASE", getdownAppBase
1707 property "GETDOWNAPPDISTDIR", getdownAppDistDir
1709 outputs.file(outputFile)
1713 task buildIndices(type: JavaExec) {
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 compileJava.dependsOn prepare
1749 run.dependsOn compileJava
1750 compileTestJava.dependsOn compileJava
1755 group = "Verification"
1756 description = "Runs all testTaskN tasks)"
1759 dependsOn cloverClasses
1761 dependsOn testClasses
1764 // not running tests in this task
1767 /* testTask0 is the main test task */
1768 task testTask0(type: Test) {
1769 group = "Verification"
1770 description = "The main test task. Runs all non-testTaskN-labelled tests (unless excluded)"
1772 includeGroups testng_groups.split(",")
1773 excludeGroups testng_excluded_groups.split(",")
1774 tasks.withType(Test).matching {it.name.startsWith("testTask") && it.name != name}.all {t -> excludeGroups t.name}
1776 useDefaultListeners=true
1778 timeout = Duration.ofMinutes(15)
1781 /* separated tests */
1782 task testTask1(type: Test) {
1783 group = "Verification"
1784 description = "Tests that need to be isolated from the main test run"
1787 excludeGroups testng_excluded_groups.split(",")
1789 useDefaultListeners=true
1791 timeout = Duration.ofMinutes(5)
1794 task testTask2(type: Test) {
1795 group = "Verification"
1796 description = "Tests that need to be isolated from the main test run"
1799 excludeGroups testng_excluded_groups.split(",")
1801 useDefaultListeners=true
1803 timeout = Duration.ofMinutes(5)
1805 task testTask3(type: Test) {
1806 group = "Verification"
1807 description = "Tests that need to be isolated from the main test run"
1810 excludeGroups testng_excluded_groups.split(",")
1812 useDefaultListeners=true
1814 timeout = Duration.ofMinutes(5)
1817 /* insert more testTaskNs here -- change N to next digit or other string */
1819 task testTaskN(type: Test) {
1820 group = "Verification"
1821 description = "Tests that need to be isolated from the main test run"
1824 excludeGroups testng_excluded_groups.split(",")
1826 useDefaultListeners=true
1833 * adapted from https://medium.com/@wasyl/pretty-tests-summary-in-gradle-744804dd676c
1834 * to summarise test results from all Test tasks
1836 /* START of test tasks results summary */
1837 import groovy.time.TimeCategory
1838 import org.gradle.api.tasks.testing.logging.TestExceptionFormat
1839 import org.gradle.api.tasks.testing.logging.TestLogEvent
1840 rootProject.ext.testsResults = [] // Container for tests summaries
1842 tasks.withType(Test).matching {t -> t.getName().startsWith("testTask")}.all { testTask ->
1844 // from original test task
1846 dependsOn cloverClasses
1848 dependsOn testClasses //?
1851 // run main tests first
1852 if (!testTask.name.equals("testTask0"))
1853 testTask.mustRunAfter "testTask0"
1855 testTask.testLogging { logging ->
1856 events TestLogEvent.FAILED
1857 // TestLogEvent.SKIPPED,
1858 // TestLogEvent.STANDARD_OUT,
1859 // TestLogEvent.STANDARD_ERROR
1861 exceptionFormat TestExceptionFormat.FULL
1864 showStackTraces true
1866 showStandardStreams true
1868 info.events = [ TestLogEvent.FAILED ]
1871 if (OperatingSystem.current().isMacOsX()) {
1872 testTask.systemProperty "apple.awt.UIElement", "true"
1873 testTask.environment "JAVA_TOOL_OPTIONS", "-Dapple.awt.UIElement=true"
1877 ignoreFailures = true // Always try to run all tests for all modules
1879 afterSuite { desc, result ->
1881 return // Only summarize results for whole modules
1883 def resultsInfo = [testTask.project.name, testTask.name, result, TimeCategory.minus(new Date(result.endTime), new Date(result.startTime)), testTask.reports.html.entryPoint]
1885 rootProject.ext.testsResults.add(resultsInfo)
1888 // from original test task
1889 maxHeapSize = "1024m"
1891 workingDir = jalviewDir
1892 def testLaf = project.findProperty("test_laf")
1893 if (testLaf != null) {
1894 println("Setting Test LaF to '${testLaf}'")
1895 systemProperty "laf", testLaf
1897 def testHiDPIScale = project.findProperty("test_HiDPIScale")
1898 if (testHiDPIScale != null) {
1899 println("Setting Test HiDPI Scale to '${testHiDPIScale}'")
1900 systemProperty "sun.java2d.uiScale", testHiDPIScale
1902 sourceCompatibility = compile_source_compatibility
1903 targetCompatibility = compile_target_compatibility
1904 jvmArgs += additional_compiler_args
1907 // this is not perfect yet -- we should only add the commandLineIncludePatterns to the
1908 // testTasks that include the tests, and exclude all from the others.
1909 // get --test argument
1910 filter.commandLineIncludePatterns = test.filter.commandLineIncludePatterns
1911 // do something with testTask.getCandidateClassFiles() to see if the test should silently finish because of the
1912 // commandLineIncludePatterns not matching anything. Instead we are doing setFailOnNoMatchingTests(false) below
1916 println("Running tests " + (useClover?"WITH":"WITHOUT") + " clover")
1921 /* don't fail on no matching tests (so --tests will run across all testTasks) */
1922 testTask.filter.setFailOnNoMatchingTests(false)
1924 /* ensure the "test" task dependsOn all the testTasks */
1925 test.dependsOn testTask
1928 gradle.buildFinished {
1929 def allResults = rootProject.ext.testsResults
1931 if (!allResults.isEmpty()) {
1932 printResults allResults
1933 allResults.each {r ->
1934 if (r[2].resultType == TestResult.ResultType.FAILURE)
1935 throw new GradleException("Failed tests!")
1940 private static String colString(styler, col, colour, text) {
1941 return col?"${styler[colour](text)}":text
1944 private static String getSummaryLine(s, pn, tn, rt, rc, rs, rf, rsk, t, col) {
1945 def colour = 'black'
1953 case TestResult.ResultType.SUCCESS:
1956 case TestResult.ResultType.FAILURE:
1964 StringBuilder sb = new StringBuilder()
1968 sb.append(" results: ")
1969 sb.append(colString(s, col && !nocol, colour, text))
1971 sb.append("${rc} tests, ")
1972 sb.append(colString(s, col && rs > 0, 'green', rs))
1973 sb.append(" successes, ")
1974 sb.append(colString(s, col && rf > 0, 'red', rf))
1975 sb.append(" failures, ")
1976 sb.append("${rsk} skipped) in ${t}")
1977 return sb.toString()
1980 private static void printResults(allResults) {
1982 // styler from https://stackoverflow.com/a/56139852
1983 def styler = 'black red green yellow blue magenta cyan white'.split().toList().withIndex(30).collectEntries { key, val -> [(key) : { "\033[${val}m${it}\033[0m" }] }
1986 def failedTests = false
1987 def summaryLines = []
1989 def totalsuccess = 0
1992 def totaltime = TimeCategory.getSeconds(0)
1993 // sort on project name then task name
1994 allResults.sort {a, b -> a[0] == b[0]? a[1]<=>b[1]:a[0] <=> b[0]}.each {
1995 def projectName = it[0]
1996 def taskName = it[1]
2000 def summaryCol = getSummaryLine(styler, projectName, taskName, result.resultType, result.testCount, result.successfulTestCount, result.failedTestCount, result.skippedTestCount, time, true)
2001 def summaryPlain = getSummaryLine(styler, projectName, taskName, result.resultType, result.testCount, result.successfulTestCount, result.failedTestCount, result.skippedTestCount, time, false)
2002 def reportLine = "Report file: ${report}"
2003 def ls = summaryPlain.length()
2004 def lr = reportLine.length()
2005 def m = [ls, lr].max()
2008 def info = [ls, summaryCol, reportLine]
2009 summaryLines.add(info)
2010 failedTests |= result.resultType == TestResult.ResultType.FAILURE
2011 totalcount += result.testCount
2012 totalsuccess += result.successfulTestCount
2013 totalfail += result.failedTestCount
2014 totalskip += result.skippedTestCount
2017 def totalSummaryCol = getSummaryLine(styler, "OVERALL", "", failedTests?TestResult.ResultType.FAILURE:TestResult.ResultType.SUCCESS, totalcount, totalsuccess, totalfail, totalskip, totaltime, true)
2018 def totalSummaryPlain = getSummaryLine(styler, "OVERALL", "", failedTests?TestResult.ResultType.FAILURE:TestResult.ResultType.SUCCESS, totalcount, totalsuccess, totalfail, totalskip, totaltime, false)
2019 def tls = totalSummaryPlain.length()
2020 if (tls > maxLength)
2022 def info = [tls, totalSummaryCol, null]
2023 summaryLines.add(info)
2025 def allSummaries = []
2026 for(sInfo : summaryLines) {
2028 def summary = sInfo[1]
2029 def report = sInfo[2]
2031 StringBuilder sb = new StringBuilder()
2032 sb.append("│" + summary + " " * (maxLength - ls) + "│")
2033 if (report != null) {
2034 sb.append("\n│" + report + " " * (maxLength - report.length()) + "│")
2036 allSummaries += sb.toString()
2039 println "┌${"${"─" * maxLength}"}┐"
2040 println allSummaries.join("\n├${"${"─" * maxLength}"}┤\n")
2041 println "└${"${"─" * maxLength}"}┘"
2043 /* END of test tasks results summary */
2046 task compileLinkCheck(type: JavaCompile) {
2048 classpath = files("${jalviewDir}/${utils_dir}")
2049 destinationDir = file("${jalviewDir}/${utils_dir}")
2050 source = fileTree(dir: "${jalviewDir}/${utils_dir}", include: ["HelpLinksChecker.java", "BufferedLineReader.java"])
2052 inputs.file("${jalviewDir}/${utils_dir}/HelpLinksChecker.java")
2053 inputs.file("${jalviewDir}/${utils_dir}/HelpLinksChecker.java")
2054 outputs.file("${jalviewDir}/${utils_dir}/HelpLinksChecker.class")
2055 outputs.file("${jalviewDir}/${utils_dir}/BufferedLineReader.class")
2059 task linkCheck(type: JavaExec) {
2061 dependsOn compileLinkCheck
2063 def helpLinksCheckerOutFile = file("${jalviewDir}/${utils_dir}/HelpLinksChecker.out")
2064 classpath = files("${jalviewDir}/${utils_dir}")
2065 main = "HelpLinksChecker"
2066 workingDir = "${helpBuildDir}"
2067 args = [ "${helpBuildDir}/${help_dir}", "-nointernet" ]
2069 def outFOS = new FileOutputStream(helpLinksCheckerOutFile, false) // false == don't append
2070 standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
2073 errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
2077 inputs.dir(helpBuildDir)
2078 outputs.file(helpLinksCheckerOutFile)
2082 // import the pubhtmlhelp target
2083 ant.properties.basedir = "${jalviewDir}"
2084 ant.properties.helpBuildDir = "${helpBuildDir}/${help_dir}"
2085 ant.importBuild "${utils_dir}/publishHelp.xml"
2088 task cleanPackageDir(type: Delete) {
2090 delete fileTree(dir: "${jalviewDir}/${package_dir}", include: "*.jar")
2100 attributes "Main-Class": main_class,
2101 "Permissions": "all-permissions",
2102 "Application-Name": applicationName,
2103 "Codebase": application_codebase,
2104 "Implementation-Version": JALVIEW_VERSION
2107 def outputDir = "${jalviewDir}/${package_dir}"
2108 destinationDirectory = file(outputDir)
2109 archiveFileName = rootProject.name+".jar"
2110 duplicatesStrategy "EXCLUDE"
2117 exclude "**/*.jar.*"
2119 inputs.dir(sourceSets.main.java.outputDir)
2120 sourceSets.main.resources.srcDirs.each{ dir ->
2123 outputs.file("${outputDir}/${archiveFileName}")
2127 task copyJars(type: Copy) {
2128 from fileTree(dir: classesDir, include: "**/*.jar").files
2129 into "${jalviewDir}/${package_dir}"
2133 // doing a Sync instead of Copy as Copy doesn't deal with "outputs" very well
2134 task syncJars(type: Sync) {
2136 from fileTree(dir: "${jalviewDir}/${libDistDir}", include: "**/*.jar").files
2137 into "${jalviewDir}/${package_dir}"
2139 include jar.archiveFileName.getOrNull()
2146 description = "Put all required libraries in dist"
2147 // order of "cleanPackageDir", "copyJars", "jar" important!
2148 jar.mustRunAfter cleanPackageDir
2149 syncJars.mustRunAfter cleanPackageDir
2150 dependsOn cleanPackageDir
2153 outputs.dir("${jalviewDir}/${package_dir}")
2158 dependsOn cleanPackageDir
2164 task launcherJar(type: Jar) {
2167 "Main-Class": shadow_jar_main_class,
2168 "Implementation-Version": JALVIEW_VERSION,
2169 "Application-Name": applicationName
2175 group = "distribution"
2176 description = "Create a single jar file with all dependency libraries merged. Can be run with java -jar"
2181 def jarFiles = fileTree(dir: "${jalviewDir}/${libDistDir}", include: "*.jar", exclude: "regex.jar").getFiles()
2182 def groovyJars = jarFiles.findAll {it1 -> file(it1).getName().startsWith("groovy-swing")}
2183 def otherJars = jarFiles.findAll {it2 -> !file(it2).getName().startsWith("groovy-swing")}
2188 // shadowJar manifest must inheritFrom another Jar task. Can't set attributes here.
2189 inheritFrom(project.tasks.launcherJar.manifest)
2191 // we need to include the groovy-swing Include-Package for it to run in the shadowJar
2193 def jarFileManifests = []
2194 groovyJars.each { jarFile ->
2195 def mf = zipTree(jarFile).getFiles().find { it.getName().equals("MANIFEST.MF") }
2197 jarFileManifests += mf
2201 from (jarFileManifests) {
2202 eachEntry { details ->
2203 if (!details.key.equals("Import-Package")) {
2211 duplicatesStrategy "INCLUDE"
2213 // this mainClassName is mandatory but gets ignored due to manifest created in doFirst{}. Set the Main-Class as an attribute in launcherJar instead
2214 mainClassName = shadow_jar_main_class
2216 classifier = "all-"+JALVIEW_VERSION+"-j"+JAVA_VERSION
2220 task getdownImagesCopy() {
2221 inputs.dir getdownImagesDir
2222 outputs.dir getdownImagesBuildDir
2226 from(getdownImagesDir) {
2227 include("*getdown*.png")
2229 into getdownImagesBuildDir
2234 task getdownImagesProcess() {
2235 dependsOn getdownImagesCopy
2238 if (backgroundImageText) {
2239 if (convertBinary == null) {
2240 throw new StopExecutionException("No ImageMagick convert binary installed at '${convertBinaryExpectedLocation}'")
2242 if (!project.hasProperty("getdown_background_image_text_suffix_cmd")) {
2243 throw new StopExecutionException("No property 'getdown_background_image_text_suffix_cmd' defined. See channel_gradle.properties for channel ${CHANNEL}")
2245 fileTree(dir: getdownImagesBuildDir, include: "*background*.png").getFiles().each { file ->
2247 executable convertBinary
2250 '-font', getdown_background_image_text_font,
2251 '-fill', getdown_background_image_text_colour,
2252 '-draw', sprintf(getdown_background_image_text_suffix_cmd, channelSuffix),
2253 '-draw', sprintf(getdown_background_image_text_commit_cmd, "git-commit: ${gitHash}"),
2254 '-draw', sprintf(getdown_background_image_text_date_cmd, getDate("yyyy-MM-dd HH:mm:ss")),
2263 task getdownImages() {
2264 dependsOn getdownImagesProcess
2267 task getdownWebsiteBuild() {
2268 group = "distribution"
2269 description = "Create the getdown minimal app folder, and website folder for this version of jalview. Website folder also used for offline app installer. No digest is created."
2271 dependsOn getdownImages
2276 def getdownWebsiteResourceFilenames = []
2277 def getdownResourceDir = getdownResourceDir
2278 def getdownResourceFilenames = []
2281 // clean the getdown website and files dir before creating getdown folders
2282 delete getdownAppBaseDir
2283 delete getdownFilesDir
2286 from buildProperties
2287 rename(file(buildProperties).getName(), getdown_build_properties)
2290 getdownWebsiteResourceFilenames += "${getdownAppDistDir}/${getdown_build_properties}"
2293 from channelPropsFile
2294 filter(ReplaceTokens,
2298 'SUFFIX': channelSuffix
2301 into getdownAppBaseDir
2303 getdownWebsiteResourceFilenames += file(channelPropsFile).getName()
2305 // set some getdownTxt_ properties then go through all properties looking for getdownTxt_...
2306 def props = project.properties.sort { it.key }
2307 if (getdownAltJavaMinVersion != null && getdownAltJavaMinVersion.length() > 0) {
2308 props.put("getdown_txt_java_min_version", getdownAltJavaMinVersion)
2310 if (getdownAltJavaMaxVersion != null && getdownAltJavaMaxVersion.length() > 0) {
2311 props.put("getdown_txt_java_max_version", getdownAltJavaMaxVersion)
2313 if (getdownAltMultiJavaLocation != null && getdownAltMultiJavaLocation.length() > 0) {
2314 props.put("getdown_txt_multi_java_location", getdownAltMultiJavaLocation)
2316 if (getdownImagesBuildDir != null && file(getdownImagesBuildDir).exists()) {
2317 props.put("getdown_txt_ui.background_image", "${getdownImagesBuildDir}/${getdown_background_image}")
2318 props.put("getdown_txt_ui.instant_background_image", "${getdownImagesBuildDir}/${getdown_instant_background_image}")
2319 props.put("getdown_txt_ui.error_background", "${getdownImagesBuildDir}/${getdown_error_background}")
2320 props.put("getdown_txt_ui.progress_image", "${getdownImagesBuildDir}/${getdown_progress_image}")
2321 props.put("getdown_txt_ui.icon", "${getdownImagesDir}/${getdown_icon}")
2322 props.put("getdown_txt_ui.mac_dock_icon", "${getdownImagesDir}/${getdown_mac_dock_icon}")
2325 props.put("getdown_txt_title", jalview_name)
2326 props.put("getdown_txt_ui.name", applicationName)
2328 // start with appbase
2329 getdownTextLines += "appbase = ${getdownAppBase}"
2330 props.each{ prop, val ->
2331 if (prop.startsWith("getdown_txt_") && val != null) {
2332 if (prop.startsWith("getdown_txt_multi_")) {
2333 def key = prop.substring(18)
2334 val.split(",").each{ v ->
2335 def line = "${key} = ${v}"
2336 getdownTextLines += line
2339 // file values rationalised
2340 if (val.indexOf('/') > -1 || prop.startsWith("getdown_txt_resource")) {
2342 if (val.indexOf('/') == 0) {
2345 } else if (val.indexOf('/') > 0) {
2346 // relative path (relative to jalviewDir)
2347 r = file( "${jalviewDir}/${val}" )
2350 val = "${getdown_resource_dir}/" + r.getName()
2351 getdownWebsiteResourceFilenames += val
2352 getdownResourceFilenames += r.getPath()
2355 if (! prop.startsWith("getdown_txt_resource")) {
2356 def line = prop.substring(12) + " = ${val}"
2357 getdownTextLines += line
2363 getdownWebsiteResourceFilenames.each{ filename ->
2364 getdownTextLines += "resource = ${filename}"
2366 getdownResourceFilenames.each{ filename ->
2369 into getdownResourceDir
2373 def getdownWrapperScripts = [ getdown_bash_wrapper_script, getdown_powershell_wrapper_script, getdown_batch_wrapper_script ]
2374 getdownWrapperScripts.each{ script ->
2375 def s = file( "${jalviewDir}/utils/getdown/${getdown_wrapper_script_dir}/${script}" )
2379 into "${getdownAppBaseDir}/${getdown_wrapper_script_dir}"
2381 getdownTextLines += "xresource = ${getdown_wrapper_script_dir}/${script}"
2386 fileTree(file(package_dir)).each{ f ->
2387 if (f.isDirectory()) {
2388 def files = fileTree(dir: f, include: ["*"]).getFiles()
2390 } else if (f.exists()) {
2394 def jalviewJar = jar.archiveFileName.getOrNull()
2395 // put jalview.jar first for CLASSPATH and .properties files reasons
2396 codeFiles.sort{a, b -> ( a.getName() == jalviewJar ? -1 : ( b.getName() == jalviewJar ? 1 : a <=> b ) ) }.each{f ->
2397 def name = f.getName()
2398 def line = "code = ${getdownAppDistDir}/${name}"
2399 getdownTextLines += line
2406 // NOT USING MODULES YET, EVERYTHING SHOULD BE IN dist
2408 if (JAVA_VERSION.equals("11")) {
2409 def j11libFiles = fileTree(dir: "${jalviewDir}/${j11libDir}", include: ["*.jar"]).getFiles()
2410 j11libFiles.sort().each{f ->
2411 def name = f.getName()
2412 def line = "code = ${getdown_j11lib_dir}/${name}"
2413 getdownTextLines += line
2416 into getdownJ11libDir
2422 // 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.
2423 //getdownTextLines += "class = " + file(getdownLauncher).getName()
2424 getdownTextLines += "resource = ${getdown_launcher_new}"
2425 getdownTextLines += "class = ${main_class}"
2426 // Not setting these properties in general so that getdownappbase and getdowndistdir will default to release version in jalview.bin.Cache
2427 if (getdownSetAppBaseProperty) {
2428 getdownTextLines += "jvmarg = -Dgetdowndistdir=${getdownAppDistDir}"
2429 getdownTextLines += "jvmarg = -Dgetdownappbase=${getdownAppBase}"
2432 def getdownTxt = file("${getdownAppBaseDir}/getdown.txt")
2433 getdownTxt.write(getdownTextLines.join("\n"))
2435 getdownLaunchJvl = getdown_launch_jvl_name + ( (jvlChannelName != null && jvlChannelName.length() > 0)?"-${jvlChannelName}":"" ) + ".jvl"
2436 def launchJvl = file("${getdownAppBaseDir}/${getdownLaunchJvl}")
2437 launchJvl.write("appbase=${getdownAppBase}")
2439 // files going into the getdown website dir: getdown-launcher.jar
2441 from getdownLauncher
2442 rename(file(getdownLauncher).getName(), getdown_launcher_new)
2443 into getdownAppBaseDir
2446 // files going into the getdown website dir: getdown-launcher(-local).jar
2448 from getdownLauncher
2449 if (file(getdownLauncher).getName() != getdown_launcher) {
2450 rename(file(getdownLauncher).getName(), getdown_launcher)
2452 into getdownAppBaseDir
2455 // files going into the getdown website dir: ./install dir and files
2456 if (! (CHANNEL.startsWith("ARCHIVE") || CHANNEL.startsWith("DEVELOP"))) {
2459 from getdownLauncher
2460 from "${getdownAppDir}/${getdown_build_properties}"
2461 if (file(getdownLauncher).getName() != getdown_launcher) {
2462 rename(file(getdownLauncher).getName(), getdown_launcher)
2464 into getdownInstallDir
2467 // and make a copy in the getdown files dir (these are not downloaded by getdown)
2469 from getdownInstallDir
2470 into getdownFilesInstallDir
2474 // files going into the getdown files dir: getdown.txt, getdown-launcher.jar, channel-launch.jvl, build_properties
2478 from getdownLauncher
2479 from "${getdownAppBaseDir}/${getdown_build_properties}"
2480 from "${getdownAppBaseDir}/${channel_props}"
2481 if (file(getdownLauncher).getName() != getdown_launcher) {
2482 rename(file(getdownLauncher).getName(), getdown_launcher)
2484 into getdownFilesDir
2487 // and ./resource (not all downloaded by getdown)
2489 from getdownResourceDir
2490 into "${getdownFilesDir}/${getdown_resource_dir}"
2495 inputs.dir("${jalviewDir}/${package_dir}")
2497 outputs.dir(getdownAppBaseDir)
2498 outputs.dir(getdownFilesDir)
2502 // a helper task to allow getdown digest of any dir: `gradle getdownDigestDir -PDIGESTDIR=/path/to/my/random/getdown/dir
2503 task getdownDigestDir(type: JavaExec) {
2505 description "A task to run a getdown Digest on a dir with getdown.txt. Provide a DIGESTDIR property via -PDIGESTDIR=..."
2507 def digestDirPropertyName = "DIGESTDIR"
2509 classpath = files(getdownLauncher)
2510 def digestDir = findProperty(digestDirPropertyName)
2511 if (digestDir == null) {
2512 throw new GradleException("Must provide a DIGESTDIR value to produce an alternative getdown digest")
2516 main = "com.threerings.getdown.tools.Digester"
2520 task getdownDigest(type: JavaExec) {
2521 group = "distribution"
2522 description = "Digest the getdown website folder"
2524 dependsOn getdownWebsiteBuild
2527 classpath = files(getdownLauncher)
2529 main = "com.threerings.getdown.tools.Digester"
2530 args getdownAppBaseDir
2531 inputs.dir(getdownAppBaseDir)
2532 outputs.file("${getdownAppBaseDir}/digest2.txt")
2537 group = "distribution"
2538 description = "Create the minimal and full getdown app folder for installers and website and create digest file"
2539 dependsOn getdownDigest
2541 if (reportRsyncCommand) {
2542 def fromDir = getdownAppBaseDir + (getdownAppBaseDir.endsWith('/')?'':'/')
2543 def toDir = "${getdown_rsync_dest}/${getdownDir}" + (getdownDir.endsWith('/')?'':'/')
2544 println "LIKELY RSYNC COMMAND:"
2545 println "mkdir -p '$toDir'\nrsync -avh --delete '$fromDir' '$toDir'"
2546 if (RUNRSYNC == "true") {
2548 commandLine "mkdir", "-p", toDir
2551 commandLine "rsync", "-avh", "--delete", fromDir, toDir
2558 task getdownWebsite {
2559 group = "distribution"
2560 description = "A task to create the whole getdown channel website dir including digest file"
2562 dependsOn getdownWebsiteBuild
2563 dependsOn getdownDigest
2566 task getdownArchiveBuild() {
2567 group = "distribution"
2568 description = "Put files in the archive dir to go on the website"
2570 dependsOn getdownWebsiteBuild
2572 def v = "v${JALVIEW_VERSION_UNDERSCORES}"
2573 def vDir = "${getdownArchiveDir}/${v}"
2574 getdownFullArchiveDir = "${vDir}/getdown"
2575 getdownVersionLaunchJvl = "${vDir}/jalview-${v}.jvl"
2577 def vAltDir = "alt_${v}"
2578 def archiveImagesDir = "${jalviewDir}/${channel_properties_dir}/old/images"
2581 // cleanup old "old" dir
2582 delete getdownArchiveDir
2584 def getdownArchiveTxt = file("${getdownFullArchiveDir}/getdown.txt")
2585 getdownArchiveTxt.getParentFile().mkdirs()
2586 def getdownArchiveTextLines = []
2587 def getdownFullArchiveAppBase = "${getdownArchiveAppBase}${getdownArchiveAppBase.endsWith("/")?"":"/"}${v}/getdown/"
2591 from "${getdownAppBaseDir}/${getdownAppDistDir}"
2592 into "${getdownFullArchiveDir}/${vAltDir}"
2595 getdownTextLines.each { line ->
2596 line = line.replaceAll("^(?<s>appbase\\s*=\\s*).*", '${s}'+getdownFullArchiveAppBase)
2597 line = line.replaceAll("^(?<s>(resource|code)\\s*=\\s*)${getdownAppDistDir}/", '${s}'+vAltDir+"/")
2598 line = line.replaceAll("^(?<s>ui.background_image\\s*=\\s*).*\\.png", '${s}'+"${getdown_resource_dir}/jalview_archive_getdown_background.png")
2599 line = line.replaceAll("^(?<s>ui.instant_background_image\\s*=\\s*).*\\.png", '${s}'+"${getdown_resource_dir}/jalview_archive_getdown_background_initialising.png")
2600 line = line.replaceAll("^(?<s>ui.error_background\\s*=\\s*).*\\.png", '${s}'+"${getdown_resource_dir}/jalview_archive_getdown_background_error.png")
2601 line = line.replaceAll("^(?<s>ui.progress_image\\s*=\\s*).*\\.png", '${s}'+"${getdown_resource_dir}/jalview_archive_getdown_progress_bar.png")
2602 // remove the existing resource = resource/ or bin/ lines
2603 if (! line.matches("resource\\s*=\\s*(resource|bin)/.*")) {
2604 getdownArchiveTextLines += line
2608 // the resource dir -- add these files as resource lines in getdown.txt
2610 from "${archiveImagesDir}"
2611 into "${getdownFullArchiveDir}/${getdown_resource_dir}"
2613 getdownArchiveTextLines += "resource = ${getdown_resource_dir}/${file.getName()}"
2617 // the wrapper scripts dir
2618 if ( file("${getdownAppBaseDir}/${getdown_wrapper_script_dir}").exists() ) {
2620 from "${getdownAppBaseDir}/${getdown_wrapper_script_dir}"
2621 into "${getdownFullArchiveDir}/${getdown_wrapper_script_dir}"
2625 getdownArchiveTxt.write(getdownArchiveTextLines.join("\n"))
2627 def vLaunchJvl = file(getdownVersionLaunchJvl)
2628 vLaunchJvl.getParentFile().mkdirs()
2629 vLaunchJvl.write("appbase=${getdownFullArchiveAppBase}\n")
2630 def vLaunchJvlPath = vLaunchJvl.toPath().toAbsolutePath()
2631 def jvlLinkPath = file("${vDir}/jalview.jvl").toPath().toAbsolutePath()
2632 // for some reason filepath.relativize(fileInSameDirPath) gives a path to "../" which is wrong
2633 //java.nio.file.Files.createSymbolicLink(jvlLinkPath, jvlLinkPath.relativize(vLaunchJvlPath));
2634 java.nio.file.Files.createSymbolicLink(jvlLinkPath, java.nio.file.Paths.get(".",vLaunchJvl.getName()));
2636 // files going into the getdown files dir: getdown.txt, getdown-launcher.jar, channel-launch.jvl, build_properties
2638 from getdownLauncher
2639 from "${getdownAppBaseDir}/${getdownLaunchJvl}"
2640 from "${getdownAppBaseDir}/${getdown_launcher_new}"
2641 from "${getdownAppBaseDir}/${channel_props}"
2642 if (file(getdownLauncher).getName() != getdown_launcher) {
2643 rename(file(getdownLauncher).getName(), getdown_launcher)
2645 into getdownFullArchiveDir
2651 task getdownArchiveDigest(type: JavaExec) {
2652 group = "distribution"
2653 description = "Digest the getdown archive folder"
2655 dependsOn getdownArchiveBuild
2658 classpath = files(getdownLauncher)
2659 args getdownFullArchiveDir
2661 main = "com.threerings.getdown.tools.Digester"
2662 inputs.dir(getdownFullArchiveDir)
2663 outputs.file("${getdownFullArchiveDir}/digest2.txt")
2666 task getdownArchive() {
2667 group = "distribution"
2668 description = "Build the website archive dir with getdown digest"
2670 dependsOn getdownArchiveBuild
2671 dependsOn getdownArchiveDigest
2674 tasks.withType(JavaCompile) {
2675 options.encoding = 'UTF-8'
2681 delete getdownAppBaseDir
2682 delete getdownFilesDir
2683 delete getdownArchiveDir
2689 if (file(install4jHomeDir).exists()) {
2691 } else if (file(System.getProperty("user.home")+"/buildtools/install4j").exists()) {
2692 install4jHomeDir = System.getProperty("user.home")+"/buildtools/install4j"
2693 } else if (file("/Applications/install4j.app/Contents/Resources/app").exists()) {
2694 install4jHomeDir = "/Applications/install4j.app/Contents/Resources/app"
2696 installDir(file(install4jHomeDir))
2698 mediaTypes = Arrays.asList(install4j_media_types.split(","))
2702 task copyInstall4jTemplate {
2703 def install4jTemplateFile = file("${install4jDir}/${install4j_template}")
2704 def install4jFileAssociationsFile = file("${install4jDir}/${install4j_installer_file_associations}")
2705 inputs.file(install4jTemplateFile)
2706 inputs.file(install4jFileAssociationsFile)
2707 inputs.property("CHANNEL", { CHANNEL })
2708 outputs.file(install4jConfFile)
2711 def install4jConfigXml = new XmlParser().parse(install4jTemplateFile)
2713 // turn off code signing if no OSX_KEYPASS
2714 if (OSX_KEYPASS == "") {
2715 install4jConfigXml.'**'.codeSigning.each { codeSigning ->
2716 codeSigning.'@macEnabled' = "false"
2718 install4jConfigXml.'**'.windows.each { windows ->
2719 windows.'@runPostProcessor' = "false"
2723 // disable install screen for OSX dmg (for 2.11.2.0)
2724 install4jConfigXml.'**'.macosArchive.each { macosArchive ->
2725 macosArchive.attributes().remove('executeSetupApp')
2726 macosArchive.attributes().remove('setupAppId')
2729 // turn off checksum creation for LOCAL channel
2730 def e = install4jConfigXml.application[0]
2731 e.'@createChecksums' = string(install4jCheckSums)
2733 // put file association actions where placeholder action is
2734 def install4jFileAssociationsText = install4jFileAssociationsFile.text
2735 def fileAssociationActions = new XmlParser().parseText("<actions>${install4jFileAssociationsText}</actions>")
2736 install4jConfigXml.'**'.action.any { a -> // .any{} stops after the first one that returns true
2737 if (a.'@name' == 'EXTENSIONS_REPLACED_BY_GRADLE') {
2738 def parent = a.parent()
2740 fileAssociationActions.each { faa ->
2743 // don't need to continue in .any loop once replacements have been made
2748 // use Windows Program Group with Examples folder for RELEASE, and Program Group without Examples for everything else
2749 // NB we're deleting the /other/ one!
2750 // Also remove the examples subdir from non-release versions
2751 def customizedIdToDelete = "PROGRAM_GROUP_RELEASE"
2752 // 2.11.1.0 NOT releasing with the Examples folder in the Program Group
2753 if (false && CHANNEL=="RELEASE") { // remove 'false && ' to include Examples folder in RELEASE channel
2754 customizedIdToDelete = "PROGRAM_GROUP_NON_RELEASE"
2756 // remove the examples subdir from Full File Set
2757 def files = install4jConfigXml.files[0]
2758 def fileset = files.filesets.fileset.find { fs -> fs.'@customizedId' == "FULL_FILE_SET" }
2759 def root = files.roots.root.find { r -> r.'@fileset' == fileset.'@id' }
2760 def mountPoint = files.mountPoints.mountPoint.find { mp -> mp.'@root' == root.'@id' }
2761 def dirEntry = files.entries.dirEntry.find { de -> de.'@mountPoint' == mountPoint.'@id' && de.'@subDirectory' == "examples" }
2762 dirEntry.parent().remove(dirEntry)
2764 install4jConfigXml.'**'.action.any { a ->
2765 if (a.'@customizedId' == customizedIdToDelete) {
2766 def parent = a.parent()
2772 // write install4j file
2773 install4jConfFile.text = XmlUtil.serialize(install4jConfigXml)
2780 delete install4jConfFile
2784 task cleanInstallersDataFiles {
2785 def installersOutputTxt = file("${jalviewDir}/${install4jBuildDir}/output.txt")
2786 def installersSha256 = file("${jalviewDir}/${install4jBuildDir}/sha256sums")
2787 def hugoDataJsonFile = file("${jalviewDir}/${install4jBuildDir}/installers-${JALVIEW_VERSION_UNDERSCORES}.json")
2789 delete installersOutputTxt
2790 delete installersSha256
2791 delete hugoDataJsonFile
2795 task install4jDMGBackgroundImageCopy {
2796 inputs.file "${install4jDMGBackgroundImageDir}/${install4jDMGBackgroundImageFile}"
2797 outputs.dir "${install4jDMGBackgroundImageBuildDir}"
2800 from(install4jDMGBackgroundImageDir) {
2801 include(install4jDMGBackgroundImageFile)
2803 into install4jDMGBackgroundImageBuildDir
2808 task install4jDMGBackgroundImageProcess {
2809 dependsOn install4jDMGBackgroundImageCopy
2812 if (backgroundImageText) {
2813 if (convertBinary == null) {
2814 throw new StopExecutionException("No ImageMagick convert binary installed at '${convertBinaryExpectedLocation}'")
2816 if (!project.hasProperty("install4j_background_image_text_suffix_cmd")) {
2817 throw new StopExecutionException("No property 'install4j_background_image_text_suffix_cmd' defined. See channel_gradle.properties for channel ${CHANNEL}")
2819 fileTree(dir: install4jDMGBackgroundImageBuildDir, include: "*.png").getFiles().each { file ->
2821 executable convertBinary
2824 '-font', install4j_background_image_text_font,
2825 '-fill', install4j_background_image_text_colour,
2826 '-draw', sprintf(install4j_background_image_text_suffix_cmd, channelSuffix),
2827 '-draw', sprintf(install4j_background_image_text_commit_cmd, "git-commit: ${gitHash}"),
2828 '-draw', sprintf(install4j_background_image_text_date_cmd, getDate("yyyy-MM-dd HH:mm:ss")),
2837 task install4jDMGDS_Store {
2838 //install4jDMGDS_Store
2839 //install4jDMGFixedDSStore
2842 task install4jDMGProcesses {
2843 dependsOn install4jDMGBackgroundImageProcess
2844 dependsOn install4jDMGDS_Store
2847 task installerFiles(type: com.install4j.gradle.Install4jTask) {
2848 group = "distribution"
2849 description = "Create the install4j installers"
2851 dependsOn copyInstall4jTemplate
2852 dependsOn cleanInstallersDataFiles
2853 dependsOn install4jDMGProcesses
2855 projectFile = install4jConfFile
2857 // run install4j with 4g
2858 vmParameters = ["-Xmx4294967296"]
2860 // create an md5 for the input files to use as version for install4j conf file
2861 def digest = MessageDigest.getInstance("MD5")
2863 (file("${install4jDir}/${install4j_template}").text +
2864 file("${install4jDir}/${install4j_info_plist_file_associations}").text +
2865 file("${install4jDir}/${install4j_installer_file_associations}").text).bytes)
2866 def filesMd5 = new BigInteger(1, digest.digest()).toString(16)
2867 if (filesMd5.length() >= 8) {
2868 filesMd5 = filesMd5.substring(0,8)
2870 def install4jTemplateVersion = "${JALVIEW_VERSION}_F${filesMd5}_C${gitHash}"
2873 'JALVIEW_NAME': jalview_name,
2874 'JALVIEW_APPLICATION_NAME': applicationName,
2875 'JALVIEW_DIR': "../..",
2876 'OSX_KEYSTORE': OSX_KEYSTORE,
2877 'OSX_APPLEID': OSX_APPLEID,
2878 'OSX_ALTOOLPASS': OSX_ALTOOLPASS,
2879 'JSIGN_SH': JSIGN_SH,
2880 'JRE_DIR': getdown_app_dir_java,
2881 'INSTALLER_TEMPLATE_VERSION': install4jTemplateVersion,
2882 'JALVIEW_VERSION': JALVIEW_VERSION,
2883 'JAVA_MIN_VERSION': JAVA_MIN_VERSION,
2884 'JAVA_MAX_VERSION': JAVA_MAX_VERSION,
2885 'JAVA_VERSION': JAVA_VERSION,
2886 'JAVA_INTEGER_VERSION': JAVA_INTEGER_VERSION,
2887 'VERSION': JALVIEW_VERSION,
2888 'COPYRIGHT_MESSAGE': install4j_copyright_message,
2889 'BUNDLE_ID': install4jBundleId,
2890 'INTERNAL_ID': install4jInternalId,
2891 'WINDOWS_APPLICATION_ID': install4jWinApplicationId,
2892 'MACOS_DMG_DS_STORE': install4jDMGDSStore,
2893 'MACOS_DMG_BG_IMAGE': "${install4jDMGBackgroundImageBuildDir}/${install4jDMGBackgroundImageFile}",
2894 'MACOS_DMG_BG_FILENAME': install4j_dmg_background_filename,
2895 'WRAPPER_LINK': getdownWrapperLink,
2896 'BASH_WRAPPER_SCRIPT': getdown_bash_wrapper_script,
2897 'POWERSHELL_WRAPPER_SCRIPT': getdown_powershell_wrapper_script,
2898 'BATCH_WRAPPER_SCRIPT': getdown_batch_wrapper_script,
2899 'WRAPPER_SCRIPT_BIN_DIR': getdown_wrapper_script_dir,
2900 'MACOSARCHIVE_X86_NAME': install4jmacOSArchiveX86Name,
2901 'MACOSARCHIVE_AARCH64_NAME': install4jmacOSArchiveAarch64Name,
2902 'INSTALL4J_UTILS_DIR': install4j_utils_dir,
2903 'GETDOWN_CHANNEL_DIR': getdownChannelDir,
2904 'GETDOWN_FILES_DIR': getdown_files_dir,
2905 'GETDOWN_RESOURCE_DIR': getdown_resource_dir,
2906 'GETDOWN_DIST_DIR': getdownAppDistDir,
2907 'GETDOWN_ALT_DIR': getdown_app_dir_alt,
2908 'GETDOWN_INSTALL_DIR': getdown_install_dir,
2909 'INFO_PLIST_FILE_ASSOCIATIONS_FILE': install4j_info_plist_file_associations,
2910 'BUILD_DIR': install4jBuildDir,
2911 'APPLICATION_CATEGORIES': install4j_application_categories,
2912 'APPLICATION_FOLDER': install4jApplicationFolder,
2913 'UNIX_APPLICATION_FOLDER': install4jUnixApplicationFolder,
2914 'EXECUTABLE_NAME': install4jExecutableName,
2915 'EXTRA_SCHEME': install4jExtraScheme,
2916 'MAC_ICONS_FILE': install4jMacIconsFile,
2917 'WINDOWS_ICONS_FILE': install4jWindowsIconsFile,
2918 'PNG_ICON_FILE': install4jPngIconFile,
2919 'BACKGROUND': install4jBackground,
2924 'windows': 'WINDOWS',
2928 // these are the bundled OS/architecture VMs needed by install4j
2931 [ "mac", "aarch64" ],
2932 [ "windows", "x64" ],
2934 [ "linux", "aarch64" ]
2936 osArch.forEach { os, arch ->
2937 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)
2938 // N.B. For some reason install4j requires the below filename to have underscores and not hyphens
2939 // otherwise running `gradle installers` generates a non-useful error:
2940 // `install4j: compilation failed. Reason: java.lang.NumberFormatException: For input string: "windows"`
2941 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)
2944 //println("INSTALL4J VARIABLES:")
2945 //variables.each{k,v->println("${k}=${v}")}
2947 destination = "${jalviewDir}/${install4jBuildDir}"
2948 buildSelected = true
2950 if (install4j_faster.equals("true") || CHANNEL.startsWith("LOCAL")) {
2952 disableSigning = true
2953 disableNotarization = true
2957 macKeystorePassword = OSX_KEYPASS
2960 if (OSX_ALTOOLPASS) {
2961 appleIdPassword = OSX_ALTOOLPASS
2962 disableNotarization = false
2964 disableNotarization = true
2968 println("Using projectFile "+projectFile)
2969 if (!disableNotarization) { println("Will notarize OSX App DMG") }
2973 inputs.dir(getdownAppBaseDir)
2974 inputs.file(install4jConfFile)
2975 inputs.file("${install4jDir}/${install4j_info_plist_file_associations}")
2976 outputs.dir("${jalviewDir}/${install4j_build_dir}/${JAVA_VERSION}")
2979 def getDataHash(File myFile) {
2980 HashCode hash = Files.asByteSource(myFile).hash(Hashing.sha256())
2981 return myFile.exists()
2983 "file" : myFile.getName(),
2984 "filesize" : myFile.length(),
2985 "sha256" : hash.toString()
2990 def writeDataJsonFile(File installersOutputTxt, File installersSha256, File dataJsonFile) {
2992 "channel" : getdownChannelName,
2993 "date" : getDate("yyyy-MM-dd HH:mm:ss"),
2994 "git-commit" : "${gitHash} [${gitBranch}]",
2995 "version" : JALVIEW_VERSION
2997 // install4j installer files
2998 if (installersOutputTxt.exists()) {
3000 installersOutputTxt.readLines().each { def line ->
3001 if (line.startsWith("#")) {
3004 line.replaceAll("\n","")
3005 def vals = line.split("\t")
3006 def filename = vals[3]
3007 def filesize = file(filename).length()
3008 filename = filename.replaceAll(/^.*\//, "")
3009 hash[vals[0]] = [ "id" : vals[0], "os" : vals[1], "name" : vals[2], "file" : filename, "filesize" : filesize ]
3010 idHash."${filename}" = vals[0]
3012 if (install4jCheckSums && installersSha256.exists()) {
3013 installersSha256.readLines().each { def line ->
3014 if (line.startsWith("#")) {
3017 line.replaceAll("\n","")
3018 def vals = line.split(/\s+\*?/)
3019 def filename = vals[1]
3020 def innerHash = (hash.(idHash."${filename}"))."sha256" = vals[0]
3026 "JAR": shadowJar.archiveFile, // executable JAR
3027 "JVL": getdownVersionLaunchJvl, // version JVL
3028 "SOURCE": sourceDist.archiveFile // source TGZ
3029 ].each { key, value ->
3030 def file = file(value)
3031 if (file.exists()) {
3032 def fileHash = getDataHash(file)
3033 if (fileHash != null) {
3034 hash."${key}" = fileHash;
3038 return dataJsonFile.write(new JsonBuilder(hash).toPrettyString())
3041 task staticMakeInstallersJsonFile {
3043 def output = findProperty("i4j_output")
3044 def sha256 = findProperty("i4j_sha256")
3045 def json = findProperty("i4j_json")
3046 if (output == null || sha256 == null || json == null) {
3047 throw new GradleException("Must provide paths to all of output.txt, sha256sums, and output.json with '-Pi4j_output=... -Pi4j_sha256=... -Pi4j_json=...")
3049 writeDataJsonFile(file(output), file(sha256), file(json))
3054 dependsOn installerFiles
3060 eclipse().configFile(eclipse_codestyle_file)
3064 task createSourceReleaseProperties(type: WriteProperties) {
3065 group = "distribution"
3066 description = "Create the source RELEASE properties file"
3068 def sourceTarBuildDir = "${buildDir}/sourceTar"
3069 def sourceReleasePropertiesFile = "${sourceTarBuildDir}/RELEASE"
3070 outputFile (sourceReleasePropertiesFile)
3073 releaseProps.each{ key, val -> property key, val }
3074 property "git.branch", gitBranch
3075 property "git.hash", gitHash
3078 outputs.file(outputFile)
3081 task sourceDist(type: Tar) {
3082 group "distribution"
3083 description "Create a source .tar.gz file for distribution"
3085 dependsOn createBuildProperties
3086 dependsOn convertMdFiles
3087 dependsOn eclipseAllPreferences
3088 dependsOn createSourceReleaseProperties
3091 def outputFileName = "${project.name}_${JALVIEW_VERSION_UNDERSCORES}.tar.gz"
3092 archiveFileName = outputFileName
3094 compression Compression.GZIP
3110 "**/*.class","$j11modDir/**/*.jar","appletlib","**/*locales",
3112 "utils/InstallAnywhere",
3127 "gradle.properties",
3139 ".settings/org.eclipse.buildship.core.prefs",
3140 ".settings/org.eclipse.jdt.core.prefs"
3144 exclude (EXCLUDE_FILES)
3145 include (PROCESS_FILES)
3146 filter(ReplaceTokens,
3150 'Version-Rel': JALVIEW_VERSION,
3151 'Year-Rel': getDate("yyyy")
3156 exclude (EXCLUDE_FILES)
3157 exclude (PROCESS_FILES)
3158 exclude ("appletlib")
3159 exclude ("**/*locales")
3160 exclude ("*locales/**")
3161 exclude ("utils/InstallAnywhere")
3163 exclude (getdown_files_dir)
3164 // getdown_website_dir and getdown_archive_dir moved to build/website/docroot/getdown
3165 //exclude (getdown_website_dir)
3166 //exclude (getdown_archive_dir)
3168 // exluding these as not using jars as modules yet
3169 exclude ("${j11modDir}/**/*.jar")
3172 include(INCLUDE_FILES)
3174 // from (jalviewDir) {
3175 // // explicit includes for stuff that seemed to not get included
3176 // include(fileTree("test/**/*."))
3177 // exclude(EXCLUDE_FILES)
3178 // exclude(PROCESS_FILES)
3181 from(file(buildProperties).getParent()) {
3182 include(file(buildProperties).getName())
3183 rename(file(buildProperties).getName(), "build_properties")
3185 line.replaceAll("^INSTALLATION=.*\$","INSTALLATION=Source Release"+" git-commit\\\\:"+gitHash+" ["+gitBranch+"]")
3189 def sourceTarBuildDir = "${buildDir}/sourceTar"
3190 from(sourceTarBuildDir) {
3191 // this includes the appended RELEASE properties file
3195 task dataInstallersJson {
3197 description "Create the installers-VERSION.json data file for installer files created"
3199 mustRunAfter installers
3200 mustRunAfter shadowJar
3201 mustRunAfter sourceDist
3202 mustRunAfter getdownArchive
3204 def installersOutputTxt = file("${jalviewDir}/${install4jBuildDir}/output.txt")
3205 def installersSha256 = file("${jalviewDir}/${install4jBuildDir}/sha256sums")
3207 if (installersOutputTxt.exists()) {
3208 inputs.file(installersOutputTxt)
3210 if (install4jCheckSums && installersSha256.exists()) {
3211 inputs.file(installersSha256)
3214 shadowJar.archiveFile, // executable JAR
3215 getdownVersionLaunchJvl, // version JVL
3216 sourceDist.archiveFile // source TGZ
3217 ].each { fileName ->
3218 if (file(fileName).exists()) {
3219 inputs.file(fileName)
3223 outputs.file(hugoDataJsonFile)
3226 writeDataJsonFile(installersOutputTxt, installersSha256, hugoDataJsonFile)
3232 description "Copies all help pages to build dir. Runs ant task 'pubhtmlhelp'."
3235 dependsOn pubhtmlhelp
3237 inputs.dir("${helpBuildDir}/${help_dir}")
3238 outputs.dir("${buildDir}/distributions/${help_dir}")
3242 task j2sSetHeadlessBuild {
3249 task jalviewjsEnableAltFileProperty(type: WriteProperties) {
3251 description "Enable the alternative J2S Config file for headless build"
3253 outputFile = jalviewjsJ2sSettingsFileName
3254 def j2sPropsFile = file(jalviewjsJ2sSettingsFileName)
3255 def j2sProps = new Properties()
3256 if (j2sPropsFile.exists()) {
3258 def j2sPropsFileFIS = new FileInputStream(j2sPropsFile)
3259 j2sProps.load(j2sPropsFileFIS)
3260 j2sPropsFileFIS.close()
3262 j2sProps.each { prop, val ->
3265 } catch (Exception e) {
3266 println("Exception reading ${jalviewjsJ2sSettingsFileName}")
3270 if (! j2sProps.stringPropertyNames().contains(jalviewjs_j2s_alt_file_property_config)) {
3271 property(jalviewjs_j2s_alt_file_property_config, jalviewjs_j2s_alt_file_property)
3276 task jalviewjsSetEclipseWorkspace {
3277 def propKey = "jalviewjs_eclipse_workspace"
3279 if (project.hasProperty(propKey)) {
3280 propVal = project.getProperty(propKey)
3281 if (propVal.startsWith("~/")) {
3282 propVal = System.getProperty("user.home") + propVal.substring(1)
3285 def propsFileName = "${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_eclipse_workspace_location_file}"
3286 def propsFile = file(propsFileName)
3287 def eclipseWsDir = propVal
3288 def props = new Properties()
3290 def writeProps = true
3291 if (( eclipseWsDir == null || !file(eclipseWsDir).exists() ) && propsFile.exists()) {
3292 def ins = new FileInputStream(propsFileName)
3295 if (props.getProperty(propKey, null) != null) {
3296 eclipseWsDir = props.getProperty(propKey)
3301 if (eclipseWsDir == null || !file(eclipseWsDir).exists()) {
3302 def tempDir = File.createTempDir()
3303 eclipseWsDir = tempDir.getAbsolutePath()
3306 eclipseWorkspace = file(eclipseWsDir)
3309 // do not run a headless transpile when we claim to be in Eclipse
3311 println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3312 throw new StopExecutionException("Not running headless transpile whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
3314 println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3318 props.setProperty(propKey, eclipseWsDir)
3319 propsFile.parentFile.mkdirs()
3320 def bytes = new ByteArrayOutputStream()
3321 props.store(bytes, null)
3322 def propertiesString = bytes.toString()
3323 propsFile.text = propertiesString
3329 println("ECLIPSE WORKSPACE: "+eclipseWorkspace.getPath())
3332 //inputs.property(propKey, eclipseWsDir) // eclipseWsDir only gets set once this task runs, so will be out-of-date
3333 outputs.file(propsFileName)
3334 outputs.upToDateWhen { eclipseWorkspace.exists() && propsFile.exists() }
3338 task jalviewjsEclipsePaths {
3341 def eclipseRoot = jalviewjs_eclipse_root
3342 if (eclipseRoot.startsWith("~/")) {
3343 eclipseRoot = System.getProperty("user.home") + eclipseRoot.substring(1)
3345 if (OperatingSystem.current().isMacOsX()) {
3346 eclipseRoot += "/Eclipse.app"
3347 eclipseBinary = "${eclipseRoot}/Contents/MacOS/eclipse"
3348 eclipseProduct = "${eclipseRoot}/Contents/Eclipse/.eclipseproduct"
3349 } else if (OperatingSystem.current().isWindows()) { // check these paths!!
3350 if (file("${eclipseRoot}/eclipse").isDirectory() && file("${eclipseRoot}/eclipse/.eclipseproduct").exists()) {
3351 eclipseRoot += "/eclipse"
3353 eclipseBinary = "${eclipseRoot}/eclipse.exe"
3354 eclipseProduct = "${eclipseRoot}/.eclipseproduct"
3355 } else { // linux or unix
3356 if (file("${eclipseRoot}/eclipse").isDirectory() && file("${eclipseRoot}/eclipse/.eclipseproduct").exists()) {
3357 eclipseRoot += "/eclipse"
3358 println("eclipseDir exists")
3360 eclipseBinary = "${eclipseRoot}/eclipse"
3361 eclipseProduct = "${eclipseRoot}/.eclipseproduct"
3364 eclipseVersion = "4.13" // default
3365 def assumedVersion = true
3366 if (file(eclipseProduct).exists()) {
3367 def fis = new FileInputStream(eclipseProduct)
3368 def props = new Properties()
3370 eclipseVersion = props.getProperty("version")
3372 assumedVersion = false
3375 def propKey = "eclipse_debug"
3376 eclipseDebug = (project.hasProperty(propKey) && project.getProperty(propKey).equals("true"))
3379 // do not run a headless transpile when we claim to be in Eclipse
3381 println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3382 throw new StopExecutionException("Not running headless transpile whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
3384 println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3387 if (!assumedVersion) {
3388 println("ECLIPSE VERSION=${eclipseVersion}")
3394 task printProperties {
3396 description "Output to console all System.properties"
3398 System.properties.each { key, val -> System.out.println("Property: ${key}=${val}") }
3404 dependsOn eclipseProject
3405 dependsOn eclipseClasspath
3406 dependsOn eclipseJdt
3410 // this version (type: Copy) will delete anything in the eclipse dropins folder that isn't in fromDropinsDir
3411 task jalviewjsEclipseCopyDropins(type: Copy) {
3412 dependsOn jalviewjsEclipsePaths
3414 def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjs_eclipse_dropins_dir}", include: "*.jar")
3415 inputFiles += file("${jalviewDir}/${jalviewjsJ2sPlugin}")
3416 def outputDir = "${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_eclipse_tmp_dropins_dir}"
3423 // this eclipse -clean doesn't actually work
3424 task jalviewjsCleanEclipse(type: Exec) {
3425 dependsOn eclipseSetup
3426 dependsOn jalviewjsEclipsePaths
3427 dependsOn jalviewjsEclipseCopyDropins
3429 executable(eclipseBinary)
3430 args(["-nosplash", "--launcher.suppressErrors", "-data", eclipseWorkspace.getPath(), "-clean", "-console", "-consoleLog"])
3436 def inputString = """exit
3439 def inputByteStream = new ByteArrayInputStream(inputString.getBytes())
3440 standardInput = inputByteStream
3443 /* not really working yet
3444 jalviewjsEclipseCopyDropins.finalizedBy jalviewjsCleanEclipse
3448 task jalviewjsTransferUnzipSwingJs {
3449 def file_zip = "${jalviewDir}/${jalviewjs_swingjs_zip}"
3453 from zipTree(file_zip)
3454 into "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}"
3458 inputs.file file_zip
3459 outputs.dir "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}"
3463 task jalviewjsTransferUnzipLib {
3464 def zipFiles = fileTree(dir: "${jalviewDir}/${jalviewjs_libjs_dir}", include: "*.zip")
3467 zipFiles.each { file_zip ->
3469 from zipTree(file_zip)
3470 into "${jalviewDir}/${jalviewjsTransferSiteLibDir}"
3475 inputs.files zipFiles
3476 outputs.dir "${jalviewDir}/${jalviewjsTransferSiteLibDir}"
3480 task jalviewjsTransferUnzipAllLibs {
3481 dependsOn jalviewjsTransferUnzipSwingJs
3482 dependsOn jalviewjsTransferUnzipLib
3486 task jalviewjsCreateJ2sSettings(type: WriteProperties) {
3488 description "Create the alternative j2s file from the j2s.* properties"
3490 jalviewjsJ2sProps = project.properties.findAll { it.key.startsWith("j2s.") }.sort { it.key }
3491 def siteDirProperty = "j2s.site.directory"
3492 def setSiteDir = false
3493 jalviewjsJ2sProps.each { prop, val ->
3495 if (prop == siteDirProperty) {
3496 if (!(val.startsWith('/') || val.startsWith("file://") )) {
3497 val = "${jalviewDir}/${jalviewjsTransferSiteJsDir}/${val}"
3503 if (!setSiteDir) { // default site location, don't override specifically set property
3504 property(siteDirProperty,"${jalviewDirRelativePath}/${jalviewjsTransferSiteJsDir}")
3507 outputFile = jalviewjsJ2sAltSettingsFileName
3510 inputs.properties(jalviewjsJ2sProps)
3511 outputs.file(jalviewjsJ2sAltSettingsFileName)
3516 task jalviewjsEclipseSetup {
3517 dependsOn jalviewjsEclipseCopyDropins
3518 dependsOn jalviewjsSetEclipseWorkspace
3519 dependsOn jalviewjsCreateJ2sSettings
3523 task jalviewjsSyncAllLibs (type: Sync) {
3524 dependsOn jalviewjsTransferUnzipAllLibs
3525 def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjsTransferSiteLibDir}")
3526 inputFiles += fileTree(dir: "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}")
3527 def outputDir = "${jalviewDir}/${jalviewjsSiteDir}"
3531 def outputFiles = []
3532 rename { filename ->
3533 outputFiles += "${outputDir}/${filename}"
3540 // should this be exclude really ?
3541 duplicatesStrategy "INCLUDE"
3543 outputs.files outputFiles
3544 inputs.files inputFiles
3548 task jalviewjsSyncResources (type: Sync) {
3549 dependsOn buildResources
3551 def inputFiles = fileTree(dir: resourcesBuildDir)
3552 def outputDir = "${jalviewDir}/${jalviewjsSiteDir}/${jalviewjs_j2s_subdir}"
3556 def outputFiles = []
3557 rename { filename ->
3558 outputFiles += "${outputDir}/${filename}"
3564 outputs.files outputFiles
3565 inputs.files inputFiles
3569 task jalviewjsSyncSiteResources (type: Sync) {
3570 def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjs_site_resource_dir}")
3571 def outputDir = "${jalviewDir}/${jalviewjsSiteDir}"
3575 def outputFiles = []
3576 rename { filename ->
3577 outputFiles += "${outputDir}/${filename}"
3583 outputs.files outputFiles
3584 inputs.files inputFiles
3588 task jalviewjsSyncBuildProperties (type: Sync) {
3589 dependsOn createBuildProperties
3590 def inputFiles = [file(buildProperties)]
3591 def outputDir = "${jalviewDir}/${jalviewjsSiteDir}/${jalviewjs_j2s_subdir}"
3595 def outputFiles = []
3596 rename { filename ->
3597 outputFiles += "${outputDir}/${filename}"
3603 outputs.files outputFiles
3604 inputs.files inputFiles
3608 task jalviewjsProjectImport(type: Exec) {
3609 dependsOn eclipseSetup
3610 dependsOn jalviewjsEclipsePaths
3611 dependsOn jalviewjsEclipseSetup
3614 // do not run a headless import when we claim to be in Eclipse
3616 println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3617 throw new StopExecutionException("Not running headless import whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
3619 println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3623 //def projdir = eclipseWorkspace.getPath()+"/.metadata/.plugins/org.eclipse.core.resources/.projects/jalview/org.eclipse.jdt.core"
3624 def projdir = eclipseWorkspace.getPath()+"/.metadata/.plugins/org.eclipse.core.resources/.projects/jalview"
3625 executable(eclipseBinary)
3626 args(["-nosplash", "--launcher.suppressErrors", "-application", "com.seeq.eclipse.importprojects.headlessimport", "-data", eclipseWorkspace.getPath(), "-import", jalviewDirAbsolutePath])
3630 args += [ "--launcher.appendVmargs", "-vmargs", "-Dorg.eclipse.equinox.p2.reconciler.dropins.directory=${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_eclipse_tmp_dropins_dir}" ]
3632 args += [ "-D${j2sHeadlessBuildProperty}=true" ]
3633 args += [ "-D${jalviewjs_j2s_alt_file_property}=${jalviewjsJ2sAltSettingsFileName}" ]
3636 inputs.file("${jalviewDir}/.project")
3637 outputs.upToDateWhen {
3638 file(projdir).exists()
3643 task jalviewjsTranspile(type: Exec) {
3644 dependsOn jalviewjsEclipseSetup
3645 dependsOn jalviewjsProjectImport
3646 dependsOn jalviewjsEclipsePaths
3648 dependsOn jalviewjsEnableAltFileProperty
3652 // do not run a headless transpile when we claim to be in Eclipse
3654 println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3655 throw new StopExecutionException("Not running headless transpile whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
3657 println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3661 executable(eclipseBinary)
3662 args(["-nosplash", "--launcher.suppressErrors", "-application", "org.eclipse.jdt.apt.core.aptBuild", "-data", eclipseWorkspace, "-${jalviewjs_eclipse_build_arg}", eclipse_project_name ])
3666 args += [ "--launcher.appendVmargs", "-vmargs", "-Dorg.eclipse.equinox.p2.reconciler.dropins.directory=${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_eclipse_tmp_dropins_dir}" ]
3668 args += [ "-D${j2sHeadlessBuildProperty}=true" ]
3669 args += [ "-D${jalviewjs_j2s_alt_file_property}=${jalviewjsJ2sAltSettingsFileName}" ]
3675 stdout = new ByteArrayOutputStream()
3676 stderr = new ByteArrayOutputStream()
3678 def logOutFileName = "${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}"
3679 def logOutFile = file(logOutFileName)
3680 logOutFile.createNewFile()
3681 logOutFile.text = """ROOT: ${jalviewjs_eclipse_root}
3682 BINARY: ${eclipseBinary}
3683 VERSION: ${eclipseVersion}
3684 WORKSPACE: ${eclipseWorkspace}
3685 DEBUG: ${eclipseDebug}
3688 def logOutFOS = new FileOutputStream(logOutFile, true) // true == append
3689 // combine stdout and stderr
3690 def logErrFOS = logOutFOS
3692 if (jalviewjs_j2s_to_console.equals("true")) {
3693 standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
3694 new org.apache.tools.ant.util.TeeOutputStream(
3698 errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
3699 new org.apache.tools.ant.util.TeeOutputStream(
3704 standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
3707 errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
3714 if (stdout.toString().contains("Error processing ")) {
3715 // j2s did not complete transpile
3716 //throw new TaskExecutionException("Error during transpilation:\n${stderr}\nSee eclipse transpile log file '${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}'")
3717 if (jalviewjs_ignore_transpile_errors.equals("true")) {
3718 println("IGNORING TRANSPILE ERRORS")
3719 println("See eclipse transpile log file '${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}'")
3721 throw new GradleException("Error during transpilation:\n${stderr}\nSee eclipse transpile log file '${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}'")
3726 inputs.dir("${jalviewDir}/${sourceDir}")
3727 outputs.dir("${jalviewDir}/${jalviewjsTransferSiteJsDir}")
3728 outputs.upToDateWhen( { file("${jalviewDir}/${jalviewjsTransferSiteJsDir}${jalviewjs_server_resource}").exists() } )
3732 def jalviewjsCallCore(String name, FileCollection list, String prefixFile, String suffixFile, String jsfile, String zjsfile, File logOutFile, Boolean logOutConsole) {
3734 def stdout = new ByteArrayOutputStream()
3735 def stderr = new ByteArrayOutputStream()
3737 def coreFile = file(jsfile)
3739 msg = "Creating core for ${name}...\nGenerating ${jsfile}"
3741 logOutFile.createNewFile()
3742 logOutFile.append(msg+"\n")
3744 def coreTop = file(prefixFile)
3745 def coreBottom = file(suffixFile)
3746 coreFile.getParentFile().mkdirs()
3747 coreFile.createNewFile()
3748 coreFile.write( coreTop.getText("UTF-8") )
3752 def t = f.getText("UTF-8")
3753 t.replaceAll("Clazz\\.([^_])","Clazz_${1}")
3754 coreFile.append( t )
3756 msg = "...file '"+f.getPath()+"' does not exist, skipping"
3758 logOutFile.append(msg+"\n")
3761 coreFile.append( coreBottom.getText("UTF-8") )
3763 msg = "Generating ${zjsfile}"
3765 logOutFile.append(msg+"\n")
3766 def logOutFOS = new FileOutputStream(logOutFile, true) // true == append
3767 def logErrFOS = logOutFOS
3770 classpath = files(["${jalviewDir}/${jalviewjs_closure_compiler}"])
3771 main = "com.google.javascript.jscomp.CommandLineRunner"
3772 jvmArgs = [ "-Dfile.encoding=UTF-8" ]
3773 args = [ "--compilation_level", "SIMPLE_OPTIMIZATIONS", "--warning_level", "QUIET", "--charset", "UTF-8", "--js", jsfile, "--js_output_file", zjsfile ]
3776 msg = "\nRunning '"+commandLine.join(' ')+"'\n"
3778 logOutFile.append(msg+"\n")
3780 if (logOutConsole) {
3781 standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
3782 new org.apache.tools.ant.util.TeeOutputStream(
3786 errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
3787 new org.apache.tools.ant.util.TeeOutputStream(
3792 standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
3795 errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
3802 logOutFile.append(msg+"\n")
3806 task jalviewjsBuildAllCores {
3808 description "Build the core js lib closures listed in the classlists dir"
3809 dependsOn jalviewjsTranspile
3810 dependsOn jalviewjsTransferUnzipSwingJs
3812 def j2sDir = "${jalviewDir}/${jalviewjsTransferSiteJsDir}/${jalviewjs_j2s_subdir}"
3813 def swingJ2sDir = "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}/${jalviewjs_j2s_subdir}"
3814 def libJ2sDir = "${jalviewDir}/${jalviewjsTransferSiteLibDir}/${jalviewjs_j2s_subdir}"
3815 def jsDir = "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}/${jalviewjs_js_subdir}"
3816 def outputDir = "${jalviewDir}/${jalviewjsTransferSiteCoreDir}/${jalviewjs_j2s_subdir}/core"
3817 def prefixFile = "${jsDir}/core/coretop2.js"
3818 def suffixFile = "${jsDir}/core/corebottom2.js"
3820 inputs.file prefixFile
3821 inputs.file suffixFile
3823 def classlistFiles = []
3824 // add the classlists found int the jalviewjs_classlists_dir
3825 fileTree(dir: "${jalviewDir}/${jalviewjs_classlists_dir}", include: "*.txt").each {
3827 def name = file.getName() - ".txt"
3834 // _jmol and _jalview cores. Add any other peculiar classlist.txt files here
3835 //classlistFiles += [ 'file': file("${jalviewDir}/${jalviewjs_classlist_jmol}"), 'name': "_jvjmol" ]
3836 classlistFiles += [ 'file': file("${jalviewDir}/${jalviewjs_classlist_jalview}"), 'name': jalviewjsJalviewCoreName ]
3838 jalviewjsCoreClasslists = []
3840 classlistFiles.each {
3843 def file = hash['file']
3844 if (! file.exists()) {
3845 //println("...classlist file '"+file.getPath()+"' does not exist, skipping")
3846 return false // this is a "continue" in groovy .each closure
3848 def name = hash['name']
3850 name = file.getName() - ".txt"
3858 def list = fileTree(dir: j2sDir, includes: filelist)
3860 def jsfile = "${outputDir}/core${name}.js"
3861 def zjsfile = "${outputDir}/core${name}.z.js"
3863 jalviewjsCoreClasslists += [
3872 outputs.file(jsfile)
3873 outputs.file(zjsfile)
3876 // _stevesoft core. add any cores without a classlist here (and the inputs and outputs)
3877 def stevesoftClasslistName = "_stevesoft"
3878 def stevesoftClasslist = [
3879 'jsfile': "${outputDir}/core${stevesoftClasslistName}.js",
3880 'zjsfile': "${outputDir}/core${stevesoftClasslistName}.z.js",
3881 'list': fileTree(dir: j2sDir, include: "com/stevesoft/pat/**/*.js"),
3882 'name': stevesoftClasslistName
3884 jalviewjsCoreClasslists += stevesoftClasslist
3885 inputs.files(stevesoftClasslist['list'])
3886 outputs.file(stevesoftClasslist['jsfile'])
3887 outputs.file(stevesoftClasslist['zjsfile'])
3890 def allClasslistName = "_all"
3891 def allJsFiles = fileTree(dir: j2sDir, include: "**/*.js")
3892 allJsFiles += fileTree(
3896 // these exlusions are files that the closure-compiler produces errors for. Should fix them
3897 "**/org/jmol/jvxl/readers/IsoIntersectFileReader.js",
3898 "**/org/jmol/export/JSExporter.js"
3901 allJsFiles += fileTree(
3905 // these exlusions are files that the closure-compiler produces errors for. Should fix them
3906 "**/sun/misc/Unsafe.js",
3907 "**/swingjs/jquery/jquery-editable-select.js",
3908 "**/swingjs/jquery/j2sComboBox.js",
3909 "**/sun/misc/FloatingDecimal.js"
3912 def allClasslist = [
3913 'jsfile': "${outputDir}/core${allClasslistName}.js",
3914 'zjsfile': "${outputDir}/core${allClasslistName}.z.js",
3916 'name': allClasslistName
3918 // not including this version of "all" core at the moment
3919 //jalviewjsCoreClasslists += allClasslist
3920 inputs.files(allClasslist['list'])
3921 outputs.file(allClasslist['jsfile'])
3922 outputs.file(allClasslist['zjsfile'])
3925 def logOutFile = file("${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_j2s_closure_stdout}")
3926 logOutFile.getParentFile().mkdirs()
3927 logOutFile.createNewFile()
3928 logOutFile.write(getDate("yyyy-MM-dd HH:mm:ss")+" jalviewjsBuildAllCores\n----\n")
3930 jalviewjsCoreClasslists.each {
3931 jalviewjsCallCore(it.name, it.list, prefixFile, suffixFile, it.jsfile, it.zjsfile, logOutFile, jalviewjs_j2s_to_console.equals("true"))
3938 def jalviewjsPublishCoreTemplate(String coreName, String templateName, File inputFile, String outputFile) {
3941 into file(outputFile).getParentFile()
3942 rename { filename ->
3943 if (filename.equals(inputFile.getName())) {
3944 return file(outputFile).getName()
3948 filter(ReplaceTokens,
3952 'MAIN': '"'+main_class+'"',
3954 'NAME': jalviewjsJalviewTemplateName+" [core ${coreName}]",
3955 'COREKEY': jalviewjs_core_key,
3956 'CORENAME': coreName
3963 task jalviewjsPublishCoreTemplates {
3964 dependsOn jalviewjsBuildAllCores
3965 def inputFileName = "${jalviewDir}/${j2s_coretemplate_html}"
3966 def inputFile = file(inputFileName)
3967 def outputDir = "${jalviewDir}/${jalviewjsTransferSiteCoreDir}"
3969 def outputFiles = []
3970 jalviewjsCoreClasslists.each { cl ->
3971 def outputFile = "${outputDir}/${jalviewjsJalviewTemplateName}_${cl.name}.html"
3972 cl['outputfile'] = outputFile
3973 outputFiles += outputFile
3977 jalviewjsCoreClasslists.each { cl ->
3978 jalviewjsPublishCoreTemplate(cl.name, jalviewjsJalviewTemplateName, inputFile, cl.outputfile)
3981 inputs.file(inputFile)
3982 outputs.files(outputFiles)
3986 task jalviewjsSyncCore (type: Sync) {
3987 dependsOn jalviewjsBuildAllCores
3988 dependsOn jalviewjsPublishCoreTemplates
3989 def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjsTransferSiteCoreDir}")
3990 def outputDir = "${jalviewDir}/${jalviewjsSiteDir}"
3994 def outputFiles = []
3995 rename { filename ->
3996 outputFiles += "${outputDir}/${filename}"
4002 outputs.files outputFiles
4003 inputs.files inputFiles
4007 // this Copy version of TransferSiteJs will delete anything else in the target dir
4008 task jalviewjsCopyTransferSiteJs(type: Copy) {
4009 dependsOn jalviewjsTranspile
4010 from "${jalviewDir}/${jalviewjsTransferSiteJsDir}"
4011 into "${jalviewDir}/${jalviewjsSiteDir}"
4015 // this Sync version of TransferSite is used by buildship to keep the website automatically up to date when a file changes
4016 task jalviewjsSyncTransferSiteJs(type: Sync) {
4017 from "${jalviewDir}/${jalviewjsTransferSiteJsDir}"
4019 into "${jalviewDir}/${jalviewjsSiteDir}"
4026 jalviewjsSyncAllLibs.mustRunAfter jalviewjsCopyTransferSiteJs
4027 jalviewjsSyncResources.mustRunAfter jalviewjsCopyTransferSiteJs
4028 jalviewjsSyncSiteResources.mustRunAfter jalviewjsCopyTransferSiteJs
4029 jalviewjsSyncBuildProperties.mustRunAfter jalviewjsCopyTransferSiteJs
4031 jalviewjsSyncAllLibs.mustRunAfter jalviewjsSyncTransferSiteJs
4032 jalviewjsSyncResources.mustRunAfter jalviewjsSyncTransferSiteJs
4033 jalviewjsSyncSiteResources.mustRunAfter jalviewjsSyncTransferSiteJs
4034 jalviewjsSyncBuildProperties.mustRunAfter jalviewjsSyncTransferSiteJs
4037 task jalviewjsPrepareSite {
4039 description "Prepares the website folder including unzipping files and copying resources"
4040 dependsOn jalviewjsSyncAllLibs
4041 dependsOn jalviewjsSyncResources
4042 dependsOn jalviewjsSyncSiteResources
4043 dependsOn jalviewjsSyncBuildProperties
4044 dependsOn jalviewjsSyncCore
4048 task jalviewjsBuildSite {
4050 description "Builds the whole website including transpiled code"
4051 dependsOn jalviewjsCopyTransferSiteJs
4052 dependsOn jalviewjsPrepareSite
4056 task cleanJalviewjsTransferSite {
4058 delete "${jalviewDir}/${jalviewjsTransferSiteJsDir}"
4059 delete "${jalviewDir}/${jalviewjsTransferSiteLibDir}"
4060 delete "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}"
4061 delete "${jalviewDir}/${jalviewjsTransferSiteCoreDir}"
4066 task cleanJalviewjsSite {
4067 dependsOn cleanJalviewjsTransferSite
4069 delete "${jalviewDir}/${jalviewjsSiteDir}"
4074 task jalviewjsSiteTar(type: Tar) {
4076 description "Creates a tar.gz file for the website"
4077 dependsOn jalviewjsBuildSite
4078 def outputFilename = "jalviewjs-site-${JALVIEW_VERSION}.tar.gz"
4079 archiveFileName = outputFilename
4081 compression Compression.GZIP
4083 from "${jalviewDir}/${jalviewjsSiteDir}"
4084 into jalviewjs_site_dir // this is inside the tar file
4086 inputs.dir("${jalviewDir}/${jalviewjsSiteDir}")
4090 task jalviewjsServer {
4092 def filename = "jalviewjsTest.html"
4093 description "Starts a webserver on localhost to test the website. See ${filename} to access local site on most recently used port."
4094 def htmlFile = "${jalviewDirAbsolutePath}/${filename}"
4099 def f = Class.forName("org.gradle.plugins.javascript.envjs.http.simple.SimpleHttpFileServerFactory")
4100 factory = f.newInstance()
4101 } catch (ClassNotFoundException e) {
4102 throw new GradleException("Unable to create SimpleHttpFileServerFactory")
4104 def port = Integer.valueOf(jalviewjs_server_port)
4109 while(port < start+1000 && !running) {
4111 def doc_root = new File("${jalviewDirAbsolutePath}/${jalviewjsSiteDir}")
4112 jalviewjsServer = factory.start(doc_root, port)
4114 url = jalviewjsServer.getResourceUrl(jalviewjs_server_resource)
4115 println("SERVER STARTED with document root ${doc_root}.")
4116 println("Go to "+url+" . Run gradle --stop to stop (kills all gradle daemons).")
4117 println("For debug: "+url+"?j2sdebug")
4118 println("For verbose: "+url+"?j2sverbose")
4119 } catch (Exception e) {
4124 <p><a href="${url}">JalviewJS Test. <${url}></a></p>
4125 <p><a href="${url}?j2sdebug">JalviewJS Test with debug. <${url}?j2sdebug></a></p>
4126 <p><a href="${url}?j2sverbose">JalviewJS Test with verbose. <${url}?j2sdebug></a></p>
4128 jalviewjsCoreClasslists.each { cl ->
4129 def urlcore = jalviewjsServer.getResourceUrl(file(cl.outputfile).getName())
4131 <p><a href="${urlcore}">${jalviewjsJalviewTemplateName} [core ${cl.name}]. <${urlcore}></a></p>
4133 println("For core ${cl.name}: "+urlcore)
4136 file(htmlFile).text = htmlText
4139 outputs.file(htmlFile)
4140 outputs.upToDateWhen({false})
4144 task cleanJalviewjsAll {
4146 description "Delete all configuration and build artifacts to do with JalviewJS build"
4147 dependsOn cleanJalviewjsSite
4148 dependsOn jalviewjsEclipsePaths
4151 delete "${jalviewDir}/${jalviewjsBuildDir}"
4152 delete "${jalviewDir}/${eclipse_bin_dir}"
4153 if (eclipseWorkspace != null && file(eclipseWorkspace.getAbsolutePath()+"/.metadata").exists()) {
4154 delete file(eclipseWorkspace.getAbsolutePath()+"/.metadata")
4156 delete jalviewjsJ2sAltSettingsFileName
4159 outputs.upToDateWhen( { false } )
4163 task jalviewjsIDE_checkJ2sPlugin {
4164 group "00 JalviewJS in Eclipse"
4165 description "Compare the swingjs/net.sf.j2s.core(-j11)?.jar file with the Eclipse IDE's plugin version (found in the 'dropins' dir)"
4168 def j2sPlugin = string("${jalviewDir}/${jalviewjsJ2sPlugin}")
4169 def j2sPluginFile = file(j2sPlugin)
4170 def eclipseHome = System.properties["eclipse.home.location"]
4171 if (eclipseHome == null || ! IN_ECLIPSE) {
4172 throw new StopExecutionException("Cannot find running Eclipse home from System.properties['eclipse.home.location']. Skipping J2S Plugin Check.")
4174 def eclipseJ2sPluginDirs = [ "${eclipseHome}/dropins" ]
4175 def altPluginsDir = System.properties["org.eclipse.equinox.p2.reconciler.dropins.directory"]
4176 if (altPluginsDir != null && file(altPluginsDir).exists()) {
4177 eclipseJ2sPluginDirs += altPluginsDir
4179 def foundPlugin = false
4180 def j2sPluginFileName = j2sPluginFile.getName()
4181 def eclipseJ2sPlugin
4182 def eclipseJ2sPluginFile
4183 eclipseJ2sPluginDirs.any { dir ->
4184 eclipseJ2sPlugin = "${dir}/${j2sPluginFileName}"
4185 eclipseJ2sPluginFile = file(eclipseJ2sPlugin)
4186 if (eclipseJ2sPluginFile.exists()) {
4192 def msg = "Eclipse J2S Plugin is not installed (could not find '${j2sPluginFileName}' in\n"+eclipseJ2sPluginDirs.join("\n")+"\n)\nTry running task jalviewjsIDE_copyJ2sPlugin"
4193 System.err.println(msg)
4194 throw new StopExecutionException(msg)
4197 def digest = MessageDigest.getInstance("MD5")
4199 digest.update(j2sPluginFile.text.bytes)
4200 def j2sPluginMd5 = new BigInteger(1, digest.digest()).toString(16).padLeft(32, '0')
4202 digest.update(eclipseJ2sPluginFile.text.bytes)
4203 def eclipseJ2sPluginMd5 = new BigInteger(1, digest.digest()).toString(16).padLeft(32, '0')
4205 if (j2sPluginMd5 != eclipseJ2sPluginMd5) {
4206 def msg = "WARNING! Eclipse J2S Plugin '${eclipseJ2sPlugin}' is different to this commit's version '${j2sPlugin}'"
4207 System.err.println(msg)
4208 throw new StopExecutionException(msg)
4210 def msg = "Eclipse J2S Plugin '${eclipseJ2sPlugin}' is the same as '${j2sPlugin}' (this is good)"
4216 task jalviewjsIDE_copyJ2sPlugin {
4217 group "00 JalviewJS in Eclipse"
4218 description "Copy the swingjs/net.sf.j2s.core(-j11)?.jar file into the Eclipse IDE's 'dropins' dir"
4221 def j2sPlugin = string("${jalviewDir}/${jalviewjsJ2sPlugin}")
4222 def j2sPluginFile = file(j2sPlugin)
4223 def eclipseHome = System.properties["eclipse.home.location"]
4224 if (eclipseHome == null || ! IN_ECLIPSE) {
4225 throw new StopExecutionException("Cannot find running Eclipse home from System.properties['eclipse.home.location']. NOT copying J2S Plugin.")
4227 def eclipseJ2sPlugin = "${eclipseHome}/dropins/${j2sPluginFile.getName()}"
4228 def eclipseJ2sPluginFile = file(eclipseJ2sPlugin)
4229 def msg = "WARNING! Copying this commit's j2s plugin '${j2sPlugin}' to Eclipse J2S Plugin '${eclipseJ2sPlugin}'\n* May require an Eclipse restart"
4230 System.err.println(msg)
4233 eclipseJ2sPluginFile.getParentFile().mkdirs()
4234 into eclipseJ2sPluginFile.getParent()
4240 task jalviewjsIDE_j2sFile {
4241 group "00 JalviewJS in Eclipse"
4242 description "Creates the .j2s file"
4243 dependsOn jalviewjsCreateJ2sSettings
4247 task jalviewjsIDE_SyncCore {
4248 group "00 JalviewJS in Eclipse"
4249 description "Build the core js lib closures listed in the classlists dir and publish core html from template"
4250 dependsOn jalviewjsSyncCore
4254 task jalviewjsIDE_SyncSiteAll {
4255 dependsOn jalviewjsSyncAllLibs
4256 dependsOn jalviewjsSyncResources
4257 dependsOn jalviewjsSyncSiteResources
4258 dependsOn jalviewjsSyncBuildProperties
4262 cleanJalviewjsTransferSite.mustRunAfter jalviewjsIDE_SyncSiteAll
4265 task jalviewjsIDE_PrepareSite {
4266 group "00 JalviewJS in Eclipse"
4267 description "Sync libs and resources to site dir, but not closure cores"
4269 dependsOn jalviewjsIDE_SyncSiteAll
4270 //dependsOn cleanJalviewjsTransferSite // not sure why this clean is here -- will slow down a re-run of this task
4274 task jalviewjsIDE_AssembleSite {
4275 group "00 JalviewJS in Eclipse"
4276 description "Assembles unzipped supporting zipfiles, resources, site resources and closure cores into the Eclipse transpiled site"
4277 dependsOn jalviewjsPrepareSite
4281 task jalviewjsIDE_SiteClean {
4282 group "00 JalviewJS in Eclipse"
4283 description "Deletes the Eclipse transpiled site"
4284 dependsOn cleanJalviewjsSite
4288 task jalviewjsIDE_Server {
4289 group "00 JalviewJS in Eclipse"
4290 description "Starts a webserver on localhost to test the website"
4291 dependsOn jalviewjsServer
4295 // buildship runs this at import or gradle refresh
4296 task eclipseSynchronizationTask {
4297 //dependsOn eclipseSetup
4298 dependsOn createBuildProperties
4300 dependsOn jalviewjsIDE_j2sFile
4301 dependsOn jalviewjsIDE_checkJ2sPlugin
4302 dependsOn jalviewjsIDE_PrepareSite
4307 // buildship runs this at build time or project refresh
4308 task eclipseAutoBuildTask {
4309 //dependsOn jalviewjsIDE_checkJ2sPlugin
4310 //dependsOn jalviewjsIDE_PrepareSite
4314 task jalviewjsCopyStderrLaunchFile(type: Copy) {
4315 from file(jalviewjs_stderr_launch)
4316 into jalviewjsSiteDir
4318 inputs.file jalviewjs_stderr_launch
4319 outputs.file jalviewjsStderrLaunchFilename
4322 task cleanJalviewjsChromiumUserDir {
4324 delete jalviewjsChromiumUserDir
4326 outputs.dir jalviewjsChromiumUserDir
4327 // always run when depended on
4328 outputs.upToDateWhen { !file(jalviewjsChromiumUserDir).exists() }
4331 task jalviewjsChromiumProfile {
4332 dependsOn cleanJalviewjsChromiumUserDir
4333 mustRunAfter cleanJalviewjsChromiumUserDir
4335 def firstRun = file("${jalviewjsChromiumUserDir}/First Run")
4338 mkdir jalviewjsChromiumProfileDir
4341 outputs.file firstRun
4344 task jalviewjsLaunchTest {
4346 description "Check JalviewJS opens in a browser"
4347 dependsOn jalviewjsBuildSite
4348 dependsOn jalviewjsCopyStderrLaunchFile
4349 dependsOn jalviewjsChromiumProfile
4351 def macOS = OperatingSystem.current().isMacOsX()
4352 def chromiumBinary = macOS ? jalviewjs_macos_chromium_binary : jalviewjs_chromium_binary
4353 if (chromiumBinary.startsWith("~/")) {
4354 chromiumBinary = System.getProperty("user.home") + chromiumBinary.substring(1)
4360 def timeoutms = Integer.valueOf(jalviewjs_chromium_overall_timeout) * 1000
4362 def binary = file(chromiumBinary)
4363 if (!binary.exists()) {
4364 throw new StopExecutionException("Could not find chromium binary '${chromiumBinary}'. Cannot run task ${name}.")
4366 stdout = new ByteArrayOutputStream()
4367 stderr = new ByteArrayOutputStream()
4370 if (jalviewjs_j2s_to_console.equals("true")) {
4371 execStdout = new org.apache.tools.ant.util.TeeOutputStream(
4374 execStderr = new org.apache.tools.ant.util.TeeOutputStream(
4382 "--no-sandbox", // --no-sandbox IS USED BY THE THORIUM APPIMAGE ON THE BUILDSERVER
4385 "--timeout=${timeoutms}",
4386 "--virtual-time-budget=${timeoutms}",
4387 "--user-data-dir=${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_chromium_user_dir}",
4388 "--profile-directory=${jalviewjs_chromium_profile_name}",
4389 "--allow-file-access-from-files",
4390 "--enable-logging=stderr",
4391 "file://${jalviewDirAbsolutePath}/${jalviewjsStderrLaunchFilename}"
4394 if (true || macOS) {
4395 ScheduledExecutorService executor = Executors.newScheduledThreadPool(3);
4396 Future f1 = executor.submit(
4399 standardOutput = execStdout
4400 errorOutput = execStderr
4401 executable(chromiumBinary)
4403 println "COMMAND: '"+commandLine.join(" ")+"'"
4405 executor.shutdownNow()
4409 def noChangeBytes = 0
4410 def noChangeIterations = 0
4411 executor.scheduleAtFixedRate(
4413 String stderrString = stderr.toString()
4414 // shutdown the task if we have a success string
4415 if (stderrString.contains(jalviewjs_desktop_init_string)) {
4418 executor.shutdownNow()
4420 // if no change in stderr for 10s then also end
4421 if (noChangeIterations >= jalviewjs_chromium_idle_timeout) {
4422 executor.shutdownNow()
4424 if (stderrString.length() == noChangeBytes) {
4425 noChangeIterations++
4427 noChangeBytes = stderrString.length()
4428 noChangeIterations = 0
4431 1, 1, TimeUnit.SECONDS)
4433 executor.schedule(new Runnable(){
4436 executor.shutdownNow()
4438 }, timeoutms, TimeUnit.MILLISECONDS)
4440 executor.awaitTermination(timeoutms+10000, TimeUnit.MILLISECONDS)
4441 executor.shutdownNow()
4448 stderr.toString().eachLine { line ->
4449 if (line.contains(jalviewjs_desktop_init_string)) {
4450 println("Found line '"+line+"'")
4456 throw new GradleException("Could not find evidence of Desktop launch in JalviewJS.")
4464 description "Build the JalviewJS site and run the launch test"
4465 dependsOn jalviewjsBuildSite
4466 dependsOn jalviewjsLaunchTest