Skip to content

Commit

Permalink
gh: Use prebuilt as cache to speedup build
Browse files Browse the repository at this point in the history
  • Loading branch information
garazdawi committed Oct 18, 2022
1 parent 692e98c commit ee862db
Show file tree
Hide file tree
Showing 6 changed files with 365 additions and 111 deletions.
10 changes: 7 additions & 3 deletions .github/dockerfiles/Dockerfile.64-bit
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,13 @@ WORKDIR /buildroot/otp/

ENV CFLAGS="-O2 -g -Werror"

## Configure, check that no application are disabled and then make
RUN ./configure --prefix="/Erlang ∅⊤℞" && \
if cat lib/*/CONF_INFO || cat lib/*/SKIP || cat lib/SKIP-APPLICATIONS; then exit 1; fi && \
## Configure (if not cached), check that no application are disabled and then make
RUN if [ ! -f Makefile ]; then \
touch README.md && \
./configure --prefix="/Erlang ∅⊤℞" && \
if cat lib/*/CONF_INFO || cat lib/*/SKIP || cat lib/SKIP-APPLICATIONS; then exit 1; fi && \
find . -type f -newer README.md | xargs tar --transform 's:^./:otp/:' -cf ../otp_cache.tar; \
fi && \
make && make docs DOC_TARGETS=chunks && \
sudo make install install-docs DOC_TARGETS=chunks

Expand Down
7 changes: 6 additions & 1 deletion .github/scripts/init-pre-release.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@
## to create the pre-built tar ball

AUTOCONF=0
TARGET=otp_src.tar.gz

if [ -n "$1" ]; then
TARGET="$1"
fi

## This script is used to create archives for older releases
## so if configure does not exist in the git repo we need to
Expand All @@ -23,7 +28,7 @@ if [ ! -f configure ]; then
git commit --no-verify -m 'Add generated configure files'
AUTOCONF=1
fi
git archive --prefix otp/ -o otp_src.tar.gz HEAD
git archive --prefix otp/ -o "$TARGET" HEAD

if [ "$AUTOCONF" = 1 ]; then
git reset --hard HEAD~1
Expand Down
162 changes: 162 additions & 0 deletions .github/scripts/restore-from-prebuilt.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
#!/bin/bash

set -xe

CACHE_SOURCE_DIR="$1"
TARGET="$2"
ARCHIVE="$3"
EVENT="$4"
DELETED="$5"
CHANGES="$9"

if [ ! -f "${CACHE_SOURCE_DIR}/otp_src.tar.gz" ] || [ "${NO_CACHE}" = "true" ]; then
cp "${ARCHIVE}" "${TARGET}"
cp "${ARCHIVE}" "${CACHE_SOURCE_DIR}/otp_src.tar.gz"
exit 0
fi

TMP_DIR=$(mktemp -d)
CACHE_DIR="${TMP_DIR}"
ARCHIVE_DIR="${TMP_DIR}/archive"

mkdir "${ARCHIVE_DIR}"

#################################
## START WORK ON THE CACHED FILES
#################################
echo "::group::{Restore cached files}"
tar -C "${CACHE_DIR}/" -xzf "${CACHE_SOURCE_DIR}/otp_src.tar.gz"

## If configure scripts have NOT changed, we can restore configure and other C/java programs
if [ -z "${CONFIGURE}" ] || [ "${CONFIGURE}" = "false" ]; then
tar -C "${CACHE_DIR}/" -xzf "${CACHE_SOURCE_DIR}/otp_cache.tar.gz"
fi

## If bootstrap has been changed, we do not use the cached .beam files
EXCLUDE_BOOTSTRAP=""
if [ "${BOOTSTRAP}" = "true" ]; then
find "${CACHE_DIR}/otp/lib" -name "*.beam" -exec rm -f {} \;
else
EXCLUDE_BOOTSTRAP=(--exclude "bootstrap")
fi

## Make a copy of the cache for debugging
mkdir "${TMP_DIR}/cache"
cp -rp "${CACHE_DIR}/otp" "${TMP_DIR}/cache/"

CACHE_DIR="${CACHE_DIR}/otp"

echo "::group::{Delete files from PR}"
## Delete any files that this PR deletes
for delete in $DELETED; do
if [ -d "${CACHE_DIR}/${delete}" ]; then
rm -r "${CACHE_DIR}/${delete}"
elif [ -f "${CACHE_DIR}/${delete}" ]; then
rm "${CACHE_DIR}/${delete}"
else
echo "Could not find $delete to delete"
exit 1
fi
done

##################################
## START WORK ON THE UPDATED FILES
##################################

