#!/bin/bash
# cmddiff	Command Difference
# 	stores a command output in RCS file,
#	shows a diff with previous version,
#	if field # given calculates changes' speed
#	if maximal value given calculates when it will be reached
# Copyright (C) 1999 Rafał Maszkowski <rzm@icm.edu.pl>
# Licence: GNU GPL rev 3+
# 19990205 written; rcs, line.field syntax
# 19990504 check if there is any command given
#	   -h option
# 19990506 check if t1-t0 or speed ==0
# 19990512 cat first version
# 2000-05-26 more flexible fields selection [?]
# 2011-08-12 more precise -p description; limit numbers accuracy on output
# 2012-12-06 licence: GPL 2 -> 3+; script encoding: latin2 -> utf8; help corrections; [ ] std test -> [[ ]] bash test
# 2021-04-01 no path appended by default, -p left for compatibility, -P - append path; multiple  -f  options; appropriate multiple  -e  options, can be omitted by  -e ""
# 2021-04-02 local time in diff header; 04-03 %#.3g with # to not to loose the trailing zeroes; +P in while pattern

# TODO
# -r options other than 0, -1, x.y will be time span to make comparison in, in seconds
# options cache for given command
# remove spaces and such and make lower case before md5summing ( tr A-Z a-z|tr -dc 'a-z0-9' ?)
# maximal value error checking
# curve fitting to field value
# -n option for not to add next entry into RCS
# div. by 0
# rounding the results to 3 sign. digits
# initialize option
unset LANG
path=""
rev=0
nend=0
tmp=~/.cmddiff
declare -A ends

while [[ "$1" =~ -[fepPrh] ]]; do
	case "$1" in
		"-f") shift; fields="$fields $1"; shift;;
		"-e") shift; nend=$(( $nend + 1 )); ends[$nend]="$1"; shift;;
		"-p") shift; path="";;
		"-P") shift; path=`pwd`;;
		"-r") shift; rev="$1"; shift;;
		"-h") shift; cat <<EOT
cmddiff - command output tracing

example:
cmddiff -f 2 -e 137000 -p -r 1.6 'wc -l addr.resolved'
-f 2          compare the 2nd field in 1st (default) line; general form: [line.]field ,
              can be specified many times
-e 137000     calculate when the field is going to reach this value, can be specified
              many times for appropriate fields, use "" to omit specifying some end
-P            do append path of the current directory to the characteristic command string
-r 1.6        compare with revision 1.6, default: 0 == 1.1, -1 means the previous one
'wc ...'      the command
EOT
			exit;;
	esac
done

if [ "$1" = "" ]; then
	echo missing command argument, use -h option to see help
	exit 1
fi

if [ ! -d "$tmp" ]; then mkdir "$tmp"; fi

file=`echo "$path$@" | md5sum | awk '{print $1}'`
tmpf="$tmp/$file"
tmprcs="$tmp/$file,v"

if [ ! -e "$tmprcs" ]; then
	name="$@"
fi

case $rev in
	0) rev=1.1;;
	-1) if [ -e "$tmprcs" ]; then
		rev=`rlog -b "$tmprcs" | awk '/^revision / { print $2; exit }'`
	else
		rev=1.1
	fi
	;;
esac
# else given, e.g. 1.6

sh -c "$@" 2>&1 > "$tmpf"

cd "$tmp"
if [ -e "$tmprcs" ]; then
	rlog -t "$tmprcs" | tail -2 | head -1
	rcsdiff -q -r$rev -u -zLT "$tmprcs"
else
	echo First version:
	cat "$tmpf"
fi

echo "$name" | ci -d -q -f "$tmpf"
rcs -U -q "$tmprcs"

nend=0
for field in $fields; do
	toendstr=""; nend=$(( $nend + 1 )); end=${ends[$nend]}
	co -r$rev -q -M -f -u "$tmprcs"
	t0=`date -r "$tmpf" +%s`
	v0=`cat "$tmpf" | awk --assign=field="$field" 'BEGIN { n=split ( field, lnfd, "." ); if (n==1) { lnfd[2]=lnfd[1]; lnfd[1]=1 } } { i++; if (i==lnfd[1]) { print $lnfd[2]; exit} }'`
	revcurr=`co -M -f -u "$tmprcs" 2>&1 | awk '/revision/ { print $2 }'`
	t1=`date -r "$tmpf" +%s`
	v1=`cat "$tmpf" | awk --assign=field="$field" 'BEGIN { n=split ( field, lnfd, "." ); if (n==1) { lnfd[2]=lnfd[1]; lnfd[1]=1 } } { i++; if (i==lnfd[1]) { print $lnfd[2]; exit} }'`
	tdiff=`echo "$t1-$t0" | bc -l`
	if [ "$tdiff" != 0 ]; then
		speed=`echo "($v1-$v0)/($tdiff)" | bc -l`
		if [ ! -z "$end" -a "$speed" != 0 ]; then
			toend=`echo "($end-$v1)/$speed + 0.5" | bc -l | sed 's/\..*//'`
			atend=`date -d "now + $toend seconds"`
			toendstr=`echo , gets to $end on $atend`
		fi
		printf "$rev-$revcurr, field $field, change: %#.3g/s%s\n" "$speed" "$toendstr"
	fi
done
