tj.git-extras/bin/git-effort
2015-07-28 20:41:53 +02:00

214 lines
3.8 KiB
Bash
Executable file

#!/usr/bin/env bash
tmp=$(git_extra_mktemp)
above=0
color=
#
# get dates for the given <commit>
#
dates() {
eval "git log --pretty='format: %ad' --date=short $args_to_git_log "$1""
}
#
# hide cursor
#
hide_cursor() {
printf '\033[?25l'
}
#
# show cursor, and remove temporary file
#
show_cursor_and_cleanup() {
printf '\033[?25h'
printf '\033[m\n'
rm "$tmp" > /dev/null 2>&1
exit 0
}
#
# get active days for the given <commit>
#
active_days() {
uniq <<<$(echo "$1") | wc -l
}
#
# set 'color' based on the given <num>
#
color_for() {
test $1 -gt 10 && color='33'
test $1 -gt 25 && color='33;1'
test $1 -gt 50 && color='93'
test $1 -gt 75 && color='93;1'
test $1 -gt 100 && color='31'
test $1 -gt 125 && color='31;1'
test $1 -gt 150 && color='91'
test $1 -gt 200 && color='91;1'
}
#
# compute the effort of the given <file ...>
#
effort() {
file=$1
local commit_dates
commit_dates=`dates $file`
[ $? -gt 0 ] && exit 255
# Ensure it's not just an empty line
if [ -z "`head -c 1 <<<$(echo $commit_dates)`" ]
then
exit 0
fi
commits=`wc -l <<<"$(echo "$commit_dates")"`
color='90'
# ignore <= --above
test $commits -le $above && exit 0
# commits
color_for $(( $commits - $above ))
len=${#file}
dot="."
f_dot="$file"
i=0 ; while test $i -lt $((45-$len)) ; do
f_dot=$f_dot$dot
i=$(($i+1))
done
msg=$(printf " \033[${color}m%s %-10d" $f_dot $commits)
# active days
active=`active_days "$commit_dates"`
color_for $(( $active - $above ))
msg="$msg $(printf "\033[${color}m %d\033[0m\n" $active)"
echo "$msg"
}
#
# print heading
#
heading() {
echo
printf " %-45s %-10s %s\n" 'file' 'commits' 'active days'
echo
}
#
# output sorted results
#
sort_effort() {
clear
echo
heading
< $tmp sort -rn -k 2
}
above_index=0
has_above=false
next_is_above=false
num_files=0
for i in `seq ${#@}`
do
cur="${!i}"
if "$next_is_above" ; then
above="$cur"
next_is_above=false
continue
fi
case "$cur" in
--above)
if "$has_above" ; then
echo "error: --above can only be specified one time" 1>&2
exit 1
fi
next_is_above=true
has_above=true
above_index=$(( i - 1 ))
;;
--*)
;;
*)
num_files=$(( num_files + 1 ))
;;
esac
done
# Exit if above-value is not an int
if [ -z "${above##*[!0-9]*}" ] ; then
echo "error: argument to --above was not an integer" 1>&2
exit 1
fi
args_before_above=`printf " %q" "${@:1:$above_index}"`
num_args=$(( i - num_files ))
if $has_above ; then offset=2 ; else offset=0 ; fi
from=$(( 1 + above_index + offset ))
len=$(( num_args - $(( above_index + offset)) ))
args_after_above=`printf " %q" "${@:$from:$len}"`
args_to_git_log="${args_before_above#\ \'\'}${args_after_above#\ \'\'}"
shift $num_args
export args_to_git_log
# [file ...]
declare -a files=()
if test $# -ge 1; then
files=("$@")
else
save_ifs=$IFS
IFS=`echo -en "\n\b"`
files=(`git ls-files`)
IFS=$safe_ifs
unset save_ifs
fi
# hide cursor
hide_cursor
trap show_cursor_and_cleanup INT
# export functions so subshells can call them
export -f effort
export -f color_for
export -f active_days
export -f dates
export above
export log_args
bash_params=
# If bash exits sucessfully with --import-functions,
# then we need to pass it (FreeBSD probably)
bash --import-functions -c ":" 1>/dev/null 2>&1
if [ $? -eq 0 ] ; then
bash_params="--import-functions"
fi
heading
# send files to effort
printf "%s\0" "${files[@]}" | xargs -0 -n 1 -P 4 -I % bash $bash_params -c "effort \"%\"" | tee $tmp
# if more than one file, sort and print
test "$(wc -l $tmp | awk '{print $1}')" -gt 1 && sort_effort
echo
show_cursor_and_cleanup