#!/usr/bin/env bash tmp=$(git_extra_mktemp) above=0 color= # # get dates for the given # 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 # active_days() { uniq <(echo "$1") | 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() { 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