|
#!/usr/bin/env bash |
|
|
|
function log() { |
|
local content |
|
if [[ $# != 0 ]] || [[ -t 0 ]]; then |
|
content="${@}" |
|
else |
|
content="$( < /dev/stdin )" |
|
fi |
|
# direct to stdout |
|
echo "$content" >&2 |
|
} |
|
|
|
function count-lines() { |
|
local config_text=$(gawk '{ |
|
FS="="; |
|
catMatch = match($0, /^\[(.*)\]/, _ca) |
|
if (catMatch != 0) { |
|
cat = _ca[1] |
|
} |
|
valMatch = match($0, /^\s*([a-zA-Z0-9_\-]+)\s*=\s*(!?)\/(.*)\/\s*$/, _va) |
|
if (valMatch != 0) { |
|
printf("%s %s %s %s\n", cat, _va[1], _va[3], (_va[2]=="!" ? "-" : "+")); |
|
} |
|
}' "${BASH_SOURCE%/*}/count-lines.ini") |
|
|
|
declare -A unique_cats |
|
while read -r category other; do |
|
# log "cat ${category}" |
|
unique_cats[$category]=1 |
|
done <<< "$config_text" |
|
|
|
local categories=( "${!unique_cats[@]}" ) |
|
|
|
local include_patterns=() |
|
local exclude_patterns=() |
|
local numbers_only=0 |
|
local list_all=0 |
|
local verbose=0 |
|
local sub_args="" |
|
|
|
local filter_categories=() |
|
while [[ $# -gt 0 ]]; do |
|
opt="$1"; |
|
shift; #expose next argument |
|
case "$opt" in |
|
"--incl" ) include_patterns+=("($1)"); shift;; |
|
"--excl" ) exclude_patterns+=("($1)"); shift;; |
|
"--nums" ) numbers_only=1;; |
|
"--verb" ) verbose=1;; |
|
|
|
*) |
|
if [[ " ${categories[@]} " =~ " ${opt} " ]]; then |
|
filter_categories+=( "$opt" ) |
|
else |
|
log "Unknown category '$opt'" |
|
return 1 |
|
fi |
|
;; |
|
esac |
|
done |
|
|
|
if [ ${#filter_categories[@]} -eq 0 ]; then |
|
list_all=1 |
|
fi |
|
|
|
local changes |
|
if [[ -t 0 ]]; then # terminal |
|
changes=$(git diff --numstat) |
|
else # pipe |
|
changes="$( < /dev/stdin )" |
|
fi |
|
|
|
if [[ ${list_all} == 1 ]]; then |
|
for cat in "${categories[@]}"; do |
|
local args="" |
|
[[ $verbose = 1 ]] && args="$args --verb"; |
|
local nums="$(echo "$changes" | count-lines --nums "$cat" $args)" |
|
[[ $? != 0 ]] && return $?; |
|
echo "$cat: $nums" | awk '{ |
|
printf("%-8s %4d %6s %6s %6s %6s\n", $1, $2, "+"$3, "-"$4, "="$5, ":"($6>0?$6:-$6)) |
|
}' |
|
|
|
done |
|
return |
|
fi |
|
|
|
while read -r category section pattern action; do |
|
if [[ " ${filter_categories[@]} " =~ " ${category} " ]]; then |
|
# log "$category $pattern $action" |
|
[[ "$action" == "+" ]] && include_patterns+=("($pattern)"); |
|
[[ "$action" == "-" ]] && exclude_patterns+=("($pattern)"); |
|
fi |
|
done <<< "$config_text" |
|
|
|
local match_pattern="$( ( IFS=$'|'; echo "${include_patterns[*]}" ))" |
|
local unmatch_pattern="$( ( IFS=$'|'; echo "${exclude_patterns[*]}" ))" |
|
|
|
if [[ ! -z "${unmatch_pattern// }" ]]; then |
|
changes=$(echo "$changes" | awk "\$3 !~ /$unmatch_pattern/") |
|
fi |
|
|
|
if [[ ! -z "${match_pattern// }" ]]; then |
|
changes=$(echo "$changes" | awk "\$3 ~ /$match_pattern/") |
|
else |
|
changes="" |
|
fi |
|
|
|
local awk_line='{ |
|
if (length($0) != 0) files += 1; |
|
add += $1; |
|
rem += $2 |
|
}' |
|
local awk_printf_str |
|
if [[ ${numbers_only} == 1 ]]; then |
|
awk_printf_str="%d %d %d %d %d\n" |
|
else |
|
awk_printf_str="in %d files: added: %d, removed: %d, total: %d, diff: %d\n" |
|
fi |
|
local awk_end="END {\ |
|
tot = add + rem; dif = add - rem;\ |
|
printf \"$awk_printf_str\", files, add, rem, tot, dif\ |
|
}" |
|
local awk_cmd="$awk_line $awk_end" |
|
|
|
if [[ ${verbose} == 1 ]]; then |
|
echo "$changes" | awk '{print " " $0}' | log |
|
fi |
|
|
|
echo "$changes" | awk "$awk_cmd" |
|
|
|
} |
|
|
|
|
|
|
|
function main() { |
|
local cmd="$1"; |
|
shift |
|
case "$cmd" in |
|
"count" ) count-lines $@;; |
|
"list-counts" ) count-lines list;; |
|
*) echo >&2 "Unknown command: $cmd"; exit 1;; |
|
esac |
|
} |
|
|
|
main $@ |