#!/bin/bash
# ---------------------------------------------------------------------------
# Build LTP into a tarball that can be carried to an offline machine.
#
# Run this on a machine WITH network access.  LTP is the only one of the
# three engines that has to be compiled: KUnit and kselftest are already
# built inside RPMs Red Hat ships.
#
#   ./build-ltp.sh                          fetch and build the pinned release
#   ./build-ltp.sh --tarball ltp-full.tar.xz    build a release you already have
#
# The result is bundle/ltp-<version>-<arch>.tar.gz, which unpacks to /opt/ltp.
# ---------------------------------------------------------------------------
set -uo pipefail

KT_ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
# shellcheck source=lib/common.sh
. "$KT_ROOT/lib/common.sh"
kt_load_settings

# The release this kit was tested against.  Bump it deliberately: an LTP
# version change renames tests, and renamed tests show up in a patch
# comparison as "new" and "gone", which buries the real result.
LTP_VERSION=${LTP_VERSION:-20260529}
LTP_URL_BASE=${LTP_URL_BASE:-https://github.com/linux-test-project/ltp/releases/download}

TARBALL=""
WORK=${LTP_BUILD_DIR:-/var/tmp/ltp-build}
OUT=$KT_ROOT/bundle
JOBS=$(nproc)
SKIP_DEPS=0

usage() { sed -n '3,14p' "$0" | sed 's/^# \{0,1\}//'; cat <<'EOF'

Options:
      --tarball FILE   use this ltp-full-*.tar.xz instead of downloading
      --version VER    LTP release to fetch (default: the pinned one)
      --work DIR       scratch directory for the build
      --out DIR        where to put the finished tarball
  -j, --jobs N         parallel compile jobs
      --skip-deps      do not try to install build dependencies
  -h, --help           this text
EOF
}

while [ $# -gt 0 ]; do
    case $1 in
        --tarball) TARBALL=$2; shift 2 ;;
        --version) LTP_VERSION=$2; shift 2 ;;
        --work)    WORK=$2; shift 2 ;;
        --out)     OUT=$2; shift 2 ;;
        -j|--jobs) JOBS=$2; shift 2 ;;
        --skip-deps) SKIP_DEPS=1; shift ;;
        -h|--help) usage; exit 0 ;;
        *) kt_err "unknown option: $1"; usage; exit 2 ;;
    esac
done

kt_require_root
mkdir -p "$WORK" "$OUT" || kt_die "cannot create $WORK / $OUT"

# --- build dependencies ----------------------------------------------------
# LTP builds a much smaller set of tests when these are missing, and it does
# so silently: configure just reports "no" and carries on.
DEPS=(gcc make autoconf automake m4 pkgconf bison flex
      libcap-devel libcap-ng-devel libaio-devel libtirpc-devel numactl-devel
      keyutils-libs-devel openssl-devel libattr-devel libselinux-devel
      libmnl-devel kernel-headers)
