name.remal.gradle_plugins.dsl.cache.BaseCache.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of gradle-plugins-kotlin-dsl Show documentation
Show all versions of gradle-plugins-kotlin-dsl Show documentation
Remal Gradle plugins: gradle-plugins-kotlin-dsl
package name.remal.gradle_plugins.dsl.cache
import name.remal.forLockedFileChannel
import name.remal.forceDeleteRecursively
import name.remal.lockAndReadBytes
import name.remal.lockAndWriteBytes
import org.gradle.wrapper.GradleUserHomeLookup.gradleUserHome
import java.io.File
import java.nio.ByteBuffer
abstract class BaseCache(protected val cacheId: String, protected val version: Int) {
companion object {
protected val baseCacheDir: File = File(gradleUserHome(), "caches/remal-gradle-plugins").absoluteFile
private val CACHE_ID_REGEX = Regex("[\\w./-]+")
}
protected abstract val serializer: (value: WriteValueType) -> ByteArray?
protected abstract val deserializer: (bytes: ByteArray) -> ReadValueType?
init {
if (!cacheId.matches(CACHE_ID_REGEX)) {
throw IllegalArgumentException("Cache ID '$cacheId' doesn't match to '$CACHE_ID_REGEX' regex")
}
if (version <= 0) {
throw IllegalArgumentException("version <= 0: $version")
}
}
private val cacheFile = File(baseCacheDir, buildString {
if (cacheId.contains('/')) {
append(cacheId.substringBeforeLast('/')).append('/')
}
val fileName = cacheId.substringAfterLast('/')
val extPos = fileName.lastIndexOf('.')
if (0 <= extPos) {
append(fileName.substring(0, extPos))
append(".").append(version)
append(fileName.substring(extPos))
} else {
append(fileName)
append(".").append(version)
}
})
fun write(value: WriteValueType?) {
val bytes = value?.let(serializer)
if (bytes == null) {
cacheFile.forceDeleteRecursively()
} else {
cacheFile.lockAndWriteBytes(bytes)
}
}
fun read(): ReadValueType? {
if (cacheFile.exists()) {
val bytes = cacheFile.lockAndReadBytes()
val value = deserializer(bytes)
return value
} else {
return null
}
}
fun compute(func: (currentValue: ReadValueType?) -> WriteValueType?) {
synchronized(this) {
cacheFile.forLockedFileChannel { channel ->
val currentValue = read()
val value = func(currentValue)
val bytes = value?.let(serializer)
if (bytes == null) {
cacheFile.forceDeleteRecursively()
} else {
channel.write(ByteBuffer.wrap(bytes))
}
Unit
}
}
}
override fun toString() = "${javaClass.simpleName}[$cacheId/$version]"
}