Skip to content

Commit

Permalink
convert engine build to kotlin (#5196)
Browse files Browse the repository at this point in the history
* rename to build.gradle.kts

* timestamp cannot be ignored easily with ignoreproperties, so leave
it as is, and remove the todo.

* move down writing the jar file, to assure version is specified in
 typehandlerlibrary e.g. which has it like project(:engine).version

* add jmh gradle plugin

* intermediate jmh

* jmh now compiles again
  • Loading branch information
soloturn authored May 14, 2024
1 parent 6077f50 commit 13c07b8
Showing 1 changed file with 96 additions and 107 deletions.
203 changes: 96 additions & 107 deletions engine/build.gradle → engine/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
// SPDX-License-Identifier: Apache-2.0

// The engine build is the primary Java project and has the primary list of dependencies

import groovy.json.JsonSlurper
import java.time.OffsetDateTime
import java.time.ZoneOffset
import java.time.format.DateTimeFormatter
Expand All @@ -16,45 +14,35 @@ plugins {
}

// Grab all the common stuff like plugins to use, artifact repositories, code analysis config, etc
apply from: "$rootDir/config/gradle/publish.gradle"

// 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()
apply(from = "$rootDir/config/gradle/publish.gradle")

templatesDir = new File(rootDir, "templates")
// Read environment variables, including variables passed by jenkins continuous integration server
val env = System.getenv()

// Stuff for our automatic version file setup
startDateTimeString = OffsetDateTime.now(ZoneOffset.UTC).format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssXXX"))
versionBase = new File(templatesDir, "version.txt").text.trim()
displayVersion = versionBase
}
// Stuff for our automatic version file setup
val startDateTimeString = OffsetDateTime.now(ZoneOffset.UTC).format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssXXX"))
val displayVersion by lazy { File("$rootDir/templates/version.txt").readText().trim() }

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Java Section //
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

