#!/bin/bash

# Copyright (C) 2011-2014 Red Hat, Inc.
#
# This file is part of csmock.
#
# csmock is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# any later version.
#
# csmock is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with csmock.  If not, see <http://www.gnu.org/licenses/>.

SELF="$0"
ARGS="`for i in "$@"; do printf " '%s'" "$i"; done`"

set -o pipefail

export LC_ALL=C

if tty 0>&2 >/dev/null; then
    R="\033[1;31m"
    G="\033[1;32m"
    N="\033[0m"
else
    R=
    G=
    N=
fi

printf "${R}
********************************************************************************
*                                                                              *
*   ${N}cov-diffbuild is deprecated, please use '${G}csmock --diff-patches${N}' instead!${R}   *
*                                                                              *
********************************************************************************
${N}\n" >&2

test -z "$TMPDIR" && TMPDIR="/tmp"

OPTS="bcd:fhilm::ntw:"

usage(){
    cat << EOF
Usage: $(basename $SELF) [-$OPTS] MOCK_PROFILE my-package.src.rpm [COV_OPTS]

  -b  Do not use Coverity Static Analysis (default for csmock, the new cli).

  -c  Enable the Cppcheck tool (uses the version installed on the host).

  -d  A space-separated list of manually added dependences needed for build.

  -f  Overwrite the file with results if it already exists.  By default, this
      would fail.

  -h  Provide HTML output of cov-format-errors.  [Coverity only]

  -i  Keep Coverity intermediate directory for further processing.  By default,
      only build-log.txt is kept.  [Coverity only]

  -l  Enable clang analyzer.  It will use the clang-analyzer package from your
      mock chroot, or fail if the package is not installable.

  -m  Commit the results to Integrity Manager specified by the following
      format: user:passwd@host:port/stream

  -n  Do not clean mock root after the build.

  -t  Do not compress the resulting tarball.

  -wN  Adjust compiler warning level.  -w0 means default flags, -w1 appends
       -Wall and -Wextra, and -w2 enables some other useful warnings.

  MOCK_PROFILE  Only name of the mock profile, without the path and without
                the .cfg suffix.

  COV_OPTS      Options passed to cov-analyze.
EOF
    exit 1
}

die(){
    if test -n "$1"; then
        echo "$SELF: error: $1" >&2
    else
        echo "$SELF: generic error" >&2
    fi
    exit 1
}

if test "x--version" = "x$1"; then
    rpm -qf $SELF
    exit $?
fi

while getopts $OPTS opt; do
    case "$opt" in
        b|c|h|i|l|n)
            COV_MOCKBUILD_OPTS="$COV_MOCKBUILD_OPTS -$opt"
            ;;

        d|m|w)
            COV_MOCKBUILD_OPTS="$COV_MOCKBUILD_OPTS -$opt $OPTARG"
            ;;

        f)  OVERWRITE_RESULTS=yes
            ;;

        t)  TAR_ONLY=yes
            ;;

        *)
            usage
            ;;
    esac
done
shift $(($OPTIND - 1))

# the first operand is the mock profile to use
MOCK_PROFILE="$1"
MOCK_CFG="/etc/mock/$MOCK_PROFILE.cfg"
test -f "$MOCK_CFG" || usage

# the second operand is the SRPM to build/analyze
SRPM="`readlink -f "$2"`"
test -n "$SRPM" || usage
test -r "$SRPM" || die "failed to open $SRPM"
rpm -pq "$SRPM" || die "failed to open an RPM package: $SRPM"

BASE="`basename "$SRPM" .src.rpm`"
JS="$BASE.js"
HTML="$BASE.html"
RESULTS="$BASE.tar"

if test xyes = "x$TAR_ONLY"; then
    TGZ="$RESULTS"
else
    TGZ="$RESULTS.xz"
    TAR_OPTS=-J
fi

if test xyes = "x$OVERWRITE_RESULTS"; then
    rm -fv "$TGZ"
fi

test -e "$TGZ" && die "'$TGZ' already exists"

# extra options for cov-analyze
shift
shift
COV_OPTS="$*"

# create the directory for results in $TMPDIR
TMP="`mktemp -d $TMPDIR/cov-diffbuild.XXXXXX`"
RESULTS_DIR="$TMP/$BASE"
INI="$RESULTS_DIR/$BASE.ini"
mkdir -p "$RESULTS_DIR/run0" "$RESULTS_DIR/run1"
test -d "$RESULTS_DIR" || die "mktemp failed"

trap "echo --- $SELF: removing $TMP... 2>&1; rm -rf '$TMP'" EXIT

# FIXME: we should replace 2s by wait() somehow
trap "echo --- $SELF: killing children... 2>&1; kill -SIGINT 0; sleep 2" \
    SIGINT SIGTERM SIGHUP

cmd_wrap() {
    printf "\n>>> %s\t%s\n" "`date`" "$*" >&2
    "$@" < /dev/null
    last_ec=$?

    if test 128 -le "$last_ec" -a "$last_ec" -lt 192; then
        echo "<<< $SELF: child signalled to die by $(($last_ec - 128))" >&2
        exit $last_ec
    fi

    return $last_ec
}

unpack_results(){
    cmd_wrap tar xf "$RESULTS" && rm -f "$RESULTS"
}

self_version() {
    rpm -q cov-mockbuild 2>&1
}

echo
printf "[scan]
tool = cov-diffbuild
tool-version = %s
tool-args =%s
time-created = %s
title = %s - Defects in Patches\n" \
    "`self_version`" "$ARGS" "`date '+%Y-%m-%d %H:%M:%S'`" "$BASE" \
    | tee "$INI"

pushd "$TMP" >/dev/null || die

# build the package without patches
cmd_wrap cov-mockbuild $COV_MOCKBUILD_OPTS -xt $MOCK_PROFILE "$SRPM" \
    $COV_OPTS || printf "status-run0 = %d\n" "$?" >> "$INI"
unpack_results

# build the package with patches
cmd_wrap cov-mockbuild $COV_MOCKBUILD_OPTS -t $MOCK_PROFILE "$SRPM"  \
    $COV_OPTS || printf "status-run1 = %d\n" "$?" >> "$INI"
unpack_results

printf "time-finished = %s\n" "`date '+%Y-%m-%d %H:%M:%S'`" >> "$INI"

# compare both defect lists
JS_DIFF="$RESULTS_DIR/defects-in-patches.js"
cmd_wrap csdiff                                                      \
    "$RESULTS_DIR/run0/results.js"                                   \
    "$RESULTS_DIR/run1/results.js"                                   \
    | cslinker --inifile "$INI" - > "$JS_DIFF"                       \
    || touch "$RESULTS_DIR/diff.FAILED"

CSHTML_OPTS="--defect-url-template ${COV_IM_PUB_URL}/\
sourcebrowser.htm?projectId=%s#mergedDefectId=%s"

cmd_wrap csgrep --prune-events=1 "$JS_DIFF" \
    | tee "$RESULTS_DIR/defects-in-patches.err"

{ cmd_wrap sh -c "csgrep --mode=json --prune-events=1 \"$JS_DIFF\" \
    | cshtml $CSHTML_OPTS - > \"$RESULTS_DIR/defects-in-patches.html\""; } \
    2>&1 | tee --append "$LOG"

# finally write the results
popd >/dev/null || die
cmd_wrap tar $TAR_OPTS -cvf "$TGZ" -C "$TMP" "$BASE"

# return non-zero exit code in case any of run0/run1 failed
if test -f "$RESULTS_DIR/run0.FAILED" || test -f "$RESULTS_DIR/run1.FAILED"
then
    exit 1
fi
