From c8edfac39e3c9af44b2354abf5b76fc181e8b27b Mon Sep 17 00:00:00 2001 From: Wolfgang Walther Date: Fri, 16 Apr 2021 18:09:19 +0200 Subject: [PATCH] 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 --- nix/devtools.nix | 39 ++++++++++------ .../checked-shell-script.nix | 46 +++++++++++++++++-- nix/tests.nix | 6 ++- nix/withtools.nix | 14 +++++- 4 files changed, 82 insertions(+), 23 deletions(-) diff --git a/nix/devtools.nix b/nix/devtools.nix index 786ca0866..1c4489329 100644 --- a/nix/devtools.nix +++ b/nix/devtools.nix @@ -19,16 +19,19 @@ let Watch the project for changes and reinvoke the given command. Example: - 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 inRootDir = true; } '' 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 ''; @@ -56,18 +59,25 @@ let { name = "postgrest-build"; docs = "Build PostgREST interactively using cabal-install."; + args = [ "ARG_LEFTOVERS([Cabal arguments])" ]; inRootDir = true; } - ''exec ${cabal-install}/bin/cabal v2-build ${devCabalOptions} "$@"''; + '' + ${cabal-install}/bin/cabal v2-build ${devCabalOptions} "''${_arg_leftovers[@]}" + ''; run = checkedShellScript { name = "postgrest-run"; docs = "Run PostgREST after buidling it interactively with cabal-install"; + args = [ "ARG_LEFTOVERS([PostgREST arguments])" ]; 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 = checkedShellScript @@ -108,21 +118,21 @@ let { name = "postgrest-dump-minimal-imports"; docs = "Dump minimal imports into given directory."; + args = [ "ARG_POSITIONAL_SINGLE([dumpdir], [Output directory])" ]; inRootDir = true; withTmpDir = true; } '' - dumpdir="''${1:?dumpdir not set}" - mkdir -p "$dumpdir" + mkdir -p "$_arg_dumpdir" ${cabal-install}/bin/cabal v2-build ${devCabalOptions} \ --builddir="$tmpdir" \ --ghc-option=-ddump-minimal-imports \ - --ghc-option=-dumpdir="$dumpdir" \ + --ghc-option=-dumpdir="$_arg_dumpdir" \ 1>&2 # Fix OverloadedRecordFields imports # shellcheck disable=SC2016 - sed -E 's/\$sel:.*://g' -i "$dumpdir"/* + sed -E 's/\$sel:.*://g' -i "$_arg_dumpdir"/* ''; hsieMinimalImports = @@ -130,11 +140,12 @@ let { name = "postgrest-hsie-minimal-imports"; docs = "Run hsie with a provided dump of minimal imports."; + args = [ "ARG_LEFTOVERS([hsie arguments])" ]; withTmpDir = true; } '' ${dumpMinimalImports} "$tmpdir" - ${hsie} "$tmpdir" "$@" + ${hsie} "$tmpdir" "''${_arg_leftovers[@]}" ''; hsieGraphModules = @@ -142,10 +153,10 @@ let { name = "postgrest-hsie-graph-modules"; 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 "$outfile" + ${hsie} graph-modules main src | ${graphviz}/bin/dot -Tpng -o "$_arg_outfile" ''; hsieGraphSymbols = @@ -153,10 +164,10 @@ let { name = "postgrest-hsie-graph-symbols"; 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 "$outfile" + ${hsieMinimalImports} graph-symbols | ${graphviz}/bin/dot -Tpng -o "$_arg_outfile" ''; in buildEnv { diff --git a/nix/overlays/checked-shell-script/checked-shell-script.nix b/nix/overlays/checked-shell-script/checked-shell-script.nix index fc46b8c89..5a1ba4a4c 100644 --- a/nix/overlays/checked-shell-script/checked-shell-script.nix +++ b/nix/overlays/checked-shell-script/checked-shell-script.nix @@ -1,23 +1,51 @@ # 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, # to be used in a path for example. -{ git +{ argbash +, bash_5 +, git , lib , runCommand -, runtimeShell , shellcheck , stdenv , writeTextFile }: -# TODO: do something sensible with docs, e.g. provide automated --help { name , docs +, args ? [ ] , inRootDir ? false , redirectTixFiles ? true , withEnv ? null , withTmpDir ? false }: text: 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 = writeTextFile { inherit name; @@ -26,15 +54,19 @@ let text = '' - #!${runtimeShell} + #!${bash_5}/bin/bash set -euo pipefail + + source ${argsParser} '' + + lib.optionalString redirectTixFiles '' # storing tix files in a temporary throw away directory avoids mix/tix conflicts after changes hpctixdir=$(mktemp -d) export HPCTIXFILE="$hpctixdir"/postgrest.tix trap 'rm -rf $hpctixdir' EXIT '' + + lib.optionalString inRootDir '' cd "$(${git}/bin/git rev-parse --show-toplevel)" @@ -44,6 +76,7 @@ let exit 1 fi '' + + lib.optionalString withTmpDir '' tmpdir="$(mktemp -d)" @@ -52,11 +85,14 @@ let # remove the tmpdir when cancelled (postgrest-watch) trap 'rm -rf "$tmpdir"' SIGINT SIGTERM '' + + lib.optionalString (withEnv != null) '' env="$(cat ${withEnv})" export PATH="$env/bin:$PATH" '' + + "(${text})" + + lib.optionalString withTmpDir '' rm -rf "$tmpdir" @@ -68,7 +104,7 @@ let ${stdenv.shell} -n $out/bin/${name} # check for shellcheck recommendations - ${shellcheck}/bin/shellcheck $out/bin/${name} + ${shellcheck}/bin/shellcheck -x $out/bin/${name} ''; }; diff --git a/nix/tests.nix b/nix/tests.nix index 6db7e6268..f50ecce22 100644 --- a/nix/tests.nix +++ b/nix/tests.nix @@ -59,13 +59,14 @@ let { name = "postgrest-test-io"; docs = "Run the pytest-based IO tests."; + args = [ "ARG_LEFTOVERS([pytest arguments])" ]; inRootDir = true; withEnv = postgrest.env; } '' ${cabal-install}/bin/cabal v2-build ${devCabalOptions} ${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 = @@ -101,6 +102,7 @@ let { name = "postgrest-coverage"; docs = "Run spec and io tests while collecting hpc coverage data."; + args = [ "ARG_LEFTOVERS([hpc report arguments])" ]; inRootDir = true; redirectTixFiles = false; withEnv = postgrest.env; @@ -153,7 +155,7 @@ let # create html and stdout reports ${ghc}/bin/hpc markup --destdir=coverage coverage/postgrest.tix echo "file://$(pwd)/coverage/hpc_index.html" - ${ghc}/bin/hpc report coverage/postgrest.tix "$@" + ${ghc}/bin/hpc report coverage/postgrest.tix "''${_arg_leftovers[@]}" fi ''; diff --git a/nix/withtools.nix b/nix/withtools.nix index 6415c3735..fde422aa4 100644 --- a/nix/withtools.nix +++ b/nix/withtools.nix @@ -11,6 +11,11 @@ let { name = "postgrest-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; redirectTixFiles = false; } @@ -19,7 +24,7 @@ let if test ! -v PGRST_DB_URI; then export PATH=${postgresql}/bin:"$PATH" - exec ${../test/with_tmp_db} "$@" + exec ${../test/with_tmp_db} "$_arg_command" "''${_arg_leftovers[@]}" else "$@" fi @@ -40,7 +45,7 @@ let trap 'echo "Failed on ${pg.name}"' exit - ${withTmpDb pg} "$@" + ${withTmpDb pg} "$_arg_command" "''${_arg_leftovers[@]}" trap "" exit @@ -56,6 +61,11 @@ let { name = "postgrest-with-all"; docs = "Run command against all supported PostgreSQL versions."; + args = + [ + "ARG_POSITIONAL_SINGLE([command], [Command to run])" + "ARG_LEFTOVERS([command arguments])" + ]; inRootDir = true; } (lib.concatStringsSep "\n\n" runners);