Skip to content

Commit 44a4406

Browse files
committed
Separate "__bp_invoke_pre{cmd,exec}_functions"
* Do not prefix local varnames with underscores * Make "__bp_invoke_pre{cmd,exec}_functions" return the last non-zero exit status * Test "__bp_invoke_pre{cmd,exec}_functions"
1 parent b73ed5f commit 44a4406

File tree

2 files changed

+112
-12
lines changed

2 files changed

+112
-12
lines changed

bash-preexec.sh

Lines changed: 42 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -157,21 +157,38 @@ __bp_precmd_invoke_cmd() {
157157
return
158158
fi
159159
local __bp_inside_precmd=1
160+
__bp_invoke_precmd_functions "$__bp_last_ret_value" "$__bp_last_argument_prev_command"
160161

162+
__bp_set_ret_value "$__bp_last_ret_value" "$__bp_last_argument_prev_command"
163+
}
164+
165+
# This function invokes every function defined in our function array
166+
# "precmd_function". This function receives the arguments $1 and $2 for $? and
167+
# $_, respectively, which will be set for each precmd function. This function
168+
# returns the last non-zero exit status of the hook functions. If there is no
169+
# error, this function returns 0.
170+
__bp_invoke_precmd_functions() {
171+
local lastexit=$1 lastarg=$2
161172
# Invoke every function defined in our function array.
162173
local precmd_function
174+
local precmd_function_ret_value
175+
local precmd_ret_value=0
163176
for precmd_function in "${precmd_functions[@]}"; do
164177

165178
# Only execute this function if it actually exists.
166179
# Test existence of functions with: declare -[Ff]
167180
if type -t "$precmd_function" 1>/dev/null; then
168-
__bp_set_ret_value "$__bp_last_ret_value" "$__bp_last_argument_prev_command"
181+
__bp_set_ret_value "$lastexit" "$lastarg"
169182
# Quote our function invocation to prevent issues with IFS
170183
"$precmd_function"
184+
precmd_function_ret_value=$?
185+
if [[ "$precmd_function_ret_value" != 0 ]]; then
186+
precmd_ret_value="$precmd_function_ret_value"
187+
fi
171188
fi
172189
done
173190

174-
__bp_set_ret_value "$__bp_last_ret_value"
191+
__bp_set_ret_value "$precmd_ret_value"
175192
}
176193

