Extracted RawFile generation to its own class

This commit is contained in:
Abdelilah El Aissaoui 2021-12-27 22:55:31 +01:00
parent bd719be963
commit 86fd61d0d7
5 changed files with 100 additions and 78 deletions

View 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
}

View File

@ -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 {

View 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()
}
}

View File

@ -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)
} }

View File

@ -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 {