#!/bin/bash
#Configuration
: ${ARCH:=amd64}
: ${DIST_RELEASE:=squeeze}
: ${CONF_DIR:=/etc/schroot/chroot.d}
: ${CHROOT_DIR:=/srv/chroot}
: ${ALTERNATIVE_EDITOR:=/usr/bin/vim.basic}
: ${CHROOT_FINAL_HOOK:=/bin/true}
# Additional Variables taken from the environmen
# DATA_DIR
# CHROOT_EXTRA_DEBIAN_PACKAGES

#Automatically generated variables
CHROOTNAME=$DIST_RELEASE-$ARCH
CHNAME=building_$CHROOTNAME
TEMP_CHROOT_CONF=$CONF_DIR/$CHNAME.conf
FINAL_CHROOT_CONF=$CHROOTNAME.conf
ROOT=`pwd`
CHDIR=$ROOT/$CHNAME
USER=`whoami`
COMP_FILENAME=$CHROOTNAME.tar.gz
COMP_FILEPATH=$ROOT/$COMP_FILENAME
TEMP_DATA_DIR=`mktemp -d`
ACTUAL_DATA_DIR=$DATA_DIR
ACTUAL_DATA_DIR=${ACTUAL_DATA_DIR:-$TEMP_DATA_DIR}
GHC_VERSION="7.6.3"
CABAL_INSTALL_VERSION="1.18.0.2"
SHA1_LIST='
cabal-install-1.18.0.2.tar.gz 2d1f7a48d17b1e02a1e67584a889b2ff4176a773
ghc-7.6.3-i386-unknown-linux.tar.bz2 f042b4171a2d4745137f2e425e6949c185f8ea14
ghc-7.6.3-x86_64-unknown-linux.tar.bz2 46ec3f3352ff57fba0dcbc8d9c20f7bcb6924b77
'

# export all variables needed in the schroot
export ARCH GHC_VERSION CABAL_INSTALL_VERSION SHA1_LIST

# Use gzip --rsyncable if available, to speed up transfers of generated files
# The environment variable GZIP is read automatically by 'gzip',
# see ENVIRONMENT in gzip(1).
gzip --rsyncable </dev/null >/dev/null 2>&1 && export GZIP="--rsyncable"

#Runnability checks
if [ $USER != 'root' ]
then
  echo "This script requires root permissions to run"
  exit
fi

if [ -f $TEMP_CHROOT_CONF ]
then
  echo "The configuration file name for the temporary chroot"
  echo "  $TEMP_CHROOT_CONF"
  echo "already exists."
  echo "Remove it or change the CHNAME value in the script."
  exit
fi

#Create configuration dir and files if they do not exist
if [ ! -d $ACTUAL_DATA_DIR ]
then
  mkdir $ACTUAL_DATA_DIR
  echo "The data directory"
  echo "  $ACTUAL_DATA_DIR"
  echo "has been created."
fi

if [ ! -f $ACTUAL_DATA_DIR/final.schroot.conf.in ]
then
  cat <<END >$ACTUAL_DATA_DIR/final.schroot.conf.in
[${CHROOTNAME}]
description=Debian ${DIST_RELEASE} ${ARCH}
groups=src
source-root-groups=root
type=file
file=${CHROOT_DIR}/${COMP_FILENAME}
END
  echo "The file"
  echo " $ACTUAL_DATA_DIR/final.schroot.conf.in"
  echo "has been created with default configurations."
fi

if [ ! -f $ACTUAL_DATA_DIR/temp.schroot.conf.in ]
then
  cat <<END >$ACTUAL_DATA_DIR/temp.schroot.conf.in
[${CHNAME}]
description=Debian ${DIST_RELEASE} ${ARCH}
directory=${CHDIR}
groups=src
users=root
type=directory
END
  echo "The file"
  echo " $ACTUAL_DATA_DIR/temp.schroot.conf.in"
  echo "has been created with default configurations."
fi

#Stop on errors
set -e

#Cleanup
rm -rf $CHDIR
mkdir $CHDIR

#Install tools for building chroots
apt-get install -y schroot debootstrap

shopt -s expand_aliases
alias in_chroot='schroot -c $CHNAME -d / '
function subst_variables {
  sed \
    -e "s/\${ARCH}/$ARCH/" \
    -e "s*\${CHDIR}*$CHDIR*" \
    -e "s/\${CHNAME}/$CHNAME/" \
    -e "s/\${CHROOTNAME}/$CHROOTNAME/" \
    -e "s*\${CHROOT_DIR}*$CHROOT_DIR*" \
    -e "s/\${COMP_FILENAME}/$COMP_FILENAME/" \
    -e "s/\${DIST_RELEASE}/$DIST_RELEASE/" $@
}

