provs/doc/ForDevelopers.md
2024-08-16 17:31:12 +02:00

3.6 KiB

This page provides information for developers.

Tasks

What is a task ?

A task is the basic execution unit in provs. When executed, each task produces exactly one result (line) with either success or failure.

The success or failure is computed automatically in the following way:

  • a task fails if it calls subtasks and if at least one subtask has failed
  • a taskWithResult works the same except that it requires an additional result to be returned which is also included in the success calculation
  • a task defined with optional (i.e. = optional { /* ... */ } always returns success (even if there are failing subtasks)
  • requireLast defines a task which must provide an explicit result and solely this result counts for success calculation

Task declaration

A task can be declared by

fun Prov.myCustomTask() = task { /* ... code and subtasks come here ... */ }
// e.g.
fun Prov.myEchoTask() = task { 
    cmd("echo hello world!") 
}

The task will succeed if all sub-tasks (called tasks during execution) have succeeded resp. if no sub-task was called.

Alternative ways

The following ways are equivalent but are more verbose:

// Redundant declaration of the return type (ProvResult), which is already declared by task
fun Prov.myCustomTask(): ProvResult = task { /* ... code and subtasks come here ... */ }

// Redundant parentheses behind task
fun Prov.myCustomTask() = task() { /* ... code and subtasks come here ... */ }

// Redundant definition of the task name, but could be used to output a different task name  
fun Prov.myCustomTask() = task("myCustomTask") { /* ... code and subtasks come here ... */ }

// Functionally equal, but with additional curly brackets 
fun Prov.myCustomTask() { task { /* ... code and subtasks come here ... */ } }

Btw, the following lines are wrong and will not work as expected, as they result in too much lamda nesting:

fun Prov.myCustomTask() = { task { /* ... code and subtasks come here ... */ } }
fun Prov.myCustomTask() {{ task { /* ... code and subtasks come here ... */ } }}

TaskWithResult

In case you want explicitly to include the return value (of type ProvResult) of a task to be added to the evaluation, you need to use taskWithResult instead of task and return the intended value, e.g. like

fun Prov.myEchoTask() = taskWithResult { 
    cmd("echo hello world!") 
    // ...
    ProvResult(false, "Error: ... error message ...")  // will be the returned as return value and included in the evaluation 
}

IMPORTANT: the value you want to return must be placed at the end of the lambda code (as usual in functional programming)! The following will NOT work as expected:

fun Prov.myEchoTask() = taskWithResult {
    ProvResult(false, "Error: ... error message ...")  // will be ignored
    // the result from the call below (i.e. from task "cmd") will be returned by myEchoTask,
    // which is redundant as its result is already included in the evaluation anyway. 
    cmd("echo hello world!")  
}

Task output

If the correctly defined task myEchoTask is run e.g. with local().myEchoTask(), it will produce output like

>  Success -- myEchoTask 
--->  Success -- cmd [/bin/bash, -c, echo hello world!]

Call hierarchy

In the following link you can find an example of a sequence diagram when provisioning a desktop:

ProvisionDesktopSequence.md

Create a provs jar-file

  • Clone this repo
  • Build the jar-file by ./gradlew uberjarDesktop
  • In folder build/libs you'll find the file provs-desktop.jar

This uberjar is a Java jar-file including all required dependencies.