You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
98 lines
3.6 KiB
98 lines
3.6 KiB
package org.jetbrains.compose.resources |
|
|
|
import org.gradle.api.DefaultTask |
|
import org.gradle.api.file.DirectoryProperty |
|
import org.gradle.api.provider.Property |
|
import org.gradle.api.tasks.* |
|
import java.io.File |
|
import java.nio.file.Path |
|
import javax.xml.parsers.DocumentBuilderFactory |
|
import kotlin.io.path.relativeTo |
|
|
|
/** |
|
* This task should be FAST and SAFE! Because it is being run during IDE import. |
|
*/ |
|
abstract class GenerateResClassTask : DefaultTask() { |
|
@get:Input |
|
abstract val packageName: Property<String> |
|
|
|
@get:InputDirectory |
|
@get:PathSensitive(PathSensitivity.RELATIVE) |
|
abstract val resDir: DirectoryProperty |
|
|
|
@get:OutputDirectory |
|
abstract val codeDir: DirectoryProperty |
|
|
|
init { |
|
this.onlyIf { resDir.asFile.get().exists() } |
|
} |
|
|
|
@TaskAction |
|
fun generate() { |
|
try { |
|
val rootResDir = resDir.get().asFile |
|
logger.info("Generate resources for $rootResDir") |
|
|
|
//get first level dirs |
|
val dirs = rootResDir.listFiles { f -> f.isDirectory }.orEmpty() |
|
|
|
//type -> id -> resource item |
|
val resources: Map<ResourceType, Map<String, List<ResourceItem>>> = dirs |
|
.flatMap { dir -> |
|
dir.listFiles { f -> !f.isDirectory } |
|
.orEmpty() |
|
.mapNotNull { it.fileToResourceItems(rootResDir.parentFile.toPath()) } |
|
.flatten() |
|
} |
|
.groupBy { it.type } |
|
.mapValues { (_, items) -> items.groupBy { it.name } } |
|
|
|
val kotlinDir = codeDir.get().asFile |
|
kotlinDir.deleteRecursively() |
|
kotlinDir.mkdirs() |
|
getResFileSpec(resources, packageName.get()).writeTo(kotlinDir) |
|
} catch (e: Exception) { |
|
//message must contain two ':' symbols to be parsed by IDE UI! |
|
logger.error("e: GenerateResClassTask was failed:", e) |
|
} |
|
} |
|
|
|
private fun File.fileToResourceItems( |
|
relativeTo: Path |
|
): List<ResourceItem>? { |
|
val file = this |
|
if (file.isDirectory) return null |
|
val dirName = file.parentFile.name ?: return null |
|
val typeAndQualifiers = dirName.lowercase().split("-") |
|
if (typeAndQualifiers.isEmpty()) return null |
|
|
|
val typeString = typeAndQualifiers.first().lowercase() |
|
val qualifiers = typeAndQualifiers.takeLast(typeAndQualifiers.size - 1).map { it.lowercase() }.toSet() |
|
val path = file.toPath().relativeTo(relativeTo) |
|
|
|
return if (typeString == "values" && file.name.equals("strings.xml", true)) { |
|
val stringIds = getStringIds(file) |
|
stringIds.map { strId -> |
|
ResourceItem(ResourceType.STRING, qualifiers, strId.lowercase(), path) |
|
} |
|
} else { |
|
val type = try { |
|
ResourceType.fromString(typeString) |
|
} catch (e: Exception) { |
|
logger.error("e: Error: $path", e) |
|
return null |
|
} |
|
listOf(ResourceItem(type, qualifiers, file.nameWithoutExtension.lowercase(), path)) |
|
} |
|
} |
|
|
|
private val stringTypeNames = listOf("string", "string-array") |
|
private fun getStringIds(stringsXml: File): Set<String> { |
|
val doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(stringsXml) |
|
val items = doc.getElementsByTagName("resources").item(0).childNodes |
|
val ids = List(items.length) { items.item(it) } |
|
.filter { it.nodeName in stringTypeNames } |
|
.map { it.attributes.getNamedItem("name").nodeValue } |
|
return ids.toSet() |
|
} |
|
} |