commit - 8f270315ac1a03425e7daccc1db3b14cd7080df8
commit + 701fffebad34d0f36f5fd2165569f42d177ffef9
blob - /dev/null
blob + 5d5d3b53a52c1f7cb2b933f3284eaa56abb6524a (mode 644)
--- /dev/null
+++ src/main/kotlin/dev/nezzontli/gotvcs/GotChangeProvider.kt
+package dev.nezzontli.gotvcs
+
+import com.intellij.openapi.progress.ProgressIndicator
+import com.intellij.openapi.vcs.FileStatus
+import com.intellij.openapi.vcs.changes.Change
+import com.intellij.openapi.vcs.changes.ChangeListManagerGate
+import com.intellij.openapi.vcs.changes.ChangeProvider
+import com.intellij.openapi.vcs.changes.ChangelistBuilder
+import com.intellij.openapi.vcs.changes.CurrentContentRevision
+import com.intellij.openapi.vcs.changes.LocallyDeletedChange
+import com.intellij.openapi.vcs.changes.VcsDirtyScope
+import com.intellij.openapi.vfs.LocalFileSystem
+import com.intellij.openapi.vfs.VirtualFile
+import com.intellij.vcsUtil.VcsUtil
+import java.io.File
+
+class GotChangeProvider(private val commandLine: GotCommandLineWrapper) : ChangeProvider {
+
+ override fun getChanges(
+ dirtyScope: VcsDirtyScope,
+ builder: ChangelistBuilder,
+ progress: ProgressIndicator,
+ addGate: ChangeListManagerGate,
+ ) {
+ for (root in dirtyScope.affectedContentRoots) {
+ val workDir = File(root.path)
+ val entries = commandLine.status(workDir)
+
+ for (entry in entries) {
+ val absoluteFile = File(workDir, entry.path)
+ val filePath = VcsUtil.getFilePath(absoluteFile, false)
+
+ when (entry.code) {
+ '?' -> {
+ val virtualFile = LocalFileSystem.getInstance().findFileByIoFile(absoluteFile)
+ if (virtualFile != null) builder.processUnversionedFile(virtualFile)
+ }
+
+ '!' -> builder.processLocallyDeletedFile(LocallyDeletedChange(filePath, filePath.path))
+
+ 'M', 'm', 'C' -> {
+ val status = if (entry.code == 'C') FileStatus.MERGED_WITH_CONFLICTS else FileStatus.MODIFIED
+ val before = GotContentRevision(filePath, workDir, entry.path, commandLine)
+ val after = CurrentContentRevision(filePath)
+ builder.processChange(Change(before, after, status), GotVcs.getKey())
+ }
+
+ 'A' -> {
+ val after = CurrentContentRevision(filePath)
+ builder.processChange(Change(null, after, FileStatus.ADDED), GotVcs.getKey())
+ }
+
+ 'D' -> {
+ val before = GotContentRevision(filePath, workDir, entry.path, commandLine)
+ builder.processChange(Change(before, null, FileStatus.DELETED), GotVcs.getKey())
+ }
+
+ else -> Unit
+ }
+ }
+ }
+ }
+
+ override fun isModifiedDocumentTrackingRequired(): Boolean = false
+
+ override fun doCleanup(files: MutableList<out VirtualFile>) = Unit
+}
blob - /dev/null
blob + ac1cc93524bbae9807b2bb24fc2210a6b8af6352 (mode 644)
--- /dev/null
+++ src/main/kotlin/dev/nezzontli/gotvcs/GotCommandLineWrapper.kt
+package dev.nezzontli.gotvcs
+
+import com.intellij.execution.ExecutionException
+import com.intellij.execution.configurations.GeneralCommandLine
+import com.intellij.execution.util.ExecUtil
+import com.intellij.openapi.vcs.VcsException
+import java.io.File
+import java.nio.charset.StandardCharsets
+
+data class GotStatusEntry(val code: Char, val stagedCode: Char, val path: String)
+
+/**
+ * Centraliza todas las invocaciones al binario `got`. La ruta de abajo es la
+ * del store de Nix resuelta al momento de escribir este código
+ * (readlink -f /etc/profiles/per-user/ale/bin/idea muestra el store path del
+ * IDE; el de got se resolvió igual desde /run/current-system/sw/bin/got).
+ * Cambia con cada rebuild del sistema -> deuda para GotConfigurable (Fase 6).
+ */
+class GotCommandLineWrapper {
+
+ private fun binaryPath(): String {
+ val nixPath = File("/run/current-system/sw/bin/got")
+ return if (nixPath.canExecute()) nixPath.path else "got"
+ }
+
+ private fun run(workDir: File, vararg args: String): String {
+ val commandLine = GeneralCommandLine(binaryPath(), *args)
+ .withWorkDirectory(workDir)
+ .withCharset(StandardCharsets.UTF_8)
+ val output = try {
+ ExecUtil.execAndGetOutput(commandLine)
+ } catch (e: ExecutionException) {
+ throw VcsException("No se pudo ejecutar got ${args.joinToString(" ")}: ${e.message}", e)
+ }
+ if (output.exitCode != 0) {
+ throw VcsException("got ${args.joinToString(" ")} salió con código ${output.exitCode}: ${output.stderr.trim()}")
+ }
+ return output.stdout
+ }
+
+ @Throws(VcsException::class)
+ fun status(workDir: File): List<GotStatusEntry> {
+ val output = run(workDir, "status")
+ return output.lineSequence()
+ .filter { it.isNotBlank() }
+ .map { line ->
+ val code = line[0]
+ val stagedCode = line.getOrElse(1) { ' ' }
+ val path = line.substring(minOf(3, line.length))
+ GotStatusEntry(code, stagedCode, path)
+ }
+ .toList()
+ }
+
+ @Throws(VcsException::class)
+ fun catAtBase(workDir: File, relativePath: String): String =
+ run(workDir, "cat", "-c", ":base", "-P", relativePath)
+}
blob - /dev/null
blob + 71fc5d1ce6d080d0810c34ed9caf00cac683e449 (mode 644)
--- /dev/null
+++ src/main/kotlin/dev/nezzontli/gotvcs/GotContentRevision.kt
+package dev.nezzontli.gotvcs
+
+import com.intellij.openapi.vcs.FilePath
+import com.intellij.openapi.vcs.VcsException
+import com.intellij.openapi.vcs.changes.ContentRevision
+import com.intellij.openapi.vcs.history.VcsRevisionNumber
+import java.io.File
+
+/** Contenido de un archivo en el commit base del work tree, vía `got cat -c :base`. */
+class GotContentRevision(
+ private val filePath: FilePath,
+ private val workDir: File,
+ private val relativePath: String,
+ private val commandLine: GotCommandLineWrapper,
+) : ContentRevision {
+
+ @Throws(VcsException::class)
+ override fun getContent(): String = commandLine.catAtBase(workDir, relativePath)
+
+ override fun getFile(): FilePath = filePath
+
+ override fun getRevisionNumber(): VcsRevisionNumber = VcsRevisionNumber.NULL
+}