Next: , Previous: , Up: API  


1.8 (maak shell)

The shell helpers that sit on top of ‘(maak dsl)’. Where the core module offers the primitives (‘$’, ‘run’, ‘syscall’, ‘cp’, a few file moves), this one collects the everyday conveniences a task reaches for: locating a program before relying on it, running a command and reading its output, changing directory for the duration of a thunk, and reading environment variables.

Every helper here honours ‘dry-run?’ and ‘quiet?’ through the ‘run’ or ‘syscall’ it is built on, so a dry run prints instead of acting.

1.8.1 Procedures

Procedure: capture command KEY: #:error? #:allow-failure?

Run COMMAND and return its standard output as a string.

With ERROR? true the command’s standard error is captured too.

A command that exits non-zero raises a maak error naming its exit code, rather than returning the empty or partial output it managed to produce: a caller that reads ‘""’ cannot tell a command that printed nothing from one that failed. With ALLOW-FAILURE? true the output is returned anyway, and the caller decides what the failure means.

In dry-run mode the command is only printed and the empty string is returned. Use ‘$’ when a failing command must stop the task without its output, and ‘run’ when the command takes arguments that a shell must not split.

(string-trim (capture describe-tags-command))
Procedure: cd dir

Change the process working directory to DIR and return it.

Unlike ‘with-directory’ the change lasts for the rest of the run, which is what a task that only ever works from one place wants.

Procedure: chmod-file mode file KEY: #:recursive? #:verbose? #:expand?

Change the permissions of FILE to MODE, an octal string such as 755.

With EXPAND? #t the shell expands FILE, so a wildcard names every file whose permissions are to change.

Procedure: command-exists? command

Return #t when COMMAND can be found on ‘PATH’.

Procedure: env-file-entries path

Return the ‘(NAME . VALUE)’ assignments in the environment file PATH.

Blank lines and lines whose first non-blank character is ‘#’ are skipped, as are lines without an ‘=’. A leading ‘export ’ is accepted so a file that is valid for a POSIX shell is valid here too. The name and the value are trimmed, and a value wrapped in matching single or double quotes is unwrapped.

(env-file-entries ".env")
⇒ (("CI" . "1") ("DATABASE_URL" . "postgres://localhost/dev"))
Procedure: env-get name OPT: default

Return the value of environment variable NAME, or DEFAULT when unset.

Procedure: env-set! name value

Set environment variable NAME to VALUE and return VALUE.

Procedure: env-unset! name

Remove environment variable NAME.

Procedure: home-dir

Return the current user’s home directory, or the empty string when unset.

Procedure: ln-s target link-name KEY: #:force? #:verbose? #:expand?

Create a symbolic link LINK-NAME pointing at TARGET.

With FORCE? (the default) an existing link is replaced, which is what ‘ln -sf’ does. With EXPAND? #t the shell expands the two paths as words.

Procedure: load-env-file path KEY: #:override?

Read the ‘NAME=VALUE’ assignments of PATH into the environment.

Returns the list of variables that were actually set. A name that is already in the environment keeps its value unless OVERRIDE? is #t: the environment a process was started with has the last word over a file next to the code, which is the precedence ‘dotenv’ established and the one that makes ‘CI=1 maak test’ behave as asked. Pass ‘#:override? #t’ when the file is meant to win.

A missing PATH is not an error – the file is optional by definition – and returns the empty list.

(load-env-file ".env")
(load-env-file ".env.local" #:override? #t)
Procedure: read-file file KEY: #:default

Return the contents of FILE as a string.

When the file does not exist, DEFAULT is returned instead of raising; this keeps a task from having to guard every optional file with ‘file-exists?’.

Procedure: require-command command KEY: #:hint

Return the path of COMMAND, raising a maak error when it is missing.

Use this at the top of a task that depends on an external program so the user learns about the missing tool in one line instead of from a failing shell command.

(require-command guile #:hint "Install Guile 3.")
Procedure: shell-quote str

Return STR quoted so that a shell reads it as one literal word.

The POSIX recipe: wrap the value in single quotes and turn every embedded single quote into the four characters backslash-quote-quote-quote. Unlike ‘~s’, this is safe for spaces, tabs, ‘$’, backticks and newlines.

Procedure: tmp-dir

Return the directory for temporary files, honouring ‘TMPDIR’.

Procedure: touch file KEY: #:verbose? #:expand?

Create FILE if it does not exist, or update its timestamp.

With EXPAND? #t the shell expands FILE, so a wildcard touches every name it matches; see ‘run’ for what the opt-in does to the other helpers.

Procedure: which command

Return the absolute path of COMMAND on ‘PATH’, or #f when it is missing.

(which guile)
⇒ /gnu/store/.../bin/guile
Procedure: with-directory dir thunk

Call THUNK with the process working directory changed to DIR.

The previous directory is restored even when THUNK raises.

(with-directory build-dir (lambda () (syscall make-command)))
Procedure: with-env name value thunk

Call THUNK with environment variable NAME set to VALUE.

The previous value, if any, is restored afterwards.

Procedure: with-env-vars variables thunk

Call THUNK with every NAME and VALUE pair of VARIABLES set.

(with-env-vars configured-variables (lambda () (syscall make-command)))
Procedure: write-file file content KEY: #:append? #:mkdir-parents?

Write CONTENT to FILE, creating its directory first when needed.

With APPEND? #t the content is added to the end of FILE rather than replacing it.


Next: (maak version), Previous: (maak nix), Up: API