#!/usr/bin/env bash tmp=$(git_extra_mktemp) above=0 color= # # print usage message # usage() { echo 1>&2 "usage: git effort [--above ] [...] [-- [...]]" } # # get dates for the given # dates() { eval "git log $args_to_git_log --pretty='format: %ad' --date=short \"$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 # active_days() { echo "$1" | uniq | wc -l } # # set 'color' based on the given # 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 # effort() { path=$1 local commit_dates commit_dates=`dates "$path"` [ $? -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=${#path} dot="." f_dot="$path" 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" 'path' 'commits' 'active days' echo } # # output sorted results # sort_effort() { clear echo heading < $tmp sort -rn -k 2 } declare -a paths=() while [ "${#}" -ge 1 ] ; do case "$1" in --above) shift above=$1 ;; --) shift args_to_git_log=$(printf " %q" "${@:1}") break ;; --*) usage echo 1>&2 "error: unknown argument $1" echo 1>&2 "error: if that argument was meant for git-log," echo 1>&2 "error: please put it after two dashes ( -- )." exit 1 ;; *) paths+=( "$1" ) ;; esac shift 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 # remove empty quotes that appear when there are no arguments args_to_git_log="${args_to_git_log#\ \'\'}" export args_to_git_log # [path ...] if test "${#paths}" -eq 0; then save_ifs=$IFS IFS=`echo -en "\n\b"` paths=(`git ls-files`) IFS=$save_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 paths to effort printf "%s\0" "${paths[@]}" | xargs -0 -n 1 -P 4 -I % bash $bash_params -c "effort \"%\"" | tee $tmp # if more than one path, sort and print test "$(wc -l $tmp | awk '{print $1}')" -gt 1 && sort_effort echo show_cursor_and_cleanup