1 /* Convention for properties. Read from gradle.properties, use lower_case_underlines for property names.
2 * For properties set within build.gradle, use camelCaseNoSpace.
4 import org.apache.tools.ant.filters.ReplaceTokens
5 import org.gradle.internal.os.OperatingSystem
6 import org.gradle.plugins.ide.internal.generator.PropertiesPersistableConfigurationObject
7 import org.gradle.api.internal.PropertiesTransformer
8 import org.gradle.util.ConfigureUtil
9 import org.gradle.plugins.ide.eclipse.model.Output
10 import org.gradle.plugins.ide.eclipse.model.Library
11 import java.security.MessageDigest
12 import java.util.regex.Matcher
13 import java.util.concurrent.Executors
14 import java.util.concurrent.Future
15 import java.util.concurrent.ScheduledExecutorService
16 import java.util.concurrent.TimeUnit
17 import groovy.transform.ExternalizeMethods
18 import groovy.util.XmlParser
19 import groovy.xml.XmlUtil
20 import groovy.json.JsonBuilder
21 import com.vladsch.flexmark.util.ast.Node
22 import com.vladsch.flexmark.html.HtmlRenderer
23 import com.vladsch.flexmark.parser.Parser
24 import com.vladsch.flexmark.util.data.MutableDataSet
25 import com.vladsch.flexmark.ext.gfm.tasklist.TaskListExtension
26 import com.vladsch.flexmark.ext.tables.TablesExtension
27 import com.vladsch.flexmark.ext.gfm.strikethrough.StrikethroughExtension
28 import com.vladsch.flexmark.ext.autolink.AutolinkExtension
29 import com.vladsch.flexmark.ext.anchorlink.AnchorLinkExtension
30 import com.vladsch.flexmark.ext.toc.TocExtension
31 import com.google.common.hash.HashCode
32 import com.google.common.hash.Hashing
33 import com.google.common.io.Files
34 import org.jsoup.Jsoup
35 import org.jsoup.nodes.Element
43 classpath "com.vladsch.flexmark:flexmark-all:0.62.0"
44 classpath "org.jsoup:jsoup:1.14.3"
45 classpath "com.eowise:gradle-imagemagick:0.5.1"
54 id "com.diffplug.spotless" version "6.18.0" //.gradle.spotless" "3.28.0"
55 id 'com.github.johnrengelman.shadow' version '8.1.1' // was 4.0.3
56 id 'com.install4j.gradle' version '10.0.3'
57 id 'com.dorongold.task-tree' version '2.1.1' // only needed to display task dependency tree with gradle task1 [task2 ...] taskTree
58 id 'com.palantir.git-version' version '0.13.0' apply false
69 // in ext the values are cast to Object. Ensure string values are cast as String (and not GStringImpl) for later use
70 def string(Object o) {
71 return o == null ? "" : o.toString()
74 def overrideProperties(String propsFileName, boolean output = false) {
75 if (propsFileName == null) {
78 def propsFile = file(propsFileName)
79 if (propsFile != null && propsFile.exists()) {
80 println("Using properties from file '${propsFileName}'")
82 def p = new Properties()
83 def localPropsFIS = new FileInputStream(propsFile)
89 if (project.hasProperty(key)) {
90 oldval = project.findProperty(key)
91 project.setProperty(key, val)
93 println("Overriding property '${key}' ('${oldval}') with ${file(propsFile).getName()} value '${val}'")
96 ext.setProperty(key, val)
98 println("Setting ext property '${key}' with ${file(propsFile).getName()}s value '${val}'")
102 } catch (Exception e) {
103 println("Exception reading local.properties")
110 jalviewDirAbsolutePath = file(jalviewDir).getAbsolutePath()
111 jalviewDirRelativePath = jalviewDir
114 getdownChannelName = CHANNEL.toLowerCase()
115 // default to "default". Currently only has different cosmetics for "develop", "release", "default"
116 propertiesChannelName = ["develop", "release", "test-release", "jalviewjs", "jalviewjs-release" ].contains(getdownChannelName) ? getdownChannelName : "default"
117 channelDirName = propertiesChannelName
118 // Import channel_properties
119 if (getdownChannelName.startsWith("develop-")) {
120 channelDirName = "develop-SUFFIX"
122 channelDir = string("${jalviewDir}/${channel_properties_dir}/${channelDirName}")
123 channelGradleProperties = string("${channelDir}/channel_gradle.properties")
124 channelPropsFile = string("${channelDir}/${resource_dir}/${channel_props}")
125 overrideProperties(channelGradleProperties, false)
126 // local build environment properties
127 // can be "projectDir/local.properties"
128 overrideProperties("${projectDir}/local.properties", true)
129 // or "../projectDir_local.properties"
130 overrideProperties(projectDir.getParent() + "/" + projectDir.getName() + "_local.properties", true)
133 // Import releaseProps from the RELEASE file
134 // or a file specified via JALVIEW_RELEASE_FILE if defined
135 // Expect jalview.version and target release branch in jalview.release
136 releaseProps = new Properties();
137 def releasePropFile = findProperty("JALVIEW_RELEASE_FILE");
138 def defaultReleasePropFile = "${jalviewDirAbsolutePath}/RELEASE";
140 (new File(releasePropFile!=null ? releasePropFile : defaultReleasePropFile)).withInputStream {
141 releaseProps.load(it)
143 } catch (Exception fileLoadError) {
144 throw new Error("Couldn't load release properties file "+(releasePropFile==null ? defaultReleasePropFile : "from custom location: releasePropFile"),fileLoadError);
147 // Set JALVIEW_VERSION if it is not already set
148 if (findProperty("JALVIEW_VERSION")==null || "".equals(JALVIEW_VERSION)) {
149 JALVIEW_VERSION = releaseProps.get("jalview.version")
151 println("JALVIEW_VERSION is set to '${JALVIEW_VERSION}'")
153 // this property set when running Eclipse headlessly
154 j2sHeadlessBuildProperty = string("net.sf.j2s.core.headlessbuild")
155 // this property set by Eclipse
156 eclipseApplicationProperty = string("eclipse.application")
157 // CHECK IF RUNNING FROM WITHIN ECLIPSE
158 def eclipseApplicationPropertyVal = System.properties[eclipseApplicationProperty]
159 IN_ECLIPSE = eclipseApplicationPropertyVal != null && eclipseApplicationPropertyVal.startsWith("org.eclipse.ui.")
160 // BUT WITHOUT THE HEADLESS BUILD PROPERTY SET
161 if (System.properties[j2sHeadlessBuildProperty].equals("true")) {
162 println("Setting IN_ECLIPSE to ${IN_ECLIPSE} as System.properties['${j2sHeadlessBuildProperty}'] == '${System.properties[j2sHeadlessBuildProperty]}'")
166 println("WITHIN ECLIPSE IDE")
168 println("HEADLESS BUILD")
171 J2S_ENABLED = (project.hasProperty('j2s.compiler.status') && project['j2s.compiler.status'] != null && project['j2s.compiler.status'] == "enable")
173 println("J2S ENABLED")
176 System.properties.sort { it.key }.each {
177 key, val -> println("SYSTEM PROPERTY ${key}='${val}'")
180 if (false && IN_ECLIPSE) {
181 jalviewDir = jalviewDirAbsolutePath
186 buildDate = new Date().format("yyyyMMdd")
189 bareSourceDir = string(source_dir)
190 sourceDir = string("${jalviewDir}/${bareSourceDir}")
191 resourceDir = string("${jalviewDir}/${resource_dir}")
192 bareTestSourceDir = string(test_source_dir)
193 testDir = string("${jalviewDir}/${bareTestSourceDir}")
195 classesDir = string("${jalviewDir}/${classes_dir}")
196 destinationDirectory = file(classesDir)
199 useClover = clover.equals("true")
200 cloverBuildDir = "${buildDir}/clover"
201 cloverInstrDir = file("${cloverBuildDir}/clover-instr")
202 cloverClassesDir = file("${cloverBuildDir}/clover-classes")
203 cloverReportDir = file("${buildDir}/reports/clover")
204 cloverTestInstrDir = file("${cloverBuildDir}/clover-test-instr")
205 cloverTestClassesDir = file("${cloverBuildDir}/clover-test-classes")
206 //cloverTestClassesDir = cloverClassesDir
207 cloverDb = string("${cloverBuildDir}/clover.db")
209 testSourceDir = useClover ? cloverTestInstrDir : testDir
210 testClassesDir = useClover ? cloverTestClassesDir : "${jalviewDir}/${test_output_dir}"
213 backgroundImageText = BACKGROUNDIMAGETEXT
214 getdownChannelDir = string("${getdown_website_dir}/${propertiesChannelName}")
215 getdownAppBaseDir = string("${jalviewDir}/${getdownChannelDir}/${JAVA_VERSION}")
216 getdownArchiveDir = string("${jalviewDir}/${getdown_archive_dir}")
217 getdownFullArchiveDir = null
218 getdownTextLines = []
219 getdownLaunchJvl = null
220 getdownVersionLaunchJvl = null
222 buildProperties = null
224 // the following values might be overridden by the CHANNEL switch
225 getdownDir = string("${getdownChannelName}/${JAVA_VERSION}")
226 getdownAppBase = string("${getdown_channel_base}/${getdownDir}")
227 getdownArchiveAppBase = getdown_archive_base
228 getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher}")
229 getdownAppDistDir = getdown_app_dir_alt
230 getdownImagesDir = string("${jalviewDir}/${getdown_images_dir}")
231 getdownImagesBuildDir = string("${buildDir}/imagemagick/getdown")
232 getdownSetAppBaseProperty = false // whether to pass the appbase and appdistdir to the application
233 reportRsyncCommand = false
234 jvlChannelName = CHANNEL.toLowerCase()
235 install4jSuffix = CHANNEL.substring(0, 1).toUpperCase() + CHANNEL.substring(1).toLowerCase(); // BUILD -> Build
236 install4jDMGDSStore = "${install4j_images_dir}/${install4j_dmg_ds_store}"
237 install4jDMGBackgroundImageDir = "${install4j_images_dir}"
238 install4jDMGBackgroundImageBuildDir = "build/imagemagick/install4j"
239 install4jDMGBackgroundImageFile = "${install4j_dmg_background}"
240 install4jInstallerName = "${jalview_name} Non-Release Installer"
241 install4jExecutableName = install4j_executable_name
242 install4jExtraScheme = "jalviewx"
243 install4jMacIconsFile = string("${install4j_images_dir}/${install4j_mac_icons_file}")
244 install4jWindowsIconsFile = string("${install4j_images_dir}/${install4j_windows_icons_file}")
245 install4jPngIconFile = string("${install4j_images_dir}/${install4j_png_icon_file}")
246 install4jBackground = string("${install4j_images_dir}/${install4j_background}")
247 install4jBuildDir = "${install4j_build_dir}/${JAVA_VERSION}"
248 install4jCheckSums = true
250 applicationName = "${jalview_name}"
254 // TODO: get bamboo build artifact URL for getdown artifacts
255 getdown_channel_base = bamboo_channelbase
256 getdownChannelName = string("${bamboo_planKey}/${JAVA_VERSION}")
257 getdownAppBase = string("${bamboo_channelbase}/${bamboo_planKey}${bamboo_getdown_channel_suffix}/${JAVA_VERSION}")
258 jvlChannelName += "_${getdownChannelName}"
259 // automatically add the test group Not-bamboo for exclusion
260 if ("".equals(testng_excluded_groups)) {
261 testng_excluded_groups = "Not-bamboo"
263 install4jExtraScheme = "jalviewb"
264 backgroundImageText = true
267 case [ "RELEASE", "JALVIEWJS-RELEASE" ]:
268 getdownAppDistDir = getdown_app_dir_release
269 getdownSetAppBaseProperty = true
270 reportRsyncCommand = true
272 install4jInstallerName = "${jalview_name} Installer"
276 getdownChannelName = CHANNEL.toLowerCase()+"/${JALVIEW_VERSION}"
277 getdownDir = string("${getdownChannelName}/${JAVA_VERSION}")
278 getdownAppBase = string("${getdown_channel_base}/${getdownDir}")
279 if (!file("${ARCHIVEDIR}/${package_dir}").exists()) {
280 throw new GradleException("Must provide an ARCHIVEDIR value to produce an archive distribution")
282 package_dir = string("${ARCHIVEDIR}/${package_dir}")
283 buildProperties = string("${ARCHIVEDIR}/${classes_dir}/${build_properties_file}")
286 reportRsyncCommand = true
287 install4jExtraScheme = "jalviewa"
291 getdownChannelName = string("archive/${JALVIEW_VERSION}")
292 getdownDir = string("${getdownChannelName}/${JAVA_VERSION}")
293 getdownAppBase = file(getdownAppBaseDir).toURI().toString()
294 if (!file("${ARCHIVEDIR}/${package_dir}").exists()) {
295 throw new GradleException("Must provide an ARCHIVEDIR value to produce an archive distribution [did not find '${ARCHIVEDIR}/${package_dir}']")
297 package_dir = string("${ARCHIVEDIR}/${package_dir}")
298 buildProperties = string("${ARCHIVEDIR}/${classes_dir}/${build_properties_file}")
301 reportRsyncCommand = true
302 getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher_local}")
303 install4jSuffix = "Archive"
304 install4jExtraScheme = "jalviewa"
307 case ~/^DEVELOP-([\.\-\w]*)$/:
308 def suffix = Matcher.lastMatcher[0][1]
309 reportRsyncCommand = true
310 getdownSetAppBaseProperty = true
311 JALVIEW_VERSION=JALVIEW_VERSION+"-d${suffix}-${buildDate}"
312 install4jSuffix = "Develop ${suffix}"
313 install4jExtraScheme = "jalviewd"
314 install4jInstallerName = "${jalview_name} Develop ${suffix} Installer"
315 getdownChannelName = string("develop-${suffix}")
316 getdownChannelDir = string("${getdown_website_dir}/${getdownChannelName}")
317 getdownAppBaseDir = string("${jalviewDir}/${getdownChannelDir}/${JAVA_VERSION}")
318 getdownDir = string("${getdownChannelName}/${JAVA_VERSION}")
319 getdownAppBase = string("${getdown_channel_base}/${getdownDir}")
320 channelSuffix = string(suffix)
321 backgroundImageText = true
325 reportRsyncCommand = true
326 getdownSetAppBaseProperty = true
327 // DEVELOP-RELEASE is usually associated with a Jalview release series so set the version
328 JALVIEW_VERSION=JALVIEW_VERSION+"-d${buildDate}"
330 install4jSuffix = "Develop"
331 install4jExtraScheme = "jalviewd"
332 install4jInstallerName = "${jalview_name} Develop Installer"
333 backgroundImageText = true
337 reportRsyncCommand = true
338 getdownSetAppBaseProperty = true
339 // Don't ignore transpile errors for release build
340 if (jalviewjs_ignore_transpile_errors.equals("true")) {
341 jalviewjs_ignore_transpile_errors = "false"
342 println("Setting jalviewjs_ignore_transpile_errors to 'false'")
344 JALVIEW_VERSION = JALVIEW_VERSION+"-test"
345 install4jSuffix = "Test"
346 install4jExtraScheme = "jalviewt"
347 install4jInstallerName = "${jalview_name} Test Installer"
348 backgroundImageText = true
351 case ~/^SCRATCH(|-[-\w]*)$/:
352 getdownChannelName = CHANNEL
353 JALVIEW_VERSION = JALVIEW_VERSION+"-"+CHANNEL
355 getdownDir = string("${getdownChannelName}/${JAVA_VERSION}")
356 getdownAppBase = string("${getdown_channel_base}/${getdownDir}")
357 reportRsyncCommand = true
358 install4jSuffix = "Scratch"
362 if (!file("${LOCALDIR}").exists()) {
363 throw new GradleException("Must provide a LOCALDIR value to produce a local distribution")
365 getdownAppBase = file(file("${LOCALDIR}").getAbsolutePath()).toURI().toString()
366 getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher_local}")
368 JALVIEW_VERSION = "TEST"
369 install4jSuffix = "Test-Local"
370 install4jExtraScheme = "jalviewt"
371 install4jInstallerName = "${jalview_name} Test Installer"
372 backgroundImageText = true
375 case [ "LOCAL", "JALVIEWJS" ]:
376 JALVIEW_VERSION = "TEST"
377 getdownAppBase = file(getdownAppBaseDir).toURI().toString()
378 getdownArchiveAppBase = file("${jalviewDir}/${getdown_archive_dir}").toURI().toString()
379 getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher_local}")
380 install4jExtraScheme = "jalviewl"
381 install4jCheckSums = false
384 default: // something wrong specified
385 throw new GradleException("CHANNEL must be one of BUILD, RELEASE, ARCHIVE, DEVELOP, TEST-RELEASE, SCRATCH-..., LOCAL [default]")
389 JALVIEW_VERSION_UNDERSCORES = JALVIEW_VERSION.replaceAll("\\.", "_")
390 hugoDataJsonFile = file("${jalviewDir}/${hugo_build_dir}/${hugo_data_installers_dir}/installers-${JALVIEW_VERSION_UNDERSCORES}.json")
391 hugoArchiveMdFile = file("${jalviewDir}/${hugo_build_dir}/${hugo_version_archive_dir}/Version-${JALVIEW_VERSION_UNDERSCORES}/_index.md")
392 // override getdownAppBase if requested
393 if (findProperty("getdown_appbase_override") != null) {
394 // revert to LOCAL if empty string
395 if (string(getdown_appbase_override) == "") {
396 getdownAppBase = file(getdownAppBaseDir).toURI().toString()
397 getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher_local}")
398 } else if (string(getdown_appbase_override).startsWith("file://")) {
399 getdownAppBase = string(getdown_appbase_override)
400 getdownLauncher = string("${jalviewDir}/${getdown_lib_dir}/${getdown_launcher_local}")
402 getdownAppBase = string(getdown_appbase_override)
404 println("Overriding getdown appbase with '${getdownAppBase}'")
406 // sanitise file name for jalview launcher file for this channel
407 jvlChannelName = jvlChannelName.replaceAll("[^\\w\\-]+", "_")
408 // install4j application and folder names
409 if (install4jSuffix == "") {
410 install4jBundleId = "${install4j_bundle_id}"
411 install4jWinApplicationId = install4j_release_win_application_id
413 applicationName = "${jalview_name} ${install4jSuffix}"
414 install4jBundleId = "${install4j_bundle_id}-" + install4jSuffix.toLowerCase()
415 // add int hash of install4jSuffix to the last part of the application_id
416 def id = install4j_release_win_application_id
417 def idsplitreverse = id.split("-").reverse()
418 idsplitreverse[0] = idsplitreverse[0].toInteger() + install4jSuffix.hashCode()
419 install4jWinApplicationId = idsplitreverse.reverse().join("-")
421 // sanitise folder and id names
422 // install4jApplicationFolder = e.g. "Jalview Build"
423 install4jApplicationFolder = applicationName
424 .replaceAll("[\"'~:/\\\\\\s]", "_") // replace all awkward filename chars " ' ~ : / \
425 .replaceAll("_+", "_") // collapse __
426 install4jInternalId = applicationName
428 .replaceAll("[^\\w\\-\\.]", "_") // replace other non [alphanumeric,_,-,.]
429 .replaceAll("_+", "") // collapse __
430 //.replaceAll("_*-_*", "-") // collapse _-_
431 install4jUnixApplicationFolder = applicationName
433 .replaceAll("[^\\w\\-\\.]", "_") // replace other non [alphanumeric,_,-,.]
434 .replaceAll("_+", "_") // collapse __
435 .replaceAll("_*-_*", "-") // collapse _-_
438 getdownWrapperLink = install4jUnixApplicationFolder // e.g. "jalview_local"
439 getdownAppDir = string("${getdownAppBaseDir}/${getdownAppDistDir}")
440 //getdownJ11libDir = "${getdownAppBaseDir}/${getdown_j11lib_dir}"
441 getdownResourceDir = string("${getdownAppBaseDir}/${getdown_resource_dir}")
442 getdownInstallDir = string("${getdownAppBaseDir}/${getdown_install_dir}")
443 getdownFilesDir = string("${jalviewDir}/${getdown_files_dir}/${JAVA_VERSION}/")
444 getdownFilesInstallDir = string("${getdownFilesDir}/${getdown_install_dir}")
445 /* compile without modules -- using classpath libraries
446 modules_compileClasspath = fileTree(dir: "${jalviewDir}/${j11modDir}", include: ["*.jar"])
447 modules_runtimeClasspath = modules_compileClasspath
453 apply plugin: "com.palantir.git-version"
454 def details = versionDetails()
455 gitHash = details.gitHash
456 gitBranch = details.branchName
457 } catch(org.gradle.api.internal.plugins.PluginApplicationException e) {
458 println("Not in a git repository. Using git values from RELEASE properties file.")
459 gitHash = releaseProps.getProperty("git.hash")
460 gitBranch = releaseProps.getProperty("git.branch")
461 } catch(java.lang.RuntimeException e1) {
462 throw new GradleException("Error with git-version plugin. Directory '.git' exists but versionDetails() cannot be found.")
465 println("Using a ${CHANNEL} profile.")
467 additional_compiler_args = []
468 // configure classpath/args for j8/j11 compilation
469 if (JAVA_VERSION.equals("1.8")) {
470 JAVA_INTEGER_VERSION = string("8")
473 libDistDir = j8libDir
474 compile_source_compatibility = 1.8
475 compile_target_compatibility = 1.8
476 // these are getdown.txt properties defined dependent on the JAVA_VERSION
477 getdownAltJavaMinVersion = string(findProperty("getdown_alt_java8_min_version"))
478 getdownAltJavaMaxVersion = string(findProperty("getdown_alt_java8_max_version"))
479 // this property is assigned below and expanded to multiple lines in the getdown task
480 getdownAltMultiJavaLocation = string(findProperty("getdown_alt_java8_txt_multi_java_location"))
481 // this property is for the Java library used in eclipse
482 eclipseJavaRuntimeName = string("JavaSE-1.8")
483 } else if (JAVA_VERSION.equals("11")) {
484 JAVA_INTEGER_VERSION = string("11")
486 libDistDir = j11libDir
487 compile_source_compatibility = 11
488 compile_target_compatibility = 11
489 getdownAltJavaMinVersion = string(findProperty("getdown_alt_java11_min_version"))
490 getdownAltJavaMaxVersion = string(findProperty("getdown_alt_java11_max_version"))
491 getdownAltMultiJavaLocation = string(findProperty("getdown_alt_java11_txt_multi_java_location"))
492 eclipseJavaRuntimeName = string("JavaSE-11")
493 /* compile without modules -- using classpath libraries
494 additional_compiler_args += [
495 '--module-path', modules_compileClasspath.asPath,
496 '--add-modules', j11modules
499 } else if (JAVA_VERSION.equals("17")) {
500 JAVA_INTEGER_VERSION = string("17")
502 libDistDir = j17libDir
503 compile_source_compatibility = 17
504 compile_target_compatibility = 17
505 getdownAltJavaMinVersion = string(findProperty("getdown_alt_java11_min_version"))
506 getdownAltJavaMaxVersion = string(findProperty("getdown_alt_java11_max_version"))
507 getdownAltMultiJavaLocation = string(findProperty("getdown_alt_java11_txt_multi_java_location"))
508 eclipseJavaRuntimeName = string("JavaSE-17")
509 /* compile without modules -- using classpath libraries
510 additional_compiler_args += [
511 '--module-path', modules_compileClasspath.asPath,
512 '--add-modules', j11modules
516 throw new GradleException("JAVA_VERSION=${JAVA_VERSION} not currently supported by Jalview")
521 JAVA_MIN_VERSION = JAVA_VERSION
522 JAVA_MAX_VERSION = JAVA_VERSION
523 jreInstallsDir = string(jre_installs_dir)
524 if (jreInstallsDir.startsWith("~/")) {
525 jreInstallsDir = System.getProperty("user.home") + jreInstallsDir.substring(1)
527 install4jDir = string("${jalviewDir}/${install4j_utils_dir}")
528 install4jConfFileName = string("jalview-install4j-conf.install4j")
529 install4jConfFile = file("${install4jDir}/${install4jConfFileName}")
530 install4jHomeDir = install4j_home_dir
531 if (install4jHomeDir.startsWith("~/")) {
532 install4jHomeDir = System.getProperty("user.home") + install4jHomeDir.substring(1)
535 resourceBuildDir = string("${buildDir}/resources")
536 resourcesBuildDir = string("${resourceBuildDir}/resources_build")
537 helpBuildDir = string("${resourceBuildDir}/help_build")
538 docBuildDir = string("${resourceBuildDir}/doc_build")
540 if (buildProperties == null) {
541 buildProperties = string("${resourcesBuildDir}/${build_properties_file}")
543 buildingHTML = string("${jalviewDir}/${doc_dir}/building.html")
544 helpParentDir = string("${jalviewDir}/${help_parent_dir}")
545 helpSourceDir = string("${helpParentDir}/${help_dir}")
546 helpFile = string("${helpBuildDir}/${help_dir}/help.jhm")
549 convertBinaryExpectedLocation = imagemagick_convert
550 if (convertBinaryExpectedLocation.startsWith("~/")) {
551 convertBinaryExpectedLocation = System.getProperty("user.home") + convertBinaryExpectedLocation.substring(1)
553 if (file(convertBinaryExpectedLocation).exists()) {
554 convertBinary = convertBinaryExpectedLocation
557 relativeBuildDir = file(jalviewDirAbsolutePath).toPath().relativize(buildDir.toPath())
558 jalviewjsBuildDir = string("${relativeBuildDir}/jalviewjs")
559 jalviewjsSiteDir = string("${jalviewjsBuildDir}/${jalviewjs_site_dir}")
561 jalviewjsTransferSiteJsDir = string(jalviewjsSiteDir)
563 jalviewjsTransferSiteJsDir = string("${jalviewjsBuildDir}/tmp/${jalviewjs_site_dir}_js")
565 jalviewjsTransferSiteLibDir = string("${jalviewjsBuildDir}/tmp/${jalviewjs_site_dir}_lib")
566 jalviewjsTransferSiteSwingJsDir = string("${jalviewjsBuildDir}/tmp/${jalviewjs_site_dir}_swingjs")
567 jalviewjsTransferSiteCoreDir = string("${jalviewjsBuildDir}/tmp/${jalviewjs_site_dir}_core")
568 jalviewjsJalviewCoreHtmlFile = string("")
569 jalviewjsJalviewCoreName = string(jalviewjs_core_name)
570 jalviewjsCoreClasslists = []
571 jalviewjsJalviewTemplateName = string(jalviewjs_name)
572 jalviewjsJ2sSettingsFileName = string("${jalviewDir}/${jalviewjs_j2s_settings}")
573 jalviewjsJ2sAltSettingsFileName = string("${jalviewDir}/${jalviewjs_j2s_alt_settings}")
574 jalviewjsJ2sProps = null
575 jalviewjsJ2sPlugin = jalviewjs_j2s_plugin
576 jalviewjsStderrLaunchFilename = "${jalviewjsSiteDir}/"+(file(jalviewjs_stderr_launch).getName())
578 eclipseWorkspace = null
579 eclipseBinary = string("")
580 eclipseVersion = string("")
583 jalviewjsChromiumUserDir = "${jalviewjsBuildDir}/${jalviewjs_chromium_user_dir}"
584 jalviewjsChromiumProfileDir = "${ext.jalviewjsChromiumUserDir}/${jalviewjs_chromium_profile_name}"
594 destinationDirectory = file(classesDir)
598 srcDirs = [ resourcesBuildDir, docBuildDir, helpBuildDir ]
601 compileClasspath = files(sourceSets.main.java.destinationDirectory)
602 compileClasspath += fileTree(dir: "${jalviewDir}/${libDir}", include: ["*.jar"])
604 runtimeClasspath = compileClasspath
605 runtimeClasspath += files(sourceSets.main.resources.srcDirs)
610 srcDirs cloverInstrDir
611 destinationDirectory = cloverClassesDir
615 srcDirs = sourceSets.main.resources.srcDirs
618 compileClasspath = files( sourceSets.clover.java.destinationDirectory )
619 //compileClasspath += files( testClassesDir )
620 compileClasspath += fileTree(dir: "${jalviewDir}/${libDir}", include: ["*.jar"])
621 compileClasspath += fileTree(dir: "${jalviewDir}/${clover_lib_dir}", include: ["*.jar"])
622 compileClasspath += fileTree(dir: "${jalviewDir}/${utils_dir}/testnglibs", include: ["**/*.jar"])
624 runtimeClasspath = compileClasspath
629 srcDirs testSourceDir
630 destinationDirectory = file(testClassesDir)
634 srcDirs = useClover ? sourceSets.clover.resources.srcDirs : sourceSets.main.resources.srcDirs
637 compileClasspath = files( sourceSets.test.java.destinationDirectory )
638 compileClasspath += useClover ? sourceSets.clover.compileClasspath : sourceSets.main.compileClasspath
639 compileClasspath += fileTree(dir: "${jalviewDir}/${utils_dir}/testnglibs", include: ["**/*.jar"])
641 runtimeClasspath = compileClasspath
642 runtimeClasspath += files(sourceSets.test.resources.srcDirs)
648 // eclipse project and settings files creation, also used by buildship
651 name = eclipse_project_name
653 natures 'org.eclipse.jdt.core.javanature',
654 'org.eclipse.jdt.groovy.core.groovyNature',
655 'org.eclipse.buildship.core.gradleprojectnature'
657 buildCommand 'org.eclipse.jdt.core.javabuilder'
658 buildCommand 'org.eclipse.buildship.core.gradleprojectbuilder'
662 //defaultOutputDir = sourceSets.main.java.destinationDirectory
663 configurations.each{ c->
664 if (c.isCanBeResolved()) {
665 minusConfigurations += [c]
669 plusConfigurations = [ ]
673 def removeTheseToo = []
674 HashMap<String, Boolean> alreadyAddedSrcPath = new HashMap<>();
675 cp.entries.each { entry ->
676 // This conditional removes all src classpathentries that a) have already been added or b) aren't "src" or "test".
677 // e.g. this removes the resources dir being copied into bin/main, bin/test AND bin/clover
678 // we add the resources and help/help dirs in as libs afterwards (see below)
679 if (entry.kind == 'src') {
680 if (alreadyAddedSrcPath.getAt(entry.path) || !(entry.path == bareSourceDir || entry.path == bareTestSourceDir)) {
681 removeTheseToo += entry
683 alreadyAddedSrcPath.putAt(entry.path, true)
688 cp.entries.removeAll(removeTheseToo)
690 //cp.entries += new Output("${eclipse_bin_dir}/main")
691 if (file(helpParentDir).isDirectory()) {
692 cp.entries += new Library(fileReference(helpParentDir))
694 if (file(resourceDir).isDirectory()) {
695 cp.entries += new Library(fileReference(resourceDir))
698 HashMap<String, Boolean> alreadyAddedLibPath = new HashMap<>();
700 sourceSets.main.compileClasspath.findAll { it.name.endsWith(".jar") }.any {
701 //don't want to add destinationDirectory as eclipse is using its own output dir in bin/main
702 if (it.isDirectory() || ! it.exists()) {
703 // don't add dirs to classpath, especially if they don't exist
704 return false // groovy "continue" in .any closure
706 def itPath = it.toString()
707 if (itPath.startsWith("${jalviewDirAbsolutePath}/")) {
708 // make relative path
709 itPath = itPath.substring(jalviewDirAbsolutePath.length()+1)
711 if (alreadyAddedLibPath.get(itPath)) {
712 //println("Not adding duplicate entry "+itPath)
714 //println("Adding entry "+itPath)
715 cp.entries += new Library(fileReference(itPath))
716 alreadyAddedLibPath.put(itPath, true)
720 sourceSets.test.compileClasspath.findAll { it.name.endsWith(".jar") }.any {
721 //no longer want to add destinationDirectory as eclipse is using its own output dir in bin/main
722 if (it.isDirectory() || ! it.exists()) {
723 // don't add dirs to classpath
724 return false // groovy "continue" in .any closure
727 def itPath = it.toString()
728 if (itPath.startsWith("${jalviewDirAbsolutePath}/")) {
729 itPath = itPath.substring(jalviewDirAbsolutePath.length()+1)
731 if (alreadyAddedLibPath.get(itPath)) {
734 def lib = new Library(fileReference(itPath))
735 lib.entryAttributes["test"] = "true"
737 alreadyAddedLibPath.put(itPath, true)
745 containers 'org.eclipse.buildship.core.gradleclasspathcontainer'
750 // for the IDE, use java 11 compatibility
751 sourceCompatibility = compile_source_compatibility
752 targetCompatibility = compile_target_compatibility
753 javaRuntimeName = eclipseJavaRuntimeName
755 // add in jalview project specific properties/preferences into eclipse core preferences
757 withProperties { props ->
758 def jalview_prefs = new Properties()
759 def ins = new FileInputStream("${jalviewDirAbsolutePath}/${eclipse_extra_jdt_prefs_file}")
760 jalview_prefs.load(ins)
762 jalview_prefs.forEach { t, v ->
763 if (props.getAt(t) == null) {
767 // codestyle file -- overrides previous formatter prefs
768 def csFile = file("${jalviewDirAbsolutePath}/${eclipse_codestyle_file}")
769 if (csFile.exists()) {
770 XmlParser parser = new XmlParser()
771 def profiles = parser.parse(csFile)
772 def profile = profiles.'profile'.find { p -> (p.'@kind' == "CodeFormatterProfile" && p.'@name' == "Jalview") }
773 if (profile != null) {
774 profile.'setting'.each { s ->
776 def value = s.'@value'
777 if (id != null && value != null) {
778 props.putAt(id, value)
789 // Don't want these to be activated if in headless build
790 synchronizationTasks "eclipseSynchronizationTask"
791 //autoBuildTasks "eclipseAutoBuildTask"
797 /* hack to change eclipse prefs in .settings files other than org.eclipse.jdt.core.prefs */
798 // Class to allow updating arbitrary properties files
799 class PropertiesFile extends PropertiesPersistableConfigurationObject {
800 public PropertiesFile(PropertiesTransformer t) { super(t); }
801 @Override protected void load(Properties properties) { }
802 @Override protected void store(Properties properties) { }
803 @Override protected String getDefaultResourceName() { return ""; }
804 // This is necessary, because PropertiesPersistableConfigurationObject fails
805 // if no default properties file exists.
806 @Override public void loadDefaults() { load(new StringBufferInputStream("")); }
809 // Task to update arbitrary properties files (set outputFile)
810 class PropertiesFileTask extends PropertiesGeneratorTask<PropertiesFile> {
811 private final PropertiesFileContentMerger file;
812 public PropertiesFileTask() { file = new PropertiesFileContentMerger(getTransformer()); }
813 protected PropertiesFile create() { return new PropertiesFile(getTransformer()); }
814 protected void configure(PropertiesFile props) {
815 file.getBeforeMerged().execute(props); file.getWhenMerged().execute(props);
817 public void file(Closure closure) { ConfigureUtil.configure(closure, file); }
820 task eclipseUIPreferences(type: PropertiesFileTask) {
821 description = "Generate Eclipse additional settings"
822 def filename = "org.eclipse.jdt.ui.prefs"
823 outputFile = "$projectDir/.settings/${filename}" as File
826 it.load new FileInputStream("$projectDir/utils/eclipse/${filename}" as String)
831 task eclipseGroovyCorePreferences(type: PropertiesFileTask) {
832 description = "Generate Eclipse additional settings"
833 def filename = "org.eclipse.jdt.groovy.core.prefs"
834 outputFile = "$projectDir/.settings/${filename}" as File
837 it.load new FileInputStream("$projectDir/utils/eclipse/${filename}" as String)
842 task eclipseAllPreferences {
844 dependsOn eclipseUIPreferences
845 dependsOn eclipseGroovyCorePreferences
848 eclipseUIPreferences.mustRunAfter eclipseJdt
849 eclipseGroovyCorePreferences.mustRunAfter eclipseJdt
851 /* end of eclipse preferences hack */
859 delete cloverBuildDir
860 delete cloverReportDir
865 task cloverInstrJava(type: JavaExec) {
866 group = "Verification"
867 description = "Create clover instrumented source java files"
869 dependsOn cleanClover
871 inputs.files(sourceSets.main.allJava)
872 outputs.dir(cloverInstrDir)
874 //classpath = fileTree(dir: "${jalviewDir}/${clover_lib_dir}", include: ["*.jar"])
875 classpath = sourceSets.clover.compileClasspath
876 main = "com.atlassian.clover.CloverInstr"
884 cloverInstrDir.getPath(),
886 def srcFiles = sourceSets.main.allJava.files
889 { file -> file.absolutePath }
892 args argsList.toArray()
895 delete cloverInstrDir
896 println("Clover: About to instrument "+srcFiles.size() +" files")
901 task cloverInstrTests(type: JavaExec) {
902 group = "Verification"
903 description = "Create clover instrumented source test files"
905 dependsOn cleanClover
907 inputs.files(testDir)
908 outputs.dir(cloverTestInstrDir)
910 classpath = sourceSets.clover.compileClasspath
911 main = "com.atlassian.clover.CloverInstr"
921 cloverTestInstrDir.getPath(),
923 args argsList.toArray()
926 delete cloverTestInstrDir
927 println("Clover: About to instrument test files")
933 group = "Verification"
934 description = "Create clover instrumented all source files"
936 dependsOn cloverInstrJava
937 dependsOn cloverInstrTests
941 cloverClasses.dependsOn cloverInstr
944 task cloverConsoleReport(type: JavaExec) {
945 group = "Verification"
946 description = "Creates clover console report"
949 file(cloverDb).exists()
952 inputs.dir cloverClassesDir
954 classpath = sourceSets.clover.runtimeClasspath
955 main = "com.atlassian.clover.reporters.console.ConsoleReporter"
957 if (cloverreport_mem.length() > 0) {
958 maxHeapSize = cloverreport_mem
960 if (cloverreport_jvmargs.length() > 0) {
961 jvmArgs Arrays.asList(cloverreport_jvmargs.split(" "))
971 args argsList.toArray()
975 task cloverHtmlReport(type: JavaExec) {
976 group = "Verification"
977 description = "Creates clover HTML report"
980 file(cloverDb).exists()
983 def cloverHtmlDir = cloverReportDir
984 inputs.dir cloverClassesDir
985 outputs.dir cloverHtmlDir
987 classpath = sourceSets.clover.runtimeClasspath
988 main = "com.atlassian.clover.reporters.html.HtmlReporter"
990 if (cloverreport_mem.length() > 0) {
991 maxHeapSize = cloverreport_mem
993 if (cloverreport_jvmargs.length() > 0) {
994 jvmArgs Arrays.asList(cloverreport_jvmargs.split(" "))
1005 if (cloverreport_html_options.length() > 0) {
1006 argsList += cloverreport_html_options.split(" ")
1009 args argsList.toArray()
1013 task cloverXmlReport(type: JavaExec) {
1014 group = "Verification"
1015 description = "Creates clover XML report"
1018 file(cloverDb).exists()
1021 def cloverXmlFile = "${cloverReportDir}/clover.xml"
1022 inputs.dir cloverClassesDir
1023 outputs.file cloverXmlFile
1025 classpath = sourceSets.clover.runtimeClasspath
1026 main = "com.atlassian.clover.reporters.xml.XMLReporter"
1028 if (cloverreport_mem.length() > 0) {
1029 maxHeapSize = cloverreport_mem
1031 if (cloverreport_jvmargs.length() > 0) {
1032 jvmArgs Arrays.asList(cloverreport_jvmargs.split(" "))
1043 if (cloverreport_xml_options.length() > 0) {
1044 argsList += cloverreport_xml_options.split(" ")
1047 args argsList.toArray()
1052 group = "Verification"
1053 description = "Creates clover reports"
1055 dependsOn cloverXmlReport
1056 dependsOn cloverHtmlReport
1063 sourceCompatibility = compile_source_compatibility
1064 targetCompatibility = compile_target_compatibility
1065 options.compilerArgs += additional_compiler_args
1066 print ("Setting target compatibility to "+targetCompatibility+"\n")
1068 //classpath += configurations.cloverRuntime
1074 // JBP->BS should the print statement in doFirst refer to compile_target_compatibility ?
1075 sourceCompatibility = compile_source_compatibility
1076 targetCompatibility = compile_target_compatibility
1077 options.compilerArgs += additional_compiler_args
1078 options.encoding = "UTF-8"
1080 print ("Setting target compatibility to "+compile_target_compatibility+"\n")
1087 sourceCompatibility = compile_source_compatibility
1088 targetCompatibility = compile_target_compatibility
1089 options.compilerArgs += additional_compiler_args
1091 print ("Setting target compatibility to "+targetCompatibility+"\n")
1098 delete sourceSets.main.java.destinationDirectory
1104 dependsOn cleanClover
1106 delete sourceSets.test.java.destinationDirectory
1111 // format is a string like date.format("dd MMMM yyyy")
1112 def getDate(format) {
1113 return date.format(format)
1117 def convertMdToHtml (FileTree mdFiles, File cssFile) {
1118 MutableDataSet options = new MutableDataSet()
1120 def extensions = new ArrayList<>()
1121 extensions.add(AnchorLinkExtension.create())
1122 extensions.add(AutolinkExtension.create())
1123 extensions.add(StrikethroughExtension.create())
1124 extensions.add(TaskListExtension.create())
1125 extensions.add(TablesExtension.create())
1126 extensions.add(TocExtension.create())
1128 options.set(Parser.EXTENSIONS, extensions)
1130 // set GFM table parsing options
1131 options.set(TablesExtension.WITH_CAPTION, false)
1132 options.set(TablesExtension.COLUMN_SPANS, false)
1133 options.set(TablesExtension.MIN_HEADER_ROWS, 1)
1134 options.set(TablesExtension.MAX_HEADER_ROWS, 1)
1135 options.set(TablesExtension.APPEND_MISSING_COLUMNS, true)
1136 options.set(TablesExtension.DISCARD_EXTRA_COLUMNS, true)
1137 options.set(TablesExtension.HEADER_SEPARATOR_COLUMN_MATCH, true)
1139 options.set(AnchorLinkExtension.ANCHORLINKS_SET_ID, false)
1140 options.set(AnchorLinkExtension.ANCHORLINKS_ANCHOR_CLASS, "anchor")
1141 options.set(AnchorLinkExtension.ANCHORLINKS_SET_NAME, true)
1142 options.set(AnchorLinkExtension.ANCHORLINKS_TEXT_PREFIX, "<span class=\"octicon octicon-link\"></span>")
1144 Parser parser = Parser.builder(options).build()
1145 HtmlRenderer renderer = HtmlRenderer.builder(options).build()
1147 mdFiles.each { mdFile ->
1148 // add table of contents
1149 def mdText = "[TOC]\n"+mdFile.text
1151 // grab the first top-level title
1153 def titleRegex = /(?m)^#(\s+|([^#]))(.*)/
1154 def matcher = mdText =~ titleRegex
1155 if (matcher.size() > 0) {
1156 // matcher[0][2] is the first character of the title if there wasn't any whitespace after the #
1157 title = (matcher[0][2] != null ? matcher[0][2] : "")+matcher[0][3]
1159 // or use the filename if none found
1160 if (title == null) {
1161 title = mdFile.getName()
1164 Node document = parser.parse(mdText)
1165 String htmlBody = renderer.render(document)
1166 def htmlText = '''<html>
1167 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
1168 <html xmlns="http://www.w3.org/1999/xhtml">
1170 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
1171 <meta http-equiv="Content-Style-Type" content="text/css" />
1172 <meta name="generator" content="flexmark" />
1174 htmlText += ((title != null) ? " <title>${title}</title>" : '' )
1176 <style type="text/css">code{white-space: pre;}</style>
1178 htmlText += ((cssFile != null) ? cssFile.text : '')
1179 htmlText += '''</head>
1182 htmlText += htmlBody
1188 def htmlFilePath = mdFile.getPath().replaceAll(/\..*?$/, ".html")
1189 def htmlFile = file(htmlFilePath)
1190 println("Creating ${htmlFilePath}")
1191 htmlFile.text = htmlText
1196 task copyDocs(type: Copy) {
1197 def inputDir = "${jalviewDir}/${doc_dir}"
1198 def destinationDirectory = "${docBuildDir}/${doc_dir}"
1202 include('**/*.html')
1204 filter(ReplaceTokens,
1208 'Version-Rel': JALVIEW_VERSION,
1209 'Year-Rel': getDate("yyyy")
1216 exclude('**/*.html')
1219 into destinationDirectory
1221 inputs.dir(inputDir)
1222 outputs.dir(destinationDirectory)
1226 task convertMdFiles {
1228 def mdFiles = fileTree(dir: docBuildDir, include: "**/*.md")
1229 def cssFile = file("${jalviewDir}/${flexmark_css}")
1232 convertMdToHtml(mdFiles, cssFile)
1235 inputs.files(mdFiles)
1236 inputs.file(cssFile)
1239 mdFiles.each { mdFile ->
1240 def htmlFilePath = mdFile.getPath().replaceAll(/\..*?$/, ".html")
1241 htmlFiles.add(file(htmlFilePath))
1243 outputs.files(htmlFiles)
1247 def hugoTemplateSubstitutions(String input, Map extras=null) {
1248 def replacements = [
1249 DATE: getDate("yyyy-MM-dd"),
1250 CHANNEL: propertiesChannelName,
1251 APPLICATION_NAME: applicationName,
1253 GIT_BRANCH: gitBranch,
1254 VERSION: JALVIEW_VERSION,
1255 JAVA_VERSION: JAVA_VERSION,
1256 VERSION_UNDERSCORES: JALVIEW_VERSION_UNDERSCORES,
1261 if (extras != null) {
1262 extras.each{ k, v ->
1263 output = output.replaceAll("__${k}__", ((v == null)?"":v))
1266 replacements.each{ k, v ->
1267 output = output.replaceAll("__${k}__", ((v == null)?"":v))
1272 def mdFileComponents(File mdFile, def dateOnly=false) {
1275 if (mdFile.exists()) {
1276 def inFrontMatter = false
1277 def firstLine = true
1278 mdFile.eachLine { line ->
1279 if (line.matches("---")) {
1280 def prev = inFrontMatter
1281 inFrontMatter = firstLine
1282 if (inFrontMatter != prev)
1285 if (inFrontMatter) {
1287 if (m == line =~ /^date:\s*(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})/) {
1288 map["date"] = new Date().parse("yyyy-MM-dd HH:mm:ss", m[0][1])
1289 } else if (m == line =~ /^date:\s*(\d{4}-\d{2}-\d{2})/) {
1290 map["date"] = new Date().parse("yyyy-MM-dd", m[0][1])
1291 } else if (m == line =~ /^channel:\s*(\S+)/) {
1292 map["channel"] = m[0][1]
1293 } else if (m == line =~ /^version:\s*(\S+)/) {
1294 map["version"] = m[0][1]
1295 } else if (m == line =~ /^\s*([^:]+)\s*:\s*(\S.*)/) {
1296 map[ m[0][1] ] = m[0][2]
1298 if (dateOnly && map["date"] != null) {
1304 content += line+"\n"
1309 return dateOnly ? map["date"] : [map, content]
1312 task hugoTemplates {
1314 description "Create partially populated md pages for hugo website build"
1316 def hugoTemplatesDir = file("${jalviewDir}/${hugo_templates_dir}")
1317 def hugoBuildDir = "${jalviewDir}/${hugo_build_dir}"
1318 def templateFiles = fileTree(dir: hugoTemplatesDir)
1319 def releaseMdFile = file("${jalviewDir}/${releases_dir}/release-${JALVIEW_VERSION_UNDERSCORES}.md")
1320 def whatsnewMdFile = file("${jalviewDir}/${whatsnew_dir}/whatsnew-${JALVIEW_VERSION_UNDERSCORES}.md")
1321 def oldJvlFile = file("${jalviewDir}/${hugo_old_jvl}")
1322 def jalviewjsFile = file("${jalviewDir}/${hugo_jalviewjs}")
1325 // specific release template for version archive
1328 def givenDate = null
1329 def givenChannel = null
1330 def givenVersion = null
1331 if (CHANNEL == "RELEASE") {
1332 def (map, content) = mdFileComponents(releaseMdFile)
1333 givenDate = map.date
1334 givenChannel = map.channel
1335 givenVersion = map.version
1337 if (givenVersion != null && givenVersion != JALVIEW_VERSION) {
1338 throw new GradleException("'version' header (${givenVersion}) found in ${releaseMdFile} does not match JALVIEW_VERSION (${JALVIEW_VERSION})")
1341 if (whatsnewMdFile.exists())
1342 whatsnew = whatsnewMdFile.text
1345 def oldJvl = oldJvlFile.exists() ? oldJvlFile.collect{it} : []
1346 def jalviewjsLink = jalviewjsFile.exists() ? jalviewjsFile.collect{it} : []
1348 def changesHugo = null
1349 if (changes != null) {
1350 changesHugo = '<div class="release_notes">\n\n'
1351 def inSection = false
1352 changes.eachLine { line ->
1354 if (m == line =~ /^##([^#].*)$/) {
1356 changesHugo += "</div>\n\n"
1358 def section = m[0][1].trim()
1359 section = section.toLowerCase()
1360 section = section.replaceAll(/ +/, "_")
1361 section = section.replaceAll(/[^a-z0-9_\-]/, "")
1362 changesHugo += "<div class=\"${section}\">\n\n"
1364 } else if (m == line =~ /^(\s*-\s*)<!--([^>]+)-->(.*?)(<br\/?>)?\s*$/) {
1365 def comment = m[0][2].trim()
1366 if (comment != "") {
1367 comment = comment.replaceAll('"', """)
1369 comment.eachMatch(/JAL-\d+/) { jal -> issuekeys += jal }
1370 def newline = m[0][1]
1371 if (comment.trim() != "")
1372 newline += "{{<comment>}}${comment}{{</comment>}} "
1373 newline += m[0][3].trim()
1374 if (issuekeys.size() > 0)
1375 newline += " {{< jal issue=\"${issuekeys.join(",")}\" alt=\"${comment}\" >}}"
1376 if (m[0][4] != null)
1381 changesHugo += line+"\n"
1384 changesHugo += "\n</div>\n\n"
1386 changesHugo += '</div>'
1389 templateFiles.each{ templateFile ->
1390 def newFileName = string(hugoTemplateSubstitutions(templateFile.getName()))
1391 def relPath = hugoTemplatesDir.toPath().relativize(templateFile.toPath()).getParent()
1392 def newRelPathName = hugoTemplateSubstitutions( relPath.toString() )
1394 def outPathName = string("${hugoBuildDir}/$newRelPathName")
1398 rename(templateFile.getName(), newFileName)
1402 def newFile = file("${outPathName}/${newFileName}".toString())
1403 def content = newFile.text
1404 newFile.text = hugoTemplateSubstitutions(content,
1407 CHANGES: changesHugo,
1408 DATE: givenDate == null ? "" : givenDate.format("yyyy-MM-dd"),
1409 DRAFT: givenDate == null ? "true" : "false",
1410 JALVIEWJSLINK: jalviewjsLink.contains(JALVIEW_VERSION) ? "true" : "false",
1411 JVL_HEADER: oldJvl.contains(JALVIEW_VERSION) ? "jvl: true" : ""
1418 inputs.file(oldJvlFile)
1419 inputs.dir(hugoTemplatesDir)
1420 inputs.property("JALVIEW_VERSION", { JALVIEW_VERSION })
1421 inputs.property("CHANNEL", { CHANNEL })
1424 def getMdDate(File mdFile) {
1425 return mdFileComponents(mdFile, true)
1428 def getMdSections(String content) {
1430 def sectionContent = ""
1431 def sectionName = null
1432 content.eachLine { line ->
1434 if (m == line =~ /^##([^#].*)$/) {
1435 if (sectionName != null) {
1436 sections[sectionName] = sectionContent
1440 sectionName = m[0][1].trim()
1441 sectionName = sectionName.toLowerCase()
1442 sectionName = sectionName.replaceAll(/ +/, "_")
1443 sectionName = sectionName.replaceAll(/[^a-z0-9_\-]/, "")
1444 } else if (sectionName != null) {
1445 sectionContent += line+"\n"
1448 if (sectionContent != null) {
1449 sections[sectionName] = sectionContent
1455 task copyHelp(type: Copy) {
1456 def inputDir = helpSourceDir
1457 def destinationDirectory = "${helpBuildDir}/${help_dir}"
1461 include('**/*.html')
1465 filter(ReplaceTokens,
1469 'Version-Rel': JALVIEW_VERSION,
1470 'Year-Rel': getDate("yyyy")
1477 exclude('**/*.html')
1482 into destinationDirectory
1484 inputs.dir(inputDir)
1485 outputs.files(helpFile)
1486 outputs.dir(destinationDirectory)
1491 task releasesTemplates {
1493 description "Recreate whatsNew.html and releases.html from markdown files and templates in help"
1497 def releasesTemplateFile = file("${jalviewDir}/${releases_template}")
1498 def whatsnewTemplateFile = file("${jalviewDir}/${whatsnew_template}")
1499 def releasesHtmlFile = file("${helpBuildDir}/${help_dir}/${releases_html}")
1500 def whatsnewHtmlFile = file("${helpBuildDir}/${help_dir}/${whatsnew_html}")
1501 def releasesMdDir = "${jalviewDir}/${releases_dir}"
1502 def whatsnewMdDir = "${jalviewDir}/${whatsnew_dir}"
1505 def releaseMdFile = file("${releasesMdDir}/release-${JALVIEW_VERSION_UNDERSCORES}.md")
1506 def whatsnewMdFile = file("${whatsnewMdDir}/whatsnew-${JALVIEW_VERSION_UNDERSCORES}.md")
1508 if (CHANNEL == "RELEASE") {
1509 if (!releaseMdFile.exists()) {
1510 throw new GradleException("File ${releaseMdFile} must be created for RELEASE")
1512 if (!whatsnewMdFile.exists()) {
1513 throw new GradleException("File ${whatsnewMdFile} must be created for RELEASE")
1517 def releaseFiles = fileTree(dir: releasesMdDir, include: "release-*.md")
1518 def releaseFilesDates = releaseFiles.collectEntries {
1519 [(it): getMdDate(it)]
1521 releaseFiles = releaseFiles.sort { a,b -> releaseFilesDates[a].compareTo(releaseFilesDates[b]) }
1523 def releasesTemplate = releasesTemplateFile.text
1524 def m = releasesTemplate =~ /(?s)__VERSION_LOOP_START__(.*)__VERSION_LOOP_END__/
1525 def versionTemplate = m[0][1]
1527 MutableDataSet options = new MutableDataSet()
1529 def extensions = new ArrayList<>()
1530 options.set(Parser.EXTENSIONS, extensions)
1531 options.set(Parser.HTML_BLOCK_COMMENT_ONLY_FULL_LINE, true)
1533 Parser parser = Parser.builder(options).build()
1534 HtmlRenderer renderer = HtmlRenderer.builder(options).build()
1536 def actualVersions = releaseFiles.collect { rf ->
1537 def (rfMap, rfContent) = mdFileComponents(rf)
1538 return rfMap.version
1540 def versionsHtml = ""
1541 def linkedVersions = []
1542 releaseFiles.reverse().each { rFile ->
1543 def (rMap, rContent) = mdFileComponents(rFile)
1545 def versionLink = ""
1546 def partialVersion = ""
1547 def firstPart = true
1548 rMap.version.split("\\.").each { part ->
1549 def displayPart = ( firstPart ? "" : "." ) + part
1550 partialVersion += displayPart
1552 linkedVersions.contains(partialVersion)
1553 || ( actualVersions.contains(partialVersion) && partialVersion != rMap.version )
1555 versionLink += displayPart
1557 versionLink += "<a id=\"Jalview.${partialVersion}\">${displayPart}</a>"
1558 linkedVersions += partialVersion
1562 def displayDate = releaseFilesDates[rFile].format("dd/MM/yyyy")
1565 def rContentProcessed = ""
1566 rContent.eachLine { line ->
1567 if (lm == line =~ /^(\s*-)(\s*<!--[^>]*?-->)(.*)$/) {
1568 line = "${lm[0][1]}${lm[0][3]}${lm[0][2]}"
1569 } else if (lm == line =~ /^###([^#]+.*)$/) {
1570 line = "_${lm[0][1].trim()}_"
1572 rContentProcessed += line + "\n"
1575 def rContentSections = getMdSections(rContentProcessed)
1576 def rVersion = versionTemplate
1577 if (rVersion != "") {
1578 def rNewFeatures = rContentSections["new_features"]
1579 def rIssuesResolved = rContentSections["issues_resolved"]
1580 Node newFeaturesNode = parser.parse(rNewFeatures)
1581 String newFeaturesHtml = renderer.render(newFeaturesNode)
1582 Node issuesResolvedNode = parser.parse(rIssuesResolved)
1583 String issuesResolvedHtml = renderer.render(issuesResolvedNode)
1584 rVersion = hugoTemplateSubstitutions(rVersion,
1586 VERSION: rMap.version,
1587 VERSION_LINK: versionLink,
1588 DISPLAY_DATE: displayDate,
1589 NEW_FEATURES: newFeaturesHtml,
1590 ISSUES_RESOLVED: issuesResolvedHtml
1593 versionsHtml += rVersion
1597 releasesTemplate = releasesTemplate.replaceAll("(?s)__VERSION_LOOP_START__.*__VERSION_LOOP_END__", versionsHtml)
1598 releasesTemplate = hugoTemplateSubstitutions(releasesTemplate)
1599 releasesHtmlFile.text = releasesTemplate
1601 if (whatsnewMdFile.exists()) {
1602 def wnDisplayDate = releaseFilesDates[releaseMdFile] != null ? releaseFilesDates[releaseMdFile].format("dd MMMM yyyy") : ""
1603 def whatsnewMd = hugoTemplateSubstitutions(whatsnewMdFile.text)
1604 Node whatsnewNode = parser.parse(whatsnewMd)
1605 String whatsnewHtml = renderer.render(whatsnewNode)
1606 whatsnewHtml = whatsnewTemplateFile.text.replaceAll("__WHATS_NEW__", whatsnewHtml)
1607 whatsnewHtmlFile.text = hugoTemplateSubstitutions(whatsnewHtml,
1609 VERSION: JALVIEW_VERSION,
1610 DISPLAY_DATE: wnDisplayDate
1613 } else if (gradle.taskGraph.hasTask(":linkCheck")) {
1614 whatsnewHtmlFile.text = "Development build " + getDate("yyyy-MM-dd HH:mm:ss")
1619 inputs.file(releasesTemplateFile)
1620 inputs.file(whatsnewTemplateFile)
1621 inputs.dir(releasesMdDir)
1622 inputs.dir(whatsnewMdDir)
1623 outputs.file(releasesHtmlFile)
1624 outputs.file(whatsnewHtmlFile)
1629 task copyResources(type: Copy) {
1631 description = "Copy (and make text substitutions in) the resources dir to the build area"
1633 def inputDir = resourceDir
1634 def destinationDirectory = resourcesBuildDir
1638 include('**/*.html')
1640 filter(ReplaceTokens,
1644 'Version-Rel': JALVIEW_VERSION,
1645 'Year-Rel': getDate("yyyy")
1652 exclude('**/*.html')
1655 into destinationDirectory
1657 inputs.dir(inputDir)
1658 outputs.dir(destinationDirectory)
1661 task copyChannelResources(type: Copy) {
1662 dependsOn copyResources
1664 description = "Copy the channel resources dir to the build resources area"
1666 def inputDir = "${channelDir}/${resource_dir}"
1667 def destinationDirectory = resourcesBuildDir
1669 include(channel_props)
1670 filter(ReplaceTokens,
1674 'SUFFIX': channelSuffix
1679 exclude(channel_props)
1681 into destinationDirectory
1683 inputs.dir(inputDir)
1684 outputs.dir(destinationDirectory)
1687 task createBuildProperties(type: WriteProperties) {
1688 dependsOn copyResources
1689 dependsOn copyChannelResources
1691 description = "Create the ${buildProperties} file"
1693 inputs.dir(sourceDir)
1694 inputs.dir(resourcesBuildDir)
1695 outputFile (buildProperties)
1696 // taking time specific comment out to allow better incremental builds
1697 comment "--Jalview Build Details--\n"+getDate("yyyy-MM-dd HH:mm:ss")
1698 //comment "--Jalview Build Details--\n"+getDate("yyyy-MM-dd")
1699 property "BUILD_DATE", getDate("HH:mm:ss dd MMMM yyyy")
1700 property "VERSION", JALVIEW_VERSION
1701 property "INSTALLATION", INSTALLATION+" git-commit:"+gitHash+" ["+gitBranch+"]"
1702 property "JAVA_COMPILE_VERSION", JAVA_INTEGER_VERSION
1703 if (getdownSetAppBaseProperty) {
1704 property "GETDOWNAPPBASE", getdownAppBase
1705 property "GETDOWNAPPDISTDIR", getdownAppDistDir
1707 outputs.file(outputFile)
1711 task buildIndices(type: JavaExec) {
1713 //dependsOn releasesTemplates
1714 classpath = sourceSets.main.compileClasspath
1715 main = "com.sun.java.help.search.Indexer"
1716 workingDir = "${helpBuildDir}/${help_dir}"
1719 inputs.dir("${workingDir}/${argDir}")
1721 outputs.dir("${classesDir}/doc")
1722 outputs.dir("${classesDir}/help")
1723 outputs.file("${workingDir}/JavaHelpSearch/DOCS")
1724 outputs.file("${workingDir}/JavaHelpSearch/DOCS.TAB")
1725 outputs.file("${workingDir}/JavaHelpSearch/OFFSETS")
1726 outputs.file("${workingDir}/JavaHelpSearch/POSITIONS")
1727 outputs.file("${workingDir}/JavaHelpSearch/SCHEMA")
1728 outputs.file("${workingDir}/JavaHelpSearch/TMAP")
1731 task buildResources {
1732 dependsOn copyResources
1733 dependsOn copyChannelResources
1734 dependsOn createBuildProperties
1738 dependsOn buildResources
1741 //dependsOn releasesTemplates
1742 dependsOn convertMdFiles
1743 dependsOn buildIndices
1747 // random block of dependencies
1748 compileJava.dependsOn prepare
1749 run.dependsOn compileJava
1750 //run.dependsOn prepare
1751 compileTestJava.dependsOn compileJava //
1752 compileTestJava.dependsOn buildIndices //
1753 processResources.dependsOn copyChannelResources //
1754 processResources.dependsOn copyResources //
1755 processResources.dependsOn createBuildProperties //
1756 processResources.dependsOn copyDocs //
1757 processResources.dependsOn convertMdFiles //
1758 processResources.dependsOn copyHelp //
1759 processResources.dependsOn buildIndices //
1761 group = "Verification"
1762 description = "Runs all testTaskN tasks)"
1765 dependsOn cloverClasses
1767 dependsOn testClasses
1770 // not running tests in this task
1773 /* testTask0 is the main test task */
1774 task testTask0(type: Test) {
1775 group = "Verification"
1776 description = "The main test task. Runs all non-testTaskN-labelled tests (unless excluded)"
1778 includeGroups testng_groups.split(",")
1779 excludeGroups testng_excluded_groups.split(",")
1780 tasks.withType(Test).matching {it.name.startsWith("testTask") && it.name != name}.all {t -> excludeGroups t.name}
1782 useDefaultListeners=true
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
1798 /* insert more testTaskNs here -- change N to next digit or other string */
1800 task testTaskN(type: Test) {
1801 group = "Verification"
1802 description = "Tests that need to be isolated from the main test run"
1805 excludeGroups testng_excluded_groups.split(",")
1807 useDefaultListeners=true
1813 * adapted from https://medium.com/@wasyl/pretty-tests-summary-in-gradle-744804dd676c
1814 * to summarise test results from all Test tasks
1816 /* START of test tasks results summary */
1817 import groovy.time.TimeCategory
1818 import org.gradle.api.tasks.testing.logging.TestExceptionFormat
1819 import org.gradle.api.tasks.testing.logging.TestLogEvent
1820 rootProject.ext.testsResults = [] // Container for tests summaries
1822 tasks.withType(Test).matching {t -> t.getName().startsWith("testTask")}.all { testTask ->
1824 // from original test task
1826 dependsOn cloverClasses
1828 dependsOn testClasses //?
1831 // run main tests first
1832 if (!testTask.name.equals("testTask0"))
1833 testTask.mustRunAfter "testTask0"
1835 testTask.testLogging { logging ->
1836 events TestLogEvent.FAILED
1837 // TestLogEvent.SKIPPED,
1838 // TestLogEvent.STANDARD_OUT,
1839 // TestLogEvent.STANDARD_ERROR
1841 exceptionFormat TestExceptionFormat.FULL
1844 showStackTraces true
1846 info.events = [ TestLogEvent.FAILED ]
1851 ignoreFailures = true // Always try to run all tests for all modules
1853 afterSuite { desc, result ->
1855 return // Only summarize results for whole modules
1857 def resultsInfo = [testTask.project.name, testTask.name, result, TimeCategory.minus(new Date(result.endTime), new Date(result.startTime)), testTask.reports.html.entryPoint]
1859 rootProject.ext.testsResults.add(resultsInfo)
1862 // from original test task
1863 maxHeapSize = "1024m"
1865 workingDir = jalviewDir
1866 def testLaf = project.findProperty("test_laf")
1867 if (testLaf != null) {
1868 println("Setting Test LaF to '${testLaf}'")
1869 systemProperty "laf", testLaf
1871 def testHiDPIScale = project.findProperty("test_HiDPIScale")
1872 if (testHiDPIScale != null) {
1873 println("Setting Test HiDPI Scale to '${testHiDPIScale}'")
1874 systemProperty "sun.java2d.uiScale", testHiDPIScale
1876 sourceCompatibility = compile_source_compatibility
1877 targetCompatibility = compile_target_compatibility
1878 jvmArgs += additional_compiler_args
1881 // this is not perfect yet -- we should only add the commandLineIncludePatterns to the
1882 // testTasks that include the tests, and exclude all from the others.
1883 // get --test argument
1884 filter.commandLineIncludePatterns = test.filter.commandLineIncludePatterns
1885 // do something with testTask.getCandidateClassFiles() to see if the test should silently finish because of the
1886 // commandLineIncludePatterns not matching anything. Instead we are doing setFailOnNoMatchingTests(false) below
1890 println("Running tests " + (useClover?"WITH":"WITHOUT") + " clover")
1895 /* don't fail on no matching tests (so --tests will run across all testTasks) */
1896 testTask.filter.setFailOnNoMatchingTests(false)
1898 /* ensure the "test" task dependsOn all the testTasks */
1899 test.dependsOn testTask
1902 gradle.buildFinished {
1903 def allResults = rootProject.ext.testsResults
1905 if (!allResults.isEmpty()) {
1906 printResults allResults
1907 allResults.each {r ->
1908 if (r[2].resultType == TestResult.ResultType.FAILURE)
1909 throw new GradleException("Failed tests!")
1914 private static String colString(styler, col, colour, text) {
1915 return col?"${styler[colour](text)}":text
1918 private static String getSummaryLine(s, pn, tn, rt, rc, rs, rf, rsk, t, col) {
1919 def colour = 'black'
1927 case TestResult.ResultType.SUCCESS:
1930 case TestResult.ResultType.FAILURE:
1938 StringBuilder sb = new StringBuilder()
1942 sb.append(" results: ")
1943 sb.append(colString(s, col && !nocol, colour, text))
1945 sb.append("${rc} tests, ")
1946 sb.append(colString(s, col && rs > 0, 'green', rs))
1947 sb.append(" successes, ")
1948 sb.append(colString(s, col && rf > 0, 'red', rf))
1949 sb.append(" failures, ")
1950 sb.append("${rsk} skipped) in ${t}")
1951 return sb.toString()
1954 private static void printResults(allResults) {
1956 // styler from https://stackoverflow.com/a/56139852
1957 def styler = 'black red green yellow blue magenta cyan white'.split().toList().withIndex(30).collectEntries { key, val -> [(key) : { "\033[${val}m${it}\033[0m" }] }
1960 def failedTests = false
1961 def summaryLines = []
1963 def totalsuccess = 0
1966 def totaltime = TimeCategory.getSeconds(0)
1967 // sort on project name then task name
1968 allResults.sort {a, b -> a[0] == b[0]? a[1]<=>b[1]:a[0] <=> b[0]}.each {
1969 def projectName = it[0]
1970 def taskName = it[1]
1974 def summaryCol = getSummaryLine(styler, projectName, taskName, result.resultType, result.testCount, result.successfulTestCount, result.failedTestCount, result.skippedTestCount, time, true)
1975 def summaryPlain = getSummaryLine(styler, projectName, taskName, result.resultType, result.testCount, result.successfulTestCount, result.failedTestCount, result.skippedTestCount, time, false)
1976 def reportLine = "Report file: ${report}"
1977 def ls = summaryPlain.length()
1978 def lr = reportLine.length()
1979 def m = [ls, lr].max()
1982 def info = [ls, summaryCol, reportLine]
1983 summaryLines.add(info)
1984 failedTests |= result.resultType == TestResult.ResultType.FAILURE
1985 totalcount += result.testCount
1986 totalsuccess += result.successfulTestCount
1987 totalfail += result.failedTestCount
1988 totalskip += result.skippedTestCount
1991 def totalSummaryCol = getSummaryLine(styler, "OVERALL", "", failedTests?TestResult.ResultType.FAILURE:TestResult.ResultType.SUCCESS, totalcount, totalsuccess, totalfail, totalskip, totaltime, true)
1992 def totalSummaryPlain = getSummaryLine(styler, "OVERALL", "", failedTests?TestResult.ResultType.FAILURE:TestResult.ResultType.SUCCESS, totalcount, totalsuccess, totalfail, totalskip, totaltime, false)
1993 def tls = totalSummaryPlain.length()
1994 if (tls > maxLength)
1996 def info = [tls, totalSummaryCol, null]
1997 summaryLines.add(info)
1999 def allSummaries = []
2000 for(sInfo : summaryLines) {
2002 def summary = sInfo[1]
2003 def report = sInfo[2]
2005 StringBuilder sb = new StringBuilder()
2006 sb.append("│" + summary + " " * (maxLength - ls) + "│")
2007 if (report != null) {
2008 sb.append("\n│" + report + " " * (maxLength - report.length()) + "│")
2010 allSummaries += sb.toString()
2013 println "┌${"${"─" * maxLength}"}┐"
2014 println allSummaries.join("\n├${"${"─" * maxLength}"}┤\n")
2015 println "└${"${"─" * maxLength}"}┘"
2017 /* END of test tasks results summary */
2021 task compileLinkCheck(type: JavaCompile) {
2023 classpath = files("${jalviewDir}/${utils_dir}")
2024 destinationDir = file("${jalviewDir}/${utils_dir}")
2025 source = fileTree(dir: "${jalviewDir}/${utils_dir}", include: ["HelpLinksChecker.java", "BufferedLineReader.java"])
2027 inputs.file("${jalviewDir}/${utils_dir}/HelpLinksChecker.java")
2028 inputs.file("${jalviewDir}/${utils_dir}/HelpLinksChecker.java")
2029 outputs.file("${jalviewDir}/${utils_dir}/HelpLinksChecker.class")
2030 outputs.file("${jalviewDir}/${utils_dir}/BufferedLineReader.class")
2034 task linkCheck(type: JavaExec) {
2036 dependsOn compileLinkCheck
2038 def helpLinksCheckerOutFile = file("${jalviewDir}/${utils_dir}/HelpLinksChecker.out")
2039 classpath = files("${jalviewDir}/${utils_dir}")
2040 main = "HelpLinksChecker"
2041 workingDir = "${helpBuildDir}"
2042 args = [ "${helpBuildDir}/${help_dir}", "-nointernet" ]
2044 def outFOS = new FileOutputStream(helpLinksCheckerOutFile, false) // false == don't append
2045 standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
2048 errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
2052 inputs.dir(helpBuildDir)
2053 outputs.file(helpLinksCheckerOutFile)
2058 // import the pubhtmlhelp target
2059 ant.properties.basedir = "${jalviewDir}"
2060 ant.properties.helpBuildDir = "${helpBuildDir}/${help_dir}"
2061 ant.importBuild "${utils_dir}/publishHelp.xml"
2064 task cleanPackageDir(type: Delete) {
2066 delete fileTree(dir: "${jalviewDir}/${package_dir}", include: "*.jar")
2070 // block of dependencies
2071 //compileTestJava.dependsOn compileLinkCheck //
2072 //copyChannelResources.dependsOn compileLinkCheck //
2073 //convertMdFiles.dependsOn compileLinkCheck //
2077 dependsOn //linkCheck
2080 attributes "Main-Class": main_class,
2081 "Permissions": "all-permissions",
2082 "Application-Name": applicationName,
2083 "Codebase": application_codebase,
2084 "Implementation-Version": JALVIEW_VERSION
2087 def destinationDirectory = "${jalviewDir}/${package_dir}"
2088 destinationDirectory = file(destinationDirectory)
2089 archiveFileName = rootProject.name+".jar"
2090 duplicatesStrategy "EXCLUDE"
2097 exclude "**/*.jar.*"
2099 inputs.dir(sourceSets.main.java.destinationDirectory)
2100 sourceSets.main.resources.srcDirs.each{ dir ->
2103 outputs.file("${destinationDirectory}/${archiveFileName}")
2107 task copyJars(type: Copy) {
2108 from fileTree(dir: classesDir, include: "**/*.jar").files
2109 into "${jalviewDir}/${package_dir}"
2113 // doing a Sync instead of Copy as Copy doesn't deal with "outputs" very well
2114 task syncJars(type: Sync) {
2116 from fileTree(dir: "${jalviewDir}/${libDistDir}", include: "**/*.jar").files
2117 into "${jalviewDir}/${package_dir}"
2119 include jar.archiveFileName.getOrNull()
2126 description = "Put all required libraries in dist"
2127 // order of "cleanPackageDir", "copyJars", "jar" important!
2128 jar.mustRunAfter cleanPackageDir
2129 syncJars.mustRunAfter cleanPackageDir
2130 dependsOn cleanPackageDir
2133 outputs.dir("${jalviewDir}/${package_dir}")
2138 dependsOn cleanPackageDir
2145 group = "distribution"
2146 description = "Create a single jar file with all dependency libraries merged. Can be run with java -jar"
2150 from ("${jalviewDir}/${libDistDir}") {
2154 attributes "Implementation-Version": JALVIEW_VERSION,
2155 "Application-Name": applicationName
2158 duplicatesStrategy "INCLUDE"
2160 mainClassName = shadow_jar_main_class
2162 archiveClassifier = "all-"+JALVIEW_VERSION+"-j"+JAVA_VERSION
2166 task getdownImagesCopy() {
2167 inputs.dir getdownImagesDir
2168 outputs.dir getdownImagesBuildDir
2172 from(getdownImagesDir) {
2173 include("*getdown*.png")
2175 into getdownImagesBuildDir
2180 task getdownImagesProcess() {
2181 dependsOn getdownImagesCopy
2184 if (backgroundImageText) {
2185 if (convertBinary == null) {
2186 throw new StopExecutionException("No ImageMagick convert binary installed at '${convertBinaryExpectedLocation}'")
2188 if (!project.hasProperty("getdown_background_image_text_suffix_cmd")) {
2189 throw new StopExecutionException("No property 'getdown_background_image_text_suffix_cmd' defined. See channel_gradle.properties for channel ${CHANNEL}")
2191 fileTree(dir: getdownImagesBuildDir, include: "*background*.png").getFiles().each { file ->
2193 executable convertBinary
2196 '-font', getdown_background_image_text_font,
2197 '-fill', getdown_background_image_text_colour,
2198 '-draw', sprintf(getdown_background_image_text_suffix_cmd, channelSuffix),
2199 '-draw', sprintf(getdown_background_image_text_commit_cmd, "git-commit: ${gitHash}"),
2200 '-draw', sprintf(getdown_background_image_text_date_cmd, getDate("yyyy-MM-dd HH:mm:ss")),
2209 task getdownImages() {
2210 dependsOn getdownImagesProcess
2213 task getdownWebsite() {
2214 group = "distribution"
2215 description = "Create the getdown minimal app folder, and website folder for this version of jalview. Website folder also used for offline app installer"
2217 dependsOn getdownImages
2222 def getdownWebsiteResourceFilenames = []
2223 def getdownResourceDir = getdownResourceDir
2224 def getdownResourceFilenames = []
2227 // clean the getdown website and files dir before creating getdown folders
2228 delete getdownAppBaseDir
2229 delete getdownFilesDir
2232 from buildProperties
2233 rename(file(buildProperties).getName(), getdown_build_properties)
2236 getdownWebsiteResourceFilenames += "${getdownAppDistDir}/${getdown_build_properties}"
2239 from channelPropsFile
2240 filter(ReplaceTokens,
2244 'SUFFIX': channelSuffix
2247 into getdownAppBaseDir
2249 getdownWebsiteResourceFilenames += file(channelPropsFile).getName()
2251 // set some getdownTxt_ properties then go through all properties looking for getdownTxt_...
2252 def props = project.properties.sort { it.key }
2253 if (getdownAltJavaMinVersion != null && getdownAltJavaMinVersion.length() > 0) {
2254 props.put("getdown_txt_java_min_version", getdownAltJavaMinVersion)
2256 if (getdownAltJavaMaxVersion != null && getdownAltJavaMaxVersion.length() > 0) {
2257 props.put("getdown_txt_java_max_version", getdownAltJavaMaxVersion)
2259 if (getdownAltMultiJavaLocation != null && getdownAltMultiJavaLocation.length() > 0) {
2260 props.put("getdown_txt_multi_java_location", getdownAltMultiJavaLocation)
2262 if (getdownImagesBuildDir != null && file(getdownImagesBuildDir).exists()) {
2263 props.put("getdown_txt_ui.background_image", "${getdownImagesBuildDir}/${getdown_background_image}")
2264 props.put("getdown_txt_ui.instant_background_image", "${getdownImagesBuildDir}/${getdown_instant_background_image}")
2265 props.put("getdown_txt_ui.error_background", "${getdownImagesBuildDir}/${getdown_error_background}")
2266 props.put("getdown_txt_ui.progress_image", "${getdownImagesBuildDir}/${getdown_progress_image}")
2267 props.put("getdown_txt_ui.icon", "${getdownImagesDir}/${getdown_icon}")
2268 props.put("getdown_txt_ui.mac_dock_icon", "${getdownImagesDir}/${getdown_mac_dock_icon}")
2271 props.put("getdown_txt_title", jalview_name)
2272 props.put("getdown_txt_ui.name", applicationName)
2274 // start with appbase
2275 getdownTextLines += "appbase = ${getdownAppBase}"
2276 props.each{ prop, val ->
2277 if (prop.startsWith("getdown_txt_") && val != null) {
2278 if (prop.startsWith("getdown_txt_multi_")) {
2279 def key = prop.substring(18)
2280 val.split(",").each{ v ->
2281 def line = "${key} = ${v}"
2282 getdownTextLines += line
2285 // file values rationalised
2286 if (val.indexOf('/') > -1 || prop.startsWith("getdown_txt_resource")) {
2288 if (val.indexOf('/') == 0) {
2291 } else if (val.indexOf('/') > 0) {
2292 // relative path (relative to jalviewDir)
2293 r = file( "${jalviewDir}/${val}" )
2296 val = "${getdown_resource_dir}/" + r.getName()
2297 getdownWebsiteResourceFilenames += val
2298 getdownResourceFilenames += r.getPath()
2301 if (! prop.startsWith("getdown_txt_resource")) {
2302 def line = prop.substring(12) + " = ${val}"
2303 getdownTextLines += line
2309 getdownWebsiteResourceFilenames.each{ filename ->
2310 getdownTextLines += "resource = ${filename}"
2312 getdownResourceFilenames.each{ filename ->
2315 into getdownResourceDir
2319 def getdownWrapperScripts = [ getdown_bash_wrapper_script, getdown_powershell_wrapper_script, getdown_batch_wrapper_script ]
2320 getdownWrapperScripts.each{ script ->
2321 def s = file( "${jalviewDir}/utils/getdown/${getdown_wrapper_script_dir}/${script}" )
2325 into "${getdownAppBaseDir}/${getdown_wrapper_script_dir}"
2327 getdownTextLines += "resource = ${getdown_wrapper_script_dir}/${script}"
2332 fileTree(file(package_dir)).each{ f ->
2333 if (f.isDirectory()) {
2334 def files = fileTree(dir: f, include: ["*"]).getFiles()
2336 } else if (f.exists()) {
2340 def jalviewJar = jar.archiveFileName.getOrNull()
2341 // put jalview.jar first for CLASSPATH and .properties files reasons
2342 codeFiles.sort{a, b -> ( a.getName() == jalviewJar ? -1 : ( b.getName() == jalviewJar ? 1 : a <=> b ) ) }.each{f ->
2343 def name = f.getName()
2344 def line = "code = ${getdownAppDistDir}/${name}"
2345 getdownTextLines += line
2352 // NOT USING MODULES YET, EVERYTHING SHOULD BE IN dist
2354 if (JAVA_VERSION.equals("11")) {
2355 def j11libFiles = fileTree(dir: "${jalviewDir}/${j11libDir}", include: ["*.jar"]).getFiles()
2356 j11libFiles.sort().each{f ->
2357 def name = f.getName()
2358 def line = "code = ${getdown_j11lib_dir}/${name}"
2359 getdownTextLines += line
2362 into getdownJ11libDir
2368 // 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.
2369 //getdownTextLines += "class = " + file(getdownLauncher).getName()
2370 getdownTextLines += "resource = ${getdown_launcher_new}"
2371 getdownTextLines += "class = ${main_class}"
2372 // Not setting these properties in general so that getdownappbase and getdowndistdir will default to release version in jalview.bin.Cache
2373 if (getdownSetAppBaseProperty) {
2374 getdownTextLines += "jvmarg = -Dgetdowndistdir=${getdownAppDistDir}"
2375 getdownTextLines += "jvmarg = -Dgetdownappbase=${getdownAppBase}"
2378 def getdownTxt = file("${getdownAppBaseDir}/getdown.txt")
2379 getdownTxt.write(getdownTextLines.join("\n"))
2381 getdownLaunchJvl = getdown_launch_jvl_name + ( (jvlChannelName != null && jvlChannelName.length() > 0)?"-${jvlChannelName}":"" ) + ".jvl"
2382 def launchJvl = file("${getdownAppBaseDir}/${getdownLaunchJvl}")
2383 launchJvl.write("appbase=${getdownAppBase}")
2385 // files going into the getdown website dir: getdown-launcher.jar
2387 from getdownLauncher
2388 rename(file(getdownLauncher).getName(), getdown_launcher_new)
2389 into getdownAppBaseDir
2392 // files going into the getdown website dir: getdown-launcher(-local).jar
2394 from getdownLauncher
2395 if (file(getdownLauncher).getName() != getdown_launcher) {
2396 rename(file(getdownLauncher).getName(), getdown_launcher)
2398 into getdownAppBaseDir
2401 // files going into the getdown website dir: ./install dir and files
2402 if (! (CHANNEL.startsWith("ARCHIVE") || CHANNEL.startsWith("DEVELOP"))) {
2405 from getdownLauncher
2406 from "${getdownAppDir}/${getdown_build_properties}"
2407 if (file(getdownLauncher).getName() != getdown_launcher) {
2408 rename(file(getdownLauncher).getName(), getdown_launcher)
2410 into getdownInstallDir
2413 // and make a copy in the getdown files dir (these are not downloaded by getdown)
2415 from getdownInstallDir
2416 into getdownFilesInstallDir
2420 // files going into the getdown files dir: getdown.txt, getdown-launcher.jar, channel-launch.jvl, build_properties
2424 from getdownLauncher
2425 from "${getdownAppBaseDir}/${getdown_build_properties}"
2426 from "${getdownAppBaseDir}/${channel_props}"
2427 if (file(getdownLauncher).getName() != getdown_launcher) {
2428 rename(file(getdownLauncher).getName(), getdown_launcher)
2430 into getdownFilesDir
2433 // and ./resource (not all downloaded by getdown)
2435 from getdownResourceDir
2436 into "${getdownFilesDir}/${getdown_resource_dir}"
2441 inputs.dir("${jalviewDir}/${package_dir}")
2443 outputs.dir(getdownAppBaseDir)
2444 outputs.dir(getdownFilesDir)
2448 // a helper task to allow getdown digest of any dir: `gradle getdownDigestDir -PDIGESTDIR=/path/to/my/random/getdown/dir
2449 task getdownDigestDir(type: JavaExec) {
2451 description "A task to run a getdown Digest on a dir with getdown.txt. Provide a DIGESTDIR property via -PDIGESTDIR=..."
2453 def digestDirPropertyName = "DIGESTDIR"
2455 classpath = files(getdownLauncher)
2456 def digestDir = findProperty(digestDirPropertyName)
2457 if (digestDir == null) {
2458 throw new GradleException("Must provide a DIGESTDIR value to produce an alternative getdown digest")
2462 main = "com.threerings.getdown.tools.Digester"
2466 task getdownDigest(type: JavaExec) {
2467 group = "distribution"
2468 description = "Digest the getdown website folder"
2469 dependsOn getdownWebsite
2471 classpath = files(getdownLauncher)
2473 main = "com.threerings.getdown.tools.Digester"
2474 args getdownAppBaseDir
2475 inputs.dir(getdownAppBaseDir)
2476 outputs.file("${getdownAppBaseDir}/digest2.txt")
2481 group = "distribution"
2482 description = "Create the minimal and full getdown app folder for installers and website and create digest file"
2483 dependsOn getdownDigest
2485 if (reportRsyncCommand) {
2486 def fromDir = getdownAppBaseDir + (getdownAppBaseDir.endsWith('/')?'':'/')
2487 def toDir = "${getdown_rsync_dest}/${getdownDir}" + (getdownDir.endsWith('/')?'':'/')
2488 println "LIKELY RSYNC COMMAND:"
2489 println "mkdir -p '$toDir'\nrsync -avh --delete '$fromDir' '$toDir'"
2490 if (RUNRSYNC == "true") {
2492 commandLine "mkdir", "-p", toDir
2495 commandLine "rsync", "-avh", "--delete", fromDir, toDir
2503 task getdownArchiveBuild() {
2504 group = "distribution"
2505 description = "Put files in the archive dir to go on the website"
2507 dependsOn getdownWebsite
2509 def v = "v${JALVIEW_VERSION_UNDERSCORES}"
2510 def vDir = "${getdownArchiveDir}/${v}"
2511 getdownFullArchiveDir = "${vDir}/getdown"
2512 getdownVersionLaunchJvl = "${vDir}/jalview-${v}.jvl"
2514 def vAltDir = "alt_${v}"
2515 def archiveImagesDir = "${jalviewDir}/${channel_properties_dir}/old/images"
2518 // cleanup old "old" dir
2519 delete getdownArchiveDir
2521 def getdownArchiveTxt = file("${getdownFullArchiveDir}/getdown.txt")
2522 getdownArchiveTxt.getParentFile().mkdirs()
2523 def getdownArchiveTextLines = []
2524 def getdownFullArchiveAppBase = "${getdownArchiveAppBase}${getdownArchiveAppBase.endsWith("/")?"":"/"}${v}/getdown/"
2528 from "${getdownAppBaseDir}/${getdownAppDistDir}"
2529 into "${getdownFullArchiveDir}/${vAltDir}"
2532 getdownTextLines.each { line ->
2533 line = line.replaceAll("^(?<s>appbase\\s*=\\s*).*", '${s}'+getdownFullArchiveAppBase)
2534 line = line.replaceAll("^(?<s>(resource|code)\\s*=\\s*)${getdownAppDistDir}/", '${s}'+vAltDir+"/")
2535 line = line.replaceAll("^(?<s>ui.background_image\\s*=\\s*).*\\.png", '${s}'+"${getdown_resource_dir}/jalview_archive_getdown_background.png")
2536 line = line.replaceAll("^(?<s>ui.instant_background_image\\s*=\\s*).*\\.png", '${s}'+"${getdown_resource_dir}/jalview_archive_getdown_background_initialising.png")
2537 line = line.replaceAll("^(?<s>ui.error_background\\s*=\\s*).*\\.png", '${s}'+"${getdown_resource_dir}/jalview_archive_getdown_background_error.png")
2538 line = line.replaceAll("^(?<s>ui.progress_image\\s*=\\s*).*\\.png", '${s}'+"${getdown_resource_dir}/jalview_archive_getdown_progress_bar.png")
2539 // remove the existing resource = resource/ or bin/ lines
2540 if (! line.matches("resource\\s*=\\s*(resource|bin)/.*")) {
2541 getdownArchiveTextLines += line
2545 // the resource dir -- add these files as resource lines in getdown.txt
2547 from "${archiveImagesDir}"
2548 into "${getdownFullArchiveDir}/${getdown_resource_dir}"
2550 getdownArchiveTextLines += "resource = ${getdown_resource_dir}/${file.getName()}"
2554 getdownArchiveTxt.write(getdownArchiveTextLines.join("\n"))
2556 def vLaunchJvl = file(getdownVersionLaunchJvl)
2557 vLaunchJvl.getParentFile().mkdirs()
2558 vLaunchJvl.write("appbase=${getdownFullArchiveAppBase}\n")
2559 def vLaunchJvlPath = vLaunchJvl.toPath().toAbsolutePath()
2560 def jvlLinkPath = file("${vDir}/jalview.jvl").toPath().toAbsolutePath()
2561 // for some reason filepath.relativize(fileInSameDirPath) gives a path to "../" which is wrong
2562 //java.nio.file.Files.createSymbolicLink(jvlLinkPath, jvlLinkPath.relativize(vLaunchJvlPath));
2563 java.nio.file.Files.createSymbolicLink(jvlLinkPath, java.nio.file.Paths.get(".",vLaunchJvl.getName()));
2565 // files going into the getdown files dir: getdown.txt, getdown-launcher.jar, channel-launch.jvl, build_properties
2567 from getdownLauncher
2568 from "${getdownAppBaseDir}/${getdownLaunchJvl}"
2569 from "${getdownAppBaseDir}/${getdown_launcher_new}"
2570 from "${getdownAppBaseDir}/${channel_props}"
2571 if (file(getdownLauncher).getName() != getdown_launcher) {
2572 rename(file(getdownLauncher).getName(), getdown_launcher)
2574 into getdownFullArchiveDir
2580 task getdownArchiveDigest(type: JavaExec) {
2581 group = "distribution"
2582 description = "Digest the getdown archive folder"
2584 dependsOn getdownArchiveBuild
2587 classpath = files(getdownLauncher)
2588 args getdownFullArchiveDir
2590 main = "com.threerings.getdown.tools.Digester"
2591 inputs.dir(getdownFullArchiveDir)
2592 outputs.file("${getdownFullArchiveDir}/digest2.txt")
2595 task getdownArchive() {
2596 group = "distribution"
2597 description = "Build the website archive dir with getdown digest"
2599 dependsOn getdownArchiveBuild
2600 dependsOn getdownArchiveDigest
2603 tasks.withType(JavaCompile) {
2604 options.encoding = 'UTF-8'
2610 delete getdownAppBaseDir
2611 delete getdownFilesDir
2612 delete getdownArchiveDir
2618 if (file(install4jHomeDir).exists()) {
2620 } else if (file(System.getProperty("user.home")+"/buildtools/install4j").exists()) {
2621 install4jHomeDir = System.getProperty("user.home")+"/buildtools/install4j"
2622 } else if (file("/Applications/install4j.app/Contents/Resources/app").exists()) {
2623 install4jHomeDir = "/Applications/install4j.app/Contents/Resources/app"
2625 installDir(file(install4jHomeDir))
2627 mediaTypes = Arrays.asList(install4j_media_types.split(","))
2631 task copyInstall4jTemplate {
2632 def install4jTemplateFile = file("${install4jDir}/${install4j_template}")
2633 def install4jFileAssociationsFile = file("${install4jDir}/${install4j_installer_file_associations}")
2634 inputs.file(install4jTemplateFile)
2635 inputs.file(install4jFileAssociationsFile)
2636 inputs.property("CHANNEL", { CHANNEL })
2637 outputs.file(install4jConfFile)
2640 def install4jConfigXml = new XmlParser().parse(install4jTemplateFile)
2642 // turn off code signing if no OSX_KEYPASS
2643 if (OSX_KEYPASS == "") {
2644 install4jConfigXml.'**'.codeSigning.each { codeSigning ->
2645 codeSigning.'@macEnabled' = "false"
2647 install4jConfigXml.'**'.windows.each { windows ->
2648 windows.'@runPostProcessor' = "false"
2652 // disable install screen for OSX dmg (for 2.11.2.0)
2653 install4jConfigXml.'**'.macosArchive.each { macosArchive ->
2654 macosArchive.attributes().remove('executeSetupApp')
2655 macosArchive.attributes().remove('setupAppId')
2658 // turn off checksum creation for LOCAL channel
2659 def e = install4jConfigXml.application[0]
2660 e.'@createChecksums' = string(install4jCheckSums)
2662 // put file association actions where placeholder action is
2663 def install4jFileAssociationsText = install4jFileAssociationsFile.text
2664 def fileAssociationActions = new XmlParser().parseText("<actions>${install4jFileAssociationsText}</actions>")
2665 install4jConfigXml.'**'.action.any { a -> // .any{} stops after the first one that returns true
2666 if (a.'@name' == 'EXTENSIONS_REPLACED_BY_GRADLE') {
2667 def parent = a.parent()
2669 fileAssociationActions.each { faa ->
2672 // don't need to continue in .any loop once replacements have been made
2677 // use Windows Program Group with Examples folder for RELEASE, and Program Group without Examples for everything else
2678 // NB we're deleting the /other/ one!
2679 // Also remove the examples subdir from non-release versions
2680 def customizedIdToDelete = "PROGRAM_GROUP_RELEASE"
2681 // 2.11.1.0 NOT releasing with the Examples folder in the Program Group
2682 if (false && CHANNEL=="RELEASE") { // remove 'false && ' to include Examples folder in RELEASE channel
2683 customizedIdToDelete = "PROGRAM_GROUP_NON_RELEASE"
2685 // remove the examples subdir from Full File Set
2686 def files = install4jConfigXml.files[0]
2687 def fileset = files.filesets.fileset.find { fs -> fs.'@customizedId' == "FULL_FILE_SET" }
2688 def root = files.roots.root.find { r -> r.'@fileset' == fileset.'@id' }
2689 def mountPoint = files.mountPoints.mountPoint.find { mp -> mp.'@root' == root.'@id' }
2690 def dirEntry = files.entries.dirEntry.find { de -> de.'@mountPoint' == mountPoint.'@id' && de.'@subDirectory' == "examples" }
2691 dirEntry.parent().remove(dirEntry)
2693 install4jConfigXml.'**'.action.any { a ->
2694 if (a.'@customizedId' == customizedIdToDelete) {
2695 def parent = a.parent()
2701 // write install4j file
2702 install4jConfFile.text = XmlUtil.serialize(install4jConfigXml)
2709 delete install4jConfFile
2713 task cleanInstallersDataFiles {
2714 def installersOutputTxt = file("${jalviewDir}/${install4jBuildDir}/output.txt")
2715 def installersSha256 = file("${jalviewDir}/${install4jBuildDir}/sha256sums")
2716 def hugoDataJsonFile = file("${jalviewDir}/${install4jBuildDir}/installers-${JALVIEW_VERSION_UNDERSCORES}.json")
2718 delete installersOutputTxt
2719 delete installersSha256
2720 delete hugoDataJsonFile
2724 task install4jDMGBackgroundImageCopy {
2725 inputs.file "${install4jDMGBackgroundImageDir}/${install4jDMGBackgroundImageFile}"
2726 outputs.dir "${install4jDMGBackgroundImageBuildDir}"
2729 from(install4jDMGBackgroundImageDir) {
2730 include(install4jDMGBackgroundImageFile)
2732 into install4jDMGBackgroundImageBuildDir
2737 task install4jDMGBackgroundImageProcess {
2738 dependsOn install4jDMGBackgroundImageCopy
2741 if (backgroundImageText) {
2742 if (convertBinary == null) {
2743 throw new StopExecutionException("No ImageMagick convert binary installed at '${convertBinaryExpectedLocation}'")
2745 if (!project.hasProperty("install4j_background_image_text_suffix_cmd")) {
2746 throw new StopExecutionException("No property 'install4j_background_image_text_suffix_cmd' defined. See channel_gradle.properties for channel ${CHANNEL}")
2748 fileTree(dir: install4jDMGBackgroundImageBuildDir, include: "*.png").getFiles().each { file ->
2750 executable convertBinary
2753 '-font', install4j_background_image_text_font,
2754 '-fill', install4j_background_image_text_colour,
2755 '-draw', sprintf(install4j_background_image_text_suffix_cmd, channelSuffix),
2756 '-draw', sprintf(install4j_background_image_text_commit_cmd, "git-commit: ${gitHash}"),
2757 '-draw', sprintf(install4j_background_image_text_date_cmd, getDate("yyyy-MM-dd HH:mm:ss")),
2766 task install4jDMGBackgroundImage {
2767 dependsOn install4jDMGBackgroundImageProcess
2770 task installerFiles(type: com.install4j.gradle.Install4jTask) {
2771 group = "distribution"
2772 description = "Create the install4j installers"
2774 dependsOn copyInstall4jTemplate
2775 dependsOn cleanInstallersDataFiles
2776 dependsOn install4jDMGBackgroundImage
2778 projectFile = install4jConfFile
2780 // create an md5 for the input files to use as version for install4j conf file
2781 def digest = MessageDigest.getInstance("MD5")
2783 (file("${install4jDir}/${install4j_template}").text +
2784 file("${install4jDir}/${install4j_info_plist_file_associations}").text +
2785 file("${install4jDir}/${install4j_installer_file_associations}").text).bytes)
2786 def filesMd5 = new BigInteger(1, digest.digest()).toString(16)
2787 if (filesMd5.length() >= 8) {
2788 filesMd5 = filesMd5.substring(0,8)
2790 def install4jTemplateVersion = "${JALVIEW_VERSION}_F${filesMd5}_C${gitHash}"
2793 'JALVIEW_NAME': jalview_name,
2794 'JALVIEW_APPLICATION_NAME': applicationName,
2795 'JALVIEW_DIR': "../..",
2796 'OSX_KEYSTORE': OSX_KEYSTORE,
2797 'OSX_APPLEID': OSX_APPLEID,
2798 'OSX_ALTOOLPASS': OSX_ALTOOLPASS,
2799 'JSIGN_SH': JSIGN_SH,
2800 'JRE_DIR': getdown_app_dir_java,
2801 'INSTALLER_TEMPLATE_VERSION': install4jTemplateVersion,
2802 'JALVIEW_VERSION': JALVIEW_VERSION,
2803 'JAVA_MIN_VERSION': JAVA_MIN_VERSION,
2804 'JAVA_MAX_VERSION': JAVA_MAX_VERSION,
2805 'JAVA_VERSION': JAVA_VERSION,
2806 'JAVA_INTEGER_VERSION': JAVA_INTEGER_VERSION,
2807 'VERSION': JALVIEW_VERSION,
2808 'COPYRIGHT_MESSAGE': install4j_copyright_message,
2809 'BUNDLE_ID': install4jBundleId,
2810 'INTERNAL_ID': install4jInternalId,
2811 'WINDOWS_APPLICATION_ID': install4jWinApplicationId,
2812 'MACOS_DMG_DS_STORE': install4jDMGDSStore,
2813 'MACOS_DMG_BG_IMAGE': "${install4jDMGBackgroundImageBuildDir}/${install4jDMGBackgroundImageFile}",
2814 'WRAPPER_LINK': getdownWrapperLink,
2815 'BASH_WRAPPER_SCRIPT': getdown_bash_wrapper_script,
2816 'POWERSHELL_WRAPPER_SCRIPT': getdown_powershell_wrapper_script,
2817 'BATCH_WRAPPER_SCRIPT': getdown_batch_wrapper_script,
2818 'WRAPPER_SCRIPT_BIN_DIR': getdown_wrapper_script_dir,
2819 'INSTALLER_NAME': install4jInstallerName,
2820 'INSTALL4J_UTILS_DIR': install4j_utils_dir,
2821 'GETDOWN_CHANNEL_DIR': getdownChannelDir,
2822 'GETDOWN_FILES_DIR': getdown_files_dir,
2823 'GETDOWN_RESOURCE_DIR': getdown_resource_dir,
2824 'GETDOWN_DIST_DIR': getdownAppDistDir,
2825 'GETDOWN_ALT_DIR': getdown_app_dir_alt,
2826 'GETDOWN_INSTALL_DIR': getdown_install_dir,
2827 'INFO_PLIST_FILE_ASSOCIATIONS_FILE': install4j_info_plist_file_associations,
2828 'BUILD_DIR': install4jBuildDir,
2829 'APPLICATION_CATEGORIES': install4j_application_categories,
2830 'APPLICATION_FOLDER': install4jApplicationFolder,
2831 'UNIX_APPLICATION_FOLDER': install4jUnixApplicationFolder,
2832 'EXECUTABLE_NAME': install4jExecutableName,
2833 'EXTRA_SCHEME': install4jExtraScheme,
2834 'MAC_ICONS_FILE': install4jMacIconsFile,
2835 'WINDOWS_ICONS_FILE': install4jWindowsIconsFile,
2836 'PNG_ICON_FILE': install4jPngIconFile,
2837 'BACKGROUND': install4jBackground,
2842 'windows': 'WINDOWS',
2846 // these are the bundled OS/architecture VMs needed by install4j
2849 [ "mac", "aarch64" ],
2850 [ "windows", "x64" ],
2852 [ "linux", "aarch64" ]
2854 osArch.forEach { os, arch ->
2855 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)
2856 // N.B. For some reason install4j requires the below filename to have underscores and not hyphens
2857 // otherwise running `gradle installers` generates a non-useful error:
2858 // `install4j: compilation failed. Reason: java.lang.NumberFormatException: For input string: "windows"`
2859 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)
2862 //println("INSTALL4J VARIABLES:")
2863 //variables.each{k,v->println("${k}=${v}")}
2865 destination = "${jalviewDir}/${install4jBuildDir}"
2866 buildSelected = true
2868 if (install4j_faster.equals("true") || CHANNEL.startsWith("LOCAL")) {
2870 disableSigning = true
2871 disableNotarization = true
2875 macKeystorePassword = OSX_KEYPASS
2878 if (OSX_ALTOOLPASS) {
2879 appleIdPassword = OSX_ALTOOLPASS
2880 disableNotarization = false
2882 disableNotarization = true
2886 println("Using projectFile "+projectFile)
2887 if (!disableNotarization) { println("Will notarize OSX App DMG") }
2891 inputs.dir(getdownAppBaseDir)
2892 inputs.file(install4jConfFile)
2893 inputs.file("${install4jDir}/${install4j_info_plist_file_associations}")
2894 outputs.dir("${jalviewDir}/${install4j_build_dir}/${JAVA_VERSION}")
2897 def getDataHash(File myFile) {
2898 HashCode hash = Files.asByteSource(myFile).hash(Hashing.sha256())
2899 return myFile.exists()
2901 "file" : myFile.getName(),
2902 "filesize" : myFile.length(),
2903 "sha256" : hash.toString()
2908 def writeDataJsonFile(File installersOutputTxt, File installersSha256, File dataJsonFile) {
2910 "channel" : getdownChannelName,
2911 "date" : getDate("yyyy-MM-dd HH:mm:ss"),
2912 "git-commit" : "${gitHash} [${gitBranch}]",
2913 "version" : JALVIEW_VERSION
2915 // install4j installer files
2916 if (installersOutputTxt.exists()) {
2918 installersOutputTxt.readLines().each { def line ->
2919 if (line.startsWith("#")) {
2922 line.replaceAll("\n","")
2923 def vals = line.split("\t")
2924 def filename = vals[3]
2925 def filesize = file(filename).length()
2926 filename = filename.replaceAll(/^.*\//, "")
2927 hash[vals[0]] = [ "id" : vals[0], "os" : vals[1], "name" : vals[2], "file" : filename, "filesize" : filesize ]
2928 idHash."${filename}" = vals[0]
2930 if (install4jCheckSums && installersSha256.exists()) {
2931 installersSha256.readLines().each { def line ->
2932 if (line.startsWith("#")) {
2935 line.replaceAll("\n","")
2936 def vals = line.split(/\s+\*?/)
2937 def filename = vals[1]
2938 def innerHash = (hash.(idHash."${filename}"))."sha256" = vals[0]
2944 "JAR": shadowJar.archiveFile, // executable JAR
2945 "JVL": getdownVersionLaunchJvl, // version JVL
2946 "SOURCE": sourceDist.archiveFile // source TGZ
2947 ].each { key, value ->
2948 def file = file(value)
2949 if (file.exists()) {
2950 def fileHash = getDataHash(file)
2951 if (fileHash != null) {
2952 hash."${key}" = fileHash;
2956 return dataJsonFile.write(new JsonBuilder(hash).toPrettyString())
2959 task staticMakeInstallersJsonFile {
2961 def output = findProperty("i4j_output")
2962 def sha256 = findProperty("i4j_sha256")
2963 def json = findProperty("i4j_json")
2964 if (output == null || sha256 == null || json == null) {
2965 throw new GradleException("Must provide paths to all of output.txt, sha256sums, and output.json with '-Pi4j_output=... -Pi4j_sha256=... -Pi4j_json=...")
2967 writeDataJsonFile(file(output), file(sha256), file(json))
2972 dependsOn installerFiles
2978 eclipse().configFile(eclipse_codestyle_file)
2982 task createSourceReleaseProperties(type: WriteProperties) {
2983 group = "distribution"
2984 description = "Create the source RELEASE properties file"
2986 def sourceTarBuildDir = "${buildDir}/sourceTar"
2987 def sourceReleasePropertiesFile = "${sourceTarBuildDir}/RELEASE"
2988 outputFile (sourceReleasePropertiesFile)
2991 releaseProps.each{ key, val -> property key, val }
2992 property "git.branch", gitBranch
2993 property "git.hash", gitHash
2996 outputs.file(outputFile)
2999 task sourceDist(type: Tar) {
3000 group "distribution"
3001 description "Create a source .tar.gz file for distribution"
3003 dependsOn createBuildProperties
3004 dependsOn convertMdFiles
3005 dependsOn eclipseAllPreferences
3006 dependsOn createSourceReleaseProperties
3009 def outputFileName = "${project.name}_${JALVIEW_VERSION_UNDERSCORES}.tar.gz"
3010 archiveFileName = outputFileName
3012 compression Compression.GZIP
3027 "**/*.class","$j11modDir/**/*.jar","appletlib","**/*locales",
3029 "utils/InstallAnywhere",
3044 "gradle.properties",
3056 ".settings/org.eclipse.buildship.core.prefs",
3057 ".settings/org.eclipse.jdt.core.prefs"
3061 exclude (EXCLUDE_FILES)
3062 include (PROCESS_FILES)
3063 filter(ReplaceTokens,
3067 'Version-Rel': JALVIEW_VERSION,
3068 'Year-Rel': getDate("yyyy")
3073 exclude (EXCLUDE_FILES)
3074 exclude (PROCESS_FILES)
3075 exclude ("appletlib")
3076 exclude ("**/*locales")
3077 exclude ("*locales/**")
3078 exclude ("utils/InstallAnywhere")
3080 exclude (getdown_files_dir)
3081 // getdown_website_dir and getdown_archive_dir moved to build/website/docroot/getdown
3082 //exclude (getdown_website_dir)
3083 //exclude (getdown_archive_dir)
3085 // exluding these as not using jars as modules yet
3086 exclude ("${j11modDir}/**/*.jar")
3089 include(INCLUDE_FILES)
3091 // from (jalviewDir) {
3092 // // explicit includes for stuff that seemed to not get included
3093 // include(fileTree("test/**/*."))
3094 // exclude(EXCLUDE_FILES)
3095 // exclude(PROCESS_FILES)
3098 from(file(buildProperties).getParent()) {
3099 include(file(buildProperties).getName())
3100 rename(file(buildProperties).getName(), "build_properties")
3102 line.replaceAll("^INSTALLATION=.*\$","INSTALLATION=Source Release"+" git-commit\\\\:"+gitHash+" ["+gitBranch+"]")
3106 def sourceTarBuildDir = "${buildDir}/sourceTar"
3107 from(sourceTarBuildDir) {
3108 // this includes the appended RELEASE properties file
3112 task dataInstallersJson {
3114 description "Create the installers-VERSION.json data file for installer files created"
3116 mustRunAfter installers
3117 mustRunAfter shadowJar
3118 mustRunAfter sourceDist
3119 mustRunAfter getdownArchive
3121 def installersOutputTxt = file("${jalviewDir}/${install4jBuildDir}/output.txt")
3122 def installersSha256 = file("${jalviewDir}/${install4jBuildDir}/sha256sums")
3124 if (installersOutputTxt.exists()) {
3125 inputs.file(installersOutputTxt)
3127 if (install4jCheckSums && installersSha256.exists()) {
3128 inputs.file(installersSha256)
3131 shadowJar.archiveFile, // executable JAR
3132 getdownVersionLaunchJvl, // version JVL
3133 sourceDist.archiveFile // source TGZ
3134 ].each { fileName ->
3135 if (file(fileName).exists()) {
3136 inputs.file(fileName)
3140 outputs.file(hugoDataJsonFile)
3143 writeDataJsonFile(installersOutputTxt, installersSha256, hugoDataJsonFile)
3149 description "Copies all help pages to build dir. Runs ant task 'pubhtmlhelp'."
3152 dependsOn pubhtmlhelp
3154 inputs.dir("${helpBuildDir}/${help_dir}")
3155 outputs.dir("${buildDir}/distributions/${help_dir}")
3159 task j2sSetHeadlessBuild {
3166 task jalviewjsEnableAltFileProperty(type: WriteProperties) {
3168 description "Enable the alternative J2S Config file for headless build"
3170 outputFile = jalviewjsJ2sSettingsFileName
3171 def j2sPropsFile = file(jalviewjsJ2sSettingsFileName)
3172 def j2sProps = new Properties()
3173 if (j2sPropsFile.exists()) {
3175 def j2sPropsFileFIS = new FileInputStream(j2sPropsFile)
3176 j2sProps.load(j2sPropsFileFIS)
3177 j2sPropsFileFIS.close()
3179 j2sProps.each { prop, val ->
3182 } catch (Exception e) {
3183 println("Exception reading ${jalviewjsJ2sSettingsFileName}")
3187 if (! j2sProps.stringPropertyNames().contains(jalviewjs_j2s_alt_file_property_config)) {
3188 property(jalviewjs_j2s_alt_file_property_config, jalviewjs_j2s_alt_file_property)
3193 task jalviewjsSetEclipseWorkspace {
3194 def propKey = "jalviewjs_eclipse_workspace"
3196 if (project.hasProperty(propKey)) {
3197 propVal = project.getProperty(propKey)
3198 if (propVal.startsWith("~/")) {
3199 propVal = System.getProperty("user.home") + propVal.substring(1)
3202 def propsFileName = "${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_eclipse_workspace_location_file}"
3203 def propsFile = file(propsFileName)
3204 def eclipseWsDir = propVal
3205 def props = new Properties()
3207 def writeProps = true
3208 if (( eclipseWsDir == null || !file(eclipseWsDir).exists() ) && propsFile.exists()) {
3209 def ins = new FileInputStream(propsFileName)
3212 if (props.getProperty(propKey, null) != null) {
3213 eclipseWsDir = props.getProperty(propKey)
3218 if (eclipseWsDir == null || !file(eclipseWsDir).exists()) {
3219 def tempDir = File.createTempDir()
3220 eclipseWsDir = tempDir.getAbsolutePath()
3223 eclipseWorkspace = file(eclipseWsDir)
3226 // do not run a headless transpile when we claim to be in Eclipse
3228 println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3229 throw new StopExecutionException("Not running headless transpile whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
3231 println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3235 props.setProperty(propKey, eclipseWsDir)
3236 propsFile.parentFile.mkdirs()
3237 def bytes = new ByteArrayOutputStream()
3238 props.store(bytes, null)
3239 def propertiesString = bytes.toString()
3240 propsFile.text = propertiesString
3246 println("ECLIPSE WORKSPACE: "+eclipseWorkspace.getPath())
3249 //inputs.property(propKey, eclipseWsDir) // eclipseWsDir only gets set once this task runs, so will be out-of-date
3250 outputs.file(propsFileName)
3251 outputs.upToDateWhen { eclipseWorkspace.exists() && propsFile.exists() }
3255 task jalviewjsEclipsePaths {
3258 def eclipseRoot = jalviewjs_eclipse_root
3259 if (eclipseRoot.startsWith("~/")) {
3260 eclipseRoot = System.getProperty("user.home") + eclipseRoot.substring(1)
3262 if (OperatingSystem.current().isMacOsX()) {
3263 eclipseRoot += "/Eclipse.app"
3264 eclipseBinary = "${eclipseRoot}/Contents/MacOS/eclipse"
3265 eclipseProduct = "${eclipseRoot}/Contents/Eclipse/.eclipseproduct"
3266 } else if (OperatingSystem.current().isWindows()) { // check these paths!!
3267 if (file("${eclipseRoot}/eclipse").isDirectory() && file("${eclipseRoot}/eclipse/.eclipseproduct").exists()) {
3268 eclipseRoot += "/eclipse"
3270 eclipseBinary = "${eclipseRoot}/eclipse.exe"
3271 eclipseProduct = "${eclipseRoot}/.eclipseproduct"
3272 } else { // linux or unix
3273 if (file("${eclipseRoot}/eclipse").isDirectory() && file("${eclipseRoot}/eclipse/.eclipseproduct").exists()) {
3274 eclipseRoot += "/eclipse"
3275 println("eclipseDir exists")
3277 eclipseBinary = "${eclipseRoot}/eclipse"
3278 eclipseProduct = "${eclipseRoot}/.eclipseproduct"
3281 eclipseVersion = "4.13" // default
3282 def assumedVersion = true
3283 if (file(eclipseProduct).exists()) {
3284 def fis = new FileInputStream(eclipseProduct)
3285 def props = new Properties()
3287 eclipseVersion = props.getProperty("version")
3289 assumedVersion = false
3292 def propKey = "eclipse_debug"
3293 eclipseDebug = (project.hasProperty(propKey) && project.getProperty(propKey).equals("true"))
3296 // do not run a headless transpile when we claim to be in Eclipse
3298 println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3299 throw new StopExecutionException("Not running headless transpile whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
3301 println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3304 if (!assumedVersion) {
3305 println("ECLIPSE VERSION=${eclipseVersion}")
3311 task printProperties {
3313 description "Output to console all System.properties"
3315 System.properties.each { key, val -> System.out.println("Property: ${key}=${val}") }
3321 dependsOn eclipseProject
3322 dependsOn eclipseClasspath
3323 dependsOn eclipseJdt
3327 // this version (type: Copy) will delete anything in the eclipse dropins folder that isn't in fromDropinsDir
3328 task jalviewjsEclipseCopyDropins(type: Copy) {
3329 dependsOn jalviewjsEclipsePaths
3331 def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjs_eclipse_dropins_dir}", include: "*.jar")
3332 inputFiles += file("${jalviewDir}/${jalviewjsJ2sPlugin}")
3333 def destinationDirectory = "${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_eclipse_tmp_dropins_dir}"
3336 into destinationDirectory
3340 // this eclipse -clean doesn't actually work
3341 task jalviewjsCleanEclipse(type: Exec) {
3342 dependsOn eclipseSetup
3343 dependsOn jalviewjsEclipsePaths
3344 dependsOn jalviewjsEclipseCopyDropins
3346 executable(eclipseBinary)
3347 args(["-nosplash", "--launcher.suppressErrors", "-data", eclipseWorkspace.getPath(), "-clean", "-console", "-consoleLog"])
3353 def inputString = """exit
3356 def inputByteStream = new ByteArrayInputStream(inputString.getBytes())
3357 standardInput = inputByteStream
3360 /* not really working yet
3361 jalviewjsEclipseCopyDropins.finalizedBy jalviewjsCleanEclipse
3365 task jalviewjsTransferUnzipSwingJs {
3366 def file_zip = "${jalviewDir}/${jalviewjs_swingjs_zip}"
3370 from zipTree(file_zip)
3371 into "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}"
3375 inputs.file file_zip
3376 outputs.dir "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}"
3380 task jalviewjsTransferUnzipLib {
3381 def zipFiles = fileTree(dir: "${jalviewDir}/${jalviewjs_libjs_dir}", include: "*.zip")
3384 zipFiles.each { file_zip ->
3386 from zipTree(file_zip)
3387 into "${jalviewDir}/${jalviewjsTransferSiteLibDir}"
3392 inputs.files zipFiles
3393 outputs.dir "${jalviewDir}/${jalviewjsTransferSiteLibDir}"
3397 task jalviewjsTransferUnzipAllLibs {
3398 dependsOn jalviewjsTransferUnzipSwingJs
3399 dependsOn jalviewjsTransferUnzipLib
3403 task jalviewjsCreateJ2sSettings(type: WriteProperties) {
3405 description "Create the alternative j2s file from the j2s.* properties"
3407 jalviewjsJ2sProps = project.properties.findAll { it.key.startsWith("j2s.") }.sort { it.key }
3408 def siteDirProperty = "j2s.site.directory"
3409 def setSiteDir = false
3410 jalviewjsJ2sProps.each { prop, val ->
3412 if (prop == siteDirProperty) {
3413 if (!(val.startsWith('/') || val.startsWith("file://") )) {
3414 val = "${jalviewDir}/${jalviewjsTransferSiteJsDir}/${val}"
3420 if (!setSiteDir) { // default site location, don't override specifically set property
3421 property(siteDirProperty,"${jalviewDirRelativePath}/${jalviewjsTransferSiteJsDir}")
3424 outputFile = jalviewjsJ2sAltSettingsFileName
3427 inputs.properties(jalviewjsJ2sProps)
3428 outputs.file(jalviewjsJ2sAltSettingsFileName)
3433 task jalviewjsEclipseSetup {
3434 dependsOn jalviewjsEclipseCopyDropins
3435 dependsOn jalviewjsSetEclipseWorkspace
3436 dependsOn jalviewjsCreateJ2sSettings
3440 task jalviewjsSyncAllLibs (type: Sync) {
3441 dependsOn jalviewjsTransferUnzipAllLibs
3442 def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjsTransferSiteLibDir}")
3443 inputFiles += fileTree(dir: "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}")
3444 def destinationDirectory = "${jalviewDir}/${jalviewjsSiteDir}"
3447 into destinationDirectory
3448 def outputFiles = []
3449 rename { filename ->
3450 outputFiles += "${destinationDirectory}/${filename}"
3457 // should this be exclude really ?
3458 duplicatesStrategy "INCLUDE"
3460 outputs.files outputFiles
3461 inputs.files inputFiles
3465 task jalviewjsSyncResources (type: Sync) {
3466 dependsOn buildResources
3468 def inputFiles = fileTree(dir: resourcesBuildDir)
3469 def destinationDirectory = "${jalviewDir}/${jalviewjsSiteDir}/${jalviewjs_j2s_subdir}"
3472 into destinationDirectory
3473 def outputFiles = []
3474 rename { filename ->
3475 outputFiles += "${destinationDirectory}/${filename}"
3481 outputs.files outputFiles
3482 inputs.files inputFiles
3486 task jalviewjsSyncSiteResources (type: Sync) {
3487 def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjs_site_resource_dir}")
3488 def destinationDirectory = "${jalviewDir}/${jalviewjsSiteDir}"
3491 into destinationDirectory
3492 def outputFiles = []
3493 rename { filename ->
3494 outputFiles += "${destinationDirectory}/${filename}"
3500 outputs.files outputFiles
3501 inputs.files inputFiles
3505 task jalviewjsSyncBuildProperties (type: Sync) {
3506 dependsOn createBuildProperties
3507 def inputFiles = [file(buildProperties)]
3508 def destinationDirectory = "${jalviewDir}/${jalviewjsSiteDir}/${jalviewjs_j2s_subdir}"
3511 into destinationDirectory
3512 def outputFiles = []
3513 rename { filename ->
3514 outputFiles += "${destinationDirectory}/${filename}"
3520 outputs.files outputFiles
3521 inputs.files inputFiles
3525 task jalviewjsProjectImport(type: Exec) {
3526 dependsOn eclipseSetup
3527 dependsOn jalviewjsEclipsePaths
3528 dependsOn jalviewjsEclipseSetup
3531 // do not run a headless import when we claim to be in Eclipse
3533 println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3534 throw new StopExecutionException("Not running headless import whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
3536 println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3540 //def projdir = eclipseWorkspace.getPath()+"/.metadata/.plugins/org.eclipse.core.resources/.projects/jalview/org.eclipse.jdt.core"
3541 def projdir = eclipseWorkspace.getPath()+"/.metadata/.plugins/org.eclipse.core.resources/.projects/jalview"
3542 executable(eclipseBinary)
3543 args(["-nosplash", "--launcher.suppressErrors", "-application", "com.seeq.eclipse.importprojects.headlessimport", "-data", eclipseWorkspace.getPath(), "-import", jalviewDirAbsolutePath])
3547 args += [ "--launcher.appendVmargs", "-vmargs", "-Dorg.eclipse.equinox.p2.reconciler.dropins.directory=${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_eclipse_tmp_dropins_dir}" ]
3549 args += [ "-D${j2sHeadlessBuildProperty}=true" ]
3550 args += [ "-D${jalviewjs_j2s_alt_file_property}=${jalviewjsJ2sAltSettingsFileName}" ]
3553 inputs.file("${jalviewDir}/.project")
3554 outputs.upToDateWhen {
3555 file(projdir).exists()
3560 task jalviewjsTranspile(type: Exec) {
3561 dependsOn jalviewjsEclipseSetup
3562 dependsOn jalviewjsProjectImport
3563 dependsOn jalviewjsEclipsePaths
3565 dependsOn jalviewjsEnableAltFileProperty
3569 // do not run a headless transpile when we claim to be in Eclipse
3571 println("Skipping task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3572 throw new StopExecutionException("Not running headless transpile whilst IN_ECLIPSE is '${IN_ECLIPSE}'")
3574 println("Running task ${name} as IN_ECLIPSE=${IN_ECLIPSE}")
3578 executable(eclipseBinary)
3579 args(["-nosplash", "--launcher.suppressErrors", "-application", "org.eclipse.jdt.apt.core.aptBuild", "-data", eclipseWorkspace, "-${jalviewjs_eclipse_build_arg}", eclipse_project_name ])
3583 args += [ "--launcher.appendVmargs", "-vmargs", "-Dorg.eclipse.equinox.p2.reconciler.dropins.directory=${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_eclipse_tmp_dropins_dir}" ]
3585 args += [ "-D${j2sHeadlessBuildProperty}=true" ]
3586 args += [ "-D${jalviewjs_j2s_alt_file_property}=${jalviewjsJ2sAltSettingsFileName}" ]
3592 stdout = new ByteArrayOutputStream()
3593 stderr = new ByteArrayOutputStream()
3595 def logOutFileName = "${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}"
3596 def logOutFile = file(logOutFileName)
3597 logOutFile.createNewFile()
3598 logOutFile.text = """ROOT: ${jalviewjs_eclipse_root}
3599 BINARY: ${eclipseBinary}
3600 VERSION: ${eclipseVersion}
3601 WORKSPACE: ${eclipseWorkspace}
3602 DEBUG: ${eclipseDebug}
3605 def logOutFOS = new FileOutputStream(logOutFile, true) // true == append
3606 // combine stdout and stderr
3607 def logErrFOS = logOutFOS
3609 if (jalviewjs_j2s_to_console.equals("true")) {
3610 standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
3611 new org.apache.tools.ant.util.TeeOutputStream(
3615 errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
3616 new org.apache.tools.ant.util.TeeOutputStream(
3621 standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
3624 errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
3631 if (stdout.toString().contains("Error processing ")) {
3632 // j2s did not complete transpile
3633 //throw new TaskExecutionException("Error during transpilation:\n${stderr}\nSee eclipse transpile log file '${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}'")
3634 if (jalviewjs_ignore_transpile_errors.equals("true")) {
3635 println("IGNORING TRANSPILE ERRORS")
3636 println("See eclipse transpile log file '${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}'")
3638 throw new GradleException("Error during transpilation:\n${stderr}\nSee eclipse transpile log file '${jalviewDir}/${jalviewjsBuildDir}/${jalviewjs_j2s_transpile_stdout}'")
3643 inputs.dir("${jalviewDir}/${sourceDir}")
3644 outputs.dir("${jalviewDir}/${jalviewjsTransferSiteJsDir}")
3645 outputs.upToDateWhen( { file("${jalviewDir}/${jalviewjsTransferSiteJsDir}${jalviewjs_server_resource}").exists() } )
3649 def jalviewjsCallCore(String name, FileCollection list, String prefixFile, String suffixFile, String jsfile, String zjsfile, File logOutFile, Boolean logOutConsole) {
3651 def stdout = new ByteArrayOutputStream()
3652 def stderr = new ByteArrayOutputStream()
3654 def coreFile = file(jsfile)
3656 msg = "Creating core for ${name}...\nGenerating ${jsfile}"
3658 logOutFile.createNewFile()
3659 logOutFile.append(msg+"\n")
3661 def coreTop = file(prefixFile)
3662 def coreBottom = file(suffixFile)
3663 coreFile.getParentFile().mkdirs()
3664 coreFile.createNewFile()
3665 coreFile.write( coreTop.getText("UTF-8") )
3669 def t = f.getText("UTF-8")
3670 t.replaceAll("Clazz\\.([^_])","Clazz_${1}")
3671 coreFile.append( t )
3673 msg = "...file '"+f.getPath()+"' does not exist, skipping"
3675 logOutFile.append(msg+"\n")
3678 coreFile.append( coreBottom.getText("UTF-8") )
3680 msg = "Generating ${zjsfile}"
3682 logOutFile.append(msg+"\n")
3683 def logOutFOS = new FileOutputStream(logOutFile, true) // true == append
3684 def logErrFOS = logOutFOS
3687 classpath = files(["${jalviewDir}/${jalviewjs_closure_compiler}"])
3688 main = "com.google.javascript.jscomp.CommandLineRunner"
3689 jvmArgs = [ "-Dfile.encoding=UTF-8" ]
3690 args = [ "--compilation_level", "SIMPLE_OPTIMIZATIONS", "--warning_level", "QUIET", "--charset", "UTF-8", "--js", jsfile, "--js_output_file", zjsfile ]
3693 msg = "\nRunning '"+commandLine.join(' ')+"'\n"
3695 logOutFile.append(msg+"\n")
3697 if (logOutConsole) {
3698 standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
3699 new org.apache.tools.ant.util.TeeOutputStream(
3703 errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
3704 new org.apache.tools.ant.util.TeeOutputStream(
3709 standardOutput = new org.apache.tools.ant.util.TeeOutputStream(
3712 errorOutput = new org.apache.tools.ant.util.TeeOutputStream(
3719 logOutFile.append(msg+"\n")
3723 task jalviewjsBuildAllCores {
3725 description "Build the core js lib closures listed in the classlists dir"
3726 dependsOn jalviewjsTranspile
3727 dependsOn jalviewjsTransferUnzipSwingJs
3729 def j2sDir = "${jalviewDir}/${jalviewjsTransferSiteJsDir}/${jalviewjs_j2s_subdir}"
3730 def swingJ2sDir = "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}/${jalviewjs_j2s_subdir}"
3731 def libJ2sDir = "${jalviewDir}/${jalviewjsTransferSiteLibDir}/${jalviewjs_j2s_subdir}"
3732 def jsDir = "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}/${jalviewjs_js_subdir}"
3733 def destinationDirectory = "${jalviewDir}/${jalviewjsTransferSiteCoreDir}/${jalviewjs_j2s_subdir}/core"
3734 def prefixFile = "${jsDir}/core/coretop2.js"
3735 def suffixFile = "${jsDir}/core/corebottom2.js"
3737 inputs.file prefixFile
3738 inputs.file suffixFile
3740 def classlistFiles = []
3741 // add the classlists found int the jalviewjs_classlists_dir
3742 fileTree(dir: "${jalviewDir}/${jalviewjs_classlists_dir}", include: "*.txt").each {
3744 def name = file.getName() - ".txt"
3751 // _jmol and _jalview cores. Add any other peculiar classlist.txt files here
3752 //classlistFiles += [ 'file': file("${jalviewDir}/${jalviewjs_classlist_jmol}"), 'name': "_jvjmol" ]
3753 classlistFiles += [ 'file': file("${jalviewDir}/${jalviewjs_classlist_jalview}"), 'name': jalviewjsJalviewCoreName ]
3755 jalviewjsCoreClasslists = []
3757 classlistFiles.each {
3760 def file = hash['file']
3761 if (! file.exists()) {
3762 //println("...classlist file '"+file.getPath()+"' does not exist, skipping")
3763 return false // this is a "continue" in groovy .each closure
3765 def name = hash['name']
3767 name = file.getName() - ".txt"
3775 def list = fileTree(dir: j2sDir, includes: filelist)
3777 def jsfile = "${destinationDirectory}/core${name}.js"
3778 def zjsfile = "${destinationDirectory}/core${name}.z.js"
3780 jalviewjsCoreClasslists += [
3789 outputs.file(jsfile)
3790 outputs.file(zjsfile)
3793 // _stevesoft core. add any cores without a classlist here (and the inputs and outputs)
3794 def stevesoftClasslistName = "_stevesoft"
3795 def stevesoftClasslist = [
3796 'jsfile': "${destinationDirectory}/core${stevesoftClasslistName}.js",
3797 'zjsfile': "${destinationDirectory}/core${stevesoftClasslistName}.z.js",
3798 'list': fileTree(dir: j2sDir, include: "com/stevesoft/pat/**/*.js"),
3799 'name': stevesoftClasslistName
3801 jalviewjsCoreClasslists += stevesoftClasslist
3802 inputs.files(stevesoftClasslist['list'])
3803 outputs.file(stevesoftClasslist['jsfile'])
3804 outputs.file(stevesoftClasslist['zjsfile'])
3807 def allClasslistName = "_all"
3808 def allJsFiles = fileTree(dir: j2sDir, include: "**/*.js")
3809 allJsFiles += fileTree(
3813 // these exlusions are files that the closure-compiler produces errors for. Should fix them
3814 "**/org/jmol/jvxl/readers/IsoIntersectFileReader.js",
3815 "**/org/jmol/export/JSExporter.js"
3818 allJsFiles += fileTree(
3822 // these exlusions are files that the closure-compiler produces errors for. Should fix them
3823 "**/sun/misc/Unsafe.js",
3824 "**/swingjs/jquery/jquery-editable-select.js",
3825 "**/swingjs/jquery/j2sComboBox.js",
3826 "**/sun/misc/FloatingDecimal.js"
3829 def allClasslist = [
3830 'jsfile': "${destinationDirectory}/core${allClasslistName}.js",
3831 'zjsfile': "${destinationDirectory}/core${allClasslistName}.z.js",
3833 'name': allClasslistName
3835 // not including this version of "all" core at the moment
3836 //jalviewjsCoreClasslists += allClasslist
3837 inputs.files(allClasslist['list'])
3838 outputs.file(allClasslist['jsfile'])
3839 outputs.file(allClasslist['zjsfile'])
3842 def logOutFile = file("${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_j2s_closure_stdout}")
3843 logOutFile.getParentFile().mkdirs()
3844 logOutFile.createNewFile()
3845 logOutFile.write(getDate("yyyy-MM-dd HH:mm:ss")+" jalviewjsBuildAllCores\n----\n")
3847 jalviewjsCoreClasslists.each {
3848 jalviewjsCallCore(it.name, it.list, prefixFile, suffixFile, it.jsfile, it.zjsfile, logOutFile, jalviewjs_j2s_to_console.equals("true"))
3855 def jalviewjsPublishCoreTemplate(String coreName, String templateName, File inputFile, String outputFile) {
3858 into file(outputFile).getParentFile()
3859 rename { filename ->
3860 if (filename.equals(inputFile.getName())) {
3861 return file(outputFile).getName()
3865 filter(ReplaceTokens,
3869 'MAIN': '"'+main_class+'"',
3871 'NAME': jalviewjsJalviewTemplateName+" [core ${coreName}]",
3872 'COREKEY': jalviewjs_core_key,
3873 'CORENAME': coreName
3880 task jalviewjsPublishCoreTemplates {
3881 dependsOn jalviewjsBuildAllCores
3882 def inputFileName = "${jalviewDir}/${j2s_coretemplate_html}"
3883 def inputFile = file(inputFileName)
3884 def destinationDirectory = "${jalviewDir}/${jalviewjsTransferSiteCoreDir}"
3886 def outputFiles = []
3887 jalviewjsCoreClasslists.each { cl ->
3888 def outputFile = "${destinationDirectory}/${jalviewjsJalviewTemplateName}_${cl.name}.html"
3889 cl['outputfile'] = outputFile
3890 outputFiles += outputFile
3894 jalviewjsCoreClasslists.each { cl ->
3895 jalviewjsPublishCoreTemplate(cl.name, jalviewjsJalviewTemplateName, inputFile, cl.outputfile)
3898 inputs.file(inputFile)
3899 outputs.files(outputFiles)
3903 task jalviewjsSyncCore (type: Sync) {
3904 dependsOn jalviewjsBuildAllCores
3905 dependsOn jalviewjsPublishCoreTemplates
3906 def inputFiles = fileTree(dir: "${jalviewDir}/${jalviewjsTransferSiteCoreDir}")
3907 def destinationDirectory = "${jalviewDir}/${jalviewjsSiteDir}"
3910 into destinationDirectory
3911 def outputFiles = []
3912 rename { filename ->
3913 outputFiles += "${destinationDirectory}/${filename}"
3919 outputs.files outputFiles
3920 inputs.files inputFiles
3924 // this Copy version of TransferSiteJs will delete anything else in the target dir
3925 task jalviewjsCopyTransferSiteJs(type: Copy) {
3926 dependsOn jalviewjsTranspile
3927 from "${jalviewDir}/${jalviewjsTransferSiteJsDir}"
3928 into "${jalviewDir}/${jalviewjsSiteDir}"
3932 // this Sync version of TransferSite is used by buildship to keep the website automatically up to date when a file changes
3933 task jalviewjsSyncTransferSiteJs(type: Sync) {
3934 from "${jalviewDir}/${jalviewjsTransferSiteJsDir}"
3936 into "${jalviewDir}/${jalviewjsSiteDir}"
3943 jalviewjsSyncAllLibs.mustRunAfter jalviewjsCopyTransferSiteJs
3944 jalviewjsSyncResources.mustRunAfter jalviewjsCopyTransferSiteJs
3945 jalviewjsSyncSiteResources.mustRunAfter jalviewjsCopyTransferSiteJs
3946 jalviewjsSyncBuildProperties.mustRunAfter jalviewjsCopyTransferSiteJs
3948 jalviewjsSyncAllLibs.mustRunAfter jalviewjsSyncTransferSiteJs
3949 jalviewjsSyncResources.mustRunAfter jalviewjsSyncTransferSiteJs
3950 jalviewjsSyncSiteResources.mustRunAfter jalviewjsSyncTransferSiteJs
3951 jalviewjsSyncBuildProperties.mustRunAfter jalviewjsSyncTransferSiteJs
3954 task jalviewjsPrepareSite {
3956 description "Prepares the website folder including unzipping files and copying resources"
3957 dependsOn jalviewjsSyncAllLibs
3958 dependsOn jalviewjsSyncResources
3959 dependsOn jalviewjsSyncSiteResources
3960 dependsOn jalviewjsSyncBuildProperties
3961 dependsOn jalviewjsSyncCore
3965 task jalviewjsBuildSite {
3967 description "Builds the whole website including transpiled code"
3968 dependsOn jalviewjsCopyTransferSiteJs
3969 dependsOn jalviewjsPrepareSite
3973 task cleanJalviewjsTransferSite {
3975 delete "${jalviewDir}/${jalviewjsTransferSiteJsDir}"
3976 delete "${jalviewDir}/${jalviewjsTransferSiteLibDir}"
3977 delete "${jalviewDir}/${jalviewjsTransferSiteSwingJsDir}"
3978 delete "${jalviewDir}/${jalviewjsTransferSiteCoreDir}"
3983 task cleanJalviewjsSite {
3984 dependsOn cleanJalviewjsTransferSite
3986 delete "${jalviewDir}/${jalviewjsSiteDir}"
3991 task jalviewjsSiteTar(type: Tar) {
3993 description "Creates a tar.gz file for the website"
3994 dependsOn jalviewjsBuildSite
3995 def outputFilename = "jalviewjs-site-${JALVIEW_VERSION}.tar.gz"
3996 archiveFileName = outputFilename
3998 compression Compression.GZIP
4000 from "${jalviewDir}/${jalviewjsSiteDir}"
4001 into jalviewjs_site_dir // this is inside the tar file
4003 inputs.dir("${jalviewDir}/${jalviewjsSiteDir}")
4007 task jalviewjsServer {
4009 def filename = "jalviewjsTest.html"
4010 description "Starts a webserver on localhost to test the website. See ${filename} to access local site on most recently used port."
4011 def htmlFile = "${jalviewDirAbsolutePath}/${filename}"
4016 def f = Class.forName("org.gradle.plugins.javascript.envjs.http.simple.SimpleHttpFileServerFactory")
4017 factory = f.newInstance()
4018 } catch (ClassNotFoundException e) {
4019 throw new GradleException("Unable to create SimpleHttpFileServerFactory")
4021 def port = Integer.valueOf(jalviewjs_server_port)
4026 while(port < start+1000 && !running) {
4028 def doc_root = new File("${jalviewDirAbsolutePath}/${jalviewjsSiteDir}")
4029 jalviewjsServer = factory.start(doc_root, port)
4031 url = jalviewjsServer.getResourceUrl(jalviewjs_server_resource)
4032 println("SERVER STARTED with document root ${doc_root}.")
4033 println("Go to "+url+" . Run gradle --stop to stop (kills all gradle daemons).")
4034 println("For debug: "+url+"?j2sdebug")
4035 println("For verbose: "+url+"?j2sverbose")
4036 } catch (Exception e) {
4041 <p><a href="${url}">JalviewJS Test. <${url}></a></p>
4042 <p><a href="${url}?j2sdebug">JalviewJS Test with debug. <${url}?j2sdebug></a></p>
4043 <p><a href="${url}?j2sverbose">JalviewJS Test with verbose. <${url}?j2sdebug></a></p>
4045 jalviewjsCoreClasslists.each { cl ->
4046 def urlcore = jalviewjsServer.getResourceUrl(file(cl.outputfile).getName())
4048 <p><a href="${urlcore}">${jalviewjsJalviewTemplateName} [core ${cl.name}]. <${urlcore}></a></p>
4050 println("For core ${cl.name}: "+urlcore)
4053 file(htmlFile).text = htmlText
4056 outputs.file(htmlFile)
4057 outputs.upToDateWhen({false})
4061 task cleanJalviewjsAll {
4063 description "Delete all configuration and build artifacts to do with JalviewJS build"
4064 dependsOn cleanJalviewjsSite
4065 dependsOn jalviewjsEclipsePaths
4068 delete "${jalviewDir}/${jalviewjsBuildDir}"
4069 delete "${jalviewDir}/${eclipse_bin_dir}"
4070 if (eclipseWorkspace != null && file(eclipseWorkspace.getAbsolutePath()+"/.metadata").exists()) {
4071 delete file(eclipseWorkspace.getAbsolutePath()+"/.metadata")
4073 delete jalviewjsJ2sAltSettingsFileName
4076 outputs.upToDateWhen( { false } )
4080 task jalviewjsIDE_checkJ2sPlugin {
4081 group "00 JalviewJS in Eclipse"
4082 description "Compare the swingjs/net.sf.j2s.core(-j11)?.jar file with the Eclipse IDE's plugin version (found in the 'dropins' dir)"
4085 def j2sPlugin = string("${jalviewDir}/${jalviewjsJ2sPlugin}")
4086 def j2sPluginFile = file(j2sPlugin)
4087 def eclipseHome = System.properties["eclipse.home.location"]
4088 if (eclipseHome == null || ! IN_ECLIPSE) {
4089 throw new StopExecutionException("Cannot find running Eclipse home from System.properties['eclipse.home.location']. Skipping J2S Plugin Check.")
4091 def eclipseJ2sPluginDirs = [ "${eclipseHome}/dropins" ]
4092 def altPluginsDir = System.properties["org.eclipse.equinox.p2.reconciler.dropins.directory"]
4093 if (altPluginsDir != null && file(altPluginsDir).exists()) {
4094 eclipseJ2sPluginDirs += altPluginsDir
4096 def foundPlugin = false
4097 def j2sPluginFileName = j2sPluginFile.getName()
4098 def eclipseJ2sPlugin
4099 def eclipseJ2sPluginFile
4100 eclipseJ2sPluginDirs.any { dir ->
4101 eclipseJ2sPlugin = "${dir}/${j2sPluginFileName}"
4102 eclipseJ2sPluginFile = file(eclipseJ2sPlugin)
4103 if (eclipseJ2sPluginFile.exists()) {
4109 def msg = "Eclipse J2S Plugin is not installed (could not find '${j2sPluginFileName}' in\n"+eclipseJ2sPluginDirs.join("\n")+"\n)\nTry running task jalviewjsIDE_copyJ2sPlugin"
4110 System.err.println(msg)
4111 throw new StopExecutionException(msg)
4114 def digest = MessageDigest.getInstance("MD5")
4116 digest.update(j2sPluginFile.text.bytes)
4117 def j2sPluginMd5 = new BigInteger(1, digest.digest()).toString(16).padLeft(32, '0')
4119 digest.update(eclipseJ2sPluginFile.text.bytes)
4120 def eclipseJ2sPluginMd5 = new BigInteger(1, digest.digest()).toString(16).padLeft(32, '0')
4122 if (j2sPluginMd5 != eclipseJ2sPluginMd5) {
4123 def msg = "WARNING! Eclipse J2S Plugin '${eclipseJ2sPlugin}' is different to this commit's version '${j2sPlugin}'"
4124 System.err.println(msg)
4125 throw new StopExecutionException(msg)
4127 def msg = "Eclipse J2S Plugin '${eclipseJ2sPlugin}' is the same as '${j2sPlugin}' (this is good)"
4133 task jalviewjsIDE_copyJ2sPlugin {
4134 group "00 JalviewJS in Eclipse"
4135 description "Copy the swingjs/net.sf.j2s.core(-j11)?.jar file into the Eclipse IDE's 'dropins' dir"
4138 def j2sPlugin = string("${jalviewDir}/${jalviewjsJ2sPlugin}")
4139 def j2sPluginFile = file(j2sPlugin)
4140 def eclipseHome = System.properties["eclipse.home.location"]
4141 if (eclipseHome == null || ! IN_ECLIPSE) {
4142 throw new StopExecutionException("Cannot find running Eclipse home from System.properties['eclipse.home.location']. NOT copying J2S Plugin.")
4144 def eclipseJ2sPlugin = "${eclipseHome}/dropins/${j2sPluginFile.getName()}"
4145 def eclipseJ2sPluginFile = file(eclipseJ2sPlugin)
4146 def msg = "WARNING! Copying this commit's j2s plugin '${j2sPlugin}' to Eclipse J2S Plugin '${eclipseJ2sPlugin}'\n* May require an Eclipse restart"
4147 System.err.println(msg)
4150 eclipseJ2sPluginFile.getParentFile().mkdirs()
4151 into eclipseJ2sPluginFile.getParent()
4157 task jalviewjsIDE_j2sFile {
4158 group "00 JalviewJS in Eclipse"
4159 description "Creates the .j2s file"
4160 dependsOn jalviewjsCreateJ2sSettings
4164 task jalviewjsIDE_SyncCore {
4165 group "00 JalviewJS in Eclipse"
4166 description "Build the core js lib closures listed in the classlists dir and publish core html from template"
4167 dependsOn jalviewjsSyncCore
4171 task jalviewjsIDE_SyncSiteAll {
4172 dependsOn jalviewjsSyncAllLibs
4173 dependsOn jalviewjsSyncResources
4174 dependsOn jalviewjsSyncSiteResources
4175 dependsOn jalviewjsSyncBuildProperties
4179 cleanJalviewjsTransferSite.mustRunAfter jalviewjsIDE_SyncSiteAll
4182 task jalviewjsIDE_PrepareSite {
4183 group "00 JalviewJS in Eclipse"
4184 description "Sync libs and resources to site dir, but not closure cores"
4186 dependsOn jalviewjsIDE_SyncSiteAll
4187 //dependsOn cleanJalviewjsTransferSite // not sure why this clean is here -- will slow down a re-run of this task
4191 task jalviewjsIDE_AssembleSite {
4192 group "00 JalviewJS in Eclipse"
4193 description "Assembles unzipped supporting zipfiles, resources, site resources and closure cores into the Eclipse transpiled site"
4194 dependsOn jalviewjsPrepareSite
4198 task jalviewjsIDE_SiteClean {
4199 group "00 JalviewJS in Eclipse"
4200 description "Deletes the Eclipse transpiled site"
4201 dependsOn cleanJalviewjsSite
4205 task jalviewjsIDE_Server {
4206 group "00 JalviewJS in Eclipse"
4207 description "Starts a webserver on localhost to test the website"
4208 dependsOn jalviewjsServer
4212 // buildship runs this at import or gradle refresh
4213 task eclipseSynchronizationTask {
4214 //dependsOn eclipseSetup
4215 dependsOn createBuildProperties
4217 dependsOn jalviewjsIDE_j2sFile
4218 dependsOn jalviewjsIDE_checkJ2sPlugin
4219 dependsOn jalviewjsIDE_PrepareSite
4224 // buildship runs this at build time or project refresh
4225 task eclipseAutoBuildTask {
4226 //dependsOn jalviewjsIDE_checkJ2sPlugin
4227 //dependsOn jalviewjsIDE_PrepareSite
4231 task jalviewjsCopyStderrLaunchFile(type: Copy) {
4232 from file(jalviewjs_stderr_launch)
4233 into jalviewjsSiteDir
4235 inputs.file jalviewjs_stderr_launch
4236 outputs.file jalviewjsStderrLaunchFilename
4239 task cleanJalviewjsChromiumUserDir {
4241 delete jalviewjsChromiumUserDir
4243 outputs.dir jalviewjsChromiumUserDir
4244 // always run when depended on
4245 outputs.upToDateWhen { !file(jalviewjsChromiumUserDir).exists() }
4248 task jalviewjsChromiumProfile {
4249 dependsOn cleanJalviewjsChromiumUserDir
4250 mustRunAfter cleanJalviewjsChromiumUserDir
4252 def firstRun = file("${jalviewjsChromiumUserDir}/First Run")
4255 mkdir jalviewjsChromiumProfileDir
4258 outputs.file firstRun
4261 task jalviewjsLaunchTest {
4263 description "Check JalviewJS opens in a browser"
4264 dependsOn jalviewjsBuildSite
4265 dependsOn jalviewjsCopyStderrLaunchFile
4266 dependsOn jalviewjsChromiumProfile
4268 def macOS = OperatingSystem.current().isMacOsX()
4269 def chromiumBinary = macOS ? jalviewjs_macos_chromium_binary : jalviewjs_chromium_binary
4270 if (chromiumBinary.startsWith("~/")) {
4271 chromiumBinary = System.getProperty("user.home") + chromiumBinary.substring(1)
4277 def timeoutms = Integer.valueOf(jalviewjs_chromium_overall_timeout) * 1000
4279 def binary = file(chromiumBinary)
4280 if (!binary.exists()) {
4281 throw new StopExecutionException("Could not find chromium binary '${chromiumBinary}'. Cannot run task ${name}.")
4283 stdout = new ByteArrayOutputStream()
4284 stderr = new ByteArrayOutputStream()
4287 if (jalviewjs_j2s_to_console.equals("true")) {
4288 execStdout = new org.apache.tools.ant.util.TeeOutputStream(
4291 execStderr = new org.apache.tools.ant.util.TeeOutputStream(
4299 "--no-sandbox", // --no-sandbox IS USED BY THE THORIUM APPIMAGE ON THE BUILDSERVER
4302 "--timeout=${timeoutms}",
4303 "--virtual-time-budget=${timeoutms}",
4304 "--user-data-dir=${jalviewDirAbsolutePath}/${jalviewjsBuildDir}/${jalviewjs_chromium_user_dir}",
4305 "--profile-directory=${jalviewjs_chromium_profile_name}",
4306 "--allow-file-access-from-files",
4307 "--enable-logging=stderr",
4308 "file://${jalviewDirAbsolutePath}/${jalviewjsStderrLaunchFilename}"
4311 if (true || macOS) {
4312 ScheduledExecutorService executor = Executors.newScheduledThreadPool(3);
4313 Future f1 = executor.submit(
4316 standardOutput = execStdout
4317 errorOutput = execStderr
4318 executable(chromiumBinary)
4320 println "COMMAND: '"+commandLine.join(" ")+"'"
4322 executor.shutdownNow()
4326 def noChangeBytes = 0
4327 def noChangeIterations = 0
4328 executor.scheduleAtFixedRate(
4330 String stderrString = stderr.toString()
4331 // shutdown the task if we have a success string
4332 if (stderrString.contains(jalviewjs_desktop_init_string)) {
4335 executor.shutdownNow()
4337 // if no change in stderr for 10s then also end
4338 if (noChangeIterations >= jalviewjs_chromium_idle_timeout) {
4339 executor.shutdownNow()
4341 if (stderrString.length() == noChangeBytes) {
4342 noChangeIterations++
4344 noChangeBytes = stderrString.length()
4345 noChangeIterations = 0
4348 1, 1, TimeUnit.SECONDS)
4350 executor.schedule(new Runnable(){
4353 executor.shutdownNow()
4355 }, timeoutms, TimeUnit.MILLISECONDS)
4357 executor.awaitTermination(timeoutms+10000, TimeUnit.MILLISECONDS)
4358 executor.shutdownNow()
4365 stderr.toString().eachLine { line ->
4366 if (line.contains(jalviewjs_desktop_init_string)) {
4367 println("Found line '"+line+"'")
4373 throw new GradleException("Could not find evidence of Desktop launch in JalviewJS.")
4381 description "Build the JalviewJS site and run the launch test"
4382 dependsOn jalviewjsBuildSite
4383 dependsOn jalviewjsLaunchTest