From ad1d73aaa1537ae99334cbb412a30ef03a0bd395 Mon Sep 17 00:00:00 2001 From: John D Pell Date: Mon, 26 Jul 2021 14:26:38 -0700 Subject: [PATCH 1/7] lib/command_duration: remove temporary files --- themes/command_duration.theme.bash | 31 +++++++++++++----------------- 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/themes/command_duration.theme.bash b/themes/command_duration.theme.bash index cf91785c..c7fb6655 100644 --- a/themes/command_duration.theme.bash +++ b/themes/command_duration.theme.bash @@ -1,40 +1,34 @@ # shellcheck shell=bash -if [ -z "$BASH_IT_COMMAND_DURATION" ] || [ "$BASH_IT_COMMAND_DURATION" != true ]; then +if [[ "${BASH_IT_COMMAND_DURATION:-false}" != true ]]; then _command_duration() { echo -n } return fi -# Define tmp dir and file -COMMAND_DURATION_TMPDIR="${TMPDIR:-/tmp}" -COMMAND_DURATION_FILE="${COMMAND_DURATION_FILE:-$COMMAND_DURATION_TMPDIR/bashit_theme_execution_$BASHPID}" +COMMAND_DURATION_START_TIME= COMMAND_DURATION_ICON=${COMMAND_DURATION_ICON:-' ο€— '} COMMAND_DURATION_MIN_SECONDS=${COMMAND_DURATION_MIN_SECONDS:-'1'} -trap _command_duration_delete_temp_file EXIT HUP INT TERM - -_command_duration_delete_temp_file() { - if [[ -f "$COMMAND_DURATION_FILE" ]]; then - rm -f "$COMMAND_DURATION_FILE" - fi -} - _command_duration_pre_exec() { - date +%s.%1N > "$COMMAND_DURATION_FILE" + local command_nano_now="$(date +%1N)" + [[ "$command_nano_now" == "1N" ]] && command_nano_now=1 + COMMAND_DURATION_START_TIME="$(date "+%s").${command_nano_now}" } _command_duration() { local command_duration command_start current_time local minutes seconds deciseconds local command_start_sseconds current_time_seconds command_start_deciseconds current_time_deciseconds - current_time=$(date +%s.%1N) + local command_nano_now="$(date +%1N)" + [[ "$command_nano_now" == "1N" ]] && command_nano_now=1 + current_time="$(date "+%s").${command_nano_now}" - if [[ -f "$COMMAND_DURATION_FILE" ]]; then - command_start=$(< "$COMMAND_DURATION_FILE") - command_start_sseconds=${command_start%.*} + if [[ -n "${COMMAND_DURATION_START_TIME:-}" ]]; then + _bash_it_log_section="command_duration" _log_debug "calculating start time" + command_start_sseconds=${COMMAND_DURATION_START_TIME%.*} current_time_seconds=${current_time%.*} command_start_deciseconds=$((10#${command_start#*.})) @@ -42,6 +36,7 @@ _command_duration() { # seconds command_duration=$((current_time_seconds - command_start_sseconds)) + _bash_it_log_section="command_duration" _log_debug "duration: $command_duration (from $COMMAND_DURATION_START_TIME to $current_time)" if ((current_time_deciseconds >= command_start_deciseconds)); then deciseconds=$(((current_time_deciseconds - command_start_deciseconds))) @@ -49,12 +44,12 @@ _command_duration() { ((command_duration -= 1)) deciseconds=$((10 - ((command_start_deciseconds - current_time_deciseconds)))) fi - command rm "$COMMAND_DURATION_FILE" else command_duration=0 fi if ((command_duration > 0)); then + _bash_it_log_section="command_duration" _log_debug "calculating minutes and seconds" minutes=$((command_duration / 60)) seconds=$((command_duration % 60)) fi From 09e8c25b644315f3b3499776884d0c6f6c5cc863 Mon Sep 17 00:00:00 2001 From: John D Pell Date: Fri, 4 Mar 2022 12:39:58 -0800 Subject: [PATCH 2/7] lib/command_duration: dynamic clock hand Calculate the position (from 1 to 12) of the hour hand on the clock emoji used for the _command_duration string. Expressly handle COMMAND_DURATION_COLOR as blank when undefined. --- themes/command_duration.theme.bash | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/themes/command_duration.theme.bash b/themes/command_duration.theme.bash index c7fb6655..c0772d2d 100644 --- a/themes/command_duration.theme.bash +++ b/themes/command_duration.theme.bash @@ -9,7 +9,7 @@ fi COMMAND_DURATION_START_TIME= -COMMAND_DURATION_ICON=${COMMAND_DURATION_ICON:-' ο€— '} +COMMAND_DURATION_ICON=${COMMAND_DURATION_ICON:-' ο€— '} πŸ•˜ COMMAND_DURATION_MIN_SECONDS=${COMMAND_DURATION_MIN_SECONDS:-'1'} _command_duration_pre_exec() { @@ -18,6 +18,11 @@ _command_duration_pre_exec() { COMMAND_DURATION_START_TIME="$(date "+%s").${command_nano_now}" } +function _dynamic_clock_icon { + local -i clock_hand=$(((${1:-${SECONDS}} % 12) + 90)) + printf -v 'COMMAND_DURATION_ICON' '%b' "\xf0\x9f\x95\x$clock_hand" +} + _command_duration() { local command_duration command_start current_time local minutes seconds deciseconds @@ -54,10 +59,11 @@ _command_duration() { seconds=$((command_duration % 60)) fi + _dynamic_clock_icon if ((minutes > 0)); then - printf "%s%s%dm %ds" "$COMMAND_DURATION_ICON" "$COMMAND_DURATION_COLOR" "$minutes" "$seconds" + printf "%s%s%dm %ds" "${COMMAND_DURATION_ICON:-}" "${COMMAND_DURATION_COLOR:-}" "$minutes" "$seconds" elif ((seconds >= COMMAND_DURATION_MIN_SECONDS)); then - printf "%s%s%d.%01ds" "$COMMAND_DURATION_ICON" "$COMMAND_DURATION_COLOR" "$seconds" "$deciseconds" + printf "%s%s%d.%01ds" "${COMMAND_DURATION_ICON:-}" "${COMMAND_DURATION_COLOR:-}" "$seconds" "$deciseconds" fi } From 33505d4db1eb4b0fe31293a2b75db6f2918058fe Mon Sep 17 00:00:00 2001 From: John D Pell Date: Fri, 4 Mar 2022 12:40:26 -0800 Subject: [PATCH 3/7] lib/command_duration: Refactor using `$EPOCHREALTIME` Fallback to `$SECONDS` for older versions of _Bash_. Instead of shortcircuiting the definition, just short-circuit the function. This allows the variable to be set later, e.g. on theme change. --- themes/command_duration.theme.bash | 58 ++++++++++++------------------ 1 file changed, 22 insertions(+), 36 deletions(-) diff --git a/themes/command_duration.theme.bash b/themes/command_duration.theme.bash index c0772d2d..791c8d49 100644 --- a/themes/command_duration.theme.bash +++ b/themes/command_duration.theme.bash @@ -1,21 +1,13 @@ # shellcheck shell=bash +# +# Functions for measuring and reporting how long a command takes to run. -if [[ "${BASH_IT_COMMAND_DURATION:-false}" != true ]]; then - _command_duration() { - echo -n - } - return -fi +: "${COMMAND_DURATION_START_SECONDS:=${EPOCHREALTIME:-$SECONDS}}" +: "${COMMAND_DURATION_ICON:=πŸ•˜}" +: "${COMMAND_DURATION_MIN_SECONDS:=1}" -COMMAND_DURATION_START_TIME= - -COMMAND_DURATION_ICON=${COMMAND_DURATION_ICON:-' ο€— '} πŸ•˜ -COMMAND_DURATION_MIN_SECONDS=${COMMAND_DURATION_MIN_SECONDS:-'1'} - -_command_duration_pre_exec() { - local command_nano_now="$(date +%1N)" - [[ "$command_nano_now" == "1N" ]] && command_nano_now=1 - COMMAND_DURATION_START_TIME="$(date "+%s").${command_nano_now}" +function _command_duration_pre_exec() { + COMMAND_DURATION_START_SECONDS="${EPOCHREALTIME:-$SECONDS}" } function _dynamic_clock_icon { @@ -23,43 +15,37 @@ function _dynamic_clock_icon { printf -v 'COMMAND_DURATION_ICON' '%b' "\xf0\x9f\x95\x$clock_hand" } -_command_duration() { - local command_duration command_start current_time - local minutes seconds deciseconds - local command_start_sseconds current_time_seconds command_start_deciseconds current_time_deciseconds - local command_nano_now="$(date +%1N)" - [[ "$command_nano_now" == "1N" ]] && command_nano_now=1 - current_time="$(date "+%s").${command_nano_now}" +function _command_duration() { + [[ -n "${BASH_IT_COMMAND_DURATION:-}" ]] || return - if [[ -n "${COMMAND_DURATION_START_TIME:-}" ]]; then - _bash_it_log_section="command_duration" _log_debug "calculating start time" - command_start_sseconds=${COMMAND_DURATION_START_TIME%.*} - current_time_seconds=${current_time%.*} - - command_start_deciseconds=$((10#${command_start#*.})) - current_time_deciseconds=$((10#${current_time#*.})) + local command_duration=0 command_start="${COMMAND_DURATION_START_SECONDS:-0}" + local -i minutes=0 seconds=0 deciseconds=0 + local -i command_start_seconds="${command_start%.*}" + local -i command_start_deciseconds=$((10#${command_start##*.})) + local current_time="${EPOCHREALTIME:-$SECONDS}" + local -i current_time_seconds="${current_time%.*}" + local -i current_time_deciseconds="$((10#${current_time##*.}))" + if [[ "${command_start_seconds:-0}" -gt 0 ]]; then # seconds - command_duration=$((current_time_seconds - command_start_sseconds)) - _bash_it_log_section="command_duration" _log_debug "duration: $command_duration (from $COMMAND_DURATION_START_TIME to $current_time)" + command_duration="$((current_time_seconds - command_start_seconds))" if ((current_time_deciseconds >= command_start_deciseconds)); then - deciseconds=$(((current_time_deciseconds - command_start_deciseconds))) + deciseconds="$((current_time_deciseconds - command_start_deciseconds))" else ((command_duration -= 1)) - deciseconds=$((10 - ((command_start_deciseconds - current_time_deciseconds)))) + deciseconds="$((10 - (command_start_deciseconds - current_time_deciseconds)))" fi else command_duration=0 fi if ((command_duration > 0)); then - _bash_it_log_section="command_duration" _log_debug "calculating minutes and seconds" minutes=$((command_duration / 60)) seconds=$((command_duration % 60)) fi - _dynamic_clock_icon + _dynamic_clock_icon "${command_duration}" if ((minutes > 0)); then printf "%s%s%dm %ds" "${COMMAND_DURATION_ICON:-}" "${COMMAND_DURATION_COLOR:-}" "$minutes" "$seconds" elif ((seconds >= COMMAND_DURATION_MIN_SECONDS)); then @@ -67,4 +53,4 @@ _command_duration() { fi } -preexec_functions+=(_command_duration_pre_exec) +safe_append_preexec '_command_duration_pre_exec' From 6ca10cf84c4048656e0392dfc1c2561712ede7dc Mon Sep 17 00:00:00 2001 From: John D Pell Date: Fri, 4 Mar 2022 12:42:18 -0800 Subject: [PATCH 4/7] plugin/cmd-returned-notify: Rewrite to match/use `lib/command_duration` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use `$EPOCHREALTIME` (or `$SECONDS`) built-in variable provided by Bash instead of `date +%s`. We're only measuing the difference in seconds, so avoid both the binary invocation as well as the subshell. AlsΓΆ, Reduce environmental pollution by not exporting every variable, and unsetting when done. Change variable names to match lib/command-duration Remove `preexec_return_notification()` in favor of `lib/command-duration`'s `_command_duration_pre_exec()`. This should now use the same preexec hook and variables as the theme library `command_duration`. tests: handle nanoseconds --- .../available/cmd-returned-notify.plugin.bash | 20 +++++++------- test/plugins/cmd-returned-notify.plugin.bats | 27 ++++++++++--------- 2 files changed, 25 insertions(+), 22 deletions(-) diff --git a/plugins/available/cmd-returned-notify.plugin.bash b/plugins/available/cmd-returned-notify.plugin.bash index d9be5e4e..88c07722 100644 --- a/plugins/available/cmd-returned-notify.plugin.bash +++ b/plugins/available/cmd-returned-notify.plugin.bash @@ -2,15 +2,15 @@ cite about-plugin about-plugin 'Alert (BEL) when process ends after a threshold of seconds' -precmd_return_notification() { - export LAST_COMMAND_DURATION=$(($(date +%s) - ${LAST_COMMAND_TIME:=$(date +%s)})) - [[ ${LAST_COMMAND_DURATION} -gt ${NOTIFY_IF_COMMAND_RETURNS_AFTER:-5} ]] && echo -e "\a" - export LAST_COMMAND_TIME= +function precmd_return_notification() { + local command_start="${COMMAND_DURATION_START_SECONDS:=0}" + local current_time="${EPOCHREALTIME:-$SECONDS}" + local -i command_duration="$((${current_time%.*} - ${command_start%.*}))" + if [[ "${command_duration}" -gt "${NOTIFY_IF_COMMAND_RETURNS_AFTER:-5}" ]]; then + printf '\a' + fi + return 0 } -preexec_return_notification() { - [[ -z "${LAST_COMMAND_TIME}" ]] && LAST_COMMAND_TIME=$(date +%s) -} - -precmd_functions+=(precmd_return_notification) -preexec_functions+=(preexec_return_notification) +safe_append_prompt_command 'precmd_return_notification' +safe_append_preexec '_command_duration_pre_exec' diff --git a/test/plugins/cmd-returned-notify.plugin.bats b/test/plugins/cmd-returned-notify.plugin.bats index ca40f3b5..7399d6e1 100644 --- a/test/plugins/cmd-returned-notify.plugin.bats +++ b/test/plugins/cmd-returned-notify.plugin.bats @@ -4,12 +4,13 @@ load "${MAIN_BASH_IT_DIR?}/test/test_helper.bash" function local_setup_file() { setup_libs "preexec" #"command_duration" + load ../../themes/command_duration.theme load "${BASH_IT?}/plugins/available/cmd-returned-notify.plugin.bash" } @test "plugins cmd-returned-notify: notify after elapsed time" { export NOTIFY_IF_COMMAND_RETURNS_AFTER=0 - export LAST_COMMAND_TIME=$(date +%s) + export COMMAND_DURATION_START_SECONDS="${EPOCHREALTIME:-$SECONDS}" sleep 1 run precmd_return_notification assert_success @@ -18,7 +19,7 @@ function local_setup_file() { @test "plugins cmd-returned-notify: do not notify before elapsed time" { export NOTIFY_IF_COMMAND_RETURNS_AFTER=10 - export LAST_COMMAND_TIME=$(date +%s) + export COMMAND_DURATION_START_SECONDS="${EPOCHREALTIME:-$SECONDS}" sleep 1 run precmd_return_notification assert_success @@ -26,23 +27,25 @@ function local_setup_file() { } @test "plugins cmd-returned-notify: preexec no output" { - export LAST_COMMAND_TIME= - run preexec_return_notification + export COMMAND_DURATION_START_SECONDS= + run _command_duration_pre_exec assert_success assert_output "" } @test "plugins cmd-returned-notify: preexec no output env set" { - export LAST_COMMAND_TIME=$(date +%s) - run preexec_return_notification + skip "wut" + export COMMAND_DURATION_START_SECONDS="${EPOCHREALTIME:-$SECONDS}" + run _command_duration_pre_exec assert_failure assert_output "" } -@test "plugins cmd-returned-notify: preexec set LAST_COMMAND_TIME" { - export LAST_COMMAND_TIME= - assert_equal "${LAST_COMMAND_TIME}" "" - NOW=$(date +%s) - preexec_return_notification - assert_equal "${LAST_COMMAND_TIME}" "${NOW}" +@test "plugins cmd-returned-notify: preexec set COMMAND_DURATION_START_SECONDS" { + export COMMAND_DURATION_START_SECONDS= + assert_equal "${COMMAND_DURATION_START_SECONDS}" "" + NOW="${EPOCHREALTIME:-$SECONDS}" + _command_duration_pre_exec + # We need to make sure to account for nanoseconds... + assert_equal "${COMMAND_DURATION_START_SECONDS%.*}" "${NOW%.*}" } From 4e0e59230b77bd2f736a1bef550014c0cdc8f1e8 Mon Sep 17 00:00:00 2001 From: John D Pell Date: Fri, 4 Mar 2022 12:43:02 -0800 Subject: [PATCH 5/7] lib/command_duration: rename `theme/command_duration.theme` Rename the `theme/command_duration.theme` file as it's not really got anything to do with theming or SCM. --- bash_it.sh | 2 -- clean_files.txt | 2 +- .../command_duration.theme.bash => lib/command_duration.bash | 0 test/plugins/cmd-returned-notify.plugin.bats | 3 +-- 4 files changed, 2 insertions(+), 5 deletions(-) rename themes/command_duration.theme.bash => lib/command_duration.bash (100%) diff --git a/bash_it.sh b/bash_it.sh index 00a1bcea..ddc02b70 100755 --- a/bash_it.sh +++ b/bash_it.sh @@ -51,8 +51,6 @@ if [[ -n "${BASH_IT_THEME:-}" ]]; then source "${BASH_IT}/themes/githelpers.theme.bash" BASH_IT_LOG_PREFIX="themes: p4helpers: " source "${BASH_IT}/themes/p4helpers.theme.bash" - BASH_IT_LOG_PREFIX="themes: command_duration: " - source "${BASH_IT}/themes/command_duration.theme.bash" BASH_IT_LOG_PREFIX="themes: base: " source "${BASH_IT}/themes/base.theme.bash" diff --git a/clean_files.txt b/clean_files.txt index 36bdc08c..e52d5a9f 100644 --- a/clean_files.txt +++ b/clean_files.txt @@ -78,6 +78,7 @@ completion/available/wpscan.completion.bash # libraries lib/appearance.bash lib/colors.bash +lib/command_duration.bash lib/helpers.bash lib/history.bash lib/log.bash @@ -155,7 +156,6 @@ themes/bobby-python themes/brainy themes/brunton themes/candy -themes/command_duration.theme.bash themes/easy themes/essential themes/githelpers.theme.bash diff --git a/themes/command_duration.theme.bash b/lib/command_duration.bash similarity index 100% rename from themes/command_duration.theme.bash rename to lib/command_duration.bash diff --git a/test/plugins/cmd-returned-notify.plugin.bats b/test/plugins/cmd-returned-notify.plugin.bats index 7399d6e1..e712cbd9 100644 --- a/test/plugins/cmd-returned-notify.plugin.bats +++ b/test/plugins/cmd-returned-notify.plugin.bats @@ -3,8 +3,7 @@ load "${MAIN_BASH_IT_DIR?}/test/test_helper.bash" function local_setup_file() { - setup_libs "preexec" #"command_duration" - load ../../themes/command_duration.theme + setup_libs "command_duration" load "${BASH_IT?}/plugins/available/cmd-returned-notify.plugin.bash" } From 1c2fc2837f7448988746400a2192720dda0d2da6 Mon Sep 17 00:00:00 2001 From: John D Pell Date: Wed, 29 Dec 2021 10:07:04 -0800 Subject: [PATCH 6/7] lib/command_duration: adopt `_bash_it_library_finalize_hook` --- lib/command_duration.bash | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/command_duration.bash b/lib/command_duration.bash index 791c8d49..bc0cca8e 100644 --- a/lib/command_duration.bash +++ b/lib/command_duration.bash @@ -53,4 +53,4 @@ function _command_duration() { fi } -safe_append_preexec '_command_duration_pre_exec' +_bash_it_library_finalize_hook+=("safe_append_preexec '_command_duration_pre_exec'") From 866e5be86b4ed26f32904d2329019e590b5e31e9 Mon Sep 17 00:00:00 2001 From: John D Pell Date: Sun, 30 Jan 2022 16:03:58 -0800 Subject: [PATCH 7/7] lib/command_duration: tests & whitespace --- test/plugins/cmd-returned-notify.plugin.bats | 57 +++++++++----------- test/test_helper.bash | 2 +- 2 files changed, 25 insertions(+), 34 deletions(-) diff --git a/test/plugins/cmd-returned-notify.plugin.bats b/test/plugins/cmd-returned-notify.plugin.bats index e712cbd9..04edad95 100644 --- a/test/plugins/cmd-returned-notify.plugin.bats +++ b/test/plugins/cmd-returned-notify.plugin.bats @@ -8,43 +8,34 @@ function local_setup_file() { } @test "plugins cmd-returned-notify: notify after elapsed time" { - export NOTIFY_IF_COMMAND_RETURNS_AFTER=0 - export COMMAND_DURATION_START_SECONDS="${EPOCHREALTIME:-$SECONDS}" - sleep 1 - run precmd_return_notification - assert_success - assert_output $'\a' + export NOTIFY_IF_COMMAND_RETURNS_AFTER=0 + export COMMAND_DURATION_START_SECONDS="${EPOCHREALTIME:-$SECONDS}" + sleep 1 + run precmd_return_notification + assert_success + assert_output $'\a' } @test "plugins cmd-returned-notify: do not notify before elapsed time" { - export NOTIFY_IF_COMMAND_RETURNS_AFTER=10 - export COMMAND_DURATION_START_SECONDS="${EPOCHREALTIME:-$SECONDS}" - sleep 1 - run precmd_return_notification - assert_success - assert_output $'' + export NOTIFY_IF_COMMAND_RETURNS_AFTER=10 + export COMMAND_DURATION_START_SECONDS="${EPOCHREALTIME:-$SECONDS}" + sleep 1 + run precmd_return_notification + assert_success + assert_output $'' } -@test "plugins cmd-returned-notify: preexec no output" { - export COMMAND_DURATION_START_SECONDS= - run _command_duration_pre_exec - assert_success - assert_output "" +@test "lib command_duration: preexec no output" { + export COMMAND_DURATION_START_SECONDS= + run _command_duration_pre_exec + assert_success + assert_output "" } - -@test "plugins cmd-returned-notify: preexec no output env set" { - skip "wut" - export COMMAND_DURATION_START_SECONDS="${EPOCHREALTIME:-$SECONDS}" - run _command_duration_pre_exec - assert_failure - assert_output "" -} - -@test "plugins cmd-returned-notify: preexec set COMMAND_DURATION_START_SECONDS" { - export COMMAND_DURATION_START_SECONDS= - assert_equal "${COMMAND_DURATION_START_SECONDS}" "" - NOW="${EPOCHREALTIME:-$SECONDS}" - _command_duration_pre_exec - # We need to make sure to account for nanoseconds... - assert_equal "${COMMAND_DURATION_START_SECONDS%.*}" "${NOW%.*}" +@test "lib command_duration: preexec set COMMAND_DURATION_START_SECONDS" { + export COMMAND_DURATION_START_SECONDS= + assert_equal "${COMMAND_DURATION_START_SECONDS}" "" + NOW="${EPOCHREALTIME:-$SECONDS}" + _command_duration_pre_exec + # We need to make sure to account for nanoseconds... + assert_equal "${COMMAND_DURATION_START_SECONDS%.*}" "${NOW%.*}" } diff --git a/test/test_helper.bash b/test/test_helper.bash index 919e7559..bffb59ed 100644 --- a/test/test_helper.bash +++ b/test/test_helper.bash @@ -57,7 +57,7 @@ function common_setup_file() { function setup_libs() { local lib # Use a loop to allow convenient short-circuiting for some test files - for lib in "log" "utilities" "helpers" "search" "preexec" "colors"; do + for lib in "log" "utilities" "helpers" "search" "preexec" "colors" "command_duration"; do load "${BASH_IT?}/lib/${lib}.bash" || return # shellcheck disable=SC2015 # short-circuit if we've reached the requested library [[ "${lib}" == "${1:-}" ]] && return 0 || true