Skip to content
This repository has been archived by the owner on Jul 8, 2022. It is now read-only.

Commit

Permalink
Partial support for gradle cache configuration on the korge plugin (#470
Browse files Browse the repository at this point in the history
)
  • Loading branch information
soywiz-invideo authored Mar 9, 2022
1 parent a61fd37 commit 6ad1cef
Show file tree
Hide file tree
Showing 7 changed files with 206 additions and 150 deletions.
3 changes: 3 additions & 0 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -89,3 +89,6 @@ kotlin.native.ignoreIncorrectDependencies=true
kotlin.native.ignoreDisabledTargets=true

#org.gradle.caching=true

#org.gradle.unsafe.configuration-cache=true
#org.gradle.unsafe.configuration-cache-problems=warn
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ import java.io.*

class KorgeGradleApply(val project: Project) {
fun apply(includeIndirectAndroid: Boolean = true) = project {
System.setProperty("java.awt.headless", "true")
// @TODO: Doing this disables the ability to use configuration cache
//System.setProperty("java.awt.headless", "true")

val currentGradleVersion = SemVer(project.gradle.gradleVersion)
//val expectedGradleVersion = SemVer("6.8.1")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,13 @@ import com.soywiz.korge.gradle.targets.*
import com.soywiz.korge.gradle.targets.jvm.KorgeJavaExec
import com.soywiz.korge.gradle.util.*
import org.gradle.api.*
import org.gradle.api.file.*
import org.gradle.api.tasks.*
import org.jetbrains.kotlin.gradle.dsl.*
import org.jetbrains.kotlin.gradle.plugin.*
import java.io.File
import java.net.*
import javax.inject.Inject

fun Project.getCompilationKorgeProcessedResourcesFolder(compilation: KotlinCompilation<*>): File {
return getCompilationKorgeProcessedResourcesFolder(compilation.target.name, compilation.name)
Expand All @@ -22,68 +26,91 @@ fun getKorgeProcessResourcesTaskName(target: org.jetbrains.kotlin.gradle.plugin.
fun getKorgeProcessResourcesTaskName(targetName: String, compilationName: String): String =
"korgeProcessedResources${targetName.capitalize()}${compilationName.capitalize()}"

fun Project.addGenResourcesTasks() = this {
tasks.apply {
val jvmMainClasses by lazy { (tasks["jvmMainClasses"]) }
val runJvm by lazy { (tasks["runJvm"] as KorgeJavaExec) }
fun Project.addGenResourcesTasks(): Project {
val jvmMainClasses by lazy { (tasks["jvmMainClasses"]) }
val runJvm by lazy { (tasks["runJvm"] as KorgeJavaExec) }

create("listKorgeTargets", Task::class.java) {
it.group = GROUP_KORGE_LIST
it.doLast {
println("gkotlin.targets: ${gkotlin.targets.names}")
}
tasks.create("listKorgeTargets", Task::class.java) {
it.group = GROUP_KORGE_LIST
it.doLast {
println("gkotlin.targets: ${gkotlin.targets.names}")
}
}

create("listKorgePlugins", Task::class.java) {
it.group = GROUP_KORGE_LIST
it.dependsOn(jvmMainClasses)
it.doLast {
//URLClassLoader(prepareResourceProcessingClasses.outputs.files.toList().map { it.toURL() }.toTypedArray(), ClassLoader.getSystemClassLoader()).use { classLoader ->
tasks.create("listKorgePlugins", Task::class.java) {
it.group = GROUP_KORGE_LIST
it.dependsOn("jvmMainClasses")
it.doLast {
//URLClassLoader(prepareResourceProcessingClasses.outputs.files.toList().map { it.toURL() }.toTypedArray(), ClassLoader.getSystemClassLoader()).use { classLoader ->

executeInPlugin(runJvm.korgeClassPath, "com.soywiz.korge.resources.ResourceProcessorRunner", "printPlugins") { listOf(it) }
}
executeInPlugin(runJvm.korgeClassPath, "com.soywiz.korge.resources.ResourceProcessorRunner", "printPlugins") { listOf(it) }
}
}

for (target in kotlin.targets) {
for (compilation in target.compilations) {
val isJvm = compilation.compileKotlinTask.name == "compileKotlinJvm"
val processedResourcesFolder = getCompilationKorgeProcessedResourcesFolder(compilation)
compilation.defaultSourceSet.resources.srcDir(processedResourcesFolder)
val korgeProcessedResources = create(getKorgeProcessResourcesTaskName(target, compilation)) { task ->
task.group = GROUP_KORGE_RESOURCES
//dependsOn(prepareResourceProcessingClasses)
task.dependsOn(jvmMainClasses)

// @TODO: Add specific files instead of all the folders?
task.outputs.dirs(processedResourcesFolder)

task.doLast {
processedResourcesFolder.mkdirs()
//URLClassLoader(prepareResourceProcessingClasses.outputs.files.toList().map { it.toURL() }.toTypedArray(), ClassLoader.getSystemClassLoader()).use { classLoader ->

if (isJvm) {
processedResourcesFolder["@appicon.png"].writeBytes(korge.getIconBytes())
//processedResourcesFolder["@appicon-16.png"].writeBytes(korge.getIconBytes(16))
//processedResourcesFolder["@appicon-32.png"].writeBytes(korge.getIconBytes(32))
//processedResourcesFolder["@appicon-64.png"].writeBytes(korge.getIconBytes(64))
}


val folders = compilation.allKotlinSourceSets.flatMap { it.resources.srcDirs }.filter { it != processedResourcesFolder }.map { it.toString() }

executeInPlugin(runJvm.korgeClassPath, "com.soywiz.korge.resources.ResourceProcessorRunner", "run") { classLoader ->
listOf(classLoader, folders, processedResourcesFolder.toString(), compilation.name)
}
}
}
if (!isJvm) {
compilation.compileKotlinTask.dependsOn(korgeProcessedResources)
} else {
compilation.compileKotlinTask.finalizedBy(korgeProcessedResources)
getByName("runJvm").dependsOn(korgeProcessedResources)
}
for (target in kotlin.targets) {
for (compilation in target.compilations) {
val isJvm = compilation.compileKotlinTask.name == "compileKotlinJvm"
val processedResourcesFolder = getCompilationKorgeProcessedResourcesFolder(compilation)
compilation.defaultSourceSet.resources.srcDir(processedResourcesFolder)

//val compilation = project.kotlin.targets.getByName(config.targetName).compilations.getByName(config.compilationName)
val folders: List<String> = compilation.allKotlinSourceSets.flatMap { it.resources.srcDirs }.filter { it != processedResourcesFolder }.map { it.toString() }

val korgeProcessedResources = tasks.create(
getKorgeProcessResourcesTaskName(target, compilation),
KorgeProcessedResourcesTask::class.java,
KorgeProcessedResourcesTaskConfig(
isJvm, target.name, compilation.name, runJvm.korgeClassPath,
project.korge.getIconBytes(),
)
).also { task ->
task.group = GROUP_KORGE_RESOURCES
task.dependsOn("jvmMainClasses")
task.outputs.dirs(processedResourcesFolder)
task.folders = folders.map { File(it) }
task.processedResourcesFolder = processedResourcesFolder
}
if (!isJvm) {
compilation.compileKotlinTask.dependsOn(korgeProcessedResources)
} else {
compilation.compileKotlinTask.finalizedBy(korgeProcessedResources)
tasks.getByName("runJvm").dependsOn(korgeProcessedResources)
}
}
}
return this
}

data class KorgeProcessedResourcesTaskConfig(
val isJvm: Boolean,
val targetName: String,
val compilationName: String,
val korgeClassPath: FileCollection,
val iconBytes: ByteArray,
)

open class KorgeProcessedResourcesTask @Inject constructor(
private val config: KorgeProcessedResourcesTaskConfig,
//private val fs: FileSystemOperations,
) : DefaultTask() {
@get:OutputDirectory lateinit var processedResourcesFolder: File
// https://docs.gradle.org/7.4/userguide/configuration_cache.html#config_cache:requirements:use_project_during_execution
@get:InputFiles @get:Classpath lateinit var folders: List<File>

@TaskAction
fun run() {
processedResourcesFolder.mkdirs()
//URLClassLoader(prepareResourceProcessingClasses.outputs.files.toList().map { it.toURL() }.toTypedArray(), ClassLoader.getSystemClassLoader()).use { classLoader ->

if (config.isJvm) {
processedResourcesFolder["@appicon.png"].writeBytes(config.iconBytes)
//processedResourcesFolder["@appicon-16.png"].writeBytes(korge.getIconBytes(16))
//processedResourcesFolder["@appicon-32.png"].writeBytes(korge.getIconBytes(32))
//processedResourcesFolder["@appicon-64.png"].writeBytes(korge.getIconBytes(64))
}

executeInPlugin(config.korgeClassPath, "com.soywiz.korge.resources.ResourceProcessorRunner", "run") { classLoader ->
listOf(classLoader, folders.map { it.toString() }, processedResourcesFolder.toString(), config.compilationName)
}
}
}
Original file line number Diff line number Diff line change
@@ -1,35 +1,47 @@
package com.soywiz.korge.gradle.targets

import com.soywiz.korge.gradle.KorgeExtension
import com.soywiz.korge.gradle.KorgeGradlePlugin
import com.soywiz.korge.gradle.*
import com.soywiz.korge.gradle.util.encodePNG
import com.soywiz.korge.gradle.util.getScaledInstance
import com.soywiz.korge.gradle.util.toBufferedImage
import org.gradle.api.*
import java.io.*
import javax.imageio.ImageIO

val ICON_SIZES = listOf(20, 29, 40, 44, 48, 50, 55, 57, 58, 60, 72, 76, 80, 87, 88, 100, 114, 120, 144, 152, 167, 172, 180, 196, 1024)

fun tryGetResourceBytes(path: String): ByteArray? {
return KorgeGradlePlugin::class.java.getResource("/" + path.trim('/'))?.readBytes()
}
fun tryGetResourceBytes(path: String): ByteArray? =
KorgeGradlePlugin::class.java.getResource("/" + path.trim('/'))?.readBytes()

fun getResourceBytes(path: String): ByteArray = tryGetResourceBytes(path) ?: error("Can't find resource '$path'")
fun getResourceString(path: String): String = getResourceBytes(path).toString(Charsets.UTF_8)

fun KorgeExtension.iconExists() = icon != null && icon!!.exists()
fun KorgeExtension.bannerExists() = banner != null && banner!!.exists()
fun KorgeExtension.getIconBytes(): ByteArray = KorgeIconProvider(this).getIconBytes()
fun KorgeExtension.getBannerBytes(): ByteArray = KorgeIconProvider(this).getBannerBytes()

fun KorgeExtension.getIconBytes(): ByteArray = when {
iconExists() -> icon!!.readBytes()
else -> getResourceBytes("/icons/korge.png")
}
fun KorgeExtension.getIconBytes(width: Int, height: Int = width): ByteArray = ImageIO.read(getIconBytes().inputStream()).getScaledInstance(width, height).toBufferedImage().encodePNG()
fun KorgeExtension.getBannerBytes(width: Int, height: Int = width): ByteArray = ImageIO.read(getBannerBytes().inputStream()).getScaledInstance(width, height).toBufferedImage().encodePNG()

fun KorgeExtension.getBannerBytes(): ByteArray = when {
bannerExists() -> banner!!.readBytes()
iconExists() -> icon!!.readBytes()
else -> getResourceBytes("/banners/korge.png")
}
class KorgeIconProvider(val icon: File? = null, val banner: File? = null) {
constructor(korge: KorgeExtension) : this(korge.icon, korge.banner)
constructor(project: Project) : this(project.korge)

fun iconExists() = icon != null && icon!!.exists()
fun bannerExists() = banner != null && banner!!.exists()

fun getIconBytes(): ByteArray = when {
iconExists() -> icon!!.readBytes()
else -> getResourceBytes("/icons/korge.png")
}

fun KorgeExtension.getIconBytes(width: Int, height: Int = width): ByteArray = ImageIO.read(getIconBytes().inputStream()).getScaledInstance(width, height).toBufferedImage().encodePNG()
fun KorgeExtension.getBannerBytes(width: Int, height: Int = width): ByteArray = ImageIO.read(getBannerBytes().inputStream()).getScaledInstance(width, height).toBufferedImage().encodePNG()
fun getBannerBytes(): ByteArray = when {
bannerExists() -> banner!!.readBytes()
iconExists() -> icon!!.readBytes()
else -> getResourceBytes("/banners/korge.png")
}


fun getIconBytes(width: Int, height: Int = width): ByteArray = ImageIO.read(getIconBytes().inputStream()).getScaledInstance(width, height).toBufferedImage().encodePNG()
fun getBannerBytes(width: Int, height: Int = width): ByteArray = ImageIO.read(getBannerBytes().inputStream()).getScaledInstance(width, height).toBufferedImage().encodePNG()

}
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package com.soywiz.korge.gradle.targets

val GROUP_KORGE = "korge"
val GROUP_KORGE_RESOURCES = "korge-resources"
val GROUP_KORGE_RUN = "run"
val GROUP_KORGE_ADB = "adb"
val GROUP_KORGE_LIST = "list"
val GROUP_KORGE_PACKAGE = "package"
val GROUP_KORGE_INSTALL = "install"
const val GROUP_KORGE: String = "korge"
const val GROUP_KORGE_RESOURCES: String = "korge-resources"
const val GROUP_KORGE_RUN: String = "run"
const val GROUP_KORGE_ADB: String = "adb"
const val GROUP_KORGE_LIST: String = "list"
const val GROUP_KORGE_PACKAGE: String = "package"
const val GROUP_KORGE_INSTALL: String = "install"

Original file line number Diff line number Diff line change
Expand Up @@ -58,68 +58,84 @@ fun Project.configureJavaScript() {

val generatedIndexHtmlDir = File(project.buildDir, "processedResources-www")

val jsCreateIndexHtml = project.tasks.create("jsCreateIndexHtml", Task::class.java).apply {
doLast {
val targetDir = generatedIndexHtmlDir
generatedIndexHtmlDir.mkdirs()
logger.info("jsCreateIndexHtml.targetDir: $targetDir")
afterEvaluate {
val jsCreateIndexHtml = project.tasks.create("jsCreateIndexHtml", JsCreateIndexTask::class.java).also { task ->
val jsMainCompilation = kotlin.js().compilations["main"]!!
//val jsFile = File(jsMainCompilation.kotlinOptions.outputFile ?: "dummy.js").name
// @TODO: How to get the actual .js file generated/served?
val jsFile = File("${project.name}.js").name
val resourcesFolders = jsMainCompilation.allKotlinSourceSets
val resourcesFolders: List<File> = jsMainCompilation.allKotlinSourceSets
.flatMap { it.resources.srcDirs } + listOf(File(rootProject.rootDir, "_template"))
//println("jsFile: $jsFile")
//println("resourcesFolders: $resourcesFolders")
fun readTextFile(name: String): String {
for (folder in resourcesFolders) {
val file = File(folder, name)?.takeIf { it.exists() } ?: continue
return file.readText()
}
return JavaScriptClass::class.java.classLoader.getResourceAsStream(name)?.readBytes()?.toString(Charsets.UTF_8)
?: error("We cannot find suitable '$name'")
task.resourcesFolders = resourcesFolders
task.targetDir = generatedIndexHtmlDir
}
(project.tasks.getByName("jsProcessResources") as Copy).apply {
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
dependsOn(jsCreateIndexHtml)
from(generatedIndexHtmlDir) {
it.duplicatesStrategy = DuplicatesStrategy.EXCLUDE
}
//println(this.outputs.files.toList())

val indexTemplateHtml = readTextFile("index.v2.template.html")
val customCss = readTextFile("custom-styles.template.css")
val customHtmlHead = readTextFile("custom-html-head.template.html")
val customHtmlBody = readTextFile("custom-html-body.template.html")
}
}

//println(File(targetDir, "index.html"))
configureEsbuild()
configureWebpackFixes()
configureJavascriptRun()
configureClosureCompiler()
}

try {
File(targetDir, "favicon.ico").writeBytes(ICO2.encode(listOf(16, 32).map {
project.korge.getIconBytes(it).decodeImage()
}))
} catch (e: Throwable) {
e.printStackTrace()
abstract class JsCreateIndexTask : DefaultTask() {
@get:InputFiles lateinit var resourcesFolders: List<File>
//@get:OutputDirectory lateinit var targetDir: File
@Internal lateinit var targetDir: File
private val projectName: String = project.name
private val korgeTitle: String? = project.korge.title
private val korgeName: String? = project.korge.name

private val iconProvider: KorgeIconProvider = KorgeIconProvider(project)

@TaskAction
fun run() {
targetDir.mkdirs()
logger.info("jsCreateIndexHtml.targetDir: $targetDir")
//val jsFile = File(jsMainCompilation.kotlinOptions.outputFile ?: "dummy.js").name
// @TODO: How to get the actual .js file generated/served?
val jsFile = File("${projectName}.js").name
//println("jsFile: $jsFile")
//println("resourcesFolders: $resourcesFolders")
fun readTextFile(name: String): String {
for (folder in resourcesFolders) {
val file = File(folder, name)?.takeIf { it.exists() } ?: continue
return file.readText()
}

File(targetDir, "index.html").writeText(
groovy.text.SimpleTemplateEngine().createTemplate(indexTemplateHtml).make(
mapOf(
"OUTPUT" to jsFile,
"TITLE" to (korge.title ?: korge.name),
"CUSTOM_CSS" to customCss,
"CUSTOM_HTML_HEAD" to customHtmlHead,
"CUSTOM_HTML_BODY" to customHtmlBody
)
).toString()
)
return JavaScriptClass::class.java.classLoader.getResourceAsStream(name)?.readBytes()?.toString(Charsets.UTF_8)
?: error("We cannot find suitable '$name'")
}
}

(project.tasks.getByName("jsProcessResources") as Copy).apply {
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
dependsOn(jsCreateIndexHtml)
from(generatedIndexHtmlDir) {
it.duplicatesStrategy = DuplicatesStrategy.EXCLUDE
val indexTemplateHtml = readTextFile("index.v2.template.html")
val customCss = readTextFile("custom-styles.template.css")
val customHtmlHead = readTextFile("custom-html-head.template.html")
val customHtmlBody = readTextFile("custom-html-body.template.html")

//println(File(targetDir, "index.html"))

try {
File(targetDir, "favicon.ico").writeBytes(ICO2.encode(listOf(16, 32).map {
iconProvider.getIconBytes(it).decodeImage()
}))
} catch (e: Throwable) {
e.printStackTrace()
}
//println(this.outputs.files.toList())

File(targetDir, "index.html").writeText(
groovy.text.SimpleTemplateEngine().createTemplate(indexTemplateHtml).make(
mapOf(
"OUTPUT" to jsFile,
"TITLE" to (korgeTitle ?: korgeName ?: "KorGE"),
"CUSTOM_CSS" to customCss,
"CUSTOM_HTML_HEAD" to customHtmlHead,
"CUSTOM_HTML_BODY" to customHtmlBody
)
).toString()
)
}
configureEsbuild()
configureWebpackFixes()
configureJavascriptRun()
configureClosureCompiler()
}
Loading

0 comments on commit 6ad1cef

Please sign in to comment.