Skip to content

Commit

Permalink
Re-implement shellspec-time for locale support
Browse files Browse the repository at this point in the history
  • Loading branch information
ko1nksm committed Jun 4, 2024
1 parent 45b02e0 commit 81c611e
Show file tree
Hide file tree
Showing 8 changed files with 193 additions and 72 deletions.
5 changes: 1 addition & 4 deletions helper/fixture/time_log.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1 @@

real 1.23
user 0.11
sys 12.45
real:1.23 user:0.11 sys:12.45 type:external
28 changes: 11 additions & 17 deletions lib/libexec/reporter.sh
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,16 @@ count_examples() {
# $1: prefix, $2: filename
# shellcheck disable=SC2295
read_time_log() {
eval "$1_real='' $1_user='' $1_sys=''"
[ -r "$2" ] || return 1
# shellcheck disable=SC2034
while IFS= read -r line; do
case $line in (real[\ $TAB]*|user[\ $TAB]*|sys[\ $TAB]*)
case ${line##*[ $TAB]} in (*[!0-9.,]*) continue; esac
eval "$1_${line%%[ $TAB]*}=\"\${line##*[ \$TAB]}\""
esac
done < "$2" &&:
eval "[ \"\$$1_real\" ] && [ \"\$$1_user\" ] && [ \"\$$1_sys\" ]"
eval "$1_real='' $1_user='' $1_sys='' $1_type=''"
[ -s "$2" ] || return 1
{
set -- "$1_real" "$1_user" "$1_sys" "$1_type"
IFS=" " read -r "$@" || return 1
while [ $# -gt 0 ]; do
eval "$1=\${$1#${1#*_}:}"
shift
done
} < "$2"
}

field_description() {
Expand Down Expand Up @@ -112,18 +112,12 @@ inc() {

read_profiler() {
time_real_nano=0
case $3 in
*,*) separator=',' ;;
*) separator='.' ;;
esac
shellspec_replace_all time_real_nano "$3" "$separator" '.'
shellspec_shift10 time_real_nano "$time_real_nano" 4
shellspec_shift10 time_real_nano "$3" 4

profiler_count=0
while IFS=" " read -r tick; do
duration=$(($time_real_nano * $tick / $2))
shellspec_shift10 duration "$duration" -4
shellspec_replace_all duration "$duration" '.' "$separator"
set -- "$1" "$2" "$3" "$profiler_count" "$tick" "$duration"
eval "profiler_tick$4=\$5 profiler_time$4=\$6"
"$@"
Expand Down
4 changes: 3 additions & 1 deletion lib/libexec/reporter/finished_formatter.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ create_buffers finished

finished_end() {
finished '=' "Finished in ${time_real:-?} seconds" \
"(user ${time_user:-?} seconds, sys ${time_sys:-?} seconds)${LF}"
"(user: ${time_user:-n/a}${time_user:+s}," \
"sys: ${time_sys:-n/a}${time_sys:+s})" \
"[time: $time_type]${LF}"
}

finished_output() {
Expand Down
5 changes: 1 addition & 4 deletions libexec/shellspec-executor.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,6 @@

set -eu

# Close the file descriptor for time command
exec 2>&3

# shellcheck source=lib/libexec/executor.sh
. "${SHELLSPEC_LIB:-./lib}/libexec/executor.sh"

Expand Down Expand Up @@ -115,4 +112,4 @@ set +e
read -r xs2 && [ "$xs2" -ne 0 ] && exit "$xs2"
exit 0
)
) 4>&1
) 4>&1 3>&2
2 changes: 1 addition & 1 deletion libexec/shellspec-runner.sh
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ executor() {
start_profiler
executor="$SHELLSPEC_LIBEXEC/shellspec-executor.sh"
# shellcheck disable=SC2086
$SHELLSPEC_TIME $SHELLSPEC_SHELL "$executor" "$@" 3>&2 2>"$SHELLSPEC_TIME_LOG"
$SHELLSPEC_SHELL "$SHELLSPEC_TIME" $SHELLSPEC_SHELL "$executor" "$@"
eval "stop_profiler; return $?"
}

Expand Down
203 changes: 171 additions & 32 deletions libexec/shellspec-time.sh
Original file line number Diff line number Diff line change
@@ -1,46 +1,185 @@
#!/bin/sh
#shellcheck disable=SC2004
# shellcheck disable=SC2004
# Write it to work in a Bourne shell if possible.

set -f

: "${SHELLSPEC_TRAP:=trap}"
: "${SHELLSPEC_TIME_TYPE:=auto}"
LF='
'

"$SHELLSPEC_TRAP" : INT

if [ "$BASH_VERSION" ] || [ "$KSH_VERSION" ]; then
time -p "$@"
exit $?
fi
datetime2unixtime() {
set -- "$1" "${2%%-*}" "${2%%T*}" "${2##*T}"
set -- "$1" "${2#"${2%%[!0]*}"}" "${3#*-}" "${4%%:*}" "${4#*:}"
set -- "$1" "$2" "${3%%-*}" "${3#*-}" "$4" "${5%%:*}" "${5#*:}"
set -- "$1" "${2:-0}" "${3#0}" "${4#0}" "${5#0}" "${6#0}" "${7#0}"
[ "$3" -lt 3 ] && set -- "$1" $(($2-1)) $(($3+12)) "$4" "$5" "$6" "$7"
set -- "$1" $((365*$2+$2/4-$2/100+$2/400)) "$3" "$4" "$5" "$6" "$7"
set -- "$1" "$2" $(((306*($3+1)/10)-428)) "$4" "$5" "$6" "${7%.*}" "${7#*.}"
eval "$1=$((($2+$3+$4-719163)*86400+$5*3600+$6*60+$7))${8:+.}${8}"
}

time_using_date() {
date +'start %Y-%m-%dT%H:%M:%S.%N'
"$@"
set -- $?
date +'end %Y-%m-%dT%H:%M:%S.%N'
return "$1"
}

detect_time_type() {
[ "$SHELLSPEC_TIME_TYPE" = auto ] || return 0

if ! { time true; } >/dev/null 2>&1; then
SHELLSPEC_TIME_TYPE=external-date && return 0
fi

if [ ! "${KSH_VERSION:-}" ]; then
# shellcheck disable=SC2006
KSH_VERSION=`eval 'echo ${.sh.version}'`
fi 2>/dev/null

if [ "${BASH_VERSION:-}" ]; then
SHELLSPEC_TIME_TYPE=bash-builtin && return 0
fi

if [ "${KSH_VERSION:-}" ]; then
case $KSH_VERSION in
*PD\ KSH*) SHELLSPEC_TIME_TYPE=pdksh-builtin ;;
*MIRBSD\ KSH*) SHELLSPEC_TIME_TYPE=mksh-builtin ;;
*LEGACY\ KSH*) SHELLSPEC_TIME_TYPE=lksh-builtin ;;
*) SHELLSPEC_TIME_TYPE=ksh93-builtin ;;
esac
return 0
fi

if [ "${ZSH_VERSION:-}" ]; then
SHELLSPEC_TIME_TYPE=zsh-builtin && return 0
fi

if { time -p true; } >/dev/null 2>&1; then
SHELLSPEC_TIME_TYPE=external-time
else
SHELLSPEC_TIME_TYPE=legacy-time
fi
}

detect_time_type

{
(
"$SHELLSPEC_TRAP" : INT

set -- -- "$@"

set -eu
case ${LC_ALL+x} in
?) set -- -s LC_ALL "$LC_ALL" "$@" ;;
*) set -- -u LC_ALL "$@" ;;
esac
LC_ALL=C && export LC_ALL

read -r sec_start millisec_start <<HERE
$(date +"%s %2N")
HERE
# bash or ksh93
case ${TIMEFORMAT+x} in
?) set -- -s TIMEFORMAT "$TIMEFORMAT" "$@" ;;
*) set -- -u TIMEFORMAT "$@" ;;
esac
TIMEFORMAT="real %R${LF}user %U${LF}sys %S"

case $millisec_start in (*[!0-9]*)
millisec_start=0
esac
# zsh
case ${TIMEFMT+x} in
?) set -- -s TIMEFMT "$TIMEFMT" "$@" ;;
*) set -- -u TIMEFMT "$@" ;;
esac
TIMEFMT="real %*E${LF}user %*U${LF}sys %*S"

status=0
# GNU time
case ${TIME+x} in
?) set -- -s TIME "$TIME" "$@" ;;
*) set -- -u TIME "$@" ;;
esac
TIME="real %e${LF}user %U${LF}sys %S" && export TIME

if [ $# -gt 0 ]; then
"$@" &&:
status=$?
fi
# shellcheck disable=SC2016
set -- sh -c '
# Use Bourne shell syntax as sh may be a Bourne shell
while [ $# -gt 0 ]; do
case $1 in
-s) eval "$2=\"\$3\""; export "$2"; shift 2 ;;
-u) unset "$2"; shift ;;
--) shift; break ;;
*) break ;;
esac
shift
done
exec "$@" 2>&3 3>&- >&4
' "$0" "$@"