sourceSets {
configure<SourceSetContainer> {
// Adjust output path (changed with the Gradle 6 upgrade, this puts it back)
main {
proto {
srcDir "src/main/protobuf"
}
java {
// Adjust output path (changed with the Gradle 6 upgrade, this puts it back)
destinationDirectory = new File("$buildDir/classes")
}
test.java.destinationDirectory = new File("$buildDir/testClasses")
java.destinationDirectory.set(layout.buildDirectory.dir("classes"))
proto.srcDir("src/main/protobuf")
}
test { java.destinationDirectory.set(layout.buildDirectory.dir("testClasses")) }
}

// Customizations for the main compilation configuration
configurations {

// Exclude a couple JWJGL modules that aren't needed during compilation (OS specific stuff in these two perhaps)
implementation {
exclude module: "lwjgl-platform"
exclude module: "jinput-platform"
exclude(module = "lwjgl-platform")
exclude(module = "jinput-platform")
}
}

Expand Down Expand Up @@ -90,7 +78,7 @@ dependencies {
implementation("com.esotericsoftware:reflectasm:1.11.9")

// Graphics, 3D, UI, etc
api(platform("org.lwjgl:lwjgl-bom:$LwjglVersion"))
api(platform("org.lwjgl:lwjgl-bom:${rootProject.extra["LwjglVersion"]}"))
api("org.lwjgl:lwjgl")
implementation("org.lwjgl:lwjgl-assimp")
api("org.lwjgl:lwjgl-glfw")
Expand Down Expand Up @@ -128,7 +116,7 @@ dependencies {

// telemetry
implementation("com.snowplowanalytics:snowplow-java-tracker:0.12.1") {
exclude group: "org.slf4j", module: "slf4j-simple"
exclude(group = "org.slf4j", module = "slf4j-simple")
}
implementation("net.logstash.logback:logstash-logback-encoder:7.4")

Expand All @@ -148,7 +136,7 @@ dependencies {


// Wildcard dependency to catch any libs provided with the project (remote repo preferred instead)
api fileTree(dir: "libs", include: "*.jar")
api(fileTree("libs") { include("*.jar") })

// TODO: Consider moving this back to the PC Facade instead of having the engine rely on it?
implementation("org.terasology.crashreporter:cr-terasology:5.0.0")
Expand All @@ -164,95 +152,50 @@ protobuf {
}
}

// Instructions for packaging a jar file for the engine
jar {
// Unlike the content modules Gradle grabs the assets as they're in a resources directory. Need to avoid dupes tho
duplicatesStrategy = "EXCLUDE"

doFirst {
manifest {
def manifestClasspath = "$subDirLibs/" + configurations."${sourceSets.main.runtimeClasspathConfigurationName}".collect {
it.getName()
}.join(" $subDirLibs/")
attributes("Class-Path": manifestClasspath, "Implementation-Title": "Terasology", "Implementation-Version": displayVersion + ", engine v" + project.version + " , build number " + env.BUILD_NUMBER)
}
}
}

// JMH related tasks

sourceSets {
jmh {
java.srcDirs = ["src/jmh/java"]
resources.srcDirs = ["src/jmh/resources"]
compileClasspath += sourceSets.main.runtimeClasspath
java.destinationDirectory = new File("$buildDir/jmhClasses")
}
}

tasks.register("jmh", JavaExec) {
dependsOn jmhClasses
mainClass = "org.openjdk.jmh.Main"
classpath = sourceSets.jmh.compileClasspath + sourceSets.jmh.runtimeClasspath
}

dependencies {
jmhAnnotationProcessor("org.openjdk.jmh:jmh-generator-annprocess:1.27")
jmhImplementation("org.openjdk.jmh:jmh-core:1.27")
jmhImplementation("org.openjdk.jmh:jmh-generator-annprocess:1.27")
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Version file stuff //
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

// First read the internal version out of the engine"s module.txt
def moduleFile = file("src/main/resources/org/terasology/engine/module.txt")

if (!moduleFile.exists()) {
println "Failed to find module.txt for engine"
throw new GradleException("Failed to find module.txt for engine")
}
val moduleFile = layout.projectDirectory.file("src/main/resources/org/terasology/engine/module.txt").asFile

println "Scanning for version in module.txt for engine"
def slurper = new JsonSlurper()
def moduleConfig = slurper.parseText(moduleFile.text)
println("Scanning for version in module.txt for engine")
val moduleConfig = groovy.json.JsonSlurper().parseText(moduleFile.readText()) as Map<String, String>

// Gradle uses the magic version variable when creating the jar name (unless explicitly set differently)
version = moduleConfig.version
version = moduleConfig["version"]!!

// Jenkins-Artifactory integration catches on to this as part of the Maven-type descriptor
group = "org.terasology.engine"

println "Version for $project.name loaded as $version for group $group"

// This version info file actually goes inside the built jar and can be used at runtime
def createVersionInfoFile = tasks.register("createVersionInfoFile", WriteProperties) {
//noinspection GroovyAssignabilityCheck
properties([
buildNumber: env.BUILD_NUMBER,
buildId: env.BUILD_ID,
buildTag: env.BUILD_TAG,
buildUrl: env.BUILD_URL,
jobName: env.JOB_NAME,
gitCommit: env.GIT_COMMIT,
displayVersion: displayVersion,
engineVersion: version
].findAll { it.value != null })
if (env.JOB_NAME != null) {
// Only set the dateTime property when there is a Jenkins JOB_NAME.
// It is a value we can always get (on Jenkins or otherwise) but we don't want local builds
// to invalidate their cache whenever the time changes.
// TODO: after upgrading to Gradle 6.8, see if we can have it ignore this property specifically:
// https://docs.gradle.org/current/userguide/incremental_build.html#sec:property_file_normalization
println("Version for $project.name loaded as $version for group $group")

// This version info file actually goes inside the built jar and can be used at runtime, contents:
// displayVersion=alpha-20
// engineVersion=5.4.0-SNAPSHOT
tasks.register<WriteProperties>("createVersionInfoFile") {
mapOf(
"buildNumber" to env["BUILD_NUMBER"],
"buildId" to env["BUILD_ID"],
"buildTag" to env["BUILD_TAG"],
"buildUrl" to env["BUILD_URL"],
"jobName" to env["JOB_NAME"],
"gitCommit" to env["GIT_COMMIT"],
"displayVersion" to displayVersion,
"engineVersion" to version
).filterValues { it != null }.forEach { (key, value) ->
property(key, value!!)
inputs.property(key, value)
}
if (env["JOB_NAME"] != null) {
property("dateTime", startDateTimeString)
}

destinationFile = layout.buildDirectory.dir("createrVersionInfoFile").get().file("versionInfo.properties")
}

tasks.named("processResources", Copy) {
from(createVersionInfoFile) {
tasks.named<Copy>("processResources") {
from("createVersionInfoFile") {
into("org/terasology/engine/version/")
}
from("$rootDir/docs") {
Expand All @@ -261,16 +204,62 @@ tasks.named("processResources", Copy) {
}

//TODO: Remove this when gestalt can handle ProtectionDomain without classes (Resources)
tasks.register("copyResourcesToClasses", Copy) {
from processResources
into sourceSets.main.output.classesDirs.first()

tasks.register<Copy>("copyResourcesToClasses") {
from("processResources")
into(sourceSets["main"].output.classesDirs.first())
}

tasks.named("compileJava") {
dependsOn(tasks.named("copyResourcesToClasses"))
}

// Instructions for packaging a jar file for the engine
tasks.withType<Jar> {
// Unlike the content modules Gradle grabs the assets as they're in a resources directory. Need to avoid dupes tho
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
manifest {
attributes["Class-Path"] = "libs/" + configurations.runtimeClasspath.get().joinToString(" libs/") { it.name }
attributes["Implementation-Title"] = "Terasology"
attributes["Implementation-Version"] =
"$displayVersion, engine v${project.version}, build number ${env["BUILD_NUMBER"]}"
}
}

// JMH related tasks

sourceSets {
create("jmh") {
java.srcDir("src/jmh/java")
resources.srcDir("src/jmh/resources")
compileClasspath += sourceSets["main"].runtimeClasspath
java.destinationDirectory.set(layout.buildDirectory.dir("jmhClasses"))
}
}

tasks.register<JavaExec>("jmh") {
dependsOn("jmhClasses")
mainClass.set("org.openjdk.jmh.Main")
classpath = sourceSets.named("jmh").get().compileClasspath + sourceSets.named("jmh").get().runtimeClasspath
}

dependencies {
"jmhAnnotationProcessor"("org.openjdk.jmh:jmh-generator-annprocess:1.27")
"jmhImplementation"("org.openjdk.jmh:jmh-core:1.27")
"jmhImplementation"("org.openjdk.jmh:jmh-generator-annprocess:1.27")
}

// following tasks use the output of jmh, so declare explicit dependency
listOf(
Checkstyle::class,
Pmd::class,
Javadoc::class,
com.github.spotbugs.snom.SpotBugsTask::class
).forEach { taskClass ->
tasks.withType(taskClass.java).configureEach {
dependsOn(":engine:compileJmhJava")
}
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// General IDE customization //
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Expand All @@ -281,11 +270,11 @@ idea {
inheritOutputDirs = false
outputDir = file("build/classes")
testOutputDir = file("build/testClasses")
downloadSources = true
isDownloadSources = true
}
}

// Make sure our config file for code analytics get extracted (vulnerability: non-IDE execution of single analytic)
ideaModule.dependsOn rootProject.extractConfig
tasks.eclipse.dependsOn rootProject.extractConfig
check.dependsOn rootProject.extractConfig
tasks.named("ideaModule") { dependsOn(tasks.getByPath(":extractConfig")) }
tasks.named("eclipse") { dependsOn(tasks.getByPath(":extractConfig")) }
tasks.named("check") { dependsOn(tasks.getByPath(":extractConfig")) }

0 comments on commit 13c07b8

Please sign in to comment.