Obscure configuration logic by using a buildSrc plugin

This commit is contained in:
Edwin Jakobs
2024-03-14 10:45:51 +01:00
parent a83e888dc3
commit 3350274efb
7 changed files with 377 additions and 351 deletions

29
buildSrc/build.gradle.kts Normal file
View File

@@ -0,0 +1,29 @@
plugins {
`kotlin-dsl`
}
repositories {
mavenCentral()
mavenLocal()
gradlePluginPortal()
}
dependencies {
implementation(libs.kotlin.gradle.plugin)
implementation(libs.shadow.gradle.plugin)
implementation(libs.runtime.gradle.plugin)
//implementation(libs.kotlin.serialization.gradle.plugin)
// https://github.com/gradle/gradle/issues/15383#issuecomment-779893192
implementation(files(libs.javaClass.superclass.protectionDomain.codeSource.location))
}
gradlePlugin {
plugins {
register("openrndr-plugin") {
id = "openrndr"
implementationClass = "org.openrndr.template.OpenrndrPlugin"
}
}
}

View File

@@ -0,0 +1,7 @@
dependencyResolutionManagement {
versionCatalogs {
create("libs") {
from(files("../gradle/libs.versions.toml"))
}
}
}

View File

@@ -0,0 +1,69 @@
package org.openrndr.template.convention
import org.gradle.accessors.dm.LibrariesForLibs
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
import org.gradle.internal.os.OperatingSystem
val libs = the<LibrariesForLibs>()
var applicationMainClass: String = "setme"
plugins {
kotlin("jvm")
id("com.github.johnrengelman.shadow")
id("org.beryx.runtime")
application
}
tasks {
named<ShadowJar>("shadowJar") {
manifest {
attributes["Main-Class"] = application.mainClass.get()
attributes["Implementation-Version"] = project.version
}
minimize {
exclude(dependency("org.openrndr:openrndr-gl3:.*"))
exclude(dependency("org.jetbrains.kotlin:kotlin-reflect:.*"))
exclude(dependency("org.slf4j:slf4j-simple:.*"))
exclude(dependency("org.apache.logging.log4j:log4j-slf4j2-impl:.*"))
exclude(dependency("com.fasterxml.jackson.core:jackson-databind:.*"))
exclude(dependency("com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:.*"))
}
}
named<org.beryx.runtime.JPackageTask>("jpackage") {
doLast {
val destPath = if(OperatingSystem.current().isMacOsX)
"build/jpackage/openrndr-application.app/Contents/Resources/data"
else
"build/jpackage/openrndr-application/data"
copy {
from("data") {
include("**/*")
}
into(destPath)
}
}
}
}
tasks.register<Zip>("jpackageZip") {
archiveFileName.set("openrndr-application.zip")
from("${layout.buildDirectory.get()}/jpackage") {
include("**/*")
}
}
tasks.findByName("jpackageZip")?.dependsOn("jpackage")
runtime {
jpackage {
imageName = "openrndr-application"
skipInstaller = true
if (OperatingSystem.current().isMacOsX) {
jvmArgs.add("-XstartOnFirstThread")
jvmArgs.add("-Duser.dir=${"$"}APPDIR/../Resources")
}
}
options.set(listOf("--strip-debug", "--compress", "1", "--no-header-files", "--no-man-pages"))
modules.set(listOf("jdk.unsupported", "java.management", "java.desktop"))
}

View File

