Created
June 8, 2013 17:56
-
-
Save paulp/5736053 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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