diff --git a/lib/0-utils.sh b/lib/0-utils.sh index c15af11..83ac7fd 100644 --- a/lib/0-utils.sh +++ b/lib/0-utils.sh @@ -37,11 +37,13 @@ echo_exit() { } void() { echo "$@" >/dev/null; } -echo_if_fail() { +trace_cmd_to_file() { local cmd=("$@") - local logName="${LOGNAME:-${RANDOM}}-" - local out="${TMP_DIR}/${logName}stdout" - local err="${TMP_DIR}/${logName}stderr" + test -n "${OUT}" && test -n "${ERR}" && test -n "${TRACE}" || return 1 + local out="${OUT}" + local err="${ERR}" + local trace="${TRACE}" + local fd=6 # get current trace status local set @@ -55,21 +57,36 @@ echo_if_fail() { set +x # set trace to the cmdEvalTrace and open file descriptor - local cmdEvalTrace="${TMP_DIR}/${logName}cmdEvalTrace" - exec 5>"${cmdEvalTrace}" - export BASH_XTRACEFD=5 + eval "exec ${fd}>\"${trace}\"" + export BASH_XTRACEFD=${fd} set -x "${cmd[@]}" >"${out}" 2>"${err}" local retval=$? # unset and close file descriptor + # unset BASH_XTRACEFD first set +x - exec 5>&- + unset BASH_XTRACEFD + eval "exec ${fd}>&-" # reset previous state set ${set} + return ${retval} +} + +echo_if_fail() { + local cmd=("$@") + local logName="${LOGNAME:-${RANDOM}}-" + local out="${TMP_DIR}/${logName}stdout" + local err="${TMP_DIR}/${logName}stderr" + local trace="${TMP_DIR}/${logName}trace" + + OUT="${out}" ERR="${err}" TRACE="${trace}" trace_cmd_to_file \ + "${cmd[@]}" + local retval=$? + # parse out relevant part of the trace local cmdEvalLines=() while IFS= read -r line; do @@ -77,7 +94,7 @@ echo_if_fail() { test "${line}" == 'set +x' && continue test "${line}" == '' && continue cmdEvalLines+=("${line}") - done <"${cmdEvalTrace}" + done <"${trace}" if ! test ${retval} -eq 0; then echo @@ -90,7 +107,7 @@ echo_if_fail() { echo fi if [[ -z ${LOGNAME} ]]; then - rm "${out}" "${err}" "${cmdEvalTrace}" + rm "${out}" "${err}" "${trace}" fi return ${retval} } @@ -426,11 +443,29 @@ ensure_dir() { done } +get_date() { + printf '%(%Y-%m-%d)T\n' -1 +} + get_remote_head() { local url="$1" - local remoteHEAD='' - IFS=$' \t' read -r remoteHEAD _ <<< \ - "$(git ls-remote "${url}" HEAD)" + # ${build} is magically populated from get_build_conf + local remoteCommitFile="${TMP_DIR}/${build}-remote-head.txt" + local date="$(get_date)" + # want to cache the remote head for faster retrieval + # and only get it once per day + local remoteHEAD + if [[ -f ${remoteCommitFile} ]]; then + IFS=' ' read -r prevDate prevBuild prevCommit <"${remoteCommitFile}" + fi + + if [[ "${date}:${build}" == "${prevDate}:${prevBuild}" ]]; then + remoteHEAD="${prevCommit}" + else + IFS=$' \t' read -r remoteHEAD _ <<< \ + "$(git ls-remote "${url}" HEAD)" + echo "${date} ${build} ${remoteHEAD}" >"${remoteCommitFile}" + fi echo "${remoteHEAD}" } @@ -450,3 +485,51 @@ print_padded() { echo -n ' ' done } + +benchmark_command() { + local cmd=("$@") + local out='/dev/null' + local err='/dev/null' + local trace="${TMP_DIR}/benchmark-trace.txt" + + # note this marker around the awk parsing + local traceMarker='TRACEOUTPUT ; ' + + echo_warn "tracing ${cmd[*]}" + PS4='$EPOCHREALTIME TRACEOUTPUT ; ' OUT="${out}" ERR="${err}" TRACE="${trace}" trace_cmd_to_file \ + "${cmd[@]}" || return 1 + echo_pass "done tracing ${cmd[*]}" + + awk ' + BEGIN { + # Use a regex for the marker to handle leading/trailing whitespace cleanly + marker = "TRACEOUTPUT ; " + } + + # Match lines starting with a timestamp followed by the marker + $0 ~ /^[0-9.]+[ ]+TRACEOUTPUT ; / { + # 1. Calculate duration for the PREVIOUS command now that we have a new timestamp + if (prev_time != "") { + duration = $1 - prev_time + # Output for the system sort: [duration] | [command] + printf "%012.6f | %s\n", duration, prev_cmd + } + + # 2. Start tracking the NEW command + prev_time = $1 + + # Extract everything after "TRACEOUTPUT ; " + # match() finds the position, substr() grabs the rest + match($0, /TRACEOUTPUT ; /) + prev_cmd = substr($0, RSTART + RLENGTH) + next + } + + # If the line does not match the timestamp pattern, it is a newline in a variable + { + if (prev_time != "") { + prev_cmd = prev_cmd "\n" $0 + } + } + ' "${trace}" | sort -rn | head -n 20 +} diff --git a/main.sh b/main.sh index b29c5de..1816c69 100755 --- a/main.sh +++ b/main.sh @@ -81,9 +81,9 @@ cmd="${scr_name//.sh/}" if [[ $DEBUG == 1 ]]; then set -x; fi $cmd "$@"' >"${ENTRY_SCRIPT}" chmod +x "${ENTRY_SCRIPT}" - for funcName in "${FB_FUNC_NAMES[@]}"; do - (cd "${SCRIPT_DIR}" && ln -sf "entry.sh" "${funcName}.sh") - done + for funcName in "${FB_FUNC_NAMES[@]}"; do + (cd "${SCRIPT_DIR}" && ln -sf "entry.sh" "${funcName}.sh") + done fi } gen_links || return 1