#!/bin/bash

quote() {
  echo "$1" | sed 's/[^[:alnum:]]/\\&/g'
}

fail() {
  echo "$@" >&2
  exit 1
}

dist_arch=$1; shift
a=
if [ "$1" = "-A" ]; then a=-A; shift; fi
chroot=$dist_arch-sbuild
dist=$(echo "$dist_arch" | sed 's/^\(.*\)-\([^-]*\)$/\1/')
arch=$(echo "$dist_arch" | sed 's/^\(.*\)-\([^-]*\)$/\2/')
. /mit/debathena/bin/debian-versions.sh
tag=$(gettag $dist)
: ${DEBATHENA_APT=/mit/debathena/apt}
: ${DEBATHENA_RELEASE=production}
export DEBATHENA_APT
export DEBATHENA_RELEASE
pkgfiles="$DEBATHENA_APT/dists/$dist/openafs/binary-$arch/Packages.gz $DEBATHENA_APT/dists/${dist}-proposed/openafs/binary-$arch/Packages.gz"

if [ "$DEBATHENA_RELEASE" = "production" ]; then
    apt_release=""
else
    apt_release="$DEBATHENA_RELEASE"
fi

do_binary=no
do_upload=no
for arg; do
  case $arg in
  source)
    ;;
  binary)
    do_binary=yes
    ;;
  upload)
    do_upload=yes
    ;;
  *)
    fail "Usage: $0 DIST_ARCH [-A] source|binary|upload ..."
    ;;
  esac
done

sid=$(schroot -b -c "$chroot") || exit 1
trap 'schroot -e -c "$sid"' EXIT
sch() { schroot -r -c "$sid" -- "$@"; }           # Run in the chroot
schq() { schroot -q -r -c "$sid" -- "$@"; }       # Run in the chroot quietly
schr() { schroot -r -c "$sid" -u root -- "$@"; }  # Run in the chroot as root
schr apt-get -qq -y update || exit 3

afsv=$(schq apt-cache show --no-all-versions openafs-modules-source | \
  sed -n 's/^Version: // p')

# Get all of the packages named linux-image-*.  This list includes
# three types of packages:
#  - Actual kernel images (e.g. linux-image-2.6.24-19-generic)
#  - Metapackages (e.g. linux-image-generic) which are used to keep
#    kernel images up to date
#  - Meta-metapackages which depend on other metapackages; these
#    exist for transitional reasons or to provide more generic names
#    (e.g. linux-image-amd64 depends on linux-image-2.6-amd64 in
#    lenny)
#
# We can distinguish actual kernel images from metapackages by looking
# at the source package; actual images will have the source "linux"
# (Ubuntu) or "linux-2.6" (Debian) while both kinds of metapackages
# will have the source "linux-meta" (Ubuntu) or "linux-latest-2.6"
# (Debian).
#
# To distinguish metapackages from meta-metapackages, we need to look
# at whether the package's linux-image-* dependency is an actual
# kernel image or a metapackage.
pkgs=$(sch apt-cache search --names-only '^linux-image-' | awk '{print $1}')

# Identify the metapackages which depend directly on actual kernel
# images, as well as the header packages corresponding to those
# dependencies.
metareg='linux-meta\|linux-latest.*'
mpkgs=
headers=
for pkg in $pkgs; do
  info=$(schq apt-cache show --no-all-versions "$pkg")

  # Disregard if this is not a metapackage.
  src=$(echo "$info" | sed -ne 's/^Source: //p')
  if [ $(expr "$src" : "$metareg") = 0 ]; then
    continue
  fi

  # Disregard if this package's linux-image dependency is a metapackage.
  dep=$(echo "$info" | sed -ne 's/^Depends:.*\(linux-image-[^ ,]*\).*$/\1/p')
  depsrc=$(schq apt-cache show --no-all-versions "$dep" \
    | sed -ne 's/^Source: //p')
  if [ $(expr "$depsrc" : "$metareg") != 0 ]; then
    continue
  fi

  # Find the corresponding linux-headers package.  If there isn't one,
  # this is probably an Ubuntu linux-image-debug metapackage and we
  # can ignore it.
  hdr=$(echo "$dep" | sed -e 's/image/headers/')
  hdrinfo=$(schq apt-cache show "$hdr" 2>/dev/null)
  if [ -z "$hdrinfo" ]; then
    continue
  fi

  mpkgs="$mpkgs $pkg"
  headers="$headers $hdr"
