Feature variants (#376)
Migrate from buildSrc to build-logic. Setup feature variants.
This commit is contained in:
7
build-logic/build.gradle.kts
Normal file
7
build-logic/build.gradle.kts
Normal file
@@ -0,0 +1,7 @@
|
||||
plugins {
|
||||
`kotlin-dsl`
|
||||
}
|
||||
|
||||
repositories {
|
||||
gradlePluginPortal()
|
||||
}
|
||||
24
build-logic/orx-convention/build.gradle.kts
Normal file
24
build-logic/orx-convention/build.gradle.kts
Normal file
@@ -0,0 +1,24 @@
|
||||
plugins {
|
||||
`kotlin-dsl`
|
||||
}
|
||||
|
||||
val preload: SourceSet by project.sourceSets.creating
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
mavenLocal()
|
||||
}
|
||||
val libs = extensions.getByType<VersionCatalogsExtension>().named("libs")
|
||||
dependencies {
|
||||
implementation(project(":orx-variant-plugin"))
|
||||
implementation(libs.findLibrary("kotlin-gradle-plugin").get())
|
||||
implementation(libs.findLibrary("dokka-gradle-plugin").get())
|
||||
"preloadImplementation"(openrndr.application)
|
||||
"preloadImplementation"(openrndr.orextensions)
|
||||
}
|
||||
kotlin {
|
||||
compilerOptions {
|
||||
freeCompilerArgs.add("-Xskip-metadata-version-check")
|
||||
}
|
||||
}
|
||||
tasks.getByName("compileKotlin").dependsOn("compilePreloadKotlin")
|
||||
@@ -0,0 +1,182 @@
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.file.DirectoryProperty
|
||||
import org.gradle.api.file.FileCollection
|
||||
import org.gradle.api.file.FileType
|
||||
import org.gradle.api.provider.ListProperty
|
||||
import org.gradle.api.provider.Property
|
||||
import org.gradle.api.tasks.*
|
||||
import org.gradle.kotlin.dsl.register
|
||||
import org.gradle.process.ExecOperations
|
||||
import org.gradle.work.InputChanges
|
||||
import java.io.File
|
||||
import java.net.URLClassLoader
|
||||
import javax.inject.Inject
|
||||
|
||||
private class CustomClassLoader(parent: ClassLoader) : ClassLoader(parent) {
|
||||
fun findClass(file: File): Class<*> = defineClass(null, file.readBytes(), 0, file.readBytes().size)
|
||||
}
|
||||
|
||||
abstract class CollectScreenshotsTask @Inject constructor() : DefaultTask() {
|
||||
@get:InputDirectory
|
||||
@get:PathSensitive(PathSensitivity.NAME_ONLY)
|
||||
@get:SkipWhenEmpty
|
||||
abstract val inputDir: DirectoryProperty
|
||||
|
||||
@get:InputFiles
|
||||
abstract val runtimeDependencies: Property<FileCollection>
|
||||
|
||||
@get:OutputDirectory
|
||||
abstract val outputDir: DirectoryProperty
|
||||
|
||||
@get:Input
|
||||
@get:Optional
|
||||
abstract val ignore: ListProperty<String>
|
||||
|
||||
@get:Inject
|
||||
abstract val execOperations: ExecOperations
|
||||
|
||||
@TaskAction
|
||||
fun execute(inputChanges: InputChanges) {
|
||||
val preloadClass = File(project.rootProject.projectDir, "build-logic/orx-convention/build/classes/kotlin/preload")
|
||||
require(preloadClass.exists()) {
|
||||
"preload class not found: '${preloadClass.absolutePath}'"
|
||||
}
|
||||
|
||||
// Execute demos and produce PNG files
|
||||
inputChanges.getFileChanges(inputDir).forEach { change ->
|
||||
if (change.fileType == FileType.DIRECTORY) return@forEach
|
||||
if (change.file.extension == "class") {
|
||||
var klassName = change.file.nameWithoutExtension
|
||||
if (klassName.dropLast(2) in ignore.get()) {
|
||||
return@forEach
|
||||
}
|
||||
try {
|
||||
val cp = (runtimeDependencies.get().map { it.toURI().toURL() } + inputDir.get().asFile.toURI()
|
||||
.toURL()).toTypedArray()
|
||||
val ucl = URLClassLoader(cp)
|
||||
val ccl = CustomClassLoader(ucl)
|
||||
val tempClass = ccl.findClass(change.file)
|
||||
klassName = tempClass.name
|
||||
val klass = ucl.loadClass(klassName)
|
||||
klass.getMethod("main")
|
||||
} catch (e: NoSuchMethodException) {
|
||||
return@forEach
|
||||
}
|
||||
|
||||
println("Collecting screenshot for $klassName")
|
||||
val imageName = klassName.replace(".", "-")
|
||||
val pngFile = "${outputDir.get().asFile}/$imageName.png"
|
||||
|
||||
fun launchDemoProgram() {
|
||||
execOperations.javaexec {
|
||||
this.classpath += project.files(inputDir.get().asFile, preloadClass)
|
||||
this.classpath += runtimeDependencies.get()
|
||||
this.mainClass.set(klassName)
|
||||
this.workingDir(project.rootProject.projectDir)
|
||||
this.jvmArgs(
|
||||
"-DtakeScreenshot=true",
|
||||
"-DscreenshotPath=$pngFile",
|
||||
"-Dorg.openrndr.exceptions=JVM",
|
||||
"-Dorg.openrndr.gl3.debug=true",
|
||||
"-Dorg.openrndr.gl3.delete_angle_on_exit=false"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// A. Create an empty image for quick tests
|
||||
//File(pngFile).createNewFile()
|
||||
|
||||
// B. Create an actual image by running a demo program
|
||||
runCatching {
|
||||
launchDemoProgram()
|
||||
}.onFailure {
|
||||
println("Retrying $klassName after error: ${it.message}")
|
||||
Thread.sleep(5000)
|
||||
launchDemoProgram()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// List produced PNG images.
|
||||
// Only executed if there are changes in the inputDir.
|
||||
val demoImageBaseNames = outputDir.get().asFile.listFiles { file: File ->
|
||||
file.extension == "png"
|
||||
}!!.sortedBy { it.absolutePath.lowercase() }.map { it.nameWithoutExtension }
|
||||
|
||||
// Update readme.md using the found PNG images
|
||||
val readme = File(project.projectDir, "README.md")
|
||||
if (readme.exists()) {
|
||||
var readmeLines = readme.readLines().toMutableList()
|
||||
val screenshotsLine = readmeLines.indexOfFirst { it == "<!-- __demos__ -->" }
|
||||
if (screenshotsLine != -1) {
|
||||
readmeLines = readmeLines.subList(0, screenshotsLine)
|
||||
}
|
||||
readmeLines.add("<!-- __demos__ -->")
|
||||
readmeLines.add("## Demos")
|
||||
|
||||
val isKotlinMultiplatform = project.plugins.hasPlugin("org.jetbrains.kotlin.multiplatform")
|
||||
val demoModuleName = if (isKotlinMultiplatform) "jvmDemo" else "demo"
|
||||
|
||||
for (demoImageBaseName in demoImageBaseNames) {
|
||||
val projectPath = project.projectDir.relativeTo(project.rootDir)
|
||||
|
||||
// val url = "" // for local testing
|
||||
val url = "https://raw.githubusercontent.com/openrndr/orx/media/$projectPath/"
|
||||
|
||||
val imagePath = demoImageBaseName.dropLast(2).replace("-", "/")
|
||||
val ktFilePath = "src/$demoModuleName/kotlin/$imagePath.kt"
|
||||
val ktFile = File("$projectPath/$ktFilePath")
|
||||
|
||||
val description = if (ktFile.isFile) {
|
||||
val codeLines = ktFile.readLines()
|
||||
val main = codeLines.indexOfFirst { it.startsWith("fun main") }
|
||||
val head = codeLines.take(main)
|
||||
val start = head.indexOfLast { it.startsWith("/**") }
|
||||
val end = head.indexOfLast { it.endsWith("*/") }
|
||||
|
||||
if ((start < end) && (end < main)) {
|
||||
codeLines.subList(start + 1, end).joinToString("\n") { line ->
|
||||
val trimmed = line.trimStart(' ', '*')
|
||||
if(trimmed.startsWith("@see")) "" else trimmed
|
||||
}
|
||||
} else {
|
||||
println("/** comment */ missing in $projectPath/$ktFilePath")
|
||||
""
|
||||
}
|
||||
} else ""
|
||||
|
||||
readmeLines.add(
|
||||
"""
|
||||
|### $imagePath
|
||||
|
|
||||
|$description
|
||||
|
|
||||
|
|
||||
|
|
||||
|[source code]($ktFilePath)
|
||||
|
|
||||
""".trimMargin()
|
||||
)
|
||||
}
|
||||
readme.delete()
|
||||
readme.writeText(readmeLines.joinToString("\n"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object ScreenshotsHelper {
|
||||
fun collectScreenshots(
|
||||
project: Project,
|
||||
sourceSet: SourceSet,
|
||||
config: CollectScreenshotsTask.() -> Unit
|
||||
): CollectScreenshotsTask {
|
||||
val task = project.tasks.register<CollectScreenshotsTask>("collectScreenshots").get()
|
||||
task.outputDir.set(project.file(project.projectDir.toString() + "/images"))
|
||||
task.inputDir.set(File(project.layout.buildDirectory.get().asFile, "classes/kotlin/${sourceSet.name}"))
|
||||
task.runtimeDependencies.set(sourceSet.runtimeClasspath)
|
||||
task.config()
|
||||
task.dependsOn(sourceSet.output)
|
||||
return task
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.file.DirectoryProperty
|
||||
import org.gradle.api.file.FileType
|
||||
import org.gradle.api.provider.Property
|
||||
import org.gradle.api.tasks.*
|
||||
import org.gradle.work.ChangeType
|
||||
import org.gradle.work.Incremental
|
||||
import org.gradle.work.InputChanges
|
||||
import org.gradle.workers.WorkerExecutor
|
||||
import javax.inject.Inject
|
||||
|
||||
abstract class EmbedShadersTask : DefaultTask() {
|
||||
@get:Incremental
|
||||
@get:PathSensitive(PathSensitivity.NAME_ONLY)
|
||||
@get:InputDirectory
|
||||
abstract val inputDir: DirectoryProperty
|
||||
|
||||
@get:OutputDirectory
|
||||
abstract val outputDir: DirectoryProperty
|
||||
|
||||
@get:Input
|
||||
abstract val defaultPackage: Property<String>
|
||||
|
||||
@get:Input
|
||||
abstract val defaultVisibility: Property<String>
|
||||
|
||||
@get:Input
|
||||
abstract val namePrefix: Property<String>
|
||||
|
||||
@Inject
|
||||
abstract fun getWorkerExecutor(): WorkerExecutor
|
||||
|
||||
init {
|
||||
defaultVisibility.set("")
|
||||
namePrefix.set("")
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
fun execute(inputChanges: InputChanges) {
|
||||
|
||||
inputChanges.getFileChanges(inputDir).forEach { change ->
|
||||
if (change.fileType == FileType.DIRECTORY) return@forEach
|
||||
val name = "${namePrefix.get()}${change.file.nameWithoutExtension.replace("-", "_")}"
|
||||
val targetFile = outputDir.file(change.normalizedPath.replace(".", "_") + ".kt").get().asFile
|
||||
if (change.changeType == ChangeType.REMOVED) {
|
||||
targetFile.delete()
|
||||
} else {
|
||||
val contents = change.file.readText()
|
||||
val lines = contents.split("\n")
|
||||
var packageStatement = "package ${defaultPackage.get()}\n"
|
||||
val visibilityStatement =
|
||||
if (defaultVisibility.get().isNotBlank()) "${defaultVisibility.get()} " else ""
|
||||
|
||||
val r = Regex("#pragma package ([a-z.]+)")
|
||||
for (line in lines) {
|
||||
val m = r.find(line.trim())
|
||||
if (m != null) {
|
||||
packageStatement = "package ${m.groupValues[1]}\n"
|
||||
}
|
||||
}
|
||||
val text =
|
||||
"${packageStatement}${visibilityStatement}const val $name = ${"\"\"\""}${contents}${"\"\"\""}"
|
||||
targetFile.writeText(text)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package org.openrndr.extra.convention
|
||||
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.kotlin.dsl.named
|
||||
import org.gradle.nativeplatform.MachineArchitecture
|
||||
import org.gradle.nativeplatform.OperatingSystemFamily
|
||||
import org.gradle.nativeplatform.platform.internal.DefaultNativePlatform
|
||||
|
||||
val currentOperatingSystemName: String = DefaultNativePlatform.getCurrentOperatingSystem().toFamilyName()
|
||||
val currentArchitectureName: String = DefaultNativePlatform.getCurrentArchitecture().name
|
||||
|
||||
fun Project.addHostMachineAttributesToRuntimeConfigurations() {
|
||||
configurations.matching {
|
||||
it.name.endsWith("runtimeClasspath", ignoreCase = true)
|
||||
}.configureEach {
|
||||
attributes {
|
||||
attribute(OperatingSystemFamily.OPERATING_SYSTEM_ATTRIBUTE, objects.named(currentOperatingSystemName))
|
||||
attribute(MachineArchitecture.ARCHITECTURE_ATTRIBUTE, objects.named(currentArchitectureName))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
package org.openrndr.extra.convention
|
||||
|
||||
addHostMachineAttributesToRuntimeConfigurations()
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
package org.openrndr.extra.convention
|
||||
|
||||
plugins {
|
||||
id("org.jetbrains.dokka")
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dokka {
|
||||
pluginsConfiguration.html {
|
||||
customStyleSheets.from(rootProject.file("dokka/styles/extra.css"))
|
||||
customAssets.from(rootProject.file("dokka/images/logo-icon.svg"))
|
||||
}
|
||||
dokkaSourceSets.configureEach {
|
||||
skipDeprecated.set(false)
|
||||
|
||||
val sourcesDirectory = try {
|
||||
file("src/$name/kotlin", PathValidation.EXISTS)
|
||||
} catch (_: InvalidUserDataException) {
|
||||
return@configureEach
|
||||
}
|
||||
|
||||
// Specifies the location of the project source code on the Web.
|
||||
// If provided, Dokka generates "source" links for each declaration.
|
||||
sourceLink {
|
||||
// Unix based directory relative path to the root of the project (where you execute gradle respectively).
|
||||
localDirectory = sourcesDirectory
|
||||
|
||||
// URL showing where the source code can be accessed through the web browser
|
||||
remoteUrl("https://github.com/openrndr/orx/blob/master/${moduleName.get()}/src/$name/kotlin")
|
||||
|
||||
// Suffix which is used to append the line number to the URL. Use #L for GitHub
|
||||
remoteLineSuffix.set("#L")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
package org.openrndr.extra.convention
|
||||
|
||||
import ScreenshotsHelper.collectScreenshots
|
||||
import org.gradle.api.tasks.testing.logging.TestExceptionFormat
|
||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||
import org.gradle.nativeplatform.platform.internal.DefaultNativePlatform
|
||||
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||
import org.jetbrains.kotlin.gradle.dsl.KotlinVersion
|
||||
|
||||
val sharedLibs = extensions.getByType(VersionCatalogsExtension::class.java).named("sharedLibs")
|
||||
val openrndr = extensions.getByType(VersionCatalogsExtension::class.java).named("openrndr")
|
||||
val libs = extensions.getByType(VersionCatalogsExtension::class.java).named("libs")
|
||||
|
||||
val shouldPublish = project.name !in setOf("openrndr-demos", "orx-git-archiver-gradle")
|
||||
|
||||
plugins {
|
||||
java
|
||||
kotlin("jvm")
|
||||
`maven-publish` apply false
|
||||
id("org.openrndr.extra.convention.component-metadata-rule")
|
||||
id("org.openrndr.extra.convention.dokka")
|
||||
signing
|
||||
}
|
||||
if (shouldPublish) {
|
||||
apply(plugin = "maven-publish")
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
mavenLocal()
|
||||
}
|
||||
|
||||
group = "org.openrndr.extra"
|
||||
|
||||
val main: SourceSet by project.sourceSets.getting
|
||||
|
||||
@Suppress("UNUSED_VARIABLE")
|
||||
val demo: SourceSet by project.sourceSets.creating {
|
||||
val skipDemos = setOf(
|
||||
"openrndr-demos",
|
||||
"orx-axidraw",
|
||||
"orx-midi",
|
||||
"orx-minim",
|
||||
"orx-realsense2",
|
||||
"orx-runway",
|
||||
"orx-syphon",
|
||||
"orx-video-profiles",
|
||||
)
|
||||
if (project.name !in skipDemos) {
|
||||
collectScreenshots(project, this@creating) { }
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(sharedLibs.findLibrary("kotlin-stdlib").get())
|
||||
implementation(sharedLibs.findLibrary("kotlin-logging").get())
|
||||
testImplementation(sharedLibs.findLibrary("kotlin-test").get())
|
||||
testRuntimeOnly(sharedLibs.findLibrary("slf4j-simple").get())
|
||||
"demoImplementation"(main.output.classesDirs + main.runtimeClasspath)
|
||||
"demoImplementation"(openrndr.findLibrary("application").get())
|
||||
"demoImplementation"(openrndr.findLibrary("orextensions").get())
|
||||
|
||||
"demoRuntimeOnly"(openrndr.findLibrary("gl3").get())
|
||||
|
||||
"demoRuntimeOnly"(sharedLibs.findLibrary("slf4j-simple").get())
|
||||
}
|
||||
|
||||
tasks {
|
||||
@Suppress("UNUSED_VARIABLE")
|
||||
val test by getting(Test::class) {
|
||||
if (DefaultNativePlatform.getCurrentOperatingSystem().isMacOsX) {
|
||||
allJvmArgs = allJvmArgs + "-XstartOnFirstThread"
|
||||
}
|
||||
useJUnitPlatform()
|
||||
testLogging.exceptionFormat = TestExceptionFormat.FULL
|
||||
}
|
||||
|
||||
@Suppress("UNUSED_VARIABLE")
|
||||
val javadoc by getting(Javadoc::class) {
|
||||
options {
|
||||
this as StandardJavadocDocletOptions
|
||||
addBooleanOption("Xdoclint:none", true)
|
||||
}
|
||||
}
|
||||
withType<KotlinCompile> {
|
||||
compilerOptions {
|
||||
jvmTarget.set(JvmTarget.valueOf("JVM_${libs.findVersion("jvmTarget").get().displayName.replace(".", "_")}"))
|
||||
freeCompilerArgs.add("-Xexpect-actual-classes")
|
||||
freeCompilerArgs.add("-Xjdk-release=${libs.findVersion("jvmTarget").get().displayName}")
|
||||
apiVersion.set(KotlinVersion.valueOf("KOTLIN_${libs.findVersion("kotlinApi").get().displayName.replace(".", "_")}"))
|
||||
languageVersion.set(KotlinVersion.valueOf("KOTLIN_${libs.findVersion("kotlinLanguage").get().displayName.replace(".", "_")}"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
java {
|
||||
withJavadocJar()
|
||||
withSourcesJar()
|
||||
targetCompatibility = JavaVersion.valueOf("VERSION_${libs.findVersion("jvmTarget").get().displayName}")
|
||||
sourceCompatibility = JavaVersion.valueOf("VERSION_${libs.findVersion("jvmTarget").get().displayName}")
|
||||
}
|
||||
|
||||
val isReleaseVersion = !(version.toString()).endsWith("SNAPSHOT")
|
||||
|
||||
if (shouldPublish) {
|
||||
publishing {
|
||||
publications {
|
||||
create<MavenPublication>("maven") {
|
||||
from(components["java"])
|
||||
groupId = "org.openrndr.extra"
|
||||
artifactId = project.name
|
||||
description = project.name
|
||||
versionMapping {
|
||||
allVariants {
|
||||
fromResolutionResult()
|
||||
}
|
||||
}
|
||||
pom {
|
||||
name.set(project.name)
|
||||
description.set(project.name)
|
||||
url.set("https://openrndr.org")
|
||||
developers {
|
||||
developer {
|
||||
id.set("edwinjakobs")
|
||||
name.set("Edwin Jakobs")
|
||||
email.set("edwin@openrndr.org")
|
||||
}
|
||||
}
|
||||
|
||||
licenses {
|
||||
license {
|
||||
name.set("BSD-2-Clause")
|
||||
url.set("https://github.com/openrndr/orx/blob/master/LICENSE")
|
||||
distribution.set("repo")
|
||||
}
|
||||
}
|
||||
|
||||
scm {
|
||||
connection.set("scm:git:git@github.com:openrndr/orx.git")
|
||||
developerConnection.set("scm:git:ssh://github.com/openrndr/orx.git")
|
||||
url.set("https://github.com/openrndr/orx")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
signing {
|
||||
setRequired({ isReleaseVersion && gradle.taskGraph.hasTask("publish") })
|
||||
sign(publishing.publications)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,198 @@
|
||||
package org.openrndr.extra.convention
|
||||
|
||||
import CollectScreenshotsTask
|
||||
|
||||
import org.gradle.api.tasks.testing.logging.TestExceptionFormat
|
||||
import org.gradle.nativeplatform.platform.internal.DefaultNativePlatform
|
||||
import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi
|
||||
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||
import org.jetbrains.kotlin.gradle.dsl.KotlinVersion
|
||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompilationTask
|
||||
import org.jetbrains.kotlin.gradle.tasks.KotlinJvmCompile
|
||||
|
||||
val libs = extensions.getByType(VersionCatalogsExtension::class.java).named("libs")
|
||||
val sharedLibs = extensions.getByType(VersionCatalogsExtension::class.java).named("sharedLibs")
|
||||
val openrndr = extensions.getByType(VersionCatalogsExtension::class.java).named("openrndr")
|
||||
|
||||
val shouldPublish = project.name !in setOf("openrndr-demos")
|
||||
|
||||
plugins {
|
||||
kotlin("multiplatform")
|
||||
`maven-publish` apply false
|
||||
id("org.openrndr.extra.convention.component-metadata-rule")
|
||||
id("org.openrndr.extra.convention.dokka")
|
||||
signing
|
||||
}
|
||||
if (shouldPublish) {
|
||||
apply(plugin = "maven-publish")
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
mavenLocal()
|
||||
}
|
||||
|
||||
group = "org.openrndr.extra"
|
||||
|
||||
tasks.withType<KotlinCompilationTask<*>> {
|
||||
compilerOptions {
|
||||
apiVersion.set(KotlinVersion.valueOf("KOTLIN_${libs.findVersion("kotlinApi").get().displayName.replace(".", "_")}"))
|
||||
languageVersion.set(KotlinVersion.valueOf("KOTLIN_${libs.findVersion("kotlinLanguage").get().displayName.replace(".", "_")}"))
|
||||
freeCompilerArgs.add("-Xexpect-actual-classes")
|
||||
}
|
||||
}
|
||||
|
||||
tasks.withType<KotlinJvmCompile>().configureEach {
|
||||
compilerOptions {
|
||||
jvmTarget.set(JvmTarget.fromTarget(libs.findVersion("jvmTarget").get().displayName))
|
||||
freeCompilerArgs.add("-Xjdk-release=${libs.findVersion("jvmTarget").get().displayName}")
|
||||
}
|
||||
}
|
||||
|
||||
kotlin {
|
||||
jvm {
|
||||
compilations {
|
||||
val main by getting
|
||||
|
||||
val demo by creating {
|
||||
associateWith(main)
|
||||
tasks.register<CollectScreenshotsTask>("collectScreenshots") {
|
||||
// since Kotlin 2.1.20 output.classesDirs no longer contains a single file
|
||||
inputDir.set(output.classesDirs.filter { it.path.contains("classes/kotlin") }.singleFile)
|
||||
runtimeDependencies.set(runtimeDependencyFiles)
|
||||
outputDir.set(project.file(project.projectDir.toString() + "/images"))
|
||||
dependsOn(compileTaskProvider)
|
||||
}
|
||||
dependencies {
|
||||
runtimeOnly(openrndr.findLibrary("gl3").get())
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
testRuns["test"].executionTask {
|
||||
useJUnitPlatform()
|
||||
testLogging.exceptionFormat = TestExceptionFormat.FULL
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalKotlinGradlePluginApi::class)
|
||||
mainRun {
|
||||
classpath(kotlin.jvm().compilations.getByName("demo").output.allOutputs)
|
||||
classpath(kotlin.jvm().compilations.getByName("demo").configurations.runtimeDependencyConfiguration!!)
|
||||
}
|
||||
}
|
||||
|
||||
js(IR) {
|
||||
browser()
|
||||
nodejs()
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
val commonMain by getting {
|
||||
dependencies {
|
||||
implementation(libs.findLibrary("kotlin-stdlib").get())
|
||||
implementation(sharedLibs.findLibrary("kotlin-logging").get())
|
||||
}
|
||||
}
|
||||
|
||||
val commonTest by getting {
|
||||
dependencies {
|
||||
implementation(libs.findLibrary("kotlin-test").get())
|
||||
}
|
||||
}
|
||||
|
||||
val jvmTest by getting {
|
||||
dependencies {
|
||||
runtimeOnly(sharedLibs.findBundle("jupiter").get())
|
||||
runtimeOnly(sharedLibs.findLibrary("slf4j.simple").get())
|
||||
}
|
||||
}
|
||||
|
||||
val jvmDemo by getting {
|
||||
dependencies {
|
||||
implementation(openrndr.findLibrary("application").get())
|
||||
implementation(openrndr.findLibrary("orextensions").get())
|
||||
runtimeOnly(openrndr.findLibrary("gl3").get())
|
||||
runtimeOnly(sharedLibs.findLibrary("slf4j-simple").get())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val isReleaseVersion = !(version.toString()).endsWith("SNAPSHOT")
|
||||
|
||||
if (shouldPublish) {
|
||||
publishing {
|
||||
publications {
|
||||
val fjdj = tasks.register("fakeJavaDocJar", Jar::class) {
|
||||
archiveClassifier.set("javadoc")
|
||||
}
|
||||
named("js") {
|
||||
this as MavenPublication
|
||||
versionMapping {
|
||||
allVariants {
|
||||
fromResolutionOf("jsMainResolvableDependenciesMetadata")
|
||||
}
|
||||
}
|
||||
}
|
||||
named("jvm") {
|
||||
this as MavenPublication
|
||||
this.artifact(fjdj)
|
||||
versionMapping {
|
||||
allVariants {
|
||||
fromResolutionOf("jvmMainResolvableDependenciesMetadata")
|
||||
}
|
||||
}
|
||||
}
|
||||
named("kotlinMultiplatform") {
|
||||
this as MavenPublication
|
||||
versionMapping {
|
||||
allVariants {
|
||||
fromResolutionOf("commonMainResolvableDependenciesMetadata")
|
||||
}
|
||||
}
|
||||
}
|
||||
all {
|
||||
this as MavenPublication
|
||||
pom {
|
||||
name.set(project.name)
|
||||
description.set(project.name)
|
||||
url.set("https://openrndr.org")
|
||||
developers {
|
||||
developer {
|
||||
id.set("edwinjakobs")
|
||||
name.set("Edwin Jakobs")
|
||||
email.set("edwin@openrndr.org")
|
||||
}
|
||||
}
|
||||
|
||||
licenses {
|
||||
license {
|
||||
name.set("BSD-2-Clause")
|
||||
url.set("https://github.com/openrndr/orx/blob/master/LICENSE")
|
||||
distribution.set("repo")
|
||||
}
|
||||
}
|
||||
|
||||
scm {
|
||||
connection.set("scm:git:git@github.com:openrndr/orx.git")
|
||||
developerConnection.set("scm:git:ssh://github.com/openrndr/orx.git")
|
||||
url.set("https://github.com/openrndr/orx")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
signing {
|
||||
setRequired({ isReleaseVersion && gradle.taskGraph.hasTask("publish") })
|
||||
sign(publishing.publications)
|
||||
}
|
||||
}
|
||||
|
||||
tasks.withType<JavaExec>().matching { it.name == "jvmRun" }.configureEach {
|
||||
workingDir = rootDir
|
||||
val os: OperatingSystem? = DefaultNativePlatform.getCurrentOperatingSystem()
|
||||
if (os?.name == "Mac OS X") {
|
||||
setJvmArgs(listOf("-XstartOnFirstThread"))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package org.openrndr.extra.convention
|
||||
|
||||
plugins {
|
||||
id("orx-variant")
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package org.openrndr
|
||||
|
||||
import org.openrndr.extensions.SingleScreenshot
|
||||
|
||||
/**
|
||||
* This [Preload] class is used by the [CollectScreenshots] task to inject the [SingleScreenshot] extension
|
||||
*/
|
||||
class Preload : ApplicationPreload() {
|
||||
override fun onProgramSetup(program: Program) {
|
||||
program.extend(SingleScreenshot()) {
|
||||
this.outputFile = System.getProperty("screenshotPath")
|
||||
}
|
||||
}
|
||||
}
|
||||
17
build-logic/orx-variant-plugin/build.gradle.kts
Normal file
17
build-logic/orx-variant-plugin/build.gradle.kts
Normal file
@@ -0,0 +1,17 @@
|
||||
plugins {
|
||||
`kotlin-dsl`
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
|
||||
gradlePlugin {
|
||||
plugins {
|
||||
create("orxVariants") {
|
||||
id = "orx-variant"
|
||||
implementationClass = "org.openrndr.extra.variant.plugin.VariantPlugin"
|
||||
}
|
||||
}
|
||||
}
|
||||
169
build-logic/orx-variant-plugin/src/main/kotlin/VariantPlugin.kt
Normal file
169
build-logic/orx-variant-plugin/src/main/kotlin/VariantPlugin.kt
Normal file
@@ -0,0 +1,169 @@
|
||||
package org.openrndr.extra.variant.plugin
|
||||
|
||||
import org.gradle.api.Action
|
||||
import org.gradle.api.Plugin
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.artifacts.Configuration
|
||||
import org.gradle.api.artifacts.Dependency
|
||||
import org.gradle.api.attributes.Attribute
|
||||
import org.gradle.api.attributes.Bundling
|
||||
import org.gradle.api.attributes.Category
|
||||
import org.gradle.api.attributes.LibraryElements
|
||||
import org.gradle.api.attributes.Usage
|
||||
import org.gradle.api.attributes.java.TargetJvmVersion
|
||||
import org.gradle.api.component.AdhocComponentWithVariants
|
||||
import org.gradle.api.model.ObjectFactory
|
||||
import org.gradle.api.plugins.jvm.JvmComponentDependencies
|
||||
import org.gradle.api.tasks.Nested
|
||||
import org.gradle.api.tasks.SourceSet
|
||||
import org.gradle.api.tasks.SourceSetContainer
|
||||
import org.gradle.api.tasks.TaskContainer
|
||||
import org.gradle.jvm.tasks.Jar
|
||||
import org.gradle.kotlin.dsl.dependencies
|
||||
import org.gradle.kotlin.dsl.named
|
||||
import org.gradle.language.jvm.tasks.ProcessResources
|
||||
import org.gradle.nativeplatform.platform.internal.DefaultNativePlatform
|
||||
import javax.inject.Inject
|
||||
|
||||
fun arch(arch: String = System.getProperty("os.arch")): String {
|
||||
return when (arch) {
|
||||
"x86-64", "x86_64", "amd64" -> "x86-64"
|
||||
"arm64", "aarch64" -> "aarch64"
|
||||
else -> error("unsupported arch $arch")
|
||||
}
|
||||
}
|
||||
|
||||
abstract class VariantContainer @Inject constructor(
|
||||
@Inject val tasks: TaskContainer,
|
||||
val apiElements: Configuration,
|
||||
|
||||
val runtimeElements: Configuration,
|
||||
val sourceSet: SourceSet
|
||||
) {
|
||||
|
||||
@Nested
|
||||
abstract fun getDependencies(): JvmComponentDependencies
|
||||
|
||||
fun Dependency.withClassifier(classifier: String): String {
|
||||
return "$group:$name:$version:$classifier"
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup dependencies for this variant.
|
||||
*/
|
||||
fun dependencies(action: Action<in JvmComponentDependencies>) {
|
||||
action.execute(getDependencies())
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify that this variant comes with a resource bundle.
|
||||
*/
|
||||
fun jar(action: Action<Unit>) {
|
||||
sourceSet.resources.srcDirs.add(sourceSet.java.srcDirs.first().parentFile.resolve("resources"))
|
||||
sourceSet.resources.includes.add("**/*.*")
|
||||
tasks.named<Jar>(sourceSet.jarTaskName).configure {
|
||||
include("**/*.*")
|
||||
dependsOn(tasks.named<ProcessResources>(sourceSet.processResourcesTaskName))
|
||||
manifest {
|
||||
//this.attributes()
|
||||
}
|
||||
this.from(sourceSet.resources.srcDirs)
|
||||
}
|
||||
runtimeElements.outgoing.artifact(tasks.named(sourceSet.jarTaskName))
|
||||
action.execute(Unit)
|
||||
}
|
||||
}
|
||||
|
||||
abstract class VariantExtension(
|
||||
@Inject val objectFactory: ObjectFactory,
|
||||
@Inject val project: Project
|
||||
) {
|
||||
|
||||
fun platform(os: String, arch: String, f: VariantContainer.() -> Unit) {
|
||||
val sourceSets = project.extensions.getByType(SourceSetContainer::class.java)
|
||||
|
||||
val sourceSetArch = arch.replace("-", "_")
|
||||
val nameMain = "${os}${sourceSetArch.capitalize()}Main"
|
||||
val platformMain = sourceSets.create(nameMain)
|
||||
val tasks = project.tasks
|
||||
tasks.register(platformMain.jarTaskName, Jar::class.java) {
|
||||
archiveClassifier.set("$os-$arch")
|
||||
}
|
||||
|
||||
val configurations = project.configurations
|
||||
val objects = project.objects
|
||||
|
||||
val main = sourceSets.getByName("main")
|
||||
val mainApi = configurations.getByName(main.apiElementsConfigurationName)
|
||||
val mainRuntimeOnly = configurations.getByName(main.runtimeElementsConfigurationName)
|
||||
|
||||
mainApi.attributes {
|
||||
val osAttribute = Attribute.of("org.gradle.native.operatingSystem", String::class.java)
|
||||
attribute(osAttribute, "do_not_use_me")
|
||||
}
|
||||
|
||||
val platformMainRuntimeElements = configurations.create(platformMain.runtimeElementsConfigurationName) {
|
||||
extendsFrom(mainRuntimeOnly, mainApi)
|
||||
isCanBeResolved = false
|
||||
isCanBeConsumed = true
|
||||
val osAttribute = Attribute.of("org.gradle.native.operatingSystem", String::class.java)
|
||||
val archAttribute = Attribute.of("org.gradle.native.architecture", String::class.java)
|
||||
val typeAttribute = Attribute.of("org.jetbrains.kotlin.platform.type", String::class.java)
|
||||
val environmentAttribute = Attribute.of("org.gradle.jvm.environment", String::class.java)
|
||||
|
||||
attributes {
|
||||
attribute(Usage.USAGE_ATTRIBUTE, objects.named(Usage.JAVA_RUNTIME))
|
||||
attribute(Category.CATEGORY_ATTRIBUTE, objects.named(Category.LIBRARY))
|
||||
attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, objects.named(LibraryElements.JAR))
|
||||
attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 17)
|
||||
attribute(Bundling.BUNDLING_ATTRIBUTE, objects.named(Bundling.EXTERNAL))
|
||||
|
||||
attribute(osAttribute, os)
|
||||
attribute(archAttribute, arch)
|
||||
attribute(typeAttribute, "jvm")
|
||||
attribute(environmentAttribute, "standard-jvm")
|
||||
}
|
||||
outgoing.artifact(tasks.named(main.jarTaskName))
|
||||
outgoing.artifact(tasks.named(platformMain.jarTaskName))
|
||||
}
|
||||
|
||||
val javaComponent = project.components.getByName("java") as AdhocComponentWithVariants
|
||||
javaComponent.addVariantsFromConfiguration(platformMainRuntimeElements) {
|
||||
platformMain.runtimeClasspath.files.add(platformMain.resources.srcDirs.first())
|
||||
}
|
||||
|
||||
val variantContainer = objectFactory.newInstance(
|
||||
VariantContainer::class.java,
|
||||
platformMainRuntimeElements,
|
||||
platformMainRuntimeElements,
|
||||
platformMain
|
||||
)
|
||||
variantContainer.f()
|
||||
|
||||
platformMainRuntimeElements.dependencies.addAll(variantContainer.getDependencies().runtimeOnly.dependencies.get())
|
||||
|
||||
/*
|
||||
Setup dependencies for current platform. This will make in-module tests and demos work.
|
||||
*/
|
||||
val currentOperatingSystemName: String = DefaultNativePlatform.getCurrentOperatingSystem().toFamilyName()
|
||||
val currentArchitectureName: String = arch()
|
||||
|
||||
if (currentOperatingSystemName == os && currentArchitectureName == arch) {
|
||||
project.dependencies {
|
||||
add("testRuntimeOnly", platformMain.output)
|
||||
add("demoRuntimeOnly", platformMain.output)
|
||||
for (i in platformMainRuntimeElements.dependencies) {
|
||||
add("testRuntimeOnly", i)
|
||||
add("demoRuntimeOnly", i)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class VariantPlugin : Plugin<Project> {
|
||||
override fun apply(target: Project) {
|
||||
val project = target
|
||||
project.extensions.create("variants", VariantExtension::class.java)
|
||||
}
|
||||
}
|
||||
27
build-logic/settings.gradle.kts
Normal file
27
build-logic/settings.gradle.kts
Normal file
@@ -0,0 +1,27 @@
|
||||
include("orx-convention", "orx-variant-plugin")
|
||||
|
||||
dependencyResolutionManagement {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
mavenLocal {
|
||||
include("org.openrndr")
|
||||
}
|
||||
}
|
||||
|
||||
versionCatalogs {
|
||||
create("libs") {
|
||||
from(files("../gradle/libs.versions.toml"))
|
||||
}
|
||||
|
||||
// We use a regex to get the openrndr version from the primary catalog as there is no public Gradle API to parse catalogs.
|
||||
val regEx = Regex("^openrndr[ ]*=[ ]*(?:\\{[ ]*require[ ]*=[ ]*)?\"(.*)\"[ ]*(?:\\})?", RegexOption.MULTILINE)
|
||||
val openrndrVersion = regEx.find(File(rootDir,"../gradle/libs.versions.toml").readText())?.groupValues?.get(1) ?: error("can't find openrndr version")
|
||||
create("sharedLibs") {
|
||||
from("org.openrndr:openrndr-dependency-catalog:$openrndrVersion")
|
||||
}
|
||||
create("openrndr") {
|
||||
from("org.openrndr:openrndr-module-catalog:$openrndrVersion")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user