Skip to content

Commit

Permalink
Invoke external programs using full paths (#13)
Browse files Browse the repository at this point in the history
Fixes #12

Add nix tests
  • Loading branch information
tesujimath authored Nov 25, 2024
1 parent ae95409 commit 8d6872c
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 32 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/test-suite.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,4 @@ jobs:
uses: cachix/install-nix-action@v30
- name: Run tests
run: |
nix develop '.#ci' --command ./tests.bats
nix develop '.#ci' --command bats tests.bats nix-tests.bats
55 changes: 32 additions & 23 deletions bash-env-json
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,20 @@
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

VERSION="0.9.1"
VERSION="0.9.2a"
USAGE="bash-env-json [--help] [--shellfns <comma-separated-function-names>] [path]"

shopt -s extglob

# external dependencies are ideally invoked via full paths,
# so make it straightforward for the Nix flake to substitute for these
function _env() { env "$@"; }
function _jq() { jq "$@"; }
function _mktemp() { mktemp "$@"; }
function _rm() { rm "$@"; }
function _sed() { sed "$@"; }
function _touch() { touch "$@"; }

function capture() {
local -n _capture_env="$1"
local -n _capture_shellvars="$2"
Expand All @@ -37,12 +46,12 @@ function capture() {
# environment variables
while IFS='=' read -r -d '' _name _value; do
_capture_env["$_name"]="${_value}"
done < <(env -0)
done < <(_env -0)

# shellvars
for _name in $(
set -o posix
set | sed -n -e '/^[a-zA-Z_][a-zA-Z_0-9]*=/s/=.*$//p'
set | _sed -n -e '/^[a-zA-Z_][a-zA-Z_0-9]*=/s/=.*$//p'
set +o posix
); do
if test -v "$_name" -a ! "${_capture_env[$_name]+EXISTS}" -a ! "${_inhibit_shellvars[$_name]+EXISTS}"; then
Expand All @@ -52,9 +61,9 @@ function capture() {
}

function emit_value() {
# jq -R produces nothing on empty input, but we want ""
# `jq -R` produces nothing on empty input, but we want ""
if test -n "$1"; then
echo -n "$1" | jq -R
echo -n "$1" | _jq -R
else
echo -n '""'
fi
Expand Down Expand Up @@ -82,17 +91,17 @@ function emit_error() {
}

function emit_error_exit() {
emit_error "$@" | jq
emit_error "$@" | _jq
exit 1
}

function emit_help_exit() {
emit_meta '{' '}' usage | jq
emit_meta '{' '}' usage | _jq
exit 0
}

function emit_version_exit() {
emit_meta '{' '}' | jq
emit_meta '{' '}' | _jq
exit 0
}

Expand Down Expand Up @@ -136,11 +145,11 @@ function eval_or_source() {
local _source _path _error_file
_path="$1"

_error_file=$(mktemp -u)
touch "$_error_file"
_error_file=$(_mktemp -u)
_touch "$_error_file"
# shellcheck disable=SC2094
exec 3<"$_error_file" 4>"$_error_file"
rm -f "$_error_file"
_rm -f "$_error_file"

if test -n "$_path"; then
# source from file if specified
Expand All @@ -161,19 +170,19 @@ function eval_or_source() {
if ! eval "$_source" >/dev/null 2>&4; then
exec 4>&-
# discard error location, because it is this file not the one sourced
emit_error_exit "$(sed -e 's/^.*line\s*[0-9]*:\s*//' <&3)"
emit_error_exit "$(_sed -e 's/^.*line\s*[0-9]*:\s*//' <&3)"
fi
fi
}

function invoke_safely() {
local _fn="$1"

_error_file=$(mktemp -u)
touch "$_error_file"
_error_file=$(_mktemp -u)
_touch "$_error_file"
# shellcheck disable=SC2094
exec 3<"$_error_file" 4>"$_error_file"
rm -f "$_error_file"
_rm -f "$_error_file"

"$_fn" >/dev/null 2>&4 || {
exec 4>&-
Expand Down Expand Up @@ -233,14 +242,14 @@ function main() {
capture _env_current _shellvars_current

# accumulate result in a file until we know we are error-free
_result_file=$(mktemp -u)
touch "$_result_file"
_result_file=$(_mktemp -u)
_touch "$_result_file"
# shellcheck disable=SC2094
exec 5<"$_result_file" 6>"$_result_file"
rm -f "$_result_file"
_rm -f "$_result_file"

emit "{" env _env_previous _env_current >&6
emit "," shellvars _shellvars_previous _shellvars_current >&6
emit "{" "env" _env_previous _env_current >&6
emit "," "shellvars" _shellvars_previous _shellvars_current >&6

test "${#_shellfn_names[@]}" -gt 0 && {
echo ",\"fn\":{" >&6
Expand All @@ -253,8 +262,8 @@ function main() {
capture _env_current _shellvars_current

echo "$_fn_comma\"$_fn\":" >&6
emit "{" env _env_previous _env_current >&6
emit "," shellvars _shellvars_previous _shellvars_current >&6
emit "{" "env" _env_previous _env_current >&6
emit "," "shellvars" _shellvars_previous _shellvars_current >&6
echo "}" >&6
_fn_comma=","
done
Expand All @@ -266,7 +275,7 @@ function main() {
emit_meta ',' '}' >&6
exec 6>&-

jq <&5
_jq <&5
}

function bad_usage() {
Expand Down
26 changes: 18 additions & 8 deletions flake.nix
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
description = "Nix package for bash-env";
description = "Nix package for bash-env-json";

inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
Expand All @@ -17,18 +17,28 @@
let
inherit (pkgs) bash coreutils gnused jq makeWrapper writeShellScriptBin;
inherit (pkgs.lib) makeBinPath;

substFullPaths = program_package:
let replaceList = pkgs.lib.attrsets.mapAttrsToList (name: pkg: { from = " ${name} "; to = " ${pkg}/bin/${name} "; }) program_package; in
builtins.replaceStrings (map (x: x.from) replaceList) (map (x: x.to) replaceList);

in
(writeShellScriptBin "bash-env-json" (builtins.readFile ./bash-env-json)).overrideAttrs (old: {
buildInputs = [ bash jq makeWrapper ];
(writeShellScriptBin "bash-env-json"
(substFullPaths
{
env = pkgs.coreutils;
jq = pkgs.jq;
mktemp = pkgs.coreutils;
rm = pkgs.coreutils;
sed = pkgs.gnused;
touch = pkgs.coreutils;
}
(builtins.readFile ./bash-env-json))).overrideAttrs (old: {
buildInputs = [ bash ];
buildCommand =
''
${old.buildCommand}
patchShebangs $out
wrapProgram $out/bin/bash-env-json --prefix PATH : ${makeBinPath [
coreutils
gnused
jq
]}
'';
});
in
Expand Down
15 changes: 15 additions & 0 deletions nix-tests.bats
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#!/usr/bin/env bats
#
# simple tests for the Nix packaging

@test "simple" {
actual=$(echo 'export SOME_VARIABLE=some_value' | bash-env-json | jq -r '.env.SOME_VARIABLE')
expected='some_value'
test "$actual" == "$expected"
}

@test "path" {
actual=$(echo 'export PATH=/oops' | bash-env-json | jq -r '.env.PATH')
expected='/oops'
test "$actual" == "$expected"
}

0 comments on commit 8d6872c

Please sign in to comment.