add fileContent for large files

merge-requests/1/merge
az 2 years ago
parent db33edf0f7
commit 906deb4ac7

@ -4,6 +4,7 @@ import org.domaindrivenarchitecture.provs.framework.core.platforms.SHELL
import org.domaindrivenarchitecture.provs.framework.core.*
import org.domaindrivenarchitecture.provs.framework.core.getLocalFileContent
import java.io.File
import java.util.*
/**
@ -109,7 +110,7 @@ fun Prov.createFile(
val chunkedTest = text.chunked(maxBlockSize)
for (chunk in chunkedTest) {
// todo: consider usage of function addTextToFile
cmd(
cmdNoLog(
"printf '%s' " + chunk
.escapeAndEncloseByDoubleQuoteForShell() + " | $withSudo tee -a $fullyQualifiedFilename > /dev/null"
)
@ -145,28 +146,71 @@ fun Prov.deleteFile(file: String, path: String? = null, sudo: Boolean = false):
fun Prov.fileContainsText(file: String, content: String, sudo: Boolean = false): Boolean {
// todo consider grep e.g. for content without newlines
// return cmdNoEval(prefixWithSudo("grep -- '${content.escapeSingleQuote()}' $file", sudo)).success
val fileContent = fileContent(file, sudo = sudo)
return if (fileContent == null) {
false
if (!checkFile(file, sudo)) {
return false
}
// use grep for a single line or for a single line enclosed by a newline
if (!content.contains("\n") || (content.length >= 3 && !content.drop(1).dropLast(1).contains("\n"))) {
return cmdNoEval(prefixWithSudo("grep -- '${content.escapeSingleQuote().trim('\n')}' $file", sudo)).success
} else {
fileContent.contains(content)
val fileContent = fileContent(file, sudo = sudo)
return fileContent?.contains(content) ?: false
}
}
fun Prov.fileContent(file: String, sudo: Boolean = false): String? {
return cmdNoEval(prefixWithSudo("cat $file", sudo)).out
val largeFileSize = 40000
val size = fileSize(file, sudo)
if (size == null || size > largeFileSize) {
return fileContentLargeFile(file, sudo)
} else {
return cmdNoEval(prefixWithSudo("cat $file", sudo)).out
}
}
fun Prov.fileContentLargeFile(file: String, sudo: Boolean = false, chunkSize: Int = 10000): String? {
require(chunkSize <= 40000) { "Chunk size must be < 40000" }
val maxSizeLargeFileContent = 10000000 // 10 MB
val size = fileSize(file, sudo)
if (size != null && size > maxSizeLargeFileContent) {
throw IllegalArgumentException("Cannot retrieve file content of files larger than: $maxSizeLargeFileContent bytes")
}
fun Prov.addTextToFile(
text: String,
file: String,
doNotAddIfExisting: Boolean = true,
sudo: Boolean = false
): ProvResult = addTextToFile(text, File(file), doNotAddIfExisting, sudo)
var offset = 0
var resultString: String? = null
do {
// todo : file paths starting with ~/ are not yet supported
val chunkResult =
cmdNoEval(prefixWithSudo("dd if=\"$file\" iflag=skip_bytes,count_bytes,fullblock bs=\"$chunkSize\" skip=\"$offset\" count=\"$chunkSize\" status=none | base64", sudo))
// check first chunk
if (resultString == null) {
if (!chunkResult.success) {
return resultString
} else {
resultString = ""
}
}
val b = chunkResult.out?.trim() ?: ""
offset += chunkSize
if (b.isEmpty() || b == "0") {
break
}
// Use MimeDecoder to ignore newlines (\n)
val decodedBytes: ByteArray = Base64.getMimeDecoder().decode( b )
val dec = String(decodedBytes)
resultString += dec
} while (true)
return resultString
}
fun Prov.addTextToFile(
@ -303,8 +347,8 @@ fun Prov.userHome(): String {
/**
* Returns number of bytes of a file or null if size could not be determined
*/
fun Prov.fileSize(filename: String): Int? {
val result = cmd("wc -c < $filename")
fun Prov.fileSize(filename: String, sudo: Boolean = false): Int? {
val result = cmdNoEval("wc -c < $filename", sudo = sudo)
return result.out?.trim()?.toIntOrNull()
}

@ -2,6 +2,7 @@ package org.domaindrivenarchitecture.provs.framework.ubuntu.filesystem.base
import org.domaindrivenarchitecture.provs.test.defaultTestContainer
import org.domaindrivenarchitecture.provs.test.tags.ContainerTest
import org.domaindrivenarchitecture.provs.test.tags.ExtensiveContainerTest
import org.domaindrivenarchitecture.provs.test.testLocal
import org.junit.jupiter.api.Assertions.*
import org.junit.jupiter.api.Test
@ -267,7 +268,7 @@ internal class FilesystemKtTest {
defaultTestContainer().copyFileFromLocal("copiedFileFromLocal", "$resourcesDirectory/resource-test")
// then
val content = defaultTestContainer().fileContent( "copiedFileFromLocal")
val content = defaultTestContainer().fileContent("copiedFileFromLocal")
assertEquals("resource text\n", content)
}
@ -275,18 +276,88 @@ internal class FilesystemKtTest {
@ContainerTest
fun fileContainsText() {
// given
defaultTestContainer().createFile("testfilecontainingtext", "abc\n- def\nefg")
val file = "file_with_text"
defaultTestContainer().createFile(file, "\n\nabc\n- def\nefg\nhij\nklm\no\npq", sudo = true)
// when
val res = defaultTestContainer().fileContainsText("testfilecontainingtext", "abc")
val res2 = defaultTestContainer().fileContainsText("testfilecontainingtext", "de")
val res3 = defaultTestContainer().fileContainsText("testfilecontainingtext", "- def")
val res4 = defaultTestContainer().fileContainsText("testfilecontainingtext", "xyy")
val res = defaultTestContainer().fileContainsText(file, "abc")
val res2 = defaultTestContainer().fileContainsText(file, "de")
val res3 = defaultTestContainer().fileContainsText(file, "- def")
val res4 = defaultTestContainer().fileContainsText(file, "xyy")
val res5 = defaultTestContainer().fileContainsText(file, "c\n- def\nefg\nhi")
val res6 = defaultTestContainer().fileContainsText(file, "\n\n")
val res7 = defaultTestContainer().fileContainsText(file, "\n\n\n")
val res8 = defaultTestContainer().fileContainsText(file, "\no\n")
val res10 = defaultTestContainer().fileContainsText(file, "\n\nabc")
// then
assertTrue(res)
assertTrue(res2)
assertTrue(res3)
assertFalse(res4)
assertTrue(res5)
assertTrue(res6)
assertFalse(res7)
assertTrue(res8)
assertTrue(res10)
}
@Test
@ContainerTest
fun fileContainsText_with_sudo() {
// given
val file = "sudotestfilecontainingtext"
defaultTestContainer().createFile(file, "abc\n- def\nefg\nhij\nklm\nop", sudo = true)
// when
val res = defaultTestContainer().fileContainsText(file, "abc", sudo = true)
val res2 = defaultTestContainer().fileContainsText(file, "de", sudo = true)
val res3 = defaultTestContainer().fileContainsText(file, "- def", sudo = true)
val res4 = defaultTestContainer().fileContainsText(file, "xyy", sudo = true)
// test if newlines are recognized
val res5 = defaultTestContainer().fileContainsText(file, "c\n- def\nefg\nhi", sudo = true)
// then
assertTrue(res)
assertTrue(res2)
assertTrue(res3)
assertFalse(res4)
assertTrue(res5)
}
@ExtensiveContainerTest
fun fileContentLargeFile_success() {
// given
val prov = defaultTestContainer()
val filename = "largetestfile"
val content = "012345äöüß".repeat(100000)
// when
val res = prov.createFile(filename, content, overwriteIfExisting = true)
val size = prov.fileSize(filename)
val actualContent = prov.fileContentLargeFile(filename, chunkSize = 40000)
// then
assertTrue(res.success)
assertEquals(content, actualContent)
assertEquals(1400000, size)
}
@ExtensiveContainerTest
fun fileContentLargeFile_with_sudo_success() {
// given
val prov = defaultTestContainer()
val filename = "largetestfile"
val content = "012345äöüß".repeat(100000)
// when
val res = prov.createFile(filename, content, overwriteIfExisting = true, sudo = true)
val size = prov.fileSize(filename, sudo = true)
val actualContent = prov.fileContentLargeFile(filename, chunkSize = 40000, sudo = true)
// then
assertTrue(res.success)
assertEquals(content, actualContent)
assertEquals(1400000, size)
}
}

Loading…
Cancel
Save