if [ "$SKIP_DEPS" = 0 ]; then
    missing=()
    for p in "${DEPS[@]}"; do rpm -q "$p" >/dev/null 2>&1 || missing+=("$p"); done
    if [ ${#missing[@]} -gt 0 ]; then
        kt_log "installing ${#missing[@]} build dependencies: ${missing[*]}"
        dnf install -y "${missing[@]}" || kt_die "could not install build dependencies"
    else
        kt_log "all build dependencies present"
    fi
fi

# --- source ----------------------------------------------------------------
if [ -z "$TARBALL" ]; then
    TARBALL=$WORK/ltp-full-$LTP_VERSION.tar.xz
    if [ ! -s "$TARBALL" ]; then
        url=$LTP_URL_BASE/$LTP_VERSION/ltp-full-$LTP_VERSION.tar.xz
        kt_log "downloading $url"
        curl -fsSL -o "$TARBALL" "$url" || kt_die "download failed"
        if curl -fsSL -o "$TARBALL.sha256" "$url.sha256" 2>/dev/null; then
            ( cd "$(dirname "$TARBALL")" && sha256sum -c "$(basename "$TARBALL").sha256" ) \
                || kt_die "checksum mismatch on $TARBALL"
            kt_ok "checksum verified"
        else
            kt_warn "no .sha256 published for this release; cannot verify the download"
        fi
    else
        kt_log "using the tarball already in $WORK"
    fi
fi
[ -s "$TARBALL" ] || kt_die "no such tarball: $TARBALL"

SRC=$WORK/ltp-full-$LTP_VERSION
rm -rf "$SRC"
kt_log "unpacking"
tar xf "$TARBALL" -C "$WORK" || kt_die "cannot unpack $TARBALL"
[ -d "$SRC" ] || SRC=$(find "$WORK" -maxdepth 1 -type d -name 'ltp*' | head -1)
[ -d "$SRC" ] || kt_die "cannot find the unpacked source"

# --- build -----------------------------------------------------------------
DEST=$WORK/destdir
rm -rf "$DEST"
LOG=$WORK/build.log
kt_log "configuring (log: $LOG)"
# --with-realtime-testsuite is accepted but does nothing in current LTP and
# only produces a deprecation warning, so it is not passed.
( cd "$SRC" && ./configure --prefix="$LTP_DIR" \
    --with-open-posix-testsuite ) > "$LOG" 2>&1 \
    || { tail -30 "$LOG"; kt_die "configure failed"; }

# What configure decided matters: a "no" here means a whole group of tests
# will not exist in the bundle, and nobody notices until the target reports
# far fewer tests than expected.
kt_head "configure summary"
sed -n '/TESTSUITES/,/^$/p;/LIBRARIES/,/^$/p' "$LOG" | sed 's/^/  /'
# "glibc SUN-RPC: no" is normal and expected: modern glibc dropped SUN-RPC
# and libtirpc replaces it, so it is not a missing dependency.
if sed -n '/LIBRARIES/,/^$/p' "$LOG" | grep -v 'SUN-RPC' | grep -q ': no'; then
    kt_warn "some libraries were not found; the tests that need them will be missing"
    sed -n '/LIBRARIES/,/^$/p' "$LOG" | grep -v 'SUN-RPC' | grep ': no' | sed 's/^/    /'
fi

kt_log "compiling with -j$JOBS (this takes several minutes)"
( cd "$SRC" && make -j"$JOBS" all ) >> "$LOG" 2>&1 \
    || { tail -40 "$LOG"; kt_die "build failed"; }

kt_log "installing into a staging directory"
# SKIP_IDCHECK stops the install from creating users and groups on the build
# machine; install-offline.sh does that on the target instead.
( cd "$SRC" && make -j"$JOBS" DESTDIR="$DEST" SKIP_IDCHECK=1 install ) >> "$LOG" 2>&1 \
    || { tail -40 "$LOG"; kt_die "install failed"; }

STAGE=$DEST$LTP_DIR
[ -d "$STAGE/runtest" ] || kt_die "the staged tree has no runtest directory"

# Debug symbols are two thirds of the size and are of no use on the target.
before=$(du -sm "$STAGE" | cut -f1)
find "$STAGE" -type f -perm -u+x -print0 2>/dev/null \
    | xargs -0 -r -P "$JOBS" -n 200 strip --strip-unneeded 2>/dev/null
after=$(du -sm "$STAGE" | cut -f1)
kt_log "stripped debug symbols: ${before}MB -> ${after}MB"

# --- package ---------------------------------------------------------------
ARCH=$(uname -m)
OUTFILE=$OUT/ltp-$LTP_VERSION-$ARCH.tar.gz
kt_log "packing $OUTFILE"
# Packed relative to / so it unpacks straight over $LTP_DIR on the target.
( cd "$DEST" && tar czf "$OUTFILE" ".$LTP_DIR" ) || kt_die "packing failed"
( cd "$OUT" && sha256sum "$(basename "$OUTFILE")" > "$(basename "$OUTFILE").sha256" )

printf '%s\n' "$LTP_VERSION" > "$OUT/ltp-version.txt"
kt_ok "$OUTFILE  ($(du -h "$OUTFILE" | cut -f1))"
kt_log "tests built: $(find "$STAGE/testcases/bin" -maxdepth 1 -type f | wc -l)"
kt_log "scenarios  : $(find "$STAGE/runtest" -maxdepth 1 -type f | wc -l)"
