Skip to content

Commit 5d71244

Browse files
committed
Plugin rework
1 parent e164fe4 commit 5d71244

File tree

6 files changed

+135
-92
lines changed

6 files changed

+135
-92
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,3 +122,4 @@ java/build/
122122
/java/gradle/example/.processing
123123
/java/android/example/build
124124
/java/android/example/.processing
125+
/java/gradle/example/build

app/src/processing/app/gradle/GradleService.kt

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,8 @@ class GradleService(val editor: Editor) {
129129

130130
// TODO: Attach listener if new tab is created
131131
}
132+
133+
// TODO: Attach a debugger (to gradle, and the running sketch)
132134
}
133135

134136

@@ -140,27 +142,41 @@ class GradleService(val editor: Editor) {
140142
val workingDir = kotlin.io.path.createTempDirectory()
141143
val group = System.getProperty("processing.group", "org.processing")
142144

145+
146+
// TODO: is this the best way to handle unsaved data?
147+
val unsaved = mutableListOf<String>()
148+
editor.sketch.code.forEach { code ->
149+
if(!code.isModified) return@forEach
150+
151+
val file = workingDir.resolve("unsaved/${code.fileName}")
152+
file.parent.toFile().mkdirs()
153+
file.writeText(code.documentText)
154+
unsaved.add(code.fileName)
155+
}
156+
143157
val variables = mapOf(
144158
"group" to group,
145159
"version" to Base.getVersionName(),
146160
"sketchFolder" to folder.absolutePath,
147161
"workingDir" to workingDir.toAbsolutePath().toString(),
148-
"settings" to Platform.getSettingsFolder().absolutePath.toString()
162+
"settings" to Platform.getSettingsFolder().absolutePath.toString(),
163+
"unsaved" to unsaved.joinToString(",")
149164
)
165+
val repository = Platform.getContentFile("repository").absolutePath
150166

151167
val initGradle = workingDir.resolve("init.gradle.kts").apply {
152168
val content = """
153169
beforeSettings{
154170
pluginManagement {
155171
repositories {
156-
maven { url = uri("${Platform.getContentFile("repository").absolutePath}") }
172+
maven { url = uri("$repository") }
157173
gradlePluginPortal()
158174
}
159175
}
160176
}
161177
allprojects{
162178
repositories {
163-
maven { url = uri("${Platform.getContentFile("repository").absolutePath}") }
179+
maven { url = uri("$repository") }
164180
mavenCentral()
165181
}
166182
}
@@ -169,6 +185,8 @@ class GradleService(val editor: Editor) {
169185
writeText(content)
170186
}
171187

188+
189+
172190
val buildGradle = folder.resolve("build.gradle.kts")
173191
// TODO: Manage script if the comment exists
174192
if(!buildGradle.exists()){
@@ -177,7 +195,7 @@ class GradleService(val editor: Editor) {
177195
// TODO: Allow for the whole configuration to be overridden
178196
// TODO: Move this to java mode
179197
val content = """
180-
// Managed by: Processing ${Base.getVersionName()}
198+
// Managed by: Processing ${Base.getVersionName()} ${editor.mode.title}
181199
// If you delete this comment Processing will no longer update the build scripts
182200
183201
plugins{
@@ -188,7 +206,7 @@ class GradleService(val editor: Editor) {
188206
}
189207

190208
return this.newBuild()
191-
// .setJavaHome(Platform.getJavaHome())
209+
.setJavaHome(Platform.getJavaHome())
192210
.withArguments(
193211
"--init-script", initGradle.toAbsolutePath().toString(),
194212
*variables.entries.map { "-Pprocessing.${it.key}=${it.value}" }.toTypedArray()

gradle.properties

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
#version=4.12.1
2+
#group=nl.steftervelde
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
plugins{
2-
id("processing.java.gradle")
2+
id("org.processing.gradle")
33
}

java/gradle/src/main/kotlin/ProcessingPlugin.kt

Lines changed: 81 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -17,33 +17,71 @@ import javax.inject.Inject
1717

1818
class ProcessingPlugin @Inject constructor(private val objectFactory: ObjectFactory) : Plugin<Project> {
1919
override fun apply(project: Project) {
20+
val sketchName = project.layout.projectDirectory.asFile.name.replace(Regex("[^a-zA-Z0-9_]"), "_")
21+
2022
val isProcessing = project.findProperty("processing.version") != null
21-
val processingVersion = project.findProperty("processing.version") as String? ?: "4.0.0"
23+
val processingVersion = project.findProperty("processing.version") as String? ?: "4.3.4"
2224
val processingGroup = project.findProperty("processing.group") as String? ?: "org.processing"
25+
val workingDir = project.findProperty("processing.workingDir") as String?
26+
27+
// Grab the settings from the most likely location
28+
var settingsFolder = (project.findProperty("processing.settings") as String?)?.let { File(it) }
29+
if(settingsFolder == null) {
30+
val osName = System.getProperty("os.name").lowercase()
31+
if (osName.contains("win")) {
32+
settingsFolder = File(System.getenv("APPDATA"), "Processing")
33+
} else if (osName.contains("mac")) {
34+
settingsFolder = File(System.getProperty("user.home"), "Library/Processing")
35+
} else if (osName.contains("nix") || osName.contains("nux")) {
36+
settingsFolder = File(System.getProperty("user.home"), ".processing")
37+
}
38+
}
2339

40+
val preferences = File(settingsFolder, "preferences.txt")
41+
val prefs = Properties()
42+
prefs.load(preferences.inputStream())
43+
prefs.setProperty("export.application.fullscreen", "false")
44+
prefs.setProperty("export.application.present", "false")
45+
prefs.setProperty("export.application.stop", "false")
46+
prefs.store(preferences.outputStream(), null)
47+
48+
val sketchbook = prefs.getProperty("sketchbook.path.four")
49+
50+
// Apply the Java plugin to the Project
2451
project.plugins.apply(JavaPlugin::class.java)
2552

2653
if(isProcessing){
27-
project.layout.buildDirectory.set(File(project.findProperty("processing.workingDir") as String))
54+
// Set the build directory to a temp file so it doesn't clutter up the sketch folder
55+
// Only if the build directory doesn't exist, otherwise proceed as normal
56+
if(!project.layout.buildDirectory.asFile.get().exists()) {
57+
project.layout.buildDirectory.set(File(project.findProperty("processing.workingDir") as String))
58+
}
59+
// Disable the wrapper in the sketch to keep it cleaner
2860
project.tasks.findByName("wrapper")?.enabled = false
2961
}
3062

63+
// Add the compose plugin to wrap the sketch in an executable
3164
project.plugins.apply("org.jetbrains.compose")
65+
66+
// TODO: Do we need these?
67+
// Add kotlin support
3268
project.plugins.apply("org.jetbrains.kotlin.jvm")
69+
// Add jetpack compose support
3370
project.plugins.apply("org.jetbrains.kotlin.plugin.compose")
3471

35-
// TODO: Add to tests
72+
// Add the Processing core library (within Processing from the internal maven repo and outside from the internet)
3673
project.dependencies.add("implementation", "$processingGroup:core:${processingVersion}")
37-
// TODO: Add tests to test if code jars are working
74+
75+
// Add the jars in the code folder
3876
project.dependencies.add("implementation", project.fileTree("src").apply { include("**/code/*.jar") })
3977

40-
// Base JOGL and Gluegen dependencies
78+
// Add JOGL and Gluegen dependencies
4179
// TODO: Add only if user is compiling for P2D or P3D
80+
// TODO: Would require adding this after pre-processing
4281
project.dependencies.add("runtimeOnly", "org.jogamp.jogl:jogl-all-main:2.5.0")
4382
project.dependencies.add("runtimeOnly", "org.jogamp.gluegen:gluegen-rt-main:2.5.0")
4483

4584
// TODO: Only add the native dependencies for the platform the user is building for
46-
4785
// MacOS specific native dependencies
4886
project.dependencies.add("runtimeOnly", "org.jogamp.jogl:jogl-all:2.5.0:natives-macosx-universal")
4987
project.dependencies.add("runtimeOnly", "org.jogamp.gluegen:gluegen-rt:2.5.0:natives-macosx-universal")
@@ -62,47 +100,53 @@ class ProcessingPlugin @Inject constructor(private val objectFactory: ObjectFact
62100
project.dependencies.add("runtimeOnly", "org.jogamp.jogl:nativewindow:2.5.0:natives-windows-amd64")
63101
project.dependencies.add("runtimeOnly", "org.jogamp.jogl:nativewindow:2.5.0:natives-linux-amd64")
64102

103+
// Add the repositories necessary for building the sketch
65104
project.repositories.add(project.repositories.maven { it.setUrl("https://jogamp.org/deployment/maven") })
66105
project.repositories.add(project.repositories.mavenCentral())
67106
project.repositories.add(project.repositories.mavenLocal())
68107

108+
// Configure the compose Plugin
69109
project.extensions.configure(ComposeExtension::class.java) { extension ->
70110
extension.extensions.getByType(DesktopExtension::class.java).application { application ->
71-
application.mainClass = project.layout.projectDirectory.asFile.name.replace(Regex("[^a-zA-Z0-9_]"), "_")
111+
// Set the class to be executed initially
112+
application.mainClass = sketchName
72113
application.nativeDistributions.modules("java.management")
73114
}
74115
}
75116

76-
project.tasks.create("sketch").apply {
77-
group = "processing"
78-
description = "Runs the Processing sketch"
79-
dependsOn("run")
80-
}
81-
project.tasks.create("present").apply {
82-
group = "processing"
83-
description = "Presents the Processing sketch"
84-
doFirst{
85-
project.tasks.withType(JavaExec::class.java).configureEach{ task ->
86-
task.systemProperty("processing.fullscreen", "true")
117+
// Add convenience tasks for running, presenting, and exporting the sketch outside of Processing
118+
if(!isProcessing) {
119+
project.tasks.create("sketch").apply {
120+
group = "processing"
121+
description = "Runs the Processing sketch"
122+
dependsOn("run")
123+
}
124+
project.tasks.create("present").apply {
125+
group = "processing"
126+
description = "Presents the Processing sketch"
127+
doFirst {
128+
project.tasks.withType(JavaExec::class.java).configureEach { task ->
129+
task.systemProperty("processing.fullscreen", "true")
130+
}
87131
}
132+
finalizedBy("run")
88133
}
89-
finalizedBy("run")
90-
}
91-
project.tasks.create("export").apply {
92-
group = "processing"
93-
description = "Creates a distributable version of the Processing sketch"
94-
95-
dependsOn("createDistributable")
96-
doLast{
97-
project.copy {
98-
it.from(project.tasks.named("createDistributable").get().outputs.files)
99-
it.into(project.layout.projectDirectory)
134+
project.tasks.create("export").apply {
135+
group = "processing"
136+
description = "Creates a distributable version of the Processing sketch"
137+
138+
dependsOn("createDistributable")
139+
doLast {
140+
project.copy {
141+
it.from(project.tasks.named("createDistributable").get().outputs.files)
142+
it.into(project.layout.projectDirectory)
143+
}
100144
}
101145
}
102146
}
103147

104148
project.extensions.getByType(JavaPluginExtension::class.java).sourceSets.all { sourceSet ->
105-
// TODO: also supporting normal gradle setup
149+
// For each java source set (mostly main) add a new source set for the PDE files
106150
val pdeSourceSet = objectFactory.newInstance(
107151
DefaultPDESourceDirectorySet::class.java,
108152
objectFactory.sourceDirectorySet("${sourceSet.name}.pde", "${sourceSet.name} Processing Source")
@@ -114,42 +158,26 @@ class ProcessingPlugin @Inject constructor(private val objectFactory: ObjectFact
114158
}
115159
sourceSet.allSource.source(pdeSourceSet)
116160

117-
val outputDirectory = project.layout.buildDirectory.file( "generated/pde/" + sourceSet.name).get().asFile
161+
val outputDirectory = project.layout.buildDirectory.asFile.get().resolve( "generated/pde/" + sourceSet.name)
118162
sourceSet.java.srcDir(outputDirectory)
119163

120164
val taskName = sourceSet.getTaskName("preprocess", "PDE")
121165
project.tasks.register(taskName, ProcessingTask::class.java) { task ->
122166
task.description = "Processes the ${sourceSet.name} PDE"
123167
task.source = pdeSourceSet
124168
task.outputDirectory = outputDirectory
169+
task.sketchName = sketchName
170+
task.workingDir = workingDir
171+
task.sketchBook = sketchbook
125172
}
126173

127174
project.tasks.named(
128175
sourceSet.compileJavaTaskName
129-
) { task -> task.dependsOn(taskName) }
130-
}
131-
132-
// TODO: get this data from code used within the editor
133-
var settingsFolder = File(System.getProperty("user.home"),".processing")
134-
val osName = System.getProperty("os.name").lowercase()
135-
if (osName.contains("win")) {
136-
settingsFolder = File(System.getenv("APPDATA"), "Processing")
137-
} else if (osName.contains("mac")) {
138-
settingsFolder = File(System.getProperty("user.home"), "Library/Processing")
139-
}else if (osName.contains("nix") || osName.contains("nux")) {
140-
settingsFolder = File(System.getProperty("user.home"), ".processing")
176+
) { task ->
177+
task.dependsOn(taskName)
178+
}
141179
}
142180

143-
val preferences = File(settingsFolder, "preferences.txt")
144-
val prefs = Properties()
145-
prefs.load(preferences.inputStream())
146-
prefs.setProperty("export.application.fullscreen", "false")
147-
prefs.setProperty("export.application.present", "false")
148-
prefs.setProperty("export.application.stop", "false")
149-
prefs.store(preferences.outputStream(), null)
150-
151-
val sketchbook = prefs.getProperty("sketchbook.path.four")
152-
153181
// TODO: Move to ProcessingTask after reading the libs from the sketch
154182
File(sketchbook, "libraries").listFiles { file -> file.isDirectory }?.forEach{
155183
project.dependencies.add("implementation", project.fileTree(it).apply { include("**/*.jar") })

java/gradle/src/main/kotlin/ProcessingTask.kt

Lines changed: 27 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,14 @@ package org.processing.java.gradle
33
import org.gradle.api.file.*
44
import org.gradle.api.tasks.*
55
import org.gradle.internal.file.Deleter
6-
import org.gradle.work.ChangeType
7-
import org.gradle.work.FileChange
86
import org.gradle.work.InputChanges
97
import processing.mode.java.preproc.PdePreprocessor
108
import java.io.File
11-
import java.io.IOException
12-
import java.io.UncheckedIOException
139
import java.util.concurrent.Callable
1410
import javax.inject.Inject
1511

1612
abstract class ProcessingTask : SourceTask() {
17-
@get:OutputDirectory
13+
@get:OutputDirectory
1814
var outputDirectory: File? = null
1915

2016
@get:InputFiles
@@ -23,45 +19,43 @@ abstract class ProcessingTask : SourceTask() {
2319
@get:SkipWhenEmpty
2420
open val stableSources: FileCollection = project.files(Callable<Any> { this.source })
2521

22+
@get:Input
23+
@get:Optional
24+
var workingDir: String? = null
25+
26+
@get:Input
27+
var sketchName: String = "processing"
28+
29+
@get:Input
30+
@get:Optional
31+
var sketchBook: String? = null
32+
2633
@TaskAction
2734
fun execute(inputChanges: InputChanges) {
28-
val files: MutableSet<File> = HashSet()
29-
if (inputChanges.isIncremental) {
30-
var rebuildRequired = false
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-
}
35+
// Using stableSources since we can only run the pre-processor on the full set of sources
36+
// TODO: Allow pre-processor to run on individual files
5137

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")
38+
val unsaved = (project.findProperty("processing.unsaved") as String?)?.split(",") ?: emptyList()
39+
40+
val combined = stableSources.map { file ->
41+
if (file.name in unsaved)
42+
File(workingDir, "unsaved").resolve(file.name)
43+
else
44+
file
45+
}.joinToString("\n"){
46+
it.readText()
47+
}
48+
File(outputDirectory, "$sketchName.java")
5549
.bufferedWriter()
5650
.use { out ->
5751
val meta = PdePreprocessor
58-
.builderFor(name)
52+
.builderFor(sketchName)
5953
.build()
6054
.write(out, combined)
6155

6256

63-
// TODO: Only import the libraries that are actually used
6457
val importStatement = meta.importStatements
58+
println(sketchBook)
6559

6660
// for (import in importStatement) {
6761
// project.dependencies.add("implementation", import)

0 commit comments

Comments
 (0)