Commit 58d6e2c8 authored by Profpatsch's avatar Profpatsch

containers/helpers: extensive docstrings

parent 668e6b6f
......@@ -4,19 +4,25 @@
# programs without depending on an OS base image (like Alpine).
# All attributes that are named the same as `dockerTools.buildImage`
# attrs work the same.
{ name
, tag
, contents
, config
, description
# like runAsRoot, but the base setup is already done
, rootSetupScript ? ""
# Add an init process as entry point that reaps zombie processes.
# See https://github.com/krallin/tini
# and https://github.com/docker-library/official-images#init
# Note that `docker run` can do that via `--init`, but that
# is given at deploy time and therefore easy to forget.
, initProcess ? [ "${pkgs.tini}/bin/tini" "--" ]
{
# : string
name,
# : string
tag,
# : contents TODO
contents,
# : dockerConfig TODO
config,
# : lines
description,
# like runAsRoot, but the base setup is already done
rootSetupScript ? "",
# Add an init process as entry point that reaps zombie processes.
# See https://github.com/krallin/tini
# and https://github.com/docker-library/official-images#init
# Note that `docker run` can do that via `--init`, but that
# is given at deploy time and therefore easy to forget.
initProcess ? [ "${pkgs.tini}/bin/tini" "--" ]
}:
let
......
{ stdenv, helpers, writeText, nix-prefetch-scripts }:
# Updater for git sources
let
args = writeText "args.nix" ''
{ nixPrefetchGit = "${nix-prefetch-scripts}/bin/nix-prefetch-git"; }
......
{ glibcLocales }:
# generate a localedb for the given UTF-8 locale string
# Generate a localedb for the given UTF-8 locale string.
# a locale string formatted like `en_US.UTF-8`
locale:
......
{ lib, pkgs, stdenv, helpers, libPath ? <nixpkgs/lib> }:
# Scripts to transform json via nix eval.
# See the tests below for examples.
# TODO: Do we need all of lib?
let
# Produce nix files that read the input files
# and then call `nix eval`.
transGeneric = name: synopsis: nixCommand: with helpers.script;
withOptions {
inherit name synopsis;
......@@ -32,9 +36,12 @@ let
script = ''
#!${stdenv.shell}
# nix needs a path, containing / (`args` could be e.g. 'myfolder').
ARGS="$(realpath "$args")"
DIR=$(mktemp -d)
# TODO: script-input should contain the name of `trans`
# to ease debugging
cat >$DIR/script-input.nix <<EOF
with import ${libPath};
$(cat "$trans")
......@@ -59,6 +66,7 @@ let
'';
};
# `nix eval` call for json output
json2json = transGeneric
"nix-json-to-json"
"Transform a json file using a nix expression."
......@@ -70,9 +78,7 @@ let
""
'';
# TODO: Not sure if the produced output path is always
# reachable from the result? Maybe enable passing a valid
# path from outside?
# `nix eval` call for plain text output
json2string = transGeneric
"nix-json-to-out"
"Convert a json file to a string using a nix expression."
......@@ -88,6 +94,7 @@ let
jsonTests =
let
# compare json2json output with given result file
eq = nixFile: jsonFile: resultFile: ''
echo "{}" > ./args.nix
${pkgs.diffutils}/bin/diff \
......@@ -99,6 +106,9 @@ let
'';
in {
# the identity function should produce the same output
# we can compare bit-by-bit because the input is produced
# by nix as well in this case
idJson =
let
json = mkjson {
......@@ -107,6 +117,7 @@ let
idScr = pkgs.writeText "id-converter" "{}: id";
in eq idScr json json;
# we can apply library functions, like `mapAttrs`
replaceAttrsJson =
eq (pkgs.writeText "maybe-its-neuer"
''{}: mapAttrs (_: _: "manuel neuer")'')
......@@ -116,6 +127,7 @@ let
outTests = {
# the string is echoed as-is
buildEchoScriptFromJsonString = ''
echo "{}" > ./args.nix
echo "{}: str: str" > ./echo.nix
......@@ -128,6 +140,9 @@ let
grep "world!" <out
'';
# this one is interesting, we don’t transform at all
# but rather use the fact that additional stuff can
# be passed by args, e.g. store paths to executables
passingArguments =
let
args = pkgs.writeText "args.nix" ''
......@@ -141,6 +156,8 @@ let
'';
in ''
touch empty.json
# we produce a script in the `trans` expression,
# print it, eval it and check its output
${json2string} \
--args ${args} \
--trans ${echoshell} \
......
{ lib, pkgs }:
# Generates a postgresql template by executing initdb.
# Initialization of the database server (e.g. adding roles
# and databases) can be done by an init script like:
# psql --file=./mocks/projects.sql --username=postgres sangha
{
# template name
# : string
name,
# `genUtf8Localedb`
# : localeDrv
locale,
# script to connect to the database running locally
# : lines
initScript,
# attrset of postgresql.conf values
# : attrs nixScalar
postgresqlConf
}:
......
{ pkgs }:
# prepend folders to a derivations’s contents
# Prepend folders to a derivations’s contents.
# folder prefix
prefix:
......
{ stdenv, lib, writeText, writeScript, runCommand, utillinux }:
# Create a bash script and automatically generate an option parser.
# The option names are put into scope as plain bash variables.
{
# script name
# : string
name,
# short synopsis (shown in usage)
# : string
synopsis,
# long (multi-line) description
# : lines
description ? "",
# { description, checks }
# attrset of option names;
# the key is used as name,
# the value if of type
# `{ description : string , checks : check }`
# where `check` is of type
# { fnName : string # check bash function name
# , name : string # name displayed in usage
# , code : lines # bash code of the check
# }
options,
# bash script that has all options in scope
# as variables of the same name
# : lines
script
}:
let
# the usage text
usage =
let
checks = lib.concatMapStringsSep ", " (c: c.name);
......@@ -22,6 +42,7 @@ let
(lib.mapAttrsToList usageAttr options)}
'';
# bash function that prints usage to stderr
usageFn = ''
function USAGE__ {
cat 1>&2 <<EOF
......@@ -37,6 +58,7 @@ let
ourChecks = builtins.concatLists
(lib.mapAttrsToList (_: opt: opt.checks) options);
# check bash functions
checkFns =
let
checkFn = c: ''
......@@ -48,6 +70,7 @@ let
nameMapOptsSep = sep: f: lib.concatMapStringsSep sep f
(builtins.attrNames options);
# bash getopt invocation
getopt =
let
opts = nameMapOptsSep "," (o: "${o}:");
......@@ -65,6 +88,7 @@ let
eval set -- "$PARSED__"
'';
# parsing the getopt output
parseArguments =
let
# this is probably not very efficient …
......@@ -81,10 +105,12 @@ let
embed = builtins.concatLists;
applyIndent = builtins.concatStringsSep "\n";
# a check inside an argument handler
runCheck = argName: c: embed [
(i0 ''${c.fnName} "$2" \'')
(i2 (i0 ''|| ERRS__+="--${argName}: file '$2' does not exist\n"''))
];
# generated argument handler for each option
argHandler = name: opt: embed [
(i0 ''--${name})'')
(i2 (embed (map (runCheck name) opt.checks)))
......@@ -95,7 +121,9 @@ let
])
];
in ''
# accumulate errors
ERRS_=
# parse getopt output
while true; do
case "$1" in
${applyIndent
......@@ -113,10 +141,12 @@ let
;;
esac
done
# check if there were errors
[[ "$ERRS__" != "" ]] \
&& USAGE__ "Argument errors:\n$ERRS__"
'';
# we abort on missing options
checkAllOptionsGiven = ''
# check whether all options have been given
ERRS__=
......@@ -128,7 +158,7 @@ let
&& USAGE__ "options$ERRS__ are required"
'';
# the optparser, which is sourced by the final script
optParser = writeText "${name}-optparser.sh" ''
# This is an automatically generated optparser.
# It sets the following bash variables:
......@@ -151,6 +181,8 @@ let
unset -f ${lib.concatMapStringsSep " " (c: c.fnName) ourChecks}
'';
# the optparser is sourced because the generated code is quite long
# and the actual script logic should not be shadowed by that.
# TODO: maybe invert it, that you call the argparser yourself?
finalScript = writeScript name ''
#!${stdenv.shell}
......
{ pkgs }:
let
writeScriptOptparse = pkgs.callPackage ./build-script.nix {};
# main documentation in here
withOptions = pkgs.callPackage ./build-script.nix {};
checks = {
# A list of checks that can be passed to `script.withOptions`.
optionChecks = {
fileExists = {
fnName = "FILE_EXISTS__";
name = "FILE";
......@@ -13,13 +15,13 @@ let
# TODO: nice tests
tests = {
foo = writeScriptOptparse {
foo = withOptions {
name = "myname";
synopsis = "dis is synopsis";
options = {
args = {
description = "argument description";
checks = [ checks.fileExists ];
checks = [ optionChecks.fileExists ];
};
json = {
description = "some json!";
......@@ -34,8 +36,5 @@ let
};
in {
optionChecks = checks;
# TODO: Opt/Arg? Argh!
withOptions = writeScriptOptparse;
tests = tests;
inherit withOptions optionChecks tests;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment