#!/bin/sh

# Copyright (c) 2008-2011 Aleksey Cheusov <vle@gmx.net>
# All rights reserved.
#
# See LICENSE file

############################################################

set -e
export LC_ALL=C

# usage: distbb_diff dir1 dir2
usage (){
    cat <<EOF
distbb_diff - compare results of two bulk builds

usage: distbb_diff [OPTIONS] bbdir1 bbdir2
OPTIONS:
  -h       display this help message
  -V       distbb version

bbdir1 - path to bulk build directory, e.g. ~/bulk-logs/20080915.1010
bbdir2 - path to bulk build directory

Output format:
<CMP> <PKGPATH> <PKGBASE> <Version(s)>
where CMP is a combination of the following characters
+   - package failed in bbdir1 but succeeded in bbdir2
-   - package was built sucessfully in bbdir1 but failed in bbdir2
R   - package was removed or pkg_src_summary failed for it
d   - package failed due to broken dependency
EOF
}

while getopts hV f
do
    case $f in
	h)      usage; exit 0;;
        V)      echo 'distbb-0.48.0'; exit 0;;
        '?')    usage; exit 1;;
    esac
done
shift `expr $OPTIND - 1`

if test $# -ne 2; then
    usage
    exit 1
fi

######################################################################

# init
bbdir1="$1"
bbdir2="$2"
shift
shift

######################################################################
# temp directory
. /usr/pkg/libexec/psu/sig_handler.sh
on_exit () { rm -rf $tmp_dir; }

tmp_dir=`mktemp -d /tmp/distbb_slave.XXXXXX`
test -n "$tmp_dir"

# main
######################################################################
if ! test -d "$bbdir1"; then
    exit 21
fi
if ! test -d "$bbdir2"; then
    exit 22
fi

cmp_fn=$tmp_dir/cmp.txt

pkg_cmp_summary -p \
    $bbdir1/META/pkg_src_summary.txt \
    $bbdir2/META/pkg_src_summary.txt > $cmp_fn

total1_fn=$bbdir1/META/packages_built_total.txt
total2_fn=$bbdir2/META/packages_built_total.txt

failed_dep1_fn=$bbdir1/META/packages_failed_deps.txt

failed2_fn=$bbdir2/META/packages_failed.txt
failed_notavail2_fn=$bbdir2/META/packages_failed_notavail.txt
failed_dep2_fn=$bbdir2/META/packages_failed_deps.txt
failed_scan2_fn=$bbdir2/META/packages_failed_scan.txt

res_failed_fn=$tmp_dir/failed
res_failed_deps_fn=$tmp_dir/failed_deps
res_failed_scan_fn=$tmp_dir/failed_scan
res_succeeded_fn=$tmp_dir/succeeded
res_removed_fn=$tmp_dir/removed

touch $res_failed_fn
touch $res_failed_deps_fn
touch $res_failed_scan_fn
touch $res_succeeded_fn
touch $res_removed_fn

runawk \
   -v cmp_fn="$cmp_fn" \
   -v total1_fn=$total1_fn \
   -v total2_fn=$total2_fn \
   -v failed_dep1_fn=$failed_dep1_fn \
   -v failed2_fn=$failed2_fn \
   -v failed_notavail2_fn=$failed_notavail2_fn \
   -v failed_dep2_fn=$failed_dep2_fn \
   -v failed_scan2_fn=$failed_scan2_fn \
   -v res_failed_fn=$res_failed_fn \
   -v res_failed_deps_fn=$res_failed_deps_fn \
   -v res_failed_scan_fn=$res_failed_scan_fn \
   -v res_succeeded_fn=$res_succeeded_fn \
   -v res_removed_fn=$res_removed_fn \
   -e '
#use "xgetline.awk"

function print_failed (pkg, prefix){
   if (pkg in failed_new)
      print prefix, pkg, pkg_ver [pkg]       > res_failed_fn
   else if (pkg in failed_dep_new)
      print prefix "d", pkg, pkg_ver [pkg]   > res_failed_deps_fn
   else if (pkg in failed_scan_new)
      print prefix "c", pkg                  > res_failed_scan_fn
   else{
      print prefix "?", pkg                  > res_failed_scan_fn
#      abort("pkg=`" pkg "` prefix=`" prefix "`")
   }
}

function print_succeeded (pkg, prefix){
   if (pkg in failed_dep_old){
      print prefix "d", pkg, pkg_ver [pkg]          > res_succeeded_fn
   }else{
      print prefix, pkg, pkg_ver [pkg]          > res_succeeded_fn
   }
}

BEGIN {
   SUBSEP = "\t"
   OFS    = "\t"

   while (xgetline0(cmp_fn)) {
      sub(/:.*$/, "", $2)    # multivar pkg -> normal PKGPATH
      if ($1 == "+")
         pkg_ver [$2, $3] = pkg_new [$2, $3] = $4
      else if ($1 == "-")
         pkg_del [$2, $3] = 1
      else if ($1 ~ /^[=<>]$/){
         if ($4 != $5)
            pkg_ver [$2, $3] = ($4 " -> " $5)
         else
            pkg_ver [$2, $3] = $4
      }
   }
   while (xgetline0(total1_fn)) {
      sub(/:.*$/, "", $1)
      sub(/-[^-]*$/, "", $2)
      total_old [$1, $2] = $3
   }
   while (xgetline0(total2_fn)) {
      sub(/:.*$/, "", $1)
      sub(/-[^-]*$/, "", $2)
      total_new [$1, $2] = $3
   }
   while (xgetline0(failed_dep1_fn)) {
      sub(/:.*$/, "", $1)
      sub(/-[^-]*$/, "", $2)
      failed_dep_old [$1, $2] = $3
   }
   while (xgetline0(failed2_fn)) {
      sub(/:.*$/, "", $1)
      sub(/-[^-]*$/, "", $2)
      failed_new [$1, $2] = $3
   }
   while (xgetline0(failed_notavail2_fn)) {
      sub(/:.*$/, "", $1)
      sub(/-[^-]*$/, "", $2)
      failed_new [$1, $2] = $3
   }
   while (xgetline0(failed_dep2_fn)) {
      sub(/:.*$/, "", $1)
      sub(/-[^-]*$/, "", $2)
      failed_dep_new [$1, $2] = $3
   }
   while (xgetline0(failed_scan2_fn)) {
      sub(/:.*$/, "", $1)
      failed_scan_new [$1] = $3
   }

   # print results
   for (i in total_old){
      if (i in pkg_del){
         pkgpath = i
         sub(SUBSEP ".*$", "", pkgpath)
         if (pkgpath in failed_scan_new)
            print_failed(i, "-")
         else
            print "R", i                   > res_removed_fn
      }else if (! (i in total_new)){
         print_failed(i, "-")
      }
   }
   for (i in pkg_new){
      if (! (i in total_new))
         print_failed(i, "N-")
   }
   for (i in total_new){
      if (i in pkg_new)
         print_succeeded(i, "N+")
      else if (! (i in total_old))
         print_succeeded(i, "+")
   }
}
' $ignore_fn $total1_fn $total2_fn

sort -t'	' -k2   $res_removed_fn
sort -t'	' -k2,3 $res_failed_scan_fn
sort -t'	' -k2,3 $res_failed_fn
sort -t'	' -k2,3 $res_failed_deps_fn
sort -t'	' -k2,3 $res_succeeded_fn

if test -s $res_removed_fn -o -s $res_failed_fn -o -s $res_succeeded_fn; then
    false
else
    true
fi
