#!/bin/bash -eux
#
# Copyright (C) 2021 Roberto Mier Escandón <rmescandon@gmail.com>
#
# This script creates a .deb package file with yq valid for ubuntu 20.04 by default
# You can pass 

DOCKER_IMAGE_NAME=yq-deb-builder
DOCKER_IMAGE_TAG=$(git describe --always --tags)
OUTPUT=
GOVERSION="1.17.4"
KEYID=
MAINTAINER=
DO_PUBLISH=
PPA="rmescandon/yq"
VERSION=
DISTRIBUTION=
DO_SIGN=
PASSPHRASE=

show_help() {
  echo "  usage: $(basename "$0") VERSION [options...]"
  echo ""
  echo "  positional arguments"
  echo "    VERSION"
  echo ""
  echo "  optional arguments:"
  echo "    -h, --help		              Shows this help"
  echo "    -d, --distribution DISTRO   The distribution to use for the changelog generation. If not provided, last changelog entry"
  echo "                                  distribution is considered"
  echo "    --goversion VERSION         The version of golang to use. Default to $GOVERSION"
  echo "    -k, --sign-key KEYID        Sign the package sources with the provided gpg key id (long format). When not provided this"
  echo "                                  paramater, the generated sources are not signed"
  echo "    -s, --sign                  Sign the package sources with a gpg key of the maintainer"
  echo "    -m, --maintainer WHO        The maintainer used as author of the changelog. git.name and git.email (see git config) is"
  echo "                                  the considered format"
  echo "    -o DIR, --output DIR        The path where leaving the generated debian package. Default to a temporary folder if not set"
  echo "    -p                          The resultant file is being published to ppa"
  echo "    --ppa PPA                   Push resultant files to indicated ppa. This option should be given along with a signing key."
  echo "                                  Otherwise, the server could reject the package building. Default is set to 'rmescandon/yq'"
  echo "    --passphrase PASSPHRASE     Passphrase to decrypt the signage key"
  exit 1
}
# read input args
while [ $# -ne 0 ]; do
  case $1 in
    -h|--help)
      show_help
      ;;
    -d|--distribution)
      shift
      DISTRIBUTION="$1"
      ;;
    --goversion)
      shift
      GOVERSION="$1"
      ;;
    -k|--sign-key)
      shift
      DO_SIGN='y'
      KEYID="$1"
      ;;
    -s|--sign)
      DO_SIGN='y'
      ;;
    -m|--maintainer)
      shift
      MAINTAINER="$1"
      ;;
    -o|--output)
      shift
      OUTPUT="$1"
      ;;
    -p)
      DO_PUBLISH="y"
      ;;
    --ppa)
      shift
      DO_PUBLISH="y"
      PPA="$1"
      ;;
    --passphrase)
      shift
      PASSPHRASE="$1"
      ;;
    *)
      if [ -z "$VERSION" ]; then
        VERSION="$1"
      else
        show_help
      fi
  esac
  shift
done

[ -n "$VERSION" ] || (echo "error - you have to provide a version" && show_help)

if [ -n "$OUTPUT" ]; then
  OUTPUT="$(realpath "$OUTPUT")"
  mkdir -p "$OUTPUT"
else
  # Temporary folder where leaving the built deb package in case that output folder is not provided
  OUTPUT="$(mktemp -d)"
fi 

# Define the folders with the source project and the build artifacts and files
srcdir="$(realpath "$(dirname "$0")"/..)"
blddir="$(cd "${srcdir}" && mkdir -p build && cd build && echo "$(pwd)")"
# clean on exit
cleanup() {
  rm -f "${blddir}/build.sh" || true
  rm -f "${blddir}/Dockerfile" || true
  rm -f "${blddir}/dput.cf" || true
  docker rmi "${DOCKER_IMAGE_NAME}:${DOCKER_IMAGE_TAG}" -f > /dev/null 2>&1 || true
}
trap cleanup EXIT INT

# configure the dput config in case publishing is requested
lp_id="$(echo "$PPA" | cut -d'/' -f1)"
ppa_id="$(echo "$PPA" | cut -d'/' -f2)"
cat << EOF > ${blddir}/dput.cf
[ppa]
fqdn                    = ppa.launchpad.net
method                  = ftp
incoming                = ~${lp_id}/ubuntu/${ppa_id}
login                   = anonymous
EOF

# create the main script
cat << EOF > ${blddir}/build.sh
#!/bin/bash 
set -e -o pipefail

PATH=$PATH:/usr/local/go/bin
export GPG_TTY=$(tty)

go mod vendor

### bump debian/changelog