177194
# Sets a return value in $?. We may want to get access to the $? variable in our
@@ -258,7 +275,27 @@ __bp_preexec_invoke_exec() {
258275
return
259276
fi
260277

261-
# Invoke every function defined in our function array.
278+
__bp_invoke_preexec_functions "${__bp_last_ret_value:-}" "$__bp_last_argument_prev_command" "$this_command"
279+
local preexec_ret_value=$?
280+
281+
# Restore the last argument of the last executed command, and set the return
282+
# value of the DEBUG trap to be the return code of the last preexec function
283+
# to return an error.
284+
# If `extdebug` is enabled a non-zero return value from any preexec function
285+
# will cause the user's command not to execute.
286+
# Run `shopt -s extdebug` to enable
287+
__bp_set_ret_value "$preexec_ret_value" "$__bp_last_argument_prev_command"
288+
}
289+
290+
# This function invokes every function defined in our function array
291+
# "preexec_function". This function receives the arguments $1 and $2 for $?
292+
# and $_, respectively, which will be set for each preexec function. The third
293+
# argument $3 specifies the user command that is going to be executed
294+
# (corresponding to BASH_COMMAND in the DEBUG trap). This function returns the
295+
# last non-zero exit status from the preexec functions. If there is no error,
296+
# this function returns `0`.
297+
__bp_invoke_preexec_functions() {
298+
local lastexit=$1 lastarg=$2 this_command=$3
262299
local preexec_function
263300
local preexec_function_ret_value
264301
local preexec_ret_value=0
@@ -267,7 +304,7 @@ __bp_preexec_invoke_exec() {
267304
# Only execute each function if it actually exists.
268305
# Test existence of function with: declare -[fF]
269306
if type -t "$preexec_function" 1>/dev/null; then
270-
__bp_set_ret_value "${__bp_last_ret_value:-}"
307+
__bp_set_ret_value "$lastexit" "$lastarg"
271308
# Quote our function invocation to prevent issues with IFS
272309
"$preexec_function" "$this_command"
273310
preexec_function_ret_value="$?"
@@ -276,14 +313,7 @@ __bp_preexec_invoke_exec() {
276313
fi
277314
fi
278315
done
279-
280-
# Restore the last argument of the last executed command, and set the return
281-
# value of the DEBUG trap to be the return code of the last preexec function
282-
# to return an error.
283-
# If `extdebug` is enabled a non-zero return value from any preexec function
284-
# will cause the user's command not to execute.
285-
# Run `shopt -s extdebug` to enable
286-
__bp_set_ret_value "$preexec_ret_value" "$__bp_last_argument_prev_command"
316+
__bp_set_ret_value "$preexec_ret_value"
287317
}
288318

289319
__bp_install() {

test/bash-preexec.bats

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,76 @@ set_exit_code_and_run_precmd() {
328328
[ $status -eq 1 ]
329329
}
330330

331+
@test "__bp_invoke_precmd_functions should be transparent for \$? and \$_" {
332+
tester1() { test1_lastexit=$? test1_lastarg=$_; }
333+
tester2() { test2_lastexit=$? test2_lastarg=$_; }
334+
precmd_functions=(tester1 tester2)
335+
trap - DEBUG # remove the Bats stack-trace trap so $_ doesn't get overwritten
336+
__bp_invoke_precmd_functions 111 'vxxJlwNx9VPJDA' || true
337+
338+
[ "$test1_lastexit" == 111 ]
339+
[ "$test1_lastarg" == 'vxxJlwNx9VPJDA' ]
340+
[ "$test2_lastexit" == 111 ]
341+
[ "$test2_lastarg" == 'vxxJlwNx9VPJDA' ]
342+
}
343+
344+
@test "__bp_invoke_precmd_functions returns the last non-zero exit status" {
345+
tester1() { return 91; }
346+
tester2() { return 38; }
347+
tester3() { return 0; }
348+
precmd_functions=(tester1 tester2 tester3)
349+
status=0
350+
__bp_invoke_precmd_functions 1 'lastarg' || status=$?
351+
352+
[ "$status" == 38 ]
353+
354+
precmd_functions=(tester3)
355+
status=0
356+
__bp_invoke_precmd_functions 1 'lastarg' || status=$?
357+
358+
[ "$status" == 0 ]
359+
}
360+
361+
@test "__bp_invoke_preexec_functions should be transparent for \$? and \$_" {
362+
tester1() { test1_lastexit=$? test1_lastarg=$_; }
363+
tester2() { test2_lastexit=$? test2_lastarg=$_; }
364+
preexec_functions=(tester1 tester2)
365+
trap - DEBUG # remove the Bats stack-trace trap so $_ doesn't get overwritten
366+
__bp_invoke_preexec_functions 87 'ehQrzHTHtE2E7Q' 'command' || true
367+
368+
[ "$test1_lastexit" == 87 ]
369+
[ "$test1_lastarg" == 'ehQrzHTHtE2E7Q' ]
370+
[ "$test2_lastexit" == 87 ]
371+
[ "$test2_lastarg" == 'ehQrzHTHtE2E7Q' ]
372+
}
373+
374+
@test "__bp_invoke_preexec_functions returns the last non-zero exit status" {
375+
tester1() { return 52; }
376+
tester2() { return 112; }
377+
tester3() { return 0; }
378+
preexec_functions=(tester1 tester2 tester3)
379+
status=0
380+
__bp_invoke_preexec_functions 1 'lastarg' 'command' || status=$?
381+
382+
[ "$status" == 112 ]
383+
384+
preexec_functions=(tester3)
385+
status=0
386+
__bp_invoke_preexec_functions 1 'lastarg' 'command' || status=$?
387+
388+
[ "$status" == 0 ]
389+
}
390+
391+
@test "__bp_invoke_preexec_functions should supply a current command in the first argument" {
392+
tester1() { test1_bash_command=$1; }
393+
tester2() { test2_bash_command=$1; }
394+
preexec_functions=(tester1 tester2)
395+
__bp_invoke_preexec_functions 1 'lastarg' 'UEVkErELArSwjA' || true
396+
397+
[ "$test1_bash_command" == 'UEVkErELArSwjA' ]
398+
[ "$test2_bash_command" == 'UEVkErELArSwjA' ]
399+
}
400+
331401
@test "in_prompt_command should detect if a command is part of PROMPT_COMMAND" {
332402

333403
PROMPT_COMMAND=$'precmd_invoke_cmd\n something; echo yo\n __bp_interactive_mode'

0 commit comments

Comments
 (0)