#Generate chroot configurations
cat $ACTUAL_DATA_DIR/temp.schroot.conf.in | subst_variables > $TEMP_CHROOT_CONF
cat $ACTUAL_DATA_DIR/final.schroot.conf.in | subst_variables > $FINAL_CHROOT_CONF

#Install the base system
debootstrap --arch $ARCH $DIST_RELEASE $CHDIR

APT_INSTALL="apt-get install -y --no-install-recommends"

if [ DIST_RELEASE = squeeze ]
then
  echo "deb http://backports.debian.org/debian-backports" \
       "$DIST_RELEASE-backports main contrib non-free" \
       > $CHDIR/etc/apt/sources.list.d/backports.list
fi

#Install all the packages
in_chroot -- \
  apt-get update


# Functions for downloading and checking Haskell core components.
# The functions run commands within the schroot.

# arguments : file_name expected_sha1
function verify_sha1 {
  local SUM="$( in_chroot -- sha1sum "$1" | awk '{print $1;exit}' )"
  if [ "$SUM" != "$2" ] ; then
    echo "ERROR: The SHA1 sum $SUM of $1 doesn't match $2." >&2
    return 1
  else
    echo "SHA1 of $1 verified correct."
  fi
}

# arguments: URL
function lookup_sha1 {
  grep -o "${1##*/}"'\s\+[0-9a-fA-F]*' <<<"$SHA1_LIST" | awk '{print $2;exit}'
}

# arguments : file_name URL
function download {
  local FNAME="$1"
  local URL="$2"
  in_chroot -- wget --output-document="$FNAME" "$URL"
  verify_sha1 "$FNAME" "$( lookup_sha1 "$URL" )"
}

function install_ghc {
  local GHC_ARCH=$ARCH
  local TDIR=$( schroot -c $CHNAME -d / -- mktemp -d )
  [ -n "$TDIR" ]
  if [ "$ARCH" == "amd64" ] ; then
    download "$TDIR"/ghc.tar.bz2 \
      http://www.haskell.org/ghc/dist/${GHC_VERSION}/ghc-${GHC_VERSION}-x86_64-unknown-linux.tar.bz2
  elif [ "$ARCH" == "i386" ] ; then
    download "$TDIR"/ghc.tar.bz2 \
      http://www.haskell.org/ghc/dist/${GHC_VERSION}/ghc-${GHC_VERSION}-i386-unknown-linux.tar.bz2
  else
    echo "Don't know what GHC to download for architecture $ARCH" >&2
    return 1
  fi
  schroot -c $CHNAME -d "$TDIR" -- \
    tar xjf ghc.tar.bz2
  schroot -c $CHNAME -d "$TDIR/ghc-${GHC_VERSION}" -- \
    ./configure --prefix=/usr/local
  schroot -c $CHNAME -d "$TDIR/ghc-${GHC_VERSION}" -- \
     make install
  schroot -c $CHNAME -d "/" -- \
    rm -rf "$TDIR"
}

function install_cabal {
  local TDIR=$( schroot -c $CHNAME -d / -- mktemp -d )
  [ -n "$TDIR" ]
  download "$TDIR"/cabal-install.tar.gz \
    http://www.haskell.org/cabal/release/cabal-install-${CABAL_INSTALL_VERSION}/cabal-install-${CABAL_INSTALL_VERSION}.tar.gz
  schroot -c $CHNAME -d "$TDIR" -- \
    tar xzf cabal-install.tar.gz
  schroot -c $CHNAME -d "$TDIR/cabal-install-${CABAL_INSTALL_VERSION}" -- \
    bash -c 'EXTRA_CONFIGURE_OPTS="--enable-library-profiling" ./bootstrap.sh --global'
  schroot -c $CHNAME -d "/" -- \
    rm -rf "$TDIR"
}


