Extracted RawFile generation to its own class
This commit is contained in:
parent
bd719be963
commit
86fd61d0d7
16
src/main/kotlin/app/di/RawFileManagerFactory.kt
Normal file
16
src/main/kotlin/app/di/RawFileManagerFactory.kt
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
package app.di
|
||||||
|
|
||||||
|
import app.git.RawFileManager
|
||||||
|
import app.git.diff.HunkDiffGenerator
|
||||||
|
import dagger.assisted.AssistedFactory
|
||||||
|
import org.eclipse.jgit.lib.Repository
|
||||||
|
|
||||||
|
@AssistedFactory
|
||||||
|
interface RawFileManagerFactory {
|
||||||
|
fun create(repository: Repository): RawFileManager
|
||||||
|
}
|
||||||
|
|
||||||
|
@AssistedFactory
|
||||||
|
interface HunkDiffGeneratorFactory {
|
||||||
|
fun create(repository: Repository, rawFileManager: RawFileManager): HunkDiffGenerator
|
||||||
|
}
|
@ -1,11 +1,12 @@
|
|||||||
package app.git
|
package app.git
|
||||||
|
|
||||||
|
import app.di.HunkDiffGeneratorFactory
|
||||||
|
import app.di.RawFileManagerFactory
|
||||||
import app.extensions.fullData
|
import app.extensions.fullData
|
||||||
import app.git.diff.Hunk
|
import app.git.diff.Hunk
|
||||||
import app.git.diff.HunkDiffGenerator
|
import app.git.diff.HunkDiffGenerator
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import org.apache.commons.logging.LogFactory.objectId
|
|
||||||
import org.eclipse.jgit.api.Git
|
import org.eclipse.jgit.api.Git
|
||||||
import org.eclipse.jgit.diff.DiffEntry
|
import org.eclipse.jgit.diff.DiffEntry
|
||||||
import org.eclipse.jgit.diff.DiffFormatter
|
import org.eclipse.jgit.diff.DiffFormatter
|
||||||
@ -21,7 +22,10 @@ import java.io.ByteArrayOutputStream
|
|||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
|
||||||
class DiffManager @Inject constructor() {
|
class DiffManager @Inject constructor(
|
||||||
|
private val rawFileManagerFactory: RawFileManagerFactory,
|
||||||
|
private val hunkDiffGeneratorFactory: HunkDiffGeneratorFactory,
|
||||||
|
) {
|
||||||
suspend fun diffFormat(git: Git, diffEntryType: DiffEntryType): List<Hunk> = withContext(Dispatchers.IO) {
|
suspend fun diffFormat(git: Git, diffEntryType: DiffEntryType): List<Hunk> = withContext(Dispatchers.IO) {
|
||||||
val diffEntry = diffEntryType.diffEntry
|
val diffEntry = diffEntryType.diffEntry
|
||||||
val byteArrayOutputStream = ByteArrayOutputStream()
|
val byteArrayOutputStream = ByteArrayOutputStream()
|
||||||
@ -42,7 +46,9 @@ class DiffManager @Inject constructor() {
|
|||||||
formatter.flush()
|
formatter.flush()
|
||||||
}
|
}
|
||||||
|
|
||||||
val hunkDiffGenerator = HunkDiffGenerator(git.repository)
|
val rawFileManager = rawFileManagerFactory.create(repository)
|
||||||
|
val hunkDiffGenerator = hunkDiffGeneratorFactory.create(repository, rawFileManager)
|
||||||
|
|
||||||
val hunks = mutableListOf<Hunk>()
|
val hunks = mutableListOf<Hunk>()
|
||||||
|
|
||||||
hunkDiffGenerator.use {
|
hunkDiffGenerator.use {
|
||||||
|
55
src/main/kotlin/app/git/RawFileManager.kt
Normal file
55
src/main/kotlin/app/git/RawFileManager.kt
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
package app.git
|
||||||
|
|
||||||
|
import dagger.assisted.Assisted
|
||||||
|
import dagger.assisted.AssistedInject
|
||||||
|
import org.eclipse.jgit.diff.ContentSource
|
||||||
|
import org.eclipse.jgit.diff.DiffEntry
|
||||||
|
import org.eclipse.jgit.diff.RawText
|
||||||
|
import org.eclipse.jgit.lib.Constants
|
||||||
|
import org.eclipse.jgit.lib.FileMode
|
||||||
|
import org.eclipse.jgit.lib.ObjectReader
|
||||||
|
import org.eclipse.jgit.lib.Repository
|
||||||
|
import org.eclipse.jgit.storage.pack.PackConfig
|
||||||
|
import org.eclipse.jgit.treewalk.AbstractTreeIterator
|
||||||
|
import org.eclipse.jgit.treewalk.WorkingTreeIterator
|
||||||
|
import org.eclipse.jgit.util.LfsFactory
|
||||||
|
|
||||||
|
private const val DEFAULT_BINARY_FILE_THRESHOLD = PackConfig.DEFAULT_BIG_FILE_THRESHOLD
|
||||||
|
|
||||||
|
class RawFileManager @AssistedInject constructor(
|
||||||
|
@Assisted private val repository: Repository
|
||||||
|
) : AutoCloseable {
|
||||||
|
private var reader: ObjectReader = repository.newObjectReader()
|
||||||
|
private var source: ContentSource.Pair
|
||||||
|
|
||||||
|
init {
|
||||||
|
val cs = ContentSource.create(reader)
|
||||||
|
source = ContentSource.Pair(cs, cs)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun scan(oldTreeIterator: AbstractTreeIterator, newTreeIterator: AbstractTreeIterator) {
|
||||||
|
source = ContentSource.Pair(source(oldTreeIterator), source(newTreeIterator))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun source(iterator: AbstractTreeIterator): ContentSource {
|
||||||
|
return if (iterator is WorkingTreeIterator)
|
||||||
|
ContentSource.create(iterator)
|
||||||
|
else
|
||||||
|
ContentSource.create(reader)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getRawContent(side: DiffEntry.Side, entry: DiffEntry): RawText {
|
||||||
|
if (entry.getMode(side) === FileMode.MISSING) return RawText.EMPTY_TEXT
|
||||||
|
if (entry.getMode(side).objectType != Constants.OBJ_BLOB) return RawText.EMPTY_TEXT
|
||||||
|
|
||||||
|
val ldr = LfsFactory.getInstance().applySmudgeFilter(
|
||||||
|
repository,
|
||||||
|
source.open(side, entry), entry.diffAttribute
|
||||||
|
)
|
||||||
|
return RawText.load(ldr, DEFAULT_BINARY_FILE_THRESHOLD)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun close() {
|
||||||
|
reader.close()
|
||||||
|
}
|
||||||
|
}
|
@ -4,6 +4,6 @@ data class Hunk(val header: String, val lines: List<Line>)
|
|||||||
|
|
||||||
sealed class Line(val content: String) {
|
sealed class Line(val content: String) {
|
||||||
class ContextLine(content: String, val oldLineNumber: Int, val newLineNumber: Int): Line(content)
|
class ContextLine(content: String, val oldLineNumber: Int, val newLineNumber: Int): Line(content)
|
||||||
class AddedLine(content: String, val lineNumber: Int): Line(content)
|
class AddedLine(content: String, val oldLineNumber: Int, val newLineNumber: Int): Line(content)
|
||||||
class RemovedLine(content: String, val lineNumber: Int): Line(content)
|
class RemovedLine(content: String, val lineNumber: Int): Line(content)
|
||||||
}
|
}
|
@ -1,104 +1,49 @@
|
|||||||
package app.git.diff
|
package app.git.diff
|
||||||
|
|
||||||
import app.extensions.lineAt
|
import app.extensions.lineAt
|
||||||
|
import app.git.RawFileManager
|
||||||
|
import dagger.assisted.Assisted
|
||||||
|
import dagger.assisted.AssistedInject
|
||||||
import org.eclipse.jgit.diff.*
|
import org.eclipse.jgit.diff.*
|
||||||
import org.eclipse.jgit.diff.DiffAlgorithm.SupportedAlgorithm
|
import org.eclipse.jgit.lib.Repository
|
||||||
import org.eclipse.jgit.lib.*
|
|
||||||
import org.eclipse.jgit.patch.FileHeader
|
import org.eclipse.jgit.patch.FileHeader
|
||||||
import org.eclipse.jgit.patch.FileHeader.PatchType
|
import org.eclipse.jgit.patch.FileHeader.PatchType
|
||||||
import org.eclipse.jgit.storage.pack.PackConfig
|
|
||||||
import org.eclipse.jgit.treewalk.AbstractTreeIterator
|
import org.eclipse.jgit.treewalk.AbstractTreeIterator
|
||||||
import org.eclipse.jgit.treewalk.WorkingTreeIterator
|
|
||||||
import org.eclipse.jgit.util.LfsFactory
|
|
||||||
import java.io.ByteArrayOutputStream
|
import java.io.ByteArrayOutputStream
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import kotlin.math.max
|
import kotlin.math.max
|
||||||
import kotlin.math.min
|
import kotlin.math.min
|
||||||
|
|
||||||
private const val DEFAULT_BINARY_FILE_THRESHOLD = PackConfig.DEFAULT_BIG_FILE_THRESHOLD
|
private const val CONTEXT_LINES = 3
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generator of [Hunk] lists from [DiffEntry]
|
* Generator of [Hunk] lists from [DiffEntry]
|
||||||
*/
|
*/
|
||||||
class HunkDiffGenerator(
|
class HunkDiffGenerator @AssistedInject constructor(
|
||||||
private val repository: Repository,
|
@Assisted private val repository: Repository,
|
||||||
|
@Assisted private val rawFileManager: RawFileManager,
|
||||||
) : AutoCloseable {
|
) : AutoCloseable {
|
||||||
private var reader: ObjectReader? = null
|
|
||||||
private lateinit var diffCfg: DiffConfig
|
|
||||||
private lateinit var diffAlgorithm: DiffAlgorithm
|
|
||||||
private var context = 3
|
|
||||||
private var binaryFileThreshold = DEFAULT_BINARY_FILE_THRESHOLD
|
|
||||||
private val outputStream = ByteArrayOutputStream() // Dummy output stream used for the diff formatter
|
private val outputStream = ByteArrayOutputStream() // Dummy output stream used for the diff formatter
|
||||||
private val diffFormatter = DiffFormatter(outputStream).apply {
|
private val diffFormatter = DiffFormatter(outputStream).apply {
|
||||||
setRepository(repository)
|
setRepository(repository)
|
||||||
}
|
}
|
||||||
|
|
||||||
init {
|
|
||||||
setReader(repository.newObjectReader(), repository.config)
|
|
||||||
}
|
|
||||||
|
|
||||||
private var source: ContentSource.Pair? = null
|
|
||||||
private var quotePaths: Boolean? = null
|
|
||||||
|
|
||||||
private fun setReader(reader: ObjectReader, cfg: Config) {
|
|
||||||
close()
|
|
||||||
this.reader = reader
|
|
||||||
diffCfg = cfg.get(DiffConfig.KEY)
|
|
||||||
if (quotePaths == null) {
|
|
||||||
quotePaths = java.lang.Boolean
|
|
||||||
.valueOf(
|
|
||||||
cfg.getBoolean(
|
|
||||||
ConfigConstants.CONFIG_CORE_SECTION,
|
|
||||||
ConfigConstants.CONFIG_KEY_QUOTE_PATH, true
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
val cs = ContentSource.create(reader)
|
|
||||||
source = ContentSource.Pair(cs, cs)
|
|
||||||
diffAlgorithm = DiffAlgorithm.getAlgorithm(
|
|
||||||
cfg.getEnum(
|
|
||||||
ConfigConstants.CONFIG_DIFF_SECTION, null,
|
|
||||||
ConfigConstants.CONFIG_KEY_ALGORITHM,
|
|
||||||
SupportedAlgorithm.HISTOGRAM
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun close() {
|
override fun close() {
|
||||||
reader?.close()
|
|
||||||
outputStream.close()
|
outputStream.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun scan(oldTreeIterator: AbstractTreeIterator, newTreeIterator: AbstractTreeIterator) {
|
fun scan(oldTreeIterator: AbstractTreeIterator, newTreeIterator: AbstractTreeIterator) {
|
||||||
source = ContentSource.Pair(source(oldTreeIterator), source(newTreeIterator))
|
rawFileManager.scan(oldTreeIterator, newTreeIterator)
|
||||||
diffFormatter.scan(oldTreeIterator, newTreeIterator)
|
diffFormatter.scan(oldTreeIterator, newTreeIterator)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun source(iterator: AbstractTreeIterator): ContentSource {
|
|
||||||
return if (iterator is WorkingTreeIterator)
|
|
||||||
ContentSource.create(iterator)
|
|
||||||
else
|
|
||||||
ContentSource.create(reader)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun format(ent: DiffEntry): List<Hunk> {
|
fun format(ent: DiffEntry): List<Hunk> {
|
||||||
val fileHeader = diffFormatter.toFileHeader(ent)
|
val fileHeader = diffFormatter.toFileHeader(ent)
|
||||||
val rawOld = getRawContent(DiffEntry.Side.OLD, ent)
|
val rawOld = rawFileManager.getRawContent(DiffEntry.Side.OLD, ent)
|
||||||
val rawNew = getRawContent(DiffEntry.Side.NEW, ent)
|
val rawNew = rawFileManager.getRawContent(DiffEntry.Side.NEW, ent)
|
||||||
return format(fileHeader, rawOld, rawNew)
|
return format(fileHeader, rawOld, rawNew)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getRawContent(side: DiffEntry.Side, entry: DiffEntry): RawText {
|
|
||||||
if (entry.getMode(side) === FileMode.MISSING) return RawText.EMPTY_TEXT
|
|
||||||
if (entry.getMode(side).objectType != Constants.OBJ_BLOB) return RawText.EMPTY_TEXT
|
|
||||||
|
|
||||||
val ldr = LfsFactory.getInstance().applySmudgeFilter(
|
|
||||||
repository,
|
|
||||||
source!!.open(side, entry), entry.diffAttribute
|
|
||||||
)
|
|
||||||
return RawText.load(ldr, binaryFileThreshold)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given a [FileHeader] and the both [RawText], generate a [List] of [Hunk]
|
* Given a [FileHeader] and the both [RawText], generate a [List] of [Hunk]
|
||||||
*/
|
*/
|
||||||
@ -116,10 +61,10 @@ class HunkDiffGenerator(
|
|||||||
var curEdit = edits[curIdx]
|
var curEdit = edits[curIdx]
|
||||||
val endIdx = findCombinedEnd(edits, curIdx)
|
val endIdx = findCombinedEnd(edits, curIdx)
|
||||||
val endEdit = edits[endIdx]
|
val endEdit = edits[endIdx]
|
||||||
var oldCurrentLine = max(0, curEdit.beginA - context)
|
var oldCurrentLine = max(0, curEdit.beginA - CONTEXT_LINES)
|
||||||
var newCurrentLine = max(0, curEdit.beginB - context)
|
var newCurrentLine = max(0, curEdit.beginB - CONTEXT_LINES)
|
||||||
val oldEndLine = min(oldRawText.size(), endEdit.endA + context)
|
val oldEndLine = min(oldRawText.size(), endEdit.endA + CONTEXT_LINES)
|
||||||
val newEndLine = min(newRawText.size(), endEdit.endB + context)
|
val newEndLine = min(newRawText.size(), endEdit.endB + CONTEXT_LINES)
|
||||||
|
|
||||||
val headerText = createHunkHeader(oldCurrentLine, oldEndLine, newCurrentLine, newEndLine)
|
val headerText = createHunkHeader(oldCurrentLine, oldEndLine, newCurrentLine, newEndLine)
|
||||||
val lines = mutableListOf<Line>()
|
val lines = mutableListOf<Line>()
|
||||||
@ -138,7 +83,7 @@ class HunkDiffGenerator(
|
|||||||
oldCurrentLine++
|
oldCurrentLine++
|
||||||
} else if (newCurrentLine < curEdit.endB) {
|
} else if (newCurrentLine < curEdit.endB) {
|
||||||
val lineText = newRawText.lineAt(newCurrentLine)
|
val lineText = newRawText.lineAt(newCurrentLine)
|
||||||
lines.add(Line.AddedLine(lineText, newCurrentLine))
|
lines.add(Line.AddedLine(lineText, oldCurrentLine, newCurrentLine))
|
||||||
|
|
||||||
newCurrentLine++
|
newCurrentLine++
|
||||||
}
|
}
|
||||||
@ -187,11 +132,11 @@ class HunkDiffGenerator(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun combineA(e: List<Edit>, i: Int): Boolean {
|
private fun combineA(e: List<Edit>, i: Int): Boolean {
|
||||||
return e[i].beginA - e[i - 1].endA <= 2 * context
|
return e[i].beginA - e[i - 1].endA <= 2 * CONTEXT_LINES
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun combineB(e: List<Edit>, i: Int): Boolean {
|
private fun combineB(e: List<Edit>, i: Int): Boolean {
|
||||||
return e[i].beginB - e[i - 1].endB <= 2 * context
|
return e[i].beginB - e[i - 1].endB <= 2 * CONTEXT_LINES
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun end(edit: Edit, a: Int, b: Int): Boolean {
|
private fun end(edit: Edit, a: Int, b: Int): Boolean {
|
||||||
|
Loading…
Reference in New Issue
Block a user