tvl-depot/nix/runExecline/runExecline.nix
Profpatsch 4402c363b6 feat(nix/runExecline): add runExecline
runExecline is a primitive that just does not care.

It’s similar to `runCommand`, but instead of concatenating bash
scripts left and right, it actually *uses* the features of
`derivation`, passing things to `args` and making it possible to
overwrite the `builder` in a sensible manner.

Additionally, it provides a way to pass a nix string to `stdin` of the
build script.

Similar to `writeExecline`, the passed script is not a string, but a
nested list of nix lists representing execline blocks. Escaping is
done by the implementation, the user can just use normal nix strings.

Change-Id: I890d9e5d921207751cdc8cc4309381395d92742f
Reviewed-on: https://cl.tvl.fyi/c/depot/+/701
Reviewed-by: BuildkiteCI
Reviewed-by: isomer <isomer@tvl.fyi>
Reviewed-by: tazjin <mail@tazj.in>
Tested-by: BuildkiteCI
2020-06-29 22:58:47 +00:00

121 lines
3.4 KiB
Nix
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{ pkgs, stdenv, lib, getBins, escapeExecline }:
# runExecline is a primitive building block
# for writing non-kitchen sink builders.
#
# Its conceptually similar to `runCommand`,
# but instead of concatenating bash scripts left
# and right, it actually *uses* the features of
# `derivation`, passing things to `args`
# and making it possible to overwrite the `builder`
# in a sensible manner.
#
# Additionally, it provides a way to pass a nix string
# to `stdin` of the build script.
#
# Similar to //nix/writeExecline, the passed script is
# not a string, but a nested list of nix lists
# representing execline blocks. Escaping is
# done by the implementation, the user can just use
# normal nix strings.
#
# Example:
#
# runExecline "my-drv" { stdin = "hi!"; } [
# "importas" "out" "out"
# # this pipes stdout of s6-cat to $out
# # and s6-cat redirects from stdin to stdout
# "redirfd" "-w" "1" "$out" bins.s6-cat
# ]
#
# which creates a derivation with "hi!" in $out.
#
# See ./tests.nix for more examples.
let
bins = getBins pkgs.execline [
"execlineb"
{ use = "if"; as = "execlineIf"; }
"redirfd"
"importas"
"exec"
]
// getBins pkgs.s6-portable-utils [
"s6-cat"
"s6-grep"
"s6-touch"
"s6-test"
"s6-chmod"
];
in
name:
{
# a string to pass as stdin to the execline script
stdin ? ""
# a program wrapping the acutal execline invocation;
# should be in Bernstein-chaining style
, builderWrapper ? bins.exec
# additional arguments to pass to the derivation
, derivationArgs ? {}
}:
# the execline script as a nested list of string,
# representing the blocks;
# see docs of `escapeExecline`.
execline:
# those arguments cant be overwritten
assert !derivationArgs ? system;
assert !derivationArgs ? name;
assert !derivationArgs ? builder;
assert !derivationArgs ? args;
derivation (derivationArgs // {
# TODO(Profpatsch): what about cross?
inherit (stdenv) system;
inherit name;
# okay, `builtins.toFile` does not accept strings
# that reference drv outputs. This means we need
# to pass the script and stdin as envvar;
# this might clash with another passed envar,
# so we give it a long & unique name
_runExeclineScript =
let
in escapeExecline execline;
_runExeclineStdin = stdin;
passAsFile = [
"_runExeclineScript"
"_runExeclineStdin"
] ++ derivationArgs.passAsFile or [];
# the default, exec acts as identity executable
builder = builderWrapper;
args = [
bins.importas # import script file as $script
"-ui" # drop the envvar afterwards
"script" # substitution name
"_runExeclineScriptPath" # passed script file
bins.importas # do the same for $stdin
"-ui"
"stdin"
"_runExeclineStdinPath"
bins.redirfd # now we
"-r" # read the file
"0" # into the stdin of execlineb
"$stdin" # that was given via stdin
bins.execlineb # the actual invocation
# TODO(Profpatsch): depending on the use-case, -S0 might not be enough
# in all use-cases, then a wrapper for execlineb arguments
# should be added (-P, -S, -s).
"-S0" # set $@ inside the execline script
"-W" # die on syntax error
"$script" # substituted by importas
];
})