case $DIST_RELEASE in

  squeeze)

    # do not install libghc6-network-dev, since it's too old, and just
    # confuses the dependencies
    in_chroot -- \
      $APT_INSTALL \
        autoconf automake \
        zlib1g-dev \
        libgmp3-dev \
        libcurl4-gnutls-dev \
        libpcre3-dev \
        happy \
        hlint hscolour pandoc \
        graphviz qemu-utils \
        python-docutils \
        python-simplejson \
        python-pyparsing \
        python-pyinotify \
        python-pycurl \
        python-ipaddr \
        python-yaml \
        python-paramiko

    in_chroot -- \
      $APT_INSTALL python-setuptools python-dev build-essential

    in_chroot -- \
      easy_install \
        logilab-astng==0.24.1 \
        logilab-common==0.58.3 \
        mock==1.0.1 \
        pylint==0.26.0

    in_chroot -- \
      easy_install \
        sphinx==1.1.3 \
        pep8==1.3.3 \
        coverage==3.4 \
        bitarray==0.8.0

    install_ghc

    install_cabal

    in_chroot -- \
      cabal update

    # sinec we're using Cabal >=1.16, we can use the parallel install option
    in_chroot -- \
      cabal install --global -j --enable-library-profiling \
        attoparsec-0.11.1.0 \
        base64-bytestring-1.0.0.1 \
        blaze-builder-0.3.3.2 \
        case-insensitive-1.1.0.3 \
        Crypto-4.2.5.1 \
        curl-1.3.8 \
        happy \
        hashable-1.2.1.0 \
        hinotify-0.3.6 \
        hscolour-1.20.3 \
        hslogger-1.2.3 \
        json-0.7 \
        lifted-base-0.2.2.0 \
        lens-4.0.4 \
        MonadCatchIO-transformers-0.3.0.0 \
        network-2.4.1.2 \
        parallel-3.2.0.4 \
        parsec-3.1.3 \
        regex-pcre-0.94.4 \
        temporary-1.2.0.1 \
        vector-0.10.9.1 \
        zlib-0.5.4.1 \
        \
        hlint-1.8.57 \
        HUnit-1.2.5.2 \
        QuickCheck-2.6 \
        test-framework-0.8.0.3 \
        test-framework-hunit-0.3.0.1 \
        test-framework-quickcheck2-0.3.0.2 \
        \
        snap-server-0.9.4.0 \
        \
        cabal-file-th-0.2.3 \
        shelltestrunner

    #Install selected packages from backports
    in_chroot -- \
      $APT_INSTALL -t squeeze-backports \
        git \
        git-email \
        vim

;;

  wheezy)

    in_chroot -- \
      $APT_INSTALL \
      autoconf automake ghc ghc-haddock libghc-network-dev \
      libghc-test-framework{,-hunit,-quickcheck2}-dev \
      libghc-json-dev libghc-curl-dev libghc-hinotify-dev \
      libghc-parallel-dev libghc-utf8-string-dev \
      libghc-hslogger-dev libghc-crypto-dev \
      libghc-regex-pcre-dev libghc-attoparsec-dev \
      libghc-vector-dev libghc-temporary-dev \
      libghc-snap-server-dev libpcre3 libpcre3-dev hscolour hlint pandoc \
      libghc-zlib-dev \
      cabal-install \
      python-setuptools python-sphinx python-epydoc graphviz python-pyparsing \
      python-simplejson python-pycurl python-paramiko \
      python-bitarray python-ipaddr python-yaml qemu-utils python-coverage pep8 \
      shelltestrunner python-dev pylint openssh-client vim git git-email

    # We need version 0.9.4 of pyinotify because the packaged version, 0.9.3, is
    # incompatibile with the packaged version of python-epydoc 3.0.1.
    # Reason: a logger class in pyinotify calculates its superclasses at
    # runtime, which clashes with python-epydoc's static analysis phase.
    #
    # Problem introduced in:
    #   https://github.com/seb-m/pyinotify/commit/2c7e8f8959d2f8528e0d90847df360
    # and "fixed" in:
    #   https://github.com/seb-m/pyinotify/commit/98c5f41a6e2e90827a63ff1b878596

    in_chroot -- \
      easy_install pyinotify==0.9.4

     in_chroot -- \
       cabal update

     in_chroot -- \
       cabal install --global \
        'base64-bytestring>=1' \
        lens-3.10.2 \
        'lifted-base>=0.1.2'
;;

  testing)

    in_chroot -- \
      $APT_INSTALL \
      autoconf automake ghc ghc-haddock libghc-network-dev \
      libghc-test-framework{,-hunit,-quickcheck2}-dev \
      libghc-json-dev libghc-curl-dev libghc-hinotify-dev \
      libghc-parallel-dev libghc-utf8-string-dev \
      libghc-hslogger-dev libghc-crypto-dev \
      libghc-regex-pcre-dev libghc-attoparsec-dev \
      libghc-vector-dev libghc-temporary-dev \
      libghc-snap-server-dev libpcre3 libpcre3-dev hscolour hlint pandoc \
      libghc-zlib-dev \
      libghc-base64-bytestring-dev libghc-lens-dev libghc-lifted-base-dev \
      cabal-install \
      python-setuptools python-sphinx python-epydoc graphviz python-pyparsing \
      python-simplejson python-pycurl python-pyinotify python-paramiko \
      python-bitarray python-ipaddr python-yaml qemu-utils python-coverage pep8 \
      shelltestrunner python-dev pylint openssh-client vim git git-email
