Skip to content

Commit 1b8a8ed

Browse files
committed
Gradle Plugin from PoC
1 parent 5468da0 commit 1b8a8ed

File tree

8 files changed

+260
-6
lines changed

8 files changed

+260
-6
lines changed

.gitignore

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,9 @@ bin-test
9898
processing-examples
9999

100100
# Maven ignores
101+
/.kotlin/sessions
101102
.gradle
103+
.build/
102104
core/build/
103105
build/publish/
104106
app/build
@@ -108,7 +110,5 @@ java/build/
108110
/java/libraries/svg/bin
109111
/java/preprocessor/build
110112
/java/lsp/build
111-
/.kotlin/sessions
112113
/core/examples/build
113-
114-
.build/
114+
/java/gradle/build

core/build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ plugins {
66
alias(libs.plugins.mavenPublish)
77
}
88

9-
group = "org.processing"
9+
version = rootProject.version
1010

1111
repositories {
1212
mavenCentral()

gradle/libs.versions.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,5 @@ kotlinMultiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref =
3131
compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
3232
serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
3333
download = { id = "de.undercouch.download", version = "5.6.0" }
34-
mavenPublish = { id = "com.vanniktech.maven.publish", version = "0.30.0" }
34+
mavenPublish = { id = "com.vanniktech.maven.publish", version = "0.30.0" }
35+
gradlePublish = { id = "com.gradle.plugin-publish", version = "1.2.1" }

java/gradle/build.gradle.kts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
plugins{
2+
`java-gradle-plugin`
3+
alias(libs.plugins.gradlePublish)
4+
5+
kotlin("jvm") version libs.versions.kotlin
6+
}
7+
8+
version = rootProject.version
9+
10+
repositories {
11+
mavenCentral()
12+
maven { url = uri("https://jogamp.org/deployment/maven") }
13+
}
14+
15+
dependencies{
16+
implementation(project(":java:preprocessor"))
17+
18+
implementation("org.jetbrains.compose:compose-gradle-plugin:1.7.3")
19+
implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.21")
20+
}
21+
22+
gradlePlugin{
23+
plugins{
24+
create("processing"){
25+
id = "org.processing"
26+
implementationClass = "org.processing.gradle.ProcessingPlugin"
27+
}
28+
}
29+
}
30+
publishing{
31+
repositories{
32+
mavenLocal()
33+
}
34+
}
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
package org.processing.gradle
2+
3+
import org.gradle.api.Plugin
4+
import org.gradle.api.Project
5+
import org.gradle.api.file.SourceDirectorySet
6+
import org.gradle.api.internal.file.DefaultSourceDirectorySet
7+
import org.gradle.api.internal.tasks.TaskDependencyFactory
8+
import org.gradle.api.model.ObjectFactory
9+
import org.gradle.api.plugins.JavaPlugin
10+
import org.gradle.api.plugins.JavaPluginExtension
11+
import org.jetbrains.compose.ComposeExtension
12+
import org.jetbrains.compose.desktop.DesktopExtension
13+
import java.io.File
14+
import java.util.*
15+
import javax.inject.Inject
16+
17+
class ProcessingPlugin @Inject constructor(private val objectFactory: ObjectFactory) : Plugin<Project> {
18+
override fun apply(project: Project) {
19+
project.plugins.apply(JavaPlugin::class.java)
20+
21+
// TODO: Only set the build directory when run from the Processing plugin
22+
project.layout.buildDirectory.set(project.layout.projectDirectory.dir(".processing"))
23+
24+
project.plugins.apply("org.jetbrains.compose")
25+
project.plugins.apply("org.jetbrains.kotlin.jvm")
26+
27+
project.dependencies.add("implementation", "org.processing:core:4.3.1")
28+
project.dependencies.add("implementation", project.fileTree("src").apply { include("**/code/*.jar") })
29+
30+
// Base JOGL and Gluegen dependencies
31+
project.dependencies.add("runtimeOnly", "org.jogamp.jogl:jogl-all-main:2.5.0")
32+
project.dependencies.add("runtimeOnly", "org.jogamp.gluegen:gluegen-rt-main:2.5.0")
33+
34+
// TODO: Only add the native dependencies for the platform the user is building for
35+
36+
// MacOS specific native dependencies
37+
project.dependencies.add("runtimeOnly", "org.jogamp.jogl:jogl-all:2.5.0:natives-macosx-universal")
38+
project.dependencies.add("runtimeOnly", "org.jogamp.gluegen:gluegen-rt:2.5.0:natives-macosx-universal")
39+
40+
// Windows specific native dependencies
41+
project.dependencies.add("runtimeOnly", "org.jogamp.jogl:jogl-all:2.5.0:natives-windows-amd64")
42+
project.dependencies.add("runtimeOnly", "org.jogamp.gluegen:gluegen-rt:2.5.0:natives-windows-amd64")
43+
44+
// Linux specific native dependencies
45+
project.dependencies.add("runtimeOnly", "org.jogamp.jogl:jogl-all:2.5.0:natives-linux-amd64")
46+
project.dependencies.add("runtimeOnly", "org.jogamp.gluegen:gluegen-rt:2.5.0:natives-linux-amd64")
47+
48+
// NativeWindow dependencies for all platforms
49+
project.dependencies.add("implementation", "org.jogamp.jogl:nativewindow:2.5.0")
50+
project.dependencies.add("runtimeOnly", "org.jogamp.jogl:nativewindow:2.5.0:natives-macosx-universal")
51+
project.dependencies.add("runtimeOnly", "org.jogamp.jogl:nativewindow:2.5.0:natives-windows-amd64")
52+
project.dependencies.add("runtimeOnly", "org.jogamp.jogl:nativewindow:2.5.0:natives-linux-amd64")
53+
54+
project.repositories.add(project.repositories.maven { it.setUrl("https://jogamp.org/deployment/maven") })
55+
project.repositories.add(project.repositories.mavenCentral())
56+
57+
project.extensions.configure(ComposeExtension::class.java) { extension ->
58+
extension.extensions.getByType(DesktopExtension::class.java).application { application ->
59+
application.mainClass = project.layout.projectDirectory.asFile.name.replace(Regex("[^a-zA-Z0-9_]"), "_")
60+
application.nativeDistributions.modules("java.management")
61+
}
62+
}
63+
64+
// TODO: Also only do within Processing
65+
project.tasks.named("wrapper").configure {
66+
it.enabled = false
67+
}
68+
69+
project.tasks.create("sketch").apply {
70+
group = "processing"
71+
description = "Runs the Processing sketch"
72+
dependsOn("run")
73+
}
74+
project.tasks.create("present").apply {
75+
// TODO: Implement dynamic fullscreen by setting the properties and recompiling the sketch every run
76+
group = "processing"
77+
description = "Presents the Processing sketch"
78+
dependsOn("run")
79+
}
80+
project.tasks.create("export").apply {
81+
group = "processing"
82+
description = "Creates a distributable version of the Processing sketch"
83+
dependsOn("createDistributable")
84+
}
85+
86+
project.extensions.getByType(JavaPluginExtension::class.java).sourceSets.all { sourceSet ->
87+
// TODO: also supporting normal gradle setup
88+
val pdeSourceSet = objectFactory.newInstance(
89+
DefaultPDESourceDirectorySet::class.java,
90+
objectFactory.sourceDirectorySet("${sourceSet.name}.pde", "${sourceSet.name} Processing Source")
91+
).apply {
92+
filter.include("**/*.pde")
93+
filter.exclude("${project.layout.buildDirectory.asFile.get().name}/**")
94+
95+
srcDir("./")
96+
}
97+
sourceSet.allSource.source(pdeSourceSet)
98+
99+
val outputDirectory = project.layout.buildDirectory.file( "generated/pde/" + sourceSet.name).get().asFile
100+
sourceSet.java.srcDir(outputDirectory)
101+
102+
// TODO: Support multiple sketches?
103+
// TODO: Preprocess PDE files in this step so we can add the library dependencies
104+
105+
val taskName = sourceSet.getTaskName("preprocess", "PDE")
106+
project.tasks.register(taskName, ProcessingTask::class.java) { task ->
107+
task.description = "Processes the ${sourceSet.name} PDE"
108+
task.source = pdeSourceSet
109+
task.outputDirectory = outputDirectory
110+
}
111+
112+
project.tasks.named(
113+
sourceSet.compileJavaTaskName
114+
) { task -> task.dependsOn(taskName) }
115+
}
116+
117+
var settingsFolder = File(System.getProperty("user.home"),".processing")
118+
val osName = System.getProperty("os.name").lowercase()
119+
if (osName.contains("win")) {
120+
settingsFolder = File(System.getenv("APPDATA"), "Processing")
121+
} else if (osName.contains("mac")) {
122+
settingsFolder = File(System.getProperty("user.home"), "Library/Processing")
123+
}else if (osName.contains("nix") || osName.contains("nux")) {
124+
settingsFolder = File(System.getProperty("user.home"), ".processing")
125+
}
126+
127+
val preferences = File(settingsFolder, "preferences.txt")
128+
val prefs = Properties()
129+
prefs.load(preferences.inputStream())
130+
131+
val sketchbook = prefs.getProperty("sketchbook.path.four")
132+
133+
File(sketchbook, "libraries").listFiles { file -> file.isDirectory
134+
}?.forEach{
135+
project.dependencies.add("implementation", project.fileTree(it).apply { include("**/*.jar") })
136+
}
137+
}
138+
abstract class DefaultPDESourceDirectorySet @Inject constructor(
139+
sourceDirectorySet: SourceDirectorySet,
140+
taskDependencyFactory: TaskDependencyFactory
141+
) : DefaultSourceDirectorySet(sourceDirectorySet, taskDependencyFactory), SourceDirectorySet
142+
}
143+
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package org.processing.gradle
2+
3+
import org.gradle.api.file.*
4+
import org.gradle.api.tasks.*
5+
import org.gradle.internal.file.Deleter
6+
import org.gradle.work.ChangeType
7+
import org.gradle.work.FileChange
8+
import org.gradle.work.InputChanges
9+
import processing.mode.java.preproc.PdePreprocessor
10+
import java.io.File
11+
import java.io.IOException
12+
import java.io.UncheckedIOException
13+
import java.util.concurrent.Callable
14+
import javax.inject.Inject
15+
16+
abstract class ProcessingTask() : SourceTask() {
17+
@get:OutputDirectory
18+
var outputDirectory: File? = null
19+
20+
@get:InputFiles
21+
@get:PathSensitive(PathSensitivity.RELATIVE)
22+
@get:IgnoreEmptyDirectories
23+
@get:SkipWhenEmpty
24+
open val stableSources: FileCollection = project.files(Callable<Any> { this.source })
25+
26+
@TaskAction
27+
fun execute(inputChanges: InputChanges) {
28+
val files: MutableSet<File> = HashSet()
29+
if (inputChanges.isIncremental) {
30+
var rebuildRequired = true
31+
for (fileChange: FileChange in inputChanges.getFileChanges(stableSources)) {
32+
if (fileChange.fileType == FileType.FILE) {
33+
if (fileChange.changeType == ChangeType.REMOVED) {
34+
rebuildRequired = true
35+
break
36+
}
37+
files.add(fileChange.file)
38+
}
39+
}
40+
if (rebuildRequired) {
41+
try {
42+
outputDirectory?.let { deleter.ensureEmptyDirectory(it) }
43+
} catch (ex: IOException) {
44+
throw UncheckedIOException(ex)
45+
}
46+
files.addAll(stableSources.files)
47+
}
48+
} else {
49+
files.addAll(stableSources.files)
50+
}
51+
52+
val name = project.layout.projectDirectory.asFile.name.replace(Regex("[^a-zA-Z0-9_]"), "_")
53+
val combined = files.joinToString("\n") { it.readText() }
54+
File(outputDirectory, "$name.java")
55+
.bufferedWriter()
56+
.use { out ->
57+
val meta = PdePreprocessor
58+
.builderFor(name)
59+
.build()
60+
.write(out, combined)
61+
62+
63+
// TODO: Only import the libraries that are actually used
64+
val importStatement = meta.importStatements
65+
}
66+
}
67+
68+
@get:Inject
69+
open val deleter: Deleter
70+
get() {
71+
throw UnsupportedOperationException("Decorator takes care of injection")
72+
}
73+
}

java/preprocessor/build.gradle.kts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ plugins{
66
alias(libs.plugins.mavenPublish)
77
}
88

9+
10+
911
repositories{
1012
mavenCentral()
1113
google()

settings.gradle.kts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
rootProject.name = "processing"
1+
rootProject.name = "org.processing"
22
include(
33
"core",
44
"core:examples",
55
"app",
66
"java",
77
"java:preprocessor",
8+
"java:gradle",
89
"java:libraries:dxf",
910
"java:libraries:io",
1011
"java:libraries:net",

0 commit comments

Comments
 (0)