RE4EKNSLYGCITZZEOPIRJAWTKIONGP7IY6S77BQO7JQL2CK27RZAC OMZXJL6QA6INENIEAARSWYFHOPMLTP4WRCVI646GQVJVWCH3LENQC 37OJKSWJFDRHNWQW6P7HSZX6OWZWVNCJ2IFT42O5TANQF7VOVX6AC GGYFPXND4VBCROZZXTKAP7Y4JOP2OOYQAFVLMUE7SLFM225EUSIAC FRFFQV7VNYKGCA7ZAOSRPC2HHYTAIZ6AGGR7A5QEV6QPAQGFDYGAC ZCRW57C5MSBXYGUMGQTZNHGHO4HGHFBICW53X5I2IMGP3H2CKWRQC ISO7J5ZH5UB7NFZKTKKJQHQHCP4DWQ3F7SM2NDMVYJAGGIKDLX4QC FNNW5IEAXQ43WKB6QSQB7DFLG3Y3T5FYPXIUX7KQ2URR2GU3QLTAC 2N67RQZCVGL6GYJJLM2US4YVCEIUK25AHCLD66C7HR4PPTNUOCWAC 6CR2EFUN7JXFHCBTNX3WWOOP4WFOCFO6KSPEBN6V6J5HFZO2LHNQC Q7FXTHVUPVAFMNY277C3NFJO3VXLZU5G6C6UYSD5QPURHSG3A7OQC OPFG6CZ26PPTGTH7ULLRQGZGR3YEIEJOV5W2E3WN7PFRZS62CVLQC Q35OTML226J2HZLHOCPV5OY6ZUM2XU4RZBE5E3GDWVHVFASHFEJAC MTPTFTHGAOKQGRUDXC55AM6XJHZZZ5EF6FPVXKFVCUYVXJNEANYQC if (Files.exists(tmpTarget.resolve(".pijul"))) {val ls = pijul(project).trackedFiles(project, tmpTarget)if (ls.statusCode !is SuccessStatusCode) {throw IllegalStateException("Failed to load state of all files in revision $revisionHash during reset. $ls")}i.fraction += 0.0001val trackedFiles = ls.result!!trackedFiles.forEachWithProgress(i) { it, indic ->indic.text2 = DraconBundle.message("index.item.description.text", it.toString())if (Files.isRegularFile(it)) {pathToRevisionState[it] = Files.readAllBytes(it)}}return pathToRevisionState}
fun loadStateInRevisionForAllFilesForFile(revisionHash: String,project: Project,root: Path,file: Path): ByteArray {val sha1 = DigestUtils.sha1Hex(revisionHash)val tempDir = FileUtilRt.createTempDirectory("dracon_diffs-all-", sha1)val tmpTarget = tempDir.toPath()if (Files.exists(tmpTarget.resolve(".pijul"))) {val relativeToRoot = file.relativeTo(root)val relativeToTmpTarget = tmpTarget.resolve(relativeToRoot)if (Files.exists(relativeToTmpTarget)) {return Files.readAllBytes(relativeToTmpTarget)}}copyFolder(root, tmpTarget, StandardCopyOption.COPY_ATTRIBUTES, StandardCopyOption.REPLACE_EXISTING)val revisions = pijul(project).latestRevisionNumber(project, tmpTarget).resultval reset = pijul(project).reset(project, tmpTarget)if (reset.statusCode !is SuccessStatusCode) {throw IllegalStateException("Failed to load state of all files in revision $revisionHash during reset. $revisions")}if (revisions == null || revisions.hash != revisionHash) {val rollbackOp = pijul(project).rollbackTo(revisionHash, project, tmpTarget)if (rollbackOp.statusCode !is SuccessStatusCode) {throw IllegalStateException("Failed to load state of all files in revision $revisionHash during unrecord. $rollbackOp")}}try {val relativeToRoot = file.relativeTo(root)val relativeToTmpTarget = tmpTarget.resolve(relativeToRoot)return if (Files.exists(relativeToTmpTarget)) {Files.readAllBytes(relativeToTmpTarget)} else {ByteArray(0)}} finally {//FileUtilRt.delete(tempDir)}}@OptIn(ExperimentalPathApi::class)
throw IllegalStateException("Failed to load state of all files in revisions '$allRevisions' during reset. $reset")
IllegalStateException("Failed to load state of all files in revisions '$allRevisions' during reset. $reset").printStackTrace()return revisionToPathToState
FileUtilRt.delete(tempDir)
//FileUtilRt.delete(tempDir)}}@OptIn(ExperimentalPathApi::class)fun loadFileStateInRevision(revision: String,project: Project,root: Path,cachePath: Path,file: Path,i: ProgressIndicator,cacheAllRevisions: Boolean = true): FileStateInCache {val dir = resolveDirForRevision(cachePath, revision, createIfNotExists = false)val fileRelativeToRoot = file.relativeTo(root)if (!Files.exists(dir)) {val allRevisions = pijul(project).allRevisions(project, root).result!!.map { it.hash }val revisions = if (allRevisions[0] == revision) {listOf(revision)} else {allRevisions.subList(0, allRevisions.indexOf(revision) + 1)}val cacheMap = createCacheForRevisionFromTo(revisions,project,root,cachePath,i,cacheAllRevisions)if (!cacheMap.containsKey(revision)) {throw IllegalStateException("Failed to load state of all files in revision $revision")}}val fileInCache = dir.resolve(fileRelativeToRoot)return if (Files.exists(fileInCache) && Files.isRegularFile(fileInCache)) {FileStateInCache(file, fileInCache, false, Files.readAllBytes(fileInCache))} else {FileStateInCache(file, fileInCache, true, ByteArray(0))}}data class FileStateInCache(val originalPath: Path,val pathInCache: Path,val deleted: Boolean,val content: ByteArray) {override fun equals(other: Any?): Boolean {if (this === other) return trueif (javaClass != other?.javaClass) return falseother as FileStateInCacheif (originalPath != other.originalPath) return falseif (pathInCache != other.pathInCache) return falseif (deleted != other.deleted) return falseif (!content.contentEquals(other.content)) return falsereturn true}override fun hashCode(): Int {var result = originalPath.hashCode()result = 31 * result + pathInCache.hashCode()result = 31 * result + deleted.hashCode()result = 31 * result + content.contentHashCode()return result}}fun resolveDirForRevision(cachePath: Path, revision: String, createIfNotExists: Boolean = true): Path {val path = cachePath.resolve(revision)if (createIfNotExists)Files.createDirectories(path)return path}@OptIn(ExperimentalPathApi::class)fun createCacheForRevisionFromTo(allRevisions: List<String>,project: Project,root: Path,cachePath: Path,i: ProgressIndicator,cacheAllRevisions: Boolean = true): Map<String, Path> {if (allRevisions.isEmpty()) {throw IllegalArgumentException("Provided 'allRevisions' argument must not be empty.")}val revisionsToCache = allRevisions.toMutableList()i.text2 = DraconBundle.message("index.check.text")val revisionToPath = mutableMapOf<String, Path>()var lastFoundCachedRevisionPath: Path? = nullvar lastFoundCachedRevision: String? = nullfor (rev in allRevisions) {i.text2 = DraconBundle.message("index.check.rev.text", rev)val path = resolveDirForRevision(cachePath, rev, createIfNotExists = false)if (path.exists()) {revisionsToCache.remove(rev)lastFoundCachedRevisionPath = pathlastFoundCachedRevision = revrevisionToPath["rev"] = path}}i.text2 = DraconBundle.message("index.item.description.finish.text")if (revisionsToCache.isEmpty()) {return revisionToPath}if (!cacheAllRevisions) {val last = revisionsToCache.last()revisionsToCache.clear()revisionsToCache.add(last)}val temporaryWorkingDirectory = cachePath.resolve(".tmp-work-dir-" + UUID.randomUUID().toString())Files.createDirectories(temporaryWorkingDirectory)if (lastFoundCachedRevision != null && lastFoundCachedRevisionPath != null) {// Copies last found revision into temporaryWorkingDirectory// This prevents from rolling back from revisions that are already cached.copyFolder(lastFoundCachedRevisionPath, temporaryWorkingDirectory)} else {// Copy current .pijul working dir into temporaryWorkingDirectorycopyFolder(root, temporaryWorkingDirectory)}val revisions = pijul(project).allRevisions(project, temporaryWorkingDirectory)if (revisions.statusCode !is SuccessStatusCode) {throw IllegalStateException("Failed to load state of all files in revisions '$revisionsToCache' during all revisions hash retrieval. $revisions")}val pijulRevisions = revisions.result!!.map { it.hash }val indexOfFirstRevision = pijulRevisions.indexOf(revisionsToCache[0])if (indexOfFirstRevision == -1) {throw IllegalArgumentException("Could not find revision ${revisionsToCache[0]} in Pijul repository!")} else {if (indexOfFirstRevision + revisionsToCache.size > pijulRevisions.size) {throw IllegalArgumentException("There are more revisions to unrecord than the amount of recorded changes in Pijul Repository.")} else {val revisionSubList = pijulRevisions.subList(indexOfFirstRevision, indexOfFirstRevision + revisionsToCache.size)if (revisionsToCache != revisionSubList) {throw IllegalArgumentException("Revisions to load must sequentially match a sub sequence of revisions in Pijul repository. " +"Changes found in pijul: $revisionSubList. Changes to unrecord: $revisionsToCache")}}}i.text2 = DraconBundle.message("index.reset.text")val reset = pijul(project).reset(project, temporaryWorkingDirectory)if (reset.statusCode !is SuccessStatusCode) {IllegalStateException("Failed to load state of all files in revisions '$revisionsToCache' during reset. $reset").printStackTrace()return revisionToPath}i.fraction += 0.0001revisionsToCache.withIndex().toList().forEachWithProgress(i) { (index, rev), indicator ->indicator.text2 = DraconBundle.message("index.revision.description.text", rev)val resolvedPathForRevision = resolveDirForRevision(cachePath, rev, createIfNotExists = false)if (Files.exists(resolvedPathForRevision)) {deleteFilesInsideDirectory(temporaryWorkingDirectory)copyFolder(resolvedPathForRevision, temporaryWorkingDirectory)} else {val rollback = pijul(project).rollbackTo(rev, project, temporaryWorkingDirectory)if (rollback.statusCode !is SuccessStatusCode) {throw IllegalStateException("Failed to load state of all files in revision '$rev' during rollback. $rollback")}/*if (index == 0) {} else {val unrecord = pijul(project).unrecord(project, temporaryWorkingDirectory, revisionsToCache[index - 1])if (unrecord.statusCode !is SuccessStatusCode) {throw IllegalStateException("Failed to load state of all files in revision '$rev' during unrecord. $unrecord")}}*/indicator.text2 = DraconBundle.message("index.copy.text")copyFolder(temporaryWorkingDirectory, resolvedPathForRevision)}revisionToPath[rev] = resolvedPathForRevision}i.text2 = DraconBundle.message("index.item.description.finish.text")try {return revisionToPath} finally {FileUtilRt.delete(temporaryWorkingDirectory.toFile())
Files.copy(file, target.resolve(source.relativize(file)), *options)
Files.copy(file, target.resolve(source.relativize(file)), *copyOptions)return FileVisitResult.CONTINUE}})}fun deleteFilesInsideDirectory(path: Path) {Files.walkFileTree(path, object : SimpleFileVisitor<Path>() {override fun preVisitDirectory(dir: Path, attrs: BasicFileAttributes): FileVisitResult {return if (dir != path) FileVisitResult.CONTINUEelse FileVisitResult.SKIP_SUBTREE}override fun visitFile(file: Path, attrs: BasicFileAttributes): FileVisitResult {Files.delete(file)
package com.github.jonathanxd.dracon.logimport com.intellij.vcs.log.Hashclass PijulHash(val hash: String) : Hash {override fun asString(): String = this.hashoverride fun toShortString(): String = this.hash.substring(0, 10)}
package com.github.jonathanxd.dracon.logimport com.intellij.vcs.log.Hashclass PijulHash(val hash: String) : Hash {override fun asString(): String = this.hashoverride fun toShortString(): String = this.hash.substring(0, 10)}
package com.github.jonathanxd.dracon.handlerimport com.github.jonathanxd.dracon.cache.FileRevisionCacheimport com.intellij.openapi.components.serviceIfCreatedimport com.intellij.openapi.project.Projectimport com.intellij.openapi.project.ProjectCloseHandlerclass DraconCloseHandler: ProjectCloseHandler {override fun canClose(project: Project): Boolean {val fileRevisionCache = project.serviceIfCreated<FileRevisionCache>()fileRevisionCache?.invalidate()return true}}
import com.intellij.openapi.progress.EmptyProgressIndicatorimport com.intellij.openapi.progress.ProgressIndicatorimport com.intellij.openapi.progress.forEachWithProgressimport com.intellij.openapi.progress.withPushPop
import com.intellij.openapi.progress.*
class FileRevisionCache(val project: Project) : CacheService<FileRevisionRef, ByteArray> {override val cache = DataCache<FileRevisionRef, ByteArray>(this.project, "file_revision")
class FileRevisionCache(val project: Project) {//override val cache = DataCache<String, Map<String, ByteArray>>(this.project, "path_revision")fun cachePath(): Path =this.project.getProjectDataPath("com.github.jonathanxd.dracon").resolve("revision-cache")
return this.cache.queryOrLoadAsyncExpanded(fileRev) {val revisions = loadStateInEveryRevisionForAllFiles(listOf(rev.hash),project,root,EmptyProgressIndicator())
Files.createDirectories(cache)val completableFuture = CompletableFuture<ByteArray>()
val revisionsForHash = revisions[rev.hash]!!val stringKeys = revisionsForHash.mapKeys { (k, _) -> k.filePathAsString() }stringKeys[it.filePath]!! to stringKeys.map { (k, v) -> FileRevisionRef(k, rev.hash) to v }
ProgressManager.getInstance().run(object : Task.Backgroundable(project,DraconBundle.message("index.load.rev.for.text", rev.hash.substring(0, 10), file.fileName.toString()),true) {override fun run(indicator: ProgressIndicator) {indicator.isIndeterminate = falsetry {val revision = loadFileStateInRevision(rev.hash,project,root,cache,file,indicator,project.service<PijulSettings>().isToCacheAllRevisions())completableFuture.complete(revision.content)} catch (t: Throwable) {t.printStackTrace()completableFuture.completeExceptionally(t)}}})return completableFuture.handle { t, u ->u?.printStackTrace()t ?: ByteArray(0)
stateMap.entries.forEachWithProgress(indic) { (path, bytes), indicator2 ->indicator2.text2 =DraconBundle.message("index.revision.file.description.text", path.toString(), rev)val revRef = FileRevisionRef(path.filePathAsString(), rev)this.cache.updateCache(revRef) {bytes}
this.cache.updateCache(rev) {stateMap.mapKeys { (k, _) -> k.filePathAsString() }