echo "::group::{Extract changed files}"
if [ -n "${ARCHIVE}" ]; then
## Extract with updated timestamp (the -m flag) so that any change will trigger a rebuild
tar -C "${ARCHIVE_DIR}/" -xzmf "${ARCHIVE}"

## Directory permissions in the archive and cache are for some reason different...
chmod -R g-w "${ARCHIVE_DIR}/"

## rlpgoD is the same as --archive, but without --times
RSYNC_ARGS=(-rlpgoD --itemize-changes --verbose --checksum --update "${EXCLUDE_BOOTSTRAP[@]}" "${ARCHIVE_DIR}/otp/" "${CACHE_DIR}/")

CHANGES="${TMP_DIR}/changes"
PREV_CHANGES="${TMP_DIR}/prev-changes"

touch "${PREV_CHANGES}"

## Below follows some rules about when we do not want to use the cache
## The rules are run multiple times so that if any rule triggeres a delte
## we will re-run the rules again with the new changes.
for i in $(seq 1 10); do

echo "::group::{Run ${i} at pruning cache}"

## First do a dry run to see if we need to delete anything from cache
rsync --dry-run "${RSYNC_ARGS[@]}" | grep '^\(>\|c\)' > "${TMP_DIR}/changes"
cat "${TMP_DIR}/changes"

if cmp -s "${CHANGES}" "${PREV_CHANGES}"; then
break;
fi

### If any parse transform is changed we recompile everything as we have
### no idea what it may change. If the parse transform calls any other
### modules we really should delete the cache for those as well, but
### it is impossible for us to know which modules are used by a pt so
### this has to be somekind of best effort.
echo "::group::{Run ${i}: parse transforms}"
PARSE_TRANSFORMS=$(grep -r '^parse_transform(' "${CACHE_DIR}/" | grep "/lib/[^/]*/src/" | awk -F ':' '{print $1}' | uniq)
for pt in $PARSE_TRANSFORMS; do
if grep "$(basename "${pt}")" "${CHANGES}"; then
echo "Deleting entire cache as a parse transform has changed" >&2
rm -rf "${CACHE_DIR:?}/"
fi
done

echo "::group::{Run ${i}: yecc}"
### if yecc has changed, need to recompile all .yrl files
if grep "yecc.erl$" "${CHANGES}"; then
echo "Deleting all .yrl files as yecc has changed" >&2
find "${CACHE_DIR}/" -name "*.yrl" -exec rm -f {} \;
fi

echo "::group::{Run ${i}: asn1}"
### If asn1 has changed, need to re-compile all .asn1 files
if grep lib/asn1 "${CHANGES}"; then
echo "Deleting all .asn1 files as asn1 has changed" >&2
find "${CACHE_DIR}/" -name "*.asn1" -exec rm -f {} \;
fi

echo "::group::{Run ${i}: docs}"
### If any of the doc generating tools change, we need to re-compile the docs
if grep "lib/\(xmerl\|erl_docgen\|edoc\)" "${CHANGES}"; then
echo "Deleting all docs as documentation tools have changed" >&2
rm -rf "${CACHE_DIR}"/lib/*/doc/ "${CACHE_DIR}/erts/doc/" "${CACHE_DIR}/system/"
fi

### Find all behaviours in OTP and check if any them as changed, we need to
### rebuild all files that use them.
echo "::group::{Run ${i}: behaviours}"
BEHAVIOURS=$(grep -r "^-callback" "${CACHE_DIR}/" | grep "/lib/[^/]*/src/" | awk -F ':' '{print $1}' | uniq | sed 's:.*/\([^/.]*\)[.]erl$:\1:')
for behaviour in $BEHAVIOURS; do
if grep "${behaviour}[.]erl\$" "${CHANGES}"; then
echo "Deleting files using ${behaviour} has it has changed" >&2
FILES=$(grep -r "^-behaviour(${behaviour})" "${CACHE_DIR}/" | grep "/lib/[^/]*/src/" | awk -F ':' '{print $1}')
rm -f $FILES
fi
done

if [ "$i" = "10" ]; then
echo "Deleting entire cache as it did not stabalize in trime" >&2
rm -rf "${CACHE_DIR:?}"
else
mv "${CHANGES}" "${PREV_CHANGES}"
fi
done

echo "::group::{Sync changes over cached data}"

## Now we do the actual sync
rsync "${RSYNC_ARGS[@]}"
fi

tar -czf "${TARGET}" -C "${TMP_DIR}" otp

rm -rf "${TMP_DIR}"

echo "::endgroup::"
13 changes: 0 additions & 13 deletions .github/scripts/restore-otp-image.sh

This file was deleted.

Loading

0 comments on commit ee862db

Please sign in to comment.