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
Q35OTML226J2HZLHOCPV5OY6ZUM2XU4RZBE5E3GDWVHVFASHFEJAC

Dependencies

  • [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] 5AUENX2Y Add support to view files affected by a revision
  • [4] NTRPUMVQ Improved README and added roadmap.
  • [5] QXUEMZ3B Initial CahngeProvider
  • [6] ZCRW57C5 Improved support for revisions
  • [7] OPFG6CZ2 File status tracking supported.
  • [8] Q7FXTHVU First record support, YEAAAH, RECOOORD
  • [9] FNNW5IEA Added more plugin files to Pijul
  • [10] 7L5LODGZ Parse changes from `pijul change`
  • [11] 6CR2EFUN First ChangeProvider implementation!!! Wheehooo
  • [12] FRFFQV7V Basic show history support.

Change contents

  • edit in src/main/kotlin/com/github/jonathanxd/dracon/pijul/PijulExecution.kt at line 12
    [3.4087][3.4087:4124]()
    import kotlinx.coroutines.flow.Flow
  • replacement in src/main/kotlin/com/github/jonathanxd/dracon/pijul/PijulExecution.kt at line 14
    [3.4147][3.4147:4245]()
    val regularStream: Flow<String>,
    val errorStream: Flow<String>,
    val status: Flow<Int>
    [3.4147]
    [3.4245]
    val regularStream: String,
    val errorStream: String,
    val status: Int
  • edit in src/main/kotlin/com/github/jonathanxd/dracon/log/PijulLog.kt at line 4
    [3.2274]
    [3.2274]
    import com.google.gson.*
  • edit in src/main/kotlin/com/github/jonathanxd/dracon/log/PijulLog.kt at line 7
    [3.61125]
    [3.5891]
    import java.io.Serializable
  • replacement in src/main/kotlin/com/github/jonathanxd/dracon/log/PijulLog.kt at line 14
    [3.2152][3.61126:61206]()
    data class Author(val name: String?, val fullName: String?, val email: String?)
    [3.2152]
    [3.61206]
    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
    [3.61466][3.61466:61468]()
    )
    [3.61466]
    [3.2153]
    ): Serializable
  • replacement in src/main/kotlin/com/github/jonathanxd/dracon/log/PijulLog.kt at line 34
    [3.61585][3.61585:61587]()
    )
    [3.61585]
    [3.2155]
    ): Serializable
  • replacement in src/main/kotlin/com/github/jonathanxd/dracon/log/PijulLog.kt at line 36
    [3.2156][3.61588:61615]()
    sealed class IntOrAsterisk
    [3.2156]
    [3.2156]
    sealed class IntOrAsterisk: Serializable
  • replacement in src/main/kotlin/com/github/jonathanxd/dracon/log/PijulLog.kt at line 41
    [3.61718][3.61718:61754]()
    object Asterisk : IntOrAsterisk() {
    [3.61718]
    [3.61754]
    object Asterisk : IntOrAsterisk(), Serializable {
  • replacement in src/main/kotlin/com/github/jonathanxd/dracon/log/PijulLog.kt at line 48
    [3.61940][3.61940:61994]()
    data class IndexInt(val index: Int) : IntOrAsterisk()
    [3.61940]
    [3.61994]
    data class IndexInt(val index: Int) : IntOrAsterisk(), Serializable
  • replacement in src/main/kotlin/com/github/jonathanxd/dracon/log/PijulLog.kt at line 50
    [3.61995][3.61995:62023]()
    enum class DependencyType {
    [3.61995]
    [3.62023]
    enum class DependencyType: Serializable {
  • replacement in src/main/kotlin/com/github/jonathanxd/dracon/log/PijulLog.kt at line 73
    [3.62311][3.62311:62331]()
    sealed class Hunk {
    [3.62311]
    [3.62331]
    sealed class Hunk: Serializable {
  • replacement in src/main/kotlin/com/github/jonathanxd/dracon/log/PijulLog.kt at line 97
    [3.62810][3.13914:13940]()
    ): Hunk(), HunkWithPath {
    [3.62810]
    [3.13940]
    ): Hunk(), HunkWithPath, Serializable {
  • replacement in src/main/kotlin/com/github/jonathanxd/dracon/log/PijulLog.kt at line 113
    [3.63117][3.14117:14143]()
    ): Hunk(), HunkWithPath {
    [3.63117]
    [3.14143]
    ): Hunk(), HunkWithPath, Serializable {
  • replacement in src/main/kotlin/com/github/jonathanxd/dracon/log/PijulLog.kt at line 128
    [3.63430][3.14210:14236]()
    ): Hunk(), HunkWithPath {
    [3.63430]
    [3.14236]
    ): Hunk(), HunkWithPath, Serializable {
  • replacement in src/main/kotlin/com/github/jonathanxd/dracon/log/PijulLog.kt at line 141
    [3.63695][3.14303:14329]()
    ): Hunk(), HunkWithPath {
    [3.63695]
    [3.14329]
    ): Hunk(), HunkWithPath, Serializable {
  • replacement in src/main/kotlin/com/github/jonathanxd/dracon/log/PijulLog.kt at line 156
    [3.64019][3.14395:14421]()
    ): Hunk(), HunkWithPath {
    [3.64019]
    [3.14421]
    ): Hunk(), HunkWithPath, Serializable {
  • replacement in src/main/kotlin/com/github/jonathanxd/dracon/log/PijulLog.kt at line 171
    [3.64352][3.14488:14514]()
    ): Hunk(), HunkWithPath {
    [3.64352]
    [3.14514]
    ): Hunk(), HunkWithPath, Serializable {
  • replacement in src/main/kotlin/com/github/jonathanxd/dracon/log/PijulLog.kt at line 185
    [3.64642][3.14581:14607]()
    ): Hunk(), HunkWithPath {
    [3.64642]
    [3.14607]
    ): Hunk(), HunkWithPath, Serializable {
  • replacement in src/main/kotlin/com/github/jonathanxd/dracon/log/PijulLog.kt at line 200
    [3.64957][3.14674:14700]()
    ): Hunk(), HunkWithPath {
    [3.64957]
    [3.14700]
    ): Hunk(), HunkWithPath, Serializable {
  • replacement in src/main/kotlin/com/github/jonathanxd/dracon/log/PijulLog.kt at line 215
    [3.65294][3.14767:14793]()
    ): Hunk(), HunkWithPath {
    [3.65294]
    [3.14793]
    ): Hunk(), HunkWithPath, Serializable {
  • replacement in src/main/kotlin/com/github/jonathanxd/dracon/log/PijulLog.kt at line 225
    [3.65485][3.65485:65520]()
    data class Meta(val plain: String)
    [3.65485]
    [3.65520]
    data class Meta(val plain: String): Serializable
  • replacement in src/main/kotlin/com/github/jonathanxd/dracon/log/PijulLog.kt at line 232
    [3.65698][3.65698:65733]()
    data class Flag(val plain: String)
    [3.65698]
    [3.65733]
    data class Flag(val plain: String): Serializable
  • replacement in src/main/kotlin/com/github/jonathanxd/dracon/log/PijulLog.kt at line 236
    [3.65780][3.65780:65804]()
    val new: IntRange?,
    [3.65780]
    [3.65804]
    val new: Range?,
  • replacement in src/main/kotlin/com/github/jonathanxd/dracon/log/PijulLog.kt at line 238
    [3.65831][3.2463:2465](),[3.2463][3.2463:2465]()
    )
    [3.65831]
    [3.2465]
    ): Serializable
    data class Range(val start: Int, val end: Int): Serializable
  • replacement in src/main/kotlin/com/github/jonathanxd/dracon/log/PijulLog.kt at line 246
    [3.65983][3.65983:66057]()
    fun IntRange.intRangeAsSource() = "IntRange(${this.first}, ${this.last})"
    [3.65983]
    [3.2466]
    fun Range.intRangeAsSource() = "Range(${this.start}, ${this.end})"
  • replacement in src/main/kotlin/com/github/jonathanxd/dracon/log/PijulLog.kt at line 248
    [3.2467][3.66058:66080]()
    enum class HunkType {
    [3.2467]
    [3.66080]
    enum class HunkType: Serializable {
  • replacement in src/main/kotlin/com/github/jonathanxd/dracon/log/PijulLog.kt at line 264
    [3.66404][3.66404:66470]()
    data class LineChange(val type: LineChangeType, val data: String)
    [3.66404]
    [3.66470]
    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
    [3.66471][3.66471:66519]()
    enum class LineChangeType(val symbol: String) {
    [3.66471]
    [3.66519]
    enum class LineChangeType(val symbol: String): Serializable {
  • edit in src/main/kotlin/com/github/jonathanxd/dracon/log/PijulLog.kt at line 284
    [3.2518]
    [3.2518]
    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
    [3.2731][3.2731:2799]()
    val message = MESSAGE_PATTERN.find(this)?.groupValues?.get(1)!!
    [3.2731]
    [3.2799]
    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
    [3.68727]
    [3.2989]
    val message = if (messageMultiLine != null) messageMultiLine else messageSingleLine
  • replacement in src/main/kotlin/com/github/jonathanxd/dracon/log/PijulLog.kt at line 667
    [3.81325][3.81325:81429]()
    return PijulLogEntry(hash, message, timestamp.parseAsLocalDateTime(), authors, dependencies, hunks)
    [3.81325]
    [3.81429]
    return PijulLogEntry(hash, message!!, timestamp.parseAsLocalDateTime(), authors, dependencies, hunks)
  • replacement in src/main/kotlin/com/github/jonathanxd/dracon/log/PijulLog.kt at line 697
    [3.82473][3.82473:82517]()
    IntRange(firstPart, secondPart)
    [3.82473]
    [3.82517]
    Range(firstPart, secondPart)
  • replacement in src/main/kotlin/com/github/jonathanxd/dracon/log/PijulLog.kt at line 941
    [3.2822][3.2822:2827]()
    }
    [3.2822]
    }
  • file move: editor (----------)editor (d--r------)
    [3.107]
    [2.4403]
  • edit in src/main/kotlin/com/github/jonathanxd/dracon/cmd/PijulCmd.kt at line 13
    [3.11015]
    [3.15017]
    import com.github.jonathanxd.dracon.cache.HashKey
    import com.github.jonathanxd.dracon.cache.HashMapCache
    import com.github.jonathanxd.dracon.cache.PijulCache
    import com.github.jonathanxd.dracon.cache.PijulLogEntryCache
    import com.github.jonathanxd.dracon.cache.persist.DraconPersistentStateComponent
  • edit in src/main/kotlin/com/github/jonathanxd/dracon/cmd/PijulCmd.kt at line 68
    [3.12224]
    [3.12224]
    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
    [3.10608]
    [3.10608]
    this.reset(project, root)
  • replacement in src/main/kotlin/com/github/jonathanxd/dracon/cmd/PijulCmd.kt at line 342
    [3.11107][3.16544:16696](),[3.16696][3.4990:5031](),[3.4990][3.4990:5031]()
    val change = this.doExecutionWithMapper("change-$hash", this.createPainlessExecPijulOperation(project, root, listOf("change", hash))) {
    it.parseChange(hash)
    [3.11107]
    [3.5031]
    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
    [3.17714][3.18948:19100](),[3.19100][3.17870:17911](),[3.17870][3.17870:17911]()
    val change = this.doExecutionWithMapper("change-$hash", this.createPainlessExecPijulOperation(project, root, listOf("change", hash))) {
    it.parseChange(hash)
    [3.17714]
    [3.17911]
    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
    [3.20085][3.20085:20176]()
    else ChannelInfo(channels.map { PijulChannel(it[0] == '*', it.substring(1)) })
    [3.20085]
    [3.20176]
    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
    [3.13702][3.13702:13800]()
    val status = runBlocking(Dispatchers.IO) {
    execution.status.first()
    }
    [3.13702]
    [3.13800]
    val status = execution.status
  • replacement in src/main/kotlin/com/github/jonathanxd/dracon/cmd/PijulCmd.kt at line 553
    [3.13916][3.13916:14050]()
    val error = runBlocking(Dispatchers.IO) {
    execution.errorStream.toList().joinToString("\n")
    }
    [3.13916]
    [3.14050]
    val error = execution.errorStream
  • replacement in src/main/kotlin/com/github/jonathanxd/dracon/cmd/PijulCmd.kt at line 561
    [3.3971][3.3971:4059](),[3.4059][3.14133:14143](),[3.14133][3.14133:14143]()
    val status = runBlocking(Dispatchers.IO) {
    execution.status.first()
    }
    [3.3971]
    [3.4060]
    val status = execution.status
  • replacement in src/main/kotlin/com/github/jonathanxd/dracon/cmd/PijulCmd.kt at line 564
    [3.4095][3.4095:4229]()
    val std = runBlocking(Dispatchers.IO) {
    execution.regularStream.toList().joinToString("\n")
    }
    [3.4095]
    [3.4229]
    val std = execution.regularStream
  • replacement in src/main/kotlin/com/github/jonathanxd/dracon/cmd/PijulCmd.kt at line 568
    [3.4337][3.4337:4471]()
    val error = runBlocking(Dispatchers.IO) {
    execution.errorStream.toList().joinToString("\n")
    }
    [3.4337]
    [3.4471]
    val error = execution.errorStream
  • replacement in src/main/kotlin/com/github/jonathanxd/dracon/cmd/PijulCmd.kt at line 577
    [3.9507][3.9507:9605]()
    val status = runBlocking(Dispatchers.IO) {
    execution.status.first()
    }
    [3.9507]
    [3.9605]
    val status = execution.status
  • replacement in src/main/kotlin/com/github/jonathanxd/dracon/cmd/PijulCmd.kt at line 580
    [3.9640][3.9640:9774]()
    val std = runBlocking(Dispatchers.IO) {
    execution.regularStream.toList().joinToString("\n")
    }
    [3.9640]
    [3.9774]
    val std = execution.regularStream
  • replacement in src/main/kotlin/com/github/jonathanxd/dracon/cmd/PijulCmd.kt at line 584
    [3.9882][3.9882:10016]()
    val error = runBlocking(Dispatchers.IO) {
    execution.errorStream.toList().joinToString("\n")
    }
    [3.9882]
    [3.10016]
    val error = execution.errorStream
  • replacement in src/main/kotlin/com/github/jonathanxd/dracon/cmd/PijulCmd.kt at line 614
    [3.14610][3.14610:14690]()
    val input = process.inputStream
    val error = process.errorStream
    [3.14610]
    [3.14690]
    val 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()
    [3.14691]
    [3.15128]
    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
    [3.15129][3.15129:15406]()
    if (exit == 0) {
    draconConsoleWriter(project).logCommand("pijul", args, "<Exit status> $exit")
    } else {
    draconConsoleWriter(project).logCommandError("pijul", args, "<Exit status> $exit")
    }
    [3.15129]
    [3.15406]
    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
    [3.15407][3.15407:15471]()
    emit(exit)
    }.flowOn(Dispatchers.IO)
    [3.15407]
    [3.15471]
    return PijulExecution(
    input,
    error,
    exit
  • replacement in src/main/kotlin/com/github/jonathanxd/dracon/cmd/PijulCmd.kt at line 660
    [3.10425][3.10425:10505]()
    val input = process.inputStream
    val error = process.errorStream
    [3.10425]
    [3.10505]
    val 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
    [3.10537][3.10537:10578]()
    input.linesToFlow().onEach {
    [3.10537]
    [3.10578]
    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.
    *
    */
    @RequiresBackgroundThread
    private 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
    [3.10653][3.10653:10709]()
    },
    error.linesToFlow().onEach {
    [3.10653]
    [3.10709]
    }
    error.split("\n").forEach {
  • replacement in src/main/kotlin/com/github/jonathanxd/dracon/cmd/PijulCmd.kt at line 717
    [3.10789][3.10789:10864]()
    },
    flow {
    process.onExit().await()
    [3.10789]
    [3.10864]
    }
  • replacement in src/main/kotlin/com/github/jonathanxd/dracon/cmd/PijulCmd.kt at line 719
    [3.10865][3.10865:11190]()
    val exit = process.exitValue()
    if (exit == 0) {
    draconConsoleWriter(project).logCommand("pijul", args, "<Exit status> $exit")
    } else {
    draconConsoleWriter(project).logCommandError("pijul", args, "<Exit status> $exit")
    }
    [3.10865]
    [3.11190]
    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
    [3.11191][3.11191:11265]()
    emit(exit)
    }.flowOn(Dispatchers.IO)
    )
    [3.11191]
    [3.11265]
    PijulExecution(
    input,
    error,
    exit
    )
    }
  • replacement in src/main/kotlin/com/github/jonathanxd/dracon/cmd/PijulCmd.kt at line 766
    [3.15488][3.22358:22438]()
    val input = process.inputStream
    val error = process.errorStream
    [3.15488]
    [3.22438]
    val 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
    [3.22439][3.22439:22797]()
    return PijulExecution(
    input.linesToFlow().onEach {
    draconConsoleWriter(project).logCommand("pijul", args, it)
    },
    error.linesToFlow().onEach {
    draconConsoleWriter(project).logCommandError("pijul", args, it)
    },
    flow {
    process.onExit().await()
    [3.22439]
    [3.22797]
    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
    [3.22798][3.22798:22845]()
    val exit = process.exitValue()
    [3.22798]
    [3.22845]
    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
    [3.22846][3.22846:23123]()
    if (exit == 0) {
    draconConsoleWriter(project).logCommand("pijul", args, "<Exit status> $exit")
    } else {
    draconConsoleWriter(project).logCommandError("pijul", args, "<Exit status> $exit")
    }
    [3.22846]
    [3.23123]
    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
    [3.23124][3.23124:23188]()
    emit(exit)
    }.flowOn(Dispatchers.IO)
    [3.23124]
    [3.23188]
    return PijulExecution(
    input,
    error,
    exit
  • replacement in src/main/kotlin/com/github/jonathanxd/dracon/cmd/PijulCmd.kt at line 824
    [3.16113][2.10506:10586]()
    val input = process.inputStream
    val error = process.errorStream
    [3.16113]
    [3.16870]
    val 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
    [3.16871][2.10587:10945]()
    return PijulExecution(
    input.linesToFlow().onEach {
    draconConsoleWriter(project).logCommand("pijul", args, it)
    },
    error.linesToFlow().onEach {
    draconConsoleWriter(project).logCommandError("pijul", args, it)
    },
    flow {
    process.onExit().await()
    [3.16871]
    [3.16871]
    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
    [3.16872][2.10946:10993]()
    val exit = process.exitValue()
    [3.16872]
    [3.17143]
    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
    [3.17144][2.10994:11271]()
    if (exit == 0) {
    draconConsoleWriter(project).logCommand("pijul", args, "<Exit status> $exit")
    } else {
    draconConsoleWriter(project).logCommandError("pijul", args, "<Exit status> $exit")
    }
    [3.17144]
    [3.17311]
    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
    [3.17312][2.11272:11336]()
    emit(exit)
    }.flowOn(Dispatchers.IO)
    [3.17312]
    [2.11336]
    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.persist
    import com.github.jonathanxd.dracon.log.PijulLog
    import com.github.jonathanxd.dracon.log.PijulLogEntry
    import com.google.gson.Gson
    import com.google.gson.GsonBuilder
    import com.google.gson.reflect.TypeToken
    import com.intellij.util.xmlb.annotations.Property
    import java.io.ByteArrayInputStream
    import java.io.ByteArrayOutputStream
    import java.io.ObjectInputStream
    import java.io.ObjectOutputStream
    import java.util.*
  • file addition: DraconPersistentStateComponent.kt (----------)
    [0.8582]
    package com.github.jonathanxd.dracon.cache.persist
    import com.github.jonathanxd.dracon.log.PijulLogEntry
    import com.intellij.openapi.components.*
    import com.intellij.util.xmlb.XmlSerializerUtil
    import java.io.*
    import java.nio.file.Files
    import java.nio.file.Path
    import java.nio.file.StandardOpenOption
    import java.util.*
    import java.util.zip.GZIPInputStream
    import java.util.zip.GZIPOutputStream
    @State(name = "DraconLogEntries", storages = [Storage(value = StoragePathMacros.CACHE_FILE)], reloadable = true)
    @Service
    class DraconPersistentStateComponent() : PersistentStateComponent<DraconPersistentStateComponent> {
    public var data: String? = null
    override fun getState() = this
    override 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.cache
    import com.github.jonathanxd.dracon.cache.persist.createLogEntriesPersist
    import com.github.jonathanxd.dracon.cache.persist.toPijulLogEntriesMap
    import com.github.jonathanxd.dracon.log.PijulLogEntry
    import com.github.jonathanxd.dracon.pijul.PijulOperationResult
    import com.github.jonathanxd.dracon.pijul.SuccessStatusCode
    import com.intellij.openapi.project.Project
    import com.intellij.openapi.project.getProjectDataPath
    import java.nio.file.Files
    import 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.cache
    import com.github.jonathanxd.dracon.pijul.PijulExecution
    import java.util.concurrent.ConcurrentHashMap
    import 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]?.updateFn
    if (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)