Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 28 additions & 14 deletions lib/helpers.sh
Original file line number Diff line number Diff line change
Expand Up @@ -183,23 +183,37 @@ function error_and_proceed() {
};
export -f error_and_proceed;

function check_dependencies() {
if [[ "$(uname)" == 'Darwin' ]]; then
# Prefer ggrep (typically from Homebrew) if available
if command -v ggrep >/dev/null 2>&1; then
shopt -s expand_aliases;
alias grep=ggrep;
return;
fi;
# Probes the two grep behaviors tfenv depends on beyond POSIX:
# `\+` repetition in a BRE, per the 'latest' regex in lib/tfenv-version-name.sh
# `-o` reporting every match on a line, per libexec/tfenv-list-remote
function grep_is_sufficient() {
local grep_bin="${1}";
local bre_result;
local multi_match_result;

# Fall back to checking if the system grep is GNU grep
# (e.g. installed via nix or manually)
if grep --version 2>&1 | grep -q 'GNU grep'; then
return;
fi;
bre_result="$("${grep_bin}" -e '^[0-9]\+$' <<< '42' 2>/dev/null)";
[ "${bre_result}" = '42' ] || return 1;

multi_match_result="$("${grep_bin}" -o -E '[0-9]+' <<< '1 2' 2>/dev/null | tr '\n' ' ')";
[ "${multi_match_result}" = '1 2 ' ] || return 1;

return 0;
};
export -f grep_is_sufficient;

log 'error' 'GNU Grep is a requirement and your Mac does not have it. Consider "brew install grep" or "nix profile install nixpkgs#gnugrep"';
function check_dependencies() {
# ggrep, typically from Homebrew, takes precedence when it is capable
if command -v ggrep >/dev/null 2>&1 && grep_is_sufficient ggrep; then
shopt -s expand_aliases;
alias grep=ggrep;
return;
fi;

if grep_is_sufficient grep; then
return;
fi;

log 'error' 'The grep on PATH does not support `\+` in basic expressions or `-o` multi-match, both of which tfenv requires. Consider "brew install grep" or "nix profile install nixpkgs#gnugrep"';
};
export -f check_dependencies;

Expand Down
57 changes: 57 additions & 0 deletions test/test_dependencies.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#!/usr/bin/env bash

# Source common test setup
source "$(dirname "${0}")/test_common.sh";

#####################
# Begin Script Body #
#####################

declare -a errors=();

log 'info' '### Test Suite: dependencies';

log 'info' '## grep_is_sufficient: accepts the grep already on PATH';
(
grep_is_sufficient grep || exit 1;
exit 0;
) && log 'info' '## grep_is_sufficient: system grep accepted' \
|| error_and_proceed 'system grep rejected; tfenv needs only `\+` in a BRE and `-o` multi-match';

log 'info' '## grep_is_sufficient: rejects a grep whose -o returns only the first match';
(
# Satisfies the BRE probe but truncates -o output, so only the multi-match check rejects it
declare stub_dir;
stub_dir="$(mktemp -d)" || exit 1;
trap 'rm -rf "${stub_dir}"' EXIT;
cat > "${stub_dir}/grep" <<'STUB';
#!/usr/bin/env bash
if [ "${1}" = '-o' ]; then
/usr/bin/grep "${@}" | head -n 1;
else
/usr/bin/grep "${@}";
fi;
STUB
chmod +x "${stub_dir}/grep" || exit 1;
grep_is_sufficient "${stub_dir}/grep" && exit 1;
exit 0;
) && log 'info' '## grep_is_sufficient: truncating grep rejected' \
|| error_and_proceed 'grep_is_sufficient accepted a grep whose -o returns only the first match';

log 'info' '## grep_is_sufficient: rejects a grep that cannot be run';
(
grep_is_sufficient /nonexistent/grep && exit 1;
exit 0;
) && log 'info' '## grep_is_sufficient: missing binary rejected' \
|| error_and_proceed 'grep_is_sufficient accepted a grep binary that does not exist';

log 'info' '## check_dependencies: succeeds with a capable grep on PATH';
(
check_dependencies || exit 1;
exit 0;
) && log 'info' '## check_dependencies: passed' \
|| error_and_proceed 'check_dependencies failed despite a capable grep being on PATH';

finish_tests 'dependencies';

exit 0;