External dependencies
Docker, and one network step. The same imports as 08, reaching a module in another repository: lask.json says what a dependency is, the committed lask.lock.json says which bytes it is, and lask sync is the only thing that fetches.
bash
lask sync # the only step that touches the network
lask deps list # what lask.json requests, what the lock pins, and whether they agree
lask deps graph # the dependency graph
lask eval statusThe thing to take away: check, run and eval never reach the network, and an import reaches a dependency's root main.lask and nothing deeper.
This topic has 2 files, so clone the repository to try it:
bash
git clone https://github.com/lask-task-runner/lask.git
cd lask/example/02-language/09-dependenciesSource
These are example/02-language/09-dependencies in the lask repository.
lask
// External dependencies
//
// Code worth sharing lives in its own repository and is imported by
// name, not copied. What a dependency is, is declared in lask.json;
// which bytes it is, is pinned in the committed lask.lock.json.
//
// lask sync # the only step that touches the network
// lask deps list # what lask.json requests, what the lock pins
// lask deps graph # the dependency graph
// lask eval tool-version
// An import with no "./" is an external dependency, and the name is the
// key from lask.json — not a URL, not a path. Nothing in the source
// says where it came from or which revision it is; that belongs in
// lask.json and lask.lock.json, where it can be reviewed and pinned.
import * as tools from "tools"
// The named form works the same way, `as` included. Each tool of this
// dependency is a namespace, so `tf` names one here: `tf.env(...)` is
// tools.terraform.env, with its keyword parameters.
import { terraform as tf } from "tools"
// A dependency can export command words, which are imported by name
// like anything else: `jq` now runs in the environment tools declared
// for it, as if this module had declared it.
import command { "jq" } from "tools"
// An import reaches a dependency's root main.lask and nothing else:
// `import { x } from "tools/lib/aws.lask"` is a static error
// (E-MODULE-DEEP-IMPORT). A library whose API spans several files
// re-exports it from its own entry module, which is why every
// dependency has exactly one surface.
// The dependency's env function returns where terraform runs. Its image is
// the dependency's default unless one is written here, as it is:
// either way it is a head written in some file, so `lask sync`
// pulls it and pins it in this project's lock.
command { "terraform" } on tf.env(image = #hashicorp/terraform:1.16.4)
// The version of terraform the shared environment runs.
//
// @return The first line of `terraform version`.
tool_version(): String = $ terraform version
|> lines
|> first
// Check formatting, through the namespace import.
//
// @param dir A directory of .tf files.
fmt_ok(--dir: String = "."): Bool = do {
r = $*[tools.terraform.env()] terraform fmt -check -recursive #{dir}
r.code == 0
}
// A value read through the imported command word.
//
// @return The name field of a small JSON document.
name(): String = $ echo '{"name": "lask"}' | jq -r .name
|> trim
// What the dependency contributes to this module.
//
// A dependency is ordinary code: its functions are called like any
// other, and its types can be named here too.
//
// @return The tool version, and whether this directory is formatted.
status(): Record<version: String, formatted: Bool> = {
version: tool_version(),
formatted: fmt_ok()
}
// Nothing here reaches the network. `check`, `run`, `eval` and `envs`
// resolve everything from the fetched tree in .lask/, and a dependency
// that is missing or whose hash does not match the lock is an error
// naming `lask sync` — never a silent fetch in the middle of a run.json
{
"dependencies": {
"tools": {
"git": "https://github.com/lask-task-runner/lask-module-tools.git",
"rev": "v0.7.0"
}
}
}