Skip to content

Commit befc702

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 e8e9024 commit befc702

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
@@ -260,7 +277,27 @@ __bp_preexec_invoke_exec() {
260277
return
261278
fi
262279

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

291321
__bp_install() {

test/bash-preexec.bats

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,76 @@ set_exit_code_and_run_precmd() {
308308
[ $status -eq 1 ]
309309
}
310310

311+
@test "__bp_invoke_precmd_functions should be transparent for \$? and \$_" {
312+
tester1() { test1_lastexit=$? test1_lastarg=$_; }
313+
tester2() { test2_lastexit=$? test2_lastarg=$_; }
314+
precmd_functions=(tester1 tester2)
315+
trap - DEBUG # remove the Bats stack-trace trap so $_ doesn't get overwritten
316+
__bp_invoke_precmd_functions 111 'vxxJlwNx9VPJDA' || true
317+
318+
[ "$test1_lastexit" == 111 ]
319+
[ "$test1_lastarg" == 'vxxJlwNx9VPJDA' ]
320+
[ "$test2_lastexit" == 111 ]
321+
[ "$test2_lastarg" == 'vxxJlwNx9VPJDA' ]
322+
}
323+
324+
@test "__bp_invoke_precmd_functions returns the last non-zero exit status" {
325+
tester1() { return 91; }
326+
tester2() { return 38; }
327+
tester3() { return 0; }
328+
precmd_functions=(tester1 tester2 tester3)
329+
status=0
330+
__bp_invoke_precmd_functions 1 'lastarg' || status=$?
331+
332+
[ "$status" == 38 ]
333+
334+
precmd_functions=(tester3)
335+
status=0
336+
__bp_invoke_precmd_functions 1 'lastarg' || status=$?
337+
338+
[ "$status" == 0 ]
339+
}
340+
341+
@test "__bp_invoke_preexec_functions should be transparent for \$? and \$_" {
342+
tester1() { test1_lastexit=$? test1_lastarg=$_; }
343+
tester2() { test2_lastexit=$? test2_lastarg=$_; }
344+
preexec_functions=(tester1 tester2)
345+
trap - DEBUG # remove the Bats stack-trace trap so $_ doesn't get overwritten
346+
__bp_invoke_preexec_functions 87 'ehQrzHTHtE2E7Q' 'command' || true
347+
348+
[ "$test1_lastexit" == 87 ]
349+
[ "$test1_lastarg" == 'ehQrzHTHtE2E7Q' ]
350+
[ "$test2_lastexit" == 87 ]
351+
[ "$test2_lastarg" == 'ehQrzHTHtE2E7Q' ]
352+
}
353+
354+
@test "__bp_invoke_preexec_functions returns the last non-zero exit status" {
355+
tester1() { return 52; }
356+
tester2() { return 112; }
357+
tester3() { return 0; }
358+
preexec_functions=(tester1 tester2 tester3)
359+
status=0
360+
__bp_invoke_preexec_functions 1 'lastarg' 'command' || status=$?
361+
362+
[ "$status" == 112 ]
363+
364+
preexec_functions=(tester3)
365+
status=0
366+
__bp_invoke_preexec_functions 1 'lastarg' 'command' || status=$?
367+
368+
[ "$status" == 0 ]
369+
}
370+
371+
@test "__bp_invoke_preexec_functions should supply a current command in the first argument" {
372+
tester1() { test1_bash_command=$1; }
373+
tester2() { test2_bash_command=$1; }
374+
preexec_functions=(tester1 tester2)
375+
__bp_invoke_preexec_functions 1 'lastarg' 'UEVkErELArSwjA' || true
376+
377+
[ "$test1_bash_command" == 'UEVkErELArSwjA' ]
378+
[ "$test2_bash_command" == 'UEVkErELArSwjA' ]
379+
}
380+
311381
@test "in_prompt_command should detect if a command is part of PROMPT_COMMAND" {
312382

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

0 commit comments

Comments
 (0)