Commit 47ad60d4 authored by Profpatsch's avatar Profpatsch

containers/helpers: rewrite withScript to withOptions

All scripts generated now have true argparsers (and don’t throw undebuggable
error messages or default to empty string when passed the wrong data).
The usage descriptions should also help to keep complexity in check.
parent f2225c90
{ stdenv, helpers, writeScript, writeText, nix-prefetch-scripts }: { stdenv, helpers, writeText, nix-prefetch-scripts }:
let let
args = writeText "args.nix" '' args = writeText "args.nix" ''
{ nixPrefetchGit = "${nix-prefetch-scripts}/bin/nix-prefetch-git"; } { nixPrefetchGit = "${nix-prefetch-scripts}/bin/nix-prefetch-git"; }
''; '';
in writeScript "fetchgit-updater" '' in helpers.script.withOptions {
#!${stdenv.shell} name = "fetchgit-updater";
description = "Update the json description of a git source.";
options = {
file = {
description = "The json file to update.";
checks = [ helpers.script.optionChecks.fileExists ];
};
};
script = ''
${helpers.json2string} \ ${helpers.json2string} \
${args} \ ${args} \
${./json-to-prefetch-invocation.nix} \ ${./json-to-prefetch-invocation.nix} \
"$1" "$file"
'' '';
}
{ lib, pkgs, stdenv, libPath ? <nixpkgs/lib> }: { lib, pkgs, stdenv, helpers, libPath ? <nixpkgs/lib> }:
# TODO: Do we need all of lib? # TODO: Do we need all of lib?
# TODO: Is there a better way to pass stuff to nix?!
# TODO: better argument handling
let let
transGeneric = nixCommand: '' transGeneric = name: synopsis: nixCommand: with helpers.script;
withOptions {
inherit name synopsis;
description = ''
Similar to jq, but arguably more powerful.
The nix script `trans` is a function that takes
`args` as first argument (a nix attrset)
and a `json` file as a nix value as second argument.
`trans` has the <nixpkgs/lib> attrset in scope.
Through `args` it is possible to pass e.g.
nix store paths or files or more complex data.
'';
options = {
args = {
description = "Nix arguments to pass to the transformer.";
checks = [ optionChecks.fileExists ];
};
trans = {
description = "Nix JSON transformer function.";
checks = [ optionChecks.fileExists ];
};
json = {
description = "JSON input data";
checks = [ optionChecks.fileExists ];
};
};
script = ''
#!${stdenv.shell} #!${stdenv.shell}
ARGS="$(realpath "$1")" ARGS="$(realpath "$args")"
DIR=$(mktemp -d) DIR=$(mktemp -d)
cat >$DIR/script-input.nix <<EOF cat >$DIR/script-input.nix <<EOF
with import ${libPath}; with import ${libPath};
$(cat "$2") $(cat "$trans")
EOF EOF
JSON="$(realpath "$3")" JSON="$(realpath "$json")"
cat >$DIR/script.nix <<EOF cat >$DIR/script.nix <<EOF
let let
...@@ -31,27 +57,32 @@ let ...@@ -31,27 +57,32 @@ let
source ${pkgs.setupLocalNixStore} source ${pkgs.setupLocalNixStore}
${nixCommand} ${nixCommand}
''; '';
};
json2json = pkgs.writeScript "nix-json-to-json" json2json = transGeneric
(transGeneric '' "nix-json-to-json"
"Transform a json file using a nix expression."
''
${pkgs.nix}/bin/nix eval \ ${pkgs.nix}/bin/nix eval \
--json \ --json \
--show-trace \ --show-trace \
-f $DIR/script.nix \ -f $DIR/script.nix \
"" ""
''); '';
# TODO: Not sure if the produced output path is always # TODO: Not sure if the produced output path is always
# reachable from the result? Maybe enable passing a valid # reachable from the result? Maybe enable passing a valid
# path from outside? # path from outside?
json2string = pkgs.writeScript "nix-json-to-out" json2string = transGeneric
(transGeneric '' "nix-json-to-out"
"Convert a json file to a string using a nix expression."
''
${pkgs.nix}/bin/nix eval \ ${pkgs.nix}/bin/nix eval \
--raw \ --raw \
--show-trace \ --show-trace \
-f $DIR/script.nix \ -f $DIR/script.nix \
"" ""
''); '';
mkjson = json: pkgs.writeText "test.json" (builtins.toJSON json); mkjson = json: pkgs.writeText "test.json" (builtins.toJSON json);
...@@ -60,7 +91,10 @@ let ...@@ -60,7 +91,10 @@ let
eq = nixFile: jsonFile: resultFile: '' eq = nixFile: jsonFile: resultFile: ''
echo "{}" > ./args.nix echo "{}" > ./args.nix
${pkgs.diffutils}/bin/diff \ ${pkgs.diffutils}/bin/diff \
<(${json2json} ./args.nix ${nixFile} ${jsonFile}) \ <(${json2json} \
--args ./args.nix \
--trans ${nixFile} \
--json ${jsonFile}) \
${resultFile} ${resultFile}
''; '';
in { in {
...@@ -85,7 +119,10 @@ let ...@@ -85,7 +119,10 @@ let
buildEchoScriptFromJsonString = '' buildEchoScriptFromJsonString = ''
echo "{}" > ./args.nix echo "{}" > ./args.nix
echo "{}: str: str" > ./echo.nix echo "{}: str: str" > ./echo.nix
${json2string} ./args.nix ./echo.nix ${mkjson "hello!\nworld!"} \ ${json2string} \
--args=./args.nix \
--trans=./echo.nix \
--json=${mkjson "hello!\nworld!"} \
> out > out
grep "hello!" <out grep "hello!" <out
grep "world!" <out grep "world!" <out
...@@ -104,7 +141,10 @@ let ...@@ -104,7 +141,10 @@ let
''; '';
in '' in ''
touch empty.json touch empty.json
${json2string} ${args} ${echoshell} empty.json \ ${json2string} \
--args ${args} \
--trans ${echoshell} \
--json empty.json \
| ${stdenv.shell} -s \ | ${stdenv.shell} -s \
| grep echoshell | grep echoshell
''; '';
......
{ stdenv, lib, writeText, writeScript }: { stdenv, lib, writeText, writeScript, runCommand, utillinux }:
{ {
name, name,
description, synopsis,
description ? "",
# { description, checks } # { description, checks }
options, options,
script script
...@@ -13,8 +14,9 @@ let ...@@ -13,8 +14,9 @@ let
usageAttr = n: v: "--${n} (${checks v.checks}): ${v.description}"; usageAttr = n: v: "--${n} (${checks v.checks}): ${v.description}";
in in
writeText "${name}-usage.txt" '' writeText "${name}-usage.txt" ''
${name}: ${description} ${name}: ${synopsis}
${description}
${name} ${name}
${builtins.concatStringsSep "\n " ${builtins.concatStringsSep "\n "
(lib.mapAttrsToList usageAttr options)} (lib.mapAttrsToList usageAttr options)}
...@@ -49,8 +51,12 @@ let ...@@ -49,8 +51,12 @@ let
getopt = getopt =
let let
opts = nameMapOptsSep "," (o: "${o}:"); opts = nameMapOptsSep "," (o: "${o}:");
getoptBin = runCommand "getopt-bin" {} ''
install -D ${lib.getBin utillinux}/bin/getopt \
$out/bin/getopt
'';
in '' in ''
PARSED__=$(getopt --name="${name}" \ PARSED__=$(${getoptBin}/bin/getopt --name="${name}" \
--options= \ --options= \
--longoptions=${opts} \ --longoptions=${opts} \
-- "$@") -- "$@")
...@@ -123,8 +129,8 @@ let ...@@ -123,8 +129,8 @@ let
''; '';
argParser = writeText "${name}-argparser.sh" '' optParser = writeText "${name}-optparser.sh" ''
# This is an automatically generated argparser. # This is an automatically generated optparser.
# It sets the following bash variables: # It sets the following bash variables:
# ${nameMapOptsSep ", " lib.id} # ${nameMapOptsSep ", " lib.id}
# Inspired by: # Inspired by:
...@@ -150,7 +156,7 @@ let ...@@ -150,7 +156,7 @@ let
#!${stdenv.shell} #!${stdenv.shell}
# call the argparser, which sets the following variables: # call the argparser, which sets the following variables:
# ${nameMapOptsSep ", " lib.id} # ${nameMapOptsSep ", " lib.id}
source ${argParser} source ${optParser}
${script} ${script}
''; '';
......
{ pkgs }: { pkgs }:
let let
writeScriptArgparse = pkgs.callPackage ./build-script.nix {}; writeScriptOptparse = pkgs.callPackage ./build-script.nix {};
checks = { checks = {
fileExists = { fileExists = {
...@@ -13,9 +13,9 @@ let ...@@ -13,9 +13,9 @@ let
# TODO: nice tests # TODO: nice tests
tests = { tests = {
foo = writeScriptArgparse { foo = writeScriptOptparse {
name = "myname"; name = "myname";
description = "dis is description"; synopsis = "dis is synopsis";
options = { options = {
args = { args = {
description = "argument description"; description = "argument description";
...@@ -34,7 +34,8 @@ let ...@@ -34,7 +34,8 @@ let
}; };
in { in {
argumentChecks = checks; optionChecks = checks;
withArguments = writeScriptArgparse; # TODO: Opt/Arg? Argh!
# tests = tests; withOptions = writeScriptOptparse;
tests = 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