@@ -0,0 +1,48 @@
package org.openrndr.template.convention
import org.gradle.accessors.dm.LibrariesForLibs
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
val libs = the<LibrariesForLibs>()
plugins {
kotlin("jvm")
application
}
//application {
// if (hasProperty("openrndr.application")) {
// mainClass.set("${property("openrndr.application")}")
// }
//}
tasks.withType<KotlinCompile> {
kotlinOptions.jvmTarget = "11"
}
java {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
repositories {
mavenCentral()
mavenLocal()
}
dependencies {
implementation(libs.kotlinx.coroutines.core)
implementation(libs.slf4j.api)
implementation(libs.kotlin.logging)
implementation(libs.openrndr.application)
implementation(libs.openrndr.svg)
implementation(libs.openrndr.animatable)
implementation(libs.openrndr.dialogs)
implementation(libs.openrndr.extensions)
//implementation(libs.openrndr.filters)
}

View File

@@ -0,0 +1,163 @@
package org.openrndr.template
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.ProjectEvaluationListener
import org.gradle.api.ProjectState
import org.gradle.api.artifacts.DependencyResolutionListener
import org.gradle.api.artifacts.MinimalExternalModuleDependency
import org.gradle.api.artifacts.ResolvableDependencies
import org.gradle.api.provider.Property
import org.gradle.api.provider.Provider
import org.gradle.api.provider.SetProperty
import org.gradle.internal.os.OperatingSystem
import org.gradle.nativeplatform.platform.internal.DefaultNativePlatform
import java.io.File
interface OpenrndrPluginExtension {
val openrndrVersion: Property<String>
val orxVersion: Property<String>
val openrndrFeatures: SetProperty<Provider<MinimalExternalModuleDependency>>
val orxFeatures: SetProperty<Provider<MinimalExternalModuleDependency>>
val mainClass: Property<String>
}
class OpenrndrPlugin : Plugin<Project> {
override fun apply(target: Project) {
val extension = target.extensions.create("openrndr", OpenrndrPluginExtension::class.java)
// Install the convention plugins
run {
target.plugins.apply("org.openrndr.template.convention.openrndr-jvm")
target.plugins.apply("org.openrndr.template.convention.distribution-jvm")
}
// Configure the application mainClass
run {
val app =
(target as org.gradle.api.plugins.ExtensionAware).extensions.getByName("application") as org.gradle.api.plugins.JavaApplication
app.mainClass.set(extension.mainClass)
}
// Install the OPENRNDR tasks
run {
target.gradle.addListener(object : ProjectEvaluationListener {
override fun beforeEvaluate(project: Project) {
}
override fun afterEvaluate(project: Project, state: ProjectState) {
if (target.properties["openrndr.tasks"] == "true") {
target.task("create executable jar for ${extension.mainClass.get()}") {
group = " \uD83E\uDD8C OPENRNDR"
dependsOn("shadowJar")
}
target.task("run $${extension.mainClass.get()}") {
group = " \uD83E\uDD8C OPENRNDR"
dependsOn("run")
}
target.task("create standalone executable for ${extension.mainClass.get()}") {
group = " \uD83E\uDD8C OPENRNDR"
dependsOn("jpackageZip")
}
target.task("add IDE file scopes") {
group = " \uD83E\uDD8C OPENRNDR"
val scopesFolder = File("${project.projectDir}/.idea/scopes")
scopesFolder.mkdirs()
val files = listOf(
"Code" to "file:*.kt||file:*.frag||file:*.vert||file:*.glsl",
"Text" to "file:*.txt||file:*.md||file:*.xml||file:*.json",
"Gradle" to "file[*buildSrc*]:*/||file:*gradle.*||file:*.gradle||file:*/gradle-wrapper.properties||file:*.toml",
"Media" to "file:*.png||file:*.jpg||file:*.dds||file:*.exr||file:*.mp3||file:*.wav||file:*.mp4||file:*.mov||file:*.svg"
)
files.forEach { (name, pattern) ->
val file = File(scopesFolder, "__$name.xml")
if (!file.exists()) {
file.writeText(
"""
<component name="DependencyValidationManager">
<scope name=" ★ $name" pattern="$pattern" />
</component>
""".trimIndent()
)
}
}
}
}
}
})
}
// Dynamically configure dependencies from openrndrFeatures and orxFeatures
run {
val currArch = DefaultNativePlatform("current").architecture.name
val currOs = OperatingSystem.current()
val os = if (target.hasProperty("targetPlatform")) {
val supportedPlatforms = setOf("windows", "macos", "macos-arm64", "linux-x64", "linux-arm64")
val platform: String = target.property("targetPlatform") as String
if (platform !in supportedPlatforms) {
throw IllegalArgumentException("target platform not supported: $platform")
} else {
platform
}
} else when {
currOs.isWindows -> "windows"
currOs.isMacOsX -> when (currArch) {
"aarch64", "arm-v8" -> "macos-arm64"
else -> "macos"
}
currOs.isLinux -> when (currArch) {
"x86-64" -> "linux-x64"
"aarch64" -> "linux-arm64"
else -> throw IllegalArgumentException("architecture not supported: $currArch")
}
else -> throw IllegalArgumentException("os not supported: ${currOs.name}")
}
target.gradle.addListener(object : DependencyResolutionListener {
override fun beforeResolve(dependencies: ResolvableDependencies) {
for (feature in extension.orxFeatures.get()) {
target.dependencies.add("implementation", feature)
}
for (feature in extension.openrndrFeatures.get()) {
target.dependencies.add("implementation", feature)
val dep = feature.get()
when (dep.name) {
"openrndr-ffmpeg" -> target.dependencies.add(
"runtimeOnly",
"${dep.group}:${dep.name}-natives-$os:${dep.version}"
)
"openrndr-gl3" -> target.dependencies.add(
"runtimeOnly",
"${dep.group}:${dep.name}-natives-$os:${dep.version}"
)
}
}
for (feature in extension.orxFeatures.get()) {
target.dependencies.add("implementation", feature)
val dep = feature.get()
when (dep.name) {
"orx-kinect-v1" -> target.dependencies.add(
"runtimeOnly",
"${dep.group}:${dep.name}-natives-$os:${dep.version}"
)
}
}
target.gradle.removeListener(this)
}
override fun afterResolve(dependencies: ResolvableDependencies) {
}
})
}
}
}