145 lines
4.3 KiB
Nix
145 lines
4.3 KiB
Nix
# 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; }
|