Skip to content
Oleg edited this page May 17, 2017 · 3 revisions

Recipe computation

Recipe body is computation expression of type recipe. This computation returns Recipe type and is very similar to async computation. Both regular code (such as assignments/binding, loops and conditional expressions) and do! notation can be used in recipe* body.

Some of the features available within recipes:

  • execute asynchronous API
  • wait for dependent artifacts (the need function)
  • get environment and script variables
  • write the trace messages bound to artifact being built
  • record execution stats (newstep method)
  • get execution context (root folder, rules, command-line options, artifact)

Defining recipe

Defining recipe is similar to defining a regular function:

let downloadFile name = recipe {
    let! fileData = WebClient.DownloadStringAsync name
    return fileData.Length
}

Call another task/recipe

recipe {
    let! result = downloadFile "main.cpp"
    ...
}

Notice let-bang operator must be used for calling recipe or async functions. If recipe does not return a value do! operator should be used.

When to define recipe or function

Define a recipe in case any if the following conditions met:

  • you need an access the execution context
  • asynchronous functions are used
  • calling xake functions for tracing, demanding other artifacts etc

Use functions in other cases.

Exception handling: try/with/finally

recipe computation expression supports try/with and try/finally blocks.

// create a helper task/recipe
let log = trace Message
...
recipe {
  do! log "before try"

  try
    try
        do! log "Body executed"
        failwith "Ouch"
    with e ->
        do! log "Exception: %s" e.Message
  finally
    printfn "Error!"
}

tasks (with do! notation) are allowed in with block but aren't in finally block. This is limitation of F#'s computation expressions.

WhenError function

Intercepts errors (exceptions) and allows to define a custom handler.

  phony "main" (recipe{
    do! trace Message "The exception thrown below will be silently ignored"
    failwith "some error"
    } |> WhenError ignore)

FailWhen

Raises the exception if action's result meet specified condition. E.g. the following code raises error in case errorlevel (result of shell command execution) gets non-zero value.

do! shell {cmd "dir"} |> FailWhen ((<>) 0) "Failed to list files in folder"
// or just
do! shell {cmd "dir"} |> CheckErrorLevel

Clone this wiki locally