First ChangeProvider implementation!!! Wheehooo

[?]
Mar 29, 2021, 11:27 AM
6CR2EFUN7JXFHCBTNX3WWOOP4WFOCFO6KSPEBN6V6J5HFZO2LHNQC

Dependencies

  • [2] QXUEMZ3B Initial CahngeProvider
  • [3] FNNW5IEA Added more plugin files to Pijul
  • [4] NTRPUMVQ Improved README and added roadmap.
  • [5] OPFG6CZ2 File status tracking supported.

Change contents

  • edit in src/main/kotlin/com/github/jonathanxd/dracon/vfs/PijulVirtualFileStatusProvider.kt at line 22
    [3.534]
    [3.109]
    if (virtualFile.name == ".idea" || virtualFile.name == "dracon_diffs")
    return FileStatus.IGNORED
  • edit in src/main/kotlin/com/github/jonathanxd/dracon/provider/PijulChangeProvider.kt at line 3
    [2.928]
    [2.928]
    import com.github.jonathanxd.dracon.content.PijulContentRevision
    import com.github.jonathanxd.dracon.log.*
    import com.github.jonathanxd.dracon.pijul.pijul
    import com.github.jonathanxd.dracon.revision.PijulRevisionNumber
  • edit in src/main/kotlin/com/github/jonathanxd/dracon/provider/PijulChangeProvider.kt at line 9
    [2.1027]
    [2.1027]
    import com.intellij.openapi.vcs.FileStatus
    import com.intellij.openapi.vcs.LocalFilePath
    import com.intellij.openapi.vcs.ProjectLevelVcsManager
  • edit in src/main/kotlin/com/github/jonathanxd/dracon/provider/PijulChangeProvider.kt at line 14
    [2.1108]
    [2.1108]
    import java.nio.file.Files
    import java.nio.file.Path
    import java.nio.file.Paths
  • replacement in src/main/kotlin/com/github/jonathanxd/dracon/provider/PijulChangeProvider.kt at line 26
    [2.1416][2.1416:1478]()
    val dirtDirs = dirtyScope.recursivelyDirtyDirectories
    [2.1416]
    [2.1478]
    val project = dirtyScope.project
    val vcsManager = ProjectLevelVcsManager.getInstance(project)
    val revisionMap = mutableMapOf<Path, PijulRevisionNumber?>()
    val changesMap = mutableMapOf<Path, PijulLogEntry?>()
    for (dir in dirtyScope.recursivelyDirtyDirectories + dirtyScope.dirtyFilesNoExpand) {
    val root = vcsManager.getVcsRootFor(dir)
    val rootPath = Paths.get(root!!.path)
    val head = revisionMap.computeIfAbsent(rootPath) {
    pijul(this.project).latestRevisionNumber(this.project, root).result
    } ?: continue
    val change = changesMap.computeIfAbsent(rootPath) {
    pijul(this.project).diff(this.project, root).result
    } ?: continue
    for (hunk in change.hunks) {
    when (hunk) {
    is FileAddHunk -> {
    val path = Paths.get(dir.path, hunk.path)
    val filePath = LocalFilePath(path, Files.isDirectory(path))
  • replacement in src/main/kotlin/com/github/jonathanxd/dracon/provider/PijulChangeProvider.kt at line 48
    [2.1479][2.1479:1505]()
    println(dirtDirs)
    [2.1479]
    [2.1505]
    builder.processChange(
    Change(
    PijulContentRevision(
    rootPath,
    filePath,
    head,
    this.project
    ), CurrentContentRevision.create(filePath),
    FileStatus.ADDED
    ), this.key)
    }
    is FileDelHunk -> {
    val path = Paths.get(dir.path, hunk.path)
    val filePath = LocalFilePath(path, Files.isDirectory(path))
    builder.processChange(
    Change(
    PijulContentRevision(
    rootPath,
    filePath,
    head,
    this.project
    ), CurrentContentRevision.create(filePath),
    FileStatus.DELETED
    ), this.key)
    }
    is ReplacementHunk -> {
    val path = Paths.get(dir.path, hunk.path)
    val filePath = LocalFilePath(path, Files.isDirectory(path))
    builder.processChange(
    Change(
    PijulContentRevision(
    rootPath,
    filePath,
    head,
    this.project
    ), CurrentContentRevision.create(filePath),
    FileStatus.MODIFIED
    ), this.key)
    }
    is EditHunk -> {
    val path = Paths.get(dir.path, hunk.path)
    val filePath = LocalFilePath(path, Files.isDirectory(path))
    builder.processChange(
    Change(
    PijulContentRevision(
    rootPath,
    filePath,
    head,
    this.project
    ), CurrentContentRevision.create(filePath),
    FileStatus.MODIFIED
    ), this.key)
    }
    else -> Unit
    }
    }
    }
  • replacement in src/main/kotlin/com/github/jonathanxd/dracon/pijul/diff/PijulDiffJson.kt at line 27
    [3.929][3.929:1052]()
    GSON.fromJson<Map<String, List<ChangeData>>>(json, typeOf<Map<String, List<ChangeData>>>().javaType).entries.map {
    [3.929]
    [3.1052]
    if (json.isEmpty()) emptyList()
    else GSON.fromJson<Map<String, List<ChangeData>>>(json, typeOf<Map<String, List<ChangeData>>>().javaType).entries.map {
  • edit in src/main/kotlin/com/github/jonathanxd/dracon/pijul/Pijul.kt at line 14
    [2.1633]
    [2.1633]
    import com.github.jonathanxd.dracon.log.PijulLogEntry
  • edit in src/main/kotlin/com/github/jonathanxd/dracon/pijul/Pijul.kt at line 85
    [2.1838]
    [2.1838]
    @RequiresBackgroundThread
    fun rollbackTo(hash: String, project: Project, root: Path): PijulOperationResult<Boolean>
    @RequiresBackgroundThread
    fun reset(project: Project, root: Path): PijulOperationResult<Boolean>
  • edit in src/main/kotlin/com/github/jonathanxd/dracon/pijul/Pijul.kt at line 92
    [2.1839]
    [2.1839]
    /**
    * Retrieves change history
    */
  • edit in src/main/kotlin/com/github/jonathanxd/dracon/pijul/Pijul.kt at line 97
    [2.1950]
    [3.6839]
    /**
    * Retrieves difference from current revision and local files.
    */
    @RequiresBackgroundThread
    fun diff(project: Project, root: VirtualFile): PijulOperationResult<PijulLogEntry>
  • file addition: content (d--r------)
    [3.107]
  • file addition: PijulContentRevision.kt (----------)
    [0.5008]
    package com.github.jonathanxd.dracon.content
    import com.github.jonathanxd.dracon.pijul.pijul
    import com.github.jonathanxd.dracon.revision.PijulRevisionNumber
    import com.intellij.openapi.diagnostic.logger
    import com.intellij.openapi.project.Project
    import com.intellij.openapi.vcs.FilePath
    import com.intellij.openapi.vcs.changes.ContentRevision
    import com.intellij.openapi.vcs.history.VcsRevisionNumber
    import com.intellij.vcsUtil.VcsUtil
    import java.io.File
    import java.io.IOException
    import java.nio.file.*
    import java.nio.file.attribute.BasicFileAttributes
    import kotlin.io.path.ExperimentalPathApi
    import kotlin.io.path.relativeTo
    import java.util.Comparator
    class PijulContentRevision(
    val root: Path,
    val filePath: FilePath,
    val revision: PijulRevisionNumber,
    val project: Project
    ): ContentRevision {
    override fun getContent(): String {
    return loadStateInRevision()
    }
    override fun getFile(): FilePath =
    this.filePath
    override fun getRevisionNumber(): VcsRevisionNumber =
    this.revision
    @OptIn(ExperimentalPathApi::class)
    private fun loadStateInRevision(): String {
    val tmpTarget = Paths.get(this.project.baseDir.path, ".idea", "dracon_diffs", this.revision.hash)
    if (Files.exists(tmpTarget)) {
    Files.walk(tmpTarget).use { walk ->
    walk.sorted(Comparator.reverseOrder())
    .map(Path::toFile)
    .forEach(File::delete)
    }
    }
    Files.createDirectories(tmpTarget)
    copyFolder(this.root, tmpTarget, StandardCopyOption.COPY_ATTRIBUTES, StandardCopyOption.REPLACE_EXISTING)
    val rollbackOp = pijul(project).reset(this.project, tmpTarget)
    val relative = Paths.get(filePath.path).relativeTo(this.root).toString()
    return Files.readString(tmpTarget.resolve(relative))
    }
    @Throws(IOException::class)
    fun copyFolder(source: Path, target: Path, vararg options: CopyOption) {
    Files.walkFileTree(source, object : SimpleFileVisitor<Path>() {
    @Throws(IOException::class)
    override fun preVisitDirectory(dir: Path, attrs: BasicFileAttributes): FileVisitResult {
    if (dir.fileName.toString().equals(".idea", ignoreCase = true))
    return FileVisitResult.SKIP_SUBTREE
    Files.createDirectories(target.resolve(source.relativize(dir)))
    return FileVisitResult.CONTINUE
    }
    @Throws(IOException::class)
    override fun visitFile(file: Path, attrs: BasicFileAttributes): FileVisitResult {
    Files.copy(file, target.resolve(source.relativize(file)), *options)
    return FileVisitResult.CONTINUE
    }
    })
    }
    }
  • edit in src/main/kotlin/com/github/jonathanxd/dracon/cmd/PijulCmd.kt at line 25
    [3.11347]
    [3.11394]
    import com.intellij.openapi.diagnostic.logger
  • replacement in src/main/kotlin/com/github/jonathanxd/dracon/cmd/PijulCmd.kt at line 95
    [3.13604][3.3296:3474]()
    return this.doExecutionWithMapper("file_status", execution) {
    val changes = PijulDiffJson.parseJson(it)
    val changeMap = changes.toFileStatusMap()
    [3.13604]
    [3.3474]
    val fileStatusBasedInPijulDiff = this.doExecutionWithMapper("file_status", execution) {
    try {
    val changes = PijulDiffJson.parseJson(it)
    val changeMap = changes.toFileStatusMap()
    val fPath = Paths.get(VcsUtil.getFilePath(file.path).path).relativeTo(rootPath).toString()
    if (fPath.isEmpty()) {
    FileStatus.SUPPRESSED
    } else {
    changeMap[fPath]?.firstOrNull()
    }
    } catch(t: Throwable) {
    logger<PijulCmd>().error(t)
    null
    }
    }
    val fileStatusBasedInPijulLs = this.doExecutionWithMapper("file_status_from_ls", this.execPijul(project, rootPath, listOf("ls"), delay = 10L)) {
    val trackedFiles = it.split("\n")
  • replacement in src/main/kotlin/com/github/jonathanxd/dracon/cmd/PijulCmd.kt at line 116
    [3.3578][3.3578:3651]()
    if (fPath.isEmpty()) {
    FileStatus.SUPPRESSED
    [3.3578]
    [3.3651]
    if (trackedFiles.contains(fPath)) {
    FileStatus.NOT_CHANGED
  • replacement in src/main/kotlin/com/github/jonathanxd/dracon/cmd/PijulCmd.kt at line 119
    [3.3672][3.3672:3720]()
    changeMap[fPath]?.firstOrNull()
    [3.3672]
    [3.3720]
    null
    }
    }
    return if (fileStatusBasedInPijulDiff.statusCode !is SuccessStatusCode
    || fileStatusBasedInPijulDiff.result == null
    || fileStatusBasedInPijulDiff.result == FileStatus.SUPPRESSED) {
    fileStatusBasedInPijulLs
    } else {
    fileStatusBasedInPijulDiff
    }
    }
    override fun rollbackTo(hash: String, project: Project, root: Path): PijulOperationResult<Boolean> {
    val logHashExecution = this.execPijul(project, root, listOf("log", "--hash-only"), delay = 10L)
    val hashes = this.doExecutionWithMapper("log--hash-only", logHashExecution) {
    it.lines()
    }
    if (hashes.statusCode !is SuccessStatusCode) {
    return hashes as PijulOperationResult<Boolean>
    } else {
    val hashList = hashes.result!!
    if (hashList.none { it == hash } || hashList.isEmpty()) {
    return PijulOperationResult("rollbackTo_${hash}", NonZeroExitStatusCode(-1, "Could not find hash $hash in Pijul log."), false)
    } else {
    if (hashList[0] == hash) {
    return PijulOperationResult("rollbackTo_${hash}", SuccessStatusCode, true)
    } else {
    val rollbacks = hashList.subList(0, hashList.indexOf(hash))
    for (rollbackHash in rollbacks) {
    val rollback = this.doExecution(
    "rollback_$rollbackHash",
    this.execPijul(project, root, listOf("unrecord", rollbackHash), delay = 10L)
    )
    if (rollback.statusCode !is SuccessStatusCode) {
    return rollback as PijulOperationResult<Boolean>
    }
    }
    return PijulOperationResult("rollbackTo_${hash}", SuccessStatusCode, true)
    }
  • edit in src/main/kotlin/com/github/jonathanxd/dracon/cmd/PijulCmd.kt at line 164
    [3.3734]
    [3.3734]
    }
    }
    override fun reset(project: Project, root: Path): PijulOperationResult<Boolean> {
    val resetExecution = this.execPijul(project, root, listOf("reset"), delay = 10L)
    return this.doExecutionWithMapper("reset", resetExecution) {
    true
  • edit in src/main/kotlin/com/github/jonathanxd/dracon/cmd/PijulCmd.kt at line 189
    [2.4844]
    [2.4844]
    if (hash.isEmpty()) {
    break
    }
  • edit in src/main/kotlin/com/github/jonathanxd/dracon/cmd/PijulCmd.kt at line 198
    [2.5181]
    [2.5181]
    } else if (change.result != null) {
    entries += change.result
  • edit in src/main/kotlin/com/github/jonathanxd/dracon/cmd/PijulCmd.kt at line 204
    [2.5310]
    [2.5310]
    }
    }
    override fun diff(project: Project, root: VirtualFile): PijulOperationResult<PijulLogEntry> {
    val rootPath = Paths.get(VcsUtil.getFilePath(root).path)
    val change = this.doExecutionWithMapper("diff", this.execPijul(project, rootPath, listOf("diff"), delay = 10L)) {
    if (it.isEmpty()) null
    else it.parseChange("")
  • edit in src/main/kotlin/com/github/jonathanxd/dracon/cmd/PijulCmd.kt at line 214
    [2.5320]
    [2.5320]
    return change