# maintainer
export DEBEMAIL="$MAINTAINER"
if [ -z "$MAINTAINER" ]; then
  export DEBEMAIL="\$(dpkg-parsechangelog -S Maintainer)"
fi

# prepend a 'v' char to complete the tag name from where calculating the changelog
SINCE="v\$(dpkg-parsechangelog -S Version)"

# distribution
DISTRIBUTION="$DISTRIBUTION"
if [ -z "$DISTRIBUTION" ]; then
  DISTRIBUTION="\$(dpkg-parsechangelog -S Distribution)"
fi

# generate changelog
gbp dch --ignore-branch --no-multimaint -N "$VERSION" -s "\$SINCE" -D "\$DISTRIBUTION"

# using -d to prevent failing when searching for golang dep on control file
params=("-d" "-S")

# add the -sa option for signing along with the key to use when provided key id
if [ -n "$DO_SIGN" ]; then
  params+=("-sa")

  # read from gpg the key id associated with the maintainer if not provided explicitly
  if [ -z "$KEYID" ]; then
    KEYID="\$(gpg --list-keys "\$(dpkg-parsechangelog -S Maintainer)" | head -2 | tail -1 | xargs)"
  else
    KEYID="$KEYID"
  fi
  
  params+=("--sign-key="\$KEYID"")

  if [ -n "$PASSPHRASE" ]; then
    gpg-agent --verbose --daemon --options /home/yq/.gnupg/gpg-agent.conf --log-file /tmp/gpg-agent.log --allow-preset-passphrase --default-cache-ttl=31536000
    KEYGRIP="\$(gpg --with-keygrip -k "\$KEYID" | grep 'Keygrip = ' | cut -d'=' -f2 | head -1 | xargs)"
    /usr/lib/gnupg/gpg-preset-passphrase --preset --passphrase "$PASSPHRASE" "\$KEYGRIP"
  fi

else
  params+=("-us" "-uc")
fi

debuild  \${params[@]}
mv ../yq_* /home/yq/output

echo ""
echo -e "\tfind resulting package at: "$OUTPUT""

# publish to ppa whether given
if [ -n "$DO_PUBLISH" ]; then
  dput -c /etc/dput.cf ppa /home/yq/output/yq_*.changes
fi
EOF
chmod +x "${blddir}"/build.sh

# build the docker image with all dependencies
cat << EOF > ${blddir}/Dockerfile
FROM bitnami/minideb:bullseye as base
ENV LANG C.UTF-8
ENV LC_ALL C.UTF-8
ENV DEBIAN_FRONTEND noninteractive
ENV GO111MODULE on
ENV GOMODCACHE /home/yq/go

RUN set -e \
  && sed -i -- 's/# deb-src/deb-src/g' /etc/apt/sources.list \
  && apt-get -qq update

# install golang on its $GOVERSION
FROM base as golang
RUN apt-get -qq -y --no-install-recommends install \
    ca-certificates \
    wget
RUN wget "https://golang.org/dl/go${GOVERSION}.linux-amd64.tar.gz" -4
RUN tar -C /usr/local -xvf "go${GOVERSION}.linux-amd64.tar.gz"

FROM base
RUN apt-get -qq -y --no-install-recommends install \
    build-essential \
    debhelper \
    devscripts \
    dput \
    fakeroot \
    git-buildpackage \
    gpg-agent \
    libdistro-info-perl \
    pandoc \
    rsync \
    sensible-utils && \
  apt-get clean && \
  rm -rf /tmp/* /var/tmp/*

COPY --from=golang /usr/local/go /usr/local/go

# build debian package as yq user
RUN useradd -ms /bin/bash yq && \
  mkdir /home/yq/src && chown -R yq: /home/yq/src && \
  mkdir /home/yq/output && chown -R yq: /home/yq/output

ADD ./build/dput.cf /etc/dput.cf
ADD ./build/build.sh /usr/bin/build.sh
RUN chmod +x /usr/bin/build.sh && chown -R yq: /usr/bin/build.sh

USER yq

WORKDIR /home/yq/src
VOLUME ["/home/yq/src"]

# dir where output packages are finally left
VOLUME ["/home/yq/output"]

CMD ["/usr/bin/build.sh"]
EOF

DOCKER_BUILDKIT=1 docker build --pull -f "${blddir}"/Dockerfile -t "${DOCKER_IMAGE_NAME}:${DOCKER_IMAGE_TAG}" .

docker run --rm -i \
  -v "${srcdir}":/home/yq/src:delegated \
  -v "${OUTPUT}":/home/yq/output \
  -v "${HOME}"/.gnupg:/home/yq/.gnupg:delegated \
  -u "$(id -u)" \
  "${DOCKER_IMAGE_NAME}:${DOCKER_IMAGE_TAG}"
