#!/usr/bin/env bash

# Script to generate and deploy Hackage repository for head.hackage patchset.
# The hackage-security keys are stored in a tarball, $KEYS_TARBALL, encrypted
# with the key material given in $KEYS_TARBALL_KEY.
#
# To test under NixOS: nix run nixpkgs.openssl nixpkgs.pwgen

set -e

cipher=aes-256-cbc
if [ -z "$PATCHES" ]; then PATCHES=./patches; fi

# For use by administrator.
gen_keys_tarball() {
  hackage-repo-tool create-keys --keys=./keys
  pass="$(pwgen 32 1)"
  tar -c keys | openssl enc -$cipher -pbkdf2 -e -k "$pass" > keys.tar.enc
  echo "Wrote ./keys.tar.enc"
  echo "$pass" > keys.key
  echo "KEYS_TARBALL_KEY = $pass"
}

# Helper to decrypt and extract the keys tarball.
extract_keys_tarball() {
  if [ -z "$KEYS_TARBALL_KEY" ]; then
    echo "Can't extract keys tarball: KEYS_TARBALL_KEY not set"
    exit 1
  fi
  if [ -z "$KEYS_TARBALL" ]; then
    echo "Can't extract keys tarball: KEYS_TARBALL not set"
    exit 1
  fi

  curl $KEYS_TARBALL | openssl enc -$cipher -pbkdf2 -d -k "$KEYS_TARBALL_KEY" | tar -x
  if [ ! -d ./keys ]; then
    echo "Key tarball extraction failed"
    exit 1
  fi
}

build_repository_blurb() {
  local keys="$(find keys/root -type f -printf "%f")"
  local newline=$'\n'
  if [ -z "$REPO_NAME" ]; then
    REPO_NAME="head.hackage.ghc.haskell.org"
  fi
  if [ -z "$REPO_URL" ]; then
    REPO_URL="https://ghc.gitlab.haskell.org/head.hackage/"
  fi

  sed -e 's/ \+$//' <<EOF
repository $REPO_NAME
   url: $REPO_URL
   secure: True
   key-threshold: 3
   root-keys:
       ${keys//.private/$newline       }
EOF
}

build_index() {
  local commit="$CI_COMMIT_SHA"
  local commit_url="https://gitlab.haskell.org/ghc/head.hackage/commit/$commit"
  build_repository_blurb >repo/cabal.project.local

  cat >repo/ci.html <<EOF
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
    <link rel="stylesheet" href="https://unpkg.com/leaflet@1.3.1/dist/leaflet.css" />
    <link rel="stylesheet" href="https://code.jquery.com/ui/1.12.1/themes/smoothness/jquery-ui.css" media="screen">

    <script type="text/javascript" src="https://unpkg.com/leaflet@1.3.1/dist/leaflet.js"></script>
    <script type="text/javascript" src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
    <script type="text/javascript" src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>
    <script src="scripts/imgViewer2.min.js"></script>
    <title>head.hackage</title>
  </head>
  <body>
  <section class="container">
    <h1 class="title">head.hackage build results</h1>
    <p>This page summarizes the build dependency graph from the continuous
    integration build of <code>head.hackage</code> commit
    <a href="$commit_url"><code>$commit</code></a>.

    <img id="graph" width="80%" height="80%" src="summary.dot.svg">

    <script>
      (function($) {
        \$("\#graph").imgViewer2();
      })($);
    </script>
  </body>
</html>
EOF
  mkdir -p repo/scripts
  curl https://raw.githubusercontent.com/waynegm/imgViewer2/master/dist/imgViewer2.min.js \
    > repo/scripts/imgViewer2.min.js

  cat >repo/index.html <<EOF
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
    <title>head.hackage</title>
  </head>
  <body>
  <section class="container">
    <h1 class="title">head.hackage</h1>
    <p>This is a Haskell package repository containing patched
    packages from <a href="https://hackage.haskell.org/">Hackage</a> for use
    with <a href="https://gitlab.haskell.org/ghc/ghc">GHC</a> prereleases.

    <p>The source of this package repository is at <a href="https://gitlab.haskell.org/ghc/head.hackage">gitlab.haskell.org/ghc/head.hackage</a>.

    <p>To use package repository with <code>cabal-install</code> add the following
    to your project's <code>cabal.project.local</code> and run
	<code>cabal v2-update</code>: (consider using <code>scripts/head.hackage.sh update</code> as <code>v2-update</code> is broken, <a href="https://github.com/haskell/cabal/issues/5952">Cabal bug #5952</a>)
    <pre><code>
$(cat repo/cabal.project.local)
    </code></pre>

    <p>Finally, you may want to add the <a
    href="cabal.constraints">constraints</a> to your project to ensure that
    cabal chooses the patched releases.

    <p>If you find a package that doesn't build with a recent GHC
    pre-release see the <a
    href="https://gitlab.haskell.org/ghc/head.hackage#adding-a-patch">contributor
    documentation</a> for instructions on how to contribute a patch.
    
    <p>If you encounter other trouble refer to the
    <a href="https://gitlab.haskell.org/ghc/head.hackage">head.hackage
    documentation</a> or
    <a href="https://gitlab.haskell.org/ghc/head.hackage/issues">let us know</a>.

    <p>You might also be interested in referring to the <a href="ci.html">CI
    build results</a> of the build that gave rise to this repository.

    <p><code>head.hackage</code> commit:
    <a href="$commit_url"><code>$commit</code></a>
  </section>
  </body>
</html>
EOF
}

build_constraints() {
  head-hackage-ci make-constraints $PATCHES
}

# Build the hackage repository
build_repo() {
  # hackage-repo-tool bootstrap fails unless there is at least one package in the
  # repo. Seed things with acme-box.
  cabal update
  cabal fetch acme-box-0.0.0.0
  mkdir -p repo/package
  cp $HOME/.cabal/packages/hackage.haskell.org/acme-box/0.0.0.0/acme-box-0.0.0.0.tar.gz repo/package

  mkdir -p tmp
  cp -R $PATCHES tmp/patches
  hackage-repo-tool bootstrap --keys=./keys --repo=./repo

  mkdir -p template tmp/patches.cache
  tool \
    --patches=./tmp/patches \
    --repo-cache=./cache \
    --keys=./keys \
    --repo-name=head.hackage \
    --template=template \
    ./repo

  build_constraints > repo/cabal.constraints
  build_index
  rm -R tmp
}

case $1 in
  gen-keys) gen_keys_tarball ;;
  extract-keys) extract_keys_tarball ;;
  build-repo) build_repo ;;
  build-constraints) build_constraints ;;
  build-repository-blurb) build_repository_blurb ;;
  build-index)
    build_constraints > repo/cabal.constraints
    build_index ;;
  *)
    echo "error: Unknown command $1."
    echo
    echo "Usage: $0 [command]"
    echo
    echo "Commands:"
    echo "  gen-keys"
    echo "  extract-keys"
    echo "  build-repo"
    echo "  build-constraints"
    echo "  build-repository-blurb"
    echo "  build-index"
    exit 1
    ;;
esac
