diff --git a/src/main/kotlin/me/msoucy/gbat/Main.kt b/src/main/kotlin/me/msoucy/gbat/Main.kt index d643036..761c7be 100644 --- a/src/main/kotlin/me/msoucy/gbat/Main.kt +++ b/src/main/kotlin/me/msoucy/gbat/Main.kt @@ -1,9 +1,7 @@ package me.msoucy.gbat import java.io.File -import java.io.IOException import java.util.concurrent.Executors -import java.util.concurrent.TimeUnit import kotlin.math.pow import kotlin.system.exitProcess import kotlin.text.Regex @@ -77,39 +75,6 @@ class GbatArgs(parser: ArgParser) { val project_root by parser.positional("The root directory to inspect") } -fun List.runCommand(workingDir: File): Pair { - try { - val proc = ProcessBuilder(*this.toTypedArray()) - .directory(workingDir) - .redirectOutput(ProcessBuilder.Redirect.PIPE) - .redirectError(ProcessBuilder.Redirect.PIPE) - .start() - - proc.waitFor(60, TimeUnit.MINUTES) - return Pair(proc.inputStream.bufferedReader().readText(), - proc.errorStream.bufferedReader().readText()) - } catch(e: IOException) { - e.printStackTrace() - return Pair(null, null) - } -} - -class GitRepo(val project_root : File, val git_exe : String) { - fun ls() : String { - val cmd = listOf( - git_exe, - "ls-tree", - "--full-tree", - "--name-only", - "-r", - "HEAD", - project_root.absolutePath - ) - val (out, err) = cmd.runCommand(project_root) - return out ?: "" - } -} - fun main(args: Array) = mainBody { ArgParser(args).parseInto(::GbatArgs).run { val outDir = File(output) diff --git a/src/main/kotlin/me/msoucy/gbat/Models.kt b/src/main/kotlin/me/msoucy/gbat/Models.kt index f11ebe2..03785e1 100644 --- a/src/main/kotlin/me/msoucy/gbat/Models.kt +++ b/src/main/kotlin/me/msoucy/gbat/Models.kt @@ -5,16 +5,6 @@ import kotlin.io.forEachLine import org.jetbrains.exposed.sql.* import org.jetbrains.exposed.sql.transactions.transaction -fun Iterable.copyOf(): List { - val original = this - return mutableListOf().apply { addAll(original) } -} - -fun Iterable.mutableCopyOf(): MutableList { - val original = this - return mutableListOf().apply { addAll(original) } -} - enum class ChangeType { Add, Change, Remove } diff --git a/src/main/kotlin/me/msoucy/gbat/Repo.kt b/src/main/kotlin/me/msoucy/gbat/Repo.kt new file mode 100644 index 0000000..24c1a97 --- /dev/null +++ b/src/main/kotlin/me/msoucy/gbat/Repo.kt @@ -0,0 +1,81 @@ +package me.msoucy.gbat + +import java.io.File +import java.io.IOException + +typealias Diff = String + +class GitRepo(val projectRoot : File, val git_exe : String) { + fun ls() : String { + val cmd = listOf( + git_exe, + "ls-tree", + "--full-tree", + "--name-only", + "-r", + "HEAD", + projectRoot.absolutePath + ) + val (out, _) = cmd.runCommand(projectRoot) + return out ?: "" + } + + fun root() : String? { + val cmd = listOf( + git_exe, + "rev-parse", + "--show-toplevel" + ) + val (out, _) = cmd.runCommand(projectRoot) + return out + } + + fun log(fname : File) : List> { + val cmd = listOf( + git_exe, + "log", + "-z", // Null byte separate log entries + "-w", // Ignore all whitespace + "--follow", // Follow history through renames + "--patience", // Use the patience diff algorithm + "-p", // Show patches + fname.absolutePath + ) + val (out, err) = cmd.runCommand(projectRoot) + if(err != "") { + System.err.println("Error from git log: " + err) + throw IOException(err) + } + val logEntries = (out?: "").split("\u0000").filter {it.trim().isNotEmpty()} + return logEntries.map { + val (header, diffLines) = splitEntryHeader(it) + val diff = diffLines.joinToString("\n") + val author = parseAuthor(header) + author to diff + }.filter { + it.first != "" && it.second != "" + }.reversed() + } + + private fun parseAuthor(header : List) : String { + val segs = header.getOrNull(1)?.trim()?.split("\\s+")?: listOf() + return segs.subList(1, segs.size - 2).joinToString(" ") + } + + private fun splitEntryHeader(entry : String) : Pair, List> { + val lines = entry.split("\n") + if(lines.size < 2) { + return Pair(listOf(), listOf()) + } else if(!lines.get(0).startsWith("commit")) { + return Pair(listOf(), listOf()) + } else if(!lines.get(1).startsWith("Author")) { + return Pair(listOf(), listOf()) + } + var ind = 2 + while(ind < lines.size && !lines.get(ind).startsWith("diff")) { + ind++ + } + return Pair(lines.subList(0, ind).copyOf(), + lines.subList(ind, lines.size).copyOf()) + } +} \ No newline at end of file diff --git a/src/main/kotlin/me/msoucy/gbat/Util.kt b/src/main/kotlin/me/msoucy/gbat/Util.kt new file mode 100644 index 0000000..8d33acb --- /dev/null +++ b/src/main/kotlin/me/msoucy/gbat/Util.kt @@ -0,0 +1,25 @@ +package me.msoucy.gbat + +import java.io.File +import java.io.IOException +import java.util.concurrent.TimeUnit + +fun Iterable.copyOf() = mutableListOf().also { it.addAll(this) } +fun Iterable.mutableCopyOf() = mutableListOf().also { it.addAll(this) } + +fun List.runCommand(workingDir: File): Pair { + try { + val proc = ProcessBuilder(*this.toTypedArray()) + .directory(workingDir) + .redirectOutput(ProcessBuilder.Redirect.PIPE) + .redirectError(ProcessBuilder.Redirect.PIPE) + .start() + + proc.waitFor(60, TimeUnit.MINUTES) + return Pair(proc.inputStream.bufferedReader().readText(), + proc.errorStream.bufferedReader().readText()) + } catch(e: IOException) { + e.printStackTrace() + return Pair(null, null) + } +} \ No newline at end of file