done

# For each header package found, attempt to build and/or upload
# (according to the command-line arguments) a corresponding
# openafs-modules package if one does not already exist.
for hdr in $headers; do
  hdrv=$(schq apt-cache show --no-all-versions "$hdr" | \
    sed -n 's/^Version: // p')

  # Check if we already have one.
  module=$(echo "$hdr" | sed -e 's/^linux-headers/openafs-modules/')
  if zcat $pkgfiles | \
     dpkg-awk -f - "Package:^$module\$" "Version:^$(quote "$afsv+$hdrv")\$" | \
     grep -q .; then
    echo "*** Already exists: $dist_arch $module"
    continue
  fi

  if fgrep -qx "$dist_arch $hdr" failed.log; then
    echo "*** Prior build failure: $dist_arch $module"
    continue
  fi

  # Attempt to build the module if requested.
  if [ yes = "$do_binary" ]; then
    echo "*** Building: $dist_arch $module"
    kversion=$(echo "$hdr" | sed 's/^linux-headers-//')
    schr apt-get -y install module-assistant "$hdr"
    schr m-a -i -t -l "$kversion" get openafs
    schr m-a -i -t -l "$kversion" unpack openafs
    schr touch \
      "/usr/src/openafs-modules-${kversion}_${afsv}+${hdrv}_$arch.changes.pt"
    here=$(readlink -f .)
    schr sh -xec "
      eval \"\$(dpkg-architecture)\"
      if [ \"\$DEB_HOST_ARCH\" != amd64 ] && \
        fgrep -x CONFIG_X86_64=y '/lib/modules/$kversion/build/.config'; then
        apt-get -y install binutils-multiarch util-linux
        type linux64 >/dev/null || apt-get -y install linux32
        export KPKG_ARCH=amd64
        export ARCH=x86_64
        export PERSONALITY=linux64
        export PATH=$here/hacked-arch:\$PATH
      fi
      if ! [ -e /usr/src/modules/openafs/debian/genchanges* ]; then
        install -m a=rx,u+w $here/genchanges.sh \
          /usr/src/modules/openafs/debian/
      fi
      if [ lenny = \"$dist\" ]; then
        install -m a=rx,u+w $here/genchanges.sh \
          /usr/src/modules/openafs/debian/genchanges
      fi
      $PERSONALITY SIGNCHANGES=1 module-assistant -i -t -l '$kversion' \
        auto-build openafs" </dev/null
    if [ $? -eq 0 ]; then
      echo "*** Successful build: $dist_arch $module"
      mkdir -p "$dist_arch"
      schr sh -c "cp /usr/src/openafs-modules* $dist_arch"
    else
      echo "*** Failed build: $dist_arch $module"
      echo "$dist_arch $hdr" >> failed.log
    fi
    schr sh -c "rm -f /usr/src/openafs-modules*"
  fi

  # Upload the module if requested, if we successfully built one.
  if [ yes = "$do_upload" ]; then
    ch="$dist_arch/${module}_${afsv}+${hdrv}_$arch.changes"
    if [ -e "$ch" ]; then
      echo "*** Uploading: $dist_arch $module"
      dareprepro -C openafs include "${dist}${apt_release}" $ch
    else
      echo "*** No module: $dist_arch $module"
    fi
  fi
done

if [ dapper = "$dist" ]; then
  # Dapper's equivs-build doesn't handle --arch correctly, so we can't
  # easily synthesize architecture-specific metapackages.
  echo "*** Skipping metapackage creation on dapper"
  exit
fi

# For each upstream metapackage found, if we have an appropriate
# OpenAFS module, create and/or upload a metapackage tying the OpenAFS
# module to the current version of the upstream metapackage, if one
# does not already exist at the current version.
for image_mpkg in $mpkgs; do
  info=$(schq apt-cache show --no-all-versions "$image_mpkg")
  ver=$(echo "$info" | sed -ne 's/^Version: //p')
  afs_mpkg=$(echo "$image_mpkg" | sed -e 's/^linux-image/openafs-modules/')
  hdr_mpkg=$(echo "$image_mpkg" | sed -e 's/^linux-image/linux-headers/')

  # Check if we have dkms
  if schq apt-cache show openafs-modules-dkms > /dev/null 2>&1; then
    # epoch
    ver=1:1.0
  fi

  # Check if we already have an up-to-date OpenAFS metapackage.
  if zcat $pkgfiles \
    | dpkg-awk -f - "Package:^$(quote $afs_mpkg)\$" -- Version \
    | sed -ne 's/^Version: //p' \
    | fgrep -qx "$ver$tag"; then
    echo "*** Already up to date: $dist_arch $afs_mpkg"
    continue
  fi

  # Check if we have an OpenAFS module package, either in the apt
  # repository or in the build directory.
  case $ver in
    1:*)
      # using dkms
    ;;
    *)
      dep=$(echo "$info" | sed -ne 's/^Depends:.*\(linux-image-[^ ,]*\).*$/\1/p')
      module=$(echo "$dep" | sed -e 's/^linux-image/openafs-modules/')
      if ! zcat $pkgfiles | fgrep -qx "Package: $module"; then
        ch=$(ls "$dist_arch/$module"_*.changes 2>/dev/null)
        if [ -z "$ch" ]; then
          echo "*** No module: $dist_arch $afs_mpkg"
          continue
        fi
      fi
    ;;
  esac

  # Build the metapackage if requested.
  if [ yes = "$do_binary" ]; then
    echo "*** Creating: $dist_arch $afs_mpkg"
    mkdir -p "meta/$dist_arch"
    case $ver in
      1:*)
        # using dkms
        cat > meta/$dist_arch/$afs_mpkg.equivs <<EOF
