<NME> build.gradle
<BEF> // Copyright 2020 The Terasology Foundation
// SPDX-License-Identifier: Apache-2.0

/*
 * This is a Gradle build file:
 * - Gradle Homepage: http://gradle.org/
 * - Gradle Documentation: http://gradle.org/documentation
 * - View tasks for this project: $ gradlew tasks
 */

buildscript {
    repositories {
        mavenCentral()
        gradlePluginPortal()
    }
}

plugins {
    id 'application'
    id 'checkstyle'
    id "com.github.spotbugs" version "5.0.8"
    id 'de.undercouch.download' version '5.1.0'
    id 'java'
    // to help clarify conflicting logging providers
    id 'name.remal.component-metadata' version '1.5.0'
    id 'nebula.release' version '16.0.0'
    id 'pmd'
    id 'project-report'
    id 'org.openjfx.javafxplugin' version '0.0.13'
    id "org.jetbrains.gradle.plugin.idea-ext" version "1.1.5"
}

apply plugin: 'org.terasology.gradlegoo'
apply from: "./config/gradle/jre.gradle"

// Test for right version of Java in use for running this script
assert JavaVersion.current().isJava11Compatible()

import org.apache.tools.ant.filters.FixCrLfFilter

import java.text.SimpleDateFormat

def dateTimeFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX")
dateTimeFormat.timeZone = TimeZone.getTimeZone("UTC")

configurations {
    codeMetrics
}

// Declare "extra properties" (variables) for the project - a Gradle thing that makes them special.
ext {
    // Read environment variables, including variables passed by jenkins continuous integration server
    env = System.getenv()

    // Stuff for our automatic version file setup
    startDateTimeString = dateTimeFormat.format(new Date())

    // Splash image for the JAR
    splashImage = 'org/terasology/launcher/images/splash.jpg'

    // Shared code analytics configurations via retrieved config zip
    metricsConfigDir = layout.getProjectDirectory().dir('config/metrics')
}

// Declare remote repositories we're interested in - library files will be fetched from here
repositories {
    // Main Maven repo
    mavenCentral()
    maven {
        // MovingBlocks Artifactory instance(s) for libs not readily available elsewhere plus our own libs
        name "Terasology Artifactory"
        url "http://artifactory.terasology.org/artifactory/virtual-repo-live"
        allowInsecureProtocol true
    }
    maven {
        name "JitPack"  // used by org.everit.json.schema
        url "https://jitpack.io"
    }

    maven {
        // required for markdown-javafx-renderer
        url "https://sandec.jfrog.io/artifactory/repo"
    }
}

