nix(feat): Add argbash support to checked-shell-script

Each postgrest- script now has a -h/--help option showing the
checked-shell-script.docs argument.

Additional CLI arguments can be defined through the
checked-shell-script.args argument using the argbash template syntax:
https://argbash.readthedocs.io/en/stable/guide.html
This commit is contained in:
Wolfgang Walther
2021-04-18 13:51:39 +02:00
committed by Wolfgang Walther
parent 39d4646a4c
commit c8edfac39e
4 changed files with 82 additions and 23 deletions
+25 -14
View File
@@ -19,16 +19,19 @@ let
Watch the project for changes and reinvoke the given command. Watch the project for changes and reinvoke the given command.
Example: Example:
postgrest-watch postgrest-test-io postgrest-watch postgrest-test-io
''; '';
args =
[
"ARG_POSITIONAL_SINGLE([command], [Command to run])"
"ARG_LEFTOVERS([command arguments])"
];
redirectTixFiles = false; # will be done by sub-command redirectTixFiles = false; # will be done by sub-command
inRootDir = true; inRootDir = true;
} }
'' ''
while true; do while true; do
(! ${silver-searcher}/bin/ag -l . | ${entr}/bin/entr -dr "$@") (! ${silver-searcher}/bin/ag -l . | ${entr}/bin/entr -dr "$_arg_command" "''${_arg_leftovers[@]}")
done done
''; '';
@@ -56,18 +59,25 @@ let
{ {
name = "postgrest-build"; name = "postgrest-build";
docs = "Build PostgREST interactively using cabal-install."; docs = "Build PostgREST interactively using cabal-install.";
args = [ "ARG_LEFTOVERS([Cabal arguments])" ];
inRootDir = true; inRootDir = true;
} }
''exec ${cabal-install}/bin/cabal v2-build ${devCabalOptions} "$@"''; ''
${cabal-install}/bin/cabal v2-build ${devCabalOptions} "''${_arg_leftovers[@]}"
'';
run = run =
checkedShellScript checkedShellScript
{ {
name = "postgrest-run"; name = "postgrest-run";
docs = "Run PostgREST after buidling it interactively with cabal-install"; docs = "Run PostgREST after buidling it interactively with cabal-install";
args = [ "ARG_LEFTOVERS([PostgREST arguments])" ];
inRootDir = true; inRootDir = true;
} }
''exec ${cabal-install}/bin/cabal v2-run ${devCabalOptions} --verbose=0 -- postgrest "$@"''; ''
${cabal-install}/bin/cabal v2-run ${devCabalOptions} --verbose=0 -- \
postgrest "''${_arg_leftovers[@]}"
'';
clean = clean =
checkedShellScript checkedShellScript
@@ -108,21 +118,21 @@ let
{ {
name = "postgrest-dump-minimal-imports"; name = "postgrest-dump-minimal-imports";
docs = "Dump minimal imports into given directory."; docs = "Dump minimal imports into given directory.";
args = [ "ARG_POSITIONAL_SINGLE([dumpdir], [Output directory])" ];
inRootDir = true; inRootDir = true;
withTmpDir = true; withTmpDir = true;
} }
'' ''
dumpdir="''${1:?dumpdir not set}" mkdir -p "$_arg_dumpdir"
mkdir -p "$dumpdir"
${cabal-install}/bin/cabal v2-build ${devCabalOptions} \ ${cabal-install}/bin/cabal v2-build ${devCabalOptions} \
--builddir="$tmpdir" \ --builddir="$tmpdir" \
--ghc-option=-ddump-minimal-imports \ --ghc-option=-ddump-minimal-imports \
--ghc-option=-dumpdir="$dumpdir" \ --ghc-option=-dumpdir="$_arg_dumpdir" \
1>&2 1>&2
# Fix OverloadedRecordFields imports # Fix OverloadedRecordFields imports
# shellcheck disable=SC2016 # shellcheck disable=SC2016
sed -E 's/\$sel:.*://g' -i "$dumpdir"/* sed -E 's/\$sel:.*://g' -i "$_arg_dumpdir"/*
''; '';
hsieMinimalImports = hsieMinimalImports =
@@ -130,11 +140,12 @@ let
{ {
name = "postgrest-hsie-minimal-imports"; name = "postgrest-hsie-minimal-imports";
docs = "Run hsie with a provided dump of minimal imports."; docs = "Run hsie with a provided dump of minimal imports.";
args = [ "ARG_LEFTOVERS([hsie arguments])" ];
withTmpDir = true; withTmpDir = true;
} }
'' ''
${dumpMinimalImports} "$tmpdir" ${dumpMinimalImports} "$tmpdir"
${hsie} "$tmpdir" "$@" ${hsie} "$tmpdir" "''${_arg_leftovers[@]}"
''; '';
hsieGraphModules = hsieGraphModules =
@@ -142,10 +153,10 @@ let
{ {
name = "postgrest-hsie-graph-modules"; name = "postgrest-hsie-graph-modules";
docs = "Create a PNG graph of modules imported within the codebase."; docs = "Create a PNG graph of modules imported within the codebase.";
args = [ "ARG_POSITIONAL_SINGLE([outfile], [Output filename])" ];
} }
'' ''
outfile="''${1:?outfile not set}" ${hsie} graph-modules main src | ${graphviz}/bin/dot -Tpng -o "$_arg_outfile"
${hsie} graph-modules main src | ${graphviz}/bin/dot -Tpng -o "$outfile"
''; '';
hsieGraphSymbols = hsieGraphSymbols =
@@ -153,10 +164,10 @@ let
{ {
name = "postgrest-hsie-graph-symbols"; name = "postgrest-hsie-graph-symbols";
docs = "Create a PNG graph of symbols imported within the codebase."; docs = "Create a PNG graph of symbols imported within the codebase.";
args = [ "ARG_POSITIONAL_SINGLE([outfile], [Output filename])" ];
} }
'' ''
outfile="''${1:?outfile not set}" ${hsieMinimalImports} graph-symbols | ${graphviz}/bin/dot -Tpng -o "$_arg_outfile"
${hsieMinimalImports} graph-symbols | ${graphviz}/bin/dot -Tpng -o "$outfile"
''; '';
in in
buildEnv { buildEnv {
@@ -1,23 +1,51 @@
# Create a bash script that is checked with shellcheck. You can either use it # Create a bash script that is checked with shellcheck. You can either use it
# directly, or use the .bin attribute to get the script in a bin/ directory, # directly, or use the .bin attribute to get the script in a bin/ directory,
# to be used in a path for example. # to be used in a path for example.
{ git { argbash
, bash_5
, git
, lib , lib
, runCommand , runCommand
, runtimeShell
, shellcheck , shellcheck
, stdenv , stdenv
, writeTextFile , writeTextFile
}: }:
# TODO: do something sensible with docs, e.g. provide automated --help
{ name { name
, docs , docs
, args ? [ ]
, inRootDir ? false , inRootDir ? false
, redirectTixFiles ? true , redirectTixFiles ? true
, withEnv ? null , withEnv ? null
, withTmpDir ? false , withTmpDir ? false
}: text: }: text:
let let
argsTemplate =
let
# square brackets are a pain to escape - if even possible. just don't use them...
escapedDocs = builtins.replaceStrings [ "\n" ] [ " \\n" ] docs;
in
writeTextFile {
inherit name;
destination = "/${name}.m4"; # destination is needed to have the proper basename for completion
text =
''
# BASH_ARGV0 sets $0 - which is used in parser.sh for usage information
# stripping the /nix/store/... path for nicer display
BASH_ARGV0="$(basename "$0")"
# ARG_HELP([${name}], [${escapedDocs}])
${lib.strings.concatMapStrings (arg: "# " + arg) args}
# ARG_DEFAULTS_POS()
# ARGBASH_GO
'';
};
argsParser =
runCommand "${name}-parser" { }
"${argbash}/bin/argbash -o $out ${argsTemplate}/${name}.m4";
bin = bin =
writeTextFile { writeTextFile {
inherit name; inherit name;
@@ -26,15 +54,19 @@ let
text = text =
'' ''
#!${runtimeShell} #!${bash_5}/bin/bash
set -euo pipefail set -euo pipefail
source ${argsParser}
'' ''
+ lib.optionalString redirectTixFiles '' + lib.optionalString redirectTixFiles ''
# storing tix files in a temporary throw away directory avoids mix/tix conflicts after changes # storing tix files in a temporary throw away directory avoids mix/tix conflicts after changes
hpctixdir=$(mktemp -d) hpctixdir=$(mktemp -d)
export HPCTIXFILE="$hpctixdir"/postgrest.tix export HPCTIXFILE="$hpctixdir"/postgrest.tix
trap 'rm -rf $hpctixdir' EXIT trap 'rm -rf $hpctixdir' EXIT
'' ''
+ lib.optionalString inRootDir '' + lib.optionalString inRootDir ''
cd "$(${git}/bin/git rev-parse --show-toplevel)" cd "$(${git}/bin/git rev-parse --show-toplevel)"
@@ -44,6 +76,7 @@ let
exit 1 exit 1
fi fi
'' ''
+ lib.optionalString withTmpDir '' + lib.optionalString withTmpDir ''
tmpdir="$(mktemp -d)" tmpdir="$(mktemp -d)"
@@ -52,11 +85,14 @@ let
# remove the tmpdir when cancelled (postgrest-watch) # remove the tmpdir when cancelled (postgrest-watch)
trap 'rm -rf "$tmpdir"' SIGINT SIGTERM trap 'rm -rf "$tmpdir"' SIGINT SIGTERM
'' ''
+ lib.optionalString (withEnv != null) '' + lib.optionalString (withEnv != null) ''
env="$(cat ${withEnv})" env="$(cat ${withEnv})"
export PATH="$env/bin:$PATH" export PATH="$env/bin:$PATH"
'' ''
+ "(${text})" + "(${text})"
+ lib.optionalString withTmpDir '' + lib.optionalString withTmpDir ''
rm -rf "$tmpdir" rm -rf "$tmpdir"
@@ -68,7 +104,7 @@ let
${stdenv.shell} -n $out/bin/${name} ${stdenv.shell} -n $out/bin/${name}
# check for shellcheck recommendations # check for shellcheck recommendations
${shellcheck}/bin/shellcheck $out/bin/${name} ${shellcheck}/bin/shellcheck -x $out/bin/${name}
''; '';
}; };
+4 -2
View File
@@ -59,13 +59,14 @@ let
{ {
name = "postgrest-test-io"; name = "postgrest-test-io";
docs = "Run the pytest-based IO tests."; docs = "Run the pytest-based IO tests.";
args = [ "ARG_LEFTOVERS([pytest arguments])" ];
inRootDir = true; inRootDir = true;
withEnv = postgrest.env; withEnv = postgrest.env;
} }
'' ''
${cabal-install}/bin/cabal v2-build ${devCabalOptions} ${cabal-install}/bin/cabal v2-build ${devCabalOptions}
${cabal-install}/bin/cabal v2-exec ${withTools.latest} \ ${cabal-install}/bin/cabal v2-exec ${withTools.latest} \
${ioTestPython}/bin/pytest -- -v test/io-tests "$@" ${ioTestPython}/bin/pytest -- -v test/io-tests "''${_arg_leftovers[@]}"
''; '';
testMemory = testMemory =
@@ -101,6 +102,7 @@ let
{ {
name = "postgrest-coverage"; name = "postgrest-coverage";
docs = "Run spec and io tests while collecting hpc coverage data."; docs = "Run spec and io tests while collecting hpc coverage data.";
args = [ "ARG_LEFTOVERS([hpc report arguments])" ];
inRootDir = true; inRootDir = true;
redirectTixFiles = false; redirectTixFiles = false;
withEnv = postgrest.env; withEnv = postgrest.env;
@@ -153,7 +155,7 @@ let
# create html and stdout reports # create html and stdout reports
${ghc}/bin/hpc markup --destdir=coverage coverage/postgrest.tix ${ghc}/bin/hpc markup --destdir=coverage coverage/postgrest.tix
echo "file://$(pwd)/coverage/hpc_index.html" echo "file://$(pwd)/coverage/hpc_index.html"
${ghc}/bin/hpc report coverage/postgrest.tix "$@" ${ghc}/bin/hpc report coverage/postgrest.tix "''${_arg_leftovers[@]}"
fi fi
''; '';
+12 -2
View File
@@ -11,6 +11,11 @@ let
{ {
name = "postgrest-with-${name}"; name = "postgrest-with-${name}";
docs = "Run the given command in a temporary database with ${name}"; docs = "Run the given command in a temporary database with ${name}";
args =
[
"ARG_POSITIONAL_SINGLE([command], [Command to run])"
"ARG_LEFTOVERS([command arguments])"
];
inRootDir = true; inRootDir = true;
redirectTixFiles = false; redirectTixFiles = false;
} }
@@ -19,7 +24,7 @@ let
if test ! -v PGRST_DB_URI; then if test ! -v PGRST_DB_URI; then
export PATH=${postgresql}/bin:"$PATH" export PATH=${postgresql}/bin:"$PATH"
exec ${../test/with_tmp_db} "$@" exec ${../test/with_tmp_db} "$_arg_command" "''${_arg_leftovers[@]}"
else else
"$@" "$@"
fi fi
@@ -40,7 +45,7 @@ let
trap 'echo "Failed on ${pg.name}"' exit trap 'echo "Failed on ${pg.name}"' exit
${withTmpDb pg} "$@" ${withTmpDb pg} "$_arg_command" "''${_arg_leftovers[@]}"
trap "" exit trap "" exit
@@ -56,6 +61,11 @@ let
{ {
name = "postgrest-with-all"; name = "postgrest-with-all";
docs = "Run command against all supported PostgreSQL versions."; docs = "Run command against all supported PostgreSQL versions.";
args =
[
"ARG_POSITIONAL_SINGLE([command], [Command to run])"
"ARG_LEFTOVERS([command arguments])"
];
inRootDir = true; inRootDir = true;
} }
(lib.concatStringsSep "\n\n" runners); (lib.concatStringsSep "\n\n" runners);