read -r sec_end millisec_end <<HERE
$(date +"%s %2N")
HERE
case $SHELLSPEC_TIME_TYPE in
external-date)
time_using_date "$@"
;;
external-bash)
bash -c 'TIMEFORMAT=$1; shift; time "$@"' "$0" "$TIMEFORMAT" "$@"
;;
external-ksh)
ksh -c 'TIMEFORMAT=$1; shift; time "$@"' "$0" "$TIMEFORMAT" "$@"
;;
external-zsh)
zsh -c 'TIMEFMT=$1; shift; time "$@"' "$0" "$TIMEFMT" "$@"
;;
bash-builtin | ksh93-builtin | zsh-builtin | legacy-time)
time "$@"
;;
mksh-builtin | lksh-builtin | pdksh-builtin | external-time | *)
time -p "$@"
;;
esac
echo "status $?" >&2
) 2>&1 | (
"$SHELLSPEC_TRAP" '' INT

case $millisec_end in (*[!0-9]*)
millisec_end=0
esac
real='' user='' sys='' type=$SHELLSPEC_TIME_TYPE ex=''
# shellcheck disable=SC2162

sec=$(($sec_end - $sec_start))
millisec=$((1$millisec_end - 1$millisec_start))
if [ $millisec -lt 0 ]; then
millisec=$(($millisec + 100))
sec=$(($sec - 1))
fi
[ $millisec -lt 10 ] && millisec="0$millisec"
while read name time; do
# ksh88: 1m2.34s
case $time in *m*s)
type=ksh88
min=${time%m*} && time=${time#*m}
sec=${time%.*} && time=${time#*.} && time=${time%s}
time="$(($min * 60 + $sec)).$time"
esac

echo "real $sec.$millisec" >&2
case $name in
real) real=$time ;;
user) user=$time ;;
sys) sys=$time ;;
start) start=$time ;;
end) end=$time ;;
status) ex=$time ;;
esac
done

exit $status
if [ ! "$real" ]; then
datetime2unixtime start "$start"
datetime2unixtime end "$end"
real=$((${end%.*} - ${start%.*}))
case $start in
*[!0-9.]*) ;;
*)
start="${start#*.}00" end="${end#*.}00"
start="1${start%"${start#??}"}" end="3${end%"${end#??}"}"
diff=$(($end - $start))
real="$(( $real - ($diff < 200) )).${diff#[12]}"
esac
fi
if [ "${SHELLSPEC_TIME_LOG:+x}" ]; then
exec 2>"$SHELLSPEC_TIME_LOG"
fi
echo "real:${real:-0} user:$user sys:$sys type:$type" >&2
exit "${ex:-1}"
)
} 3>&2 4>&1
14 changes: 2 additions & 12 deletions shellspec
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ export SHELLSPEC_BUILTIN_READARRAY=''
export SHELLSPEC_SEEKABLE=''
export SHELLSPEC_READ_DELIM=''
export SHELLSPEC_STRING_CONCAT=''
export SHELLSPEC_TIME=''
export SHELLSPEC_LIST=''
export SHELLSPEC_COUNT_FILE=''
export SHELLSPEC_DEBUG_TRAP=''
Expand Down Expand Up @@ -130,6 +129,8 @@ export SHELLSPEC_REPORTERLIB="$SHELLSPEC_LIB/libexec/reporter"
export SHELLSPEC_LIBEXEC="$SHELLSPEC_ROOT/libexec"
export SHELLSPEC_INSPECTION="$SHELLSPEC_LIBEXEC/shellspec-inspection.sh"
export SHELLSPEC_UNREADONLY_PATH="$SHELLSPEC_LIBEXEC/shellspec-unreadonly-path.sh"
export SHELLSPEC_TIME_TYPE=auto
export SHELLSPEC_TIME="$SHELLSPEC_LIBEXEC/shellspec-time.sh"

# shellcheck source=lib/libexec/shellspec.sh
. "$SHELLSPEC_LIB/libexec/shellspec.sh"
Expand Down Expand Up @@ -410,17 +411,6 @@ fi
command_path SHELLSPEC_FIND "find" ||:
command_path SHELLSPEC_OD "od" ||:
command_path SHELLSPEC_HEXDUMP "hexdump" ||:

if command_path "time" || [ "$SHELLSPEC_BUSYBOX_W32" ]; then
SHELLSPEC_TIME="time -p"
else
SHELLSPEC_TIME="$SHELLSPEC_LIBEXEC/shellspec-time.sh"
if command_path bash; then
SHELLSPEC_TIME="bash $SHELLSPEC_TIME"
elif command_path ksh; then
SHELLSPEC_TIME="ksh $SHELLSPEC_TIME"
fi
fi
}

if ! signal 0 $$ 2>/dev/null; then
Expand Down
4 changes: 3 additions & 1 deletion spec/libexec/reporter_spec.sh
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,11 @@ Describe "libexec/reporter.sh"
Describe "read_time_log()"
Before "prefix_real=0 prefix_user=0 prefix_sys=0"
It "does not read anything if file missing"
When call read_time_log prefix "$FILE.not-exits"
When call read_time_log prefix "$FILE.not-exists"
The variable prefix_real should eq ''
The variable prefix_user should eq ''
The variable prefix_sys should eq ''
The variable prefix_type should eq ''
The status should be failure
End

Expand All @@ -40,6 +41,7 @@ Describe "libexec/reporter.sh"
The variable prefix_real should equal 1.23
The variable prefix_user should equal 0.11
The variable prefix_sys should equal 12.45
The variable prefix_type should equal external
The status should be success
End
End
Expand Down

0 comments on commit 81c611e

Please sign in to comment.