// Primary dependencies definition
dependencies {
    implementation("org.slf4j:slf4j-api:[1.7.+, 2.0.0-alpha7]") {
        because "influenced by app or test loggers as needed"
    }
    implementation("ch.qos.logback:logback-classic:1.3.0-alpha16") {
        because "1.3 series uses ServiceLoader (more packaging friendly?)"
    }

    implementation group: 'com.google.code.gson', name: 'gson', version: '2.8.5'
    implementation group: "com.google.guava", name: "guava", version: "31.1-jre"
    implementation group: 'com.github.everit-org.json-schema', name: 'org.everit.json.schema', version: '1.14.1'

    implementation group: 'org.kohsuke', name: 'github-api', version: '1.306'
    implementation group: 'com.vdurmont', name: 'semver4j', version: '3.1.0'
    implementation group: 'com.vladsch.flexmark', name: 'flexmark-all', version: '0.64.0'

    implementation('org.hildan.fxgson:fx-gson:4.0.1') {
        because "de-/serialization of launcher properties to JSON"
    }

    implementation('com.squareup.okhttp3:okhttp:4.10.0') {
        because "built-in caching of HTTP requests"
    }

    // These dependencies are only needed for running tests

    testImplementation 'org.hamcrest:hamcrest:2.2'
    testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.2'
    testImplementation 'org.junit.jupiter:junit-jupiter-params:5.8.2'
    testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.2'

    testImplementation('org.mockito:mockito-inline:4.6.1') {
        because "-inline build enables mocking final classes"
        // https://javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html#0.2
        // > Be aware that this artifact may be abolished when the inline mock making feature is integrated into the default mock maker.
    }
    testImplementation 'org.mockito:mockito-junit-jupiter:4.6.1'

    testImplementation('org.spf4j:spf4j-slf4j-test:8.9.5') {
        because "testable logging"
    }
    testImplementation("org.slf4j:slf4j-api:1.7.+!!") {
        because "spf4j-slf4j-test:8.8 needs slf4j-api:1.x"
    }

    testImplementation("org.testfx:testfx-core:4.0.16-alpha") {
        because "to test JavaFX Application"

jar {
    // DEBUG: include all source files to verify that class files are up-to-date 
    from sourceSets.main.java 
    
    // replace development "logback.xml" with productive "logback_jar.xml"
    exclude "logback.xml"
    }
    manifest {
        def manifestClasspath = configurations.runtime.collect { it.getName() }.join(" ")
        attributes("Main-Class": mainClassName)
		attributes("Class-Path": manifestClasspath)
		attributes("Implementation-Title": project.name)
		attributes("Implementation-Version": displayVersion)
		attributes("SplashScreen-Image": splashImage)
        
        // allow everything
        attributes('Permissions': 'all-permissions')

    // old hamcrest versions exist only to spite us
    // http://hamcrest.org/JavaHamcrest/distributables#upgrading-from-hamcrest-1x
    exclude group: "org.hamcrest", module: "hamcrest-core"
    exclude group: "org.hamcrest", module: "hamcrest-library"
}
}


task copyLibs(type: Sync) {
	dependsOn jar

	from configurations.compile			// these are the compile-time dependencies
	from jar                            // this is the applet.jar file
	from 'webstart'						// jnlp file, icons, etc.
	
	into "$buildDir/webstart"
	
	eachFile { println "Copying " + it.file }
}

// At the end of the applet distribution sign the jar files so they can get expanded rights in a browser
task signJars {
	dependsOn copyLibs

    if (!file('certum.jks').exists()) {
        throw new GradleException("Copy the \"certum.jks\" keystore file in \"$projectDir\" first.");
checkstyle {
    ignoreFailures = false
    configDirectory.set(metricsConfigDir.dir("checkstyle"))
}

        
    tree.each {
        if (!IsSigned.isSigned(it, null)) {
			logger.lifecycle("Signing $it");
            sign(it);
        } else {
            logger.lifecycle("File $it already signed");
    effort = 'max'
    reportLevel = 'medium'
}

mainClassName = 'org.terasology.launcher.TerasologyLauncher'

def convertGitBranch = { gitBranch ->


task webstart {
	description "Prepare WebStart launcher files"
	
	dependsOn signJars
}

task distChangelog(type: Copy) {
    inputs.property('version', version.toString())

    File versionInfoFileDir = new File(sourceSets.main.output.resourcesDir, 'org/terasology/launcher/')
    File versionFile = new File(versionInfoFileDir, 'version.txt')

    outputs.file(versionFile)

    doLast {
        versionInfoFileDir.mkdirs()
        versionFile.text = version
    }
}

task extractCodeMetricsConfig(type: Copy) {
    description = "Extract code metrics configuration to '$metricsConfigDir'"
    from {
        configurations.codeMetrics.collect {
            zipTree(it)
        }
    }
    into metricsConfigDir
}

clean {
    delete createVersionInfoFile.outputs.files
    delete extractCodeMetricsConfig.destinationDir
}

processResources.dependsOn(createVersionInfoFile, extractCodeMetricsConfig)

jar {
    //TODO we only use this name because the `.exe` start scripts require the JAR to be named 'TerasologyLauncher.jar'
    jar.archiveFileName = "${project.name}.jar"
    // replace development "logback.xml" with productive "logback_jar.xml"
    exclude "logback.xml"
    rename('logback_jar.xml', 'logback.xml')
    manifest {
        def manifestClasspath = configurations.runtimeClasspath.collect { it.getName() }.join(" ")
        attributes("Main-Class": mainClassName)
        attributes("Class-Path": manifestClasspath)
        attributes("Implementation-Title": project.name)
        attributes("Implementation-Version": project.version)
        attributes("SplashScreen-Image": splashImage)

        // allow everything
        attributes('Permissions': 'all-permissions')
        attributes('Codebase': '*')
        attributes('Application-Name': project.name)
        attributes('Application-Library-Allowable-Codebase': '*')
        attributes('Caller-Allowable-Codebase': '*')
        attributes('Trusted-Only': 'false')
    }
}

task copyExtra(type: Copy) {
    filter(FixCrLfFilter, eol: FixCrLfFilter.CrLf.newInstance("crlf"))

    from('README.md') {
        rename('README.md', 'README.txt')
    }

    from('CHANGELOG.md') {
        rename('CHANGELOG.md', 'CHANGELOG.txt')
    }

    from('CONTRIBUTING.md') {
        rename('CONTRIBUTING.md', 'CONTRIBUTING.txt')
    }

    from('LICENSE')
    from('NOTICE')

    into "$buildDir/distributions"
}

task copyExtraIntoResources(type: Copy) {
    from('README.md')
    from('CHANGELOG.md')
    from('docs/CONTRIBUTING.md')
    from('LICENSE')

    into('src/main/resources/org/terasology/launcher/about')
}
processResources.dependsOn copyExtraIntoResources

task copyIconsIntoResources(type: Copy) {
    from('icons')

    into('src/main/resources/org/terasology/launcher/icons')
}
processResources.dependsOn copyIconsIntoResources

//TODO: Temporary workaround for new exes / JRE bundling not quite being officially ready yet
distZip.exclude("*.x*.exe")


idea {
    project.settings.delegateActions {
        delegateBuildRunToGradle = false
    }
}

tasks.named('wrapper') {
    // IDEA likes this distribution to better know things.
    distributionType = Wrapper.DistributionType.ALL
}

<MSG> Updated webstart content

<DFF> @@ -134,7 +134,14 @@ distTar.dependsOn createVersionInfoFile
 
 jar {
     // DEBUG: include all source files to verify that class files are up-to-date 
-    from sourceSets.main.java 
+    from sourceSets.main.java
+	
+	// Copying the jnlp webstart file in to the signed JAR allows JWS to 
+	// verify the correctness. The freestanding copy is still needed though.
+	into ('JNLP_INF') {
+		from 'webstart.jnlp'
+		rename 'webstart.jnlp', 'APPLICATION.JNLP'
+	}
     
     // replace development "logback.xml" with productive "logback_jar.xml"
     exclude "logback.xml"
@@ -142,10 +149,10 @@ jar {
     manifest {
         def manifestClasspath = configurations.runtime.collect { it.getName() }.join(" ")
         attributes("Main-Class": mainClassName)
-		attributes("Class-Path": manifestClasspath)
-		attributes("Implementation-Title": project.name)
-		attributes("Implementation-Version": displayVersion)
-		attributes("SplashScreen-Image": splashImage)
+        attributes("Class-Path": manifestClasspath)
+        attributes("Implementation-Title": project.name)
+        attributes("Implementation-Version": displayVersion)
+        attributes("SplashScreen-Image": splashImage)
         
         // allow everything
         attributes('Permissions': 'all-permissions')
@@ -158,21 +165,21 @@ jar {
 }
 
 
-task copyLibs(type: Sync) {
-	dependsOn jar
+task copyLibs(type: Copy) {
+    dependsOn jar
 
-	from configurations.compile			// these are the compile-time dependencies
-	from jar                            // this is the applet.jar file
-	from 'webstart'						// jnlp file, icons, etc.
-	
-	into "$buildDir/webstart"
+    from configurations.compile         // these are the compile-time dependencies
+    from jar                            // this is the applet.jar file
+    from 'webstart.jnlp'                // jnlp file
+    from 'icons'                        // splash screen, etc
 	
-	eachFile { println "Copying " + it.file }
+    into "$buildDir/webstart"
+    
+    eachFile { println "Copying " + it.file }
 }
 
-// At the end of the applet distribution sign the jar files so they can get expanded rights in a browser
-task signJars {
-	dependsOn copyLibs
+// Sign the jar files so they can get full rights in a browser
+copyLibs.doLast {
 
     if (!file('certum.jks').exists()) {
         throw new GradleException("Copy the \"certum.jks\" keystore file in \"$projectDir\" first.");
@@ -184,7 +191,7 @@ task signJars {
         
     tree.each {
         if (!IsSigned.isSigned(it, null)) {
-			logger.lifecycle("Signing $it");
+            logger.lifecycle("Signing $it");
             sign(it);
         } else {
             logger.lifecycle("File $it already signed");
@@ -198,9 +205,9 @@ def sign(File it) {
 
 
 task webstart {
-	description "Prepare WebStart launcher files"
-	
-	dependsOn signJars
+    description "Prepare WebStart launcher files"
+    
+    dependsOn copyLibs
 }
 
 task distChangelog(type: Copy) {

{'addition_count': 27, 'commit_subject': 'Updated webstart content', 'deletion_count': 20, 'file_extension': '.gradle', 'lang': 'gradle', 'license': 'apache-2.0', 'repo_name': 'MovingBlocks/TerasologyLauncher'}