# 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. { argbash , bash , coreutils , git , lib , runCommand , shellcheck , stdenv , writeTextFile }: { name , docs , args ? [ ] , positionalCompletion ? "" , redirectTixFiles ? true , withEnv ? null , withPath ? [ ] , withTmpDir ? false , workingDir ? null }: text: assert workingDir == null || lib.hasPrefix "/" workingDir; let # square brackets are a pain to escape - if even possible. just don't use them... escape = builtins.replaceStrings [ "\n" ] [ " \\n" ]; argsTemplate = 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}], [${escape docs}]) ${lib.strings.concatMapStrings (arg: "# " + arg) args} # ARG_POSITIONAL_DOUBLEDASH() # ARG_DEFAULTS_POS() # ARGBASH_GO ''; }; argsParser = runCommand "${name}-parser" { } '' ${argbash}/bin/argbash ${argsTemplate}/${name}.m4 > $out # This forces optional arguments to go *before* positional arguments, # which allows leftovers to pass optional arguments to sub-commands. # Example: This way `postgrest-watch -h` will return the help output for watch, while # `postgrest-watch postgrest-test-spec -h` will return the help output for test-spec. # Taken from: https://github.com/matejak/argbash/issues/114#issuecomment-557108274 sed '/_positionals_count + 1/a\\t\t\t\tset -- "''${@:1:1}" "--" "''${@:2}"' -i $out ''; bash-completion = runCommand "${name}-completion" { } ( '' ${argbash}/bin/argbash --type completion --strip all ${argsTemplate}/${name}.m4 > $out '' + lib.optionalString (positionalCompletion != "") '' sed 's#COMPREPLY.*compgen -o bashdefault .*$#${escape positionalCompletion}#' -i $out '' ); bin = writeTextFile { inherit name; executable = true; destination = "/bin/${name}"; text = '' #!${bash}/bin/bash source ${argsParser} set -euo pipefail '' + lib.optionalString redirectTixFiles '' # storing tix files in a temporary throw away directory avoids mix/tix conflicts after changes hpctixdir=$(${coreutils}/bin/mktemp -d) export HPCTIXFILE="$hpctixdir"/postgrest.tix trap 'rm -rf $hpctixdir' EXIT '' + lib.optionalString (workingDir != null) '' cd "$(${git}/bin/git rev-parse --show-toplevel)" if test ! -f postgrest.cabal; then >&2 echo "Couldn't find postgrest.cabal. Please make sure to" \ "run this command somewhere in the PostgREST repo." exit 1 fi cd "''${PWD}${workingDir}" '' + lib.optionalString withTmpDir '' mkdir -p "''${TMPDIR:-/tmp}/postgrest" tmpdir="$(${coreutils}/bin/mktemp -d --tmpdir postgrest/${name}-XXX)" # we keep the tmpdir when an error occurs for debugging trap 'echo Temporary directory kept at: $tmpdir' ERR # 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" '' + lib.optionalString (lib.length withPath > 0) '' export PATH="${lib.concatMapStrings (p: p + "/bin:") withPath}$PATH" '' + "(${text})" + lib.optionalString withTmpDir '' rm -rf "$tmpdir" ''; checkPhase = '' # check syntax ${stdenv.shell} -n $out/bin/${name} # check for shellcheck recommendations ${shellcheck}/bin/shellcheck -x $out/bin/${name} ''; }; script = runCommand name { inherit bin name; } "ln -s $bin/bin/$name $out"; in script // { inherit bin bash-completion; }