;;

  precise)
    # ghc, git-email and other dependencies are hosted in the universe
    # repository, which is not enabled by default.
    echo "Adding universe repository..."
    cat > $CHDIR/etc/apt/sources.list.d/universe.list <<EOF
deb http://archive.ubuntu.com/ubuntu precise universe
EOF
    in_chroot -- \
      apt-get update

    echo "Installing packages"
    in_chroot -- \
      $APT_INSTALL \
      autoconf automake ghc ghc-haddock libghc-network-dev \
      libghc-test-framework{,-hunit,-quickcheck2}-dev \
      libghc-json-dev libghc-curl-dev libghc-hinotify-dev \
      libghc-parallel-dev libghc-utf8-string-dev \
      libghc-hslogger-dev libghc-crypto-dev \
      libghc-regex-pcre-dev libghc-attoparsec-dev \
      libghc-vector-dev libghc-temporary-dev \
      libghc-snap-server-dev libpcre3 libpcre3-dev hscolour hlint pandoc \
      python-setuptools python-sphinx python-epydoc graphviz python-pyparsing \
      python-simplejson python-pyinotify python-pycurl python-paramiko \
      python-bitarray python-ipaddr python-yaml qemu-utils python-coverage pep8 \
      python-dev pylint openssh-client vim git git-email \
      build-essential

    echo "Installing cabal packages"
    in_chroot -- \
      $APT_INSTALL cabal-install

    in_chroot -- \
      cabal update

     in_chroot -- \
       cabal install --global \
        'base64-bytestring>=1' \
        lens-3.10.2 \
        'lifted-base>=0.1.2'

    in_chroot -- \
      cabal install --global shelltestrunner
    ;;

  *)
    in_chroot -- \
      $APT_INSTALL \
      autoconf automake ghc ghc-haddock libghc-network-dev \
      libghc-test-framework{,-hunit,-quickcheck2}-dev \
      libghc-json-dev libghc-curl-dev libghc-hinotify-dev \
      libghc-parallel-dev libghc-utf8-string-dev \
      libghc-hslogger-dev libghc-crypto-dev \
      libghc-regex-pcre-dev libghc-attoparsec-dev \
      libghc-vector-dev libghc-temporary-dev \
      libghc-snap-server-dev libpcre3 libpcre3-dev hscolour hlint pandoc \
      libghc-lifted-base-dev \
      libghc-base64-bytestring-dev \
      python-setuptools python-sphinx python-epydoc graphviz python-pyparsing \
      python-simplejson python-pyinotify python-pycurl python-paramiko \
      python-bitarray python-ipaddr python-yaml qemu-utils python-coverage pep8 \
      shelltestrunner python-dev pylint openssh-client vim git git-email \
      build-essential

;;
esac

# print what packages and versions are installed:
in_chroot -- \
  cabal list --installed --simple-output

in_chroot -- \
  $APT_INSTALL sudo fakeroot rsync locales less socat

# Configure the locale
case $DIST_RELEASE in
  precise)
    in_chroot -- \
      $APT_INSTALL language-pack-en
    ;;
  *)
    echo "en_US.UTF-8 UTF-8" >> $CHDIR/etc/locale.gen

    in_chroot -- \
      locale-gen
    ;;
esac

in_chroot -- \
  $APT_INSTALL lvm2 ssh bridge-utils iproute iputils-arping \
               ndisc6 python-openssl openssl \
               python-mock fping qemu-utils

in_chroot -- \
  easy_install psutil

in_chroot -- \
  easy_install jsonpointer \
    jsonpointer \
    jsonpatch

in_chroot -- \
  $APT_INSTALL \
  python-epydoc debhelper quilt

# extra debian packages

for package in $CHROOT_EXTRA_DEBIAN_PACKAGES
do in_chroot -- \
  $APT_INSTALL $package
done

#Set default editor
in_chroot -- \
  update-alternatives --set editor $ALTERNATIVE_EDITOR

# Final user hook

in_chroot -- $CHROOT_FINAL_HOOK

rm -f $COMP_FILEPATH
echo "Creating compressed schroot image..."
cd $CHDIR
tar czf $COMP_FILEPATH ./*
cd $ROOT

rm -rf $CHDIR
rm -f $TEMP_CHROOT_CONF
rm -rf $TEMP_DATA_DIR

echo "Chroot created. In order to run it:"
echo " * Copy the file $FINAL_CHROOT_CONF to $CONF_DIR/$FINAL_CHROOT_CONF"
echo " * Copy the file $COMP_FILEPATH to $CHROOT_DIR/$COMP_FILENAME"
echo "Then run \"schroot -c $CHROOTNAME\""
