add task without requiring an explicit return value (ProvResult)
This commit is contained in:
parent
7eb7494fad
commit
efe158275b
15 changed files with 52 additions and 44 deletions
|
@ -12,13 +12,13 @@ fun Prov.installGopass(
|
|||
version: String = "1.12.7",
|
||||
enforceVersion: Boolean = false,
|
||||
sha256sum: String = "0824d5110ff1e68bff1ba10c1be63acb67cb1ad8e3bccddd6b6fc989608beca8" // checksum for sha256sum version 8.30 (e.g. ubuntu 20.04)
|
||||
) = task {
|
||||
) = taskWithResult {
|
||||
|
||||
if (isPackageInstalled("gopass") && !enforceVersion) {
|
||||
return@task ProvResult(true)
|
||||
return@taskWithResult ProvResult(true)
|
||||
}
|
||||
if (checkGopassVersion(version)) {
|
||||
return@task ProvResult(true, out = "Version $version of gopass is already installed.")
|
||||
return@taskWithResult ProvResult(true, out = "Version $version of gopass is already installed.")
|
||||
}
|
||||
|
||||
val path = "tmp"
|
||||
|
@ -41,17 +41,17 @@ fun Prov.installGopass(
|
|||
}
|
||||
|
||||
|
||||
fun Prov.configureGopass(gopassRootFolder: String? = null) = task {
|
||||
fun Prov.configureGopass(gopassRootFolder: String? = null) = taskWithResult() {
|
||||
val configFile = ".config/gopass/config.yml"
|
||||
val defaultRootFolder = userHome() + ".password-store"
|
||||
val rootFolder = gopassRootFolder ?: defaultRootFolder
|
||||
|
||||
if (checkFile(configFile)) {
|
||||
return@task ProvResult(true, out = "Gopass already configured in file $configFile")
|
||||
return@taskWithResult ProvResult(true, out = "Gopass already configured in file $configFile")
|
||||
}
|
||||
|
||||
if ((gopassRootFolder != null) && (!gopassRootFolder.startsWith("/"))) {
|
||||
return@task ProvResult(false, err = "Gopass cannot be initialized with a relative path or path starting with ~")
|
||||
return@taskWithResult ProvResult(false, err = "Gopass cannot be initialized with a relative path or path starting with ~")
|
||||
}
|
||||
// use default
|
||||
createDir(rootFolder)
|
||||
|
|
|
@ -5,14 +5,14 @@ import org.domaindrivenarchitecture.provs.framework.core.ProvResult
|
|||
import org.domaindrivenarchitecture.provs.framework.ubuntu.install.base.aptInstall
|
||||
import org.domaindrivenarchitecture.provs.framework.ubuntu.user.base.whoami
|
||||
|
||||
fun Prov.installVirtualBoxGuestAdditions() = task {
|
||||
fun Prov.installVirtualBoxGuestAdditions() = taskWithResult {
|
||||
// if running in a VirtualBox vm
|
||||
if (!chk("lspci | grep VirtualBox")) {
|
||||
return@task ProvResult(true, "Not running in a VirtualBox")
|
||||
return@taskWithResult ProvResult(true, "Not running in a VirtualBox")
|
||||
}
|
||||
|
||||
if (chk("VBoxService --version")) {
|
||||
return@task ProvResult(true, "VBoxService already installed")
|
||||
return@taskWithResult ProvResult(true, "VBoxService already installed")
|
||||
}
|
||||
|
||||
// install guest additions
|
||||
|
|
|
@ -67,11 +67,19 @@ open class Prov protected constructor(
|
|||
private var runInContainerWithName: String? = null
|
||||
|
||||
/**
|
||||
* Defines a task with a custom name instead of the name of the calling function.
|
||||
* Returns success if all subtasks finished with success (same as requireAll).
|
||||
* A task is the base execution unit in provs. In the results overview it is represented by one line resp. result (of either success or failure).
|
||||
* Returns success if no sub-tasks are called or if all subtasks finish with success.
|
||||
*/
|
||||
fun task(name: String? = null, a: Prov.() -> ProvResult): ProvResult {
|
||||
return handle(ResultMode.ALL, name) { a() }
|
||||
fun task(name: String? = null, taskLambda: Prov.() -> Unit): ProvResult {
|
||||
return handle(ResultMode.ALL, name) { taskLambda(); ProvResult(true) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as task but the provided lambda is explicitly required to provide a ProvResult to be returned.
|
||||
* The returned result is included in the evaluation.
|
||||
*/
|
||||
fun taskWithResult(name: String? = null, taskLambda: Prov.() -> ProvResult): ProvResult {
|
||||
return handle(ResultMode.ALL, name) { taskLambda() }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -84,7 +92,7 @@ open class Prov protected constructor(
|
|||
}
|
||||
|
||||
/**
|
||||
* defines a task, which returns success if the the last subtasks or last value returns success
|
||||
* defines a task, which returns the returned result, the results of sub-tasks are not considered
|
||||
*/
|
||||
fun requireLast(a: Prov.() -> ProvResult): ProvResult {
|
||||
return handle(ResultMode.LAST) { a() }
|
||||
|
@ -100,7 +108,7 @@ open class Prov protected constructor(
|
|||
/**
|
||||
* defines a task, which returns success if all subtasks finished with success
|
||||
*/
|
||||
@Suppress("unused")
|
||||
@Deprecated("Use function task instead", replaceWith = ReplaceWith("task()"))
|
||||
fun requireAll(a: Prov.() -> ProvResult): ProvResult {
|
||||
return handle(ResultMode.ALL) { a() }
|
||||
}
|
||||
|
@ -218,7 +226,7 @@ open class Prov protected constructor(
|
|||
* Adds a ProvResult to the overall success evaluation.
|
||||
* Intended for use in methods which do not automatically add results.
|
||||
*/
|
||||
fun addResultToEval(result: ProvResult) = task {
|
||||
fun addResultToEval(result: ProvResult) = taskWithResult {
|
||||
result
|
||||
}
|
||||
|
||||
|
@ -227,7 +235,7 @@ open class Prov protected constructor(
|
|||
* Multi-line commands within the script are not supported.
|
||||
* Empty lines and comments (all text behind # in a line) are supported, i.e. they are ignored.
|
||||
*/
|
||||
fun sh(script: String, dir: String? = null, sudo: Boolean = false) = task {
|
||||
fun sh(script: String, dir: String? = null, sudo: Boolean = false) = taskWithResult {
|
||||
val lines = script.trimIndent().replace("\\\n", "").replace("\r\n", "\n").split("\n")
|
||||
val linesWithoutComments = lines.stream().map { it.split("#")[0] }
|
||||
val linesNonEmpty = linesWithoutComments.filter { it.trim().isNotEmpty() }
|
||||
|
|
|
@ -18,7 +18,7 @@ import java.net.InetAddress
|
|||
*/
|
||||
internal fun getCallingMethodName(): String? {
|
||||
val offsetVal = 1
|
||||
val exclude = arrayOf("task", "def", "record", "invoke", "invoke0", "handle", "task\$default", "def\$default", "addResultToEval", "handle\$default")
|
||||
val exclude = arrayOf("task", "task\$default", "taskWithResult\$default", "taskWithResult", "def", "def\$default", "record", "invoke", "invoke0", "handle", "handle\$default", )
|
||||
// suffixes are also ignored as method names but will be added as suffix in the evaluation results
|
||||
val suffixes = arrayOf("optional", "requireAll", "requireLast", "inContainer")
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ class UbuntuProv internal constructor(
|
|||
}
|
||||
}
|
||||
|
||||
override fun cmd(cmd: String, dir: String?, sudo: Boolean): ProvResult = task {
|
||||
override fun cmd(cmd: String, dir: String?, sudo: Boolean): ProvResult = taskWithResult {
|
||||
exec(SHELL, "-c", commandWithDirAndSudo(cmd, dir, sudo))
|
||||
}
|
||||
|
||||
|
|
|
@ -90,7 +90,7 @@ fun Prov.createFile(
|
|||
posixFilePermission: String? = null,
|
||||
sudo: Boolean = false,
|
||||
overwriteIfExisting: Boolean = true
|
||||
): ProvResult = task {
|
||||
): ProvResult = taskWithResult {
|
||||
val maxBlockSize = 50000
|
||||
val withSudo = if (sudo) "sudo " else ""
|
||||
|
||||
|
@ -98,7 +98,7 @@ fun Prov.createFile(
|
|||
ensureValidPosixFilePermission(posixFilePermission)
|
||||
}
|
||||
if (!overwriteIfExisting && checkFile(fullyQualifiedFilename, sudo)) {
|
||||
return@task ProvResult(true, "File $fullyQualifiedFilename already existing.")
|
||||
return@taskWithResult ProvResult(true, "File $fullyQualifiedFilename already existing.")
|
||||
}
|
||||
|
||||
val modeOption = posixFilePermission?.let { "-m $it" } ?: ""
|
||||
|
@ -220,10 +220,10 @@ fun Prov.addTextToFile(
|
|||
doNotAddIfExisting: Boolean = true,
|
||||
sudo: Boolean = false
|
||||
): ProvResult =
|
||||
task {
|
||||
taskWithResult {
|
||||
val fileContainsText = fileContainsText(file.path, text, sudo = sudo)
|
||||
if (fileContainsText && doNotAddIfExisting) {
|
||||
return@task ProvResult(true, out = "Text already in file")
|
||||
return@taskWithResult ProvResult(true, out = "Text already in file")
|
||||
}
|
||||
cmd(
|
||||
"printf '%s' " + text
|
||||
|
|
|
@ -17,11 +17,11 @@ fun Prov.gitClone(
|
|||
targetPath: String = "",
|
||||
pullIfExisting: Boolean = true,
|
||||
targetFolderName: String? = null
|
||||
): ProvResult = task {
|
||||
): ProvResult = taskWithResult {
|
||||
// if specified, use targetFolderName as basename or otherwise retrieve basename from repoSource
|
||||
val basename = targetFolderName ?: cmdNoEval("basename $repoSource .git").out?.trim()
|
||||
// return err if basename could not be retrieved from repoSource
|
||||
?: return@task ProvResult(false, err = "$repoSource is not a valid git repository source path.")
|
||||
?: return@taskWithResult ProvResult(false, err = "$repoSource is not a valid git repository source path.")
|
||||
|
||||
val pathWithBasename = targetPath.normalizePath() + basename
|
||||
if (checkDir(pathWithBasename + "/.git/")) {
|
||||
|
|
|
@ -13,7 +13,7 @@ private var aptInit = false
|
|||
* @param ignoreAlreadyInstalled if true, then for an already installed package no action will be taken,
|
||||
* if "ignoreAlreadyInstalled" is false, then installation is always attempted, which normally results in an upgrade if package wa already installed
|
||||
*/
|
||||
fun Prov.aptInstall(packages: String, ignoreAlreadyInstalled: Boolean = true): ProvResult = task {
|
||||
fun Prov.aptInstall(packages: String, ignoreAlreadyInstalled: Boolean = true): ProvResult = taskWithResult {
|
||||
val packageList = packages.split(" ")
|
||||
val allInstalled: Boolean = packageList.map { isPackageInstalled(it) }.fold(true, { a, b -> a && b })
|
||||
if (!allInstalled) {
|
||||
|
|
|
@ -38,9 +38,9 @@ fun Prov.isHostKnown(hostOrIp: String) : Boolean {
|
|||
* Either add the specified rsaFingerprints or - if null - add automatically retrieved keys.
|
||||
* Note: adding keys automatically is vulnerable to a man-in-the-middle attack, thus considered insecure and not recommended.
|
||||
*/
|
||||
fun Prov.trustHost(host: String, fingerprintsOfKeysToBeAdded: Set<String>?) = task {
|
||||
fun Prov.trustHost(host: String, fingerprintsOfKeysToBeAdded: Set<String>?) = taskWithResult {
|
||||
if (isHostKnown(host)) {
|
||||
return@task ProvResult(true, out = "Host already known")
|
||||
return@taskWithResult ProvResult(true, out = "Host already known")
|
||||
}
|
||||
if (!checkFile(KNOWN_HOSTS_FILE)) {
|
||||
createDir(".ssh")
|
||||
|
@ -53,7 +53,7 @@ fun Prov.trustHost(host: String, fingerprintsOfKeysToBeAdded: Set<String>?) = ta
|
|||
// logic based on https://serverfault.com/questions/447028/non-interactive-git-clone-ssh-fingerprint-prompt
|
||||
val actualKeys = findSshKeys(host)
|
||||
if (actualKeys == null || actualKeys.size == 0) {
|
||||
return@task ProvResult(false, out = "No valid keys found for host: $host")
|
||||
return@taskWithResult ProvResult(false, out = "No valid keys found for host: $host")
|
||||
}
|
||||
val actualFingerprints = getFingerprintsForKeys(actualKeys)
|
||||
for (fingerprintToBeAdded in fingerprintsOfKeysToBeAdded) {
|
||||
|
@ -67,7 +67,7 @@ fun Prov.trustHost(host: String, fingerprintsOfKeysToBeAdded: Set<String>?) = ta
|
|||
}
|
||||
}
|
||||
if (indexOfKeyFound == -1) {
|
||||
return@task ProvResult(
|
||||
return@taskWithResult ProvResult(
|
||||
false,
|
||||
err = "Fingerprint ($fingerprintToBeAdded) could not be found in actual fingerprints: $actualFingerprints"
|
||||
)
|
||||
|
|
|
@ -22,13 +22,13 @@ fun Prov.downloadFromURL(
|
|||
followRedirect: Boolean = true,
|
||||
sha256sum: String? = null,
|
||||
overwrite: Boolean = false
|
||||
): ProvResult = task {
|
||||
): ProvResult = taskWithResult {
|
||||
|
||||
val finalFilename: String = filename ?: url.substringAfterLast("/")
|
||||
val fqFilename: String = (path?.normalizePath() ?: "") + finalFilename
|
||||
|
||||
if (!overwrite && checkFile(fqFilename, sudo = sudo)) {
|
||||
return@task ProvResult(true, out = "File $fqFilename already exists.")
|
||||
return@taskWithResult ProvResult(true, out = "File $fqFilename already exists.")
|
||||
}
|
||||
|
||||
aptInstall("curl")
|
||||
|
|
|
@ -51,9 +51,9 @@ fun Prov.deprovisionK3sInfra() = task {
|
|||
}
|
||||
|
||||
|
||||
fun Prov.installK3s(k3sConfig: K3sConfig) = task {
|
||||
fun Prov.installK3s(k3sConfig: K3sConfig) = taskWithResult {
|
||||
if (testConfigExists()) {
|
||||
return@task ProvResult(true, out = "K3s config is already in place, so skip (re)provisioning.")
|
||||
return@taskWithResult ProvResult(true, out = "K3s config is already in place, so skip (re)provisioning.")
|
||||
}
|
||||
|
||||
createDirs(k8sCredentialsDir, sudo = true)
|
||||
|
|
|
@ -8,17 +8,17 @@ import org.domaindrivenarchitecture.provs.syspec.infrastructure.findSpecConfigFr
|
|||
import org.domaindrivenarchitecture.provs.syspec.infrastructure.verifySpecConfig
|
||||
|
||||
|
||||
fun Prov.verifySpec(configFile: ConfigFileName? = null) = task {
|
||||
fun Prov.verifySpec(configFile: ConfigFileName? = null) = taskWithResult {
|
||||
val result = findSpecConfigFromFile(configFile)
|
||||
val spec = result.getOrElse { return@task ProvResult(false, "Could not read file: ${configFile?.fileName} due to: ${result.exceptionOrNull()?.message}") }
|
||||
val spec = result.getOrElse { return@taskWithResult ProvResult(false, "Could not read file: ${configFile?.fileName} due to: ${result.exceptionOrNull()?.message}") }
|
||||
verifySpecConfig(spec)
|
||||
}
|
||||
|
||||
|
||||
@Suppress("unused") // Api
|
||||
fun Prov.verifySpecFromResource(resourceName: String) = task {
|
||||
fun Prov.verifySpecFromResource(resourceName: String) = taskWithResult {
|
||||
val result = findSpecConfigFromResource(resourceName)
|
||||
val spec = result.getOrElse { return@task ProvResult(false, "Could not read resource: $resourceName due to: ${result.exceptionOrNull()?.message}") }
|
||||
val spec = result.getOrElse { return@taskWithResult ProvResult(false, "Could not read resource: $resourceName due to: ${result.exceptionOrNull()?.message}") }
|
||||
verifySpecConfig(spec)
|
||||
}
|
||||
|
||||
|
|
|
@ -149,7 +149,7 @@ private fun <T> Prov.verify(success: Boolean, message: String, expected: T? = nu
|
|||
val actualText = expected?.let { " | Actual value [$actual]" } ?: ""
|
||||
val msg = ": $message $expectedText$actualText"
|
||||
|
||||
return task("Verification") {
|
||||
return taskWithResult("Verification") {
|
||||
ProvResult(
|
||||
success,
|
||||
cmd = if (success) msg else null,
|
||||
|
|
|
@ -489,7 +489,7 @@ internal class ProvTest {
|
|||
addResultToEval(ProvResult(true))
|
||||
}
|
||||
|
||||
fun Prov.outer() = task {
|
||||
fun Prov.outer() = taskWithResult {
|
||||
inner()
|
||||
ProvResult(false)
|
||||
}
|
||||
|
@ -504,11 +504,11 @@ internal class ProvTest {
|
|||
@Test
|
||||
fun task_with_failing_subtask_and_successful_result_fails() {
|
||||
// given
|
||||
fun Prov.inner() = task {
|
||||
fun Prov.inner() = taskWithResult {
|
||||
ProvResult(false)
|
||||
}
|
||||
|
||||
fun Prov.outer() = task {
|
||||
fun Prov.outer() = taskWithResult {
|
||||
inner()
|
||||
ProvResult(true)
|
||||
}
|
||||
|
@ -527,7 +527,7 @@ internal class ProvTest {
|
|||
addResultToEval(ProvResult(false))
|
||||
}
|
||||
|
||||
fun Prov.outer() = task {
|
||||
fun Prov.outer() = taskWithResult {
|
||||
inner()
|
||||
ProvResult(true)
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ internal class TaskFunctionsKtTest {
|
|||
}
|
||||
|
||||
var count2 = 3
|
||||
fun Prov.thirdTimeSuccess() = task {
|
||||
fun Prov.thirdTimeSuccess() = taskWithResult {
|
||||
if (count2 <= 1) {
|
||||
count2 = 3
|
||||
ProvResult(true, out = "1")
|
||||
|
|
Loading…
Reference in a new issue