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 install4jDMGDSStoreJSON = "${install4j_images_dir}/${install4j_dmg_ds_store_json}"
239 install4jDMGBackgroundImageDir = "${install4j_images_dir}"
240 install4jDMGBackgroundImageBuildDir = "build/imagemagick/install4j"
241 install4jDMGBackgroundImageFile = "${install4j_dmg_background}"
242 install4jmacOSArchiveName = "${jalview_name} Non-Release ${JALVIEW_VERSION} Installer"
243 install4jExecutableName = install4j_executable_name
244 install4jExtraScheme = "jalviewextra"
245 install4jMacIconsFile = string("${install4j_images_dir}/${install4j_mac_icons_file}")
246 install4jWindowsIconsFile = string("${install4j_images_dir}/${install4j_windows_icons_file}")
247 install4jPngIconFile = string("${install4j_images_dir}/${install4j_png_icon_file}")
248 install4jBackground = string("${install4j_images_dir}/${install4j_background}")
249 install4jBuildDir = "${install4j_build_dir}/${JAVA_VERSION}"
250 install4jDMGFixedDSStore = "${install4jBuildDir}/${install4j_dmg_ds_store}"
251 install4jCheckSums = true
253 applicationName = "${jalview_name}"
257 // TODO: get bamboo build artifact URL for getdown artifacts
258 getdown_channel_base = bamboo_channelbase
259 getdownChannelName = string("${bamboo_planKey}/${JAVA_VERSION}")
260 getdownAppBase = string("${bamboo_channelbase}/${bamboo_planKey}${bamboo_getdown_channel_suffix}/${JAVA_VERSION}")
261 jvlChannelName += "_${getdownChannelName}"
262 // automatically add the test group Not-bamboo for exclusion
263 if ("".equals(testng_excluded_groups)) {
264 testng_excluded_groups = "Not-bamboo"
266 install4jExtraScheme = "jalviewb"
267 backgroundImageText = true
270 case [ "RELEASE", "JALVIEWJS-RELEASE" ]:
271 getdownAppDistDir = getdown_app_dir_release
272 getdownSetAppBaseProperty = true
273 reportRsyncCommand = true
275 install4jmacOSArchiveName = "Install ${jalview_name} ${JALVIEW_VERSION}"
276 install4jExtraScheme = (CHANNEL=="RELEASE")?"jalviewx":"jalviewjs"
280 getdownChannelName = CHANNEL.toLowerCase()+"/${JALVIEW_VERSION}"
281 getdownDir = string("${getdownChannelName}/${JAVA_VERSION}")
282 getdownAppBase = string("${getdown_channel_base}/${getdownDir}")
283 if (!file("${ARCHIVEDIR}/${package_dir}").exists()) {
284 throw new GradleException("Must provide an ARCHIVEDIR value to produce an archive distribution")
286 package_dir = string("${ARCHIVEDIR}/${package_dir}")
287 buildProperties = string("${ARCHIVEDIR}/${classes_dir}/${build_properties_file}")
290 reportRsyncCommand = true
291 install4jExtraScheme = "jalviewa"
295 getdownChannelName = string("archive/${JALVIEW_VERSION}")
296 getdownDir = string("${getdownChannelName}/${JAVA_VERSION}")
297 getdownAppBase = file(getdownAppBaseDir).toURI().toString()
298 if (!file("${ARCHIVEDIR}/${package_dir}").exists()) {
299 throw new GradleException("Must provide an ARCHIVEDIR value to produce an archive distribution [did not find '${ARCHIVEDIR}/${package_dir}']")
301 package_dir = string("${ARCHIVEDIR}/${package_dir}")
302 buildProperties = string("${ARCHIVEDIR}/${classes_dir}/${build_properties_file}")
305 reportRsyncCommand = true
306 getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher_local}")
307 install4jSuffix = "Archive"
308 install4jExtraScheme = "jalviewa"
311 case ~/^DEVELOP-([\.\-\w]*)$/:
312 def suffix = Matcher.lastMatcher[0][1]
313 reportRsyncCommand = true
314 getdownSetAppBaseProperty = true
315 JALVIEW_VERSION=JALVIEW_VERSION+"-d${suffix}-${buildDate}"
316 install4jSuffix = "Develop ${suffix}"
317 install4jExtraScheme = "jalviewd"
318 install4jmacOSArchiveName = "Install ${jalview_name} Develop ${suffix} ${JALVIEW_VERSION}"
319 getdownChannelName = string("develop-${suffix}")
320 getdownChannelDir = string("${getdown_website_dir}/${getdownChannelName}")
321 getdownAppBaseDir = string("${jalviewDir}/${getdownChannelDir}/${JAVA_VERSION}")
322 getdownDir = string("${getdownChannelName}/${JAVA_VERSION}")
323 getdownAppBase = string("${getdown_channel_base}/${getdownDir}")
324 channelSuffix = string(suffix)
325 backgroundImageText = true
329 reportRsyncCommand = true
330 getdownSetAppBaseProperty = true
331 // DEVELOP-RELEASE is usually associated with a Jalview release series so set the version
332 JALVIEW_VERSION=JALVIEW_VERSION+"-d${buildDate}"
334 install4jSuffix = "Develop"
335 install4jExtraScheme = "jalviewd"
336 install4jmacOSArchiveName = "Install ${jalview_name} Develop ${JALVIEW_VERSION}"
337 backgroundImageText = true
341 reportRsyncCommand = true
342 getdownSetAppBaseProperty = true
343 // Don't ignore transpile errors for release build
344 if (jalviewjs_ignore_transpile_errors.equals("true")) {
345 jalviewjs_ignore_transpile_errors = "false"
346 println("Setting jalviewjs_ignore_transpile_errors to 'false'")
348 JALVIEW_VERSION = JALVIEW_VERSION+"-test"
349 install4jSuffix = "Test"
350 install4jExtraScheme = "jalviewt"
351 install4jmacOSArchiveName = "Install ${jalview_name} Test ${JALVIEW_VERSION}"
352 backgroundImageText = true
355 case ~/^SCRATCH(|-[-\w]*)$/:
356 getdownChannelName = CHANNEL
357 JALVIEW_VERSION = JALVIEW_VERSION+"-"+CHANNEL
359 getdownDir = string("${getdownChannelName}/${JAVA_VERSION}")
360 getdownAppBase = string("${getdown_channel_base}/${getdownDir}")
361 reportRsyncCommand = true
362 install4jSuffix = "Scratch"
366 if (!file("${LOCALDIR}").exists()) {
367 throw new GradleException("Must provide a LOCALDIR value to produce a local distribution")
369 getdownAppBase = file(file("${LOCALDIR}").getAbsolutePath()).toURI().toString()
370 getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher_local}")
372 JALVIEW_VERSION = "TEST"
373 install4jSuffix = "Test-Local"
374 install4jExtraScheme = "jalviewt"
375 install4jmacOSArchiveName = "Install ${jalview_name} Test ${JALVIEW_VERSION}"
376 backgroundImageText = true
379 case [ "LOCAL", "JALVIEWJS" ]:
380 JALVIEW_VERSION = "TEST"
381 getdownAppBase = file(getdownAppBaseDir).toURI().toString()
382 getdownArchiveAppBase = file("${jalviewDir}/${getdown_archive_dir}").toURI().toString()
383 getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher_local}")
384 install4jExtraScheme = "jalviewl"
385 install4jCheckSums = false
388 default: // something wrong specified
389 throw new GradleException("CHANNEL must be one of BUILD, RELEASE, ARCHIVE, DEVELOP, TEST-RELEASE, SCRATCH-..., LOCAL [default]")
393 JALVIEW_VERSION_UNDERSCORES = JALVIEW_VERSION.replaceAll("\\.", "_")
394 hugoDataJsonFile = file("${jalviewDir}/${hugo_build_dir}/${hugo_data_installers_dir}/installers-${JALVIEW_VERSION_UNDERSCORES}.json")
395 hugoArchiveMdFile = file("${jalviewDir}/${hugo_build_dir}/${hugo_version_archive_dir}/Version-${JALVIEW_VERSION_UNDERSCORES}/_index.md")
396 // override getdownAppBase if requested
397 if (findProperty("getdown_appbase_override") != null) {
398 // revert to LOCAL if empty string
399 if (string(getdown_appbase_override) == "") {
400 getdownAppBase = file(getdownAppBaseDir).toURI().toString()
401 getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher_local}")
402 } else if (string(getdown_appbase_override).startsWith("file://")) {
403 getdownAppBase = string(getdown_appbase_override)
404 getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher_local}")
406 getdownAppBase = string(getdown_appbase_override)
408 println("Overriding getdown appbase with '${getdownAppBase}'")
410 // sanitise file name for jalview launcher file for this channel
411 jvlChannelName = jvlChannelName.replaceAll("[^\\w\\-]+", "_")
412 // install4j application and folder names
413 if (install4jSuffix == "") {
414 install4jBundleId = "${install4j_bundle_id}"
415 install4jWinApplicationId = install4j_release_win_application_id
417 applicationName = "${jalview_name} ${install4jSuffix}"
418 install4jBundleId = "${install4j_bundle_id}-" + install4jSuffix.toLowerCase()
419 // add int hash of install4jSuffix to the last part of the application_id
420 def id = install4j_release_win_application_id
421 def idsplitreverse = id.split("-").reverse()
422 idsplitreverse[0] = idsplitreverse[0].toInteger() + install4jSuffix.hashCode()
423 install4jWinApplicationId = idsplitreverse.reverse().join("-")
425 // sanitise folder and id names
426 // install4jApplicationFolder = e.g. "Jalview Build"
427 install4jApplicationFolder = applicationName
428 .replaceAll("[\"'~:/\\\\\\s]", "_") // replace all awkward filename chars " ' ~ : / \
429 .replaceAll("_+", "_") // collapse __
430 install4jInternalId = applicationName
432 .replaceAll("[^\\w\\-\\.]", "_") // replace other non [alphanumeric,_,-,.]
433 .replaceAll("_+", "") // collapse __
434 //.replaceAll("_*-_*", "-") // collapse _-_
435 install4jUnixApplicationFolder = applicationName
437 .replaceAll("[^\\w\\-\\.]", "_") // replace other non [alphanumeric,_,-,.]
438 .replaceAll("_+", "_") // collapse __
439 .replaceAll("_*-_*", "-") // collapse _-_
441 install4jmacOSArchiveX86Name = "${install4jmacOSArchiveName} (Intel)"
442 install4jmacOSArchiveAarch64Name = "${install4jmacOSArchiveName} (Apple Silicon)"
444 getdownWrapperLink = install4jUnixApplicationFolder // e.g. "jalview_local"
445 getdownAppDir = string("${getdownAppBaseDir}/${getdownAppDistDir}")
446 //getdownJ11libDir = "${getdownAppBaseDir}/${getdown_j11lib_dir}"
447 getdownResourceDir = string("${getdownAppBaseDir}/${getdown_resource_dir}")
448 getdownInstallDir = string("${getdownAppBaseDir}/${getdown_install_dir}")
449 getdownFilesDir = string("${jalviewDir}/${getdown_files_dir}/${JAVA_VERSION}/")
450 getdownFilesInstallDir = string("${getdownFilesDir}/${getdown_install_dir}")
451 /* compile without modules -- using classpath libraries
452 modules_compileClasspath = fileTree(dir: "${jalviewDir}/${j11modDir}", include: ["*.jar"])
453 modules_runtimeClasspath = modules_compileClasspath
459 apply plugin: "com.palantir.git-version"
460 def details = versionDetails()
461 gitHash = details.gitHash
462 gitBranch = details.branchName
463 } catch(org.gradle.api.internal.plugins.PluginApplicationException e) {
464 println("Not in a git repository. Using git values from RELEASE properties file.")
465 gitHash = releaseProps.getProperty("git.hash")
466 gitBranch = releaseProps.getProperty("git.branch")
467 } catch(java.lang.RuntimeException e1) {
468 throw new GradleException("Error with git-version plugin. Directory '.git' exists but versionDetails() cannot be found.")
471 println("Using a ${CHANNEL} profile.")
473 additional_compiler_args = []
474 // configure classpath/args for j8/j11 compilation
475 if (JAVA_VERSION.equals("1.8")) {
476 JAVA_INTEGER_VERSION = string("8")
479 libDistDir = j8libDir
480 compile_source_compatibility = 1.8
481 compile_target_compatibility = 1.8
482 // these are getdown.txt properties defined dependent on the JAVA_VERSION
483 getdownAltJavaMinVersion = string(findProperty("getdown_alt_java8_min_version"))
484 getdownAltJavaMaxVersion = string(findProperty("getdown_alt_java8_max_version"))
485 // this property is assigned below and expanded to multiple lines in the getdown task
486 getdownAltMultiJavaLocation = string(findProperty("getdown_alt_java8_txt_multi_java_location"))
487 // this property is for the Java library used in eclipse
488 eclipseJavaRuntimeName = string("JavaSE-1.8")
489 } else if (JAVA_VERSION.equals("11")) {
490 JAVA_INTEGER_VERSION = string("11")
492 libDistDir = j11libDir
493 compile_source_compatibility = 11
494 compile_target_compatibility = 11
495 getdownAltJavaMinVersion = string(findProperty("getdown_alt_java11_min_version"))
496 getdownAltJavaMaxVersion = string(findProperty("getdown_alt_java11_max_version"))
497 getdownAltMultiJavaLocation = string(findProperty("getdown_alt_java11_txt_multi_java_location"))
498 eclipseJavaRuntimeName = string("JavaSE-11")
499 /* compile without modules -- using classpath libraries
500 additional_compiler_args += [
501 '--module-path', modules_compileClasspath.asPath,
502 '--add-modules', j11modules
505 } else if (JAVA_VERSION.equals("17")) {
506 JAVA_INTEGER_VERSION = string("17")
508 libDistDir = j17libDir
509 compile_source_compatibility = 17
510 compile_target_compatibility = 17
511 getdownAltJavaMinVersion = string(findProperty("getdown_alt_java11_min_version"))
512 getdownAltJavaMaxVersion = string(findProperty("getdown_alt_java11_max_version"))
513 getdownAltMultiJavaLocation = string(findProperty("getdown_alt_java11_txt_multi_java_location"))
514 eclipseJavaRuntimeName = string("JavaSE-17")
515 /* compile without modules -- using classpath libraries
516 additional_compiler_args += [
517 '--module-path', modules_compileClasspath.asPath,
518 '--add-modules', j11modules
522 throw new GradleException("JAVA_VERSION=${JAVA_VERSION} not currently supported by Jalview")
527 JAVA_MIN_VERSION = JAVA_VERSION
528 JAVA_MAX_VERSION = JAVA_VERSION
529 jreInstallsDir = string(jre_installs_dir)
530 if (jreInstallsDir.startsWith("~/")) {
531 jreInstallsDir = System.getProperty("user.home") + jreInstallsDir.substring(1)
533 install4jDir = string("${jalviewDir}/${install4j_utils_dir}")
534 install4jConfFileName = string("jalview-install4j-conf.install4j")
535 install4jConfFile = file("${install4jDir}/${install4jConfFileName}")
536 install4jHomeDir = install4j_home_dir
537 if (install4jHomeDir.startsWith("~/")) {
538 install4jHomeDir = System.getProperty("user.home") + install4jHomeDir.substring(1)
541 resourceBuildDir = string("${buildDir}/resources")
542 resourcesBuildDir = string("${resourceBuildDir}/resources_build")
543 helpBuildDir = string("${resourceBuildDir}/help_build")
544 docBuildDir = string("${resourceBuildDir}/doc_build")
546 if (buildProperties == null) {
547 buildProperties = string("${resourcesBuildDir}/${build_properties_file}")
549 buildingHTML = string("${jalviewDir}/${doc_dir}/building.html")
550 helpParentDir = string("${jalviewDir}/${help_parent_dir}")
551 helpSourceDir = string("${helpParentDir}/${help_dir}")
552 helpFile = string("${helpBuildDir}/${help_dir}/help.jhm")
555 convertBinaryExpectedLocation = imagemagick_convert
556 if (convertBinaryExpectedLocation.startsWith("~/")) {
557 convertBinaryExpectedLocation = System.getProperty("user.home") + convertBinaryExpectedLocation.substring(1)
559 if (file(convertBinaryExpectedLocation).exists()) {
560 convertBinary = convertBinaryExpectedLocation
563 relativeBuildDir = file(jalviewDirAbsolutePath).toPath().relativize(buildDir.toPath())
564 jalviewjsBuildDir = string("${relativeBuildDir}/jalviewjs")
565 jalviewjsSiteDir = string("${jalviewjsBuildDir}/${jalviewjs_site_dir}")
567 jalviewjsTransferSiteJsDir = string(jalviewjsSiteDir)
569 jalviewjsTransferSiteJsDir = string("${jalviewjsBuildDir}/tmp/${jalviewjs_site_dir}_js")
571 jalviewjsTransferSiteLibDir = string("${jalviewjsBuildDir}/tmp/${jalviewjs_site_dir}_lib")
572 jalviewjsTransferSiteSwingJsDir = string("${jalviewjsBuildDir}/tmp/${jalviewjs_site_dir}_swingjs")
573 jalviewjsTransferSiteCoreDir = string("${jalviewjsBuildDir}/tmp/${jalviewjs_site_dir}_core")
574 jalviewjsJalviewCoreHtmlFile = string("")
575 jalviewjsJalviewCoreName = string(jalviewjs_core_name)
576 jalviewjsCoreClasslists = []
577 jalviewjsJalviewTemplateName = string(jalviewjs_name)
578 jalviewjsJ2sSettingsFileName = string("${jalviewDir}/${jalviewjs_j2s_settings}")
579 jalviewjsJ2sAltSettingsFileName = string("${jalviewDir}/${jalviewjs_j2s_alt_settings}")
580 jalviewjsJ2sProps = null
581 jalviewjsJ2sPlugin = jalviewjs_j2s_plugin
582 jalviewjsStderrLaunchFilename = "${jalviewjsSiteDir}/"+(file(jalviewjs_stderr_launch).getName())
584 eclipseWorkspace = null
585 eclipseBinary = string("")
586 eclipseVersion = string("")
589 jalviewjsChromiumUserDir = "${jalviewjsBuildDir}/${jalviewjs_chromium_user_dir}"
590 jalviewjsChromiumProfileDir = "${ext.jalviewjsChromiumUserDir}/${jalviewjs_chromium_profile_name}"
600 outputDir = file(classesDir)
604 srcDirs = [ resourcesBuildDir, docBuildDir, helpBuildDir ]
607 compileClasspath = files(sourceSets.main.java.outputDir)
608 compileClasspath += fileTree(dir: "${jalviewDir}/${libDir}", include: ["*.jar"])
610 runtimeClasspath = compileClasspath
611 runtimeClasspath += files(sourceSets.main.resources.srcDirs)
616 srcDirs cloverInstrDir
617 outputDir = cloverClassesDir
621 srcDirs = sourceSets.main.resources.srcDirs
624 compileClasspath = files( sourceSets.clover.java.outputDir )
625 //compileClasspath += files( testClassesDir )
626 compileClasspath += fileTree(dir: "${jalviewDir}/${libDir}", include: ["*.jar"])
627 compileClasspath += fileTree(dir: "${jalviewDir}/${clover_lib_dir}", include: ["*.jar"])
628 compileClasspath += fileTree(dir: "${jalviewDir}/${utils_dir}/testnglibs", include: ["**/*.jar"])
630 runtimeClasspath = compileClasspath
635 srcDirs testSourceDir
636 outputDir = file(testClassesDir)
640 srcDirs = useClover ? sourceSets.clover.resources.srcDirs : sourceSets.main.resources.srcDirs
643 compileClasspath = files( sourceSets.test.java.outputDir )
644 compileClasspath += useClover ? sourceSets.clover.compileClasspath : sourceSets.main.compileClasspath
645 compileClasspath += fileTree(dir: "${jalviewDir}/${utils_dir}/testnglibs", include: ["**/*.jar"])
647 runtimeClasspath = compileClasspath
648 runtimeClasspath += files(sourceSets.test.resources.srcDirs)
654 // eclipse project and settings files creation, also used by buildship
657 name = eclipse_project_name
659 natures 'org.eclipse.jdt.core.javanature',
660 'org.eclipse.jdt.groovy.core.groovyNature',
661 'org.eclipse.buildship.core.gradleprojectnature'
663 buildCommand 'org.eclipse.jdt.core.javabuilder'
664 buildCommand 'org.eclipse.buildship.core.gradleprojectbuilder'
668 //defaultOutputDir = sourceSets.main.java.outputDir
669 configurations.each{ c->
670 if (c.isCanBeResolved()) {
671 minusConfigurations += [c]
675 plusConfigurations = [ ]
679 def removeTheseToo = []
680 HashMap<String, Boolean> alreadyAddedSrcPath = new HashMap<>();
681 cp.entries.each { entry ->
682 // This conditional removes all src classpathentries that a) have already been added or b) aren't "src" or "test".
683 // e.g. this removes the resources dir being copied into bin/main, bin/test AND bin/clover
684 // we add the resources and help/help dirs in as libs afterwards (see below)
685 if (entry.kind == 'src') {
686 if (alreadyAddedSrcPath.getAt(entry.path) || !(entry.path == bareSourceDir || entry.path == bareTestSourceDir)) {
687 removeTheseToo += entry
689 alreadyAddedSrcPath.putAt(entry.path, true)
694 cp.entries.removeAll(removeTheseToo)
696 //cp.entries += new Output("${eclipse_bin_dir}/main")
697 if (file(helpParentDir).isDirectory()) {
698 cp.entries += new Library(fileReference(helpParentDir))
700 if (file(resourceDir).isDirectory()) {
701 cp.entries += new Library(fileReference(resourceDir))
704 HashMap<String, Boolean> alreadyAddedLibPath = new HashMap<>();
706 sourceSets.main.compileClasspath.findAll { it.name.endsWith(".jar") }.any {
707 //don't want to add outputDir as eclipse is using its own output dir in bin/main
708 if (it.isDirectory() || ! it.exists()) {
709 // don't add dirs to classpath, especially if they don't exist
710 return false // groovy "continue" in .any closure
712 def itPath = it.toString()
713 if (itPath.startsWith("${jalviewDirAbsolutePath}/")) {
714 // make relative path
715 itPath = itPath.substring(jalviewDirAbsolutePath.length()+1)
717 if (alreadyAddedLibPath.get(itPath)) {
718 //println("Not adding duplicate entry "+itPath)
720 //println("Adding entry "+itPath)
721 cp.entries += new Library(fileReference(itPath))
722 alreadyAddedLibPath.put(itPath, true)
726 sourceSets.test.compileClasspath.findAll { it.name.endsWith(".jar") }.any {
727 //no longer want to add outputDir as eclipse is using its own output dir in bin/main
728 if (it.isDirectory() || ! it.exists()) {
729 // don't add dirs to classpath
730 return false // groovy "continue" in .any closure
733 def itPath = it.toString()
734 if (itPath.startsWith("${jalviewDirAbsolutePath}/")) {
735 itPath = itPath.substring(jalviewDirAbsolutePath.length()+1)
737 if (alreadyAddedLibPath.get(itPath)) {
740 def lib = new Library(fileReference(itPath))
741 lib.entryAttributes["test"] = "true"
743 alreadyAddedLibPath.put(itPath, true)
751 containers 'org.eclipse.buildship.core.gradleclasspathcontainer'
756 // for the IDE, use java 11 compatibility
757 sourceCompatibility = compile_source_compatibility
758 targetCompatibility = compile_target_compatibility
759 javaRuntimeName = eclipseJavaRuntimeName
761 // add in jalview project specific properties/preferences into eclipse core preferences
763 withProperties { props ->
764 def jalview_prefs = new Properties()
765 def ins = new FileInputStream("${jalviewDirAbsolutePath}/${eclipse_extra_jdt_prefs_file}")
766 jalview_prefs.load(ins)
768 jalview_prefs.forEach { t, v ->
769 if (props.getAt(t) == null) {
773 // codestyle file -- overrides previous formatter prefs
774 def csFile = file("${jalviewDirAbsolutePath}/${eclipse_codestyle_file}")
775 if (csFile.exists()) {
776 XmlParser parser = new XmlParser()
777 def profiles = parser.parse(csFile)
778 def profile = profiles.'profile'.find { p -> (p.'@kind' == "CodeFormatterProfile" && p.'@name' == "Jalview") }
779 if (profile != null) {
780 profile.'setting'.each { s ->
782 def value = s.'@value'
783 if (id != null && value != null) {
784 props.putAt(id, value)
795 // Don't want these to be activated if in headless build
796 synchronizationTasks "eclipseSynchronizationTask"
797 //autoBuildTasks "eclipseAutoBuildTask"
803 /* hack to change eclipse prefs in .settings files other than org.eclipse.jdt.core.prefs */
804 // Class to allow updating arbitrary properties files
805 class PropertiesFile extends PropertiesPersistableConfigurationObject {
806 public PropertiesFile(PropertiesTransformer t) { super(t); }
807 @Override protected void load(Properties properties) { }
808 @Override protected void store(Properties properties) { }
809 @Override protected String getDefaultResourceName() { return ""; }
810 // This is necessary, because PropertiesPersistableConfigurationObject fails
811 // if no default properties file exists.
812 @Override public void loadDefaults() { load(new StringBufferInputStream("")); }
815 // Task to update arbitrary properties files (set outputFile)
816 class PropertiesFileTask extends PropertiesGeneratorTask<PropertiesFile> {
817 private final PropertiesFileContentMerger file;
818 public PropertiesFileTask() { file = new PropertiesFileContentMerger(getTransformer()); }
819 protected PropertiesFile create() { return new PropertiesFile(getTransformer()); }
820 protected void configure(PropertiesFile props) {
821 file.getBeforeMerged().execute(props); file.getWhenMerged().execute(props);
823 public void file(Closure closure) { ConfigureUtil.configure(closure, file); }
826 task eclipseUIPreferences(type: PropertiesFileTask) {
827 description = "Generate Eclipse additional settings"
828 def filename = "org.eclipse.jdt.ui.prefs"
829 outputFile = "$projectDir/.settings/${filename}" as File
832 it.load new FileInputStream("$projectDir/utils/eclipse/${filename}" as String)
837 task eclipseGroovyCorePreferences(type: PropertiesFileTask) {
838 description = "Generate Eclipse additional settings"
839 def filename = "org.eclipse.jdt.groovy.core.prefs"
840 outputFile = "$projectDir/.settings/${filename}" as File
843 it.load new FileInputStream("$projectDir/utils/eclipse/${filename}" as String)
848 task eclipseAllPreferences {
850 dependsOn eclipseUIPreferences
851 dependsOn eclipseGroovyCorePreferences
854 eclipseUIPreferences.mustRunAfter eclipseJdt
855 eclipseGroovyCorePreferences.mustRunAfter eclipseJdt
857 /* end of eclipse preferences hack */
865 delete cloverBuildDir
866 delete cloverReportDir
871 task cloverInstrJava(type: JavaExec) {
872 group = "Verification"
873 description = "Create clover instrumented source java files"
875 dependsOn cleanClover
877 inputs.files(sourceSets.main.allJava)
878 outputs.dir(cloverInstrDir)
880 //classpath = fileTree(dir: "${jalviewDir}/${clover_lib_dir}", include: ["*.jar"])
881 classpath = sourceSets.clover.compileClasspath
882 main = "com.atlassian.clover.CloverInstr"
890 cloverInstrDir.getPath(),
892 def srcFiles = sourceSets.main.allJava.files
895 { file -> file.absolutePath }
898 args argsList.toArray()
901 delete cloverInstrDir
902 println("Clover: About to instrument "+srcFiles.size() +" files")
907 task cloverInstrTests(type: JavaExec) {
908 group = "Verification"
909 description = "Create clover instrumented source test files"
911 dependsOn cleanClover
913 inputs.files(testDir)
914 outputs.dir(cloverTestInstrDir)
916 classpath = sourceSets.clover.compileClasspath
917 main = "com.atlassian.clover.CloverInstr"
927 cloverTestInstrDir.getPath(),
929 args argsList.toArray()
932 delete cloverTestInstrDir
933 println("Clover: About to instrument test files")
939 group = "Verification"
940 description = "Create clover instrumented all source files"
942 dependsOn cloverInstrJava
943 dependsOn cloverInstrTests
947 cloverClasses.dependsOn cloverInstr
950 task cloverConsoleReport(type: JavaExec) {
951 group = "Verification"
952 description = "Creates clover console report"
955 file(cloverDb).exists()
958 inputs.dir cloverClassesDir
960 classpath = sourceSets.clover.runtimeClasspath
961 main = "com.atlassian.clover.reporters.console.ConsoleReporter"
963 if (cloverreport_mem.length() > 0) {
964 maxHeapSize = cloverreport_mem
966 if (cloverreport_jvmargs.length() > 0) {
967 jvmArgs Arrays.asList(cloverreport_jvmargs.split(" "))
977 args argsList.toArray()
981 task cloverHtmlReport(type: JavaExec) {
982 group = "Verification"
983 description = "Creates clover HTML report"
986 file(cloverDb).exists()
989 def cloverHtmlDir = cloverReportDir
990 inputs.dir cloverClassesDir
991 outputs.dir cloverHtmlDir
993 classpath = sourceSets.clover.runtimeClasspath
994 main = "com.atlassian.clover.reporters.html.HtmlReporter"
996 if (cloverreport_mem.length() > 0) {
997 maxHeapSize = cloverreport_mem
999 if (cloverreport_jvmargs.length() > 0) {
1000 jvmArgs Arrays.asList(cloverreport_jvmargs.split(" "))
1011 if (cloverreport_html_options.length() > 0) {
1012 argsList += cloverreport_html_options.split(" ")
1015 args argsList.toArray()
1019 task cloverXmlReport(type: JavaExec) {
1020 group = "Verification"
1021 description = "Creates clover XML report"
1024 file(cloverDb).exists()
1027 def cloverXmlFile = "${cloverReportDir}/clover.xml"
1028 inputs.dir cloverClassesDir
1029 outputs.file cloverXmlFile
1031 classpath = sourceSets.clover.runtimeClasspath
1032 main = "com.atlassian.clover.reporters.xml.XMLReporter"
1034 if (cloverreport_mem.length() > 0) {
1035 maxHeapSize = cloverreport_mem
1037 if (cloverreport_jvmargs.length() > 0) {
1038 jvmArgs Arrays.asList(cloverreport_jvmargs.split(" "))
1049 if (cloverreport_xml_options.length() > 0) {
1050 argsList += cloverreport_xml_options.split(" ")
1053 args argsList.toArray()
1058 group = "Verification"
1059 description = "Creates clover reports"
1061 dependsOn cloverXmlReport
1062 dependsOn cloverHtmlReport
1069 sourceCompatibility = compile_source_compatibility
1070 targetCompatibility = compile_target_compatibility
1071 options.compilerArgs += additional_compiler_args
1072 print ("Setting target compatibility to "+targetCompatibility+"\n")
1074 //classpath += configurations.cloverRuntime
1080 // JBP->BS should the print statement in doFirst refer to compile_target_compatibility ?
1081 sourceCompatibility = compile_source_compatibility
1082 targetCompatibility = compile_target_compatibility
1083 options.compilerArgs += additional_compiler_args
1084 options.encoding = "UTF-8"
1086 print ("Setting target compatibility to "+compile_target_compatibility+"\n")
1093 sourceCompatibility = compile_source_compatibility
1094 targetCompatibility = compile_target_compatibility
1095 options.compilerArgs += additional_compiler_args
1097 print ("Setting target compatibility to "+targetCompatibility+"\n")
1104 delete sourceSets.main.java.outputDir
1110 dependsOn cleanClover
1112 delete sourceSets.test.java.outputDir
1117 // format is a string like date.format("dd MMMM yyyy")
1118 def getDate(format) {
1119 return date.format(format)
1123 def convertMdToHtml (FileTree mdFiles, File cssFile) {
1124 MutableDataSet options = new MutableDataSet()
1126 def extensions = new ArrayList<>()
1127 extensions.add(AnchorLinkExtension.create())
1128 extensions.add(AutolinkExtension.create())
1129 extensions.add(StrikethroughExtension.create())
1130 extensions.add(TaskListExtension.create())
1131 extensions.add(TablesExtension.create())
1132 extensions.add(TocExtension.create())
1134 options.set(Parser.EXTENSIONS, extensions)
1136 // set GFM table parsing options
1137 options.set(TablesExtension.WITH_CAPTION, false)
1138 options.set(TablesExtension.COLUMN_SPANS, false)
1139 options.set(TablesExtension.MIN_HEADER_ROWS, 1)
1140 options.set(TablesExtension.MAX_HEADER_ROWS, 1)
1141 options.set(TablesExtension.APPEND_MISSING_COLUMNS, true)
1142 options.set(TablesExtension.DISCARD_EXTRA_COLUMNS, true)
1143 options.set(TablesExtension.HEADER_SEPARATOR_COLUMN_MATCH, true)
1145 options.set(AnchorLinkExtension.ANCHORLINKS_SET_ID, false)
1146 options.set(AnchorLinkExtension.ANCHORLINKS_ANCHOR_CLASS, "anchor")
1147 options.set(AnchorLinkExtension.ANCHORLINKS_SET_NAME, true)
1148 options.set(AnchorLinkExtension.ANCHORLINKS_TEXT_PREFIX, "<span class=\"octicon octicon-link\"></span>")
1150 Parser parser = Parser.builder(options).build()
1151 HtmlRenderer renderer = HtmlRenderer.builder(options).build()
1153 mdFiles.each { mdFile ->
1154 // add table of contents
1155 def mdText = "[TOC]\n"+mdFile.text
1157 // grab the first top-level title
1159 def titleRegex = /(?m)^#(\s+|([^#]))(.*)/
1160 def matcher = mdText =~ titleRegex
1161 if (matcher.size() > 0) {
1162 // matcher[0][2] is the first character of the title if there wasn't any whitespace after the #
1163 title = (matcher[0][2] != null ? matcher[0][2] : "")+matcher[0][3]
1165 // or use the filename if none found
1166 if (title == null) {
1167 title = mdFile.getName()
1170 Node document = parser.parse(mdText)
1171 String htmlBody = renderer.render(document)
1172 def htmlText = '''<html>
1173 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
1174 <html xmlns="http://www.w3.org/1999/xhtml">
1176 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
1177 <meta http-equiv="Content-Style-Type" content="text/css" />
1178 <meta name="generator" content="flexmark" />
1180 htmlText += ((title != null) ? " <title>${title}</title>" : '' )
1182 <style type="text/css">code{white-space: pre;}</style>
1184 htmlText += ((cssFile != null) ? cssFile.text : '')
1185 htmlText += '''</head>
1188 htmlText += htmlBody
1194 def htmlFilePath = mdFile.getPath().replaceAll(/\..*?$/, ".html")
1195 def htmlFile = file(htmlFilePath)
1196 println("Creating ${htmlFilePath}")
1197 htmlFile.text = htmlText
1202 task copyDocs(type: Copy) {
1203 def inputDir = "${jalviewDir}/${doc_dir}"
1204 def outputDir = "${docBuildDir}/${doc_dir}"
1208 include('**/*.html')
1210 filter(ReplaceTokens,
1214 'Version-Rel': JALVIEW_VERSION,
1215 'Year-Rel': getDate("yyyy")
1222 exclude('**/*.html')
1227 inputs.dir(inputDir)
1228 outputs.dir(outputDir)
1232 task convertMdFiles {
1234 def mdFiles = fileTree(dir: docBuildDir, include: "**/*.md")
1235 def cssFile = file("${jalviewDir}/${flexmark_css}")
1238 convertMdToHtml(mdFiles, cssFile)
1241 inputs.files(mdFiles)
1242 inputs.file(cssFile)
1245 mdFiles.each { mdFile ->
1246 def htmlFilePath = mdFile.getPath().replaceAll(/\..*?$/, ".html")
1247 htmlFiles.add(file(htmlFilePath))
1249 outputs.files(htmlFiles)
1253 def hugoTemplateSubstitutions(String input, Map extras=null) {
1254 def replacements = [
1255 DATE: getDate("yyyy-MM-dd"),
1256 CHANNEL: propertiesChannelName,
1257 APPLICATION_NAME: applicationName,
1259 GIT_BRANCH: gitBranch,
1260 VERSION: JALVIEW_VERSION,
1261 JAVA_VERSION: JAVA_VERSION,
1262 VERSION_UNDERSCORES: JALVIEW_VERSION_UNDERSCORES,
1267 if (extras != null) {
1268 extras.each{ k, v ->
1269 output = output.replaceAll("__${k}__", ((v == null)?"":v))
1272 replacements.each{ k, v ->
1273 output = output.replaceAll("__${k}__", ((v == null)?"":v))
1278 def mdFileComponents(File mdFile, def dateOnly=false) {
1281 if (mdFile.exists()) {
1282 def inFrontMatter = false
1283 def firstLine = true
1284 mdFile.eachLine { line ->
1285 if (line.matches("---")) {
1286 def prev = inFrontMatter
1287 inFrontMatter = firstLine
1288 if (inFrontMatter != prev)
1291 if (inFrontMatter) {
1293 if (m = line =~ /^date:\s*(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})/) {
1294 map["date"] = new Date().parse("yyyy-MM-dd HH:mm:ss", m[0][1])
1295 } else if (m = line =~ /^date:\s*(\d{4}-\d{2}-\d{2})/) {
1296 map["date"] = new Date().parse("yyyy-MM-dd", m[0][1])
1297 } else if (m = line =~ /^channel:\s*(\S+)/) {
1298 map["channel"] = m[0][1]
1299 } else if (m = line =~ /^version:\s*(\S+)/) {
1300 map["version"] = m[0][1]
1301 } else if (m = line =~ /^\s*([^:]+)\s*:\s*(\S.*)/) {
1302 map[ m[0][1] ] = m[0][2]
1304 if (dateOnly && map["date"] != null) {
1310 content += line+"\n"
1315 return dateOnly ? map["date"] : [map, content]
1318 task hugoTemplates {
1320 description "Create partially populated md pages for hugo website build"
1322 def hugoTemplatesDir = file("${jalviewDir}/${hugo_templates_dir}")
1323 def hugoBuildDir = "${jalviewDir}/${hugo_build_dir}"
1324 def templateFiles = fileTree(dir: hugoTemplatesDir)
1325 def releaseMdFile = file("${jalviewDir}/${releases_dir}/release-${JALVIEW_VERSION_UNDERSCORES}.md")
1326 def whatsnewMdFile = file("${jalviewDir}/${whatsnew_dir}/whatsnew-${JALVIEW_VERSION_UNDERSCORES}.md")
1327 def oldJvlFile = file("${jalviewDir}/${hugo_old_jvl}")
1328 def jalviewjsFile = file("${jalviewDir}/${hugo_jalviewjs}")
1331 // specific release template for version archive
1334 def givenDate = null
1335 def givenChannel = null
1336 def givenVersion = null
1337 if (CHANNEL == "RELEASE") {
1338 def (map, content) = mdFileComponents(releaseMdFile)
1339 givenDate = map.date
1340 givenChannel = map.channel
1341 givenVersion = map.version
1343 if (givenVersion != null && givenVersion != JALVIEW_VERSION) {
1344 throw new GradleException("'version' header (${givenVersion}) found in ${releaseMdFile} does not match JALVIEW_VERSION (${JALVIEW_VERSION})")
1347 if (whatsnewMdFile.exists())
1348 whatsnew = whatsnewMdFile.text
1351 def oldJvl = oldJvlFile.exists() ? oldJvlFile.collect{it} : []
1352 def jalviewjsLink = jalviewjsFile.exists() ? jalviewjsFile.collect{it} : []
1354 def changesHugo = null
1355 if (changes != null) {
1356 changesHugo = '<div class="release_notes">\n\n'
1357 def inSection = false
1358 changes.eachLine { line ->
1360 if (m = line =~ /^##([^#].*)$/) {
1362 changesHugo += "</div>\n\n"
1364 def section = m[0][1].trim()
1365 section = section.toLowerCase()
1366 section = section.replaceAll(/ +/, "_")
1367 section = section.replaceAll(/[^a-z0-9_\-]/, "")
1368 changesHugo += "<div class=\"${section}\">\n\n"
1370 } else if (m = line =~ /^(\s*-\s*)<!--([^>]+)-->(.*?)(<br\/?>)?\s*$/) {
1371 def comment = m[0][2].trim()
1372 if (comment != "") {
1373 comment = comment.replaceAll('"', """)
1375 comment.eachMatch(/JAL-\d+/) { jal -> issuekeys += jal }
1376 def newline = m[0][1]
1377 if (comment.trim() != "")
1378 newline += "{{<comment>}}${comment}{{</comment>}} "
1379 newline += m[0][3].trim()
1380 if (issuekeys.size() > 0)
1381 newline += " {{< jal issue=\"${issuekeys.join(",")}\" alt=\"${comment}\" >}}"
1382 if (m[0][4] != null)
1387 changesHugo += line+"\n"
1390 changesHugo += "\n</div>\n\n"
1392 changesHugo += '</div>'
1395 templateFiles.each{ templateFile ->
1396 def newFileName = string(hugoTemplateSubstitutions(templateFile.getName()))
1397 def relPath = hugoTemplatesDir.toPath().relativize(templateFile.toPath()).getParent()
1398 def newRelPathName = hugoTemplateSubstitutions( relPath.toString() )
1400 def outPathName = string("${hugoBuildDir}/$newRelPathName")
1404 rename(templateFile.getName(), newFileName)
1408 def newFile = file("${outPathName}/${newFileName}".toString())
1409 def content = newFile.text
1410 newFile.text = hugoTemplateSubstitutions(content,
1413 CHANGES: changesHugo,
1414 DATE: givenDate == null ? "" : givenDate.format("yyyy-MM-dd"),
1415 DRAFT: givenDate == null ? "true" : "false",
1416 JALVIEWJSLINK: jalviewjsLink.contains(JALVIEW_VERSION) ? "true" : "false",
1417 JVL_HEADER: oldJvl.contains(JALVIEW_VERSION) ? "jvl: true" : ""
1424 inputs.file(oldJvlFile)
1425 inputs.dir(hugoTemplatesDir)
1426 inputs.property("JALVIEW_VERSION", { JALVIEW_VERSION })
1427 inputs.property("CHANNEL", { CHANNEL })
1430 def getMdDate(File mdFile) {
1431 return mdFileComponents(mdFile, true)
1434 def getMdSections(String content) {
1436 def sectionContent = ""
1437 def sectionName = null
1438 content.eachLine { line ->
1440 if (m = line =~ /^##([^#].*)$/) {
1441 if (sectionName != null) {
1442 sections[sectionName] = sectionContent
1446 sectionName = m[0][1].trim()
1447 sectionName = sectionName.toLowerCase()
1448 sectionName = sectionName.replaceAll(/ +/, "_")
1449 sectionName = sectionName.replaceAll(/[^a-z0-9_\-]/, "")
1450 } else if (sectionName != null) {
1451 sectionContent += line+"\n"
1454 if (sectionContent != null) {
1455 sections[sectionName] = sectionContent
1461 task copyHelp(type: Copy) {
1462 def inputDir = helpSourceDir
1463 def outputDir = "${helpBuildDir}/${help_dir}"
1467 include('**/*.html')
1471 filter(ReplaceTokens,
1475 'Version-Rel': JALVIEW_VERSION,
1476 'Year-Rel': getDate("yyyy")
1483 exclude('**/*.html')
1490 inputs.dir(inputDir)
1491 outputs.files(helpFile)
1492 outputs.dir(outputDir)
1496 task releasesTemplates {
1498 description "Recreate whatsNew.html and releases.html from markdown files and templates in help"
1502 def releasesTemplateFile = file("${jalviewDir}/${releases_template}")
1503 def whatsnewTemplateFile = file("${jalviewDir}/${whatsnew_template}")
1504 def releasesHtmlFile = file("${helpBuildDir}/${help_dir}/${releases_html}")
1505 def whatsnewHtmlFile = file("${helpBuildDir}/${help_dir}/${whatsnew_html}")
1506 def releasesMdDir = "${jalviewDir}/${releases_dir}"
1507 def whatsnewMdDir = "${jalviewDir}/${whatsnew_dir}"
1510 def releaseMdFile = file("${releasesMdDir}/release-${JALVIEW_VERSION_UNDERSCORES}.md")
1511 def whatsnewMdFile = file("${whatsnewMdDir}/whatsnew-${JALVIEW_VERSION_UNDERSCORES}.md")
1513 if (CHANNEL == "RELEASE") {
1514 if (!releaseMdFile.exists()) {
1515 throw new GradleException("File ${releaseMdFile} must be created for RELEASE")
1517 if (!whatsnewMdFile.exists()) {
1518 throw new GradleException("File ${whatsnewMdFile} must be created for RELEASE")
1522 def releaseFiles = fileTree(dir: releasesMdDir, include: "release-*.md")
1523 def releaseFilesDates = releaseFiles.collectEntries {
1524 [(it): getMdDate(it)]
1526 releaseFiles = releaseFiles.sort { a,b -> releaseFilesDates[a].compareTo(releaseFilesDates[b]) }
1528 def releasesTemplate = releasesTemplateFile.text
1529 def m = releasesTemplate =~ /(?s)__VERSION_LOOP_START__(.*)__VERSION_LOOP_END__/
1530 def versionTemplate = m[0][1]
1532 MutableDataSet options = new MutableDataSet()
1534 def extensions = new ArrayList<>()
1535 options.set(Parser.EXTENSIONS, extensions)
1536 options.set(Parser.HTML_BLOCK_COMMENT_ONLY_FULL_LINE, true)
1538 Parser parser = Parser.builder(options).build()
1539 HtmlRenderer renderer = HtmlRenderer.builder(options).build()
1541 def actualVersions = releaseFiles.collect { rf ->
1542 def (rfMap, rfContent) = mdFileComponents(rf)
1543 return rfMap.version
1545 def versionsHtml = ""
1546 def linkedVersions = []
1547 releaseFiles.reverse().each { rFile ->
1548 def (rMap, rContent) = mdFileComponents(rFile)
1550 def versionLink = ""
1551 def partialVersion = ""
1552 def firstPart = true
1553 rMap.version.split("\\.").each { part ->
1554 def displayPart = ( firstPart ? "" : "." ) + part
1555 partialVersion += displayPart
1557 linkedVersions.contains(partialVersion)
1558 || ( actualVersions.contains(partialVersion) && partialVersion != rMap.version )
1560 versionLink += displayPart
1562 versionLink += "<a id=\"Jalview.${partialVersion}\">${displayPart}</a>"
1563 linkedVersions += partialVersion
1567 def displayDate = releaseFilesDates[rFile].format("dd/MM/yyyy")
1570 def rContentProcessed = ""
1571 rContent.eachLine { line ->
1572 if (lm = line =~ /^(\s*-)(\s*<!--[^>]*?-->)(.*)$/) {
1573 line = "${lm[0][1]}${lm[0][3]}${lm[0][2]}"
1574 } else if (lm = line =~ /^###([^#]+.*)$/) {
1575 line = "_${lm[0][1].trim()}_"
1577 rContentProcessed += line + "\n"
1580 def rContentSections = getMdSections(rContentProcessed)
1581 def rVersion = versionTemplate
1582 if (rVersion != "") {
1583 def rNewFeatures = rContentSections["new_features"]
1584 def rIssuesResolved = rContentSections["issues_resolved"]
1585 Node newFeaturesNode = parser.parse(rNewFeatures)
1586 String newFeaturesHtml = renderer.render(newFeaturesNode)
1587 Node issuesResolvedNode = parser.parse(rIssuesResolved)
1588 String issuesResolvedHtml = renderer.render(issuesResolvedNode)
1589 rVersion = hugoTemplateSubstitutions(rVersion,
1591 VERSION: rMap.version,
1592 VERSION_LINK: versionLink,
1593 DISPLAY_DATE: displayDate,
1594 NEW_FEATURES: newFeaturesHtml,
1595 ISSUES_RESOLVED: issuesResolvedHtml
1598 versionsHtml += rVersion
1602 releasesTemplate = releasesTemplate.replaceAll("(?s)__VERSION_LOOP_START__.*__VERSION_LOOP_END__", versionsHtml)
1603 releasesTemplate = hugoTemplateSubstitutions(releasesTemplate)
1604 releasesHtmlFile.text = releasesTemplate
1606 if (whatsnewMdFile.exists()) {
1607 def wnDisplayDate = releaseFilesDates[releaseMdFile] != null ? releaseFilesDates[releaseMdFile].format("dd MMMM yyyy") : ""
1608 def whatsnewMd = hugoTemplateSubstitutions(whatsnewMdFile.text)
1609 Node whatsnewNode = parser.parse(whatsnewMd)
1610 String whatsnewHtml = renderer.render(whatsnewNode)
1611 whatsnewHtml = whatsnewTemplateFile.text.replaceAll("__WHATS_NEW__", whatsnewHtml)
1612 whatsnewHtmlFile.text = hugoTemplateSubstitutions(whatsnewHtml,
1614 VERSION: JALVIEW_VERSION,
1615 DISPLAY_DATE: wnDisplayDate
1618 } else if (gradle.taskGraph.hasTask(":linkCheck")) {
1619 whatsnewHtmlFile.text = "Development build " + getDate("yyyy-MM-dd HH:mm:ss")
1624 inputs.file(releasesTemplateFile)
1625 inputs.file(whatsnewTemplateFile)
1626 inputs.dir(releasesMdDir)
1627 inputs.dir(whatsnewMdDir)
1628 outputs.file(releasesHtmlFile)
1629 outputs.file(whatsnewHtmlFile)
1633 task copyResources(type: Copy) {
1635 description = "Copy (and make text substitutions in) the resources dir to the build area"
1637 def inputDir = resourceDir
1638 def outputDir = resourcesBuildDir
1642 include('**/*.html')
1644 filter(ReplaceTokens,
1648 'Version-Rel': JALVIEW_VERSION,
1649 'Year-Rel': getDate("yyyy")
1656 exclude('**/*.html')
1661 inputs.dir(inputDir)
1662 outputs.dir(outputDir)
1665 task copyChannelResources(type: Copy) {
1666 dependsOn copyResources
1668 description = "Copy the channel resources dir to the build resources area"
1670 def inputDir = "${channelDir}/${resource_dir}"
1671 def outputDir = resourcesBuildDir
1673 include(channel_props)
1674 filter(ReplaceTokens,
1678 'SUFFIX': channelSuffix
1683 exclude(channel_props)
1687 inputs.dir(inputDir)
1688 outputs.dir(outputDir)
1691 task createBuildProperties(type: WriteProperties) {
1692 dependsOn copyResources
1694 description = "Create the ${buildProperties} file"
1696 inputs.dir(sourceDir)
1697 inputs.dir(resourcesBuildDir)
1698 outputFile (buildProperties)
1699 // taking time specific comment out to allow better incremental builds
1700 comment "--Jalview Build Details--\n"+getDate("yyyy-MM-dd HH:mm:ss")
1701 //comment "--Jalview Build Details--\n"+getDate("yyyy-MM-dd")
1702 property "BUILD_DATE", getDate("HH:mm:ss dd MMMM yyyy")
1703 property "VERSION", JALVIEW_VERSION
1704 property "INSTALLATION", INSTALLATION+" git-commit:"+gitHash+" ["+gitBranch+"]"
1705 property "JAVA_COMPILE_VERSION", JAVA_INTEGER_VERSION
1706 if (getdownSetAppBaseProperty) {
1707 property "GETDOWNAPPBASE", getdownAppBase
1708 property "GETDOWNAPPDISTDIR", getdownAppDistDir
1710 outputs.file(outputFile)
1714 task buildIndices(type: JavaExec) {
1716 classpath = sourceSets.main.compileClasspath
1717 main = "com.sun.java.help.search.Indexer"
1718 workingDir = "${helpBuildDir}/${help_dir}"
1721 inputs.dir("${workingDir}/${argDir}")
1723 outputs.dir("${classesDir}/doc")
1724 outputs.dir("${classesDir}/help")
1725 outputs.file("${workingDir}/JavaHelpSearch/DOCS")
1726 outputs.file("${workingDir}/JavaHelpSearch/DOCS.TAB")
1727 outputs.file("${workingDir}/JavaHelpSearch/OFFSETS")
1728 outputs.file("${workingDir}/JavaHelpSearch/POSITIONS")
1729 outputs.file("${workingDir}/JavaHelpSearch/SCHEMA")
1730 outputs.file("${workingDir}/JavaHelpSearch/TMAP")
1733 task buildResources {
1734 dependsOn copyResources
1735 dependsOn copyChannelResources
1736 dependsOn createBuildProperties
1740 dependsOn buildResources
1743 dependsOn releasesTemplates
1744 dependsOn convertMdFiles
1745 dependsOn buildIndices
1749 compileJava.dependsOn prepare
1750 run.dependsOn compileJava
1751 compileTestJava.dependsOn compileJava
1756 group = "Verification"
1757 description = "Runs all testTaskN tasks)"
1760 dependsOn cloverClasses
1762 dependsOn testClasses
1765 // not running tests in this task
1768 /* testTask0 is the main test task */
1769 task testTask0(type: Test) {
1770 group = "Verification"
1771 description = "The main test task. Runs all non-testTaskN-labelled tests (unless excluded)"
1773 includeGroups testng_groups.split(",")
1774 excludeGroups testng_excluded_groups.split(",")
1775 tasks.withType(Test).matching {it.name.startsWith("testTask") && it.name != name}.all {t -> excludeGroups t.name}
1777 useDefaultListeners=true
1779 timeout = Duration.ofMinutes(15)
1782 /* separated tests */
1783 task testTask1(type: Test) {
1784 group = "Verification"
1785 description = "Tests that need to be isolated from the main test run"
1788 excludeGroups testng_excluded_groups.split(",")
1790 useDefaultListeners=true
1792 timeout = Duration.ofMinutes(5)
1795 task testTask2(type: Test) {
1796 group = "Verification"
1797 description = "Tests that need to be isolated from the main test run"
1800 excludeGroups testng_excluded_groups.split(",")
1802 useDefaultListeners=true
1804 timeout = Duration.ofMinutes(5)
1806 task testTask3(type: Test) {
1807 group = "Verification"
1808 description = "Tests that need to be isolated from the main test run"
1811 excludeGroups testng_excluded_groups.split(",")
1813 useDefaultListeners=true
1815 timeout = Duration.ofMinutes(5)
1818 /* insert more testTaskNs here -- change N to next digit or other string */
1820 task testTaskN(type: Test) {
1821 group = "Verification"
1822 description = "Tests that need to be isolated from the main test run"
1825 excludeGroups testng_excluded_groups.split(",")
1827 useDefaultListeners=true
1834 * adapted from https://medium.com/@wasyl/pretty-tests-summary-in-gradle-744804dd676c
1835 * to summarise test results from all Test tasks
1837 /* START of test tasks results summary */
1838 import groovy.time.TimeCategory
1839 import org.gradle.api.tasks.testing.logging.TestExceptionFormat
1840 import org.gradle.api.tasks.testing.logging.TestLogEvent
1841 rootProject.ext.testsResults = [] // Container for tests summaries
1843 tasks.withType(Test).matching {t -> t.getName().startsWith("testTask")}.all { testTask ->
1845 // from original test task
1847 dependsOn cloverClasses
1849 dependsOn testClasses //?
1852 // run main tests first
1853 if (!testTask.name.equals("testTask0"))
1854 testTask.mustRunAfter "testTask0"
1856 testTask.testLogging { logging ->
1857 events TestLogEvent.FAILED
1858 // TestLogEvent.SKIPPED,
1859 // TestLogEvent.STANDARD_OUT,
1860 // TestLogEvent.STANDARD_ERROR
1862 exceptionFormat TestExceptionFormat.FULL
1865 showStackTraces true
1867 showStandardStreams true
1869 info.events = [ TestLogEvent.FAILED ]
1872 if (OperatingSystem.current().isMacOsX()) {
1873 testTask.systemProperty "apple.awt.UIElement", "true"
1874 testTask.environment "JAVA_TOOL_OPTIONS", "-Dapple.awt.UIElement=true"
1878 ignoreFailures = true // Always try to run all tests for all modules
1880 afterSuite { desc, result ->
1882 return // Only summarize results for whole modules
1884 def resultsInfo = [testTask.project.name, testTask.name, result, TimeCategory.minus(new Date(result.endTime), new Date(result.startTime)), testTask.reports.html.entryPoint]
1886 rootProject.ext.testsResults.add(resultsInfo)
1889 // from original test task
1890 maxHeapSize = "1024m"
1892 workingDir = jalviewDir
1893 def testLaf = project.findProperty("test_laf")
1894 if (testLaf != null) {
1895 println("Setting Test LaF to '${testLaf}'")
1896 systemProperty "laf", testLaf
1898 def testHiDPIScale = project.findProperty("test_HiDPIScale")
1899 if (testHiDPIScale != null) {
1900 println("Setting Test HiDPI Scale to '${testHiDPIScale}'")
1901 systemProperty "sun.java2d.uiScale", testHiDPIScale
1903 sourceCompatibility = compile_source_compatibility
1904 targetCompatibility = compile_target_compatibility
1905 jvmArgs += additional_compiler_args
1908 // this is not perfect yet -- we should only add the commandLineIncludePatterns to the
1909 // testTasks that include the tests, and exclude all from the others.
1910 // get --test argument
1911 filter.commandLineIncludePatterns = test.filter.commandLineIncludePatterns
1912 // do something with testTask.getCandidateClassFiles() to see if the test should silently finish because of the
1913 // commandLineIncludePatterns not matching anything. Instead we are doing setFailOnNoMatchingTests(false) below
1917 println("Running tests " + (useClover?"WITH":"WITHOUT") + " clover")
1922 /* don't fail on no matching tests (so --tests will run across all testTasks) */
1923 testTask.filter.setFailOnNoMatchingTests(false)
1925 /* ensure the "test" task dependsOn all the testTasks */
1926 test.dependsOn testTask
1929 gradle.buildFinished {
1930 def allResults = rootProject.ext.testsResults
1932 if (!allResults.isEmpty()) {
1933 printResults allResults
1934 allResults.each {r ->
1935 if (r[2].resultType == TestResult.ResultType.FAILURE)
1936 throw new GradleException("Failed tests!")
1941 private static String colString(styler, col, colour, text) {
1942 return col?"${styler[colour](text)}":text
1945 private static String getSummaryLine(s, pn, tn, rt, rc, rs, rf, rsk, t, col) {
1946 def colour = 'black'
1954 case TestResult.ResultType.SUCCESS:
1957 case TestResult.ResultType.FAILURE:
1965 StringBuilder sb = new StringBuilder()
1969 sb.append(" results: ")
1970 sb.append(colString(s, col && !nocol, colour, text))
1972 sb.append("${rc} tests, ")
1973 sb.append(colString(s, col && rs > 0, 'green', rs))
1974 sb.append(" successes, ")
1975 sb.append(colString(s, col && rf > 0, 'red', rf))
1976 sb.append(" failures, ")
1977 sb.append("${rsk} skipped) in ${t}")
1978 return sb.toString()
1981 private static void printResults(allResults) {
1983 // styler from https://stackoverflow.com/a/56139852
1984 def styler = 'black red green yellow blue magenta cyan white'.split().toList().withIndex(30).collectEntries { key, val -> [(key) : { "\033[${val}m${it}\033[0m" }] }
1987 def failedTests = false
1988 def summaryLines = []
1990 def totalsuccess = 0
1993 def totaltime = TimeCategory.getSeconds(0)
1994 // sort on project name then task name
1995 allResults.sort {a, b -> a[0] == b[0]? a[1]<=>b[1]:a[0] <=> b[0]}.each {
1996 def projectName = it[0]
1997 def taskName = it[1]
2001 def summaryCol = getSummaryLine(styler, projectName, taskName, result.resultType, result.testCount, result.successfulTestCount, result.failedTestCount, result.skippedTestCount, time, true)
2002 def summaryPlain = getSummaryLine(styler, projectName, taskName, result.resultType, result.testCount, result.successfulTestCount, result.failedTestCount, result.skippedTestCount, time, false)
2003 def reportLine = "Report file: ${report}"
2004 def ls = summaryPlain.length()
2005 def lr = reportLine.length()
2006 def m = [ls, lr].max()
2009 def info = [ls, summaryCol, reportLine]
2010 summaryLines.add(info)
2011 failedTests |= result.resultType == TestResult.ResultType.FAILURE
2012 totalcount += result.testCount
2013 totalsuccess += result.successfulTestCount
2014 totalfail += result.failedTestCount
2015 totalskip += result.skippedTestCount
2018 def totalSummaryCol = getSummaryLine(styler, "OVERALL", "", failedTests?TestResult.ResultType.FAILURE:TestResult.ResultType.SUCCESS, totalcount, totalsuccess, totalfail, totalskip, totaltime, true)
2019 def totalSummaryPlain = getSummaryLine(styler, "OVERALL", "", failedTests?TestResult.ResultType.FAILURE:TestResult.ResultType.SUCCESS, totalcount, totalsuccess, totalfail, totalskip, totaltime, false)
2020 def tls = totalSummaryPlain.length()
2021 if (tls > maxLength)
2023 def info = [tls, totalSummaryCol, null]
2024 summaryLines.add(info)
2026 def allSummaries = []
2027 for(sInfo : summaryLines) {
2029 def summary = sInfo[1]
2030 def report = sInfo[2]
2032 StringBuilder sb = new StringBuilder()
2033 sb.append("│" + summary + " " * (maxLength - ls) + "│")
2034 if (report != null) {
2035 sb.append("\n│" + report + " " * (maxLength - report.length()) + "│")
2037 allSummaries += sb.toString()
2040 println "┌${"${"─" * maxLength}"}┐"
2041 println allSummaries.join("\n├${"${"─" * maxLength}"}┤\n")
2042 println "└${"${"─" * maxLength}"}┘"
2044 /* END of test tasks results summary */
2047 task compileLinkCheck(type: JavaCompile) {
2049 classpath = files("${jalviewDir}/${utils_dir}")
2050 destinationDir = file("${jalviewDir}/${utils_dir}")
2051 source = fileTree(dir: "${jalviewDir}/${utils_dir}", include: ["HelpLinksChecker.java", "BufferedLineReader.java"])
2053 inputs.file("${jalviewDir}/${utils_dir}/HelpLinksChecker.java")
2054 inputs.file("${jalviewDir}/${utils_dir}/HelpLinksChecker.java")
2055 outputs.file("${jalviewDir}/${utils_dir}/HelpLinksChecker.class")
2056 outputs.file("${jalviewDir}/${utils_dir}/BufferedLineReader.class")
2060 task linkCheck(type: JavaExec) {
2062 dependsOn compileLinkCheck
2064 def helpLinksCheckerOutFile = file("${jalviewDir}/${utils_dir}/HelpLinksChecker.out")
2065 classpath = files("${jalviewDir}/${utils_dir}")
2066 main = "HelpLinksChecker"
2067 workingDir = "${helpBuildDir}"
2068 args = [ "${helpBuildDir}/${help_dir}", "-nointernet" ]
2070 def outFOS = new FileOutputStream(helpLinksCheckerOutFile, false) // false == don't append
2071 standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
2074 errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
2078 inputs.dir(helpBuildDir)
2079 outputs.file(helpLinksCheckerOutFile)
2083 // import the pubhtmlhelp target
2084 ant.properties.basedir = "${jalviewDir}"
2085 ant.properties.helpBuildDir = "${helpBuildDir}/${help_dir}"
2086 ant.importBuild "${utils_dir}/publishHelp.xml"
2089 task cleanPackageDir(type: Delete) {
2091 delete fileTree(dir: "${jalviewDir}/${package_dir}", include: "*.jar")
2101 attributes "Main-Class": main_class,
2102 "Permissions": "all-permissions",
2103 "Application-Name": applicationName,
2104 "Codebase": application_codebase,
2105 "Implementation-Version": JALVIEW_VERSION
2108 def outputDir = "${jalviewDir}/${package_dir}"
2109 destinationDirectory = file(outputDir)
2110 archiveFileName = rootProject.name+".jar"
2111 duplicatesStrategy "EXCLUDE"
2118 exclude "**/*.jar.*"
2120 inputs.dir(sourceSets.main.java.outputDir)
2121 sourceSets.main.resources.srcDirs.each{ dir ->
2124 outputs.file("${outputDir}/${archiveFileName}")
2128 task copyJars(type: Copy) {
2129 from fileTree(dir: classesDir, include: "**/*.jar").files
2130 into "${jalviewDir}/${package_dir}"
2134 // doing a Sync instead of Copy as Copy doesn't deal with "outputs" very well
2135 task syncJars(type: Sync) {
2137 from fileTree(dir: "${jalviewDir}/${libDistDir}", include: "**/*.jar").files
2138 into "${jalviewDir}/${package_dir}"
2140 include jar.archiveFileName.getOrNull()
2147 description = "Put all required libraries in dist"
2148 // order of "cleanPackageDir", "copyJars", "jar" important!
2149 jar.mustRunAfter cleanPackageDir
2150 syncJars.mustRunAfter cleanPackageDir
2151 dependsOn cleanPackageDir
2154 outputs.dir("${jalviewDir}/${package_dir}")
2159 dependsOn cleanPackageDir
2165 task launcherJar(type: Jar) {
2168 "Main-Class": shadow_jar_main_class,
2169 "Implementation-Version": JALVIEW_VERSION,
2170 "Application-Name": applicationName
2176 group = "distribution"
2177 description = "Create a single jar file with all dependency libraries merged. Can be run with java -jar"
2182 def jarFiles = fileTree(dir: "${jalviewDir}/${libDistDir}", include: "*.jar", exclude: "regex.jar").getFiles()
2183 def groovyJars = jarFiles.findAll {it1 -> file(it1).getName().startsWith("groovy-swing")}
2184 def otherJars = jarFiles.findAll {it2 -> !file(it2).getName().startsWith("groovy-swing")}
2189 // shadowJar manifest must inheritFrom another Jar task. Can't set attributes here.
2190 inheritFrom(project.tasks.launcherJar.manifest)
2192 // we need to include the groovy-swing Include-Package for it to run in the shadowJar
2194 def jarFileManifests = []
2195 groovyJars.each { jarFile ->
2196 def mf = zipTree(jarFile).getFiles().find { it.getName().equals("MANIFEST.MF") }
2198 jarFileManifests += mf
2202 from (jarFileManifests) {
2203 eachEntry { details ->
2204 if (!details.key.equals("Import-Package")) {
2212 duplicatesStrategy "INCLUDE"
2214 // this mainClassName is mandatory but gets ignored due to manifest created in doFirst{}. Set the Main-Class as an attribute in launcherJar instead
2215 mainClassName = shadow_jar_main_class
2217 classifier = "all-"+JALVIEW_VERSION+"-j"+JAVA_VERSION
2221 task getdownImagesCopy() {
2222 inputs.dir getdownImagesDir
2223 outputs.dir getdownImagesBuildDir
2227 from(getdownImagesDir) {
2228 include("*getdown*.png")
2230 into getdownImagesBuildDir
2235 task getdownImagesProcess() {
2236 dependsOn getdownImagesCopy
2239 if (backgroundImageText) {
2240 if (convertBinary == null) {
2241 throw new StopExecutionException("No ImageMagick convert binary installed at '${convertBinaryExpectedLocation}'")
2243 if (!project.hasProperty("getdown_background_image_text_suffix_cmd")) {
2244 throw new StopExecutionException("No property 'getdown_background_image_text_suffix_cmd' defined. See channel_gradle.properties for channel ${CHANNEL}")
2246 fileTree(dir: getdownImagesBuildDir, include: "*background*.png").getFiles().each { file ->
2248 executable convertBinary
2251 '-font', getdown_background_image_text_font,
2252 '-fill', getdown_background_image_text_colour,
2253 '-draw', sprintf(getdown_background_image_text_suffix_cmd, channelSuffix),
2254 '-draw', sprintf(getdown_background_image_text_commit_cmd, "git-commit: ${gitHash}"),
2255 '-draw', sprintf(getdown_background_image_text_date_cmd, getDate("yyyy-MM-dd HH:mm:ss")),
2264 task getdownImages() {
2265 dependsOn getdownImagesProcess
2268 task getdownWebsiteBuild() {
2269 group = "distribution"
2270 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."
2272 dependsOn getdownImages
2277 def getdownWebsiteResourceFilenames = []
2278 def getdownResourceDir = getdownResourceDir
2279 def getdownResourceFilenames = []
2282 // clean the getdown website and files dir before creating getdown folders
2283 delete getdownAppBaseDir
2284 delete getdownFilesDir
2287 from buildProperties
2288 rename(file(buildProperties).getName(), getdown_build_properties)
2291 getdownWebsiteResourceFilenames += "${getdownAppDistDir}/${getdown_build_properties}"
2294 from channelPropsFile
2295 filter(ReplaceTokens,
2299 'SUFFIX': channelSuffix
2302 into getdownAppBaseDir
2304 getdownWebsiteResourceFilenames += file(channelPropsFile).getName()
2306 // set some getdownTxt_ properties then go through all properties looking for getdownTxt_...
2307 def props = project.properties.sort { it.key }
2308 if (getdownAltJavaMinVersion != null && getdownAltJavaMinVersion.length() > 0) {
2309 props.put("getdown_txt_java_min_version", getdownAltJavaMinVersion)
2311 if (getdownAltJavaMaxVersion != null && getdownAltJavaMaxVersion.length() > 0) {
2312 props.put("getdown_txt_java_max_version", getdownAltJavaMaxVersion)
2314 if (getdownAltMultiJavaLocation != null && getdownAltMultiJavaLocation.length() > 0) {
2315 props.put("getdown_txt_multi_java_location", getdownAltMultiJavaLocation)
2317 if (getdownImagesBuildDir != null && file(getdownImagesBuildDir).exists()) {
2318 props.put("getdown_txt_ui.background_image", "${getdownImagesBuildDir}/${getdown_background_image}")
2319 props.put("getdown_txt_ui.instant_background_image", "${getdownImagesBuildDir}/${getdown_instant_background_image}")
2320 props.put("getdown_txt_ui.error_background", "${getdownImagesBuildDir}/${getdown_error_background}")
2321 props.put("getdown_txt_ui.progress_image", "${getdownImagesBuildDir}/${getdown_progress_image}")
2322 props.put("getdown_txt_ui.icon", "${getdownImagesDir}/${getdown_icon}")
2323 props.put("getdown_txt_ui.mac_dock_icon", "${getdownImagesDir}/${getdown_mac_dock_icon}")
2326 props.put("getdown_txt_title", jalview_name)
2327 props.put("getdown_txt_ui.name", applicationName)
2329 // start with appbase
2330 getdownTextLines += "appbase = ${getdownAppBase}"
2331 props.each{ prop, val ->
2332 if (prop.startsWith("getdown_txt_") && val != null) {
2333 if (prop.startsWith("getdown_txt_multi_")) {
2334 def key = prop.substring(18)
2335 val.split(",").each{ v ->
2336 def line = "${key} = ${v}"
2337 getdownTextLines += line
2340 // file values rationalised
2341 if (val.indexOf('/') > -1 || prop.startsWith("getdown_txt_resource")) {
2343 if (val.indexOf('/') == 0) {
2346 } else if (val.indexOf('/') > 0) {
2347 // relative path (relative to jalviewDir)
2348 r = file( "${jalviewDir}/${val}" )
2351 val = "${getdown_resource_dir}/" + r.getName()
2352 getdownWebsiteResourceFilenames += val
2353 getdownResourceFilenames += r.getPath()
2356 if (! prop.startsWith("getdown_txt_resource")) {
2357 def line = prop.substring(12) + " = ${val}"
2358 getdownTextLines += line
2364 getdownWebsiteResourceFilenames.each{ filename ->
2365 getdownTextLines += "resource = ${filename}"
2367 getdownResourceFilenames.each{ filename ->
2370 into getdownResourceDir
2374 def getdownWrapperScripts = [ getdown_bash_wrapper_script, getdown_powershell_wrapper_script, getdown_batch_wrapper_script ]
2375 getdownWrapperScripts.each{ script ->
2376 def s = file( "${jalviewDir}/utils/getdown/${getdown_wrapper_script_dir}/${script}" )
2380 into "${getdownAppBaseDir}/${getdown_wrapper_script_dir}"
2382 getdownTextLines += "xresource = ${getdown_wrapper_script_dir}/${script}"
2387 fileTree(file(package_dir)).each{ f ->
2388 if (f.isDirectory()) {
2389 def files = fileTree(dir: f, include: ["*"]).getFiles()
2391 } else if (f.exists()) {
2395 def jalviewJar = jar.archiveFileName.getOrNull()
2396 // put jalview.jar first for CLASSPATH and .properties files reasons
2397 codeFiles.sort{a, b -> ( a.getName() == jalviewJar ? -1 : ( b.getName() == jalviewJar ? 1 : a <=> b ) ) }.each{f ->
2398 def name = f.getName()
2399 def line = "code = ${getdownAppDistDir}/${name}"
2400 getdownTextLines += line
2407 // NOT USING MODULES YET, EVERYTHING SHOULD BE IN dist
2409 if (JAVA_VERSION.equals("11")) {
2410 def j11libFiles = fileTree(dir: "${jalviewDir}/${j11libDir}", include: ["*.jar"]).getFiles()
2411 j11libFiles.sort().each{f ->
2412 def name = f.getName()
2413 def line = "code = ${getdown_j11lib_dir}/${name}"
2414 getdownTextLines += line
2417 into getdownJ11libDir
2423 // 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.
2424 //getdownTextLines += "class = " + file(getdownLauncher).getName()
2425 getdownTextLines += "resource = ${getdown_launcher_new}"
2426 getdownTextLines += "class = ${main_class}"
2427 // Not setting these properties in general so that getdownappbase and getdowndistdir will default to release version in jalview.bin.Cache
2428 if (getdownSetAppBaseProperty) {
2429 getdownTextLines += "jvmarg = -Dgetdowndistdir=${getdownAppDistDir}"
2430 getdownTextLines += "jvmarg = -Dgetdownappbase=${getdownAppBase}"
2433 def getdownTxt = file("${getdownAppBaseDir}/getdown.txt")
2434 getdownTxt.write(getdownTextLines.join("\n"))
2436 getdownLaunchJvl = getdown_launch_jvl_name + ( (jvlChannelName != null && jvlChannelName.length() > 0)?"-${jvlChannelName}":"" ) + ".jvl"
2437 def launchJvl = file("${getdownAppBaseDir}/${getdownLaunchJvl}")
2438 launchJvl.write("appbase=${getdownAppBase}")
2440 // files going into the getdown website dir: getdown-launcher.jar
2442 from getdownLauncher
2443 rename(file(getdownLauncher).getName(), getdown_launcher_new)
2444 into getdownAppBaseDir
2447 // files going into the getdown website dir: getdown-launcher(-local).jar
2449 from getdownLauncher
2450 if (file(getdownLauncher).getName() != getdown_launcher) {
2451 rename(file(getdownLauncher).getName(), getdown_launcher)
2453 into getdownAppBaseDir
2456 // files going into the getdown website dir: ./install dir and files
2457 if (! (CHANNEL.startsWith("ARCHIVE") || CHANNEL.startsWith("DEVELOP"))) {
2460 from getdownLauncher
2461 from "${getdownAppDir}/${getdown_build_properties}"
2462 if (file(getdownLauncher).getName() != getdown_launcher) {
2463 rename(file(getdownLauncher).getName(), getdown_launcher)
2465 into getdownInstallDir
2468 // and make a copy in the getdown files dir (these are not downloaded by getdown)
2470 from getdownInstallDir
2471 into getdownFilesInstallDir
2475 // files going into the getdown files dir: getdown.txt, getdown-launcher.jar, channel-launch.jvl, build_properties
2479 from getdownLauncher
2480 from "${getdownAppBaseDir}/${getdown_build_properties}"
2481 from "${getdownAppBaseDir}/${channel_props}"
2482 if (file(getdownLauncher).getName() != getdown_launcher) {
2483 rename(file(getdownLauncher).getName(), getdown_launcher)
2485 into getdownFilesDir
2488 // and ./resource (not all downloaded by getdown)
2490 from getdownResourceDir
2491 into "${getdownFilesDir}/${getdown_resource_dir}"
2496 inputs.dir("${jalviewDir}/${package_dir}")
2498 outputs.dir(getdownAppBaseDir)
2499 outputs.dir(getdownFilesDir)
2503 // a helper task to allow getdown digest of any dir: `gradle getdownDigestDir -PDIGESTDIR=/path/to/my/random/getdown/dir
2504 task getdownDigestDir(type: JavaExec) {
2506 description "A task to run a getdown Digest on a dir with getdown.txt. Provide a DIGESTDIR property via -PDIGESTDIR=..."
2508 def digestDirPropertyName = "DIGESTDIR"
2510 classpath = files(getdownLauncher)
2511 def digestDir = findProperty(digestDirPropertyName)
2512 if (digestDir == null) {
2513 throw new GradleException("Must provide a DIGESTDIR value to produce an alternative getdown digest")
2517 main = "com.threerings.getdown.tools.Digester"
2521 task getdownDigest(type: JavaExec) {
2522 group = "distribution"
2523 description = "Digest the getdown website folder"
2525 dependsOn getdownWebsiteBuild
2528 classpath = files(getdownLauncher)
2530 main = "com.threerings.getdown.tools.Digester"
2531 args getdownAppBaseDir
2532 inputs.dir(getdownAppBaseDir)
2533 outputs.file("${getdownAppBaseDir}/digest2.txt")
2538 group = "distribution"
2539 description = "Create the minimal and full getdown app folder for installers and website and create digest file"
2540 dependsOn getdownDigest
2542 if (reportRsyncCommand) {
2543 def fromDir = getdownAppBaseDir + (getdownAppBaseDir.endsWith('/')?'':'/')
2544 def toDir = "${getdown_rsync_dest}/${getdownDir}" + (getdownDir.endsWith('/')?'':'/')
2545 println "LIKELY RSYNC COMMAND:"
2546 println "mkdir -p '$toDir'\nrsync -avh --delete '$fromDir' '$toDir'"
2547 if (RUNRSYNC == "true") {
2549 commandLine "mkdir", "-p", toDir
2552 commandLine "rsync", "-avh", "--delete", fromDir, toDir
2559 task getdownWebsite {
2560 group = "distribution"
2561 description = "A task to create the whole getdown channel website dir including digest file"
2563 dependsOn getdownWebsiteBuild
2564 dependsOn getdownDigest
2567 task getdownArchiveBuild() {
2568 group = "distribution"
2569 description = "Put files in the archive dir to go on the website"
2571 dependsOn getdownWebsiteBuild
2573 def v = "v${JALVIEW_VERSION_UNDERSCORES}"
2574 def vDir = "${getdownArchiveDir}/${v}"
2575 getdownFullArchiveDir = "${vDir}/getdown"
2576 getdownVersionLaunchJvl = "${vDir}/jalview-${v}.jvl"
2578 def vAltDir = "alt_${v}"
2579 def archiveImagesDir = "${jalviewDir}/${channel_properties_dir}/old/images"
2582 // cleanup old "old" dir
2583 delete getdownArchiveDir
2585 def getdownArchiveTxt = file("${getdownFullArchiveDir}/getdown.txt")
2586 getdownArchiveTxt.getParentFile().mkdirs()
2587 def getdownArchiveTextLines = []
2588 def getdownFullArchiveAppBase = "${getdownArchiveAppBase}${getdownArchiveAppBase.endsWith("/")?"":"/"}${v}/getdown/"
2592 from "${getdownAppBaseDir}/${getdownAppDistDir}"
2593 into "${getdownFullArchiveDir}/${vAltDir}"
2596 getdownTextLines.each { line ->
2597 line = line.replaceAll("^(?<s>appbase\\s*=\\s*).*", '${s}'+getdownFullArchiveAppBase)
2598 line = line.replaceAll("^(?<s>(resource|code)\\s*=\\s*)${getdownAppDistDir}/", '${s}'+vAltDir+"/")
2599 line = line.replaceAll("^(?<s>ui.background_image\\s*=\\s*).*\\.png", '${s}'+"${getdown_resource_dir}/jalview_archive_getdown_background.png")
2600 line = line.replaceAll("^(?<s>ui.instant_background_image\\s*=\\s*).*\\.png", '${s}'+"${getdown_resource_dir}/jalview_archive_getdown_background_initialising.png")
2601 line = line.replaceAll("^(?<s>ui.error_background\\s*=\\s*).*\\.png", '${s}'+"${getdown_resource_dir}/jalview_archive_getdown_background_error.png")
2602 line = line.replaceAll("^(?<s>ui.progress_image\\s*=\\s*).*\\.png", '${s}'+"${getdown_resource_dir}/jalview_archive_getdown_progress_bar.png")
2603 // remove the existing resource = resource/ or bin/ lines
2604 if (! line.matches("resource\\s*=\\s*(resource|bin)/.*")) {
2605 getdownArchiveTextLines += line
2609 // the resource dir -- add these files as resource lines in getdown.txt
2611 from "${archiveImagesDir}"
2612 into "${getdownFullArchiveDir}/${getdown_resource_dir}"
2614 getdownArchiveTextLines += "resource = ${getdown_resource_dir}/${file.getName()}"
2618 // the wrapper scripts dir
2619 if ( file("${getdownAppBaseDir}/${getdown_wrapper_script_dir}").exists() ) {
2621 from "${getdownAppBaseDir}/${getdown_wrapper_script_dir}"
2622 into "${getdownFullArchiveDir}/${getdown_wrapper_script_dir}"
2626 getdownArchiveTxt.write(getdownArchiveTextLines.join("\n"))
2628 def vLaunchJvl = file(getdownVersionLaunchJvl)
2629 vLaunchJvl.getParentFile().mkdirs()
2630 vLaunchJvl.write("appbase=${getdownFullArchiveAppBase}\n")
2631 def vLaunchJvlPath = vLaunchJvl.toPath().toAbsolutePath()
2632 def jvlLinkPath = file("${vDir}/jalview.jvl").toPath().toAbsolutePath()
2633 // for some reason filepath.relativize(fileInSameDirPath) gives a path to "../" which is wrong
2634 //java.nio.file.Files.createSymbolicLink(jvlLinkPath, jvlLinkPath.relativize(vLaunchJvlPath));
2635 java.nio.file.Files.createSymbolicLink(jvlLinkPath, java.nio.file.Paths.get(".",vLaunchJvl.getName()));
2637 // files going into the getdown files dir: getdown.txt, getdown-launcher.jar, channel-launch.jvl, build_properties
2639 from getdownLauncher
2640 from "${getdownAppBaseDir}/${getdownLaunchJvl}"
2641 from "${getdownAppBaseDir}/${getdown_launcher_new}"
2642 from "${getdownAppBaseDir}/${channel_props}"
2643 if (file(getdownLauncher).getName() != getdown_launcher) {
2644 rename(file(getdownLauncher).getName(), getdown_launcher)
2646 into getdownFullArchiveDir
2652 task getdownArchiveDigest(type: JavaExec) {
2653 group = "distribution"
2654 description = "Digest the getdown archive folder"
2656 dependsOn getdownArchiveBuild
2659 classpath = files(getdownLauncher)
2660 args getdownFullArchiveDir
2662 main = "com.threerings.getdown.tools.Digester"
2663 inputs.dir(getdownFullArchiveDir)
2664 outputs.file("${getdownFullArchiveDir}/digest2.txt")
2667 task getdownArchive() {
2668 group = "distribution"
2669 description = "Build the website archive dir with getdown digest"
2671 dependsOn getdownArchiveBuild
2672 dependsOn getdownArchiveDigest
2675 tasks.withType(JavaCompile) {
2676 options.encoding = 'UTF-8'
2682 delete getdownAppBaseDir
2683 delete getdownFilesDir
2684 delete getdownArchiveDir
2690 if (file(install4jHomeDir).exists()) {
2692 } else if (file(System.getProperty("user.home")+"/buildtools/install4j").exists()) {
2693 install4jHomeDir = System.getProperty("user.home")+"/buildtools/install4j"
2694 } else if (file("/Applications/install4j.app/Contents/Resources/app").exists()) {
2695 install4jHomeDir = "/Applications/install4j.app/Contents/Resources/app"
2697 installDir(file(install4jHomeDir))
2699 mediaTypes = Arrays.asList(install4j_media_types.split(","))
2703 task copyInstall4jTemplate {
2704 def install4jTemplateFile = file("${install4jDir}/${install4j_template}")
2705 def install4jFileAssociationsFile = file("${install4jDir}/${install4j_installer_file_associations}")
2706 inputs.file(install4jTemplateFile)
2707 inputs.file(install4jFileAssociationsFile)
2708 inputs.property("CHANNEL", { CHANNEL })
2709 outputs.file(install4jConfFile)
2712 def install4jConfigXml = new XmlParser().parse(install4jTemplateFile)
2714 // turn off code signing if no OSX_KEYPASS
2715 if (OSX_KEYPASS == "") {
2716 install4jConfigXml.'**'.codeSigning.each { codeSigning ->
2717 codeSigning.'@macEnabled' = "false"
2719 install4jConfigXml.'**'.windows.each { windows ->
2720 windows.'@runPostProcessor' = "false"
2724 // disable install screen for OSX dmg (for 2.11.2.0)
2725 install4jConfigXml.'**'.macosArchive.each { macosArchive ->
2726 macosArchive.attributes().remove('executeSetupApp')
2727 macosArchive.attributes().remove('setupAppId')
2730 // turn off checksum creation for LOCAL channel
2731 def e = install4jConfigXml.application[0]
2732 e.'@createChecksums' = string(install4jCheckSums)
2734 // put file association actions where placeholder action is
2735 def install4jFileAssociationsText = install4jFileAssociationsFile.text
2736 def fileAssociationActions = new XmlParser().parseText("<actions>${install4jFileAssociationsText}</actions>")
2737 install4jConfigXml.'**'.action.any { a -> // .any{} stops after the first one that returns true
2738 if (a.'@name' == 'EXTENSIONS_REPLACED_BY_GRADLE') {
2739 def parent = a.parent()
2741 fileAssociationActions.each { faa ->
2744 // don't need to continue in .any loop once replacements have been made
2749 // use Windows Program Group with Examples folder for RELEASE, and Program Group without Examples for everything else
2750 // NB we're deleting the /other/ one!
2751 // Also remove the examples subdir from non-release versions
2752 def customizedIdToDelete = "PROGRAM_GROUP_RELEASE"
2753 // 2.11.1.0 NOT releasing with the Examples folder in the Program Group
2754 if (false && CHANNEL=="RELEASE") { // remove 'false && ' to include Examples folder in RELEASE channel
2755 customizedIdToDelete = "PROGRAM_GROUP_NON_RELEASE"
2757 // remove the examples subdir from Full File Set
2758 def files = install4jConfigXml.files[0]
2759 def fileset = files.filesets.fileset.find { fs -> fs.'@customizedId' == "FULL_FILE_SET" }
2760 def root = files.roots.root.find { r -> r.'@fileset' == fileset.'@id' }
2761 def mountPoint = files.mountPoints.mountPoint.find { mp -> mp.'@root' == root.'@id' }
2762 def dirEntry = files.entries.dirEntry.find { de -> de.'@mountPoint' == mountPoint.'@id' && de.'@subDirectory' == "examples" }
2763 dirEntry.parent().remove(dirEntry)
2765 install4jConfigXml.'**'.action.any { a ->
2766 if (a.'@customizedId' == customizedIdToDelete) {
2767 def parent = a.parent()
2773 // write install4j file
2774 install4jConfFile.text = XmlUtil.serialize(install4jConfigXml)
2781 delete install4jConfFile
2785 task cleanInstallersDataFiles {
2786 def installersOutputTxt = file("${jalviewDir}/${install4jBuildDir}/output.txt")
2787 def installersSha256 = file("${jalviewDir}/${install4jBuildDir}/sha256sums")
2788 def hugoDataJsonFile = file("${jalviewDir}/${install4jBuildDir}/installers-${JALVIEW_VERSION_UNDERSCORES}.json")
2790 delete installersOutputTxt
2791 delete installersSha256
2792 delete hugoDataJsonFile
2796 task install4jDMGBackgroundImageCopy {
2797 inputs.file "${install4jDMGBackgroundImageDir}/${install4jDMGBackgroundImageFile}"
2798 outputs.dir "${install4jDMGBackgroundImageBuildDir}"
2801 from(install4jDMGBackgroundImageDir) {
2802 include(install4jDMGBackgroundImageFile)
2804 into install4jDMGBackgroundImageBuildDir
2809 task install4jDMGBackgroundImageProcess {
2810 dependsOn install4jDMGBackgroundImageCopy
2813 if (backgroundImageText) {
2814 if (convertBinary == null) {
2815 throw new StopExecutionException("No ImageMagick convert binary installed at '${convertBinaryExpectedLocation}'")
2817 if (!project.hasProperty("install4j_background_image_text_suffix_cmd")) {
2818 throw new StopExecutionException("No property 'install4j_background_image_text_suffix_cmd' defined. See channel_gradle.properties for channel ${CHANNEL}")
2820 fileTree(dir: install4jDMGBackgroundImageBuildDir, include: "*.png").getFiles().each { file ->
2822 executable convertBinary
2825 '-font', install4j_background_image_text_font,
2826 '-fill', install4j_background_image_text_colour,
2827 '-draw', sprintf(install4j_background_image_text_suffix_cmd, channelSuffix),
2828 '-draw', sprintf(install4j_background_image_text_commit_cmd, "git-commit: ${gitHash}"),
2829 '-draw', sprintf(install4j_background_image_text_date_cmd, getDate("yyyy-MM-dd HH:mm:ss")),
2840 pip 'ds_store:1.3.1'
2843 task install4jCustomiseDS_Store(type: PythonTask) {
2844 inputs.file(install4jDMGDSStore)
2845 inputs.file(install4jDMGDSStoreJSON)
2846 outputs.file(install4jDMGFixedDSStore)
2847 command = [ jalview_customise_ds_store, '--input', install4jDMGDSStore, '--output', install4jDMGFixedDSStore, '--volumename', install4jmacOSArchiveName, '--background', install4j_dmg_background_filename, '--config', install4jDMGDSStoreJSON ]
2851 task install4jDMGProcesses {
2852 dependsOn install4jDMGBackgroundImageProcess
2853 dependsOn install4jCustomiseDS_Store
2856 task installerFiles(type: com.install4j.gradle.Install4jTask) {
2857 group = "distribution"
2858 description = "Create the install4j installers"
2860 dependsOn copyInstall4jTemplate
2861 dependsOn cleanInstallersDataFiles
2862 dependsOn install4jDMGProcesses
2864 projectFile = install4jConfFile
2866 // run install4j with 4g
2867 vmParameters = ["-Xmx4294967296"]
2869 // create an md5 for the input files to use as version for install4j conf file
2870 def digest = MessageDigest.getInstance("MD5")
2872 (file("${install4jDir}/${install4j_template}").text +
2873 file("${install4jDir}/${install4j_info_plist_file_associations}").text +
2874 file("${install4jDir}/${install4j_installer_file_associations}").text).bytes)
2875 def filesMd5 = new BigInteger(1, digest.digest()).toString(16)
2876 if (filesMd5.length() >= 8) {
2877 filesMd5 = filesMd5.substring(0,8)
2879 def install4jTemplateVersion = "${JALVIEW_VERSION}_F${filesMd5}_C${gitHash}"
2882 'JALVIEW_NAME': jalview_name,
2883 'JALVIEW_APPLICATION_NAME': applicationName,
2884 'JALVIEW_DIR': "../..",
2885 'OSX_KEYSTORE': OSX_KEYSTORE,
2886 'OSX_APPLEID': OSX_APPLEID,
2887 'OSX_ALTOOLPASS': OSX_ALTOOLPASS,
2888 'JSIGN_SH': JSIGN_SH,
2889 'JRE_DIR': getdown_app_dir_java,
2890 'INSTALLER_TEMPLATE_VERSION': install4jTemplateVersion,
2891 'JALVIEW_VERSION': JALVIEW_VERSION,
2892 'JAVA_MIN_VERSION': JAVA_MIN_VERSION,
2893 'JAVA_MAX_VERSION': JAVA_MAX_VERSION,
2894 'JAVA_VERSION': JAVA_VERSION,
2895 'JAVA_INTEGER_VERSION': JAVA_INTEGER_VERSION,
2896 'VERSION': JALVIEW_VERSION,
2897 'COPYRIGHT_MESSAGE': install4j_copyright_message,
2898 'BUNDLE_ID': install4jBundleId,
2899 'INTERNAL_ID': install4jInternalId,
2900 'WINDOWS_APPLICATION_ID': install4jWinApplicationId,
2901 'MACOS_DMG_DS_STORE': install4jDMGFixedDSStore,
2902 'MACOS_DMG_BG_IMAGE': "${install4jDMGBackgroundImageBuildDir}/${install4jDMGBackgroundImageFile}",
2903 'MACOS_DMG_BG_FILENAME': install4j_dmg_background_filename,
2904 'WRAPPER_LINK': getdownWrapperLink,
2905 'BASH_WRAPPER_SCRIPT': getdown_bash_wrapper_script,
2906 'POWERSHELL_WRAPPER_SCRIPT': getdown_powershell_wrapper_script,
2907 'BATCH_WRAPPER_SCRIPT': getdown_batch_wrapper_script,
2908 'WRAPPER_SCRIPT_BIN_DIR': getdown_wrapper_script_dir,
2909 'MACOSARCHIVE_X86_NAME': install4jmacOSArchiveX86Name,
2910 'MACOSARCHIVE_AARCH64_NAME': install4jmacOSArchiveAarch64Name,
2911 'INSTALL4J_UTILS_DIR': install4j_utils_dir,
2912 'GETDOWN_CHANNEL_DIR': getdownChannelDir,
2913 'GETDOWN_FILES_DIR': getdown_files_dir,
2914 'GETDOWN_RESOURCE_DIR': getdown_resource_dir,
2915 'GETDOWN_DIST_DIR': getdownAppDistDir,
2916 'GETDOWN_ALT_DIR': getdown_app_dir_alt,
2917 'GETDOWN_INSTALL_DIR': getdown_install_dir,
2918 'INFO_PLIST_FILE_ASSOCIATIONS_FILE': install4j_info_plist_file_associations,
2919 'BUILD_DIR': install4jBuildDir,
2920 'APPLICATION_CATEGORIES': install4j_application_categories,
2921 'APPLICATION_FOLDER': install4jApplicationFolder,
2922 'UNIX_APPLICATION_FOLDER': install4jUnixApplicationFolder,
2923 'EXECUTABLE_NAME': install4jExecutableName,
2924 'EXTRA_SCHEME': install4jExtraScheme,
2925 'MAC_ICONS_FILE': install4jMacIconsFile,
2926 'WINDOWS_ICONS_FILE': install4jWindowsIconsFile,
2927 'PNG_ICON_FILE': install4jPngIconFile,
2928 'BACKGROUND': install4jBackground,
2933 'windows': 'WINDOWS',
2937 // these are the bundled OS/architecture VMs needed by install4j
2940 [ "mac", "aarch64" ],
2941 [ "windows", "x64" ],
2943 [ "linux", "aarch64" ]
2945 osArch.forEach { os, arch ->
2946 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)
2947 // N.B. For some reason install4j requires the below filename to have underscores and not hyphens
2948 // otherwise running `gradle installers` generates a non-useful error:
2949 // `install4j: compilation failed. Reason: java.lang.NumberFormatException: For input string: "windows"`
2950 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)
2953 //println("INSTALL4J VARIABLES:")
2954 //variables.each{k,v->println("${k}=${v}")}
2956 destination = "${jalviewDir}/${install4jBuildDir}"
2957 buildSelected = true
2959 if (install4j_faster.equals("true") || CHANNEL.startsWith("LOCAL")) {
2961 disableSigning = true
2962 disableNotarization = true
2966 macKeystorePassword = OSX_KEYPASS
2969 if (OSX_ALTOOLPASS) {
2970 appleIdPassword = OSX_ALTOOLPASS
2971 disableNotarization = false
2973 disableNotarization = true
2977 println("Using projectFile "+projectFile)
2978 if (!disableNotarization) { println("Will notarize OSX App DMG") }
2982 inputs.dir(getdownAppBaseDir)
2983 inputs.file(install4jConfFile)
2984 inputs.file("${install4jDir}/${install4j_info_plist_file_associations}")
2985 outputs.dir("${jalviewDir}/${install4j_build_dir}/${JAVA_VERSION}")
2988 def getDataHash(File myFile) {
2989 HashCode hash = Files.asByteSource(myFile).hash(Hashing.sha256())
2990 return myFile.exists()
2992 "file" : myFile.getName(),
2993 "filesize" : myFile.length(),
2994 "sha256" : hash.toString()
2999 def writeDataJsonFile(File installersOutputTxt, File installersSha256, File dataJsonFile) {
3001 "channel" : getdownChannelName,
3002 "date" : getDate("yyyy-MM-dd HH:mm:ss"),
3003 "git-commit" : "${gitHash} [${gitBranch}]",
3004 "version" : JALVIEW_VERSION
3006 // install4j installer files
3007 if (installersOutputTxt.exists()) {
3009 installersOutputTxt.readLines().each { def line ->
3010 if (line.startsWith("#")) {
3013 line.replaceAll("\n","")
3014 def vals = line.split("\t")
3015 def filename = vals[3]
3016 def filesize = file(filename).length()
3017 filename = filename.replaceAll(/^.*\//, "")
3018 hash[vals[0]] = [ "id" : vals[0], "os" : vals[1], "name" : vals[2], "file" : filename, "filesize" : filesize ]
3019 idHash."${filename}" = vals[0]
3021 if (install4jCheckSums && installersSha256.exists()) {
3022 installersSha256.readLines().each { def line ->
3023 if (line.startsWith("#")) {
3026 line.replaceAll("\n","")
3027 def vals = line.split(/\s+\*?/)
3028 def filename = vals[1]
3029 def innerHash = (hash.(idHash."${filename}"))."sha256" = vals[0]
3035 "JAR": shadowJar.archiveFile, // executable JAR
3036 "JVL": getdownVersionLaunchJvl, // version JVL
3037 "SOURCE": sourceDist.archiveFile // source TGZ
3038 ].each { key, value ->
3039 def file = file(value)
3040 if (file.exists()) {
3041 def fileHash = getDataHash(file)
3042 if (fileHash != null) {
3043 hash."${key}" = fileHash;
3047 return dataJsonFile.write(new JsonBuilder(hash).toPrettyString())
3050 task staticMakeInstallersJsonFile {
3052 def output = findProperty("i4j_output")
3053 def sha256 = findProperty("i4j_sha256")
3054 def json = findProperty("i4j_json")
3055 if (output == null || sha256 == null || json == null) {
3056 throw new GradleException("Must provide paths to all of output.txt, sha256sums, and output.json with '-Pi4j_output=... -Pi4j_sha256=... -Pi4j_json=...")
3058 writeDataJsonFile(file(output), file(sha256), file(json))
3063 dependsOn installerFiles
3069 eclipse().configFile(eclipse_codestyle_file)
3073 task createSourceReleaseProperties(type: WriteProperties) {
3074 group = "distribution"
3075 description = "Create the source RELEASE properties file"
3077 def sourceTarBuildDir = "${buildDir}/sourceTar"
3078 def sourceReleasePropertiesFile = "${sourceTarBuildDir}/RELEASE"
3079 outputFile (sourceReleasePropertiesFile)
3082 releaseProps.each{ key, val -> property key, val }
3083 property "git.branch", gitBranch
3084 property "git.hash", gitHash
3087 outputs.file(outputFile)
3090 task sourceDist(type: Tar) {
3091 group "distribution"
3092 description "Create a source .tar.gz file for distribution"
3094 dependsOn createBuildProperties
3095 dependsOn convertMdFiles
3096 dependsOn eclipseAllPreferences
3097 dependsOn createSourceReleaseProperties
3100 def outputFileName = "${project.name}_${JALVIEW_VERSION_UNDERSCORES}.tar.gz"
3101 archiveFileName = outputFileName
3103 compression Compression.GZIP
3119 "**/*.class","$j11modDir/**/*.jar","appletlib","**/*locales",
3121 "utils/InstallAnywhere",
3136 "gradle.properties",
3148 ".settings/org.eclipse.buildship.core.prefs",
3149 ".settings/org.eclipse.jdt.core.prefs"
3153 exclude (EXCLUDE_FILES)
3154 include (PROCESS_FILES)
3155 filter(ReplaceTokens,
3159 'Version-Rel': JALVIEW_VERSION,
3160 'Year-Rel': getDate("yyyy")
3165 exclude (EXCLUDE_FILES)
3166 exclude (PROCESS_FILES)
3167 exclude ("appletlib")
3168 exclude ("**/*locales")
3169 exclude ("*locales/**")
3170 exclude ("utils/InstallAnywhere")
3172 exclude (getdown_files_dir)
3173 // getdown_website_dir and getdown_archive_dir moved to build/website/docroot/getdown
3174 //exclude (getdown_website_dir)
3175 //exclude (getdown_archive_dir)
3177 // exluding these as not using jars as modules yet
3178 exclude ("${j11modDir}/**/*.jar")
3181 include(INCLUDE_FILES)
3183 // from (jalviewDir) {
3184 // // explicit includes for stuff that seemed to not get included
3185 // include(fileTree("test/**/*."))
3186 // exclude(EXCLUDE_FILES)
3187 // exclude(PROCESS_FILES)
3190 from(file(buildProperties).getParent()) {
3191 include(file(buildProperties).getName())
3192 rename(file(buildProperties).getName(), "build_properties")
3194 line.replaceAll("^INSTALLATION=.*\$","INSTALLATION=Source Release"+" git-commit\\\\:"+gitHash+" ["+gitBranch+"]")
3198 def sourceTarBuildDir = "${buildDir}/sourceTar"
3199 from(sourceTarBuildDir) {
3200 // this includes the appended RELEASE properties file
3204 task dataInstallersJson {
3206 description "Create the installers-VERSION.json data file for installer files created"
3208 mustRunAfter installers
3209 mustRunAfter shadowJar
3210 mustRunAfter sourceDist
3211 mustRunAfter getdownArchive
3213 def installersOutputTxt = file("${jalviewDir}/${install4jBuildDir}/output.txt")
3214 def installersSha256 = file("${jalviewDir}/${install4jBuildDir}/sha256sums")
3216 if (installersOutputTxt.exists()) {
3217 inputs.file(installersOutputTxt)
3219 if (install4jCheckSums && installersSha256.exists()) {
3220 inputs.file(installersSha256)
3223 shadowJar.archiveFile, // executable JAR
3224 getdownVersionLaunchJvl, // version JVL
3225 sourceDist.archiveFile // source TGZ
3226 ].each { fileName ->
3227 if (file(fileName).exists()) {
3228 inputs.file(fileName)
3232 outputs.file(hugoDataJsonFile)
3235 writeDataJsonFile(installersOutputTxt, installersSha256, hugoDataJsonFile)
3241 description "Copies all help pages to build dir. Runs ant task 'pubhtmlhelp'."
3244 dependsOn pubhtmlhelp
3246 inputs.dir("${helpBuildDir}/${help_dir}")
3247 outputs.dir("${buildDir}/distributions/${help_dir}")
3251 task j2sSetHeadlessBuild {
3258 task jalviewjsEnableAltFileProperty(type: WriteProperties) {
3260 description "Enable the alternative J2S Config file for headless build"
3262 outputFile = jalviewjsJ2sSettingsFileName
3263 def j2sPropsFile = file(jalviewjsJ2sSettingsFileName)
3264 def j2sProps = new Properties()
3265 if (j2sPropsFile.exists()) {
3267 def j2sPropsFileFIS = new FileInputStream(j2sPropsFile)
3268 j2sProps.load(j2sPropsFileFIS)
3269 j2sPropsFileFIS.close()
3271 j2sProps.each { prop, val ->
3274 } catch (Exception e) {
3275 println("Exception reading ${jalviewjsJ2sSettingsFileName}")
3279 if (! j2sProps.stringPropertyNames().contains(jalviewjs_j2s_alt_file_property_config)) {
3280 property(jalviewjs_j2s_alt_file_property_config, jalviewjs_j2s_alt_file_property)
3285 task jalviewjsSetEclipseWorkspace {
3286 def propKey = "jalviewjs_eclipse_workspace"
3288 if (project.hasProperty(propKey)) {
3289 propVal = project.getProperty(propKey)
3290 if (propVal.startsWith("~/")) {
3291 propVal = System.getProperty("user.home") + propVal.substring(1)
3294 def propsFileName = "${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_eclipse_workspace_location_file}"
3295 def propsFile = file(propsFileName)
3296 def eclipseWsDir = propVal
3297 def props = new Properties()
3299 def writeProps = true
3300 if (( eclipseWsDir == null || !file(eclipseWsDir).exists() ) && propsFile.exists()) {
3301 def ins = new FileInputStream(propsFileName)
3304 if (props.getProperty(propKey, null) != null) {
3305 eclipseWsDir = props.getProperty(propKey)
3310 if (eclipseWsDir == null || !file(eclipseWsDir).exists()) {
3311 def tempDir = File.createTempDir()
3312 eclipseWsDir = tempDir.getAbsolutePath()
3315 eclipseWorkspace = file(eclipseWsDir)
3318 // do not run a headless transpile when we claim to be in Eclipse
3320 println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3321 throw new StopExecutionException("Not running headless transpile whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
3323 println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3327 props.setProperty(propKey, eclipseWsDir)
3328 propsFile.parentFile.mkdirs()
3329 def bytes = new ByteArrayOutputStream()
3330 props.store(bytes, null)
3331 def propertiesString = bytes.toString()
3332 propsFile.text = propertiesString
3338 println("ECLIPSE WORKSPACE: "+eclipseWorkspace.getPath())
3341 //inputs.property(propKey, eclipseWsDir) // eclipseWsDir only gets set once this task runs, so will be out-of-date
3342 outputs.file(propsFileName)
3343 outputs.upToDateWhen { eclipseWorkspace.exists() && propsFile.exists() }
3347 task jalviewjsEclipsePaths {
3350 def eclipseRoot = jalviewjs_eclipse_root
3351 if (eclipseRoot.startsWith("~/")) {
3352 eclipseRoot = System.getProperty("user.home") + eclipseRoot.substring(1)
3354 if (OperatingSystem.current().isMacOsX()) {
3355 eclipseRoot += "/Eclipse.app"
3356 eclipseBinary = "${eclipseRoot}/Contents/MacOS/eclipse"
3357 eclipseProduct = "${eclipseRoot}/Contents/Eclipse/.eclipseproduct"
3358 } else if (OperatingSystem.current().isWindows()) { // check these paths!!
3359 if (file("${eclipseRoot}/eclipse").isDirectory() && file("${eclipseRoot}/eclipse/.eclipseproduct").exists()) {
3360 eclipseRoot += "/eclipse"
3362 eclipseBinary = "${eclipseRoot}/eclipse.exe"
3363 eclipseProduct = "${eclipseRoot}/.eclipseproduct"
3364 } else { // linux or unix
3365 if (file("${eclipseRoot}/eclipse").isDirectory() && file("${eclipseRoot}/eclipse/.eclipseproduct").exists()) {
3366 eclipseRoot += "/eclipse"
3367 println("eclipseDir exists")
3369 eclipseBinary = "${eclipseRoot}/eclipse"
3370 eclipseProduct = "${eclipseRoot}/.eclipseproduct"
3373 eclipseVersion = "4.13" // default
3374 def assumedVersion = true
3375 if (file(eclipseProduct).exists()) {
3376 def fis = new FileInputStream(eclipseProduct)
3377 def props = new Properties()
3379 eclipseVersion = props.getProperty("version")
3381 assumedVersion = false
3384 def propKey = "eclipse_debug"
3385 eclipseDebug = (project.hasProperty(propKey) && project.getProperty(propKey).equals("true"))
3388 // do not run a headless transpile when we claim to be in Eclipse
3390 println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3391 throw new StopExecutionException("Not running headless transpile whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
3393 println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3396 if (!assumedVersion) {
3397 println("ECLIPSE VERSION=${eclipseVersion}")
3403 task printProperties {
3405 description "Output to console all System.properties"
3407 System.properties.each { key, val -> System.out.println("Property: ${key}=${val}") }
3413 dependsOn eclipseProject
3414 dependsOn eclipseClasspath
3415 dependsOn eclipseJdt
3419 // this version (type: Copy) will delete anything in the eclipse dropins folder that isn't in fromDropinsDir
3420 task jalviewjsEclipseCopyDropins(type: Copy) {
3421 dependsOn jalviewjsEclipsePaths
3423 def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjs_eclipse_dropins_dir}", include: "*.jar")
3424 inputFiles += file("${jalviewDir}/${jalviewjsJ2sPlugin}")
3425 def outputDir = "${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_eclipse_tmp_dropins_dir}"
3432 // this eclipse -clean doesn't actually work
3433 task jalviewjsCleanEclipse(type: Exec) {
3434 dependsOn eclipseSetup
3435 dependsOn jalviewjsEclipsePaths
3436 dependsOn jalviewjsEclipseCopyDropins
3438 executable(eclipseBinary)
3439 args(["-nosplash", "--launcher.suppressErrors", "-data", eclipseWorkspace.getPath(), "-clean", "-console", "-consoleLog"])
3445 def inputString = """exit
3448 def inputByteStream = new ByteArrayInputStream(inputString.getBytes())
3449 standardInput = inputByteStream
3452 /* not really working yet
3453 jalviewjsEclipseCopyDropins.finalizedBy jalviewjsCleanEclipse
3457 task jalviewjsTransferUnzipSwingJs {
3458 def file_zip = "${jalviewDir}/${jalviewjs_swingjs_zip}"
3462 from zipTree(file_zip)
3463 into "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}"
3467 inputs.file file_zip
3468 outputs.dir "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}"
3472 task jalviewjsTransferUnzipLib {
3473 def zipFiles = fileTree(dir: "${jalviewDir}/${jalviewjs_libjs_dir}", include: "*.zip")
3476 zipFiles.each { file_zip ->
3478 from zipTree(file_zip)
3479 into "${jalviewDir}/${jalviewjsTransferSiteLibDir}"
3484 inputs.files zipFiles
3485 outputs.dir "${jalviewDir}/${jalviewjsTransferSiteLibDir}"
3489 task jalviewjsTransferUnzipAllLibs {
3490 dependsOn jalviewjsTransferUnzipSwingJs
3491 dependsOn jalviewjsTransferUnzipLib
3495 task jalviewjsCreateJ2sSettings(type: WriteProperties) {
3497 description "Create the alternative j2s file from the j2s.* properties"
3499 jalviewjsJ2sProps = project.properties.findAll { it.key.startsWith("j2s.") }.sort { it.key }
3500 def siteDirProperty = "j2s.site.directory"
3501 def setSiteDir = false
3502 jalviewjsJ2sProps.each { prop, val ->
3504 if (prop == siteDirProperty) {
3505 if (!(val.startsWith('/') || val.startsWith("file://") )) {
3506 val = "${jalviewDir}/${jalviewjsTransferSiteJsDir}/${val}"
3512 if (!setSiteDir) { // default site location, don't override specifically set property
3513 property(siteDirProperty,"${jalviewDirRelativePath}/${jalviewjsTransferSiteJsDir}")
3516 outputFile = jalviewjsJ2sAltSettingsFileName
3519 inputs.properties(jalviewjsJ2sProps)
3520 outputs.file(jalviewjsJ2sAltSettingsFileName)
3525 task jalviewjsEclipseSetup {
3526 dependsOn jalviewjsEclipseCopyDropins
3527 dependsOn jalviewjsSetEclipseWorkspace
3528 dependsOn jalviewjsCreateJ2sSettings
3532 task jalviewjsSyncAllLibs (type: Sync) {
3533 dependsOn jalviewjsTransferUnzipAllLibs
3534 def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjsTransferSiteLibDir}")
3535 inputFiles += fileTree(dir: "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}")
3536 def outputDir = "${jalviewDir}/${jalviewjsSiteDir}"
3540 def outputFiles = []
3541 rename { filename ->
3542 outputFiles += "${outputDir}/${filename}"
3549 // should this be exclude really ?
3550 duplicatesStrategy "INCLUDE"
3552 outputs.files outputFiles
3553 inputs.files inputFiles
3557 task jalviewjsSyncResources (type: Sync) {
3558 dependsOn buildResources
3560 def inputFiles = fileTree(dir: resourcesBuildDir)
3561 def outputDir = "${jalviewDir}/${jalviewjsSiteDir}/${jalviewjs_j2s_subdir}"
3565 def outputFiles = []
3566 rename { filename ->
3567 outputFiles += "${outputDir}/${filename}"
3573 outputs.files outputFiles
3574 inputs.files inputFiles
3578 task jalviewjsSyncSiteResources (type: Sync) {
3579 def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjs_site_resource_dir}")
3580 def outputDir = "${jalviewDir}/${jalviewjsSiteDir}"
3584 def outputFiles = []
3585 rename { filename ->
3586 outputFiles += "${outputDir}/${filename}"
3592 outputs.files outputFiles
3593 inputs.files inputFiles
3597 task jalviewjsSyncBuildProperties (type: Sync) {
3598 dependsOn createBuildProperties
3599 def inputFiles = [file(buildProperties)]
3600 def outputDir = "${jalviewDir}/${jalviewjsSiteDir}/${jalviewjs_j2s_subdir}"
3604 def outputFiles = []
3605 rename { filename ->
3606 outputFiles += "${outputDir}/${filename}"
3612 outputs.files outputFiles
3613 inputs.files inputFiles
3617 task jalviewjsProjectImport(type: Exec) {
3618 dependsOn eclipseSetup
3619 dependsOn jalviewjsEclipsePaths
3620 dependsOn jalviewjsEclipseSetup
3623 // do not run a headless import when we claim to be in Eclipse
3625 println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3626 throw new StopExecutionException("Not running headless import whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
3628 println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3632 //def projdir = eclipseWorkspace.getPath()+"/.metadata/.plugins/org.eclipse.core.resources/.projects/jalview/org.eclipse.jdt.core"
3633 def projdir = eclipseWorkspace.getPath()+"/.metadata/.plugins/org.eclipse.core.resources/.projects/jalview"
3634 executable(eclipseBinary)
3635 args(["-nosplash", "--launcher.suppressErrors", "-application", "com.seeq.eclipse.importprojects.headlessimport", "-data", eclipseWorkspace.getPath(), "-import", jalviewDirAbsolutePath])
3639 args += [ "--launcher.appendVmargs", "-vmargs", "-Dorg.eclipse.equinox.p2.reconciler.dropins.directory=${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_eclipse_tmp_dropins_dir}" ]
3641 args += [ "-D${j2sHeadlessBuildProperty}=true" ]
3642 args += [ "-D${jalviewjs_j2s_alt_file_property}=${jalviewjsJ2sAltSettingsFileName}" ]
3645 inputs.file("${jalviewDir}/.project")
3646 outputs.upToDateWhen {
3647 file(projdir).exists()
3652 task jalviewjsTranspile(type: Exec) {
3653 dependsOn jalviewjsEclipseSetup
3654 dependsOn jalviewjsProjectImport
3655 dependsOn jalviewjsEclipsePaths
3657 dependsOn jalviewjsEnableAltFileProperty
3661 // do not run a headless transpile when we claim to be in Eclipse
3663 println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3664 throw new StopExecutionException("Not running headless transpile whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
3666 println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3670 executable(eclipseBinary)
3671 args(["-nosplash", "--launcher.suppressErrors", "-application", "org.eclipse.jdt.apt.core.aptBuild", "-data", eclipseWorkspace, "-${jalviewjs_eclipse_build_arg}", eclipse_project_name ])
3675 args += [ "--launcher.appendVmargs", "-vmargs", "-Dorg.eclipse.equinox.p2.reconciler.dropins.directory=${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_eclipse_tmp_dropins_dir}" ]
3677 args += [ "-D${j2sHeadlessBuildProperty}=true" ]
3678 args += [ "-D${jalviewjs_j2s_alt_file_property}=${jalviewjsJ2sAltSettingsFileName}" ]
3684 stdout = new ByteArrayOutputStream()
3685 stderr = new ByteArrayOutputStream()
3687 def logOutFileName = "${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}"
3688 def logOutFile = file(logOutFileName)
3689 logOutFile.createNewFile()
3690 logOutFile.text = """ROOT: ${jalviewjs_eclipse_root}
3691 BINARY: ${eclipseBinary}
3692 VERSION: ${eclipseVersion}
3693 WORKSPACE: ${eclipseWorkspace}
3694 DEBUG: ${eclipseDebug}
3697 def logOutFOS = new FileOutputStream(logOutFile, true) // true == append
3698 // combine stdout and stderr
3699 def logErrFOS = logOutFOS
3701 if (jalviewjs_j2s_to_console.equals("true")) {
3702 standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
3703 new org.apache.tools.ant.util.TeeOutputStream(
3707 errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
3708 new org.apache.tools.ant.util.TeeOutputStream(
3713 standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
3716 errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
3723 if (stdout.toString().contains("Error processing ")) {
3724 // j2s did not complete transpile
3725 //throw new TaskExecutionException("Error during transpilation:\n${stderr}\nSee eclipse transpile log file '${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}'")
3726 if (jalviewjs_ignore_transpile_errors.equals("true")) {
3727 println("IGNORING TRANSPILE ERRORS")
3728 println("See eclipse transpile log file '${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}'")
3730 throw new GradleException("Error during transpilation:\n${stderr}\nSee eclipse transpile log file '${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}'")
3735 inputs.dir("${jalviewDir}/${sourceDir}")
3736 outputs.dir("${jalviewDir}/${jalviewjsTransferSiteJsDir}")
3737 outputs.upToDateWhen( { file("${jalviewDir}/${jalviewjsTransferSiteJsDir}${jalviewjs_server_resource}").exists() } )
3741 def jalviewjsCallCore(String name, FileCollection list, String prefixFile, String suffixFile, String jsfile, String zjsfile, File logOutFile, Boolean logOutConsole) {
3743 def stdout = new ByteArrayOutputStream()
3744 def stderr = new ByteArrayOutputStream()
3746 def coreFile = file(jsfile)
3748 msg = "Creating core for ${name}...\nGenerating ${jsfile}"
3750 logOutFile.createNewFile()
3751 logOutFile.append(msg+"\n")
3753 def coreTop = file(prefixFile)
3754 def coreBottom = file(suffixFile)
3755 coreFile.getParentFile().mkdirs()
3756 coreFile.createNewFile()
3757 coreFile.write( coreTop.getText("UTF-8") )
3761 def t = f.getText("UTF-8")
3762 t.replaceAll("Clazz\\.([^_])","Clazz_${1}")
3763 coreFile.append( t )
3765 msg = "...file '"+f.getPath()+"' does not exist, skipping"
3767 logOutFile.append(msg+"\n")
3770 coreFile.append( coreBottom.getText("UTF-8") )
3772 msg = "Generating ${zjsfile}"
3774 logOutFile.append(msg+"\n")
3775 def logOutFOS = new FileOutputStream(logOutFile, true) // true == append
3776 def logErrFOS = logOutFOS
3779 classpath = files(["${jalviewDir}/${jalviewjs_closure_compiler}"])
3780 main = "com.google.javascript.jscomp.CommandLineRunner"
3781 jvmArgs = [ "-Dfile.encoding=UTF-8" ]
3782 args = [ "--compilation_level", "SIMPLE_OPTIMIZATIONS", "--warning_level", "QUIET", "--charset", "UTF-8", "--js", jsfile, "--js_output_file", zjsfile ]
3785 msg = "\nRunning '"+commandLine.join(' ')+"'\n"
3787 logOutFile.append(msg+"\n")
3789 if (logOutConsole) {
3790 standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
3791 new org.apache.tools.ant.util.TeeOutputStream(
3795 errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
3796 new org.apache.tools.ant.util.TeeOutputStream(
3801 standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
3804 errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
3811 logOutFile.append(msg+"\n")
3815 task jalviewjsBuildAllCores {
3817 description "Build the core js lib closures listed in the classlists dir"
3818 dependsOn jalviewjsTranspile
3819 dependsOn jalviewjsTransferUnzipSwingJs
3821 def j2sDir = "${jalviewDir}/${jalviewjsTransferSiteJsDir}/${jalviewjs_j2s_subdir}"
3822 def swingJ2sDir = "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}/${jalviewjs_j2s_subdir}"
3823 def libJ2sDir = "${jalviewDir}/${jalviewjsTransferSiteLibDir}/${jalviewjs_j2s_subdir}"
3824 def jsDir = "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}/${jalviewjs_js_subdir}"
3825 def outputDir = "${jalviewDir}/${jalviewjsTransferSiteCoreDir}/${jalviewjs_j2s_subdir}/core"
3826 def prefixFile = "${jsDir}/core/coretop2.js"
3827 def suffixFile = "${jsDir}/core/corebottom2.js"
3829 inputs.file prefixFile
3830 inputs.file suffixFile
3832 def classlistFiles = []
3833 // add the classlists found int the jalviewjs_classlists_dir
3834 fileTree(dir: "${jalviewDir}/${jalviewjs_classlists_dir}", include: "*.txt").each {
3836 def name = file.getName() - ".txt"
3843 // _jmol and _jalview cores. Add any other peculiar classlist.txt files here
3844 //classlistFiles += [ 'file': file("${jalviewDir}/${jalviewjs_classlist_jmol}"), 'name': "_jvjmol" ]
3845 classlistFiles += [ 'file': file("${jalviewDir}/${jalviewjs_classlist_jalview}"), 'name': jalviewjsJalviewCoreName ]
3847 jalviewjsCoreClasslists = []
3849 classlistFiles.each {
3852 def file = hash['file']
3853 if (! file.exists()) {
3854 //println("...classlist file '"+file.getPath()+"' does not exist, skipping")
3855 return false // this is a "continue" in groovy .each closure
3857 def name = hash['name']
3859 name = file.getName() - ".txt"
3867 def list = fileTree(dir: j2sDir, includes: filelist)
3869 def jsfile = "${outputDir}/core${name}.js"
3870 def zjsfile = "${outputDir}/core${name}.z.js"
3872 jalviewjsCoreClasslists += [
3881 outputs.file(jsfile)
3882 outputs.file(zjsfile)
3885 // _stevesoft core. add any cores without a classlist here (and the inputs and outputs)
3886 def stevesoftClasslistName = "_stevesoft"
3887 def stevesoftClasslist = [
3888 'jsfile': "${outputDir}/core${stevesoftClasslistName}.js",
3889 'zjsfile': "${outputDir}/core${stevesoftClasslistName}.z.js",
3890 'list': fileTree(dir: j2sDir, include: "com/stevesoft/pat/**/*.js"),
3891 'name': stevesoftClasslistName
3893 jalviewjsCoreClasslists += stevesoftClasslist
3894 inputs.files(stevesoftClasslist['list'])
3895 outputs.file(stevesoftClasslist['jsfile'])
3896 outputs.file(stevesoftClasslist['zjsfile'])
3899 def allClasslistName = "_all"
3900 def allJsFiles = fileTree(dir: j2sDir, include: "**/*.js")
3901 allJsFiles += fileTree(
3905 // these exlusions are files that the closure-compiler produces errors for. Should fix them
3906 "**/org/jmol/jvxl/readers/IsoIntersectFileReader.js",
3907 "**/org/jmol/export/JSExporter.js"
3910 allJsFiles += fileTree(
3914 // these exlusions are files that the closure-compiler produces errors for. Should fix them
3915 "**/sun/misc/Unsafe.js",
3916 "**/swingjs/jquery/jquery-editable-select.js",
3917 "**/swingjs/jquery/j2sComboBox.js",
3918 "**/sun/misc/FloatingDecimal.js"
3921 def allClasslist = [
3922 'jsfile': "${outputDir}/core${allClasslistName}.js",
3923 'zjsfile': "${outputDir}/core${allClasslistName}.z.js",
3925 'name': allClasslistName
3927 // not including this version of "all" core at the moment
3928 //jalviewjsCoreClasslists += allClasslist
3929 inputs.files(allClasslist['list'])
3930 outputs.file(allClasslist['jsfile'])
3931 outputs.file(allClasslist['zjsfile'])
3934 def logOutFile = file("${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_j2s_closure_stdout}")
3935 logOutFile.getParentFile().mkdirs()
3936 logOutFile.createNewFile()
3937 logOutFile.write(getDate("yyyy-MM-dd HH:mm:ss")+" jalviewjsBuildAllCores\n----\n")
3939 jalviewjsCoreClasslists.each {
3940 jalviewjsCallCore(it.name, it.list, prefixFile, suffixFile, it.jsfile, it.zjsfile, logOutFile, jalviewjs_j2s_to_console.equals("true"))
3947 def jalviewjsPublishCoreTemplate(String coreName, String templateName, File inputFile, String outputFile) {
3950 into file(outputFile).getParentFile()
3951 rename { filename ->
3952 if (filename.equals(inputFile.getName())) {
3953 return file(outputFile).getName()
3957 filter(ReplaceTokens,
3961 'MAIN': '"'+main_class+'"',
3963 'NAME': jalviewjsJalviewTemplateName+" [core ${coreName}]",
3964 'COREKEY': jalviewjs_core_key,
3965 'CORENAME': coreName
3972 task jalviewjsPublishCoreTemplates {
3973 dependsOn jalviewjsBuildAllCores
3974 def inputFileName = "${jalviewDir}/${j2s_coretemplate_html}"
3975 def inputFile = file(inputFileName)
3976 def outputDir = "${jalviewDir}/${jalviewjsTransferSiteCoreDir}"
3978 def outputFiles = []
3979 jalviewjsCoreClasslists.each { cl ->
3980 def outputFile = "${outputDir}/${jalviewjsJalviewTemplateName}_${cl.name}.html"
3981 cl['outputfile'] = outputFile
3982 outputFiles += outputFile
3986 jalviewjsCoreClasslists.each { cl ->
3987 jalviewjsPublishCoreTemplate(cl.name, jalviewjsJalviewTemplateName, inputFile, cl.outputfile)
3990 inputs.file(inputFile)
3991 outputs.files(outputFiles)
3995 task jalviewjsSyncCore (type: Sync) {
3996 dependsOn jalviewjsBuildAllCores
3997 dependsOn jalviewjsPublishCoreTemplates
3998 def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjsTransferSiteCoreDir}")
3999 def outputDir = "${jalviewDir}/${jalviewjsSiteDir}"
4003 def outputFiles = []
4004 rename { filename ->
4005 outputFiles += "${outputDir}/${filename}"
4011 outputs.files outputFiles
4012 inputs.files inputFiles
4016 // this Copy version of TransferSiteJs will delete anything else in the target dir
4017 task jalviewjsCopyTransferSiteJs(type: Copy) {
4018 dependsOn jalviewjsTranspile
4019 from "${jalviewDir}/${jalviewjsTransferSiteJsDir}"
4020 into "${jalviewDir}/${jalviewjsSiteDir}"
4024 // this Sync version of TransferSite is used by buildship to keep the website automatically up to date when a file changes
4025 task jalviewjsSyncTransferSiteJs(type: Sync) {
4026 from "${jalviewDir}/${jalviewjsTransferSiteJsDir}"
4028 into "${jalviewDir}/${jalviewjsSiteDir}"
4035 jalviewjsSyncAllLibs.mustRunAfter jalviewjsCopyTransferSiteJs
4036 jalviewjsSyncResources.mustRunAfter jalviewjsCopyTransferSiteJs
4037 jalviewjsSyncSiteResources.mustRunAfter jalviewjsCopyTransferSiteJs
4038 jalviewjsSyncBuildProperties.mustRunAfter jalviewjsCopyTransferSiteJs
4040 jalviewjsSyncAllLibs.mustRunAfter jalviewjsSyncTransferSiteJs
4041 jalviewjsSyncResources.mustRunAfter jalviewjsSyncTransferSiteJs
4042 jalviewjsSyncSiteResources.mustRunAfter jalviewjsSyncTransferSiteJs
4043 jalviewjsSyncBuildProperties.mustRunAfter jalviewjsSyncTransferSiteJs
4046 task jalviewjsPrepareSite {
4048 description "Prepares the website folder including unzipping files and copying resources"
4049 dependsOn jalviewjsSyncAllLibs
4050 dependsOn jalviewjsSyncResources
4051 dependsOn jalviewjsSyncSiteResources
4052 dependsOn jalviewjsSyncBuildProperties
4053 dependsOn jalviewjsSyncCore
4057 task jalviewjsBuildSite {
4059 description "Builds the whole website including transpiled code"
4060 dependsOn jalviewjsCopyTransferSiteJs
4061 dependsOn jalviewjsPrepareSite
4065 task cleanJalviewjsTransferSite {
4067 delete "${jalviewDir}/${jalviewjsTransferSiteJsDir}"
4068 delete "${jalviewDir}/${jalviewjsTransferSiteLibDir}"
4069 delete "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}"
4070 delete "${jalviewDir}/${jalviewjsTransferSiteCoreDir}"
4075 task cleanJalviewjsSite {
4076 dependsOn cleanJalviewjsTransferSite
4078 delete "${jalviewDir}/${jalviewjsSiteDir}"
4083 task jalviewjsSiteTar(type: Tar) {
4085 description "Creates a tar.gz file for the website"
4086 dependsOn jalviewjsBuildSite
4087 def outputFilename = "jalviewjs-site-${JALVIEW_VERSION}.tar.gz"
4088 archiveFileName = outputFilename
4090 compression Compression.GZIP
4092 from "${jalviewDir}/${jalviewjsSiteDir}"
4093 into jalviewjs_site_dir // this is inside the tar file
4095 inputs.dir("${jalviewDir}/${jalviewjsSiteDir}")
4099 task jalviewjsServer {
4101 def filename = "jalviewjsTest.html"
4102 description "Starts a webserver on localhost to test the website. See ${filename} to access local site on most recently used port."
4103 def htmlFile = "${jalviewDirAbsolutePath}/${filename}"
4108 def f = Class.forName("org.gradle.plugins.javascript.envjs.http.simple.SimpleHttpFileServerFactory")
4109 factory = f.newInstance()
4110 } catch (ClassNotFoundException e) {
4111 throw new GradleException("Unable to create SimpleHttpFileServerFactory")
4113 def port = Integer.valueOf(jalviewjs_server_port)
4118 while(port < start+1000 && !running) {
4120 def doc_root = new File("${jalviewDirAbsolutePath}/${jalviewjsSiteDir}")
4121 jalviewjsServer = factory.start(doc_root, port)
4123 url = jalviewjsServer.getResourceUrl(jalviewjs_server_resource)
4124 println("SERVER STARTED with document root ${doc_root}.")
4125 println("Go to "+url+" . Run gradle --stop to stop (kills all gradle daemons).")
4126 println("For debug: "+url+"?j2sdebug")
4127 println("For verbose: "+url+"?j2sverbose")
4128 } catch (Exception e) {
4133 <p><a href="${url}">JalviewJS Test. <${url}></a></p>
4134 <p><a href="${url}?j2sdebug">JalviewJS Test with debug. <${url}?j2sdebug></a></p>
4135 <p><a href="${url}?j2sverbose">JalviewJS Test with verbose. <${url}?j2sdebug></a></p>
4137 jalviewjsCoreClasslists.each { cl ->
4138 def urlcore = jalviewjsServer.getResourceUrl(file(cl.outputfile).getName())
4140 <p><a href="${urlcore}">${jalviewjsJalviewTemplateName} [core ${cl.name}]. <${urlcore}></a></p>
4142 println("For core ${cl.name}: "+urlcore)
4145 file(htmlFile).text = htmlText
4148 outputs.file(htmlFile)
4149 outputs.upToDateWhen({false})
4153 task cleanJalviewjsAll {
4155 description "Delete all configuration and build artifacts to do with JalviewJS build"
4156 dependsOn cleanJalviewjsSite
4157 dependsOn jalviewjsEclipsePaths
4160 delete "${jalviewDir}/${jalviewjsBuildDir}"
4161 delete "${jalviewDir}/${eclipse_bin_dir}"
4162 if (eclipseWorkspace != null && file(eclipseWorkspace.getAbsolutePath()+"/.metadata").exists()) {
4163 delete file(eclipseWorkspace.getAbsolutePath()+"/.metadata")
4165 delete jalviewjsJ2sAltSettingsFileName
4168 outputs.upToDateWhen( { false } )
4172 task jalviewjsIDE_checkJ2sPlugin {
4173 group "00 JalviewJS in Eclipse"
4174 description "Compare the swingjs/net.sf.j2s.core(-j11)?.jar file with the Eclipse IDE's plugin version (found in the 'dropins' dir)"
4177 def j2sPlugin = string("${jalviewDir}/${jalviewjsJ2sPlugin}")
4178 def j2sPluginFile = file(j2sPlugin)
4179 def eclipseHome = System.properties["eclipse.home.location"]
4180 if (eclipseHome == null || ! IN_ECLIPSE) {
4181 throw new StopExecutionException("Cannot find running Eclipse home from System.properties['eclipse.home.location']. Skipping J2S Plugin Check.")
4183 def eclipseJ2sPluginDirs = [ "${eclipseHome}/dropins" ]
4184 def altPluginsDir = System.properties["org.eclipse.equinox.p2.reconciler.dropins.directory"]
4185 if (altPluginsDir != null && file(altPluginsDir).exists()) {
4186 eclipseJ2sPluginDirs += altPluginsDir
4188 def foundPlugin = false
4189 def j2sPluginFileName = j2sPluginFile.getName()
4190 def eclipseJ2sPlugin
4191 def eclipseJ2sPluginFile
4192 eclipseJ2sPluginDirs.any { dir ->
4193 eclipseJ2sPlugin = "${dir}/${j2sPluginFileName}"
4194 eclipseJ2sPluginFile = file(eclipseJ2sPlugin)
4195 if (eclipseJ2sPluginFile.exists()) {
4201 def msg = "Eclipse J2S Plugin is not installed (could not find '${j2sPluginFileName}' in\n"+eclipseJ2sPluginDirs.join("\n")+"\n)\nTry running task jalviewjsIDE_copyJ2sPlugin"
4202 System.err.println(msg)
4203 throw new StopExecutionException(msg)
4206 def digest = MessageDigest.getInstance("MD5")
4208 digest.update(j2sPluginFile.text.bytes)
4209 def j2sPluginMd5 = new BigInteger(1, digest.digest()).toString(16).padLeft(32, '0')
4211 digest.update(eclipseJ2sPluginFile.text.bytes)
4212 def eclipseJ2sPluginMd5 = new BigInteger(1, digest.digest()).toString(16).padLeft(32, '0')
4214 if (j2sPluginMd5 != eclipseJ2sPluginMd5) {
4215 def msg = "WARNING! Eclipse J2S Plugin '${eclipseJ2sPlugin}' is different to this commit's version '${j2sPlugin}'"
4216 System.err.println(msg)
4217 throw new StopExecutionException(msg)
4219 def msg = "Eclipse J2S Plugin '${eclipseJ2sPlugin}' is the same as '${j2sPlugin}' (this is good)"
4225 task jalviewjsIDE_copyJ2sPlugin {
4226 group "00 JalviewJS in Eclipse"
4227 description "Copy the swingjs/net.sf.j2s.core(-j11)?.jar file into the Eclipse IDE's 'dropins' dir"
4230 def j2sPlugin = string("${jalviewDir}/${jalviewjsJ2sPlugin}")
4231 def j2sPluginFile = file(j2sPlugin)
4232 def eclipseHome = System.properties["eclipse.home.location"]
4233 if (eclipseHome == null || ! IN_ECLIPSE) {
4234 throw new StopExecutionException("Cannot find running Eclipse home from System.properties['eclipse.home.location']. NOT copying J2S Plugin.")
4236 def eclipseJ2sPlugin = "${eclipseHome}/dropins/${j2sPluginFile.getName()}"
4237 def eclipseJ2sPluginFile = file(eclipseJ2sPlugin)
4238 def msg = "WARNING! Copying this commit's j2s plugin '${j2sPlugin}' to Eclipse J2S Plugin '${eclipseJ2sPlugin}'\n* May require an Eclipse restart"
4239 System.err.println(msg)
4242 eclipseJ2sPluginFile.getParentFile().mkdirs()
4243 into eclipseJ2sPluginFile.getParent()
4249 task jalviewjsIDE_j2sFile {
4250 group "00 JalviewJS in Eclipse"
4251 description "Creates the .j2s file"
4252 dependsOn jalviewjsCreateJ2sSettings
4256 task jalviewjsIDE_SyncCore {
4257 group "00 JalviewJS in Eclipse"
4258 description "Build the core js lib closures listed in the classlists dir and publish core html from template"
4259 dependsOn jalviewjsSyncCore
4263 task jalviewjsIDE_SyncSiteAll {
4264 dependsOn jalviewjsSyncAllLibs
4265 dependsOn jalviewjsSyncResources
4266 dependsOn jalviewjsSyncSiteResources
4267 dependsOn jalviewjsSyncBuildProperties
4271 cleanJalviewjsTransferSite.mustRunAfter jalviewjsIDE_SyncSiteAll
4274 task jalviewjsIDE_PrepareSite {
4275 group "00 JalviewJS in Eclipse"
4276 description "Sync libs and resources to site dir, but not closure cores"
4278 dependsOn jalviewjsIDE_SyncSiteAll
4279 //dependsOn cleanJalviewjsTransferSite // not sure why this clean is here -- will slow down a re-run of this task
4283 task jalviewjsIDE_AssembleSite {
4284 group "00 JalviewJS in Eclipse"
4285 description "Assembles unzipped supporting zipfiles, resources, site resources and closure cores into the Eclipse transpiled site"
4286 dependsOn jalviewjsPrepareSite
4290 task jalviewjsIDE_SiteClean {
4291 group "00 JalviewJS in Eclipse"
4292 description "Deletes the Eclipse transpiled site"
4293 dependsOn cleanJalviewjsSite
4297 task jalviewjsIDE_Server {
4298 group "00 JalviewJS in Eclipse"
4299 description "Starts a webserver on localhost to test the website"
4300 dependsOn jalviewjsServer
4304 // buildship runs this at import or gradle refresh
4305 task eclipseSynchronizationTask {
4306 //dependsOn eclipseSetup
4307 dependsOn createBuildProperties
4309 dependsOn jalviewjsIDE_j2sFile
4310 dependsOn jalviewjsIDE_checkJ2sPlugin
4311 dependsOn jalviewjsIDE_PrepareSite
4316 // buildship runs this at build time or project refresh
4317 task eclipseAutoBuildTask {
4318 //dependsOn jalviewjsIDE_checkJ2sPlugin
4319 //dependsOn jalviewjsIDE_PrepareSite
4323 task jalviewjsCopyStderrLaunchFile(type: Copy) {
4324 from file(jalviewjs_stderr_launch)
4325 into jalviewjsSiteDir
4327 inputs.file jalviewjs_stderr_launch
4328 outputs.file jalviewjsStderrLaunchFilename
4331 task cleanJalviewjsChromiumUserDir {
4333 delete jalviewjsChromiumUserDir
4335 outputs.dir jalviewjsChromiumUserDir
4336 // always run when depended on
4337 outputs.upToDateWhen { !file(jalviewjsChromiumUserDir).exists() }
4340 task jalviewjsChromiumProfile {
4341 dependsOn cleanJalviewjsChromiumUserDir
4342 mustRunAfter cleanJalviewjsChromiumUserDir
4344 def firstRun = file("${jalviewjsChromiumUserDir}/First Run")
4347 mkdir jalviewjsChromiumProfileDir
4350 outputs.file firstRun
4353 task jalviewjsLaunchTest {
4355 description "Check JalviewJS opens in a browser"
4356 dependsOn jalviewjsBuildSite
4357 dependsOn jalviewjsCopyStderrLaunchFile
4358 dependsOn jalviewjsChromiumProfile
4360 def macOS = OperatingSystem.current().isMacOsX()
4361 def chromiumBinary = macOS ? jalviewjs_macos_chromium_binary : jalviewjs_chromium_binary
4362 if (chromiumBinary.startsWith("~/")) {
4363 chromiumBinary = System.getProperty("user.home") + chromiumBinary.substring(1)
4369 def timeoutms = Integer.valueOf(jalviewjs_chromium_overall_timeout) * 1000
4371 def binary = file(chromiumBinary)
4372 if (!binary.exists()) {
4373 throw new StopExecutionException("Could not find chromium binary '${chromiumBinary}'. Cannot run task ${name}.")
4375 stdout = new ByteArrayOutputStream()
4376 stderr = new ByteArrayOutputStream()
4379 if (jalviewjs_j2s_to_console.equals("true")) {
4380 execStdout = new org.apache.tools.ant.util.TeeOutputStream(
4383 execStderr = new org.apache.tools.ant.util.TeeOutputStream(
4391 "--no-sandbox", // --no-sandbox IS USED BY THE THORIUM APPIMAGE ON THE BUILDSERVER
4394 "--timeout=${timeoutms}",
4395 "--virtual-time-budget=${timeoutms}",
4396 "--user-data-dir=${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_chromium_user_dir}",
4397 "--profile-directory=${jalviewjs_chromium_profile_name}",
4398 "--allow-file-access-from-files",
4399 "--enable-logging=stderr",
4400 "file://${jalviewDirAbsolutePath}/${jalviewjsStderrLaunchFilename}"
4403 if (true || macOS) {
4404 ScheduledExecutorService executor = Executors.newScheduledThreadPool(3);
4405 Future f1 = executor.submit(
4408 standardOutput = execStdout
4409 errorOutput = execStderr
4410 executable(chromiumBinary)
4412 println "COMMAND: '"+commandLine.join(" ")+"'"
4414 executor.shutdownNow()
4418 def noChangeBytes = 0
4419 def noChangeIterations = 0
4420 executor.scheduleAtFixedRate(
4422 String stderrString = stderr.toString()
4423 // shutdown the task if we have a success string
4424 if (stderrString.contains(jalviewjs_desktop_init_string)) {
4427 executor.shutdownNow()
4429 // if no change in stderr for 10s then also end
4430 if (noChangeIterations >= jalviewjs_chromium_idle_timeout) {
4431 executor.shutdownNow()
4433 if (stderrString.length() == noChangeBytes) {
4434 noChangeIterations++
4436 noChangeBytes = stderrString.length()
4437 noChangeIterations = 0
4440 1, 1, TimeUnit.SECONDS)
4442 executor.schedule(new Runnable(){
4445 executor.shutdownNow()
4447 }, timeoutms, TimeUnit.MILLISECONDS)
4449 executor.awaitTermination(timeoutms+10000, TimeUnit.MILLISECONDS)
4450 executor.shutdownNow()
4457 stderr.toString().eachLine { line ->
4458 if (line.contains(jalviewjs_desktop_init_string)) {
4459 println("Found line '"+line+"'")
4465 throw new GradleException("Could not find evidence of Desktop launch in JalviewJS.")
4473 description "Build the JalviewJS site and run the launch test"
4474 dependsOn jalviewjsBuildSite
4475 dependsOn jalviewjsLaunchTest