Section: openafs
Priority: extra
Standards-Version: 3.6.2

Package: $afs_mpkg
Version: $ver$tag
Maintainer: Debathena Project <debathena@mit.edu>
Depends: openafs-modules-dkms, $image_mpkg, $hdr_mpkg
Copyright: ../common/copyright
Readme: ../common/README.in
Description: Transitional package to install dkms
 Kernel specific openafs module packages are replaced with dkms
 modules.
EOF
      ;;
      *)
        cat > meta/$dist_arch/$afs_mpkg.equivs <<EOF
Section: openafs
Priority: extra
Standards-Version: 3.6.2

Package: $afs_mpkg
Version: $ver$tag
Maintainer: Debathena Project <debathena@mit.edu>
Depends: $module, $image_mpkg (= $ver)
Copyright: ../common/copyright
Readme: ../common/README.in
Description: Metapackage to enforce OpenAFS modules for kernel
 This package prevents automatic upgrades of the $img_mpkg
 kernel until there is a corresponding openafs-modules Debathena
 package available.
EOF
      ;;
    esac
    schr apt-get -y install equivs
    (cd "meta/$dist_arch" && sch equivs-build -a "$arch" "$afs_mpkg.equivs") \
      || exit 1
  fi

  if [ yes = "$do_upload" ]; then
    deb=meta/$dist_arch/${afs_mpkg}_${ver/*:/}${tag}_${arch}.deb
    if [ -e "$deb" ]; then
      echo "*** Uploading: $dist_arch $afs_mpkg"
      dareprepro includedeb "${dist}${apt_release}" "$deb"
    else
      echo "*** No package: $dist_arch $afs_mpkg"
    fi
  fi
done
