Next: (maak main), Previous: (maak i18n), Up: API
Get a variable from the currently loaded maak file module.
Undocumented macro.
Undocumented macro.
Undocumented macro.
Undocumented macro.
Undocumented macro.
Undocumented macro.
Undocumented macro.
Undocumented macro.
Default value:
#t
Default value:
("podman-compose")
Default value:
"podman"
Default value:
#f
Default value:
"sudo"
Default value:
"curl"
Default value:
()
Default value:
#f
Executes a shell command constructed from a list of strings.
($ '("echo -n" "hello-world"))
;; as root, in the background, quietly, and without caring whether it fails
($ '("systemctl daemon-reload")
#:sudo? #t #:async? #t #:dev-null? #t #:allow-failure? #t)
ARGUMENTS:
(("CI" . "1"))), as "KEY=VALUE" strings, or as one such
string. They are passed through env and reach the command
itself.
doas when it is
installed, sudo otherwise, or whatever MAAK_ELEVATE names.
See elevation-command.
/dev/null.
#f is returned instead, so a task can decide
what a failure means. The command line itself is left alone, which is
what lets the task be told the command failed.
run), instead
of a boolean.
RETURNS: The result of the syscall function: #t if
the command completes with an exit code of 0, #f if it failed and
#:allow-failure? was given, and a job record when #:async?
was given.
Prepend DIR to Guile’s load path and record it as a maak load path.
Returns the canonical name of the directory that was added, which makes it usable in a ‘let’ when a task wants to report what it did. This is a procedure rather than the ‘add-to-load-path’ syntax because a task computes the directory at run time.
Prepend every directory of DIRS to the load path, in order.
Returns the list of directories that were added.
Return the names of the tasks maak can currently run, sorted.
Undocumented procedure.
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))
Print FILE to standard output.
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.
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.
Return #t when COMMAND can be found on ‘PATH’.
Return #t when COMMAND is an executable in one of the directories in PATH.
Return the argv that runs Compose with ARGUMENTS.
FILE is –file, PROJECT is –project-name, ENV-FILES are passed as –env-file, and PROFILES as –profile. They come before the subcommand, which is where both Docker Compose and podman-compose expect them.
Return #t when the Compose PROGRAM can be found on PATH.
PROGRAM is the list of words container-compose-command returns; its first word is what is looked for.
Build SERVICES with Compose; see ‘compose-build-argv‘.
Return the argv that builds SERVICES, or every service when it is empty.
Render the Compose configuration; see ‘compose-config-argv‘.
Return the argv that renders the resolved Compose configuration.
QUIET? asks Compose to validate without printing; SERVICES? asks for only the service definitions, and the service names are passed as arguments when given. The quiet flag is spelled -q because that is the form both Compose implementations accept.
Stop and remove SERVICES with Compose; see ‘compose-down-argv‘.
Return the argv that stops and removes SERVICES, or the whole project.
VOLUMES? also removes named volumes, which is what makes a test environment return to a clean state; it is off by default because the data is otherwise kept between runs.
Run COMMAND in SERVICE with Compose; see ‘compose-exec-argv‘.
Return the argv that runs COMMAND in SERVICE.
NO-TTY? (the default) passes -T, which both Docker Compose and podman-compose spell the same way. A task needs it: without it Compose tries to allocate a terminal, and a command run from a pipeline or a CI job does not have one. TTY? asks for a terminal instead, and wins over the default: the two flags contradict each other, so only one is ever emitted. Pass #:no-tty? #f for an interactive shell that should not be told what to do either way.
Print the logs of SERVICES with Compose; see ‘compose-logs-argv‘.
Return the argv that prints the logs of SERVICES, or of the whole project.
Run Compose with ARGUMENTS and return its output as a string.
List the containers of SERVICES with Compose; see ‘compose-ps-argv‘.
Return the argv that lists the containers of SERVICES, or of the project.
ALL? is Docker Compose’s –all; podman-compose has no equivalent flag and lists the project’s containers already, so leave it off with that program.
Pull the images of SERVICES with Compose; see ‘compose-pull-argv‘.
Return the argv that pulls the images of SERVICES.
IGNORE-PULL-FAILURES? is Docker Compose’s flag; podman-compose does not accept it, so leave it off with that program.
Restart SERVICES with Compose; see ‘compose-restart-argv‘.
Return the argv that restarts SERVICES.
Run COMMAND in a one-off container for SERVICE; see ‘compose-run-argv‘.
Return the argv that runs COMMAND in a one-off container for SERVICE.
REMOVE? (the default) passes –rm; NO-DEPS? keeps Compose from starting the service’s dependencies.
Start SERVICES with Compose; see ‘compose-up-argv‘.
Return the argv that starts SERVICES, or every service when it is empty.
DETACH? (the default) is –detach, because a task that starts a stack wants its shell back. BUILD? rebuilds images, FORCE-RECREATE? replaces the containers, REMOVE-ORPHANS? is on by default, and WAIT? waits for the services to be healthy before returning.
Run ENGINE with ARGUMENTS, a list of strings.
The escape hatch for subcommands without a wrapper, such as ‘volume ls‘. Nothing is handed to a shell, so a label or a path with a space in it stays one argument.
Return the argv that runs ENGINE with ARGUMENTS.
This is the shared shape of every helper below: the engine first, then the subcommand and its flags. It is exported because a subcommand without a wrapper is still a subcommand – pass ‘(list "volume" "ls")‘ and it works.
Return #t when ENGINE can be found on PATH.
Build the image described by CONTEXT; see ‘container-build-argv‘.
Return the argv that builds the image described by CONTEXT.
TAG is –tag, FILE is –file, TARGET is –target, and BUILD-ARGS and LABELS are lists of strings. CONTEXT is the directory sent to the engine, normally the last argument.
Run COMMAND in the container NAME; see ‘container-exec-argv‘.
Return the argv that runs COMMAND in the container NAME.
COMMAND is a list of strings. INTERACTIVE? and TTY? are the usual -i and -t; a non-interactive command needs neither, which is what a build step wants.
List images; see ‘container-images-argv‘.
Return the argv that lists images, with any extra ARGUMENTS.
Inspect NAMES; see ‘container-inspect-argv‘.
Return the argv that inspects NAMES.
FORMAT is passed as –format, which is how a task reads a field rather than the whole JSON document. TYPE is –type for engines that accept it.
Print the logs of the container NAME; see ‘container-logs-argv‘.
Return the argv that prints the logs of the container NAME.
FOLLOW? is –follow; TAIL is a number or the word all, passed as –tail; SINCE is passed as –since.
Run ENGINE with ARGUMENTS and return its output as a string.
This is the reading counterpart of ‘container‘: the output is a value a task can trim and compare rather than a line on the terminal. In dry-run mode nothing runs, the command is printed, and the empty string comes back.
List containers; see ‘container-ps-argv‘.
Return the argv that lists containers, including stopped ones with ALL?.
Pull IMAGE; see ‘container-pull-argv‘.
Return the argv that pulls IMAGE.
Push IMAGE; see ‘container-push-argv‘.
Return the argv that pushes IMAGE.
Remove the containers NAMES; see ‘container-rm-argv‘.
Return the argv that removes the containers NAMES.
FORCE? is the default because a task that removes a container means it, and a running container would otherwise fail the whole task.
Run IMAGE as a container; see ‘container-run-argv‘ for the options.
Return the argv that runs IMAGE as a container.
COMMAND is the list of arguments passed to the image, after its name. The defaults are the ones an unattended task wants: REMOVE? is #t, so a finished container leaves nothing behind, and nothing is attached to the terminal unless INTERACTIVE? or TTY? asks for it. ENV, PUBLISH, VOLUME, MOUNT and LABELS are lists of strings, each passed with its flag.
Stop the containers NAMES, a list of strings.
Return the argv that stops the containers NAMES.
Tag SOURCE as TARGET; see ‘container-tag-argv‘.
Return the argv that gives SOURCE the additional name TARGET.
Copy a file or directory from X to Y.
ARGUMENTS: x: Source file or directory. y: Destination path.
recursive?: If #t, copy directories recursively (‘-r‘). Defaults to #t. force?: If #t, overwrite existing files without prompting (‘-f‘). Defaults to #f. verbose?: If #t, logs the final shell command before execution. Defaults to #f. verbose-copy?: If #t, enables verbose output from ‘cp‘ (‘-v‘). Defaults to #t. expand?: If #t, the shell expands X and Y, so a wildcard names the files it matches. Defaults to #f, which passes both as one argument each.
Constructs and executes a command of the form:
cp [OPTIONS] X Y
through ‘run‘, so X and Y reach ‘cp‘ as one argument each and a path with a space in it is copied rather than split.
RETURNS: #t if the copy succeeds.
ERRORS: Signals an error if the underlying ‘cp‘ command exits with a non-zero status.
Run curl with ARGUMENTS, a list of strings; see ‘curl-argv’.
Return the argv that runs curl with ARGUMENTS.
The escape hatch for a flag no helper models; nothing is handed to a shell, so an argument with a space in it stays one argument.
Download URL with curl; see ‘curl-download-argv’.
Return the argv that downloads URL to OUTPUT.
Without OUTPUT curl keeps the remote name, which is what –remote-name means. DIRECTORY is curl’s –output-dir, and CREATE-DIRS? makes the parents of the destination. RESUME? continues a partial download.
Fetch URL with curl; see ‘curl-get-argv’ for the options.
Return the argv that fetches URL with curl.
The defaults are the ones a task wants: redirects are followed, an HTTP error is a failure, and the progress meter is replaced by silence plus real errors. OUTPUT writes the body to a file, OUTPUT-DIR names the directory for it, and CREATE-DIRS? creates the parents. RESUME? continues a partial file.
Ask for URL’s headers with curl; see ‘curl-head-argv’.
Return the argv that asks for URL’s headers with a HEAD request.
Run curl with ARGUMENTS and return what it printed.
This is the reading counterpart of ‘curl’: the body is a value a task can trim, split or parse. In dry-run mode nothing runs, the command is printed, and the empty string comes back.
Send a POST request to URL; see ‘curl-post-argv’.
Return the argv that sends a POST request to URL.
DATA is a body string, JSON is a JSON body sent with curl’s –json (which also sets the content type and Accept header), DATA-FILE is a file whose bytes are the body, and FORM is a list of –form fields. At least one of them must be given. METHOD defaults to POST; pass another method for an API that spells its update differently.
Return URL’s HTTP status code as a number.
A transport failure raises unless ALLOW-FAILURE? is #t, in which case #f is returned when curl prints no code. An HTTP error is still a status: 404 comes back as 404.
Return the argv that prints URL’s HTTP status code.
The body is discarded and –fail is deliberately left off, so a 404 is reported as 404 rather than as a failed download.
Fetch URL with curl and return the body as a string.
Use this instead of ‘curl-get’ when the task needs the response, not a line on the terminal. A non-zero curl exits non-zero and raises, unless ALLOW-FAILURE? is #t.
Return the argv that fetches URL’s body for a task to read.
Upload FILE to URL with curl; see ‘curl-upload-argv’.
Return the argv that uploads FILE to URL with curl.
METHOD defaults to PUT, which is what an object store usually expects; pass POST for an API that takes the file as a form upload.
Return CMD with the decorations a task asked for, applied in a fixed order.
The environment comes first and goes through ‘env’ rather than as a ‘KEY=VALUE’ prefix, because everything after a ‘guix shell –’ is executed directly: a prefix there would be looked up as a program name and fail with 127.
Whether a failure is allowed is not a decoration of the command line at all; ‘syscall’ reads the exit code, which a ‘|| true’ in the line would have hidden. Backgrounding is not one either: a trailing ‘&’ leaves nothing to wait on, so ‘#:async?’ forks instead and hands back a job (see ‘run’).
Remove the common leading indentation from a multiline STR.
Tabs are expanded to four spaces, leading and trailing blank lines are removed, and the smallest indentation shared by the remaining lines is stripped from all of them. Blank lines in the middle are preserved as empty lines.
(dedent-string " hello world") ⇒ "hello world"
Delete a directory and all its contents recursively. Runs ‘rm -rfv DIR‘ through ‘run‘, so DIR reaches ‘rm‘ as one argument however it is spelled. The deletion is recursive, forced and verbose.
With EXPAND? #t the shell expands DIR, so ‘build/*.o’ names every matching file; the same opt-in applies to the other file helpers via ‘run’.
ARGUMENTS:
RETURNS: #t if the command succeeded.
ERRORS: Signals an error if the underlying shell command exits with a non-zero status.
Return the words that run Compose, as a list.
PREFERRED, when non-empty, is split on whitespace and used as it stands. For Podman, the standalone ‘podman-compose‘ is preferred when it is installed, and ‘podman compose‘ is used otherwise; Docker always answers ‘docker compose‘. The engine is passed in rather than read from the parameter, so the result is a pure function of its arguments.
Return the container engine maak should use.
PREFERRED, when non-empty, wins unchanged. Otherwise Podman is chosen when it is on PATH, then Docker. The fallback is Podman even when neither is installed, so a missing engine is reported as a missing program rather than silently replaced by another one.
PATH is the search path, PATH itself by default, so the choice can be tested without changing the process environment.
(detect-container-engine #:path search-path) (detect-container-engine #:preferred engine-name)
Return the command maak should use to run something as root.
PREFERRED, when non-empty, wins unchanged, which is how ‘MAAK_ELEVATE’ lets a user name an escalation program maak has never heard of. Otherwise ‘doas’ is chosen when it is on PATH, and ‘sudo’ when it is not: ‘doas’ is the smaller tool and the one a machine that has it usually means, while ‘sudo’ remains the fallback every other system understands.
PATH is the search path, ‘PATH’ itself by default, so the function can be tested without changing the process environment.
(detect-elevation-command #:path "/usr/bin:/bin") ;; => "sudo" (detect-elevation-command #:preferred "doas -n") ;; => "doas -n"
Return the download program ‘download’ should use.
PREFERRED, when non-empty, wins unchanged. Otherwise curl is chosen when it is on PATH, then wget. The fallback is curl even when neither is installed, so a missing program is reported as a missing program rather than silently replaced by the other one.
PATH is the search path, PATH itself by default, so the choice can be tested without changing the process environment.
(detect-fetch-command #:path search-path) (detect-fetch-command #:preferred "wget")
Download URL with the detected downloader.
TOOL is curl or wget; the default comes from ‘fetch-command’, which is curl when it is installed, wget otherwise, or whatever MAAK_FETCH names. OUTPUT is the destination file (the remote name when it is #f), DIRECTORY is the directory it belongs in, and CONTINUE? resumes a partial file. HEADERS, USER-AGENT, TIMEOUT and RETRIES are passed to either program; USER and PASSWORD become curl’s –user or wget’s –user/–password.
(download "https://example.org/release.tar.gz"
#:output "release.tar.gz"
#:continue? #t)
(parameterize ((fetch-command "wget"))
(download "https://example.org/" #:output "index.html"))
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"))
Return the value of environment variable NAME, or DEFAULT when unset.
Set environment variable NAME to VALUE and return VALUE.
Remove environment variable NAME.
Return ENV as a list of ‘KEY=VALUE’ strings.
ENV may be #f, a single string, a list of strings, or an alist of pairs, so a caller can pass whatever shape it already has. An entry that is not a pair is used as it stands, which is what makes the plain string list useful when a value cannot be written as a literal.
Return the directories named by ‘MAAK_LOAD_PATH’.
‘GUILE_LOAD_PATH’ is already honoured by Guile itself and is deliberately not merged here; this is the maak-specific extra so a task can add paths without clobbering the user’s global setting.
Return #t when COMMAND, the downloader ‘download’ would use, is on PATH.
Return the lines that describe task NAME, given its docstring DOC.
A docstring that is one paragraph starts inline after the name, and every continuation line aligns under the first word of the documentation, so a docstring wrapped over several lines reads as one block:
build: Compile the project.
The result lands in ./target.
A docstring with a blank line in it is a set of paragraphs, and running text would flatten that shape away, so it prints as a block instead: the name on its own line and every line indented to the same column, with the blank lines left blank.
Common leading indentation is removed first with ‘dedent-string’, so a docstring written inside an indented function still reads flush left.
Run git with ARGUMENTS, a list of strings, in DIRECTORY.
This is what every wrapper below is made of, and the way to reach a
command that has no wrapper – git fetch, git reset, a
subcommand added tomorrow. Nothing is handed to a shell, so a value
with spaces in it stays one argument.
(git (list "fetch" "--all")) (git (list "log" "--oneline" "-3") #:directory "/path/to/checkout")
A command that exits non-zero raises a maak error naming it, unless ALLOW-FAILURE? is #t, in which case the call answers #f.
Stage PATHS, or every change in the tree when none is named.
Write REVISION as OUTPUT with git archive, under PREFIX, in FORMAT.
FORMAT is one git archive understands, tar.gz and zip
being the usual ones. PREFIX is the directory the archive unpacks into,
and it carries its own trailing slash. DIRECTORY is the checkout to
read from.
(git-archive "maak-1.0.tar.gz" #:prefix "maak-1.0/")
Write REVISION as the gzipped tarball OUTPUT, under PREFIX.
Write REVISION as the zip OUTPUT, under PREFIX.
Return the argv that runs git with ARGUMENTS in DIRECTORY.
The checkout is named with -C rather than by changing maak’s
working directory, so a task can read another checkout without
disturbing its own. Exposed because the argument list is the interface
every wrapper shares: a test can assert it, and a caller can log or
extend it without running git.
List the branches, or create the branches NAMES name.
Run git checkout with ARGUMENTS.
For a branch, git-switch says what it means; this wrapper is for
the rest of git checkout – restoring paths, detached commits,
--orphan.
Cherry-pick with any arguments git cherry-pick takes.
Remove untracked files with any arguments git clean takes.
git clean does nothing without -f; pass it, and -d
for directories, because there is no safer default that would still be
useful.
Clone URL into DIRECTORY, with BRANCH, DEPTH or BARE? when given.
git clone is the one command that cannot be pointed at a checkout
with -C, because the checkout it makes is the destination; the
destination is therefore the final argument rather than a decoration.
Without DIRECTORY git names the directory after the repository, exactly
as it does on the command line.
(git-clone "https://example.org/project.git" #:depth 1) (git-clone "../other" #:directory "vendor/other" #:branch "trunk")
Commit with MESSAGE, every tracked change by default.
ALL? is the -a that stages modified and deleted tracked files
without a separate git add; it is #t for the common case of
committing the working tree. AMEND? replaces the last commit,
ALLOW-EMPTY? makes a commit with no changes, and SIGN? signs it with the
configured GPG key.
(git-commit "fix: keep the config when it is missing") (git-commit "docs: typo" #:all? #f) ;; commit only what is staged
Read or write configuration with any arguments git config takes.
Return the branch the checkout in DIRECTORY is on.
A detached HEAD answers with the revision rather than the word HEAD, so a task that tags a release from CI still gets something it can record.
Return the full hash of the commit checked out in DIRECTORY.
Describe a commit, with any arguments git describe takes.
Return the most recent tag reachable from HEAD in DIRECTORY.
(git-describe-tag) ;; => v0.10.0
Show the changes between the working tree and the index, or as ARGUMENTS say.
Use --cached to compare the index with the last commit, or name
two revisions to compare them with each other.
Return #t when the checkout in DIRECTORY has anything uncommitted.
Both staged and unstaged changes count, as do untracked files: this is
the question git status --porcelain answers, rather than the
narrower one git diff --quiet answers.
Fetch from the remote, with any arguments git fetch takes.
Initialise a git repository here, with any arguments git init takes.
Show the history as a decorated one-line graph, twenty commits by default.
Merge with any arguments git merge takes.
Run git with ARGUMENTS in DIRECTORY and return what it printed.
This is the reading half of git: the output is a string the task
can trim, split and compare, not a line on the terminal. A command that
exits non-zero raises, unless ALLOW-FAILURE? is #t, in which case the
partial output is returned – the same contract as capture. In
dry-run mode nothing runs, the command is printed, and the empty string
comes back.
(string-trim (git-output (list "rev-parse" "--abbrev-ref" "HEAD")))
Pull from the upstream branch, with any arguments git pull takes.
Push the current branch, with any arguments git push takes.
A bare push does not send tags that are not annotated; (git-push
"--tags") sends them too.
Rebase with any arguments git rebase takes.
Manage remotes with any arguments git remote takes.
(git-remote (list "add" "origin" "https://example.org/project.git")) (git-remote (list "-v"))
Return the URL configured for remote NAME in DIRECTORY.
Return the names of the remotes configured in DIRECTORY, sorted.
Reset with any arguments git reset takes.
--soft and --mixed keep the changes; --hard throws
them away, which is what makes this wrapper worth naming explicitly in a
task.
Restore paths with any arguments git restore takes.
Ask git about revisions, with any arguments git rev-parse takes.
Revert with any arguments git revert takes.
Show a commit, tag or other object, with any arguments git show takes.
Stash with any arguments git stash takes.
The bare call saves the working tree; pass pop to bring it back,
or list to see what is saved.
Show the current branch and a short status of the working tree.
Manage submodules with any arguments git submodule takes.
Switch to BRANCH, creating it with CREATE? or discarding local changes with FORCE? when asked.
git switch is the modern spelling of the checkout half of
git checkout: it changes branches and nothing else, which is why
it is the default here.
Tag the current commit as NAME, without an annotation unless MESSAGE is given.
An annotated tag is what git push --follow-tags and most release
tooling expects, so passing MESSAGE is the usual choice for a release; a
lightweight tag is the default because it changes nothing in the
history.
(git-tag "v1.2.0" #:message "maak 1.2.0")
Return the names of the tags in DIRECTORY, sorted.
Return #t when a ‘guix’ program is on ‘PATH’.
Build PACKAGE as CHANNELS pins it and return its output path.
Building is what makes the answer usable: the output path is the directory the package installed into, with its ‘bin’, ‘lib’ and ‘share’ underneath.
(guix-build "hello") ⇒ "/gnu/store/…-hello-2.12.3"
Guix’s own build log goes to standard error as it does for ‘guix build’, so a long build still shows its progress.
Build PACKAGE at Guix REVISION and return its output path.
The pinned form of ‘guix-build’: REVISION is a commit of the Guix repository at URL, and no channels file is read.
Return the channel pins FILE names, as an alist of name and commit.
(guix-channels)
⇒ (("guix" . "0fb918d61609f3aadc2d8ecc212926b3bdfabb4c"))
The file is a normal ‘channels.scm’, the one ‘guix describe -f channels’ writes; the answer names every channel it lists, in the order they appear. This is the pin the ‘-at’ helpers replace, and the one ‘guix time-machine’ would read.
Run CMD-PARTS in a Guix container defined by MANIFEST.
A container isolates the process from the host: no network unless NETWORK? is #t, no access to the home directory unless it is SHARE’d. SHARE and EXPOSE are lists of ‘HOST=DEST’ (or ‘HOST’) strings passed through as ‘-S’ and ‘-E’.
(guix-container '("maak test")
#:manifest "manifest.scm"
#:share '("/home/joe"))
Return the derivation file name of PACKAGE as CHANNELS pins it.
PACKAGE is a package name, looked up in the Guix that CHANNELS names rather than in the one running. SYSTEM is the target system, or #f for this machine’s. Nothing is built: the derivation is the recipe, and its file name is enough for ‘guix build’ or for a later ‘build-derivations’.
(guix-derivation "hello") ⇒ "/gnu/store/…-hello-2.12.3.drv"
A channels file that has never been fetched is fetched here, with the network and the time that takes; afterwards Guix’s channel cache answers at once.
Return the derivation file name of PACKAGE at Guix REVISION.
REVISION is a commit of the Guix repository at URL, which defaults to the canonical one. This is the ‘guix time-machine –commit=REVISION’ question asked as a value: which Guix is not the one running, and no channels file has to exist for it.
(guix-derivation-at "0fb918d61609f3aadc2d8ecc212926b3bdfabb4c" "hello")
Build a ‘guix pack’ of the program in FILE.
FORMAT is any ‘guix pack –format’ value ("docker", "squashfs", "tarball"). IMAGE-TAG names a docker image, SYMLINKS are ‘TARGET=SOURCE’ entries for ‘-S’, and EXTRA-PACKAGES are appended to the pack.
(guix-pack '() #:format "docker" #:image-tag "maak"
#:symlinks '("/bin=bin") #:extra-packages '("bash"))
Run a program from PACKAGE as CHANNELS pins it.
ARGS are the arguments the program gets, each a string. PROGRAM names the program inside the package’s output and defaults to the package’s own name: a bare name is looked for in ‘bin’, and a name with a slash in it is taken as a path from the output’s root. The package is built first, so the program that runs is the one that pin names and not whatever the machine happens to have installed.
(guix-program "hello" '("--version"))
(guix-program "coreutils" '("-l" "/gnu/store") #:program "ls")
(guix-program "diffutils" (list "-u" a b) #:program "diff" #:async? #t)
The decorations are ‘run”s: ‘#:env’, ‘#:sudo?’, ‘#:dev-null?’, ‘#:allow-failure?’ and ‘#:async?’, so the program can be a job like any other.
In a dry run the store query is printed instead of the program line, because the path is only known once Guix has answered; #t is returned.
Run a program from PACKAGE, built by Guix REVISION, with ARGS.
The pinned form of ‘guix-program’: the package comes from the Guix at REVISION of URL rather than from the pinned channels file, which is what a task wants when it has to run one old tool for one step. PROGRAM and the decorations are ‘guix-program”s.
(guix-program-at "0fb918d61609f3aadc2d8ecc212926b3bdfabb4c"
"hello" '(--version))
Run CMD-PARTS inside a Guix shell made of PACKAGES.
This is the package-list sibling of ‘manifest-shell’ and ‘program-shell’: the environment is described inline rather than in a manifest or a ‘guix.scm’. PACKAGES may be a list of strings ("guile", "coreutils") or a single string, which is used as-is.
(guix-shell '("guile -c '(+ 1 2)'") #:packages '("guile"))
Return the current user’s home directory, or the empty string when unset.
Compile LANGUAGE’s .po file into the .mo catalogue the program loads.
Run ‘i18n-compile’ for every language of LANGUAGES, skipping missing files.
Extract translatable strings from source files into the .pot template.
DIRECTIONS is the list of directories to scan, EXTENSIONS the file types in them, and KEYWORDS the function names xgettext should treat as translatable (‘G_’ by default). With UPDATE? the strings are joined into an existing template instead of starting a fresh one, which keeps translator comments and previous line references.
(i18n-extract #:directories '("lib" "app/views"))
Create LANGUAGE’s .po file from the .pot template.
The language directory is created when missing, so a new translation starts with one call. LANGUAGE is a locale name such as nl_NL.
Run ‘i18n-init’ for every language of LANGUAGES.
With ONLY-MISSING? (the default) a language whose .po already exists is skipped, so the call can live in a task that is run repeatedly without clobbering translators’ work with a fresh template.
Return the language the process should translate into.
The first of ‘LANGUAGE’, ‘LC_ALL’, ‘LC_MESSAGES’ and ‘LANG’ that is set, with its character encoding and any modifier stripped; when none is set, ‘en_US’ is assumed.
Return the catalogue directory of LANGUAGE inside DIR.
(i18n-locale-dir "nl_NL") ⇒ "po/nl_NL/LC_MESSAGES"
Fold the current .pot template into LANGUAGE’s .po file, in place.
Run ‘i18n-merge’ for every language of LANGUAGES, skipping missing files.
Return the path of LANGUAGE’s compiled machine object file (the one the program loads).
Return the path of LANGUAGE’s portable object file (the one a translator edits).
Return the path of the template TEXTDOMAIN.pot inside DIR.
Do the whole gettext cycle: extract, merge, then compile.
This is the one call a project normally puts in its maak file; the individual steps stay available for anything more unusual.
Return the file patterns of DIRECTORIES that ‘xgettext’ should read.
A glob that matches nothing is handed to xgettext as itself, and xgettext refuses the whole invocation over the missing file – writing no template at all rather than the strings it did find. Only directories that exist are therefore asked for, so adding or removing a source tree is all a refresh ever needs.
(i18n-source-globs '("lib" "app/views"))
Install the catalogue in DIR for TEXTDOMAIN and return a translate procedure.
The returned procedure takes one message and returns its translation, falling back to the original when the catalogue has no entry. LANGUAGE defaults to ‘i18n-language’.
(define G_ (i18n-translator #:dir "po" #:textdomain "maak")) (G_ "Hello")
Indent every line of STR by BY spaces.
When FIRST? is #f the first line is left flush, which is what aligning a continuation underneath an existing prefix needs.
Return #t when JOB has finished, without waiting for it.
A finished job is reaped here, so a background process that a task never waits for does not stay a zombie for the rest of the run.
Wait for JOB when needed and return its exit code.
Returns #f when the process was terminated by a signal, which is also what ‘status:exit-val’ says about such a status.
List documentation for every maak task in the loaded file.
Tasks are sorted by name unless AS-IS? is #t. Each docstring is laid out so its lines align under the task name rather than wrapping back to the left margin; see ‘format-task-doc’.
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.
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)
Undocumented procedure.
Undocumented procedure.
Undocumented procedure.
Undocumented procedure.
Undocumented procedure.
Undocumented procedure.
Undocumented procedure.
Predicate that indicates whether a procedure is a valid maak proc.
Predicate that indicates whether it is a valid maak task.
Return the one-line version banner printed by ‘maak –version’.
Undocumented procedure.
Execute a command inside a Guix shell defined by a manifest file.
ARGUMENTS:
cmd-parts: A list of strings representing the command to run inside the Guix shell environment.
#:verbose?: If #t, logs the fully constructed command before execution. Defaults to #f. #:pure?: If #t, it will run in a pure isolated shell (clean). Defaults to #f. #:join: The string separator used when joining command segments. Defaults to a single space. #:manifest: Path to the manifest file (in Scheme) describing the package environment. Defaults to "manifest.scm".
Constructs and executes a command of the form:
guix shell -m MANIFEST -- <cmd ...>
using the ‘$‘ wrapper to enforce proper execution and error handling.
RETURNS: #t if the command succeeds.
ERRORS: Signals an error if the underlying shell command exits with a non-zero status.
Create a directory and all necessary parent directories. Executes ‘mkdir -pv DIR‘ through ‘run‘. Parent directories are created as needed and each created directory is printed. A DIR that contains spaces is one directory, not several.
ARGUMENTS:
RETURNS: #t if the command completed successfully.
ERRORS: Signals an error if the underlying shell command exits with a non-zero code.
Move or rename a file or directory. Executes ‘mv -v X Y‘ through ‘run‘, so X and Y reach ‘mv‘ as one argument each. The ‘-v‘ flag prints each move operation performed.
ARGUMENTS:
RETURNS: #t if the command succeeds.
ERRORS: Signals an error if the underlying shell command returns a non-zero exit code.
Send ARGUMENTS to ‘niri msg’.
This is the escape hatch for subcommands and flags without a wrapper. Nothing is handed to a shell, so a program name or a workspace name with a space in it reaches niri as one argument.
A command that exits non-zero raises a maak error, unless ALLOW-FAILURE? is #t, in which case the call answers #f – the usual ‘run’ contract.
Perform an action with ARGUMENTS, through ‘niri msg action’.
A bare action name is enough for the ones that take no argument, such as
close-window; the others take their reference after it.
(niri-action (list "focus-workspace" "2")) (niri-action (list "spawn" "--" "foot" "-e" "htop"))
Return the argv that performs an action with its ARGUMENTS.
The action name comes first and its own flags follow, so
("focus-workspace" "2") is the argv for ‘focus-workspace 2’.
Return the argv that sends ARGUMENTS to ‘niri msg‘.
With JSON? the global --json flag is inserted before the
subcommand, which is where niri expects it. ARGUMENTS is the subcommand
and its flags: ("outputs"), ("action" "close-window"), and
so on.
Return #t when the niri program can be found on PATH.
Send ARGUMENTS to ‘niri msg’ and return what it printed.
This is the query form: the output is a string a task can trim, split or hand to a JSON parser, rather than a line on the terminal. In dry-run mode nothing runs, the command is printed, and the empty string comes back.
List the screencasts.
Close the focused window.
Focus the column at INDEX.
Focus the monitor NAME.
Focus the window with ID.
Focus the previously focused window.
Focus the workspace REFERENCE, an index or a name.
Focus the previous workspace.
Print information about the focused output.
Print information about the focused window.
Toggle fullscreen on the focused window.
Print the configured keyboard layouts.
List the open layer-shell surfaces.
Move the focused column to the monitor NAME.
Move the focused column to the workspace REFERENCE.
Move the focused window to the monitor NAME.
Move the focused window, or WINDOW-ID, to the workspace REFERENCE.
FOCUS is default unless given: with #t the focus follows the
window, and with #f it stays on the original workspace, which niri
spells as --focus true and --focus false.
Change OUTPUT with ACTION and ARGUMENTS; see ‘niri-output-argv’.
The change is temporary and is not written to niri’s configuration file.
Return the argv that changes OUTPUT with ACTION and ARGUMENTS.
The output name comes first and the action after it, which is the order
‘niri msg output’ requires: niri msg output DP-1 mode
1920x1080@60.
(niri-output-argv "DP-1" "scale" "1.5")
Set OUTPUT’s mode, such as 1920x1080@60.
Turn OUTPUT off.
Turn OUTPUT on.
Set OUTPUT’s position on the desktop to X and Y.
Set OUTPUT’s scale, such as 1.5.
Set OUTPUT’s transform, such as 90 or flipped-180.
List the connected outputs.
Print the overview state.
Pick a color from the screen with the mouse.
Pick a window with the mouse and print information about it.
Power off all monitors via DPMS.
Power on all monitors via DPMS.
Exit niri.
SKIP-CONFIRMATION? is the default because a task that asks niri to quit is not sitting at a keyboard to press Enter.
Ask niri to return an error, which is useful for checking a client’s error handling against a live compositor.
Open the screenshot UI.
Screenshot the focused screen.
Screenshot the focused window.
Change the width of the focused column by CHANGE.
Change the width of the focused window, or of window ID, by CHANGE.
CHANGE is a string such as +10% or 500, exactly as niri’s
command line takes it.
Set the name of the focused workspace to NAME.
Spawn COMMAND, a list of strings, without a shell.
The -- that separates niri’s own flags from the program is added
here, so a program with a flag that looks like niri’s is still passed
through.
Spawn COMMAND through the shell.
Use ‘niri-spawn’ when the program and its arguments are already separate strings; this one is for a line that needs a shell.
Toggle the overview.
Toggle windowed (fake) fullscreen on the focused window.
Unset the name of the focused workspace.
Print the version of the running niri instance.
List the open windows.
List the workspaces.
Build the derivation in FILE with the classic ‘nix-build’.
ARGUMENTS are extra words passed through verbatim, for example ‘–argstr system x86_64-linux’. OUT-LINK names the result symlink (‘–out-link’), defaulting to Nix’s own ‘result’.
Run CMD-PARTS inside the development shell of the flake FLAKE.
FLAKE is a path or flake reference such as ‘.‘ or ‘github:owner/repo’. With IMPURE? the shell inherits the host environment (‘–impure’), which some tools that read environment variables need.
(nix-develop '("make test") #:flake ".")
Build the flake FLAKE, optionally selecting the output ATTR.
(nix-flake-build #:flake "." #:attr "packages.x86_64-linux.maak")
Check every output of the flake FLAKE, as ‘nix flake check’ does.
With ALL-SYSTEMS? the check runs for all systems the flake declares rather than just the current one.
Run the application APP of the flake FLAKE with CMD-PARTS as its arguments.
(nix-run '("--version") #:flake "." #:app "maak")
Run CMD-PARTS inside a Nix shell.
With FILE the shell is described by that file (typically ‘shell.nix’); without it, Nix looks for ‘shell.nix’ or ‘default.nix’ in the current directory. Each of PACKAGES is added with ‘-p’, and PURE? passes ‘–pure’ so the host environment is hidden.
The command is handed to Nix’s own ‘–run’, so it executes inside the shell rather than after it.
(nix-shell '("python -c 'print(1)'") #:packages '("python3"))
Return #t when every stage of the pipeline that produced RESULT succeeded.
RESULT is what ‘run-pipeline’ returns when asked to capture the output, whether or not failures were allowed.
Print the version banner, and the program’s homepage, to PORT.
Execute a command inside a Guix shell defined by a program file.
ARGUMENTS: cmd-parts: A list of strings representing the command to run inside the Guix shell environment.
#:verbose?: If #t, logs the full constructed command before execution. Defaults to #f.
#:join: String used to join command segments. Defaults to a single space. #:file: Path to the Guix program or manifest file defining the shell environment. Defaults to "guix.scm".
Constructs and executes a command of the form:
guix shell -f FILE -- <cmd ...>
using the ‘$‘ wrapper to safely run the command and check for errors.
RETURNS: #t if the command succeeds.
ERRORS: Signals an error if the underlying shell command exits with a non-zero status.
Raise a ‘&maak-error’ with MESSAGE and an optional HINT.
MESSAGE is the single line the user reads; HINT, when given, is printed underneath as a suggestion for what to do next. Prefer this over ‘error’ in library code so the CLI can keep the report short.
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?’.
Remove a directory if it exists, then recreate it. This results in an empty directory, regardless of its previous state. Calls ‘delete-file-recursively‘ then ‘mkdir-p‘ on DIR.
ARGUMENTS:
RETURNS: #t if the operations succeed.
ERRORS: Signals an error if any underlying shell command fails.
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.")
Return the runnable tasks of MODULE-NAME as ‘(NAME . VARIABLE)’ pairs.
When the module declares exports, only those are considered; otherwise every procedure the module defines counts as a task. See the export rules in the README.
Delete PATH recursively, forcefully and verbosely.
A short spelling of delete-file-recursively, for the times a task
says rm -rfv build in the shell. It is an alias rather than a
second implementation, so it takes the same #:verbose? and
#:expand? keywords and behaves the same way.
(rm-rf "build") (rm-rf "build/*.o" #:expand? #t)
Run a program and its arguments without a shell.
ARGV is a list of strings: the program to run, followed by one string per argument. Nothing is split or interpolated, so a path with a space in it stays one argument. This is the default way to run a program; ‘$’ is for the lines that genuinely need a shell – pipes, redirections, globs, ‘$(...)’ and ‘VAR=value’ prefixes.
With #:expand? #t the arguments are joined with spaces and handed
to the shell, so wildcards, ‘~’ and ‘$VAR’ are expanded the way a shell
expands them. That is opt-in because the shell sees words rather than
arguments: a path with a space in it becomes several words again, which
is exactly what a caller asking for a pattern wants and exactly what the
default prevents.
(run (list "mkdir" "-p" build-dir))
(run (list "git" "commit" "-m" message))
;; start a server in the background and wait for it later
(let ((server (run (list "guix" "shell" "--" "run-server")
#:async? #t)))
(log-info "server started as ~a
" (job-pid server))
(wait-job server))
ARGUMENTS:
doas when it is
installed, sudo otherwise, or whatever MAAK_ELEVATE names.
See elevation-command.
/dev/null.
#f is returned instead.
RETURNS: #t if the program exits with code 0, #f if
it failed and failures were allowed, and a job record when
#:async? was given.
ERRORS: Signals a maak error when the program exits non-zero and failures are not allowed.
Run Compose with ARGUMENTS, a list of strings.
The escape hatch for subcommands without a wrapper, such as ‘top‘. FILE, PROJECT, ENV-FILES and PROFILES are passed before the subcommand, the way both Compose implementations expect.
Run a pipeline of programs without a shell.
STAGES is a non-empty list of stages. A stage is an argument list
shaped like the ARGV of ‘run’ – the program first, then one string per
argument – or a stage form, which adds the options ‘run’ takes
for that stage alone. The standard output of each stage is the standard
input of the next, and the whole pipeline is done when every stage has
finished.
(run-pipeline (list (list "cat" file)
(list "grep" "-v" "^#")
(list "sort" "-u")))
;; a stage with an environment and a file of its own, and one that needs root
(run-pipeline (list (stage (list "sort" "-u")
#:env '("LC_ALL=C")
#:tee "sorted.txt")
(stage (list "tee" log) #:sudo? #t)))
;; keep what every stage wrote for the task to look at
(define result (run-pipeline (list (list "git" "diff" "--cached")
(list "grep" "^+"))
#:capture? #t
#:allow-failure? #t))
(pipeline-outputs result) ;; one string per stage, in order
(pipeline-ok? result) ;; #f when a stage failed
Unlike a shell’s ‘|’, which reports the exit status of the last stage
alone, a pipeline that fails anywhere reports the stages that failed and
raises; pass #:allow-failure? #t to get #f instead and
decide in the task. This is the pipefail behaviour, and it is the one
that does not let a failing producer hide behind a successful consumer.
A pipeline’s output can be looked at afterwards in two ways. A stage
with #:tee keeps a copy of what it wrote in a file the task
names, and the stage after it reads the same bytes while it runs:
nothing is held back until the pipeline ends. #:capture? #t
records every stage the same way, in temporary files, and hands the
bytes back in the result instead of printing them; the last stage’s
output is then the last entry of pipeline-outputs. Capturing is
the way to make a decision from what a pipeline produced – a count of
changed files, the list a ‘grep’ matched – without running the pipeline
twice.
ARGUMENTS:
stage.
#f is returned instead (or the result, when the
output was captured), so the task can decide what it means.
#:env is added to these, later names
winning.
<pipeline-result>, and the
pipeline prints nothing itself. The result’s pipeline-outputs
holds one string per stage, in stage order, and pipeline-ok? says
whether every stage succeeded. A stage that also has #:tee
records into that file, which is left in place.
#:allow-failure? said. An asynchronous pipeline cannot capture
its output, because the bytes would be read in the background process;
give the stage a #:tee file instead.
RETURNS: #t when every stage exits with code 0, #f
when a stage failed and failures were allowed, a
<pipeline-result> when #:capture? was given, and a job
record when #:async? was given.
ERRORS: Signals a maak error naming the failing stage or stages
when a pipeline fails and failures are not allowed, and when
#:capture? and #:async? are asked for together.
Run TASK, a single Maak task, logging its documentation first.
Args: task: a symbol naming the task to run. task-args: the arguments to pass to the task procedure.
Returns the value of the task procedure. Raises a maak error when TASK does not name a runnable task, either because it is missing or because it exists but is not visible as a task (see the export rules in the README).
Run TASKS sequentially, in the order given.
Every task must name a procedure the loaded Maak file makes visible; otherwise a maak error lists the tasks that do exist. TASK-ARGS are passed to each task. Returns the names of the tasks that failed, in the order they were given – the empty list when everything succeeded.
With KEEP-GOING? a task that fails stops nothing: the tasks after it still run. ON-FAILURE is then called with the task name and the exception it raised, as ‘(ON-FAILURE TASK KEY VALUE ...)’, so the caller can report the failure where it happened and decide what a run full of them means. Without KEEP-GOING? the first failure is raised as it always was, backtrace and all.
Run TASKS concurrently and print their output in the order they were given.
TASKS is a list of symbols; TASK-ARGS are passed to each, as ‘run-tasks’ does. JOBS limits how many run at once: a positive number runs that many, and 0 (the default) starts them all.
Each task runs in a forked worker, so a task sees the Maak file as it was loaded and cannot change the environment of the tasks beside it. A worker’s standard output and standard error, including the output of every command it runs, go to a log of its own; the logs are printed as blocks, in the order the tasks were named, as soon as the next task in that order has finished. That is what keeps a parallel run readable: no two tasks interleave their lines.
Returns the names of the tasks that failed, in the order they were given. A task that cannot be found is an error before any worker starts, so a mistyped name cannot leave half a run behind.
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.
Split a ‘PATH’-style colon separated STR into a list of directories.
An empty entry is dropped, so a trailing or doubled colon does not add the current directory twice.
Describe one stage of a pipeline, with the options ‘run’ takes.
ARGV is a program and its arguments, in the shape ‘run’ takes them. ENV sets names for this stage alone, in the shapes ‘$’ accepts; they are added to the pipeline’s own environment, later names winning. With SUDO? the stage runs through the configured privilege escalation command (see ‘elevation-command’). TEE names a file that the stage’s standard output is also written to, the way ‘tee’ does it: the stage after this one reads the same bytes, and the file keeps them for the task to look at once the pipeline is done.
(run-pipeline (list (stage (list "grep" "-v" "^#")
#:env '("LC_ALL=C")
#:tee "clean.txt")
(stage (list "sort" "-u"))))
A stage is a description only; ‘run-pipeline’ starts it.
Split STR on newlines into a list of lines.
Executes a shell command and checks its exit code.
ARGUMENTS:
#f, the way ‘cmd || true’
would keep a shell going, except that the task also learns that the
command failed.
RETURNS: #t if the command completes with an exit code of 0,
#f if it failed and failures are allowed, and a job record when
#:async? was given.
ERRORS: Signals an error if the command returns a non-zero exit code, providing the command and the exit code in the error message.
Return the tar flags that select COMPRESSION, as a list.
The names accepted are the ones a release actually uses: none,
gz, bz2, xz and zstd. gzip,
bzip2 and zst are accepted as aliases, so a caller can
spell the compressor rather than its extension. A name that is not one
of these raises a maak error instead of producing an archive tar would
refuse to read.
Write FILES as the tarball OUTPUT.
FILES is a list of paths relative to DIRECTORY, which defaults to the current directory. The compressor follows the output’s extension unless COMPRESSION names one, and EXCLUDE is a list of patterns to leave out.
OUTPUT is written in the directory the task started in, not in DIRECTORY, so packing the current directory does not put the growing tarball into the tree tar is reading. Passing an absolute OUTPUT that points inside the packed tree does, and tar then fails with "file changed as we read it".
(tar-create "maak-1.0.tar.gz" (list "src" "README.org" "COPYING")
#:exclude (list "*.o" "*.go"))
(tar-create "maak-1.0.tar.xz" (list ".") #:compression "xz")
Return the argv that writes FILES as the tarball OUTPUT.
FILES is a list of paths relative to DIRECTORY. With COMPRESSION
auto, the output’s extension names the compressor (see
tar-infer-compression); any other value is passed to
tar-compression-option. EXCLUDE is a list of patterns, each
passed as --exclude=PATTERN. With VERBOSE? the argv includes
-v, so tar prints every file it adds.
Unpack ARCHIVE, into DIRECTORY when one is named.
STRIP-COMPONENTS drops leading path components as the files are written; use 1 for the usual release tarball that wraps everything in one directory.
(tar-extract "maak-1.0.tar.gz" #:directory "build" #:strip-components 1)
Return the argv that unpacks ARCHIVE.
The compressor is detected from the archive itself, which is why no compression flag is needed here. DIRECTORY is where the files are written, and STRIP-COMPONENTS drops that many leading path components, which is how a release tarball with a single top-level directory is unpacked into the current one.
(tar-extract-argv "project-1.0.tar.gz" #:directory "build" #:strip-components 1)
Print the names of the files in ARCHIVE, without unpacking it.
With VERBOSE? tar prints the long listing instead of bare names.
Return the argv that prints the names of the files in ARCHIVE.
Raise a user-facing error from a task.
This is what a task calls when it cannot do its job: the message is printed as one line, the hint (when given) underneath it, and no Guile backtrace follows. ARGS, when given, are handed to ‘format’ to build the message, so a task can report the value that made it give up.
(task-error "no compiled artefact for ~a" #:args (list host))
(task-error "the deploy key is missing"
#:hint "Set DEPLOY_KEY, or run maak deploy --dry-run.")
Execute a command using a pinned Guix revision via ‘guix time-machine‘.
ARGUMENTS: cmd-parts: A list of strings representing the command to run after the ‘guix time-machine‘ invocation.
#:verbose?: If #t, logs the final constructed command before running it. Defaults to #f. #:join: The string used to join command segments when constructing the final command. Defaults to a single space. #:channels: Path to the channels file used to pin the Guix revision. Defaults to "channels.scm".
Constructs and executes a command of the form:
guix time-machine --channels=CHANNELS -- <cmd ...>
using the ‘$‘ wrapper to run the resulting shell command safely.
RETURNS: #t if the command succeeds.
ERRORS: Signals an error if the underlying command exits with a non-zero status.
Execute a command inside a Guix shell defined by a manifest file, using a pinned Guix revision via ‘guix time-machine‘.
ARGUMENTS: cmd-parts: A list of strings representing the command to run inside the pinned Guix shell environment.
#:verbose?: If #t, logs the composed command before execution. Defaults to #f. #:pure?: If #t, it will run in a pure isolated shell (clean). Defaults to #f. join: String used to join command segments. Defaults to a single space. #:channels: Path to the channels file used to pin the Guix revision. Defaults to "channels.scm". #:manifest: Path to the manifest file describing the package environment. Defaults to "manifest.scm".
Constructs and executes a command of the form:
guix time-machine --channels=CHANNELS -- shell -m MANIFEST -- <cmd ...>
This provides a reproducible shell environment defined by the manifest file and pinned to the Guix revision specified in the channels file.
RETURNS: #t if the command succeeds.
ERRORS: Signals an error if any underlying shell command exits with a non-zero status.
Execute a command inside a Guix shell defined by a program file, using a pinned Guix revision via ‘guix time-machine‘.
ARGUMENTS: cmd-parts: A list of strings representing the command to run inside the pinned Guix shell environment.
#:verbose?: If #t, logs the composed command before execution. Defaults to #f. #:pure?: If #t, it will run in a pure isolated shell (clean). Defaults to #f. #:join: String used to join command segments. Defaults to a single space. #:channels: Path to the channels file used to pin the Guix revision. Defaults to "channels.scm". #:file: Path to the Guix program file (e.g. guix.scm) defining the environment. Defaults to "guix.scm".
Constructs and executes a command of the form:
guix time-machine --channels=CHANNELS -- shell -f FILE -- <cmd ...>
This provides a reproducible development environment defined by the program file and pinned to the Guix revision specified in the channels file.
RETURNS: #t if the command succeeds.
ERRORS: Signals an error if any underlying shell command exits with a non-zero status.
Return the directory for temporary files, honouring ‘TMPDIR’.
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.
Raise a maak error saying TASK is not runnable, listing the tasks that are.
Join LINES with newlines, adding no trailing newline.
Join WORDS with single spaces.
Wait for JOB to finish and return #t when it exited with code 0.
Returns #f for a non-zero exit or a signal. Waiting twice is fine: the status is remembered after the first wait.
Run wget with ARGUMENTS, a list of strings; see ‘wget-argv’.
Return the argv that runs wget with ARGUMENTS.
The escape hatch for a flag no helper models; nothing is handed to a shell, so an argument with a space in it stays one argument.
Download URL with wget; see ‘wget-download-argv’.
Return the argv that downloads URL with wget.
OUTPUT names the file, DIRECTORY is the prefix the file is written under, and CONTINUE? resumes a partial file. QUIET? silences the progress output; TIMESTAMPING? and NO-CLOBBER? decide what to do with an existing file.
Mirror the site at URL with wget; see ‘wget-mirror-argv’.
Return the argv that mirrors the site at URL with wget.
The defaults are the ones a documentation snapshot wants: recursion that stays under URL, no host directory at the top, and a DIRECTORY prefix when one is named. PAGE-REQUISITES? also fetches the images and stylesheets, CONVERT-LINKS? rewrites the saved pages to point at them, and CUT-DIRS drops leading path components from the local tree.
Run wget with ARGUMENTS and return what it printed.
In dry-run mode nothing runs, the command is printed, and the empty string comes back.
Fetch URL with wget and return the body as a string.
wget writes the body to standard output with –output-document=-, which is what lets a task read it instead of finding a file afterwards. The progress output is silenced so the result is only the body.
Return the argv that fetches URL’s body for a task to read.
Return the absolute path of COMMAND on ‘PATH’, or #f when it is missing.
(which guile) ⇒ /gnu/store/.../bin/guile
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)))
Call THUNK with environment variable NAME set to VALUE.
The previous value, if any, is restored afterwards.
Call THUNK with every NAME and VALUE pair of VARIABLES set.
(with-env-vars configured-variables (lambda () (syscall make-command)))
Call THUNK with DIRS added to the load path, restoring it afterwards.
DIRS is a list of directory names. The load path is saved and restored even when THUNK raises, so a failing task does not leave the process with a polluted search path.
(with-load-path '("./lib" "./src")
(lambda () (use-modules (my project))))
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.
Write FILES as the zip archive OUTPUT.
FILES is a list of paths relative to DIRECTORY, which defaults to the current directory. The archive itself is written relative to the directory the task started in, so a ‘#:directory "dist"’ does not leave the zip inside dist.
(zip-create "maak-1.0.zip" (list "src" "README.org")
#:exclude (list "*.go" "*.o"))
Return the argv that writes FILES as the zip archive OUTPUT.
The archive is created in the current directory; zip-create is
the one that changes into #:directory for the duration of the
command, because Info-ZIP has no -C-style option to name a tree.
EXCLUDE is a list of patterns passed as -x, after the files,
which is where zip expects them. #:junk-paths? stores bare file
names rather than the paths they were found under.
Unpack ARCHIVE, into DIRECTORY when one is named.
With OVERWRITE? (the default) existing files are replaced without a prompt; with it #f they are kept and unzip skips them.
Return the argv that unpacks ARCHIVE.
OVERWRITE? is unzip’s -o: files already there are replaced
rather than asked about, which is what an unattended task needs.
DIRECTORY is where the files are written.
Print a listing of the files in ARCHIVE, without unpacking it.
Return the argv that lists the contents of ARCHIVE.
A utility function to format a string (interpolation). Alias for (apply format #f ARGS).
(~ "Hello world, my name is ~a and I am ~a years old"
"Joe"
30)
ARGUMENTS:
RETURNS: A newly allocated string resulting from the formatting operation.
This record type has the following fields:
messagehintNext: (maak main), Previous: (maak i18n), Up: API