Skip to content

Instantly share code, notes, and snippets.

@paulp
Created June 8, 2013 17:56
Show Gist options
  • Save paulp/5736053 to your computer and use it in GitHub Desktop.
Save paulp/5736053 to your computer and use it in GitHub Desktop.
#!/usr/bin/env bash
#
# Given a scalac command line which produces a stack trace, such as
# <this program> some-scalac crasher.scala
# Tracks down a scala git repository if it can; parses the stack trace
# for files and line numbers; and outputs -3 lines to +3 lines for
# each line in the stack trace, as the file was at the time of the commit.
MaxFrames=10
binDir="$(dirname $(readlink $(which $1)))"
scalaRepo="$(cd "$binDir" && git rev-parse --show-toplevel 2>/dev/null || echo $SCALA_SRC_HOME )"
echo >&2 "Extracted repository root: $scalaRepo"
declare inputLines compilerVersion filesBackThen
run () { echo "% $@" && "$@"; }
rungit () { ( cd "$scalaRepo" && run git --no-pager "$@"; ) }
packageLines () {
local file="$1"
local pkg="$2"
local text="$(egrep '\bpackage\b' "$1")"
( IFS=. && for segment in $pkg; do printf "$text\n" | grep -q "$segment" || return 1; done; return 0; )
}
findLine () {
class="$1"
method="$2"
file="$3"
lineno="$4"
wcLines () { rungit show $compilerVersion:$1 | wc -l | tr -d ' '; }
fileChoice="$(
for f in $(printf "%s\n" "$filesBackThen" | egrep -v ^test/ | egrep "\b${file}$"); do
[[ $(wcLines "$f") -ge "$lineno" ]] && \
packageLines "$f" "${class%.*}" && \
echo "$f"
done
)"
if [[ $fileChoice = *[[:space:]]* ]]; then
echo "Skipping stack frame $file:$lineno, can't figure out file among $fileChoice"
else
last=$(wcLines "$fileChoice")
start=$(( lineno - 3 ))
end=$(( lineno + 3 ))
[[ $end -gt $last ]] && end=$last
rungit blame --abbrev=5 -C20 -M10 --show-name --show-number --date=short -L $start,$end "$fileChoice" "$compilerVersion" || exit 1
echo ""
fi
}
finder () {
local -i frames=0
while read line; do
if [[ $line =~ ^[[:space:]]*at([^\(]*)\(([^\)]*)\) ]]; then
classAndMethod="${BASH_REMATCH[1]}"
fileAndLine="${BASH_REMATCH[2]}"
method="${classAndMethod##*.}"
class="${classAndMethod%.*}"
file="${fileAndLine%:*}"
lineno="${fileAndLine##*:}"
findLine "$class" "$method" "$file" "$lineno"
(( frames += 1 ))
[[ $frames -gt $MaxFrames ]] && exit 0;
fi
done
}
extractCompilerVersion () {
# Scala compiler version 2.11.0-20130606-140622-209ee3cbc5 -- Copyright 2002-2013, LAMP/EPFL
local compilerVersion="$("$1" -version 2>&1 | words | egrep '^[0-9]' | head -n1)"
# if it's something like "2.11.0-20130608-041104-feb660ccd7" it's still
# very long, and if it's not, it needs a "v" in front to be a git version.
# the eternal struggle continues.
if [[ ${#compilerVersion} -gt 15 ]]; then
compilerVersion="${compilerVersion##*-}"
else
compilerVersion="v${compilerVersion}"
fi
echo "$compilerVersion"
}
compilerVersion="$(extractCompilerVersion "$1")"
echo >&2 "Extracted scala compiler version: $compilerVersion"
rungit log -n1 "$compilerVersion"
filesBackThen="$(rungit ls-tree --full-tree -r "$compilerVersion" -- . | awk '{ print $NF }')"
inputLines="$("$@" 2>&1)"
printf "$inputLines" | finder
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment