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
import app.di.HunkDiffGeneratorFactory
import app.di.RawFileManagerFactory
import app.extensions.fullData
import app.git.diff.Hunk
import app.git.diff.HunkDiffGenerator
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import org.apache.commons.logging.LogFactory.objectId
import org.eclipse.jgit.api.Git
import org.eclipse.jgit.diff.DiffEntry
import org.eclipse.jgit.diff.DiffFormatter
@ -21,7 +22,10 @@ import java.io.ByteArrayOutputStream
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) {
val diffEntry = diffEntryType.diffEntry
val byteArrayOutputStream = ByteArrayOutputStream()
@ -42,7 +46,9 @@ class DiffManager @Inject constructor() {
formatter.flush()
}
val hunkDiffGenerator = HunkDiffGenerator(git.repository)
val rawFileManager = rawFileManagerFactory.create(repository)
val hunkDiffGenerator = hunkDiffGeneratorFactory.create(repository, rawFileManager)
val hunks = mutableListOf<Hunk>()
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) {
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)
}

View file

@ -1,104 +1,49 @@
package app.git.diff
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.DiffAlgorithm.SupportedAlgorithm
import org.eclipse.jgit.lib.*
import org.eclipse.jgit.lib.Repository
import org.eclipse.jgit.patch.FileHeader
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.WorkingTreeIterator
import org.eclipse.jgit.util.LfsFactory
import java.io.ByteArrayOutputStream
import java.io.IOException
import kotlin.math.max
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]
*/
class HunkDiffGenerator(
private val repository: Repository,
class HunkDiffGenerator @AssistedInject constructor(
@Assisted private val repository: Repository,
@Assisted private val rawFileManager: RawFileManager,
) : 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 diffFormatter = DiffFormatter(outputStream).apply {
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() {
reader?.close()
outputStream.close()
}
fun scan(oldTreeIterator: AbstractTreeIterator, newTreeIterator: AbstractTreeIterator) {
source = ContentSource.Pair(source(oldTreeIterator), source(newTreeIterator))
rawFileManager.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> {
val fileHeader = diffFormatter.toFileHeader(ent)
val rawOld = getRawContent(DiffEntry.Side.OLD, ent)
val rawNew = getRawContent(DiffEntry.Side.NEW, ent)
val rawOld = rawFileManager.getRawContent(DiffEntry.Side.OLD, ent)
val rawNew = rawFileManager.getRawContent(DiffEntry.Side.NEW, ent)
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]
*/
@ -116,10 +61,10 @@ class HunkDiffGenerator(
var curEdit = edits[curIdx]
val endIdx = findCombinedEnd(edits, curIdx)
val endEdit = edits[endIdx]
var oldCurrentLine = max(0, curEdit.beginA - context)
var newCurrentLine = max(0, curEdit.beginB - context)
val oldEndLine = min(oldRawText.size(), endEdit.endA + context)
val newEndLine = min(newRawText.size(), endEdit.endB + context)
var oldCurrentLine = max(0, curEdit.beginA - CONTEXT_LINES)
var newCurrentLine = max(0, curEdit.beginB - CONTEXT_LINES)
val oldEndLine = min(oldRawText.size(), endEdit.endA + CONTEXT_LINES)
val newEndLine = min(newRawText.size(), endEdit.endB + CONTEXT_LINES)
val headerText = createHunkHeader(oldCurrentLine, oldEndLine, newCurrentLine, newEndLine)
val lines = mutableListOf<Line>()
@ -138,7 +83,7 @@ class HunkDiffGenerator(
oldCurrentLine++
} else if (newCurrentLine < curEdit.endB) {
val lineText = newRawText.lineAt(newCurrentLine)
lines.add(Line.AddedLine(lineText, newCurrentLine))
lines.add(Line.AddedLine(lineText, oldCurrentLine, newCurrentLine))
newCurrentLine++
}
@ -187,11 +132,11 @@ class HunkDiffGenerator(
}
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 {
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 {