Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 18 additions & 5 deletions etc/profile.d/help50.sh
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,15 @@ function _help50() {
# Remove script's own output (if this is user's first command)
typescript=$(echo "$typescript" | sed '1{/^Script started on .*/d}')

# Cap typescript at MIN(1K lines, 1M bytes), else `read` is slow
typescript=$(echo "$typescript" | head -n 1024 | cut -b 1-1048576)
# Cap typescript, else `read` below is slow. Keep the first few lines, where the
# command line itself is echoed (found below), plus the last 1K lines, where
# errors tend to be (tracebacks, `make: *** Error`, segfaults); a long-running
# program that prints a lot and then crashes would otherwise lose its error.
typescript=$(echo "$typescript" | cut -b 1-1048576)
local total=$(echo "$typescript" | wc -l)
if [[ $total -gt 1088 ]]; then
typescript=$(echo "$typescript" | head -n 64; echo "[... $((total - 1088)) lines omitted ...]"; echo "$typescript" | tail -n 1024)
fi

# Remove ANSI characters
typescript=$(echo "$typescript" | ansi2txt)
Expand Down Expand Up @@ -108,8 +115,10 @@ function _help50() {
_helpful "$help"
elif [[ $status -ne 0 ]]; then # If helpless

# Cap what's relayed downstream (e.g., ddb50 rejects > 10,000 characters), keeping the end, where errors tend to be
_helpless "$(echo "$typescript" | tail -c 8192)"
# Pass the output (capped, e.g., since ddb50 rejects > 10,000 characters, keeping the end,
# where errors tend to be) and the command line itself, so that whatever explains the
# output can see what was run
_helpless "$(echo "$typescript" | tail -c 8192)" "$argv"
fi
else
_helped
Expand All @@ -123,7 +132,11 @@ function _rhetorical() {
_alert "That was a rhetorical question. <3"
}

# Default helpers
# Default helpers, overridable (e.g., by cs50/codespace) by defining them before this file is sourced:
# _helped last command succeeded
# _helpful ADVICE a helper had advice for the failed command
# _helpless OUTPUT CMD no helper had advice; OUTPUT is the failed command's (cleaned, capped)
# output, possibly empty, and CMD its command line
if ! type _helped >/dev/null 2>&1; then
function _helped() { :; } # Silent
fi
Expand Down
23 changes: 23 additions & 0 deletions tests/smoke.sh
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,27 @@ run "$IMAGE" bash --login -c 'valgrind python x.py < /dev/null; test $? -eq 1' 2
echo "- _fold wraps without a terminal"
run "$IMAGE" bash --login -c '. /opt/cs50/lib/cli; TERM= _fold "$(printf "a %.0s" {1..100})"' | head -n 1 | grep -qE '^.{1,80}$'

echo "- _helpless gets the end of a failed command's long output, plus its command line"
run "$IMAGE" bash --login -c '
export HELP50=$(mktemp)
_helpless() { printf "%s" "$1" > /tmp/output; printf "%s" "$2" > /tmp/cmd; }
. /etc/profile.d/help50.sh

# A command that prints 3000 lines and then fails, as script(1) records it
{ printf "$ ./slow\r\n"; seq 3000 | sed "s/$/\r/"; printf "Error: boom\r\n"; } > "$HELP50"
set -o history; history -s ./slow; set +o history
false; _help50
test "$(cat /tmp/cmd)" = ./slow &&
test "$(head -n 1 /tmp/output)" = 1 &&
grep -qx "\[... 1914 lines omitted ...\]" /tmp/output &&
! grep -qx 1000 /tmp/output &&
test "$(tail -n 1 /tmp/output)" = "Error: boom" || exit 1

# A command that fails without output
: > "$HELP50"
set -o history; history -s ./slow; set +o history
false; _help50
test "$(cat /tmp/cmd)" = ./slow && test ! -s /tmp/output || exit 1
'

echo "OK"
Loading