Gitnuro/src/main/kotlin/app/git/RawFileManager.kt
2022-02-21 01:49:14 +01:00

111 lines
3.6 KiB
Kotlin

package app.git
import app.TempFilesManager
import app.extensions.systemSeparator
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.errors.BinaryBlobException
import org.eclipse.jgit.lib.*
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.FileOutputStream
import java.nio.file.Path
import kotlin.io.path.createTempFile
private const val DEFAULT_BINARY_FILE_THRESHOLD = PackConfig.DEFAULT_BIG_FILE_THRESHOLD
class RawFileManager @AssistedInject constructor(
@Assisted private val repository: Repository,
private val tempFilesManager: TempFilesManager,
) : AutoCloseable {
private var reader: ObjectReader = repository.newObjectReader()
private var source: ContentSource.Pair
private val imageFormatsSupported = listOf(
"png",
"jpg",
"jpeg",
"webp",
)
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): EntryContent {
if (entry.getMode(side) === FileMode.MISSING) return EntryContent.Missing
if (entry.getMode(side).objectType != Constants.OBJ_BLOB) return EntryContent.InvalidObjectBlob
val ldr = LfsFactory.getInstance().applySmudgeFilter(
repository,
source.open(side, entry), entry.diffAttribute
)
return try {
EntryContent.Text(RawText.load(ldr, DEFAULT_BINARY_FILE_THRESHOLD))
} catch (ex: BinaryBlobException) {
if (isImage(entry)) {
generateImageBinary(ldr, entry, side)
} else
EntryContent.Binary
}
}
private fun generateImageBinary(
ldr: ObjectLoader,
entry: DiffEntry,
side: DiffEntry.Side
): EntryContent.ImageBinary {
val tempDir = tempFilesManager.tempDir
val tempFile = createTempFile(tempDir, prefix = "${entry.newPath.replace(systemSeparator, "_")}_${side.name}")
tempFile.toFile().deleteOnExit()
val out = FileOutputStream(tempFile.toFile())
out.use {
ldr.copyTo(out)
}
return EntryContent.ImageBinary(tempFile)
}
// todo check if it's an image checking the binary format, checking the extension is a temporary workaround
private fun isImage(entry: DiffEntry): Boolean {
val path = entry.newPath
val fileExtension = path.split(".").lastOrNull() ?: return false
return imageFormatsSupported.contains(fileExtension.lowercase())
}
override fun close() {
reader.close()
}
}
sealed class EntryContent {
object Missing : EntryContent()
object InvalidObjectBlob : EntryContent()
data class Text(val rawText: RawText) : EntryContent()
sealed class BinaryContent : EntryContent()
data class ImageBinary(val tempFilePath: Path) : BinaryContent()
object Binary : BinaryContent()
object TooLargeEntry : EntryContent()
}