Remove use of coroutines, which was blocking IntelliJ UI in larger repositories Improvements for bigger repositories, now Dracon caches the changes that happened in a revision in a file, so everytime Dracon needs to query the changes of a revision, it loads directly from memory instead of doing a full-scan in Pijul repository. For tiny projects it is not a problem, but for medium ones it takes more than five minutes to scan the entire repository (and it was tested with a repo of only 700 records, however there was changes that had more than 60.000 lines). The cache file is saved in IntelliJ Data Path (project specific) and is compressed with gzip, so it will not use so much disk space (the cost worths the gains).
[?]
Apr 2, 2021, 9:31 PM
Q35OTML226J2HZLHOCPV5OY6ZUM2XU4RZBE5E3GDWVHVFASHFEJACDependencies
- [2]
B43WNBLF- Add Show History to Pijul menu - Always ignore .idea and .pijul in tracking. - Make findPijul a generic function to allow to find editor-server. - Only show one revision for directories. - Add `Hunk::resolvePath(Path)` to resolve the affected file to a Java NIO Path. - Fix StringOutOfBounds in Change Parsering Algorithm - Use editor-server instead of copie for interfacing with `pijul record` file. - Fix FileStatus provider not returning correctly for untracked files. - Add CommittedChangesProvider for Pijul. - [3]
5AUENX2YAdd support to view files affected by a revision - [4]
NTRPUMVQImproved README and added roadmap. - [5]
QXUEMZ3BInitial CahngeProvider - [6]
ZCRW57C5Improved support for revisions - [7]
OPFG6CZ2File status tracking supported. - [8]
Q7FXTHVUFirst record support, YEAAAH, RECOOORD - [9]
FNNW5IEAAdded more plugin files to Pijul - [10]
7L5LODGZParse changes from `pijul change` - [11]
6CR2EFUNFirst ChangeProvider implementation!!! Wheehooo - [12]
FRFFQV7VBasic show history support.
Change contents
- edit in src/main/kotlin/com/github/jonathanxd/dracon/pijul/PijulExecution.kt at line 12
import kotlinx.coroutines.flow.Flow - replacement in src/main/kotlin/com/github/jonathanxd/dracon/pijul/PijulExecution.kt at line 14
val regularStream: Flow<String>,val errorStream: Flow<String>,val status: Flow<Int>val regularStream: String,val errorStream: String,val status: Int - edit in src/main/kotlin/com/github/jonathanxd/dracon/log/PijulLog.kt at line 4
import com.google.gson.* - edit in src/main/kotlin/com/github/jonathanxd/dracon/log/PijulLog.kt at line 7
import java.io.Serializable - replacement in src/main/kotlin/com/github/jonathanxd/dracon/log/PijulLog.kt at line 14
data class Author(val name: String?, val fullName: String?, val email: String?)data class Author(val name: String?, val fullName: String?, val email: String?): Serializable - replacement in src/main/kotlin/com/github/jonathanxd/dracon/log/PijulLog.kt at line 24
)): Serializable - replacement in src/main/kotlin/com/github/jonathanxd/dracon/log/PijulLog.kt at line 34
)): Serializable - replacement in src/main/kotlin/com/github/jonathanxd/dracon/log/PijulLog.kt at line 36
sealed class IntOrAsterisksealed class IntOrAsterisk: Serializable - replacement in src/main/kotlin/com/github/jonathanxd/dracon/log/PijulLog.kt at line 41
object Asterisk : IntOrAsterisk() {object Asterisk : IntOrAsterisk(), Serializable { - replacement in src/main/kotlin/com/github/jonathanxd/dracon/log/PijulLog.kt at line 48
data class IndexInt(val index: Int) : IntOrAsterisk()data class IndexInt(val index: Int) : IntOrAsterisk(), Serializable - replacement in src/main/kotlin/com/github/jonathanxd/dracon/log/PijulLog.kt at line 50
enum class DependencyType {enum class DependencyType: Serializable { - replacement in src/main/kotlin/com/github/jonathanxd/dracon/log/PijulLog.kt at line 73
sealed class Hunk {sealed class Hunk: Serializable { - replacement in src/main/kotlin/com/github/jonathanxd/dracon/log/PijulLog.kt at line 97
): Hunk(), HunkWithPath {): Hunk(), HunkWithPath, Serializable { - replacement in src/main/kotlin/com/github/jonathanxd/dracon/log/PijulLog.kt at line 113
): Hunk(), HunkWithPath {): Hunk(), HunkWithPath, Serializable { - replacement in src/main/kotlin/com/github/jonathanxd/dracon/log/PijulLog.kt at line 128
): Hunk(), HunkWithPath {): Hunk(), HunkWithPath, Serializable { - replacement in src/main/kotlin/com/github/jonathanxd/dracon/log/PijulLog.kt at line 141
): Hunk(), HunkWithPath {): Hunk(), HunkWithPath, Serializable { - replacement in src/main/kotlin/com/github/jonathanxd/dracon/log/PijulLog.kt at line 156
): Hunk(), HunkWithPath {): Hunk(), HunkWithPath, Serializable { - replacement in src/main/kotlin/com/github/jonathanxd/dracon/log/PijulLog.kt at line 171
): Hunk(), HunkWithPath {): Hunk(), HunkWithPath, Serializable { - replacement in src/main/kotlin/com/github/jonathanxd/dracon/log/PijulLog.kt at line 185
): Hunk(), HunkWithPath {): Hunk(), HunkWithPath, Serializable { - replacement in src/main/kotlin/com/github/jonathanxd/dracon/log/PijulLog.kt at line 200
): Hunk(), HunkWithPath {): Hunk(), HunkWithPath, Serializable { - replacement in src/main/kotlin/com/github/jonathanxd/dracon/log/PijulLog.kt at line 215
): Hunk(), HunkWithPath {): Hunk(), HunkWithPath, Serializable { - replacement in src/main/kotlin/com/github/jonathanxd/dracon/log/PijulLog.kt at line 225
data class Meta(val plain: String)data class Meta(val plain: String): Serializable - replacement in src/main/kotlin/com/github/jonathanxd/dracon/log/PijulLog.kt at line 232
data class Flag(val plain: String)data class Flag(val plain: String): Serializable - replacement in src/main/kotlin/com/github/jonathanxd/dracon/log/PijulLog.kt at line 236
val new: IntRange?,val new: Range?, - replacement in src/main/kotlin/com/github/jonathanxd/dracon/log/PijulLog.kt at line 238
)): Serializabledata class Range(val start: Int, val end: Int): Serializable - replacement in src/main/kotlin/com/github/jonathanxd/dracon/log/PijulLog.kt at line 246
fun IntRange.intRangeAsSource() = "IntRange(${this.first}, ${this.last})"fun Range.intRangeAsSource() = "Range(${this.start}, ${this.end})" - replacement in src/main/kotlin/com/github/jonathanxd/dracon/log/PijulLog.kt at line 248
enum class HunkType {enum class HunkType: Serializable { - replacement in src/main/kotlin/com/github/jonathanxd/dracon/log/PijulLog.kt at line 264
data class LineChange(val type: LineChangeType, val data: String)data class LineChange(val type: LineChangeType, val data: String): Serializable - replacement in src/main/kotlin/com/github/jonathanxd/dracon/log/PijulLog.kt at line 266
enum class LineChangeType(val symbol: String) {enum class LineChangeType(val symbol: String): Serializable { - edit in src/main/kotlin/com/github/jonathanxd/dracon/log/PijulLog.kt at line 284
val MULTI_LINE_MESSAGE_PATTERN = Regex("message = '''(.*)'''", RegexOption.DOT_MATCHES_ALL) - replacement in src/main/kotlin/com/github/jonathanxd/dracon/log/PijulLog.kt at line 309
val message = MESSAGE_PATTERN.find(this)?.groupValues?.get(1)!!val messageSingleLine = MESSAGE_PATTERN.find(this)?.groupValues?.get(1)val messageMultiLine = MULTI_LINE_MESSAGE_PATTERN.find(this)?.groupValues?.get(1) - edit in src/main/kotlin/com/github/jonathanxd/dracon/log/PijulLog.kt at line 318
val message = if (messageMultiLine != null) messageMultiLine else messageSingleLine - replacement in src/main/kotlin/com/github/jonathanxd/dracon/log/PijulLog.kt at line 667
return PijulLogEntry(hash, message, timestamp.parseAsLocalDateTime(), authors, dependencies, hunks)return PijulLogEntry(hash, message!!, timestamp.parseAsLocalDateTime(), authors, dependencies, hunks) - replacement in src/main/kotlin/com/github/jonathanxd/dracon/log/PijulLog.kt at line 697
IntRange(firstPart, secondPart)Range(firstPart, secondPart) - replacement in src/main/kotlin/com/github/jonathanxd/dracon/log/PijulLog.kt at line 941
}[3.2822]} - file move: editor → editor
- edit in src/main/kotlin/com/github/jonathanxd/dracon/cmd/PijulCmd.kt at line 13
import com.github.jonathanxd.dracon.cache.HashKeyimport com.github.jonathanxd.dracon.cache.HashMapCacheimport com.github.jonathanxd.dracon.cache.PijulCacheimport com.github.jonathanxd.dracon.cache.PijulLogEntryCacheimport com.github.jonathanxd.dracon.cache.persist.DraconPersistentStateComponent - edit in src/main/kotlin/com/github/jonathanxd/dracon/cmd/PijulCmd.kt at line 68
private val cache: PijulCache = HashMapCache()private val pijulLogEntryCache = PijulLogEntryCache(this.project) - edit in src/main/kotlin/com/github/jonathanxd/dracon/cmd/PijulCmd.kt at line 181
this.reset(project, root) - replacement in src/main/kotlin/com/github/jonathanxd/dracon/cmd/PijulCmd.kt at line 342
val change = this.doExecutionWithMapper("change-$hash", this.createPainlessExecPijulOperation(project, root, listOf("change", hash))) {it.parseChange(hash)val change = this.pijulLogEntryCache.queryOrCompute(hash) {this.doExecutionWithMapper("change-$hash",this.createPainlessExecPijulOperation(project, root, listOf("change", hash))) {it.parseChange(hash)} - replacement in src/main/kotlin/com/github/jonathanxd/dracon/cmd/PijulCmd.kt at line 409
val change = this.doExecutionWithMapper("change-$hash", this.createPainlessExecPijulOperation(project, root, listOf("change", hash))) {it.parseChange(hash)val change = this.pijulLogEntryCache.queryOrCompute(hash) {this.doExecutionWithMapper("change-$hash",this.createPainlessExecPijulOperation(project, root, listOf("change", hash))) {it.parseChange(hash)} - replacement in src/main/kotlin/com/github/jonathanxd/dracon/cmd/PijulCmd.kt at line 543
else ChannelInfo(channels.map { PijulChannel(it[0] == '*', it.substring(1)) })else ChannelInfo(channels.filter { it.isNotEmpty() }.map { PijulChannel(it[0] == '*', it.substring(1)) }) - replacement in src/main/kotlin/com/github/jonathanxd/dracon/cmd/PijulCmd.kt at line 548
val status = runBlocking(Dispatchers.IO) {execution.status.first()}val status = execution.status - replacement in src/main/kotlin/com/github/jonathanxd/dracon/cmd/PijulCmd.kt at line 553
val error = runBlocking(Dispatchers.IO) {execution.errorStream.toList().joinToString("\n")}val error = execution.errorStream - replacement in src/main/kotlin/com/github/jonathanxd/dracon/cmd/PijulCmd.kt at line 561
val status = runBlocking(Dispatchers.IO) {execution.status.first()}val status = execution.status - replacement in src/main/kotlin/com/github/jonathanxd/dracon/cmd/PijulCmd.kt at line 564
val std = runBlocking(Dispatchers.IO) {execution.regularStream.toList().joinToString("\n")}val std = execution.regularStream - replacement in src/main/kotlin/com/github/jonathanxd/dracon/cmd/PijulCmd.kt at line 568
val error = runBlocking(Dispatchers.IO) {execution.errorStream.toList().joinToString("\n")}val error = execution.errorStream - replacement in src/main/kotlin/com/github/jonathanxd/dracon/cmd/PijulCmd.kt at line 577
val status = runBlocking(Dispatchers.IO) {execution.status.first()}val status = execution.status - replacement in src/main/kotlin/com/github/jonathanxd/dracon/cmd/PijulCmd.kt at line 580
val std = runBlocking(Dispatchers.IO) {execution.regularStream.toList().joinToString("\n")}val std = execution.regularStream - replacement in src/main/kotlin/com/github/jonathanxd/dracon/cmd/PijulCmd.kt at line 584
val error = runBlocking(Dispatchers.IO) {execution.errorStream.toList().joinToString("\n")}val error = execution.errorStream - replacement in src/main/kotlin/com/github/jonathanxd/dracon/cmd/PijulCmd.kt at line 614
val input = process.inputStreamval error = process.errorStreamval input = String(process.inputStream.readAllBytes(), Charsets.UTF_8)val error = String(process.errorStream.readAllBytes(), Charsets.UTF_8) - replacement in src/main/kotlin/com/github/jonathanxd/dracon/cmd/PijulCmd.kt at line 617[3.14691]→[3.14691:15048](∅→∅),[3.15048]→[3.4705:4738](∅→∅),[3.4738]→[3.15081:15128](∅→∅),[3.15081]→[3.15081:15128](∅→∅)
return PijulExecution(input.linesToFlow().onEach {draconConsoleWriter(project).logCommand("pijul", args, it)},error.linesToFlow().onEach {draconConsoleWriter(project).logCommandError("pijul", args, it)},flow {while (process.isAlive)delay(delay)val exit = process.exitValue()input.split("\n").forEach {draconConsoleWriter(project).logCommand("pijul", args, it)}error.split("\n").forEach {draconConsoleWriter(project).logCommandError("pijul", args, it)} - replacement in src/main/kotlin/com/github/jonathanxd/dracon/cmd/PijulCmd.kt at line 625
if (exit == 0) {draconConsoleWriter(project).logCommand("pijul", args, "<Exit status> $exit")} else {draconConsoleWriter(project).logCommandError("pijul", args, "<Exit status> $exit")}val exit = process.waitFor()if (exit == 0) {draconConsoleWriter(project).logCommand("pijul", args, "<Exit status> $exit")} else {draconConsoleWriter(project).logCommandError("pijul", args, "<Exit status> $exit")} - replacement in src/main/kotlin/com/github/jonathanxd/dracon/cmd/PijulCmd.kt at line 632
emit(exit)}.flowOn(Dispatchers.IO)return PijulExecution(input,error,exit - replacement in src/main/kotlin/com/github/jonathanxd/dracon/cmd/PijulCmd.kt at line 660
val input = process.inputStreamval error = process.errorStreamval input = String(process.inputStream.readAllBytes(), Charsets.UTF_8)val error = String(process.errorStream.readAllBytes(), Charsets.UTF_8)input.split("\n").forEach {draconConsoleWriter(project).logCommand("pijul", args, it)}error.split("\n").forEach {draconConsoleWriter(project).logCommandError("pijul", args, it)}val exit = process.waitFor()if (exit == 0) {draconConsoleWriter(project).logCommand("pijul", args, "<Exit status> $exit")} else {draconConsoleWriter(project).logCommandError("pijul", args, "<Exit status> $exit")} - replacement in src/main/kotlin/com/github/jonathanxd/dracon/cmd/PijulCmd.kt at line 679
input.linesToFlow().onEach {input,error,exit)}/*** Creates a [PijulExecution] operation that could be executed at any time. This operation uses Kotlin Coroutines* and can be executed immediately through [doExecution] or through [doExecutionWithMapper].** This implementation does not requires a delay value to be provided, like [createExecPijulOperation] does, instead* it uses the kotlin conversion from `CompletionStage` to `Coroutines` and awaits the process through [Process.onExit].** [doExecution] and [doExecutionWithMapper] does execution by scheduling task to [Dispatchers.IO], instead of Main Thread,* offloading the Process execution handling to a different scheduler. However, mapping operation of [doExecutionWithMapper]* is not offloaded from the caller context.**/@RequiresBackgroundThreadprivate fun <K: Any> createPainlessExecPijulOperationWithCache(project: Project,dir: Path,args: List<String>,key: K): PijulExecution {return this.cache.cache(key) {val process = ProcessBuilder().command(listOf(this.findPijul()) + args).directory(dir.toFile()).start()val input = String(process.inputStream.readAllBytes(), Charsets.UTF_8)val error = String(process.errorStream.readAllBytes(), Charsets.UTF_8)input.split("\n").forEach { - replacement in src/main/kotlin/com/github/jonathanxd/dracon/cmd/PijulCmd.kt at line 713
},error.linesToFlow().onEach {}error.split("\n").forEach { - replacement in src/main/kotlin/com/github/jonathanxd/dracon/cmd/PijulCmd.kt at line 717
},flow {process.onExit().await()} - replacement in src/main/kotlin/com/github/jonathanxd/dracon/cmd/PijulCmd.kt at line 719
val exit = process.exitValue()if (exit == 0) {draconConsoleWriter(project).logCommand("pijul", args, "<Exit status> $exit")} else {draconConsoleWriter(project).logCommandError("pijul", args, "<Exit status> $exit")}val exit = process.waitFor()if (exit == 0) {draconConsoleWriter(project).logCommand("pijul", args, "<Exit status> $exit")} else {draconConsoleWriter(project).logCommandError("pijul", args, "<Exit status> $exit")} - replacement in src/main/kotlin/com/github/jonathanxd/dracon/cmd/PijulCmd.kt at line 726
emit(exit)}.flowOn(Dispatchers.IO))PijulExecution(input,error,exit)} - replacement in src/main/kotlin/com/github/jonathanxd/dracon/cmd/PijulCmd.kt at line 766
val input = process.inputStreamval error = process.errorStreamval input = String(process.inputStream.readAllBytes(), Charsets.UTF_8)val error = String(process.errorStream.readAllBytes(), Charsets.UTF_8) - replacement in src/main/kotlin/com/github/jonathanxd/dracon/cmd/PijulCmd.kt at line 769
return PijulExecution(input.linesToFlow().onEach {draconConsoleWriter(project).logCommand("pijul", args, it)},error.linesToFlow().onEach {draconConsoleWriter(project).logCommandError("pijul", args, it)},flow {process.onExit().await()input.split("\n").forEach {draconConsoleWriter(project).logCommand("pijul", args, it)} - replacement in src/main/kotlin/com/github/jonathanxd/dracon/cmd/PijulCmd.kt at line 773
val exit = process.exitValue()error.split("\n").forEach {draconConsoleWriter(project).logCommandError("pijul", args, it)} - replacement in src/main/kotlin/com/github/jonathanxd/dracon/cmd/PijulCmd.kt at line 777
if (exit == 0) {draconConsoleWriter(project).logCommand("pijul", args, "<Exit status> $exit")} else {draconConsoleWriter(project).logCommandError("pijul", args, "<Exit status> $exit")}val exit = process.waitFor()if (exit == 0) {draconConsoleWriter(project).logCommand("pijul", args, "<Exit status> $exit")} else {draconConsoleWriter(project).logCommandError("pijul", args, "<Exit status> $exit")} - replacement in src/main/kotlin/com/github/jonathanxd/dracon/cmd/PijulCmd.kt at line 784
emit(exit)}.flowOn(Dispatchers.IO)return PijulExecution(input,error,exit - replacement in src/main/kotlin/com/github/jonathanxd/dracon/cmd/PijulCmd.kt at line 824
val input = process.inputStreamval error = process.errorStreamval input = String(process.inputStream.readAllBytes(), Charsets.UTF_8)val error = String(process.errorStream.readAllBytes(), Charsets.UTF_8) - replacement in src/main/kotlin/com/github/jonathanxd/dracon/cmd/PijulCmd.kt at line 827
return PijulExecution(input.linesToFlow().onEach {draconConsoleWriter(project).logCommand("pijul", args, it)},error.linesToFlow().onEach {draconConsoleWriter(project).logCommandError("pijul", args, it)},flow {process.onExit().await()input.split("\n").forEach {draconConsoleWriter(project).logCommand("pijul", args, it)} - replacement in src/main/kotlin/com/github/jonathanxd/dracon/cmd/PijulCmd.kt at line 831
val exit = process.exitValue()error.split("\n").forEach {draconConsoleWriter(project).logCommandError("pijul", args, it)} - replacement in src/main/kotlin/com/github/jonathanxd/dracon/cmd/PijulCmd.kt at line 835
if (exit == 0) {draconConsoleWriter(project).logCommand("pijul", args, "<Exit status> $exit")} else {draconConsoleWriter(project).logCommandError("pijul", args, "<Exit status> $exit")}val exit = process.waitFor()if (exit == 0) {draconConsoleWriter(project).logCommand("pijul", args, "<Exit status> $exit")} else {draconConsoleWriter(project).logCommandError("pijul", args, "<Exit status> $exit")} - replacement in src/main/kotlin/com/github/jonathanxd/dracon/cmd/PijulCmd.kt at line 842
emit(exit)}.flowOn(Dispatchers.IO)return PijulExecution(input,error,exit - file addition: cache[3.107]
- file addition: persist[0.8571]
- file addition: LogEntriesPersist.kt[0.8582]
package com.github.jonathanxd.dracon.cache.persistimport com.github.jonathanxd.dracon.log.PijulLogimport com.github.jonathanxd.dracon.log.PijulLogEntryimport com.google.gson.Gsonimport com.google.gson.GsonBuilderimport com.google.gson.reflect.TypeTokenimport com.intellij.util.xmlb.annotations.Propertyimport java.io.ByteArrayInputStreamimport java.io.ByteArrayOutputStreamimport java.io.ObjectInputStreamimport java.io.ObjectOutputStreamimport java.util.* - file addition: DraconPersistentStateComponent.kt[0.8582]
package com.github.jonathanxd.dracon.cache.persistimport com.github.jonathanxd.dracon.log.PijulLogEntryimport com.intellij.openapi.components.*import com.intellij.util.xmlb.XmlSerializerUtilimport java.io.*import java.nio.file.Filesimport java.nio.file.Pathimport java.nio.file.StandardOpenOptionimport java.util.*import java.util.zip.GZIPInputStreamimport java.util.zip.GZIPOutputStream@State(name = "DraconLogEntries", storages = [Storage(value = StoragePathMacros.CACHE_FILE)], reloadable = true)@Serviceclass DraconPersistentStateComponent() : PersistentStateComponent<DraconPersistentStateComponent> {public var data: String? = nulloverride fun getState() = thisoverride fun loadState(state: DraconPersistentStateComponent) {XmlSerializerUtil.copyBean(state, this);}}fun String.toPijulLogEntries(): List<PijulLogEntry> {val decoded = Base64.getDecoder().decode(this)val reader = ObjectInputStream(ByteArrayInputStream(decoded))return reader.readObject() as List<PijulLogEntry>}fun createLogEntriesPersist(entries: List<PijulLogEntry>): String {val stream = ByteArrayOutputStream()val writer = ObjectOutputStream(stream)writer.writeObject(entries)writer.close()return Base64.getEncoder().encodeToString(stream.toByteArray())}fun Path.toPijulLogEntriesMap(): Map<String, PijulLogEntry> {Files.newInputStream(this).use { stream ->GZIPInputStream(stream).use { gz ->ObjectInputStream(gz).use { reader ->return reader.readObject() as Map<String, PijulLogEntry>}}}}fun String.toPijulLogEntriesMap(): Map<String, PijulLogEntry> {val decoded = Base64.getDecoder().decode(this)val reader = ObjectInputStream(GZIPInputStream(ByteArrayInputStream(decoded)))return reader.readObject() as Map<String, PijulLogEntry>}fun Path.createLogEntriesPersist(entries: Map<String, PijulLogEntry>) {Files.newOutputStream(this, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING).use { writer ->GZIPOutputStream(writer).use { compress ->ObjectOutputStream(compress).use {oos ->oos.writeObject(entries)}}}} - file addition: PijulLogEntryCache.kt[0.8571]
package com.github.jonathanxd.dracon.cacheimport com.github.jonathanxd.dracon.cache.persist.createLogEntriesPersistimport com.github.jonathanxd.dracon.cache.persist.toPijulLogEntriesMapimport com.github.jonathanxd.dracon.log.PijulLogEntryimport com.github.jonathanxd.dracon.pijul.PijulOperationResultimport com.github.jonathanxd.dracon.pijul.SuccessStatusCodeimport com.intellij.openapi.project.Projectimport com.intellij.openapi.project.getProjectDataPathimport java.nio.file.Filesimport java.util.concurrent.ConcurrentHashMap@Suppress("UnstableApiUsage")class PijulLogEntryCache(val project: Project) {private val map = ConcurrentHashMap<String, PijulLogEntry>()private val cachePath = project.getProjectDataPath("com.jonathanxd.dracon")private val cacheFile = cachePath.resolve("log.obj")init {Files.createDirectories(cachePath)if (Files.exists(this.cacheFile)) {try {this.map.putAll(this.cacheFile.toPijulLogEntriesMap())} catch (e: Throwable) {Files.delete(this.cacheFile)}}}fun queryOrCompute(hash: String, compute: () -> PijulOperationResult<PijulLogEntry>): PijulOperationResult<PijulLogEntry> {return if (!this.map.containsKey(hash)) {val computeEntry = compute()if (computeEntry.statusCode !is SuccessStatusCode) {return computeEntry}this.map[hash] = computeEntry.result!!this.cacheFile.createLogEntriesPersist(this.map)computeEntry} else {PijulOperationResult("change-$hash", SuccessStatusCode, this.map[hash])}}} - file addition: PijulCache.kt[0.8571]
@file:Suppress("UNCHECKED_CAST")package com.github.jonathanxd.dracon.cacheimport com.github.jonathanxd.dracon.pijul.PijulExecutionimport java.util.concurrent.ConcurrentHashMapimport java.util.concurrent.Executors/*** Some changes are so big that it takes a long time to retrieve, refreshing the view would cause* the entire change tree to be retrieved again from Pijul, taking a long time again, this cache tries to alleviate* this by caching the result of `Pijul` command.** It in fact, does not cache the result of `pijul` command, it could cache anything, however an update function* must be provided when querying the cache. The update function must be a pure function and the function identity* must be tied to the `key`, in other words, the `key` is the identity of the function. This constraint must never be broken,* because [PijulCache] does no update stored functions, the function is stored only when there is no cache data for the `key`,* subsequent calls will ignore the provided function.*/interface PijulCache {/*** Retrieves cached value, or computes if absent.*/fun <K: Any, V: Any> cache(key: K, updateFn: () -> V): V/*** Request the cache to be updated, it does not mean that the cache will be updated in the time this is invoked.*/fun <K: Any> requestUpdate(key: K)}class HashMapCache : PijulCache {private val cache = ConcurrentHashMap<Any, Cache<*>>()private val updateExecutor = Executors.newCachedThreadPool()override fun <K: Any, V: Any> cache(key: K, updateFn: () -> V): V {return (this.cache.computeIfAbsent(key) {val update = updateFn()Cache(update, updateFn)} as Cache<V>).value}override fun <K : Any> requestUpdate(key: K) {val fn = this.cache[key]?.updateFnif (fn != null) {updateExecutor.submit {val updated = fn()this.cache[key] = Cache(updated, fn)}}}}data class HashKey(val hash: String)data class Cache<V: Any>(var value: V, var updateFn: (() -> V)?)data class CommandResult(val stdOut: String, val stdErr: String)