-
-
Save marslo/d89ab035abcd5fb00bbdf158d685e088 to your computer and use it in GitHub Desktop.
inherited from git-effort
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 | |
# shellcheck disable=SC2317,SC2086,SC2006,SC2181,SC2046,SC2116,SC2004,SC2207 | |
# inherited from https://github.com/tj/git-extras/blob/master/bin/git-effort | |
# reset environment variables that could interfere with normal usage | |
export GREP_OPTIONS= | |
# put all utility functions here | |
# make a temporary file | |
git_extra_mktemp() { | |
mktemp -t "$(basename "$0")".XXXXXXX | |
} | |
git_extra_default_branch() { | |
local extras_default_branch init_default_branch | |
extras_default_branch=$(git config --get git-extras.default-branch) | |
init_default_branch=$(git config --get init.defaultBranch) | |
if [ -n "$extras_default_branch" ]; then | |
echo "$extras_default_branch" | |
elif [ -n "$init_default_branch" ]; then | |
echo "$init_default_branch" | |
else | |
echo "main" | |
fi | |
} | |
# | |
# check whether current directory is inside a git repository | |
# | |
is_git_repo() { | |
git rev-parse --show-toplevel > /dev/null 2>&1 | |
result=$? | |
if test $result != 0; then | |
>&2 echo 'Not a git repo!' | |
exit $result | |
fi | |
} | |
is_git_repo | |
# | |
# check whether current directory contains any git commit | |
# | |
has_git_commit() { | |
git rev-parse --short HEAD > /dev/null 2>&1 | |
result=$? | |
if test $result != 0; then | |
>&2 echo 'Not git commit found!' | |
exit $result | |
fi | |
} | |
has_git_commit | |
tmp=$(git_extra_mktemp) | |
above=0 | |
# if the output won't be printed to tty, disable the color | |
test -t 1 && to_tty=true | |
color= | |
# | |
# print usage message | |
# | |
usage() { | |
echo 1>&2 "usage: git effort [--above <value>] [<path>...] [-- [<log options>...]]" | |
} | |
# | |
# get dates for the given <commit> | |
# | |
dates() { | |
eval "git log $args_to_git_log --pretty='format: %ad' --date=short -- \"$1\"" | |
# eval "git log $args_to_git_log --pretty=format:%ad --date=short --numstat -- \"$1\"" | |
} | |
# tput, being quiet about unknown capabilities | |
tputq() { | |
tput "$@" 2>/dev/null | |
return 0 | |
} | |
# | |
# hide cursor | |
# | |
hide_cursor() { | |
tputq civis | |
} | |
# | |
# show cursor, and remove temporary file | |
# | |
show_cursor_and_cleanup() { | |
tputq cnorm | |
tputq sgr0 | |
rm "$tmp" > /dev/null 2>&1 | |
exit 0 | |
} | |
# | |
# get active days for the given <commit> | |
# | |
active_days() { | |
echo "$1" | sort -r | uniq | wc -l | |
} | |
# | |
# set 'color' based on the given <num> | |
# | |
color_for() { | |
if [ "$to_tty" = true ]; then | |
if [ $1 -gt 150 ]; then color="$(tputq setaf 1)$(tputq bold)" | |
elif [ $1 -gt 125 ]; then color="$(tputq setaf 1)" # red | |
elif [ $1 -gt 100 ]; then color="$(tputq setaf 2)$(tputq bold)" | |
elif [ $1 -gt 75 ]; then color="$(tputq setaf 2)" # green | |
elif [ $1 -gt 50 ]; then color="$(tputq setaf 5)$(tputq bold)" | |
elif [ $1 -gt 25 ]; then color="$(tputq setaf 5)" # purplish | |
elif [ $1 -gt 10 ]; then color="$(tputq setaf 3)$(tputq bold)" | |
elif [ $1 -gt 5 ]; then color="$(tputq setaf 3)" # yellow | |
else color="$(tputq sgr0)" # default color | |
fi | |
else | |
color="" | |
fi | |
} | |
# | |
# compute the effort of the given <path ...> | |
# | |
effort() { | |
path=$1 | |
local commit_dates | |
local color reset_color commits len dot f_dot i msg active | |
reset_color="" | |
test "$to_tty" = true && reset_color="$(tputq sgr0)" | |
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 $(( $columns - $len )) ; do | |
f_dot=$f_dot$dot | |
i=$(($i+1)) | |
done | |
msg=$(printf " ${color}%s %-10d" "$f_dot" $commits) | |
# active days | |
active=`active_days "$commit_dates"` | |
color_for $(( $active - $above )) | |
msg="$msg $(printf "${color} %d${reset_color}\n" $active)" | |
echo "$msg" | |
} | |
# | |
# print heading | |
# | |
heading() { | |
echo | |
printf " %-${columns}s %-10s %s\n" 'path' 'commits' 'active days' | |
echo | |
} | |
# | |
# output sorted results | |
# | |
sort_effort() { | |
clear | |
echo " " | |
heading | |
< $tmp sort -rn -k 2 | |
} | |
# | |
# get processor count, default 8 | |
# | |
procs() { | |
if ! (nproc --all || getconf NPROCESSORS_ONLN || getconf _NPROCESSORS_ONLN || grep -c processor /proc/cpuinfo) 2>/dev/null; then | |
echo 8 | |
fi | |
} | |
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 | |
# set column width to match longest filename | |
max=0 | |
for path in "${paths[@]}"; do | |
cur=${#path} | |
if [[ $max -lt $cur ]]; then | |
max=$cur | |
fi | |
done | |
columns=$(( max + 5 )) | |
export columns | |
# hide cursor | |
hide_cursor | |
trap show_cursor_and_cleanup INT | |
# heading | |
# send paths to effort | |
nPaths=${#paths[@]} | |
nProcs=$(procs) | |
nJobs="\j" | |
for ((i=0; i<nPaths; ++i)) | |
do | |
while (( ${nJobs@P} >= nProcs )); do | |
wait -n | |
done | |
effort "${paths[i]}" & | |
done > $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 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment