#
# Utilities to create a script to launch a target program with a suitable
# environment.
# At the moment, this boils down to populating $PATH with `bin` directories
# of Nix store derivations. Use this functionality when Nix is unable to
# figure out all the runtime dependencies from the packages you specify in
# `buildInputs` or `propagatedBuildInputs`.
#
{ pkgs ? import <nixpkgs> {} }:

with pkgs;
with lib;

rec {

  # Builds a PATH string out of the given list of packages.
  # This is done by concatenating the full path to the `bin` directory of
  # each package using ":" as a separator.
  makePath = ps: concatStrings (intersperse ":" (map (p: "${p}/bin") ps));

  # Bash statements to export the PATH generated by `makePath`.
  exportPath = ps:
    if ps == [] then ""
    else
    ''
      PATH=${makePath ps}:$PATH
      export PATH
    '';

  # Bash statement to `exec` a given program, passing it all the arguments
  # given on the command line.
  # Examples:
  #   execWithArgs ["cat"]              ~~~>   exec 'cat' "$@"
  #   execWithArgs ["python" "x y.py"]  ~~~>   exec 'python' 'x y.py' "$@"
  #
  execWithArgs = ps:
    let
      pgm = concatStrings (intersperse " " (map (p: "'${p}'") ps));
    in
      ''exec ${pgm} "$@" '';

  # Creates a derivation containing a Bash script with the specified
  # statements.
  # The statements will be preceded by a shebang and the setting of
  # $PATH to contain the `bin` directory of each package, if any, in
  # the `runtime-deps` list argument.
  #
  makeScript = { name ? "script", runtime-deps ? [] }: statements:
    writeScript name
    ''
      #!${bash}/bin/bash -e

      ${exportPath runtime-deps}

      ${statements}
    '';

  # Creates a derivation containing a Bash script to start the specified
  # program, passing it all the arguments given to the script.
  # Additionally, if any packages are specified in the `runtime-deps` list,
  # each package's `bin` directory will be added to the $PATH.
  #
  makePgmWrapper = { name ? "script", runtime-deps ? [], pgm }:
    makeScript { inherit name runtime-deps; } (execWithArgs pgm);

}
