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 install4jDMGFixedDSStoreX64 = "build/macos_dmg/${install4j_dmg_ds_store}-x64"
251 install4jDMGFixedDSStoreAarch64 = "build/macos_dmg/${install4j_dmg_ds_store}-aarch64"
252 install4jCheckSums = true
254 applicationName = "${jalview_name}"
258 // TODO: get bamboo build artifact URL for getdown artifacts
259 getdown_channel_base = bamboo_channelbase
260 getdownChannelName = string("${bamboo_planKey}/${JAVA_VERSION}")
261 getdownAppBase = string("${bamboo_channelbase}/${bamboo_planKey}${bamboo_getdown_channel_suffix}/${JAVA_VERSION}")
262 jvlChannelName += "_${getdownChannelName}"
263 // automatically add the test group Not-bamboo for exclusion
264 if ("".equals(testng_excluded_groups)) {
265 testng_excluded_groups = "Not-bamboo"
267 install4jExtraScheme = "jalviewb"
268 backgroundImageText = true
271 case [ "RELEASE", "JALVIEWJS-RELEASE" ]:
272 getdownAppDistDir = getdown_app_dir_release
273 getdownSetAppBaseProperty = true
274 reportRsyncCommand = true
276 install4jmacOSArchiveName = "Install ${jalview_name} ${JALVIEW_VERSION}"
277 install4jExtraScheme = (CHANNEL=="RELEASE")?"jalviewx":"jalviewjs"
281 getdownChannelName = CHANNEL.toLowerCase()+"/${JALVIEW_VERSION}"
282 getdownDir = string("${getdownChannelName}/${JAVA_VERSION}")
283 getdownAppBase = string("${getdown_channel_base}/${getdownDir}")
284 if (!file("${ARCHIVEDIR}/${package_dir}").exists()) {
285 throw new GradleException("Must provide an ARCHIVEDIR value to produce an archive distribution")
287 package_dir = string("${ARCHIVEDIR}/${package_dir}")
288 buildProperties = string("${ARCHIVEDIR}/${classes_dir}/${build_properties_file}")
291 reportRsyncCommand = true
292 install4jExtraScheme = "jalviewa"
296 getdownChannelName = string("archive/${JALVIEW_VERSION}")
297 getdownDir = string("${getdownChannelName}/${JAVA_VERSION}")
298 getdownAppBase = file(getdownAppBaseDir).toURI().toString()
299 if (!file("${ARCHIVEDIR}/${package_dir}").exists()) {
300 throw new GradleException("Must provide an ARCHIVEDIR value to produce an archive distribution [did not find '${ARCHIVEDIR}/${package_dir}']")
302 package_dir = string("${ARCHIVEDIR}/${package_dir}")
303 buildProperties = string("${ARCHIVEDIR}/${classes_dir}/${build_properties_file}")
306 reportRsyncCommand = true
307 getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher_local}")
308 install4jSuffix = "Archive"
309 install4jExtraScheme = "jalviewa"
312 case ~/^DEVELOP-([\.\-\w]*)$/:
313 def suffix = Matcher.lastMatcher[0][1]
314 reportRsyncCommand = true
315 getdownSetAppBaseProperty = true
316 JALVIEW_VERSION=JALVIEW_VERSION+"-d${suffix}-${buildDate}"
317 install4jSuffix = "Develop ${suffix}"
318 install4jExtraScheme = "jalviewd"
319 install4jmacOSArchiveName = "Install ${jalview_name} Develop ${suffix} ${JALVIEW_VERSION}"
320 getdownChannelName = string("develop-${suffix}")
321 getdownChannelDir = string("${getdown_website_dir}/${getdownChannelName}")
322 getdownAppBaseDir = string("${jalviewDir}/${getdownChannelDir}/${JAVA_VERSION}")
323 getdownDir = string("${getdownChannelName}/${JAVA_VERSION}")
324 getdownAppBase = string("${getdown_channel_base}/${getdownDir}")
325 channelSuffix = string(suffix)
326 backgroundImageText = true
330 reportRsyncCommand = true
331 getdownSetAppBaseProperty = true
332 // DEVELOP-RELEASE is usually associated with a Jalview release series so set the version
333 JALVIEW_VERSION=JALVIEW_VERSION+"-d${buildDate}"
335 install4jSuffix = "Develop"
336 install4jExtraScheme = "jalviewd"
337 install4jmacOSArchiveName = "Install ${jalview_name} Develop ${JALVIEW_VERSION}"
338 backgroundImageText = true
342 reportRsyncCommand = true
343 getdownSetAppBaseProperty = true
344 // Don't ignore transpile errors for release build
345 if (jalviewjs_ignore_transpile_errors.equals("true")) {
346 jalviewjs_ignore_transpile_errors = "false"
347 println("Setting jalviewjs_ignore_transpile_errors to 'false'")
349 JALVIEW_VERSION = JALVIEW_VERSION+"-test"
350 install4jSuffix = "Test"
351 install4jExtraScheme = "jalviewt"
352 install4jmacOSArchiveName = "Install ${jalview_name} Test ${JALVIEW_VERSION}"
353 backgroundImageText = true
356 case ~/^SCRATCH(|-[-\w]*)$/:
357 getdownChannelName = CHANNEL
358 JALVIEW_VERSION = JALVIEW_VERSION+"-"+CHANNEL
360 getdownDir = string("${getdownChannelName}/${JAVA_VERSION}")
361 getdownAppBase = string("${getdown_channel_base}/${getdownDir}")
362 reportRsyncCommand = true
363 install4jSuffix = "Scratch"
367 if (!file("${LOCALDIR}").exists()) {
368 throw new GradleException("Must provide a LOCALDIR value to produce a local distribution")
370 getdownAppBase = file(file("${LOCALDIR}").getAbsolutePath()).toURI().toString()
371 getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher_local}")
373 JALVIEW_VERSION = "TEST"
374 install4jSuffix = "Test-Local"
375 install4jExtraScheme = "jalviewt"
376 install4jmacOSArchiveName = "Install ${jalview_name} Test ${JALVIEW_VERSION}"
377 backgroundImageText = true
380 case [ "LOCAL", "JALVIEWJS" ]:
381 JALVIEW_VERSION = "TEST"
382 getdownAppBase = file(getdownAppBaseDir).toURI().toString()
383 getdownArchiveAppBase = file("${jalviewDir}/${getdown_archive_dir}").toURI().toString()
384 getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher_local}")
385 install4jExtraScheme = "jalviewl"
386 install4jCheckSums = false
389 default: // something wrong specified
390 throw new GradleException("CHANNEL must be one of BUILD, RELEASE, ARCHIVE, DEVELOP, TEST-RELEASE, SCRATCH-..., LOCAL [default]")
394 JALVIEW_VERSION_UNDERSCORES = JALVIEW_VERSION.replaceAll("\\.", "_")
395 hugoDataJsonFile = file("${jalviewDir}/${hugo_build_dir}/${hugo_data_installers_dir}/installers-${JALVIEW_VERSION_UNDERSCORES}.json")
396 hugoArchiveMdFile = file("${jalviewDir}/${hugo_build_dir}/${hugo_version_archive_dir}/Version-${JALVIEW_VERSION_UNDERSCORES}/_index.md")
397 // override getdownAppBase if requested
398 if (findProperty("getdown_appbase_override") != null) {
399 // revert to LOCAL if empty string
400 if (string(getdown_appbase_override) == "") {
401 getdownAppBase = file(getdownAppBaseDir).toURI().toString()
402 getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher_local}")
403 } else if (string(getdown_appbase_override).startsWith("file://")) {
404 getdownAppBase = string(getdown_appbase_override)
405 getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher_local}")
407 getdownAppBase = string(getdown_appbase_override)
409 println("Overriding getdown appbase with '${getdownAppBase}'")
411 // sanitise file name for jalview launcher file for this channel
412 jvlChannelName = jvlChannelName.replaceAll("[^\\w\\-]+", "_")
413 // install4j application and folder names
414 if (install4jSuffix == "") {
415 install4jBundleId = "${install4j_bundle_id}"
416 install4jWinApplicationId = install4j_release_win_application_id
418 applicationName = "${jalview_name} ${install4jSuffix}"
419 install4jBundleId = "${install4j_bundle_id}-" + install4jSuffix.toLowerCase()
420 // add int hash of install4jSuffix to the last part of the application_id
421 def id = install4j_release_win_application_id
422 def idsplitreverse = id.split("-").reverse()
423 idsplitreverse[0] = idsplitreverse[0].toInteger() + install4jSuffix.hashCode()
424 install4jWinApplicationId = idsplitreverse.reverse().join("-")
426 // sanitise folder and id names
427 // install4jApplicationFolder = e.g. "Jalview Build"
428 install4jApplicationFolder = applicationName
429 .replaceAll("[\"'~:/\\\\\\s]", "_") // replace all awkward filename chars " ' ~ : / \
430 .replaceAll("_+", "_") // collapse __
431 install4jInternalId = applicationName
433 .replaceAll("[^\\w\\-\\.]", "_") // replace other non [alphanumeric,_,-,.]
434 .replaceAll("_+", "") // collapse __
435 //.replaceAll("_*-_*", "-") // collapse _-_
436 install4jUnixApplicationFolder = applicationName
438 .replaceAll("[^\\w\\-\\.]", "_") // replace other non [alphanumeric,_,-,.]
439 .replaceAll("_+", "_") // collapse __
440 .replaceAll("_*-_*", "-") // collapse _-_
442 install4jmacOSArchiveX64Name = "${install4jmacOSArchiveName} (Intel)"
443 install4jmacOSArchiveAarch64Name = "${install4jmacOSArchiveName} (Apple Silicon)"
445 getdownWrapperLink = install4jUnixApplicationFolder // e.g. "jalview_local"
446 getdownAppDir = string("${getdownAppBaseDir}/${getdownAppDistDir}")
447 //getdownJ11libDir = "${getdownAppBaseDir}/${getdown_j11lib_dir}"
448 getdownResourceDir = string("${getdownAppBaseDir}/${getdown_resource_dir}")
449 getdownInstallDir = string("${getdownAppBaseDir}/${getdown_install_dir}")
450 getdownFilesDir = string("${jalviewDir}/${getdown_files_dir}/${JAVA_VERSION}/")
451 getdownFilesInstallDir = string("${getdownFilesDir}/${getdown_install_dir}")
452 /* compile without modules -- using classpath libraries
453 modules_compileClasspath = fileTree(dir: "${jalviewDir}/${j11modDir}", include: ["*.jar"])
454 modules_runtimeClasspath = modules_compileClasspath
460 apply plugin: "com.palantir.git-version"
461 def details = versionDetails()
462 gitHash = details.gitHash
463 gitBranch = details.branchName
464 } catch(org.gradle.api.internal.plugins.PluginApplicationException e) {
465 println("Not in a git repository. Using git values from RELEASE properties file.")
466 gitHash = releaseProps.getProperty("git.hash")
467 gitBranch = releaseProps.getProperty("git.branch")
468 } catch(java.lang.RuntimeException e1) {
469 throw new GradleException("Error with git-version plugin. Directory '.git' exists but versionDetails() cannot be found.")
472 println("Using a ${CHANNEL} profile.")
474 additional_compiler_args = []
475 // configure classpath/args for j8/j11 compilation
476 if (JAVA_VERSION.equals("1.8")) {
477 JAVA_INTEGER_VERSION = string("8")
480 libDistDir = j8libDir
481 compile_source_compatibility = 1.8
482 compile_target_compatibility = 1.8
483 // these are getdown.txt properties defined dependent on the JAVA_VERSION
484 getdownAltJavaMinVersion = string(findProperty("getdown_alt_java8_min_version"))
485 getdownAltJavaMaxVersion = string(findProperty("getdown_alt_java8_max_version"))
486 // this property is assigned below and expanded to multiple lines in the getdown task
487 getdownAltMultiJavaLocation = string(findProperty("getdown_alt_java8_txt_multi_java_location"))
488 // this property is for the Java library used in eclipse
489 eclipseJavaRuntimeName = string("JavaSE-1.8")
490 } else if (JAVA_VERSION.equals("11")) {
491 JAVA_INTEGER_VERSION = string("11")
493 libDistDir = j11libDir
494 compile_source_compatibility = 11
495 compile_target_compatibility = 11
496 getdownAltJavaMinVersion = string(findProperty("getdown_alt_java11_min_version"))
497 getdownAltJavaMaxVersion = string(findProperty("getdown_alt_java11_max_version"))
498 getdownAltMultiJavaLocation = string(findProperty("getdown_alt_java11_txt_multi_java_location"))
499 eclipseJavaRuntimeName = string("JavaSE-11")
500 /* compile without modules -- using classpath libraries
501 additional_compiler_args += [
502 '--module-path', modules_compileClasspath.asPath,
503 '--add-modules', j11modules
506 } else if (JAVA_VERSION.equals("17")) {
507 JAVA_INTEGER_VERSION = string("17")
509 libDistDir = j17libDir
510 compile_source_compatibility = 17
511 compile_target_compatibility = 17
512 getdownAltJavaMinVersion = string(findProperty("getdown_alt_java11_min_version"))
513 getdownAltJavaMaxVersion = string(findProperty("getdown_alt_java11_max_version"))
514 getdownAltMultiJavaLocation = string(findProperty("getdown_alt_java11_txt_multi_java_location"))
515 eclipseJavaRuntimeName = string("JavaSE-17")
516 /* compile without modules -- using classpath libraries
517 additional_compiler_args += [
518 '--module-path', modules_compileClasspath.asPath,
519 '--add-modules', j11modules
523 throw new GradleException("JAVA_VERSION=${JAVA_VERSION} not currently supported by Jalview")
528 JAVA_MIN_VERSION = JAVA_VERSION
529 JAVA_MAX_VERSION = JAVA_VERSION
530 jreInstallsDir = string(jre_installs_dir)
531 if (jreInstallsDir.startsWith("~/")) {
532 jreInstallsDir = System.getProperty("user.home") + jreInstallsDir.substring(1)
534 install4jDir = string("${jalviewDir}/${install4j_utils_dir}")
535 install4jConfFileName = string("jalview-install4j-conf.install4j")
536 install4jConfFile = file("${install4jDir}/${install4jConfFileName}")
537 install4jHomeDir = install4j_home_dir
538 if (install4jHomeDir.startsWith("~/")) {
539 install4jHomeDir = System.getProperty("user.home") + install4jHomeDir.substring(1)
541 install4jmacOSArchiveX64DMGFilename = "${install4jApplicationFolder}-${JALVIEW_VERSION}-macos-x64-java_${JAVA_INTEGER_VERSION}"
542 install4jmacOSArchiveAarch64DMGFilename = "${install4jApplicationFolder}-${JALVIEW_VERSION}-macos-aarch64-java_${JAVA_INTEGER_VERSION}"
545 resourceBuildDir = string("${buildDir}/resources")
546 resourcesBuildDir = string("${resourceBuildDir}/resources_build")
547 helpBuildDir = string("${resourceBuildDir}/help_build")
548 docBuildDir = string("${resourceBuildDir}/doc_build")
550 if (buildProperties == null) {
551 buildProperties = string("${resourcesBuildDir}/${build_properties_file}")
553 buildingHTML = string("${jalviewDir}/${doc_dir}/building.html")
554 helpParentDir = string("${jalviewDir}/${help_parent_dir}")
555 helpSourceDir = string("${helpParentDir}/${help_dir}")
556 helpFile = string("${helpBuildDir}/${help_dir}/help.jhm")
559 convertBinaryExpectedLocation = imagemagick_convert
560 if (convertBinaryExpectedLocation.startsWith("~/")) {
561 convertBinaryExpectedLocation = System.getProperty("user.home") + convertBinaryExpectedLocation.substring(1)
563 if (file(convertBinaryExpectedLocation).exists()) {
564 convertBinary = convertBinaryExpectedLocation
567 relativeBuildDir = file(jalviewDirAbsolutePath).toPath().relativize(buildDir.toPath())
568 jalviewjsBuildDir = string("${relativeBuildDir}/jalviewjs")
569 jalviewjsSiteDir = string("${jalviewjsBuildDir}/${jalviewjs_site_dir}")
571 jalviewjsTransferSiteJsDir = string(jalviewjsSiteDir)
573 jalviewjsTransferSiteJsDir = string("${jalviewjsBuildDir}/tmp/${jalviewjs_site_dir}_js")
575 jalviewjsTransferSiteLibDir = string("${jalviewjsBuildDir}/tmp/${jalviewjs_site_dir}_lib")
576 jalviewjsTransferSiteSwingJsDir = string("${jalviewjsBuildDir}/tmp/${jalviewjs_site_dir}_swingjs")
577 jalviewjsTransferSiteCoreDir = string("${jalviewjsBuildDir}/tmp/${jalviewjs_site_dir}_core")
578 jalviewjsJalviewCoreHtmlFile = string("")
579 jalviewjsJalviewCoreName = string(jalviewjs_core_name)
580 jalviewjsCoreClasslists = []
581 jalviewjsJalviewTemplateName = string(jalviewjs_name)
582 jalviewjsJ2sSettingsFileName = string("${jalviewDir}/${jalviewjs_j2s_settings}")
583 jalviewjsJ2sAltSettingsFileName = string("${jalviewDir}/${jalviewjs_j2s_alt_settings}")
584 jalviewjsJ2sProps = null
585 jalviewjsJ2sPlugin = jalviewjs_j2s_plugin
586 jalviewjsStderrLaunchFilename = "${jalviewjsSiteDir}/"+(file(jalviewjs_stderr_launch).getName())
588 eclipseWorkspace = null
589 eclipseBinary = string("")
590 eclipseVersion = string("")
593 jalviewjsChromiumUserDir = "${jalviewjsBuildDir}/${jalviewjs_chromium_user_dir}"
594 jalviewjsChromiumProfileDir = "${ext.jalviewjsChromiumUserDir}/${jalviewjs_chromium_profile_name}"
604 outputDir = file(classesDir)
608 srcDirs = [ resourcesBuildDir, docBuildDir, helpBuildDir ]
611 compileClasspath = files(sourceSets.main.java.outputDir)
612 compileClasspath += fileTree(dir: "${jalviewDir}/${libDir}", include: ["*.jar"])
614 runtimeClasspath = compileClasspath
615 runtimeClasspath += files(sourceSets.main.resources.srcDirs)
620 srcDirs cloverInstrDir
621 outputDir = cloverClassesDir
625 srcDirs = sourceSets.main.resources.srcDirs
628 compileClasspath = files( sourceSets.clover.java.outputDir )
629 //compileClasspath += files( testClassesDir )
630 compileClasspath += fileTree(dir: "${jalviewDir}/${libDir}", include: ["*.jar"])
631 compileClasspath += fileTree(dir: "${jalviewDir}/${clover_lib_dir}", include: ["*.jar"])
632 compileClasspath += fileTree(dir: "${jalviewDir}/${utils_dir}/testnglibs", include: ["**/*.jar"])
634 runtimeClasspath = compileClasspath
639 srcDirs testSourceDir
640 outputDir = file(testClassesDir)
644 srcDirs = useClover ? sourceSets.clover.resources.srcDirs : sourceSets.main.resources.srcDirs
647 compileClasspath = files( sourceSets.test.java.outputDir )
648 compileClasspath += useClover ? sourceSets.clover.compileClasspath : sourceSets.main.compileClasspath
649 compileClasspath += fileTree(dir: "${jalviewDir}/${utils_dir}/testnglibs", include: ["**/*.jar"])
651 runtimeClasspath = compileClasspath
652 runtimeClasspath += files(sourceSets.test.resources.srcDirs)
658 // eclipse project and settings files creation, also used by buildship
661 name = eclipse_project_name
663 natures 'org.eclipse.jdt.core.javanature',
664 'org.eclipse.jdt.groovy.core.groovyNature',
665 'org.eclipse.buildship.core.gradleprojectnature'
667 buildCommand 'org.eclipse.jdt.core.javabuilder'
668 buildCommand 'org.eclipse.buildship.core.gradleprojectbuilder'
672 //defaultOutputDir = sourceSets.main.java.outputDir
673 configurations.each{ c->
674 if (c.isCanBeResolved()) {
675 minusConfigurations += [c]
679 plusConfigurations = [ ]
683 def removeTheseToo = []
684 HashMap<String, Boolean> alreadyAddedSrcPath = new HashMap<>();
685 cp.entries.each { entry ->
686 // This conditional removes all src classpathentries that a) have already been added or b) aren't "src" or "test".
687 // e.g. this removes the resources dir being copied into bin/main, bin/test AND bin/clover
688 // we add the resources and help/help dirs in as libs afterwards (see below)
689 if (entry.kind == 'src') {
690 if (alreadyAddedSrcPath.getAt(entry.path) || !(entry.path == bareSourceDir || entry.path == bareTestSourceDir)) {
691 removeTheseToo += entry
693 alreadyAddedSrcPath.putAt(entry.path, true)
698 cp.entries.removeAll(removeTheseToo)
700 //cp.entries += new Output("${eclipse_bin_dir}/main")
701 if (file(helpParentDir).isDirectory()) {
702 cp.entries += new Library(fileReference(helpParentDir))
704 if (file(resourceDir).isDirectory()) {
705 cp.entries += new Library(fileReference(resourceDir))
708 HashMap<String, Boolean> alreadyAddedLibPath = new HashMap<>();
710 sourceSets.main.compileClasspath.findAll { it.name.endsWith(".jar") }.any {
711 //don't want to add outputDir as eclipse is using its own output dir in bin/main
712 if (it.isDirectory() || ! it.exists()) {
713 // don't add dirs to classpath, especially if they don't exist
714 return false // groovy "continue" in .any closure
716 def itPath = it.toString()
717 if (itPath.startsWith("${jalviewDirAbsolutePath}/")) {
718 // make relative path
719 itPath = itPath.substring(jalviewDirAbsolutePath.length()+1)
721 if (alreadyAddedLibPath.get(itPath)) {
722 //println("Not adding duplicate entry "+itPath)
724 //println("Adding entry "+itPath)
725 cp.entries += new Library(fileReference(itPath))
726 alreadyAddedLibPath.put(itPath, true)
730 sourceSets.test.compileClasspath.findAll { it.name.endsWith(".jar") }.any {
731 //no longer want to add outputDir as eclipse is using its own output dir in bin/main
732 if (it.isDirectory() || ! it.exists()) {
733 // don't add dirs to classpath
734 return false // groovy "continue" in .any closure
737 def itPath = it.toString()
738 if (itPath.startsWith("${jalviewDirAbsolutePath}/")) {
739 itPath = itPath.substring(jalviewDirAbsolutePath.length()+1)
741 if (alreadyAddedLibPath.get(itPath)) {
744 def lib = new Library(fileReference(itPath))
745 lib.entryAttributes["test"] = "true"
747 alreadyAddedLibPath.put(itPath, true)
755 containers 'org.eclipse.buildship.core.gradleclasspathcontainer'
760 // for the IDE, use java 11 compatibility
761 sourceCompatibility = compile_source_compatibility
762 targetCompatibility = compile_target_compatibility
763 javaRuntimeName = eclipseJavaRuntimeName
765 // add in jalview project specific properties/preferences into eclipse core preferences
767 withProperties { props ->
768 def jalview_prefs = new Properties()
769 def ins = new FileInputStream("${jalviewDirAbsolutePath}/${eclipse_extra_jdt_prefs_file}")
770 jalview_prefs.load(ins)
772 jalview_prefs.forEach { t, v ->
773 if (props.getAt(t) == null) {
777 // codestyle file -- overrides previous formatter prefs
778 def csFile = file("${jalviewDirAbsolutePath}/${eclipse_codestyle_file}")
779 if (csFile.exists()) {
780 XmlParser parser = new XmlParser()
781 def profiles = parser.parse(csFile)
782 def profile = profiles.'profile'.find { p -> (p.'@kind' == "CodeFormatterProfile" && p.'@name' == "Jalview") }
783 if (profile != null) {
784 profile.'setting'.each { s ->
786 def value = s.'@value'
787 if (id != null && value != null) {
788 props.putAt(id, value)
799 // Don't want these to be activated if in headless build
800 synchronizationTasks "eclipseSynchronizationTask"
801 //autoBuildTasks "eclipseAutoBuildTask"
807 /* hack to change eclipse prefs in .settings files other than org.eclipse.jdt.core.prefs */
808 // Class to allow updating arbitrary properties files
809 class PropertiesFile extends PropertiesPersistableConfigurationObject {
810 public PropertiesFile(PropertiesTransformer t) { super(t); }
811 @Override protected void load(Properties properties) { }
812 @Override protected void store(Properties properties) { }
813 @Override protected String getDefaultResourceName() { return ""; }
814 // This is necessary, because PropertiesPersistableConfigurationObject fails
815 // if no default properties file exists.
816 @Override public void loadDefaults() { load(new StringBufferInputStream("")); }
819 // Task to update arbitrary properties files (set outputFile)
820 class PropertiesFileTask extends PropertiesGeneratorTask<PropertiesFile> {
821 private final PropertiesFileContentMerger file;
822 public PropertiesFileTask() { file = new PropertiesFileContentMerger(getTransformer()); }
823 protected PropertiesFile create() { return new PropertiesFile(getTransformer()); }
824 protected void configure(PropertiesFile props) {
825 file.getBeforeMerged().execute(props); file.getWhenMerged().execute(props);
827 public void file(Closure closure) { ConfigureUtil.configure(closure, file); }
830 task eclipseUIPreferences(type: PropertiesFileTask) {
831 description = "Generate Eclipse additional settings"
832 def filename = "org.eclipse.jdt.ui.prefs"
833 outputFile = "$projectDir/.settings/${filename}" as File
836 it.load new FileInputStream("$projectDir/utils/eclipse/${filename}" as String)
841 task eclipseGroovyCorePreferences(type: PropertiesFileTask) {
842 description = "Generate Eclipse additional settings"
843 def filename = "org.eclipse.jdt.groovy.core.prefs"
844 outputFile = "$projectDir/.settings/${filename}" as File
847 it.load new FileInputStream("$projectDir/utils/eclipse/${filename}" as String)
852 task eclipseAllPreferences {
854 dependsOn eclipseUIPreferences
855 dependsOn eclipseGroovyCorePreferences
858 eclipseUIPreferences.mustRunAfter eclipseJdt
859 eclipseGroovyCorePreferences.mustRunAfter eclipseJdt
861 /* end of eclipse preferences hack */
869 delete cloverBuildDir
870 delete cloverReportDir
875 task cloverInstrJava(type: JavaExec) {
876 group = "Verification"
877 description = "Create clover instrumented source java files"
879 dependsOn cleanClover
881 inputs.files(sourceSets.main.allJava)
882 outputs.dir(cloverInstrDir)
884 //classpath = fileTree(dir: "${jalviewDir}/${clover_lib_dir}", include: ["*.jar"])
885 classpath = sourceSets.clover.compileClasspath
886 main = "com.atlassian.clover.CloverInstr"
894 cloverInstrDir.getPath(),
896 def srcFiles = sourceSets.main.allJava.files
899 { file -> file.absolutePath }
902 args argsList.toArray()
905 delete cloverInstrDir
906 println("Clover: About to instrument "+srcFiles.size() +" files")
911 task cloverInstrTests(type: JavaExec) {
912 group = "Verification"
913 description = "Create clover instrumented source test files"
915 dependsOn cleanClover
917 inputs.files(testDir)
918 outputs.dir(cloverTestInstrDir)
920 classpath = sourceSets.clover.compileClasspath
921 main = "com.atlassian.clover.CloverInstr"
931 cloverTestInstrDir.getPath(),
933 args argsList.toArray()
936 delete cloverTestInstrDir
937 println("Clover: About to instrument test files")
943 group = "Verification"
944 description = "Create clover instrumented all source files"
946 dependsOn cloverInstrJava
947 dependsOn cloverInstrTests
951 cloverClasses.dependsOn cloverInstr
954 task cloverConsoleReport(type: JavaExec) {
955 group = "Verification"
956 description = "Creates clover console report"
959 file(cloverDb).exists()
962 inputs.dir cloverClassesDir
964 classpath = sourceSets.clover.runtimeClasspath
965 main = "com.atlassian.clover.reporters.console.ConsoleReporter"
967 if (cloverreport_mem.length() > 0) {
968 maxHeapSize = cloverreport_mem
970 if (cloverreport_jvmargs.length() > 0) {
971 jvmArgs Arrays.asList(cloverreport_jvmargs.split(" "))
981 args argsList.toArray()
985 task cloverHtmlReport(type: JavaExec) {
986 group = "Verification"
987 description = "Creates clover HTML report"
990 file(cloverDb).exists()
993 def cloverHtmlDir = cloverReportDir
994 inputs.dir cloverClassesDir
995 outputs.dir cloverHtmlDir
997 classpath = sourceSets.clover.runtimeClasspath
998 main = "com.atlassian.clover.reporters.html.HtmlReporter"
1000 if (cloverreport_mem.length() > 0) {
1001 maxHeapSize = cloverreport_mem
1003 if (cloverreport_jvmargs.length() > 0) {
1004 jvmArgs Arrays.asList(cloverreport_jvmargs.split(" "))
1015 if (cloverreport_html_options.length() > 0) {
1016 argsList += cloverreport_html_options.split(" ")
1019 args argsList.toArray()
1023 task cloverXmlReport(type: JavaExec) {
1024 group = "Verification"
1025 description = "Creates clover XML report"
1028 file(cloverDb).exists()
1031 def cloverXmlFile = "${cloverReportDir}/clover.xml"
1032 inputs.dir cloverClassesDir
1033 outputs.file cloverXmlFile
1035 classpath = sourceSets.clover.runtimeClasspath
1036 main = "com.atlassian.clover.reporters.xml.XMLReporter"
1038 if (cloverreport_mem.length() > 0) {
1039 maxHeapSize = cloverreport_mem
1041 if (cloverreport_jvmargs.length() > 0) {
1042 jvmArgs Arrays.asList(cloverreport_jvmargs.split(" "))
1053 if (cloverreport_xml_options.length() > 0) {
1054 argsList += cloverreport_xml_options.split(" ")
1057 args argsList.toArray()
1062 group = "Verification"
1063 description = "Creates clover reports"
1065 dependsOn cloverXmlReport
1066 dependsOn cloverHtmlReport
1073 sourceCompatibility = compile_source_compatibility
1074 targetCompatibility = compile_target_compatibility
1075 options.compilerArgs += additional_compiler_args
1076 print ("Setting target compatibility to "+targetCompatibility+"\n")
1078 //classpath += configurations.cloverRuntime
1084 // JBP->BS should the print statement in doFirst refer to compile_target_compatibility ?
1085 sourceCompatibility = compile_source_compatibility
1086 targetCompatibility = compile_target_compatibility
1087 options.compilerArgs += additional_compiler_args
1088 options.encoding = "UTF-8"
1090 print ("Setting target compatibility to "+compile_target_compatibility+"\n")
1097 sourceCompatibility = compile_source_compatibility
1098 targetCompatibility = compile_target_compatibility
1099 options.compilerArgs += additional_compiler_args
1101 print ("Setting target compatibility to "+targetCompatibility+"\n")
1108 delete sourceSets.main.java.outputDir
1114 dependsOn cleanClover
1116 delete sourceSets.test.java.outputDir
1121 // format is a string like date.format("dd MMMM yyyy")
1122 def getDate(format) {
1123 return date.format(format)
1127 def convertMdToHtml (FileTree mdFiles, File cssFile) {
1128 MutableDataSet options = new MutableDataSet()
1130 def extensions = new ArrayList<>()
1131 extensions.add(AnchorLinkExtension.create())
1132 extensions.add(AutolinkExtension.create())
1133 extensions.add(StrikethroughExtension.create())
1134 extensions.add(TaskListExtension.create())
1135 extensions.add(TablesExtension.create())
1136 extensions.add(TocExtension.create())
1138 options.set(Parser.EXTENSIONS, extensions)
1140 // set GFM table parsing options
1141 options.set(TablesExtension.WITH_CAPTION, false)
1142 options.set(TablesExtension.COLUMN_SPANS, false)
1143 options.set(TablesExtension.MIN_HEADER_ROWS, 1)
1144 options.set(TablesExtension.MAX_HEADER_ROWS, 1)
1145 options.set(TablesExtension.APPEND_MISSING_COLUMNS, true)
1146 options.set(TablesExtension.DISCARD_EXTRA_COLUMNS, true)
1147 options.set(TablesExtension.HEADER_SEPARATOR_COLUMN_MATCH, true)
1149 options.set(AnchorLinkExtension.ANCHORLINKS_SET_ID, false)
1150 options.set(AnchorLinkExtension.ANCHORLINKS_ANCHOR_CLASS, "anchor")
1151 options.set(AnchorLinkExtension.ANCHORLINKS_SET_NAME, true)
1152 options.set(AnchorLinkExtension.ANCHORLINKS_TEXT_PREFIX, "<span class=\"octicon octicon-link\"></span>")
1154 Parser parser = Parser.builder(options).build()
1155 HtmlRenderer renderer = HtmlRenderer.builder(options).build()
1157 mdFiles.each { mdFile ->
1158 // add table of contents
1159 def mdText = "[TOC]\n"+mdFile.text
1161 // grab the first top-level title
1163 def titleRegex = /(?m)^#(\s+|([^#]))(.*)/
1164 def matcher = mdText =~ titleRegex
1165 if (matcher.size() > 0) {
1166 // matcher[0][2] is the first character of the title if there wasn't any whitespace after the #
1167 title = (matcher[0][2] != null ? matcher[0][2] : "")+matcher[0][3]
1169 // or use the filename if none found
1170 if (title == null) {
1171 title = mdFile.getName()
1174 Node document = parser.parse(mdText)
1175 String htmlBody = renderer.render(document)
1176 def htmlText = '''<html>
1177 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
1178 <html xmlns="http://www.w3.org/1999/xhtml">
1180 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
1181 <meta http-equiv="Content-Style-Type" content="text/css" />
1182 <meta name="generator" content="flexmark" />
1184 htmlText += ((title != null) ? " <title>${title}</title>" : '' )
1186 <style type="text/css">code{white-space: pre;}</style>
1188 htmlText += ((cssFile != null) ? cssFile.text : '')
1189 htmlText += '''</head>
1192 htmlText += htmlBody
1198 def htmlFilePath = mdFile.getPath().replaceAll(/\..*?$/, ".html")
1199 def htmlFile = file(htmlFilePath)
1200 println("Creating ${htmlFilePath}")
1201 htmlFile.text = htmlText
1206 task copyDocs(type: Copy) {
1207 def inputDir = "${jalviewDir}/${doc_dir}"
1208 def outputDir = "${docBuildDir}/${doc_dir}"
1212 include('**/*.html')
1214 filter(ReplaceTokens,
1218 'Version-Rel': JALVIEW_VERSION,
1219 'Year-Rel': getDate("yyyy")
1226 exclude('**/*.html')
1231 inputs.dir(inputDir)
1232 outputs.dir(outputDir)
1236 task convertMdFiles {
1238 def mdFiles = fileTree(dir: docBuildDir, include: "**/*.md")
1239 def cssFile = file("${jalviewDir}/${flexmark_css}")
1242 convertMdToHtml(mdFiles, cssFile)
1245 inputs.files(mdFiles)
1246 inputs.file(cssFile)
1249 mdFiles.each { mdFile ->
1250 def htmlFilePath = mdFile.getPath().replaceAll(/\..*?$/, ".html")
1251 htmlFiles.add(file(htmlFilePath))
1253 outputs.files(htmlFiles)
1257 def hugoTemplateSubstitutions(String input, Map extras=null) {
1258 def replacements = [
1259 DATE: getDate("yyyy-MM-dd"),
1260 CHANNEL: propertiesChannelName,
1261 APPLICATION_NAME: applicationName,
1263 GIT_BRANCH: gitBranch,
1264 VERSION: JALVIEW_VERSION,
1265 JAVA_VERSION: JAVA_VERSION,
1266 VERSION_UNDERSCORES: JALVIEW_VERSION_UNDERSCORES,
1271 if (extras != null) {
1272 extras.each{ k, v ->
1273 output = output.replaceAll("__${k}__", ((v == null)?"":v))
1276 replacements.each{ k, v ->
1277 output = output.replaceAll("__${k}__", ((v == null)?"":v))
1282 def mdFileComponents(File mdFile, def dateOnly=false) {
1285 if (mdFile.exists()) {
1286 def inFrontMatter = false
1287 def firstLine = true
1288 mdFile.eachLine { line ->
1289 if (line.matches("---")) {
1290 def prev = inFrontMatter
1291 inFrontMatter = firstLine
1292 if (inFrontMatter != prev)
1295 if (inFrontMatter) {
1297 if (m = line =~ /^date:\s*(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})/) {
1298 map["date"] = new Date().parse("yyyy-MM-dd HH:mm:ss", m[0][1])
1299 } else if (m = line =~ /^date:\s*(\d{4}-\d{2}-\d{2})/) {
1300 map["date"] = new Date().parse("yyyy-MM-dd", m[0][1])
1301 } else if (m = line =~ /^channel:\s*(\S+)/) {
1302 map["channel"] = m[0][1]
1303 } else if (m = line =~ /^version:\s*(\S+)/) {
1304 map["version"] = m[0][1]
1305 } else if (m = line =~ /^\s*([^:]+)\s*:\s*(\S.*)/) {
1306 map[ m[0][1] ] = m[0][2]
1308 if (dateOnly && map["date"] != null) {
1314 content += line+"\n"
1319 return dateOnly ? map["date"] : [map, content]
1322 task hugoTemplates {
1324 description "Create partially populated md pages for hugo website build"
1326 def hugoTemplatesDir = file("${jalviewDir}/${hugo_templates_dir}")
1327 def hugoBuildDir = "${jalviewDir}/${hugo_build_dir}"
1328 def templateFiles = fileTree(dir: hugoTemplatesDir)
1329 def releaseMdFile = file("${jalviewDir}/${releases_dir}/release-${JALVIEW_VERSION_UNDERSCORES}.md")
1330 def whatsnewMdFile = file("${jalviewDir}/${whatsnew_dir}/whatsnew-${JALVIEW_VERSION_UNDERSCORES}.md")
1331 def oldJvlFile = file("${jalviewDir}/${hugo_old_jvl}")
1332 def jalviewjsFile = file("${jalviewDir}/${hugo_jalviewjs}")
1335 // specific release template for version archive
1338 def givenDate = null
1339 def givenChannel = null
1340 def givenVersion = null
1341 if (CHANNEL == "RELEASE") {
1342 def (map, content) = mdFileComponents(releaseMdFile)
1343 givenDate = map.date
1344 givenChannel = map.channel
1345 givenVersion = map.version
1347 if (givenVersion != null && givenVersion != JALVIEW_VERSION) {
1348 throw new GradleException("'version' header (${givenVersion}) found in ${releaseMdFile} does not match JALVIEW_VERSION (${JALVIEW_VERSION})")
1351 if (whatsnewMdFile.exists())
1352 whatsnew = whatsnewMdFile.text
1355 def oldJvl = oldJvlFile.exists() ? oldJvlFile.collect{it} : []
1356 def jalviewjsLink = jalviewjsFile.exists() ? jalviewjsFile.collect{it} : []
1358 def changesHugo = null
1359 if (changes != null) {
1360 changesHugo = '<div class="release_notes">\n\n'
1361 def inSection = false
1362 changes.eachLine { line ->
1364 if (m = line =~ /^##([^#].*)$/) {
1366 changesHugo += "</div>\n\n"
1368 def section = m[0][1].trim()
1369 section = section.toLowerCase()
1370 section = section.replaceAll(/ +/, "_")
1371 section = section.replaceAll(/[^a-z0-9_\-]/, "")
1372 changesHugo += "<div class=\"${section}\">\n\n"
1374 } else if (m = line =~ /^(\s*-\s*)<!--([^>]+)-->(.*?)(<br\/?>)?\s*$/) {
1375 def comment = m[0][2].trim()
1376 if (comment != "") {
1377 comment = comment.replaceAll('"', """)
1379 comment.eachMatch(/JAL-\d+/) { jal -> issuekeys += jal }
1380 def newline = m[0][1]
1381 if (comment.trim() != "")
1382 newline += "{{<comment>}}${comment}{{</comment>}} "
1383 newline += m[0][3].trim()
1384 if (issuekeys.size() > 0)
1385 newline += " {{< jal issue=\"${issuekeys.join(",")}\" alt=\"${comment}\" >}}"
1386 if (m[0][4] != null)
1391 changesHugo += line+"\n"
1394 changesHugo += "\n</div>\n\n"
1396 changesHugo += '</div>'
1399 templateFiles.each{ templateFile ->
1400 def newFileName = string(hugoTemplateSubstitutions(templateFile.getName()))
1401 def relPath = hugoTemplatesDir.toPath().relativize(templateFile.toPath()).getParent()
1402 def newRelPathName = hugoTemplateSubstitutions( relPath.toString() )
1404 def outPathName = string("${hugoBuildDir}/$newRelPathName")
1408 rename(templateFile.getName(), newFileName)
1412 def newFile = file("${outPathName}/${newFileName}".toString())
1413 def content = newFile.text
1414 newFile.text = hugoTemplateSubstitutions(content,
1417 CHANGES: changesHugo,
1418 DATE: givenDate == null ? "" : givenDate.format("yyyy-MM-dd"),
1419 DRAFT: givenDate == null ? "true" : "false",
1420 JALVIEWJSLINK: jalviewjsLink.contains(JALVIEW_VERSION) ? "true" : "false",
1421 JVL_HEADER: oldJvl.contains(JALVIEW_VERSION) ? "jvl: true" : ""
1428 inputs.file(oldJvlFile)
1429 inputs.dir(hugoTemplatesDir)
1430 inputs.property("JALVIEW_VERSION", { JALVIEW_VERSION })
1431 inputs.property("CHANNEL", { CHANNEL })
1434 def getMdDate(File mdFile) {
1435 return mdFileComponents(mdFile, true)
1438 def getMdSections(String content) {
1440 def sectionContent = ""
1441 def sectionName = null
1442 content.eachLine { line ->
1444 if (m = line =~ /^##([^#].*)$/) {
1445 if (sectionName != null) {
1446 sections[sectionName] = sectionContent
1450 sectionName = m[0][1].trim()
1451 sectionName = sectionName.toLowerCase()
1452 sectionName = sectionName.replaceAll(/ +/, "_")
1453 sectionName = sectionName.replaceAll(/[^a-z0-9_\-]/, "")
1454 } else if (sectionName != null) {
1455 sectionContent += line+"\n"
1458 if (sectionContent != null) {
1459 sections[sectionName] = sectionContent
1465 task copyHelp(type: Copy) {
1466 def inputDir = helpSourceDir
1467 def outputDir = "${helpBuildDir}/${help_dir}"
1471 include('**/*.html')
1475 filter(ReplaceTokens,
1479 'Version-Rel': JALVIEW_VERSION,
1480 'Year-Rel': getDate("yyyy")
1487 exclude('**/*.html')
1494 inputs.dir(inputDir)
1495 outputs.files(helpFile)
1496 outputs.dir(outputDir)
1500 task releasesTemplates {
1502 description "Recreate whatsNew.html and releases.html from markdown files and templates in help"
1506 def releasesTemplateFile = file("${jalviewDir}/${releases_template}")
1507 def whatsnewTemplateFile = file("${jalviewDir}/${whatsnew_template}")
1508 def releasesHtmlFile = file("${helpBuildDir}/${help_dir}/${releases_html}")
1509 def whatsnewHtmlFile = file("${helpBuildDir}/${help_dir}/${whatsnew_html}")
1510 def releasesMdDir = "${jalviewDir}/${releases_dir}"
1511 def whatsnewMdDir = "${jalviewDir}/${whatsnew_dir}"
1514 def releaseMdFile = file("${releasesMdDir}/release-${JALVIEW_VERSION_UNDERSCORES}.md")
1515 def whatsnewMdFile = file("${whatsnewMdDir}/whatsnew-${JALVIEW_VERSION_UNDERSCORES}.md")
1517 if (CHANNEL == "RELEASE") {
1518 if (!releaseMdFile.exists()) {
1519 throw new GradleException("File ${releaseMdFile} must be created for RELEASE")
1521 if (!whatsnewMdFile.exists()) {
1522 throw new GradleException("File ${whatsnewMdFile} must be created for RELEASE")
1526 def releaseFiles = fileTree(dir: releasesMdDir, include: "release-*.md")
1527 def releaseFilesDates = releaseFiles.collectEntries {
1528 [(it): getMdDate(it)]
1530 releaseFiles = releaseFiles.sort { a,b -> releaseFilesDates[a].compareTo(releaseFilesDates[b]) }
1532 def releasesTemplate = releasesTemplateFile.text
1533 def m = releasesTemplate =~ /(?s)__VERSION_LOOP_START__(.*)__VERSION_LOOP_END__/
1534 def versionTemplate = m[0][1]
1536 MutableDataSet options = new MutableDataSet()
1538 def extensions = new ArrayList<>()
1539 options.set(Parser.EXTENSIONS, extensions)
1540 options.set(Parser.HTML_BLOCK_COMMENT_ONLY_FULL_LINE, true)
1542 Parser parser = Parser.builder(options).build()
1543 HtmlRenderer renderer = HtmlRenderer.builder(options).build()
1545 def actualVersions = releaseFiles.collect { rf ->
1546 def (rfMap, rfContent) = mdFileComponents(rf)
1547 return rfMap.version
1549 def versionsHtml = ""
1550 def linkedVersions = []
1551 releaseFiles.reverse().each { rFile ->
1552 def (rMap, rContent) = mdFileComponents(rFile)
1554 def versionLink = ""
1555 def partialVersion = ""
1556 def firstPart = true
1557 rMap.version.split("\\.").each { part ->
1558 def displayPart = ( firstPart ? "" : "." ) + part
1559 partialVersion += displayPart
1561 linkedVersions.contains(partialVersion)
1562 || ( actualVersions.contains(partialVersion) && partialVersion != rMap.version )
1564 versionLink += displayPart
1566 versionLink += "<a id=\"Jalview.${partialVersion}\">${displayPart}</a>"
1567 linkedVersions += partialVersion
1571 def displayDate = releaseFilesDates[rFile].format("dd/MM/yyyy")
1574 def rContentProcessed = ""
1575 rContent.eachLine { line ->
1576 if (lm = line =~ /^(\s*-)(\s*<!--[^>]*?-->)(.*)$/) {
1577 line = "${lm[0][1]}${lm[0][3]}${lm[0][2]}"
1578 } else if (lm = line =~ /^###([^#]+.*)$/) {
1579 line = "_${lm[0][1].trim()}_"
1581 rContentProcessed += line + "\n"
1584 def rContentSections = getMdSections(rContentProcessed)
1585 def rVersion = versionTemplate
1586 if (rVersion != "") {
1587 def rNewFeatures = rContentSections["new_features"]
1588 def rIssuesResolved = rContentSections["issues_resolved"]
1589 Node newFeaturesNode = parser.parse(rNewFeatures)
1590 String newFeaturesHtml = renderer.render(newFeaturesNode)
1591 Node issuesResolvedNode = parser.parse(rIssuesResolved)
1592 String issuesResolvedHtml = renderer.render(issuesResolvedNode)
1593 rVersion = hugoTemplateSubstitutions(rVersion,
1595 VERSION: rMap.version,
1596 VERSION_LINK: versionLink,
1597 DISPLAY_DATE: displayDate,
1598 NEW_FEATURES: newFeaturesHtml,
1599 ISSUES_RESOLVED: issuesResolvedHtml
1602 versionsHtml += rVersion
1606 releasesTemplate = releasesTemplate.replaceAll("(?s)__VERSION_LOOP_START__.*__VERSION_LOOP_END__", versionsHtml)
1607 releasesTemplate = hugoTemplateSubstitutions(releasesTemplate)
1608 releasesHtmlFile.text = releasesTemplate
1610 if (whatsnewMdFile.exists()) {
1611 def wnDisplayDate = releaseFilesDates[releaseMdFile] != null ? releaseFilesDates[releaseMdFile].format("dd MMMM yyyy") : ""
1612 def whatsnewMd = hugoTemplateSubstitutions(whatsnewMdFile.text)
1613 Node whatsnewNode = parser.parse(whatsnewMd)
1614 String whatsnewHtml = renderer.render(whatsnewNode)
1615 whatsnewHtml = whatsnewTemplateFile.text.replaceAll("__WHATS_NEW__", whatsnewHtml)
1616 whatsnewHtmlFile.text = hugoTemplateSubstitutions(whatsnewHtml,
1618 VERSION: JALVIEW_VERSION,
1619 DISPLAY_DATE: wnDisplayDate
1622 } else if (gradle.taskGraph.hasTask(":linkCheck")) {
1623 whatsnewHtmlFile.text = "Development build " + getDate("yyyy-MM-dd HH:mm:ss")
1628 inputs.file(releasesTemplateFile)
1629 inputs.file(whatsnewTemplateFile)
1630 inputs.dir(releasesMdDir)
1631 inputs.dir(whatsnewMdDir)
1632 outputs.file(releasesHtmlFile)
1633 outputs.file(whatsnewHtmlFile)
1637 task copyResources(type: Copy) {
1639 description = "Copy (and make text substitutions in) the resources dir to the build area"
1641 def inputDir = resourceDir
1642 def outputDir = resourcesBuildDir
1646 include('**/*.html')
1648 filter(ReplaceTokens,
1652 'Version-Rel': JALVIEW_VERSION,
1653 'Year-Rel': getDate("yyyy")
1660 exclude('**/*.html')
1665 inputs.dir(inputDir)
1666 outputs.dir(outputDir)
1669 task copyChannelResources(type: Copy) {
1670 dependsOn copyResources
1672 description = "Copy the channel resources dir to the build resources area"
1674 def inputDir = "${channelDir}/${resource_dir}"
1675 def outputDir = resourcesBuildDir
1677 include(channel_props)
1678 filter(ReplaceTokens,
1682 'SUFFIX': channelSuffix
1687 exclude(channel_props)
1691 inputs.dir(inputDir)
1692 outputs.dir(outputDir)
1695 task createBuildProperties(type: WriteProperties) {
1696 dependsOn copyResources
1698 description = "Create the ${buildProperties} file"
1700 inputs.dir(sourceDir)
1701 inputs.dir(resourcesBuildDir)
1702 outputFile (buildProperties)
1703 // taking time specific comment out to allow better incremental builds
1704 comment "--Jalview Build Details--\n"+getDate("yyyy-MM-dd HH:mm:ss")
1705 //comment "--Jalview Build Details--\n"+getDate("yyyy-MM-dd")
1706 property "BUILD_DATE", getDate("HH:mm:ss dd MMMM yyyy")
1707 property "VERSION", JALVIEW_VERSION
1708 property "INSTALLATION", INSTALLATION+" git-commit:"+gitHash+" ["+gitBranch+"]"
1709 property "JAVA_COMPILE_VERSION", JAVA_INTEGER_VERSION
1710 if (getdownSetAppBaseProperty) {
1711 property "GETDOWNAPPBASE", getdownAppBase
1712 property "GETDOWNAPPDISTDIR", getdownAppDistDir
1714 outputs.file(outputFile)
1718 task buildIndices(type: JavaExec) {
1720 classpath = sourceSets.main.compileClasspath
1721 main = "com.sun.java.help.search.Indexer"
1722 workingDir = "${helpBuildDir}/${help_dir}"
1725 inputs.dir("${workingDir}/${argDir}")
1727 outputs.dir("${classesDir}/doc")
1728 outputs.dir("${classesDir}/help")
1729 outputs.file("${workingDir}/JavaHelpSearch/DOCS")
1730 outputs.file("${workingDir}/JavaHelpSearch/DOCS.TAB")
1731 outputs.file("${workingDir}/JavaHelpSearch/OFFSETS")
1732 outputs.file("${workingDir}/JavaHelpSearch/POSITIONS")
1733 outputs.file("${workingDir}/JavaHelpSearch/SCHEMA")
1734 outputs.file("${workingDir}/JavaHelpSearch/TMAP")
1737 task buildResources {
1738 dependsOn copyResources
1739 dependsOn copyChannelResources
1740 dependsOn createBuildProperties
1744 dependsOn buildResources
1747 dependsOn releasesTemplates
1748 dependsOn convertMdFiles
1749 dependsOn buildIndices
1753 compileJava.dependsOn prepare
1754 run.dependsOn compileJava
1755 compileTestJava.dependsOn compileJava
1760 group = "Verification"
1761 description = "Runs all testTaskN tasks)"
1764 dependsOn cloverClasses
1766 dependsOn testClasses
1769 // not running tests in this task
1772 /* testTask0 is the main test task */
1773 task testTask0(type: Test) {
1774 group = "Verification"
1775 description = "The main test task. Runs all non-testTaskN-labelled tests (unless excluded)"
1777 includeGroups testng_groups.split(",")
1778 excludeGroups testng_excluded_groups.split(",")
1779 tasks.withType(Test).matching {it.name.startsWith("testTask") && it.name != name}.all {t -> excludeGroups t.name}
1781 useDefaultListeners=true
1783 timeout = Duration.ofMinutes(15)
1786 /* separated tests */
1787 task testTask1(type: Test) {
1788 group = "Verification"
1789 description = "Tests that need to be isolated from the main test run"
1792 excludeGroups testng_excluded_groups.split(",")
1794 useDefaultListeners=true
1796 timeout = Duration.ofMinutes(5)
1799 task testTask2(type: Test) {
1800 group = "Verification"
1801 description = "Tests that need to be isolated from the main test run"
1804 excludeGroups testng_excluded_groups.split(",")
1806 useDefaultListeners=true
1808 timeout = Duration.ofMinutes(5)
1810 task testTask3(type: Test) {
1811 group = "Verification"
1812 description = "Tests that need to be isolated from the main test run"
1815 excludeGroups testng_excluded_groups.split(",")
1817 useDefaultListeners=true
1819 timeout = Duration.ofMinutes(5)
1822 /* insert more testTaskNs here -- change N to next digit or other string */
1824 task testTaskN(type: Test) {
1825 group = "Verification"
1826 description = "Tests that need to be isolated from the main test run"
1829 excludeGroups testng_excluded_groups.split(",")
1831 useDefaultListeners=true
1838 * adapted from https://medium.com/@wasyl/pretty-tests-summary-in-gradle-744804dd676c
1839 * to summarise test results from all Test tasks
1841 /* START of test tasks results summary */
1842 import groovy.time.TimeCategory
1843 import org.gradle.api.tasks.testing.logging.TestExceptionFormat
1844 import org.gradle.api.tasks.testing.logging.TestLogEvent
1845 rootProject.ext.testsResults = [] // Container for tests summaries
1847 tasks.withType(Test).matching {t -> t.getName().startsWith("testTask")}.all { testTask ->
1849 // from original test task
1851 dependsOn cloverClasses
1853 dependsOn testClasses //?
1856 // run main tests first
1857 if (!testTask.name.equals("testTask0"))
1858 testTask.mustRunAfter "testTask0"
1860 testTask.testLogging { logging ->
1861 events TestLogEvent.FAILED
1862 // TestLogEvent.SKIPPED,
1863 // TestLogEvent.STANDARD_OUT,
1864 // TestLogEvent.STANDARD_ERROR
1866 exceptionFormat TestExceptionFormat.FULL
1869 showStackTraces true
1871 showStandardStreams true
1873 info.events = [ TestLogEvent.FAILED ]
1876 if (OperatingSystem.current().isMacOsX()) {
1877 testTask.systemProperty "apple.awt.UIElement", "true"
1878 testTask.environment "JAVA_TOOL_OPTIONS", "-Dapple.awt.UIElement=true"
1882 ignoreFailures = true // Always try to run all tests for all modules
1884 afterSuite { desc, result ->
1886 return // Only summarize results for whole modules
1888 def resultsInfo = [testTask.project.name, testTask.name, result, TimeCategory.minus(new Date(result.endTime), new Date(result.startTime)), testTask.reports.html.entryPoint]
1890 rootProject.ext.testsResults.add(resultsInfo)
1893 // from original test task
1894 maxHeapSize = "1024m"
1896 workingDir = jalviewDir
1897 def testLaf = project.findProperty("test_laf")
1898 if (testLaf != null) {
1899 println("Setting Test LaF to '${testLaf}'")
1900 systemProperty "laf", testLaf
1902 def testHiDPIScale = project.findProperty("test_HiDPIScale")
1903 if (testHiDPIScale != null) {
1904 println("Setting Test HiDPI Scale to '${testHiDPIScale}'")
1905 systemProperty "sun.java2d.uiScale", testHiDPIScale
1907 sourceCompatibility = compile_source_compatibility
1908 targetCompatibility = compile_target_compatibility
1909 jvmArgs += additional_compiler_args
1912 // this is not perfect yet -- we should only add the commandLineIncludePatterns to the
1913 // testTasks that include the tests, and exclude all from the others.
1914 // get --test argument
1915 filter.commandLineIncludePatterns = test.filter.commandLineIncludePatterns
1916 // do something with testTask.getCandidateClassFiles() to see if the test should silently finish because of the
1917 // commandLineIncludePatterns not matching anything. Instead we are doing setFailOnNoMatchingTests(false) below
1921 println("Running tests " + (useClover?"WITH":"WITHOUT") + " clover")
1926 /* don't fail on no matching tests (so --tests will run across all testTasks) */
1927 testTask.filter.setFailOnNoMatchingTests(false)
1929 /* ensure the "test" task dependsOn all the testTasks */
1930 test.dependsOn testTask
1933 gradle.buildFinished {
1934 def allResults = rootProject.ext.testsResults
1936 if (!allResults.isEmpty()) {
1937 printResults allResults
1938 allResults.each {r ->
1939 if (r[2].resultType == TestResult.ResultType.FAILURE)
1940 throw new GradleException("Failed tests!")
1945 private static String colString(styler, col, colour, text) {
1946 return col?"${styler[colour](text)}":text
1949 private static String getSummaryLine(s, pn, tn, rt, rc, rs, rf, rsk, t, col) {
1950 def colour = 'black'
1958 case TestResult.ResultType.SUCCESS:
1961 case TestResult.ResultType.FAILURE:
1969 StringBuilder sb = new StringBuilder()
1973 sb.append(" results: ")
1974 sb.append(colString(s, col && !nocol, colour, text))
1976 sb.append("${rc} tests, ")
1977 sb.append(colString(s, col && rs > 0, 'green', rs))
1978 sb.append(" successes, ")
1979 sb.append(colString(s, col && rf > 0, 'red', rf))
1980 sb.append(" failures, ")
1981 sb.append("${rsk} skipped) in ${t}")
1982 return sb.toString()
1985 private static void printResults(allResults) {
1987 // styler from https://stackoverflow.com/a/56139852
1988 def styler = 'black red green yellow blue magenta cyan white'.split().toList().withIndex(30).collectEntries { key, val -> [(key) : { "\033[${val}m${it}\033[0m" }] }
1991 def failedTests = false
1992 def summaryLines = []
1994 def totalsuccess = 0
1997 def totaltime = TimeCategory.getSeconds(0)
1998 // sort on project name then task name
1999 allResults.sort {a, b -> a[0] == b[0]? a[1]<=>b[1]:a[0] <=> b[0]}.each {
2000 def projectName = it[0]
2001 def taskName = it[1]
2005 def summaryCol = getSummaryLine(styler, projectName, taskName, result.resultType, result.testCount, result.successfulTestCount, result.failedTestCount, result.skippedTestCount, time, true)
2006 def summaryPlain = getSummaryLine(styler, projectName, taskName, result.resultType, result.testCount, result.successfulTestCount, result.failedTestCount, result.skippedTestCount, time, false)
2007 def reportLine = "Report file: ${report}"
2008 def ls = summaryPlain.length()
2009 def lr = reportLine.length()
2010 def m = [ls, lr].max()
2013 def info = [ls, summaryCol, reportLine]
2014 summaryLines.add(info)
2015 failedTests |= result.resultType == TestResult.ResultType.FAILURE
2016 totalcount += result.testCount
2017 totalsuccess += result.successfulTestCount
2018 totalfail += result.failedTestCount
2019 totalskip += result.skippedTestCount
2022 def totalSummaryCol = getSummaryLine(styler, "OVERALL", "", failedTests?TestResult.ResultType.FAILURE:TestResult.ResultType.SUCCESS, totalcount, totalsuccess, totalfail, totalskip, totaltime, true)
2023 def totalSummaryPlain = getSummaryLine(styler, "OVERALL", "", failedTests?TestResult.ResultType.FAILURE:TestResult.ResultType.SUCCESS, totalcount, totalsuccess, totalfail, totalskip, totaltime, false)
2024 def tls = totalSummaryPlain.length()
2025 if (tls > maxLength)
2027 def info = [tls, totalSummaryCol, null]
2028 summaryLines.add(info)
2030 def allSummaries = []
2031 for(sInfo : summaryLines) {
2033 def summary = sInfo[1]
2034 def report = sInfo[2]
2036 StringBuilder sb = new StringBuilder()
2037 sb.append("│" + summary + " " * (maxLength - ls) + "│")
2038 if (report != null) {
2039 sb.append("\n│" + report + " " * (maxLength - report.length()) + "│")
2041 allSummaries += sb.toString()
2044 println "┌${"${"─" * maxLength}"}┐"
2045 println allSummaries.join("\n├${"${"─" * maxLength}"}┤\n")
2046 println "└${"${"─" * maxLength}"}┘"
2048 /* END of test tasks results summary */
2051 task compileLinkCheck(type: JavaCompile) {
2053 classpath = files("${jalviewDir}/${utils_dir}")
2054 destinationDir = file("${jalviewDir}/${utils_dir}")
2055 source = fileTree(dir: "${jalviewDir}/${utils_dir}", include: ["HelpLinksChecker.java", "BufferedLineReader.java"])
2057 inputs.file("${jalviewDir}/${utils_dir}/HelpLinksChecker.java")
2058 inputs.file("${jalviewDir}/${utils_dir}/HelpLinksChecker.java")
2059 outputs.file("${jalviewDir}/${utils_dir}/HelpLinksChecker.class")
2060 outputs.file("${jalviewDir}/${utils_dir}/BufferedLineReader.class")
2064 task linkCheck(type: JavaExec) {
2066 dependsOn compileLinkCheck
2068 def helpLinksCheckerOutFile = file("${jalviewDir}/${utils_dir}/HelpLinksChecker.out")
2069 classpath = files("${jalviewDir}/${utils_dir}")
2070 main = "HelpLinksChecker"
2071 workingDir = "${helpBuildDir}"
2072 args = [ "${helpBuildDir}/${help_dir}", "-nointernet" ]
2074 def outFOS = new FileOutputStream(helpLinksCheckerOutFile, false) // false == don't append
2075 standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
2078 errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
2082 inputs.dir(helpBuildDir)
2083 outputs.file(helpLinksCheckerOutFile)
2087 // import the pubhtmlhelp target
2088 ant.properties.basedir = "${jalviewDir}"
2089 ant.properties.helpBuildDir = "${helpBuildDir}/${help_dir}"
2090 ant.importBuild "${utils_dir}/publishHelp.xml"
2093 task cleanPackageDir(type: Delete) {
2095 delete fileTree(dir: "${jalviewDir}/${package_dir}", include: "*.jar")
2105 attributes "Main-Class": main_class,
2106 "Permissions": "all-permissions",
2107 "Application-Name": applicationName,
2108 "Codebase": application_codebase,
2109 "Implementation-Version": JALVIEW_VERSION
2112 def outputDir = "${jalviewDir}/${package_dir}"
2113 destinationDirectory = file(outputDir)
2114 archiveFileName = rootProject.name+".jar"
2115 duplicatesStrategy "EXCLUDE"
2122 exclude "**/*.jar.*"
2124 inputs.dir(sourceSets.main.java.outputDir)
2125 sourceSets.main.resources.srcDirs.each{ dir ->
2128 outputs.file("${outputDir}/${archiveFileName}")
2132 task copyJars(type: Copy) {
2133 from fileTree(dir: classesDir, include: "**/*.jar").files
2134 into "${jalviewDir}/${package_dir}"
2138 // doing a Sync instead of Copy as Copy doesn't deal with "outputs" very well
2139 task syncJars(type: Sync) {
2141 from fileTree(dir: "${jalviewDir}/${libDistDir}", include: "**/*.jar").files
2142 into "${jalviewDir}/${package_dir}"
2144 include jar.archiveFileName.getOrNull()
2151 description = "Put all required libraries in dist"
2152 // order of "cleanPackageDir", "copyJars", "jar" important!
2153 jar.mustRunAfter cleanPackageDir
2154 syncJars.mustRunAfter cleanPackageDir
2155 dependsOn cleanPackageDir
2158 outputs.dir("${jalviewDir}/${package_dir}")
2163 dependsOn cleanPackageDir
2169 task launcherJar(type: Jar) {
2172 "Main-Class": shadow_jar_main_class,
2173 "Implementation-Version": JALVIEW_VERSION,
2174 "Application-Name": applicationName
2180 group = "distribution"
2181 description = "Create a single jar file with all dependency libraries merged. Can be run with java -jar"
2186 def jarFiles = fileTree(dir: "${jalviewDir}/${libDistDir}", include: "*.jar", exclude: "regex.jar").getFiles()
2187 def groovyJars = jarFiles.findAll {it1 -> file(it1).getName().startsWith("groovy-swing")}
2188 def otherJars = jarFiles.findAll {it2 -> !file(it2).getName().startsWith("groovy-swing")}
2193 // shadowJar manifest must inheritFrom another Jar task. Can't set attributes here.
2194 inheritFrom(project.tasks.launcherJar.manifest)
2196 // we need to include the groovy-swing Include-Package for it to run in the shadowJar
2198 def jarFileManifests = []
2199 groovyJars.each { jarFile ->
2200 def mf = zipTree(jarFile).getFiles().find { it.getName().equals("MANIFEST.MF") }
2202 jarFileManifests += mf
2206 from (jarFileManifests) {
2207 eachEntry { details ->
2208 if (!details.key.equals("Import-Package")) {
2216 duplicatesStrategy "INCLUDE"
2218 // this mainClassName is mandatory but gets ignored due to manifest created in doFirst{}. Set the Main-Class as an attribute in launcherJar instead
2219 mainClassName = shadow_jar_main_class
2221 classifier = "all-"+JALVIEW_VERSION+"-j"+JAVA_VERSION
2225 task getdownImagesCopy() {
2226 inputs.dir getdownImagesDir
2227 outputs.dir getdownImagesBuildDir
2231 from(getdownImagesDir) {
2232 include("*getdown*.png")
2234 into getdownImagesBuildDir
2239 task getdownImagesProcess() {
2240 dependsOn getdownImagesCopy
2243 if (backgroundImageText) {
2244 if (convertBinary == null) {
2245 throw new StopExecutionException("No ImageMagick convert binary installed at '${convertBinaryExpectedLocation}'")
2247 if (!project.hasProperty("getdown_background_image_text_suffix_cmd")) {
2248 throw new StopExecutionException("No property 'getdown_background_image_text_suffix_cmd' defined. See channel_gradle.properties for channel ${CHANNEL}")
2250 fileTree(dir: getdownImagesBuildDir, include: "*background*.png").getFiles().each { file ->
2252 executable convertBinary
2255 '-font', getdown_background_image_text_font,
2256 '-fill', getdown_background_image_text_colour,
2257 '-draw', sprintf(getdown_background_image_text_suffix_cmd, channelSuffix),
2258 '-draw', sprintf(getdown_background_image_text_commit_cmd, "git-commit: ${gitHash}"),
2259 '-draw', sprintf(getdown_background_image_text_date_cmd, getDate("yyyy-MM-dd HH:mm:ss")),
2268 task getdownImages() {
2269 dependsOn getdownImagesProcess
2272 task getdownWebsiteBuild() {
2273 group = "distribution"
2274 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."
2276 dependsOn getdownImages
2281 def getdownWebsiteResourceFilenames = []
2282 def getdownResourceDir = getdownResourceDir
2283 def getdownResourceFilenames = []
2286 // clean the getdown website and files dir before creating getdown folders
2287 delete getdownAppBaseDir
2288 delete getdownFilesDir
2291 from buildProperties
2292 rename(file(buildProperties).getName(), getdown_build_properties)
2295 getdownWebsiteResourceFilenames += "${getdownAppDistDir}/${getdown_build_properties}"
2298 from channelPropsFile
2299 filter(ReplaceTokens,
2303 'SUFFIX': channelSuffix
2306 into getdownAppBaseDir
2308 getdownWebsiteResourceFilenames += file(channelPropsFile).getName()
2310 // set some getdownTxt_ properties then go through all properties looking for getdownTxt_...
2311 def props = project.properties.sort { it.key }
2312 if (getdownAltJavaMinVersion != null && getdownAltJavaMinVersion.length() > 0) {
2313 props.put("getdown_txt_java_min_version", getdownAltJavaMinVersion)
2315 if (getdownAltJavaMaxVersion != null && getdownAltJavaMaxVersion.length() > 0) {
2316 props.put("getdown_txt_java_max_version", getdownAltJavaMaxVersion)
2318 if (getdownAltMultiJavaLocation != null && getdownAltMultiJavaLocation.length() > 0) {
2319 props.put("getdown_txt_multi_java_location", getdownAltMultiJavaLocation)
2321 if (getdownImagesBuildDir != null && file(getdownImagesBuildDir).exists()) {
2322 props.put("getdown_txt_ui.background_image", "${getdownImagesBuildDir}/${getdown_background_image}")
2323 props.put("getdown_txt_ui.instant_background_image", "${getdownImagesBuildDir}/${getdown_instant_background_image}")
2324 props.put("getdown_txt_ui.error_background", "${getdownImagesBuildDir}/${getdown_error_background}")
2325 props.put("getdown_txt_ui.progress_image", "${getdownImagesBuildDir}/${getdown_progress_image}")
2326 props.put("getdown_txt_ui.icon", "${getdownImagesDir}/${getdown_icon}")
2327 props.put("getdown_txt_ui.mac_dock_icon", "${getdownImagesDir}/${getdown_mac_dock_icon}")
2330 props.put("getdown_txt_title", jalview_name)
2331 props.put("getdown_txt_ui.name", applicationName)
2333 // start with appbase
2334 getdownTextLines += "appbase = ${getdownAppBase}"
2335 props.each{ prop, val ->
2336 if (prop.startsWith("getdown_txt_") && val != null) {
2337 if (prop.startsWith("getdown_txt_multi_")) {
2338 def key = prop.substring(18)
2339 val.split(",").each{ v ->
2340 def line = "${key} = ${v}"
2341 getdownTextLines += line
2344 // file values rationalised
2345 if (val.indexOf('/') > -1 || prop.startsWith("getdown_txt_resource")) {
2347 if (val.indexOf('/') == 0) {
2350 } else if (val.indexOf('/') > 0) {
2351 // relative path (relative to jalviewDir)
2352 r = file( "${jalviewDir}/${val}" )
2355 val = "${getdown_resource_dir}/" + r.getName()
2356 getdownWebsiteResourceFilenames += val
2357 getdownResourceFilenames += r.getPath()
2360 if (! prop.startsWith("getdown_txt_resource")) {
2361 def line = prop.substring(12) + " = ${val}"
2362 getdownTextLines += line
2368 getdownWebsiteResourceFilenames.each{ filename ->
2369 getdownTextLines += "resource = ${filename}"
2371 getdownResourceFilenames.each{ filename ->
2374 into getdownResourceDir
2378 def getdownWrapperScripts = [ getdown_bash_wrapper_script, getdown_powershell_wrapper_script, getdown_batch_wrapper_script ]
2379 getdownWrapperScripts.each{ script ->
2380 def s = file( "${jalviewDir}/utils/getdown/${getdown_wrapper_script_dir}/${script}" )
2384 into "${getdownAppBaseDir}/${getdown_wrapper_script_dir}"
2386 getdownTextLines += "xresource = ${getdown_wrapper_script_dir}/${script}"
2391 fileTree(file(package_dir)).each{ f ->
2392 if (f.isDirectory()) {
2393 def files = fileTree(dir: f, include: ["*"]).getFiles()
2395 } else if (f.exists()) {
2399 def jalviewJar = jar.archiveFileName.getOrNull()
2400 // put jalview.jar first for CLASSPATH and .properties files reasons
2401 codeFiles.sort{a, b -> ( a.getName() == jalviewJar ? -1 : ( b.getName() == jalviewJar ? 1 : a <=> b ) ) }.each{f ->
2402 def name = f.getName()
2403 def line = "code = ${getdownAppDistDir}/${name}"
2404 getdownTextLines += line
2411 // NOT USING MODULES YET, EVERYTHING SHOULD BE IN dist
2413 if (JAVA_VERSION.equals("11")) {
2414 def j11libFiles = fileTree(dir: "${jalviewDir}/${j11libDir}", include: ["*.jar"]).getFiles()
2415 j11libFiles.sort().each{f ->
2416 def name = f.getName()
2417 def line = "code = ${getdown_j11lib_dir}/${name}"
2418 getdownTextLines += line
2421 into getdownJ11libDir
2427 // 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.
2428 //getdownTextLines += "class = " + file(getdownLauncher).getName()
2429 getdownTextLines += "resource = ${getdown_launcher_new}"
2430 getdownTextLines += "class = ${main_class}"
2431 // Not setting these properties in general so that getdownappbase and getdowndistdir will default to release version in jalview.bin.Cache
2432 if (getdownSetAppBaseProperty) {
2433 getdownTextLines += "jvmarg = -Dgetdowndistdir=${getdownAppDistDir}"
2434 getdownTextLines += "jvmarg = -Dgetdownappbase=${getdownAppBase}"
2437 def getdownTxt = file("${getdownAppBaseDir}/getdown.txt")
2438 getdownTxt.write(getdownTextLines.join("\n"))
2440 getdownLaunchJvl = getdown_launch_jvl_name + ( (jvlChannelName != null && jvlChannelName.length() > 0)?"-${jvlChannelName}":"" ) + ".jvl"
2441 def launchJvl = file("${getdownAppBaseDir}/${getdownLaunchJvl}")
2442 launchJvl.write("appbase=${getdownAppBase}")
2444 // files going into the getdown website dir: getdown-launcher.jar
2446 from getdownLauncher
2447 rename(file(getdownLauncher).getName(), getdown_launcher_new)
2448 into getdownAppBaseDir
2451 // files going into the getdown website dir: getdown-launcher(-local).jar
2453 from getdownLauncher
2454 if (file(getdownLauncher).getName() != getdown_launcher) {
2455 rename(file(getdownLauncher).getName(), getdown_launcher)
2457 into getdownAppBaseDir
2460 // files going into the getdown website dir: ./install dir and files
2461 if (! (CHANNEL.startsWith("ARCHIVE") || CHANNEL.startsWith("DEVELOP"))) {
2464 from getdownLauncher
2465 from "${getdownAppDir}/${getdown_build_properties}"
2466 if (file(getdownLauncher).getName() != getdown_launcher) {
2467 rename(file(getdownLauncher).getName(), getdown_launcher)
2469 into getdownInstallDir
2472 // and make a copy in the getdown files dir (these are not downloaded by getdown)
2474 from getdownInstallDir
2475 into getdownFilesInstallDir
2479 // files going into the getdown files dir: getdown.txt, getdown-launcher.jar, channel-launch.jvl, build_properties
2483 from getdownLauncher
2484 from "${getdownAppBaseDir}/${getdown_build_properties}"
2485 from "${getdownAppBaseDir}/${channel_props}"
2486 if (file(getdownLauncher).getName() != getdown_launcher) {
2487 rename(file(getdownLauncher).getName(), getdown_launcher)
2489 into getdownFilesDir
2492 // and ./resource (not all downloaded by getdown)
2494 from getdownResourceDir
2495 into "${getdownFilesDir}/${getdown_resource_dir}"
2500 inputs.dir("${jalviewDir}/${package_dir}")
2502 outputs.dir(getdownAppBaseDir)
2503 outputs.dir(getdownFilesDir)
2507 // a helper task to allow getdown digest of any dir: `gradle getdownDigestDir -PDIGESTDIR=/path/to/my/random/getdown/dir
2508 task getdownDigestDir(type: JavaExec) {
2510 description "A task to run a getdown Digest on a dir with getdown.txt. Provide a DIGESTDIR property via -PDIGESTDIR=..."
2512 def digestDirPropertyName = "DIGESTDIR"
2514 classpath = files(getdownLauncher)
2515 def digestDir = findProperty(digestDirPropertyName)
2516 if (digestDir == null) {
2517 throw new GradleException("Must provide a DIGESTDIR value to produce an alternative getdown digest")
2521 main = "com.threerings.getdown.tools.Digester"
2525 task getdownDigest(type: JavaExec) {
2526 group = "distribution"
2527 description = "Digest the getdown website folder"
2529 dependsOn getdownWebsiteBuild
2532 classpath = files(getdownLauncher)
2534 main = "com.threerings.getdown.tools.Digester"
2535 args getdownAppBaseDir
2536 inputs.dir(getdownAppBaseDir)
2537 outputs.file("${getdownAppBaseDir}/digest2.txt")
2542 group = "distribution"
2543 description = "Create the minimal and full getdown app folder for installers and website and create digest file"
2544 dependsOn getdownDigest
2546 if (reportRsyncCommand) {
2547 def fromDir = getdownAppBaseDir + (getdownAppBaseDir.endsWith('/')?'':'/')
2548 def toDir = "${getdown_rsync_dest}/${getdownDir}" + (getdownDir.endsWith('/')?'':'/')
2549 println "LIKELY RSYNC COMMAND:"
2550 println "mkdir -p '$toDir'\nrsync -avh --delete '$fromDir' '$toDir'"
2551 if (RUNRSYNC == "true") {
2553 commandLine "mkdir", "-p", toDir
2556 commandLine "rsync", "-avh", "--delete", fromDir, toDir
2563 task getdownWebsite {
2564 group = "distribution"
2565 description = "A task to create the whole getdown channel website dir including digest file"
2567 dependsOn getdownWebsiteBuild
2568 dependsOn getdownDigest
2571 task getdownArchiveBuild() {
2572 group = "distribution"
2573 description = "Put files in the archive dir to go on the website"
2575 dependsOn getdownWebsiteBuild
2577 def v = "v${JALVIEW_VERSION_UNDERSCORES}"
2578 def vDir = "${getdownArchiveDir}/${v}"
2579 getdownFullArchiveDir = "${vDir}/getdown"
2580 getdownVersionLaunchJvl = "${vDir}/jalview-${v}.jvl"
2582 def vAltDir = "alt_${v}"
2583 def archiveImagesDir = "${jalviewDir}/${channel_properties_dir}/old/images"
2586 // cleanup old "old" dir
2587 delete getdownArchiveDir
2589 def getdownArchiveTxt = file("${getdownFullArchiveDir}/getdown.txt")
2590 getdownArchiveTxt.getParentFile().mkdirs()
2591 def getdownArchiveTextLines = []
2592 def getdownFullArchiveAppBase = "${getdownArchiveAppBase}${getdownArchiveAppBase.endsWith("/")?"":"/"}${v}/getdown/"
2596 from "${getdownAppBaseDir}/${getdownAppDistDir}"
2597 into "${getdownFullArchiveDir}/${vAltDir}"
2600 getdownTextLines.each { line ->
2601 line = line.replaceAll("^(?<s>appbase\\s*=\\s*).*", '${s}'+getdownFullArchiveAppBase)
2602 line = line.replaceAll("^(?<s>(resource|code)\\s*=\\s*)${getdownAppDistDir}/", '${s}'+vAltDir+"/")
2603 line = line.replaceAll("^(?<s>ui.background_image\\s*=\\s*).*\\.png", '${s}'+"${getdown_resource_dir}/jalview_archive_getdown_background.png")
2604 line = line.replaceAll("^(?<s>ui.instant_background_image\\s*=\\s*).*\\.png", '${s}'+"${getdown_resource_dir}/jalview_archive_getdown_background_initialising.png")
2605 line = line.replaceAll("^(?<s>ui.error_background\\s*=\\s*).*\\.png", '${s}'+"${getdown_resource_dir}/jalview_archive_getdown_background_error.png")
2606 line = line.replaceAll("^(?<s>ui.progress_image\\s*=\\s*).*\\.png", '${s}'+"${getdown_resource_dir}/jalview_archive_getdown_progress_bar.png")
2607 // remove the existing resource = resource/ or bin/ lines
2608 if (! line.matches("resource\\s*=\\s*(resource|bin)/.*")) {
2609 getdownArchiveTextLines += line
2613 // the resource dir -- add these files as resource lines in getdown.txt
2615 from "${archiveImagesDir}"
2616 into "${getdownFullArchiveDir}/${getdown_resource_dir}"
2618 getdownArchiveTextLines += "resource = ${getdown_resource_dir}/${file.getName()}"
2622 // the wrapper scripts dir
2623 if ( file("${getdownAppBaseDir}/${getdown_wrapper_script_dir}").exists() ) {
2625 from "${getdownAppBaseDir}/${getdown_wrapper_script_dir}"
2626 into "${getdownFullArchiveDir}/${getdown_wrapper_script_dir}"
2630 getdownArchiveTxt.write(getdownArchiveTextLines.join("\n"))
2632 def vLaunchJvl = file(getdownVersionLaunchJvl)
2633 vLaunchJvl.getParentFile().mkdirs()
2634 vLaunchJvl.write("appbase=${getdownFullArchiveAppBase}\n")
2635 def vLaunchJvlPath = vLaunchJvl.toPath().toAbsolutePath()
2636 def jvlLinkPath = file("${vDir}/jalview.jvl").toPath().toAbsolutePath()
2637 // for some reason filepath.relativize(fileInSameDirPath) gives a path to "../" which is wrong
2638 //java.nio.file.Files.createSymbolicLink(jvlLinkPath, jvlLinkPath.relativize(vLaunchJvlPath));
2639 java.nio.file.Files.createSymbolicLink(jvlLinkPath, java.nio.file.Paths.get(".",vLaunchJvl.getName()));
2641 // files going into the getdown files dir: getdown.txt, getdown-launcher.jar, channel-launch.jvl, build_properties
2643 from getdownLauncher
2644 from "${getdownAppBaseDir}/${getdownLaunchJvl}"
2645 from "${getdownAppBaseDir}/${getdown_launcher_new}"
2646 from "${getdownAppBaseDir}/${channel_props}"
2647 if (file(getdownLauncher).getName() != getdown_launcher) {
2648 rename(file(getdownLauncher).getName(), getdown_launcher)
2650 into getdownFullArchiveDir
2656 task getdownArchiveDigest(type: JavaExec) {
2657 group = "distribution"
2658 description = "Digest the getdown archive folder"
2660 dependsOn getdownArchiveBuild
2663 classpath = files(getdownLauncher)
2664 args getdownFullArchiveDir
2666 main = "com.threerings.getdown.tools.Digester"
2667 inputs.dir(getdownFullArchiveDir)
2668 outputs.file("${getdownFullArchiveDir}/digest2.txt")
2671 task getdownArchive() {
2672 group = "distribution"
2673 description = "Build the website archive dir with getdown digest"
2675 dependsOn getdownArchiveBuild
2676 dependsOn getdownArchiveDigest
2679 tasks.withType(JavaCompile) {
2680 options.encoding = 'UTF-8'
2686 delete getdownAppBaseDir
2687 delete getdownFilesDir
2688 delete getdownArchiveDir
2694 if (file(install4jHomeDir).exists()) {
2696 } else if (file(System.getProperty("user.home")+"/buildtools/install4j").exists()) {
2697 install4jHomeDir = System.getProperty("user.home")+"/buildtools/install4j"
2698 } else if (file("/Applications/install4j.app/Contents/Resources/app").exists()) {
2699 install4jHomeDir = "/Applications/install4j.app/Contents/Resources/app"
2701 installDir(file(install4jHomeDir))
2703 mediaTypes = Arrays.asList(install4j_media_types.split(","))
2707 task copyInstall4jTemplate {
2708 def install4jTemplateFile = file("${install4jDir}/${install4j_template}")
2709 def install4jFileAssociationsFile = file("${install4jDir}/${install4j_installer_file_associations}")
2710 inputs.file(install4jTemplateFile)
2711 inputs.file(install4jFileAssociationsFile)
2712 inputs.property("CHANNEL", { CHANNEL })
2713 outputs.file(install4jConfFile)
2716 def install4jConfigXml = new XmlParser().parse(install4jTemplateFile)
2718 // turn off code signing if no OSX_KEYPASS
2719 if (OSX_KEYPASS == "") {
2720 install4jConfigXml.'**'.codeSigning.each { codeSigning ->
2721 codeSigning.'@macEnabled' = "false"
2723 install4jConfigXml.'**'.windows.each { windows ->
2724 windows.'@runPostProcessor' = "false"
2728 // disable install screen for OSX dmg (for 2.11.2.0)
2729 install4jConfigXml.'**'.macosArchive.each { macosArchive ->
2730 macosArchive.attributes().remove('executeSetupApp')
2731 macosArchive.attributes().remove('setupAppId')
2734 // turn off checksum creation for LOCAL channel
2735 def e = install4jConfigXml.application[0]
2736 e.'@createChecksums' = string(install4jCheckSums)
2738 // put file association actions where placeholder action is
2739 def install4jFileAssociationsText = install4jFileAssociationsFile.text
2740 def fileAssociationActions = new XmlParser().parseText("<actions>${install4jFileAssociationsText}</actions>")
2741 install4jConfigXml.'**'.action.any { a -> // .any{} stops after the first one that returns true
2742 if (a.'@name' == 'EXTENSIONS_REPLACED_BY_GRADLE') {
2743 def parent = a.parent()
2745 fileAssociationActions.each { faa ->
2748 // don't need to continue in .any loop once replacements have been made
2753 // use Windows Program Group with Examples folder for RELEASE, and Program Group without Examples for everything else
2754 // NB we're deleting the /other/ one!
2755 // Also remove the examples subdir from non-release versions
2756 def customizedIdToDelete = "PROGRAM_GROUP_RELEASE"
2757 // 2.11.1.0 NOT releasing with the Examples folder in the Program Group
2758 if (false && CHANNEL=="RELEASE") { // remove 'false && ' to include Examples folder in RELEASE channel
2759 customizedIdToDelete = "PROGRAM_GROUP_NON_RELEASE"
2761 // remove the examples subdir from Full File Set
2762 def files = install4jConfigXml.files[0]
2763 def fileset = files.filesets.fileset.find { fs -> fs.'@customizedId' == "FULL_FILE_SET" }
2764 def root = files.roots.root.find { r -> r.'@fileset' == fileset.'@id' }
2765 def mountPoint = files.mountPoints.mountPoint.find { mp -> mp.'@root' == root.'@id' }
2766 def dirEntry = files.entries.dirEntry.find { de -> de.'@mountPoint' == mountPoint.'@id' && de.'@subDirectory' == "examples" }
2767 dirEntry.parent().remove(dirEntry)
2769 install4jConfigXml.'**'.action.any { a ->
2770 if (a.'@customizedId' == customizedIdToDelete) {
2771 def parent = a.parent()
2777 // write install4j file
2778 install4jConfFile.text = XmlUtil.serialize(install4jConfigXml)
2785 delete install4jConfFile
2789 task cleanInstallersDataFiles {
2790 def installersOutputTxt = file("${jalviewDir}/${install4jBuildDir}/output.txt")
2791 def installersSha256 = file("${jalviewDir}/${install4jBuildDir}/sha256sums")
2792 def hugoDataJsonFile = file("${jalviewDir}/${install4jBuildDir}/installers-${JALVIEW_VERSION_UNDERSCORES}.json")
2794 delete installersOutputTxt
2795 delete installersSha256
2796 delete hugoDataJsonFile
2800 task install4jDMGBackgroundImageCopy {
2801 inputs.file "${install4jDMGBackgroundImageDir}/${install4jDMGBackgroundImageFile}"
2802 outputs.dir "${install4jDMGBackgroundImageBuildDir}"
2805 from(install4jDMGBackgroundImageDir) {
2806 include(install4jDMGBackgroundImageFile)
2808 into install4jDMGBackgroundImageBuildDir
2813 task install4jDMGBackgroundImageProcess {
2814 dependsOn install4jDMGBackgroundImageCopy
2817 if (backgroundImageText) {
2818 if (convertBinary == null) {
2819 throw new StopExecutionException("No ImageMagick convert binary installed at '${convertBinaryExpectedLocation}'")
2821 if (!project.hasProperty("install4j_background_image_text_suffix_cmd")) {
2822 throw new StopExecutionException("No property 'install4j_background_image_text_suffix_cmd' defined. See channel_gradle.properties for channel ${CHANNEL}")
2824 fileTree(dir: install4jDMGBackgroundImageBuildDir, include: "*.png").getFiles().each { file ->
2826 executable convertBinary
2829 '-font', install4j_background_image_text_font,
2830 '-fill', install4j_background_image_text_colour,
2831 '-draw', sprintf(install4j_background_image_text_suffix_cmd, channelSuffix),
2832 '-draw', sprintf(install4j_background_image_text_commit_cmd, "git-commit: ${gitHash}"),
2833 '-draw', sprintf(install4j_background_image_text_date_cmd, getDate("yyyy-MM-dd HH:mm:ss")),
2844 pip 'ds_store:1.3.1'
2847 task install4jCustomiseDS_StoreX64(type: PythonTask) {
2848 inputs.file(install4jDMGDSStore)
2849 inputs.file(install4jDMGDSStoreJSON)
2850 outputs.file(install4jDMGFixedDSStoreX64)
2851 def command_args = [ jalview_customise_ds_store, '--input', install4jDMGDSStore, '--output', install4jDMGFixedDSStoreX64, '--volumename', install4jmacOSArchiveX64Name, '--backgroundfile', install4j_dmg_background_filename, '--dmg', install4jmacOSArchiveX64DMGFilename + ".dmg" ]
2852 if (file(install4jDMGDSStoreJSON).exists()) {
2853 command_args += [ '--config', install4jDMGDSStoreJSON ]
2855 command = command_args
2857 println("Running command '${command_args.join(' ')}'")
2861 task install4jCustomiseDS_StoreAarch64(type: PythonTask) {
2862 inputs.file(install4jDMGDSStore)
2863 inputs.file(install4jDMGDSStoreJSON)
2864 outputs.file(install4jDMGFixedDSStoreAarch64)
2865 def command_args = [ jalview_customise_ds_store, '--input', install4jDMGDSStore, '--output', install4jDMGFixedDSStoreAarch64, '--volumename', install4jmacOSArchiveAarch64Name, '--backgroundfile', install4j_dmg_background_filename, '--dmg', install4jmacOSArchiveAarch64DMGFilename + ".dmg" ]
2866 if (file(install4jDMGDSStoreJSON).exists()) {
2867 command_args += [ '--config', install4jDMGDSStoreJSON ]
2869 command = command_args
2872 for (int i = 0; i < command_args.size(); i++) {
2873 def arg = command_args[i]
2874 print_args += (i > 0 && !arg.startsWith("-")) ? "\"${arg}\"" : arg
2876 println("Running command '${print_args.join(' ')}'")
2880 task install4jCustomiseDS_Store {
2881 dependsOn install4jCustomiseDS_StoreX64
2882 dependsOn install4jCustomiseDS_StoreAarch64
2885 task install4jDMGProcesses {
2886 dependsOn install4jDMGBackgroundImageProcess
2887 dependsOn install4jCustomiseDS_Store
2890 task installerFiles(type: com.install4j.gradle.Install4jTask) {
2891 group = "distribution"
2892 description = "Create the install4j installers"
2894 dependsOn copyInstall4jTemplate
2895 dependsOn cleanInstallersDataFiles
2896 dependsOn install4jDMGProcesses
2898 projectFile = install4jConfFile
2900 // run install4j with 4g
2901 vmParameters = ["-Xmx4294967296"]
2903 // create an md5 for the input files to use as version for install4j conf file
2904 def digest = MessageDigest.getInstance("MD5")
2906 (file("${install4jDir}/${install4j_template}").text +
2907 file("${install4jDir}/${install4j_info_plist_file_associations}").text +
2908 file("${install4jDir}/${install4j_installer_file_associations}").text).bytes)
2909 def filesMd5 = new BigInteger(1, digest.digest()).toString(16)
2910 if (filesMd5.length() >= 8) {
2911 filesMd5 = filesMd5.substring(0,8)
2913 def install4jTemplateVersion = "${JALVIEW_VERSION}_F${filesMd5}_C${gitHash}"
2916 'JALVIEW_NAME': jalview_name,
2917 'JALVIEW_APPLICATION_NAME': applicationName,
2918 'JALVIEW_DIR': "../..",
2919 'OSX_KEYSTORE': OSX_KEYSTORE,
2920 'OSX_APPLEID': OSX_APPLEID,
2921 'OSX_ALTOOLPASS': OSX_ALTOOLPASS,
2922 'JSIGN_SH': JSIGN_SH,
2923 'JRE_DIR': getdown_app_dir_java,
2924 'INSTALLER_TEMPLATE_VERSION': install4jTemplateVersion,
2925 'JALVIEW_VERSION': JALVIEW_VERSION,
2926 'JAVA_MIN_VERSION': JAVA_MIN_VERSION,
2927 'JAVA_MAX_VERSION': JAVA_MAX_VERSION,
2928 'JAVA_VERSION': JAVA_VERSION,
2929 'JAVA_INTEGER_VERSION': JAVA_INTEGER_VERSION,
2930 'VERSION': JALVIEW_VERSION,
2931 'COPYRIGHT_MESSAGE': install4j_copyright_message,
2932 'BUNDLE_ID': install4jBundleId,
2933 'INTERNAL_ID': install4jInternalId,
2934 'WINDOWS_APPLICATION_ID': install4jWinApplicationId,
2935 'MACOS_X64_DMG_DS_STORE': install4jDMGFixedDSStoreX64,
2936 'MACOS_AARCH64_DMG_DS_STORE': install4jDMGFixedDSStoreAarch64,
2937 'MACOS_DMG_BG_IMAGE': "${install4jDMGBackgroundImageBuildDir}/${install4jDMGBackgroundImageFile}",
2938 'MACOS_DMG_BG_FILENAME': install4j_dmg_background_filename,
2939 'WRAPPER_LINK': getdownWrapperLink,
2940 'BASH_WRAPPER_SCRIPT': getdown_bash_wrapper_script,
2941 'POWERSHELL_WRAPPER_SCRIPT': getdown_powershell_wrapper_script,
2942 'BATCH_WRAPPER_SCRIPT': getdown_batch_wrapper_script,
2943 'WRAPPER_SCRIPT_BIN_DIR': getdown_wrapper_script_dir,
2944 'MACOSARCHIVE_X64_NAME': install4jmacOSArchiveX64Name,
2945 'MACOSARCHIVE_AARCH64_NAME': install4jmacOSArchiveAarch64Name,
2946 'INSTALL4J_UTILS_DIR': install4j_utils_dir,
2947 'GETDOWN_CHANNEL_DIR': getdownChannelDir,
2948 'GETDOWN_FILES_DIR': getdown_files_dir,
2949 'GETDOWN_RESOURCE_DIR': getdown_resource_dir,
2950 'GETDOWN_DIST_DIR': getdownAppDistDir,
2951 'GETDOWN_ALT_DIR': getdown_app_dir_alt,
2952 'GETDOWN_INSTALL_DIR': getdown_install_dir,
2953 'INFO_PLIST_FILE_ASSOCIATIONS_FILE': install4j_info_plist_file_associations,
2954 'BUILD_DIR': install4jBuildDir,
2955 'APPLICATION_CATEGORIES': install4j_application_categories,
2956 'APPLICATION_FOLDER': install4jApplicationFolder,
2957 'UNIX_APPLICATION_FOLDER': install4jUnixApplicationFolder,
2958 'EXECUTABLE_NAME': install4jExecutableName,
2959 'EXTRA_SCHEME': install4jExtraScheme,
2960 'MAC_ICONS_FILE': install4jMacIconsFile,
2961 'WINDOWS_ICONS_FILE': install4jWindowsIconsFile,
2962 'PNG_ICON_FILE': install4jPngIconFile,
2963 'BACKGROUND': install4jBackground,
2964 'MACOSARCHIVE_X64_DMG_FILENAME': install4jmacOSArchiveX64DMGFilename,
2965 'MACOSARCHIVE_AARCH64_DMG_FILENAME': install4jmacOSArchiveAarch64DMGFilename,
2970 'windows': 'WINDOWS',
2974 // these are the bundled OS/architecture VMs needed by install4j
2977 [ "mac", "aarch64" ],
2978 [ "windows", "x64" ],
2980 [ "linux", "aarch64" ]
2982 osArch.forEach { os, arch ->
2983 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)
2984 // N.B. For some reason install4j requires the below filename to have underscores and not hyphens
2985 // otherwise running `gradle installers` generates a non-useful error:
2986 // `install4j: compilation failed. Reason: java.lang.NumberFormatException: For input string: "windows"`
2987 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)
2990 //println("INSTALL4J VARIABLES:")
2991 //variables.each{k,v->println("${k}=${v}")}
2993 destination = "${jalviewDir}/${install4jBuildDir}"
2994 buildSelected = true
2996 if (install4j_faster.equals("true") || CHANNEL.startsWith("LOCAL")) {
2998 disableSigning = true
2999 disableNotarization = true
3003 macKeystorePassword = OSX_KEYPASS
3006 if (OSX_ALTOOLPASS) {
3007 appleIdPassword = OSX_ALTOOLPASS
3008 disableNotarization = false
3010 disableNotarization = true
3014 println("Using projectFile "+projectFile)
3015 if (!disableNotarization) { println("Will notarize OSX App DMG") }
3019 inputs.dir(getdownAppBaseDir)
3020 inputs.file(install4jConfFile)
3021 inputs.file("${install4jDir}/${install4j_info_plist_file_associations}")
3022 outputs.dir("${jalviewDir}/${install4j_build_dir}/${JAVA_VERSION}")
3025 def getDataHash(File myFile) {
3026 HashCode hash = Files.asByteSource(myFile).hash(Hashing.sha256())
3027 return myFile.exists()
3029 "file" : myFile.getName(),
3030 "filesize" : myFile.length(),
3031 "sha256" : hash.toString()
3036 def writeDataJsonFile(File installersOutputTxt, File installersSha256, File dataJsonFile) {
3038 "channel" : getdownChannelName,
3039 "date" : getDate("yyyy-MM-dd HH:mm:ss"),
3040 "git-commit" : "${gitHash} [${gitBranch}]",
3041 "version" : JALVIEW_VERSION
3043 // install4j installer files
3044 if (installersOutputTxt.exists()) {
3046 installersOutputTxt.readLines().each { def line ->
3047 if (line.startsWith("#")) {
3050 line.replaceAll("\n","")
3051 def vals = line.split("\t")
3052 def filename = vals[3]
3053 def filesize = file(filename).length()
3054 filename = filename.replaceAll(/^.*\//, "")
3055 hash[vals[0]] = [ "id" : vals[0], "os" : vals[1], "name" : vals[2], "file" : filename, "filesize" : filesize ]
3056 idHash."${filename}" = vals[0]
3058 if (install4jCheckSums && installersSha256.exists()) {
3059 installersSha256.readLines().each { def line ->
3060 if (line.startsWith("#")) {
3063 line.replaceAll("\n","")
3064 def vals = line.split(/\s+\*?/)
3065 def filename = vals[1]
3066 def innerHash = (hash.(idHash."${filename}"))."sha256" = vals[0]
3072 "JAR": shadowJar.archiveFile, // executable JAR
3073 "JVL": getdownVersionLaunchJvl, // version JVL
3074 "SOURCE": sourceDist.archiveFile // source TGZ
3075 ].each { key, value ->
3076 def file = file(value)
3077 if (file.exists()) {
3078 def fileHash = getDataHash(file)
3079 if (fileHash != null) {
3080 hash."${key}" = fileHash;
3084 return dataJsonFile.write(new JsonBuilder(hash).toPrettyString())
3087 task staticMakeInstallersJsonFile {
3089 def output = findProperty("i4j_output")
3090 def sha256 = findProperty("i4j_sha256")
3091 def json = findProperty("i4j_json")
3092 if (output == null || sha256 == null || json == null) {
3093 throw new GradleException("Must provide paths to all of output.txt, sha256sums, and output.json with '-Pi4j_output=... -Pi4j_sha256=... -Pi4j_json=...")
3095 writeDataJsonFile(file(output), file(sha256), file(json))
3100 dependsOn installerFiles
3106 eclipse().configFile(eclipse_codestyle_file)
3110 task createSourceReleaseProperties(type: WriteProperties) {
3111 group = "distribution"
3112 description = "Create the source RELEASE properties file"
3114 def sourceTarBuildDir = "${buildDir}/sourceTar"
3115 def sourceReleasePropertiesFile = "${sourceTarBuildDir}/RELEASE"
3116 outputFile (sourceReleasePropertiesFile)
3119 releaseProps.each{ key, val -> property key, val }
3120 property "git.branch", gitBranch
3121 property "git.hash", gitHash
3124 outputs.file(outputFile)
3127 task sourceDist(type: Tar) {
3128 group "distribution"
3129 description "Create a source .tar.gz file for distribution"
3131 dependsOn createBuildProperties
3132 dependsOn convertMdFiles
3133 dependsOn eclipseAllPreferences
3134 dependsOn createSourceReleaseProperties
3137 def outputFileName = "${project.name}_${JALVIEW_VERSION_UNDERSCORES}.tar.gz"
3138 archiveFileName = outputFileName
3140 compression Compression.GZIP
3156 "**/*.class","$j11modDir/**/*.jar","appletlib","**/*locales",
3158 "utils/InstallAnywhere",
3173 "gradle.properties",
3185 ".settings/org.eclipse.buildship.core.prefs",
3186 ".settings/org.eclipse.jdt.core.prefs"
3190 exclude (EXCLUDE_FILES)
3191 include (PROCESS_FILES)
3192 filter(ReplaceTokens,
3196 'Version-Rel': JALVIEW_VERSION,
3197 'Year-Rel': getDate("yyyy")
3202 exclude (EXCLUDE_FILES)
3203 exclude (PROCESS_FILES)
3204 exclude ("appletlib")
3205 exclude ("**/*locales")
3206 exclude ("*locales/**")
3207 exclude ("utils/InstallAnywhere")
3209 exclude (getdown_files_dir)
3210 // getdown_website_dir and getdown_archive_dir moved to build/website/docroot/getdown
3211 //exclude (getdown_website_dir)
3212 //exclude (getdown_archive_dir)
3214 // exluding these as not using jars as modules yet
3215 exclude ("${j11modDir}/**/*.jar")
3218 include(INCLUDE_FILES)
3220 // from (jalviewDir) {
3221 // // explicit includes for stuff that seemed to not get included
3222 // include(fileTree("test/**/*."))
3223 // exclude(EXCLUDE_FILES)
3224 // exclude(PROCESS_FILES)
3227 from(file(buildProperties).getParent()) {
3228 include(file(buildProperties).getName())
3229 rename(file(buildProperties).getName(), "build_properties")
3231 line.replaceAll("^INSTALLATION=.*\$","INSTALLATION=Source Release"+" git-commit\\\\:"+gitHash+" ["+gitBranch+"]")
3235 def sourceTarBuildDir = "${buildDir}/sourceTar"
3236 from(sourceTarBuildDir) {
3237 // this includes the appended RELEASE properties file
3241 task dataInstallersJson {
3243 description "Create the installers-VERSION.json data file for installer files created"
3245 mustRunAfter installers
3246 mustRunAfter shadowJar
3247 mustRunAfter sourceDist
3248 mustRunAfter getdownArchive
3250 def installersOutputTxt = file("${jalviewDir}/${install4jBuildDir}/output.txt")
3251 def installersSha256 = file("${jalviewDir}/${install4jBuildDir}/sha256sums")
3253 if (installersOutputTxt.exists()) {
3254 inputs.file(installersOutputTxt)
3256 if (install4jCheckSums && installersSha256.exists()) {
3257 inputs.file(installersSha256)
3260 shadowJar.archiveFile, // executable JAR
3261 getdownVersionLaunchJvl, // version JVL
3262 sourceDist.archiveFile // source TGZ
3263 ].each { fileName ->
3264 if (file(fileName).exists()) {
3265 inputs.file(fileName)
3269 outputs.file(hugoDataJsonFile)
3272 writeDataJsonFile(installersOutputTxt, installersSha256, hugoDataJsonFile)
3278 description "Copies all help pages to build dir. Runs ant task 'pubhtmlhelp'."
3281 dependsOn pubhtmlhelp
3283 inputs.dir("${helpBuildDir}/${help_dir}")
3284 outputs.dir("${buildDir}/distributions/${help_dir}")
3288 task j2sSetHeadlessBuild {
3295 task jalviewjsEnableAltFileProperty(type: WriteProperties) {
3297 description "Enable the alternative J2S Config file for headless build"
3299 outputFile = jalviewjsJ2sSettingsFileName
3300 def j2sPropsFile = file(jalviewjsJ2sSettingsFileName)
3301 def j2sProps = new Properties()
3302 if (j2sPropsFile.exists()) {
3304 def j2sPropsFileFIS = new FileInputStream(j2sPropsFile)
3305 j2sProps.load(j2sPropsFileFIS)
3306 j2sPropsFileFIS.close()
3308 j2sProps.each { prop, val ->
3311 } catch (Exception e) {
3312 println("Exception reading ${jalviewjsJ2sSettingsFileName}")
3316 if (! j2sProps.stringPropertyNames().contains(jalviewjs_j2s_alt_file_property_config)) {
3317 property(jalviewjs_j2s_alt_file_property_config, jalviewjs_j2s_alt_file_property)
3322 task jalviewjsSetEclipseWorkspace {
3323 def propKey = "jalviewjs_eclipse_workspace"
3325 if (project.hasProperty(propKey)) {
3326 propVal = project.getProperty(propKey)
3327 if (propVal.startsWith("~/")) {
3328 propVal = System.getProperty("user.home") + propVal.substring(1)
3331 def propsFileName = "${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_eclipse_workspace_location_file}"
3332 def propsFile = file(propsFileName)
3333 def eclipseWsDir = propVal
3334 def props = new Properties()
3336 def writeProps = true
3337 if (( eclipseWsDir == null || !file(eclipseWsDir).exists() ) && propsFile.exists()) {
3338 def ins = new FileInputStream(propsFileName)
3341 if (props.getProperty(propKey, null) != null) {
3342 eclipseWsDir = props.getProperty(propKey)
3347 if (eclipseWsDir == null || !file(eclipseWsDir).exists()) {
3348 def tempDir = File.createTempDir()
3349 eclipseWsDir = tempDir.getAbsolutePath()
3352 eclipseWorkspace = file(eclipseWsDir)
3355 // do not run a headless transpile when we claim to be in Eclipse
3357 println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3358 throw new StopExecutionException("Not running headless transpile whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
3360 println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3364 props.setProperty(propKey, eclipseWsDir)
3365 propsFile.parentFile.mkdirs()
3366 def bytes = new ByteArrayOutputStream()
3367 props.store(bytes, null)
3368 def propertiesString = bytes.toString()
3369 propsFile.text = propertiesString
3375 println("ECLIPSE WORKSPACE: "+eclipseWorkspace.getPath())
3378 //inputs.property(propKey, eclipseWsDir) // eclipseWsDir only gets set once this task runs, so will be out-of-date
3379 outputs.file(propsFileName)
3380 outputs.upToDateWhen { eclipseWorkspace.exists() && propsFile.exists() }
3384 task jalviewjsEclipsePaths {
3387 def eclipseRoot = jalviewjs_eclipse_root
3388 if (eclipseRoot.startsWith("~/")) {
3389 eclipseRoot = System.getProperty("user.home") + eclipseRoot.substring(1)
3391 if (OperatingSystem.current().isMacOsX()) {
3392 eclipseRoot += "/Eclipse.app"
3393 eclipseBinary = "${eclipseRoot}/Contents/MacOS/eclipse"
3394 eclipseProduct = "${eclipseRoot}/Contents/Eclipse/.eclipseproduct"
3395 } else if (OperatingSystem.current().isWindows()) { // check these paths!!
3396 if (file("${eclipseRoot}/eclipse").isDirectory() && file("${eclipseRoot}/eclipse/.eclipseproduct").exists()) {
3397 eclipseRoot += "/eclipse"
3399 eclipseBinary = "${eclipseRoot}/eclipse.exe"
3400 eclipseProduct = "${eclipseRoot}/.eclipseproduct"
3401 } else { // linux or unix
3402 if (file("${eclipseRoot}/eclipse").isDirectory() && file("${eclipseRoot}/eclipse/.eclipseproduct").exists()) {
3403 eclipseRoot += "/eclipse"
3404 println("eclipseDir exists")
3406 eclipseBinary = "${eclipseRoot}/eclipse"
3407 eclipseProduct = "${eclipseRoot}/.eclipseproduct"
3410 eclipseVersion = "4.13" // default
3411 def assumedVersion = true
3412 if (file(eclipseProduct).exists()) {
3413 def fis = new FileInputStream(eclipseProduct)
3414 def props = new Properties()
3416 eclipseVersion = props.getProperty("version")
3418 assumedVersion = false
3421 def propKey = "eclipse_debug"
3422 eclipseDebug = (project.hasProperty(propKey) && project.getProperty(propKey).equals("true"))
3425 // do not run a headless transpile when we claim to be in Eclipse
3427 println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3428 throw new StopExecutionException("Not running headless transpile whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
3430 println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3433 if (!assumedVersion) {
3434 println("ECLIPSE VERSION=${eclipseVersion}")
3440 task printProperties {
3442 description "Output to console all System.properties"
3444 System.properties.each { key, val -> System.out.println("Property: ${key}=${val}") }
3450 dependsOn eclipseProject
3451 dependsOn eclipseClasspath
3452 dependsOn eclipseJdt
3456 // this version (type: Copy) will delete anything in the eclipse dropins folder that isn't in fromDropinsDir
3457 task jalviewjsEclipseCopyDropins(type: Copy) {
3458 dependsOn jalviewjsEclipsePaths
3460 def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjs_eclipse_dropins_dir}", include: "*.jar")
3461 inputFiles += file("${jalviewDir}/${jalviewjsJ2sPlugin}")
3462 def outputDir = "${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_eclipse_tmp_dropins_dir}"
3469 // this eclipse -clean doesn't actually work
3470 task jalviewjsCleanEclipse(type: Exec) {
3471 dependsOn eclipseSetup
3472 dependsOn jalviewjsEclipsePaths
3473 dependsOn jalviewjsEclipseCopyDropins
3475 executable(eclipseBinary)
3476 args(["-nosplash", "--launcher.suppressErrors", "-data", eclipseWorkspace.getPath(), "-clean", "-console", "-consoleLog"])
3482 def inputString = """exit
3485 def inputByteStream = new ByteArrayInputStream(inputString.getBytes())
3486 standardInput = inputByteStream
3489 /* not really working yet
3490 jalviewjsEclipseCopyDropins.finalizedBy jalviewjsCleanEclipse
3494 task jalviewjsTransferUnzipSwingJs {
3495 def file_zip = "${jalviewDir}/${jalviewjs_swingjs_zip}"
3499 from zipTree(file_zip)
3500 into "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}"
3504 inputs.file file_zip
3505 outputs.dir "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}"
3509 task jalviewjsTransferUnzipLib {
3510 def zipFiles = fileTree(dir: "${jalviewDir}/${jalviewjs_libjs_dir}", include: "*.zip")
3513 zipFiles.each { file_zip ->
3515 from zipTree(file_zip)
3516 into "${jalviewDir}/${jalviewjsTransferSiteLibDir}"
3521 inputs.files zipFiles
3522 outputs.dir "${jalviewDir}/${jalviewjsTransferSiteLibDir}"
3526 task jalviewjsTransferUnzipAllLibs {
3527 dependsOn jalviewjsTransferUnzipSwingJs
3528 dependsOn jalviewjsTransferUnzipLib
3532 task jalviewjsCreateJ2sSettings(type: WriteProperties) {
3534 description "Create the alternative j2s file from the j2s.* properties"
3536 jalviewjsJ2sProps = project.properties.findAll { it.key.startsWith("j2s.") }.sort { it.key }
3537 def siteDirProperty = "j2s.site.directory"
3538 def setSiteDir = false
3539 jalviewjsJ2sProps.each { prop, val ->
3541 if (prop == siteDirProperty) {
3542 if (!(val.startsWith('/') || val.startsWith("file://") )) {
3543 val = "${jalviewDir}/${jalviewjsTransferSiteJsDir}/${val}"
3549 if (!setSiteDir) { // default site location, don't override specifically set property
3550 property(siteDirProperty,"${jalviewDirRelativePath}/${jalviewjsTransferSiteJsDir}")
3553 outputFile = jalviewjsJ2sAltSettingsFileName
3556 inputs.properties(jalviewjsJ2sProps)
3557 outputs.file(jalviewjsJ2sAltSettingsFileName)
3562 task jalviewjsEclipseSetup {
3563 dependsOn jalviewjsEclipseCopyDropins
3564 dependsOn jalviewjsSetEclipseWorkspace
3565 dependsOn jalviewjsCreateJ2sSettings
3569 task jalviewjsSyncAllLibs (type: Sync) {
3570 dependsOn jalviewjsTransferUnzipAllLibs
3571 def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjsTransferSiteLibDir}")
3572 inputFiles += fileTree(dir: "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}")
3573 def outputDir = "${jalviewDir}/${jalviewjsSiteDir}"
3577 def outputFiles = []
3578 rename { filename ->
3579 outputFiles += "${outputDir}/${filename}"
3586 // should this be exclude really ?
3587 duplicatesStrategy "INCLUDE"
3589 outputs.files outputFiles
3590 inputs.files inputFiles
3594 task jalviewjsSyncResources (type: Sync) {
3595 dependsOn buildResources
3597 def inputFiles = fileTree(dir: resourcesBuildDir)
3598 def outputDir = "${jalviewDir}/${jalviewjsSiteDir}/${jalviewjs_j2s_subdir}"
3602 def outputFiles = []
3603 rename { filename ->
3604 outputFiles += "${outputDir}/${filename}"
3610 outputs.files outputFiles
3611 inputs.files inputFiles
3615 task jalviewjsSyncSiteResources (type: Sync) {
3616 def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjs_site_resource_dir}")
3617 def outputDir = "${jalviewDir}/${jalviewjsSiteDir}"
3621 def outputFiles = []
3622 rename { filename ->
3623 outputFiles += "${outputDir}/${filename}"
3629 outputs.files outputFiles
3630 inputs.files inputFiles
3634 task jalviewjsSyncBuildProperties (type: Sync) {
3635 dependsOn createBuildProperties
3636 def inputFiles = [file(buildProperties)]
3637 def outputDir = "${jalviewDir}/${jalviewjsSiteDir}/${jalviewjs_j2s_subdir}"
3641 def outputFiles = []
3642 rename { filename ->
3643 outputFiles += "${outputDir}/${filename}"
3649 outputs.files outputFiles
3650 inputs.files inputFiles
3654 task jalviewjsProjectImport(type: Exec) {
3655 dependsOn eclipseSetup
3656 dependsOn jalviewjsEclipsePaths
3657 dependsOn jalviewjsEclipseSetup
3660 // do not run a headless import when we claim to be in Eclipse
3662 println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3663 throw new StopExecutionException("Not running headless import whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
3665 println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3669 //def projdir = eclipseWorkspace.getPath()+"/.metadata/.plugins/org.eclipse.core.resources/.projects/jalview/org.eclipse.jdt.core"
3670 def projdir = eclipseWorkspace.getPath()+"/.metadata/.plugins/org.eclipse.core.resources/.projects/jalview"
3671 executable(eclipseBinary)
3672 args(["-nosplash", "--launcher.suppressErrors", "-application", "com.seeq.eclipse.importprojects.headlessimport", "-data", eclipseWorkspace.getPath(), "-import", jalviewDirAbsolutePath])
3676 args += [ "--launcher.appendVmargs", "-vmargs", "-Dorg.eclipse.equinox.p2.reconciler.dropins.directory=${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_eclipse_tmp_dropins_dir}" ]
3678 args += [ "-D${j2sHeadlessBuildProperty}=true" ]
3679 args += [ "-D${jalviewjs_j2s_alt_file_property}=${jalviewjsJ2sAltSettingsFileName}" ]
3682 inputs.file("${jalviewDir}/.project")
3683 outputs.upToDateWhen {
3684 file(projdir).exists()
3689 task jalviewjsTranspile(type: Exec) {
3690 dependsOn jalviewjsEclipseSetup
3691 dependsOn jalviewjsProjectImport
3692 dependsOn jalviewjsEclipsePaths
3694 dependsOn jalviewjsEnableAltFileProperty
3698 // do not run a headless transpile when we claim to be in Eclipse
3700 println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3701 throw new StopExecutionException("Not running headless transpile whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
3703 println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3707 executable(eclipseBinary)
3708 args(["-nosplash", "--launcher.suppressErrors", "-application", "org.eclipse.jdt.apt.core.aptBuild", "-data", eclipseWorkspace, "-${jalviewjs_eclipse_build_arg}", eclipse_project_name ])
3712 args += [ "--launcher.appendVmargs", "-vmargs", "-Dorg.eclipse.equinox.p2.reconciler.dropins.directory=${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_eclipse_tmp_dropins_dir}" ]
3714 args += [ "-D${j2sHeadlessBuildProperty}=true" ]
3715 args += [ "-D${jalviewjs_j2s_alt_file_property}=${jalviewjsJ2sAltSettingsFileName}" ]
3721 stdout = new ByteArrayOutputStream()
3722 stderr = new ByteArrayOutputStream()
3724 def logOutFileName = "${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}"
3725 def logOutFile = file(logOutFileName)
3726 logOutFile.createNewFile()
3727 logOutFile.text = """ROOT: ${jalviewjs_eclipse_root}
3728 BINARY: ${eclipseBinary}
3729 VERSION: ${eclipseVersion}
3730 WORKSPACE: ${eclipseWorkspace}
3731 DEBUG: ${eclipseDebug}
3734 def logOutFOS = new FileOutputStream(logOutFile, true) // true == append
3735 // combine stdout and stderr
3736 def logErrFOS = logOutFOS
3738 if (jalviewjs_j2s_to_console.equals("true")) {
3739 standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
3740 new org.apache.tools.ant.util.TeeOutputStream(
3744 errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
3745 new org.apache.tools.ant.util.TeeOutputStream(
3750 standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
3753 errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
3760 if (stdout.toString().contains("Error processing ")) {
3761 // j2s did not complete transpile
3762 //throw new TaskExecutionException("Error during transpilation:\n${stderr}\nSee eclipse transpile log file '${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}'")
3763 if (jalviewjs_ignore_transpile_errors.equals("true")) {
3764 println("IGNORING TRANSPILE ERRORS")
3765 println("See eclipse transpile log file '${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}'")
3767 throw new GradleException("Error during transpilation:\n${stderr}\nSee eclipse transpile log file '${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}'")
3772 inputs.dir("${jalviewDir}/${sourceDir}")
3773 outputs.dir("${jalviewDir}/${jalviewjsTransferSiteJsDir}")
3774 outputs.upToDateWhen( { file("${jalviewDir}/${jalviewjsTransferSiteJsDir}${jalviewjs_server_resource}").exists() } )
3778 def jalviewjsCallCore(String name, FileCollection list, String prefixFile, String suffixFile, String jsfile, String zjsfile, File logOutFile, Boolean logOutConsole) {
3780 def stdout = new ByteArrayOutputStream()
3781 def stderr = new ByteArrayOutputStream()
3783 def coreFile = file(jsfile)
3785 msg = "Creating core for ${name}...\nGenerating ${jsfile}"
3787 logOutFile.createNewFile()
3788 logOutFile.append(msg+"\n")
3790 def coreTop = file(prefixFile)
3791 def coreBottom = file(suffixFile)
3792 coreFile.getParentFile().mkdirs()
3793 coreFile.createNewFile()
3794 coreFile.write( coreTop.getText("UTF-8") )
3798 def t = f.getText("UTF-8")
3799 t.replaceAll("Clazz\\.([^_])","Clazz_${1}")
3800 coreFile.append( t )
3802 msg = "...file '"+f.getPath()+"' does not exist, skipping"
3804 logOutFile.append(msg+"\n")
3807 coreFile.append( coreBottom.getText("UTF-8") )
3809 msg = "Generating ${zjsfile}"
3811 logOutFile.append(msg+"\n")
3812 def logOutFOS = new FileOutputStream(logOutFile, true) // true == append
3813 def logErrFOS = logOutFOS
3816 classpath = files(["${jalviewDir}/${jalviewjs_closure_compiler}"])
3817 main = "com.google.javascript.jscomp.CommandLineRunner"
3818 jvmArgs = [ "-Dfile.encoding=UTF-8" ]
3819 args = [ "--compilation_level", "SIMPLE_OPTIMIZATIONS", "--warning_level", "QUIET", "--charset", "UTF-8", "--js", jsfile, "--js_output_file", zjsfile ]
3822 msg = "\nRunning '"+commandLine.join(' ')+"'\n"
3824 logOutFile.append(msg+"\n")
3826 if (logOutConsole) {
3827 standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
3828 new org.apache.tools.ant.util.TeeOutputStream(
3832 errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
3833 new org.apache.tools.ant.util.TeeOutputStream(
3838 standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
3841 errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
3848 logOutFile.append(msg+"\n")
3852 task jalviewjsBuildAllCores {
3854 description "Build the core js lib closures listed in the classlists dir"
3855 dependsOn jalviewjsTranspile
3856 dependsOn jalviewjsTransferUnzipSwingJs
3858 def j2sDir = "${jalviewDir}/${jalviewjsTransferSiteJsDir}/${jalviewjs_j2s_subdir}"
3859 def swingJ2sDir = "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}/${jalviewjs_j2s_subdir}"
3860 def libJ2sDir = "${jalviewDir}/${jalviewjsTransferSiteLibDir}/${jalviewjs_j2s_subdir}"
3861 def jsDir = "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}/${jalviewjs_js_subdir}"
3862 def outputDir = "${jalviewDir}/${jalviewjsTransferSiteCoreDir}/${jalviewjs_j2s_subdir}/core"
3863 def prefixFile = "${jsDir}/core/coretop2.js"
3864 def suffixFile = "${jsDir}/core/corebottom2.js"
3866 inputs.file prefixFile
3867 inputs.file suffixFile
3869 def classlistFiles = []
3870 // add the classlists found int the jalviewjs_classlists_dir
3871 fileTree(dir: "${jalviewDir}/${jalviewjs_classlists_dir}", include: "*.txt").each {
3873 def name = file.getName() - ".txt"
3880 // _jmol and _jalview cores. Add any other peculiar classlist.txt files here
3881 //classlistFiles += [ 'file': file("${jalviewDir}/${jalviewjs_classlist_jmol}"), 'name': "_jvjmol" ]
3882 classlistFiles += [ 'file': file("${jalviewDir}/${jalviewjs_classlist_jalview}"), 'name': jalviewjsJalviewCoreName ]
3884 jalviewjsCoreClasslists = []
3886 classlistFiles.each {
3889 def file = hash['file']
3890 if (! file.exists()) {
3891 //println("...classlist file '"+file.getPath()+"' does not exist, skipping")
3892 return false // this is a "continue" in groovy .each closure
3894 def name = hash['name']
3896 name = file.getName() - ".txt"
3904 def list = fileTree(dir: j2sDir, includes: filelist)
3906 def jsfile = "${outputDir}/core${name}.js"
3907 def zjsfile = "${outputDir}/core${name}.z.js"
3909 jalviewjsCoreClasslists += [
3918 outputs.file(jsfile)
3919 outputs.file(zjsfile)
3922 // _stevesoft core. add any cores without a classlist here (and the inputs and outputs)
3923 def stevesoftClasslistName = "_stevesoft"
3924 def stevesoftClasslist = [
3925 'jsfile': "${outputDir}/core${stevesoftClasslistName}.js",
3926 'zjsfile': "${outputDir}/core${stevesoftClasslistName}.z.js",
3927 'list': fileTree(dir: j2sDir, include: "com/stevesoft/pat/**/*.js"),
3928 'name': stevesoftClasslistName
3930 jalviewjsCoreClasslists += stevesoftClasslist
3931 inputs.files(stevesoftClasslist['list'])
3932 outputs.file(stevesoftClasslist['jsfile'])
3933 outputs.file(stevesoftClasslist['zjsfile'])
3936 def allClasslistName = "_all"
3937 def allJsFiles = fileTree(dir: j2sDir, include: "**/*.js")
3938 allJsFiles += fileTree(
3942 // these exlusions are files that the closure-compiler produces errors for. Should fix them
3943 "**/org/jmol/jvxl/readers/IsoIntersectFileReader.js",
3944 "**/org/jmol/export/JSExporter.js"
3947 allJsFiles += fileTree(
3951 // these exlusions are files that the closure-compiler produces errors for. Should fix them
3952 "**/sun/misc/Unsafe.js",
3953 "**/swingjs/jquery/jquery-editable-select.js",
3954 "**/swingjs/jquery/j2sComboBox.js",
3955 "**/sun/misc/FloatingDecimal.js"
3958 def allClasslist = [
3959 'jsfile': "${outputDir}/core${allClasslistName}.js",
3960 'zjsfile': "${outputDir}/core${allClasslistName}.z.js",
3962 'name': allClasslistName
3964 // not including this version of "all" core at the moment
3965 //jalviewjsCoreClasslists += allClasslist
3966 inputs.files(allClasslist['list'])
3967 outputs.file(allClasslist['jsfile'])
3968 outputs.file(allClasslist['zjsfile'])
3971 def logOutFile = file("${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_j2s_closure_stdout}")
3972 logOutFile.getParentFile().mkdirs()
3973 logOutFile.createNewFile()
3974 logOutFile.write(getDate("yyyy-MM-dd HH:mm:ss")+" jalviewjsBuildAllCores\n----\n")
3976 jalviewjsCoreClasslists.each {
3977 jalviewjsCallCore(it.name, it.list, prefixFile, suffixFile, it.jsfile, it.zjsfile, logOutFile, jalviewjs_j2s_to_console.equals("true"))
3984 def jalviewjsPublishCoreTemplate(String coreName, String templateName, File inputFile, String outputFile) {
3987 into file(outputFile).getParentFile()
3988 rename { filename ->
3989 if (filename.equals(inputFile.getName())) {
3990 return file(outputFile).getName()
3994 filter(ReplaceTokens,
3998 'MAIN': '"'+main_class+'"',
4000 'NAME': jalviewjsJalviewTemplateName+" [core ${coreName}]",
4001 'COREKEY': jalviewjs_core_key,
4002 'CORENAME': coreName
4009 task jalviewjsPublishCoreTemplates {
4010 dependsOn jalviewjsBuildAllCores
4011 def inputFileName = "${jalviewDir}/${j2s_coretemplate_html}"
4012 def inputFile = file(inputFileName)
4013 def outputDir = "${jalviewDir}/${jalviewjsTransferSiteCoreDir}"
4015 def outputFiles = []
4016 jalviewjsCoreClasslists.each { cl ->
4017 def outputFile = "${outputDir}/${jalviewjsJalviewTemplateName}_${cl.name}.html"
4018 cl['outputfile'] = outputFile
4019 outputFiles += outputFile
4023 jalviewjsCoreClasslists.each { cl ->
4024 jalviewjsPublishCoreTemplate(cl.name, jalviewjsJalviewTemplateName, inputFile, cl.outputfile)
4027 inputs.file(inputFile)
4028 outputs.files(outputFiles)
4032 task jalviewjsSyncCore (type: Sync) {
4033 dependsOn jalviewjsBuildAllCores
4034 dependsOn jalviewjsPublishCoreTemplates
4035 def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjsTransferSiteCoreDir}")
4036 def outputDir = "${jalviewDir}/${jalviewjsSiteDir}"
4040 def outputFiles = []
4041 rename { filename ->
4042 outputFiles += "${outputDir}/${filename}"
4048 outputs.files outputFiles
4049 inputs.files inputFiles
4053 // this Copy version of TransferSiteJs will delete anything else in the target dir
4054 task jalviewjsCopyTransferSiteJs(type: Copy) {
4055 dependsOn jalviewjsTranspile
4056 from "${jalviewDir}/${jalviewjsTransferSiteJsDir}"
4057 into "${jalviewDir}/${jalviewjsSiteDir}"
4061 // this Sync version of TransferSite is used by buildship to keep the website automatically up to date when a file changes
4062 task jalviewjsSyncTransferSiteJs(type: Sync) {
4063 from "${jalviewDir}/${jalviewjsTransferSiteJsDir}"
4065 into "${jalviewDir}/${jalviewjsSiteDir}"
4072 jalviewjsSyncAllLibs.mustRunAfter jalviewjsCopyTransferSiteJs
4073 jalviewjsSyncResources.mustRunAfter jalviewjsCopyTransferSiteJs
4074 jalviewjsSyncSiteResources.mustRunAfter jalviewjsCopyTransferSiteJs
4075 jalviewjsSyncBuildProperties.mustRunAfter jalviewjsCopyTransferSiteJs
4077 jalviewjsSyncAllLibs.mustRunAfter jalviewjsSyncTransferSiteJs
4078 jalviewjsSyncResources.mustRunAfter jalviewjsSyncTransferSiteJs
4079 jalviewjsSyncSiteResources.mustRunAfter jalviewjsSyncTransferSiteJs
4080 jalviewjsSyncBuildProperties.mustRunAfter jalviewjsSyncTransferSiteJs
4083 task jalviewjsPrepareSite {
4085 description "Prepares the website folder including unzipping files and copying resources"
4086 dependsOn jalviewjsSyncAllLibs
4087 dependsOn jalviewjsSyncResources
4088 dependsOn jalviewjsSyncSiteResources
4089 dependsOn jalviewjsSyncBuildProperties
4090 dependsOn jalviewjsSyncCore
4094 task jalviewjsBuildSite {
4096 description "Builds the whole website including transpiled code"
4097 dependsOn jalviewjsCopyTransferSiteJs
4098 dependsOn jalviewjsPrepareSite
4102 task cleanJalviewjsTransferSite {
4104 delete "${jalviewDir}/${jalviewjsTransferSiteJsDir}"
4105 delete "${jalviewDir}/${jalviewjsTransferSiteLibDir}"
4106 delete "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}"
4107 delete "${jalviewDir}/${jalviewjsTransferSiteCoreDir}"
4112 task cleanJalviewjsSite {
4113 dependsOn cleanJalviewjsTransferSite
4115 delete "${jalviewDir}/${jalviewjsSiteDir}"
4120 task jalviewjsSiteTar(type: Tar) {
4122 description "Creates a tar.gz file for the website"
4123 dependsOn jalviewjsBuildSite
4124 def outputFilename = "jalviewjs-site-${JALVIEW_VERSION}.tar.gz"
4125 archiveFileName = outputFilename
4127 compression Compression.GZIP
4129 from "${jalviewDir}/${jalviewjsSiteDir}"
4130 into jalviewjs_site_dir // this is inside the tar file
4132 inputs.dir("${jalviewDir}/${jalviewjsSiteDir}")
4136 task jalviewjsServer {
4138 def filename = "jalviewjsTest.html"
4139 description "Starts a webserver on localhost to test the website. See ${filename} to access local site on most recently used port."
4140 def htmlFile = "${jalviewDirAbsolutePath}/${filename}"
4145 def f = Class.forName("org.gradle.plugins.javascript.envjs.http.simple.SimpleHttpFileServerFactory")
4146 factory = f.newInstance()
4147 } catch (ClassNotFoundException e) {
4148 throw new GradleException("Unable to create SimpleHttpFileServerFactory")
4150 def port = Integer.valueOf(jalviewjs_server_port)
4155 while(port < start+1000 && !running) {
4157 def doc_root = new File("${jalviewDirAbsolutePath}/${jalviewjsSiteDir}")
4158 jalviewjsServer = factory.start(doc_root, port)
4160 url = jalviewjsServer.getResourceUrl(jalviewjs_server_resource)
4161 println("SERVER STARTED with document root ${doc_root}.")
4162 println("Go to "+url+" . Run gradle --stop to stop (kills all gradle daemons).")
4163 println("For debug: "+url+"?j2sdebug")
4164 println("For verbose: "+url+"?j2sverbose")
4165 } catch (Exception e) {
4170 <p><a href="${url}">JalviewJS Test. <${url}></a></p>
4171 <p><a href="${url}?j2sdebug">JalviewJS Test with debug. <${url}?j2sdebug></a></p>
4172 <p><a href="${url}?j2sverbose">JalviewJS Test with verbose. <${url}?j2sdebug></a></p>
4174 jalviewjsCoreClasslists.each { cl ->
4175 def urlcore = jalviewjsServer.getResourceUrl(file(cl.outputfile).getName())
4177 <p><a href="${urlcore}">${jalviewjsJalviewTemplateName} [core ${cl.name}]. <${urlcore}></a></p>
4179 println("For core ${cl.name}: "+urlcore)
4182 file(htmlFile).text = htmlText
4185 outputs.file(htmlFile)
4186 outputs.upToDateWhen({false})
4190 task cleanJalviewjsAll {
4192 description "Delete all configuration and build artifacts to do with JalviewJS build"
4193 dependsOn cleanJalviewjsSite
4194 dependsOn jalviewjsEclipsePaths
4197 delete "${jalviewDir}/${jalviewjsBuildDir}"
4198 delete "${jalviewDir}/${eclipse_bin_dir}"
4199 if (eclipseWorkspace != null && file(eclipseWorkspace.getAbsolutePath()+"/.metadata").exists()) {
4200 delete file(eclipseWorkspace.getAbsolutePath()+"/.metadata")
4202 delete jalviewjsJ2sAltSettingsFileName
4205 outputs.upToDateWhen( { false } )
4209 task jalviewjsIDE_checkJ2sPlugin {
4210 group "00 JalviewJS in Eclipse"
4211 description "Compare the swingjs/net.sf.j2s.core(-j11)?.jar file with the Eclipse IDE's plugin version (found in the 'dropins' dir)"
4214 def j2sPlugin = string("${jalviewDir}/${jalviewjsJ2sPlugin}")
4215 def j2sPluginFile = file(j2sPlugin)
4216 def eclipseHome = System.properties["eclipse.home.location"]
4217 if (eclipseHome == null || ! IN_ECLIPSE) {
4218 throw new StopExecutionException("Cannot find running Eclipse home from System.properties['eclipse.home.location']. Skipping J2S Plugin Check.")
4220 def eclipseJ2sPluginDirs = [ "${eclipseHome}/dropins" ]
4221 def altPluginsDir = System.properties["org.eclipse.equinox.p2.reconciler.dropins.directory"]
4222 if (altPluginsDir != null && file(altPluginsDir).exists()) {
4223 eclipseJ2sPluginDirs += altPluginsDir
4225 def foundPlugin = false
4226 def j2sPluginFileName = j2sPluginFile.getName()
4227 def eclipseJ2sPlugin
4228 def eclipseJ2sPluginFile
4229 eclipseJ2sPluginDirs.any { dir ->
4230 eclipseJ2sPlugin = "${dir}/${j2sPluginFileName}"
4231 eclipseJ2sPluginFile = file(eclipseJ2sPlugin)
4232 if (eclipseJ2sPluginFile.exists()) {
4238 def msg = "Eclipse J2S Plugin is not installed (could not find '${j2sPluginFileName}' in\n"+eclipseJ2sPluginDirs.join("\n")+"\n)\nTry running task jalviewjsIDE_copyJ2sPlugin"
4239 System.err.println(msg)
4240 throw new StopExecutionException(msg)
4243 def digest = MessageDigest.getInstance("MD5")
4245 digest.update(j2sPluginFile.text.bytes)
4246 def j2sPluginMd5 = new BigInteger(1, digest.digest()).toString(16).padLeft(32, '0')
4248 digest.update(eclipseJ2sPluginFile.text.bytes)
4249 def eclipseJ2sPluginMd5 = new BigInteger(1, digest.digest()).toString(16).padLeft(32, '0')
4251 if (j2sPluginMd5 != eclipseJ2sPluginMd5) {
4252 def msg = "WARNING! Eclipse J2S Plugin '${eclipseJ2sPlugin}' is different to this commit's version '${j2sPlugin}'"
4253 System.err.println(msg)
4254 throw new StopExecutionException(msg)
4256 def msg = "Eclipse J2S Plugin '${eclipseJ2sPlugin}' is the same as '${j2sPlugin}' (this is good)"
4262 task jalviewjsIDE_copyJ2sPlugin {
4263 group "00 JalviewJS in Eclipse"
4264 description "Copy the swingjs/net.sf.j2s.core(-j11)?.jar file into the Eclipse IDE's 'dropins' dir"
4267 def j2sPlugin = string("${jalviewDir}/${jalviewjsJ2sPlugin}")
4268 def j2sPluginFile = file(j2sPlugin)
4269 def eclipseHome = System.properties["eclipse.home.location"]
4270 if (eclipseHome == null || ! IN_ECLIPSE) {
4271 throw new StopExecutionException("Cannot find running Eclipse home from System.properties['eclipse.home.location']. NOT copying J2S Plugin.")
4273 def eclipseJ2sPlugin = "${eclipseHome}/dropins/${j2sPluginFile.getName()}"
4274 def eclipseJ2sPluginFile = file(eclipseJ2sPlugin)
4275 def msg = "WARNING! Copying this commit's j2s plugin '${j2sPlugin}' to Eclipse J2S Plugin '${eclipseJ2sPlugin}'\n* May require an Eclipse restart"
4276 System.err.println(msg)
4279 eclipseJ2sPluginFile.getParentFile().mkdirs()
4280 into eclipseJ2sPluginFile.getParent()
4286 task jalviewjsIDE_j2sFile {
4287 group "00 JalviewJS in Eclipse"
4288 description "Creates the .j2s file"
4289 dependsOn jalviewjsCreateJ2sSettings
4293 task jalviewjsIDE_SyncCore {
4294 group "00 JalviewJS in Eclipse"
4295 description "Build the core js lib closures listed in the classlists dir and publish core html from template"
4296 dependsOn jalviewjsSyncCore
4300 task jalviewjsIDE_SyncSiteAll {
4301 dependsOn jalviewjsSyncAllLibs
4302 dependsOn jalviewjsSyncResources
4303 dependsOn jalviewjsSyncSiteResources
4304 dependsOn jalviewjsSyncBuildProperties
4308 cleanJalviewjsTransferSite.mustRunAfter jalviewjsIDE_SyncSiteAll
4311 task jalviewjsIDE_PrepareSite {
4312 group "00 JalviewJS in Eclipse"
4313 description "Sync libs and resources to site dir, but not closure cores"
4315 dependsOn jalviewjsIDE_SyncSiteAll
4316 //dependsOn cleanJalviewjsTransferSite // not sure why this clean is here -- will slow down a re-run of this task
4320 task jalviewjsIDE_AssembleSite {
4321 group "00 JalviewJS in Eclipse"
4322 description "Assembles unzipped supporting zipfiles, resources, site resources and closure cores into the Eclipse transpiled site"
4323 dependsOn jalviewjsPrepareSite
4327 task jalviewjsIDE_SiteClean {
4328 group "00 JalviewJS in Eclipse"
4329 description "Deletes the Eclipse transpiled site"
4330 dependsOn cleanJalviewjsSite
4334 task jalviewjsIDE_Server {
4335 group "00 JalviewJS in Eclipse"
4336 description "Starts a webserver on localhost to test the website"
4337 dependsOn jalviewjsServer
4341 // buildship runs this at import or gradle refresh
4342 task eclipseSynchronizationTask {
4343 //dependsOn eclipseSetup
4344 dependsOn createBuildProperties
4346 dependsOn jalviewjsIDE_j2sFile
4347 dependsOn jalviewjsIDE_checkJ2sPlugin
4348 dependsOn jalviewjsIDE_PrepareSite
4353 // buildship runs this at build time or project refresh
4354 task eclipseAutoBuildTask {
4355 //dependsOn jalviewjsIDE_checkJ2sPlugin
4356 //dependsOn jalviewjsIDE_PrepareSite
4360 task jalviewjsCopyStderrLaunchFile(type: Copy) {
4361 from file(jalviewjs_stderr_launch)
4362 into jalviewjsSiteDir
4364 inputs.file jalviewjs_stderr_launch
4365 outputs.file jalviewjsStderrLaunchFilename
4368 task cleanJalviewjsChromiumUserDir {
4370 delete jalviewjsChromiumUserDir
4372 outputs.dir jalviewjsChromiumUserDir
4373 // always run when depended on
4374 outputs.upToDateWhen { !file(jalviewjsChromiumUserDir).exists() }
4377 task jalviewjsChromiumProfile {
4378 dependsOn cleanJalviewjsChromiumUserDir
4379 mustRunAfter cleanJalviewjsChromiumUserDir
4381 def firstRun = file("${jalviewjsChromiumUserDir}/First Run")
4384 mkdir jalviewjsChromiumProfileDir
4387 outputs.file firstRun
4390 task jalviewjsLaunchTest {
4392 description "Check JalviewJS opens in a browser"
4393 dependsOn jalviewjsBuildSite
4394 dependsOn jalviewjsCopyStderrLaunchFile
4395 dependsOn jalviewjsChromiumProfile
4397 def macOS = OperatingSystem.current().isMacOsX()
4398 def chromiumBinary = macOS ? jalviewjs_macos_chromium_binary : jalviewjs_chromium_binary
4399 if (chromiumBinary.startsWith("~/")) {
4400 chromiumBinary = System.getProperty("user.home") + chromiumBinary.substring(1)
4406 def timeoutms = Integer.valueOf(jalviewjs_chromium_overall_timeout) * 1000
4408 def binary = file(chromiumBinary)
4409 if (!binary.exists()) {
4410 throw new StopExecutionException("Could not find chromium binary '${chromiumBinary}'. Cannot run task ${name}.")
4412 stdout = new ByteArrayOutputStream()
4413 stderr = new ByteArrayOutputStream()
4416 if (jalviewjs_j2s_to_console.equals("true")) {
4417 execStdout = new org.apache.tools.ant.util.TeeOutputStream(
4420 execStderr = new org.apache.tools.ant.util.TeeOutputStream(
4428 "--no-sandbox", // --no-sandbox IS USED BY THE THORIUM APPIMAGE ON THE BUILDSERVER
4431 "--timeout=${timeoutms}",
4432 "--virtual-time-budget=${timeoutms}",
4433 "--user-data-dir=${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_chromium_user_dir}",
4434 "--profile-directory=${jalviewjs_chromium_profile_name}",
4435 "--allow-file-access-from-files",
4436 "--enable-logging=stderr",
4437 "file://${jalviewDirAbsolutePath}/${jalviewjsStderrLaunchFilename}"
4440 if (true || macOS) {
4441 ScheduledExecutorService executor = Executors.newScheduledThreadPool(3);
4442 Future f1 = executor.submit(
4445 standardOutput = execStdout
4446 errorOutput = execStderr
4447 executable(chromiumBinary)
4449 println "COMMAND: '"+commandLine.join(" ")+"'"
4451 executor.shutdownNow()
4455 def noChangeBytes = 0
4456 def noChangeIterations = 0
4457 executor.scheduleAtFixedRate(
4459 String stderrString = stderr.toString()
4460 // shutdown the task if we have a success string
4461 if (stderrString.contains(jalviewjs_desktop_init_string)) {
4464 executor.shutdownNow()
4466 // if no change in stderr for 10s then also end
4467 if (noChangeIterations >= jalviewjs_chromium_idle_timeout) {
4468 executor.shutdownNow()
4470 if (stderrString.length() == noChangeBytes) {
4471 noChangeIterations++
4473 noChangeBytes = stderrString.length()
4474 noChangeIterations = 0
4477 1, 1, TimeUnit.SECONDS)
4479 executor.schedule(new Runnable(){
4482 executor.shutdownNow()
4484 }, timeoutms, TimeUnit.MILLISECONDS)
4486 executor.awaitTermination(timeoutms+10000, TimeUnit.MILLISECONDS)
4487 executor.shutdownNow()
4494 stderr.toString().eachLine { line ->
4495 if (line.contains(jalviewjs_desktop_init_string)) {
4496 println("Found line '"+line+"'")
4502 throw new GradleException("Could not find evidence of Desktop launch in JalviewJS.")
4510 description "Build the JalviewJS site and run the launch test"
4511 dependsOn jalviewjsBuildSite
4512 dependsOn jalviewjsLaunchTest