summaryrefslogtreecommitdiff
path: root/.gitlab
diff options
context:
space:
mode:
authorBen Gamari <ben@smart-cactus.org>2020-01-16 17:41:43 -0500
committerBen Gamari <ben@smart-cactus.org>2020-02-14 10:16:36 -0500
commit565ce7aee5db966070f9d0267f99a13532d5caf0 (patch)
tree07de7d6c02f0e78a7cc02aff91dae8bd1d2930ea /.gitlab
parent0725f4bbc7f59282ee5fe41619099957030d85ff (diff)
downloadhaskell-565ce7aee5db966070f9d0267f99a13532d5caf0.tar.gz
gitlab-ci: Consolidate CI logic
This moves nearly all of the CI logic to .gitlab/ci.sh. This improves things in a number of ways: * it's harder for inconsistencies to arise between architectures * it's easier to share logic between architectures * on Windows, it's easier to ensure that all CI steps are executed from within a properly initialized mingw session. While in town I also add a FreeBSD build job and update the Windows job to use the gitlab-runner PowerShell executor, since cmd.exe will be deprecated soon (fixing #17699).
Diffstat (limited to '.gitlab')
-rwxr-xr-x.gitlab/ci.sh428
-rw-r--r--.gitlab/darwin-init.sh41
-rwxr-xr-x.gitlab/prepare-system.sh99
-rw-r--r--.gitlab/win32-init.sh47
4 files changed, 428 insertions, 187 deletions
diff --git a/.gitlab/ci.sh b/.gitlab/ci.sh
new file mode 100755
index 0000000000..90d789f040
--- /dev/null
+++ b/.gitlab/ci.sh
@@ -0,0 +1,428 @@
+#!/usr/bin/env bash
+
+# This is the primary driver of the GitLab CI infrastructure.
+
+set -e -o pipefail
+
+# Configuration:
+hackage_index_state="@1579718451"
+
+# Colors
+BLACK="0;30"
+GRAY="1;30"
+RED="0;31"
+LT_RED="1;31"
+BROWN="0;33"
+LT_BROWN="1;33"
+GREEN="0;32"
+LT_GREEN="1;32"
+BLUE="0;34"
+LT_BLUE="1;34"
+PURPLE="0;35"
+LT_PURPLE="1;35"
+CYAN="0;36"
+LT_CYAN="1;36"
+WHITE="1;37"
+LT_GRAY="0;37"
+
+# GitLab Pipelines log section delimiters
+# https://gitlab.com/gitlab-org/gitlab-foss/issues/14664
+start_section() {
+ name="$1"
+ echo -e "section_start:$(date +%s):$name\015\033[0K"
+}
+
+end_section() {
+ name="$1"
+ echo -e "section_end:$(date +%s):$name\015\033[0K"
+}
+
+echo_color() {
+ local color="$1"
+ local msg="$2"
+ echo -e "\e[${color}m${msg}\e[0m"
+}
+
+error() { echo_color "${RED}" "$1"; }
+warn() { echo_color "${LT_BROWN}" "$1"; }
+info() { echo_color "${LT_BLUE}" "$1"; }
+
+fail() { error "error: $1"; exit 1; }
+
+function run() {
+ info "Running $*..."
+ "$@" || ( error "$* failed"; return 1; )
+}
+
+if [ -z "$GHC_VERSION" ]; then
+ fail "GHC_VERSION not set"
+fi
+
+TOP="$(pwd)"
+
+function mingw_init() {
+ case "$MSYSTEM" in
+ MINGW32)
+ triple="i386-unknown-mingw32"
+ boot_triple="i386-unknown-mingw32" # triple of bootstrap GHC
+ ;;
+ MINGW64)
+ triple="x86_64-unknown-mingw32"
+ boot_triple="x86_64-unknown-mingw32" # triple of bootstrap GHC
+ ;;
+ *)
+ fail "win32-init: Unknown MSYSTEM $MSYSTEM"
+ ;;
+ esac
+
+ # Bring mingw toolchain into PATH.
+ # This is extracted from /etc/profile since this script inexplicably fails to
+ # run under gitlab-runner.
+ source /etc/msystem
+ MINGW_MOUNT_POINT="${MINGW_PREFIX}"
+ PATH="$MINGW_MOUNT_POINT/bin:$PATH"
+}
+
+# This will contain GHC's local native toolchain
+toolchain="$TOP/toolchain"
+mkdir -p $toolchain/bin
+PATH="$toolchain/bin:$PATH"
+
+export METRICS_FILE="$CI_PROJECT_DIR/performance-metrics.tsv"
+
+# Use a local temporary directory to ensure that concurrent builds don't
+# interfere with one another
+mkdir -p $TOP/tmp
+export TMP="$TOP/tmp"
+export TEMP="$TOP/tmp"
+
+function darwin_setup() {
+ # It looks like we already have python2 here and just installing python3
+ # does not work.
+ brew upgrade python
+ brew install ghc cabal-install ncurses gmp
+
+ pip3 install sphinx
+ # PDF documentation disabled as MacTeX apparently doesn't include xelatex.
+ #brew cask install mactex
+}
+
+function show_tool() {
+ local tool="$1"
+ info "$tool = ${!tool}"
+ ${!tool} --version
+}
+
+function set_toolchain_paths() {
+ needs_toolchain=1
+ case "$(uname)" in
+ Linux) needs_toolchain="" ;;
+ *) ;;
+ esac
+
+ if [[ -n "$needs_toolchain" ]]; then
+ # These are populated by setup_toolchain
+ export GHC="$toolchain/bin/ghc$exe"
+ export CABAL="$toolchain/bin/cabal$exe"
+ export HAPPY="$toolchain/bin/happy$exe"
+ export ALEX="$toolchain/bin/alex$exe"
+ else
+ export GHC="$(which ghc)"
+ export CABAL="/usr/local/bin/cabal"
+ export HAPPY="$HOME/.cabal/bin/happy"
+ export ALEX="$HOME/.cabal/bin/alex"
+ fi
+
+ # FIXME: Temporarily use ghc from ports
+ case "$(uname)" in
+ FreeBSD) GHC="/usr/local/bin/ghc" ;;
+ *) ;;
+ esac
+}
+
+# Extract GHC toolchain
+function setup() {
+ if [ -d "$TOP/cabal-cache" ]; then
+ info "Extracting cabal cache..."
+ cp -Rf cabal-cache $cabal_dir
+ fi
+
+ if [[ -n "$needs_toolchain" ]]; then
+ setup_toolchain
+ fi
+ case "$(uname)" in
+ Darwin) darwin_setup ;;
+ *) ;;
+ esac
+
+ # Make sure that git works
+ git config user.email "ghc-ci@gitlab-haskell.org"
+ git config user.name "GHC GitLab CI"
+
+ info "====================================================="
+ info "Toolchain versions"
+ info "====================================================="
+ show_tool GHC
+ show_tool CABAL
+ show_tool HAPPY
+ show_tool ALEX
+}
+
+function fetch_ghc() {
+ local v="$GHC_VERSION"
+ if [[ -z "$v" ]]; then
+ fail "GHC_VERSION is not set"
+ fi
+
+ if [ ! -e "$GHC" ]; then
+ start_section "fetch GHC"
+ url="https://downloads.haskell.org/~ghc/${GHC_VERSION}/ghc-${GHC_VERSION}-${boot_triple}.tar.xz"
+ info "Fetching GHC binary distribution from $url..."
+ curl $url > ghc.tar.xz || fail "failed to fetch GHC binary distribution"
+ tar -xJf ghc.tar.xz || fail "failed to extract GHC binary distribution"
+ case "$(uname)" in
+ MSYS_*|MINGW*)
+ cp -r ghc-${GHC_VERSION}/* $toolchain
+ ;;
+ *)
+ pushd ghc-${GHC_VERSION}
+ ./configure --prefix=$toolchain
+ $MAKE install
+ popd
+ ;;
+ esac
+ rm -Rf ghc-${GHC_VERSION} ghc.tar.xz
+ end_section "fetch GHC"
+ fi
+
+}
+
+function fetch_cabal() {
+ local v="$CABAL_INSTALL_VERSION"
+ if [[ -z "$v" ]]; then
+ fail "CABAL_INSTALL_VERSION is not set"
+ fi
+
+ if [ ! -e "$CABAL" ]; then
+ start_section "fetch GHC"
+ case "$(uname)" in
+ # N.B. Windows uses zip whereas all others use .tar.xz
+ MSYS_*|MINGW*)
+ case "$MSYSTEM" in
+ MINGW32) cabal_arch="i386" ;;
+ MINGW64) cabal_arch="x86_64" ;;
+ *) fail "unknown MSYSTEM $MSYSTEM" ;;
+ esac
+ url="https://downloads.haskell.org/~cabal/cabal-install-$v/cabal-install-$v-$cabal_arch-unknown-mingw32.zip"
+ info "Fetching cabal binary distribution from $url..."
+ curl $url > $TMP/cabal.zip
+ unzip $TMP/cabal.zip
+ mv cabal.exe $CABAL
+ ;;
+ *)
+ local base_url="https://downloads.haskell.org/~cabal/cabal-install-$v/"
+ case "$(uname)" in
+ Darwin) cabal_url="$base_url/cabal-install-$v-x86_64-apple-darwin17.7.0.tar.xz" ;;
+ FreeBSD)
+ #cabal_url="$base_url/cabal-install-$v-x86_64-portbld-freebsd.tar.xz" ;;
+ cabal_url="http://home.smart-cactus.org/~ben/ghc/cabal-install-3.0.0.0-x86_64-portbld-freebsd.tar.xz" ;;
+ *) fail "don't know where to fetch cabal-install for $(uname)"
+ esac
+ echo "Fetching cabal-install from $cabal_url"
+ curl $cabal_url > cabal.tar.xz
+ tar -xJf cabal.tar.xz
+ mv cabal $toolchain/bin
+ ;;
+ esac
+ end_section "fetch GHC"
+ fi
+}
+
+# For non-Docker platforms we prepare the bootstrap toolchain
+# here. For Docker platforms this is done in the Docker image
+# build.
+function setup_toolchain() {
+ fetch_ghc
+ fetch_cabal
+ cabal_install="$CABAL v2-install --index-state=$hackage_index_state --installdir=$toolchain/bin"
+ # Avoid symlinks on Windows
+ case "$(uname)" in
+ MSYS_*|MINGW*) cabal_install="$cabal_install --install-method=copy" ;;
+ *) ;;
+ esac
+
+ if [ ! -e "$HAPPY" ]; then
+ info "Building happy..."
+ cabal update
+ $cabal_install happy
+ fi
+
+ if [ ! -e "$ALEX" ]; then
+ info "Building alex..."
+ cabal update
+ $cabal_install alex
+ fi
+}
+
+function cleanup_submodules() {
+ start_section "clean submodules"
+ info "Cleaning submodules..."
+ # On Windows submodules can inexplicably get into funky states where git
+ # believes that the submodule is initialized yet its associated repository
+ # is not valid. Avoid failing in this case with the following insanity.
+ git submodule sync --recursive || git submodule deinit --force --all
+ git submodule update --init --recursive
+ git submodule foreach git clean -xdf
+ end_section "clean submodules"
+}
+
+function prepare_build_mk() {
+ if [[ -z "$BUILD_FLAVOUR" ]]; then fail "BUILD_FLAVOUR is not set"; fi
+ if [[ -z ${BUILD_SPHINX_HTML:-} ]]; then BUILD_SPHINX_HTML=YES; fi
+ if [[ -z ${BUILD_SPHINX_PDF:-} ]]; then BUILD_SPHINX_PDF=YES; fi
+ if [[ -z ${INTEGER_LIBRARY:-} ]]; then INTEGER_LIBRARY=integer-gmp; fi
+
+ cat > mk/build.mk <<EOF
+V=1
+HADDOCK_DOCS=YES
+LATEX_DOCS=YES
+HSCOLOUR_SRCS=YES
+BUILD_SPHINX_HTML=$BUILD_SPHINX_HTML
+BUILD_SPHINX_PDF=$BUILD_SPHINX_PDF
+BeConservative=YES
+INTEGER_LIBRARY=$INTEGER_LIBRARY
+XZ_CMD=$XZ
+
+BuildFlavour=$BUILD_FLAVOUR
+ifneq "\$(BuildFlavour)" ""
+include mk/flavours/\$(BuildFlavour).mk
+endif
+GhcLibHcOpts+=-haddock
+EOF
+
+ if [ -n "$HADDOCK_HYPERLINKED_SOURCES" ]; then
+ echo "EXTRA_HADDOCK_OPTS += --hyperlinked-source --quickjump" >> mk/build.mk
+ fi
+
+ case "$(uname)" in
+ Darwin) echo "libraries/integer-gmp_CONFIGURE_OPTS += --configure-option=--with-intree-gmp" >> mk/build.mk ;;
+ *) ;;
+ esac
+
+ info "build.mk is:"
+ cat mk/build.mk
+}
+
+function configure() {
+ start_section "booting"
+ run python3 boot
+ end_section "booting"
+
+ start_section "configuring"
+ run ./configure \
+ --enable-tarballs-autodownload \
+ --target=$triple \
+ $CONFIGURE_ARGS \
+ GHC=$GHC \
+ HAPPY=$HAPPY \
+ ALEX=$ALEX \
+ || ( cat config.log; fail "configure failed" )
+ end_section "configuring"
+}
+
+function build_make() {
+ prepare_build_mk
+ if [[ -z "$BIN_DIST_PREP_TAR_COMP" ]]; then
+ fail "BIN_DIST_PREP_TAR_COMP is not set"
+ fi
+
+ echo "include mk/flavours/${BUILD_FLAVOUR}.mk" > mk/build.mk
+ echo 'GhcLibHcOpts+=-haddock' >> mk/build.mk
+ run $MAKE -j$(mk/detect-cpu-count.sh) $MAKE_ARGS
+ run $MAKE -j$(mk/detect-cpu-count.sh) binary-dist-prep TAR_COMP_OPTS=-1
+ ls -lh $BIN_DIST_PREP_TAR_COMP
+}
+
+function fetch_perf_notes() {
+ info "Fetching perf notes..."
+ $TOP/.gitlab/test-metrics.sh pull
+}
+
+function push_perf_notes() {
+ info "Pushing perf notes..."
+ $TOP/.gitlab/test-metrics.sh push
+}
+
+function test_make() {
+ run $MAKE test_bindist TEST_PREP=YES
+ run $MAKE V=0 test \
+ THREADS=$(mk/detect-cpu-count.sh) \
+ JUNIT_FILE=../../junit.xml
+}
+
+function build_hadrian() {
+ if [ -z "$FLAVOUR" ]; then
+ fail "FLAVOUR not set"
+ fi
+
+ run hadrian/build.cabal.sh \
+ --flavour=$FLAVOUR \
+ -j$(mk/detect-cpu-count.sh) \
+ $HADRIAN_ARGS \
+ binary-dist
+
+ mv _build/bindist/ghc*.tar.xz ghc.tar.xz
+}
+
+function test_hadrian() {
+ cd _build/bindist/ghc-*/
+ run ./configure --prefix=$TOP/_build/install
+ run $MAKE install
+ cd ../../../
+
+ run hadrian/build.cabal.sh \
+ --flavour=$FLAVOUR \
+ -j$(mk/detect-cpu-count.sh) \
+ $HADRIAN_ARGS \
+ test \
+ --summary-junit=./junit.xml \
+ --test-compiler=$TOP/_build/install/bin/ghc
+}
+
+function clean() {
+ rm -R tmp
+ run $MAKE --quiet clean || true
+ run rm -Rf _build
+}
+
+# Determine Cabal data directory
+case "$(uname)" in
+ MSYS_*|MINGW*) exe=".exe"; cabal_dir="$APPDATA/cabal" ;;
+ *) cabal_dir="$HOME/.cabal"; exe="" ;;
+esac
+
+# Platform-specific environment initialization
+MAKE="make"
+case "$(uname)" in
+ MSYS_*|MINGW*) mingw_init ;;
+ Darwin) boot_triple="x86_64-apple-darwin" ;;
+ FreeBSD)
+ boot_triple="x86_64-portbld-freebsd"
+ MAKE="gmake"
+ ;;
+ Linux) ;;
+ *) fail "uname $(uname) is not supported" ;;
+esac
+
+set_toolchain_paths
+
+case $1 in
+ setup) setup && cleanup_submodules ;;
+ configure) configure ;;
+ build_make) build_make ;;
+ test_make) fetch_perf_notes; test_make; push_perf_notes ;;
+ build_hadrian) build_hadrian ;;
+ test_hadrian) fetch_perf_notes; test_hadrian; push_perf_notes ;;
+ clean) clean ;;
+ *) fail "unknown mode $1" ;;
+esac
diff --git a/.gitlab/darwin-init.sh b/.gitlab/darwin-init.sh
deleted file mode 100644
index 3dadc04dc1..0000000000
--- a/.gitlab/darwin-init.sh
+++ /dev/null
@@ -1,41 +0,0 @@
-#!/bin/bash
-
-set -e
-
-toolchain=`pwd`/toolchain
-PATH="$toolchain/bin:$PATH"
-
-if [ -d "`pwd`/cabal-cache" ]; then
- cp -Rf cabal-cache $HOME/.cabal
-fi
-
-if [ ! -e $toolchain/bin/ghc ]; then
- mkdir -p tmp
- cd tmp
- ghc_tarball="https://downloads.haskell.org/~ghc/$GHC_VERSION/ghc-$GHC_VERSION-x86_64-apple-darwin.tar.xz"
- echo "Fetching GHC from $ghc_tarball"
- curl $ghc_tarball | tar -xJ
- cd ghc-$GHC_VERSION
- ./configure --prefix=$toolchain
- make install
- cd ../..
- rm -Rf tmp
-fi
-
-if [ ! -e $toolchain/bin/cabal ]; then
- cabal_tarball="https://downloads.haskell.org/~cabal/cabal-install-$CABAL_INSTALL_VERSION/cabal-install-$CABAL_INSTALL_VERSION-x86_64-apple-darwin-sierra.tar.xz"
- echo "Fetching cabal-install from $cabal_tarball"
- curl $cabal_tarball | tar -xz
- mv cabal $toolchain/bin
-fi
-
-if [ ! -e $toolchain/bin/happy ]; then
- cabal update
- cabal new-install happy --symlink-bindir=$toolchain/bin
-fi
-
-if [ ! -e $toolchain/bin/alex ]; then
- cabal update
- cabal new-install alex --symlink-bindir=$toolchain/bin
-fi
-
diff --git a/.gitlab/prepare-system.sh b/.gitlab/prepare-system.sh
deleted file mode 100755
index 4180e6029c..0000000000
--- a/.gitlab/prepare-system.sh
+++ /dev/null
@@ -1,99 +0,0 @@
-#!/usr/bin/env bash
-# vim: sw=2 et
-set -euo pipefail
-
-fail() {
- echo "ERROR: $*" >&2
- exit 1
-}
-
-hackage_index_state="@1522046735"
-
-if [[ -z ${BUILD_SPHINX_HTML:-} ]]; then BUILD_SPHINX_HTML=YES; fi
-if [[ -z ${BUILD_SPHINX_PDF:-} ]]; then BUILD_SPHINX_PDF=YES; fi
-if [[ -z ${INTEGER_LIBRARY:-} ]]; then INTEGER_LIBRARY=integer-gmp; fi
-if [[ -z ${BUILD_FLAVOUR:-} ]]; then BUILD_FLAVOUR=perf; fi
-
-if [[ -z ${XZ:-} ]]; then
- if which pxz; then
- XZ="pxz"
- elif which xz; then
- # Check whether --threads is supported
- if echo "hello" | xz --threads=$CORES >/dev/null; then
- XZ="xz --threads=$CORES"
- else
- XZ="xz"
- fi
- else
- echo "error: neither pxz nor xz were found"
- exit 1
- fi
-fi
-echo "Using $XZ for compression..."
-
-
-cat > mk/build.mk <<EOF
-V=1
-HADDOCK_DOCS=YES
-LATEX_DOCS=YES
-HSCOLOUR_SRCS=YES
-BUILD_SPHINX_HTML=$BUILD_SPHINX_HTML
-BUILD_SPHINX_PDF=$BUILD_SPHINX_PDF
-BeConservative=YES
-INTEGER_LIBRARY=$INTEGER_LIBRARY
-XZ_CMD=$XZ
-EOF
-
-cat <<EOF >> mk/build.mk
-BuildFlavour=$BUILD_FLAVOUR
-ifneq "\$(BuildFlavour)" ""
-include mk/flavours/\$(BuildFlavour).mk
-endif
-GhcLibHcOpts+=-haddock
-EOF
-
-case "$(uname)" in
- Linux)
- if [[ -n ${TARGET:-} ]]; then
- if [[ $TARGET = FreeBSD ]]; then
- # cross-compiling to FreeBSD
- echo 'HADDOCK_DOCS = NO' >> mk/build.mk
- echo 'WERROR=' >> mk/build.mk
- # https://circleci.com/docs/2.0/env-vars/#interpolating-environment-variables-to-set-other-environment-variables
- echo 'export PATH=/opt/ghc/bin:$PATH' >> $BASH_ENV
- else
- fail "TARGET=$target not supported"
- fi
- fi
- ;;
-
- Darwin)
- if [[ -n ${TARGET:-} ]]; then
- fail "uname=$(uname) not supported for cross-compilation"
- fi
- # It looks like we already have python2 here and just installing python3
- # does not work.
- brew upgrade python
- brew install ghc cabal-install ncurses gmp
-
- pip3 install sphinx
- # PDF documentation disabled as MacTeX apparently doesn't include xelatex.
- #brew cask install mactex
-
- cabal update
- cabal install --reinstall alex happy haddock hscolour --index-state=$hackage_index_state
- # put them on the $PATH, don't fail if already installed
- ln -s $HOME/.cabal/bin/alex /usr/local/bin/alex || true
- ln -s $HOME/.cabal/bin/happy /usr/local/bin/happy || true
- ln -s $HOME/.cabal/bin/HsColour /usr/local/bin/HsColour || true
- echo "libraries/integer-gmp_CONFIGURE_OPTS += --configure-option=--with-intree-gmp" >> mk/build.mk
- ;;
- *)
- fail "uname=$(uname) not supported"
-esac
-
-echo "================================================="
-echo "Build.mk:"
-echo ""
-cat mk/build.mk
-echo "================================================="
diff --git a/.gitlab/win32-init.sh b/.gitlab/win32-init.sh
deleted file mode 100644
index aec73ce083..0000000000
--- a/.gitlab/win32-init.sh
+++ /dev/null
@@ -1,47 +0,0 @@
-#!/bin/bash
-
-set -e
-
-toolchain=`pwd`/toolchain
-PATH="$toolchain/bin:/mingw64/bin:$PATH"
-
-if [ -d "`pwd`/cabal-cache" ]; then
- cp -Rf cabal-cache $APPDATA/cabal
-fi
-
-if [ ! -e $toolchain/bin/ghc ]; then
- case $MSYSTEM in
- MINGW32)
- triple="i386-unknown-mingw32"
- ;;
- MINGW64)
- triple="x86_64-unknown-mingw32"
- ;;
- *)
- echo "win32-init: Unknown MSYSTEM $MSYSTEM"
- exit 1
- ;;
- esac
- curl https://downloads.haskell.org/~ghc/$GHC_VERSION/ghc-$GHC_VERSION-$triple.tar.xz | tar -xJ
- mv ghc-$GHC_VERSION toolchain
-fi
-
-if [ ! -e $toolchain/bin/cabal ]; then
- url="https://downloads.haskell.org/~cabal/cabal-install-2.4.1.0/cabal-install-2.4.1.0-x86_64-unknown-mingw32.zip"
- curl $url > /tmp/cabal.zip
- unzip /tmp/cabal.zip
- mv cabal.exe $toolchain/bin
-fi
-
-if [ ! -e $toolchain/bin/happy ]; then
- cabal update
- cabal install happy
- cp $APPDATA/cabal/bin/happy $toolchain/bin
-fi
-
-if [ ! -e $toolchain/bin/alex ]; then
- cabal update
- cabal install alex
- cp $APPDATA/cabal/bin/alex $toolchain/bin
-fi
-