Files
molecules/scripts/iso_build.sh

562 lines
15 KiB
Bash
Executable File

#!/bin/bash
# Path to molecules.git dir
SABAYON_MOLECULE_HOME="${SABAYON_MOLECULE_HOME:-/sabayon}"
export SABAYON_MOLECULE_HOME
# setup default language, cron might not do that
export LC_ALL="en_US.UTF-8"
export LANG="en_US.UTF-8"
export LANGUAGE="en_US.UTF-8"
# We set our own stuff, do not inherit from env
unset PORTDIR PORTAGE_TMPDIR
VALID_ACTIONS=(
"daily"
"weekly"
"monthly"
"dailybase"
"release"
)
ACTION="${1}"
ACTION_VALID=
for act in "${VALID_ACTIONS[@]}"; do
if [ "${act}" = "${ACTION}" ]; then
ACTION_VALID=1
break
fi
done
if [ -z "${ACTION_VALID}" ]; then
echo "invalid action: ${ACTION}" >&2
exit 1
fi
shift
for arg in "$@"; do
[[ "${arg}" = "--push" ]] && DO_PUSH="1"
[[ "${arg}" = "--stdout" ]] && DO_STDOUT="1"
[[ "${arg}" = "--sleepnight" ]] && DO_SLEEPNIGHT="1"
[[ "${arg}" = "--pushonly" ]] && DO_PUSHONLY="1" && DO_PUSH="1"
[[ "${arg}" = "--torrents" ]] && MAKE_TORRENTS="1"
done
# Initialize script variables
SOURCE_SPECS=()
SOURCE_SPECS_ISO=()
REMASTER_SPECS=()
REMASTER_SPECS_ISO=()
REMASTER_TAR_SPECS=()
REMASTER_TAR_SPECS_TAR=()
# ISO TAG is instead used as part of the images push
# to our mirror. It is always "DAILY" but it gets a special
# meaning for monthly releases.
ISO_TAG="DAILY"
OLD_ISO_TAG="" # used to remove OLD ISO images the local dir
DISTRO_NAME="Sabayon_Linux"
ISO_DIR="daily"
CHANGELOG_DATES=""
CHANGELOG_DIR="${SABAYON_MOLECULE_HOME}/${ACTION}-git-logs"
get_default_sabayon_release() {
echo "$(date -u +%Y%m%d)"
}
if [ "${ACTION}" = "weekly" ] || [ "${ACTION}" = "daily" ]; then
export BUILDING_DAILY=1
SABAYON_RELEASE=$(get_default_sabayon_release)
# Daily molecules
SOURCE_SPECS+=(
"sabayon-amd64-spinbase.spec"
"sabayon-amd64-spinbase-dev.spec"
)
SOURCE_SPECS_ISO+=(
"${DISTRO_NAME}_${ISO_TAG}_amd64_SpinBase.iso"
"${DISTRO_NAME}_${ISO_TAG}_amd64_SpinBase-dev.iso"
)
REMASTER_SPECS+=(
"sabayon-amd64-gnome.spec"
"sabayon-amd64-kde.spec"
"sabayon-amd64-mate.spec"
"sabayon-amd64-xfce.spec"
"sabayon-amd64-minimal.spec"
"sabayon-amd64-server.spec"
"sabayon-amd64-gnome-dev.spec"
"sabayon-amd64-kde-dev.spec"
"sabayon-amd64-mate-dev.spec"
"sabayon-amd64-xfce-dev.spec"
"sabayon-amd64-minimal-dev.spec"
"sabayon-amd64-server-dev.spec"
)
REMASTER_SPECS_ISO+=(
"${DISTRO_NAME}_${ISO_TAG}_amd64_GNOME.iso"
"${DISTRO_NAME}_${ISO_TAG}_amd64_KDE.iso"
"${DISTRO_NAME}_${ISO_TAG}_amd64_MATE.iso"
"${DISTRO_NAME}_${ISO_TAG}_amd64_Xfce.iso"
"${DISTRO_NAME}_${ISO_TAG}_amd64_Minimal.iso"
"${DISTRO_NAME}_${ISO_TAG}_amd64_Server.iso"
"${DISTRO_NAME}_${ISO_TAG}_amd64_GNOME-dev.iso"
"${DISTRO_NAME}_${ISO_TAG}_amd64_KDE-dev.iso"
"${DISTRO_NAME}_${ISO_TAG}_amd64_MATE-dev.iso"
"${DISTRO_NAME}_${ISO_TAG}_amd64_Xfce-dev.iso"
"${DISTRO_NAME}_${ISO_TAG}_amd64_Minimal-dev.iso"
"${DISTRO_NAME}_${ISO_TAG}_amd64_Server-dev.iso"
)
REMASTER_TAR_SPECS+=(
"sabayon-amd64-spinbase-tarball-template.spec"
)
REMASTER_TAR_SPECS_TAR+=(
"${DISTRO_NAME}_${ISO_TAG}_amd64_tarball.tar.gz"
)
# Weekly molecules
if [ "${ACTION}" = "weekly" ]; then
REMASTER_SPECS+=(
"sabayon-amd64-xfceforensic.spec"
)
REMASTER_SPECS_ISO+=(
"${DISTRO_NAME}_${ISO_TAG}_amd64_ForensicsXfce.iso"
)
fi
elif [ "${ACTION}" = "dailybase" ]; then
export BUILDING_DAILY=1
SABAYON_RELEASE=$(get_default_sabayon_release)
SOURCE_SPECS+=(
"sabayon-amd64-spinbase.spec"
"sabayon-amd64-spinbase-dev.spec"
)
SOURCE_SPECS_ISO+=(
"${DISTRO_NAME}_${ISO_TAG}_amd64_SpinBase.iso"
"${DISTRO_NAME}_${ISO_TAG}_amd64_SpinBase-dev.iso"
)
elif [ "${ACTION}" = "monthly" ] || [ "${ACTION}" = "release" ]; then
if [ "${ACTION}" = "monthly" ] && [ -z "${SABAYON_RELEASE}" ]; then
# always one month ahead
SABAYON_RELEASE=$(/bin/date -u --date="$(/bin/date -u +%Y-%m-%d) +1 month" "+%y.%m")
fi
if [ -z "${SABAYON_RELEASE}" ]; then # release action must set this
echo "SABAYON_RELEASE is not set, wtf?" >&2
exit 1
fi
# Rewrite ISO_TAG to SABAYON_RELEASE
ISO_TAG="${SABAYON_RELEASE}"
if [ "${ACTION}" = "monthly" ]; then
OLD_ISO_TAG=$(date -u --date="last month" +%y.%m)
if [ -z "${OLD_ISO_TAG}" ]; then
echo "Cannot set OLD_ISO_TAG, wtf?" >&2
exit 1
fi
fi
ISO_DIR="monthly"
_previous_month=$(date -d "- 1 month" "+%Y-%m-%d")
_current_month=$(date +%Y-%m-%d)
CHANGELOG_DATES="${_previous_month} ${_current_month}"
mkdir -p "${CHANGELOG_DIR}" || exit 1
SOURCE_SPECS+=(
"sabayon-amd64-spinbase.spec"
)
SOURCE_SPECS_ISO+=(
"${DISTRO_NAME}_${ISO_TAG}_amd64_SpinBase.iso"
)
REMASTER_SPECS+=(
"sabayon-amd64-gnome.spec"
"sabayon-amd64-kde.spec"
"sabayon-amd64-mate.spec"
"sabayon-amd64-xfce.spec"
"sabayon-amd64-minimal.spec"
"sabayon-amd64-server.spec"
)
REMASTER_SPECS_ISO+=(
"${DISTRO_NAME}_${ISO_TAG}_amd64_GNOME.iso"
"${DISTRO_NAME}_${ISO_TAG}_amd64_KDE.iso"
"${DISTRO_NAME}_${ISO_TAG}_amd64_MATE.iso"
"${DISTRO_NAME}_${ISO_TAG}_amd64_Xfce.iso"
"${DISTRO_NAME}_${ISO_TAG}_amd64_Minimal.iso"
"${DISTRO_NAME}_${ISO_TAG}_amd64_Server.iso"
)
REMASTER_TAR_SPECS+=(
"sabayon-amd64-spinbase-tarball-template.spec"
)
REMASTER_TAR_SPECS_TAR+=(
"${DISTRO_NAME}_${ISO_TAG}_amd64_tarball.tar.gz"
)
fi
DAILY_TMPDIR=
# molecules are referencing ISO_TAG in their source_iso parameter
export ISO_TAG
export ETP_NONINTERACTIVE=1
LOG_FILE="/var/log/molecule/autobuild-${SABAYON_RELEASE}-pid-${$}-rnd-${RANDOM}.log"
# to make ISO remaster spec files working (pre_iso_script) and
# make molecules grab a proper release version
export SABAYON_RELEASE
echo "DO_PUSH=${DO_PUSH}"
echo "DO_PUSHONLY=${DO_PUSHONLY}"
echo "DO_SLEEPNIGHT=${DO_SLEEPNIGHT}"
echo "LOG_FILE=${LOG_FILE}"
sleepnight() {
if [ "${DO_SLEEPNIGHT}" = "1" ]; then
target_h=22 # 22pm
current_h=$(date +%H)
current_h=${current_h/0} # remove leading 0
delta_h=$(( target_h - current_h ))
if [ ${current_h} -ge 0 ] && [ ${current_h} -le 6 ]; then
# If it's past midnight and no later than 7am
# just push
echo "Just pusing out now"
elif [ ${delta_h} -gt 0 ]; then
delta_s=$(( delta_h * 3600 ))
echo "Sleeping for ${delta_h} hours..."
sleep ${delta_s} || exit 1
elif [ ${delta_h} -lt 0 ]; then
# between 22 and 24, run!
echo "I'm after 22pm, running"
else
echo "No need to sleep"
fi
fi
}
# Create log dir if it does not exist
mkdir -p /var/log/molecule || exit 1
# Use /var/cache/molecule instead of /var/tmp
# Because systemd may decide to reap it.
# Molecule supports MOLECULE_TMPDIR
export MOLECULE_TMPDIR="/var/cache/molecule"
mkdir -p "${MOLECULE_TMPDIR}" || exit 1
cleanup_on_exit() {
if [ -n "${DAILY_TMPDIR}" ] && [ -d "${DAILY_TMPDIR}" ]; then
rm -rf "${DAILY_TMPDIR}"
# don't care about races
DAILY_TMPDIR=""
fi
}
trap "cleanup_on_exit" EXIT INT TERM
safe_run() {
local done=0
local count="${1}"
shift
for ((i=0; i < ${count}; i++)); do
"${@}" && {
done=1;
break;
}
if [ ${i} -le 3 ]; then
sleep 10 || return 1
elif [ ${i} -le 6 ]; then
sleep 600 || return 1
else
sleep 1800 || return 1
fi
done
if [ "${done}" = "0" ]; then
return 1
fi
return 0
}
remove_from_mirrors() {
local path="${1}"
local server="entropy@pkg.sabayon.org"
local ssh_dir="/sabayon/rsync"
local ssh_path="${server}:${ssh_dir}"
if [ -z "${path}" ]; then
echo "remove_from_mirrors: no arguments passed" >&2
return 1
fi
safe_run 10 ssh "${server}" \
rm -f "${ssh_dir}/rsync.sabayon.org/iso/${ISO_DIR}/${path}"
}
move_to_mirrors() {
local do_push="${SABAYON_MOLECULE_HOME}"/DO_PUSH
local server="entropy@pkg.sabayon.org"
local ssh_dir="/sabayon/rsync"
local ssh_path="${server}:${ssh_dir}"
if [ -n "${DO_PUSH}" ] || [ -f "${do_push}" ]; then
sleepnight
rm -f "${do_push}"
(
flock --timeout $((24 * 3600)) -x 9
if [ "${?}" != "0" ]; then
echo "Timed out during move_to_mirrors lock contention" >&2
exit 1
fi
safe_run 10 rsync -av --partial --bwlimit=1024 \
"${SABAYON_MOLECULE_HOME}"/iso_rsync/*"${ISO_TAG}"* \
"${ssh_path}/rsync.sabayon.org/iso/${ISO_DIR}" \
|| exit 1
if [ "${ACTION}" = "monthly" ]; then
mkdir -p "${SABAYON_MOLECULE_HOME}/iso_rsync/${ISO_DIR}" || exit 1
echo "${ISO_TAG}" > "${SABAYON_MOLECULE_HOME}/iso_rsync/${ISO_DIR}/LATEST_IS" || exit 1
safe_run 10 rsync -av --partial \
"${SABAYON_MOLECULE_HOME}/iso_rsync/${ISO_DIR}/LATEST_IS" \
"${ssh_path}/rsync.sabayon.org/iso/${ISO_DIR}/" \
|| exit 1
fi
if [ -n "${CHANGELOG_DATES}" ]; then
safe_run 10 rsync -av --partial \
"${CHANGELOG_DIR}"/ \
"${ssh_path}/rsync.sabayon.org/iso/${ISO_DIR}/ChangeLogs/"
fi
safe_run 10 rsync -av --partial \
"${SABAYON_MOLECULE_HOME}"/scripts/gen_html \
"${ssh_path}"/iso_html_generator \
|| exit 1
safe_run 10 ssh "${server}" \
"${ssh_dir}"/iso_html_generator/gen_html/gen.sh \
|| exit 1
) 9> /tmp/.iso_build.sh.move_to_mirrors.lock || return 1
return 0
fi
}
docker_clean() {
# Best effort - cleaning orphaned containers
docker ps -a -q | xargs -n 1 -I {} sudo docker rm {}
# Best effort - cleaning orphaned images
local images=$(docker images | grep '<none>' | tr -s ' ' | cut -d ' ' -f 3)
if [ -n "${images}" ]; then
docker rmi ${images}
fi
}
build_spinbase() {
# Generating the spinbase with docker
local docker_image=${1-sabayon/spinbase-amd64:latest}
local undocker_output_directory=${2-sources/amd64-docker-spinbase}
echo "Building Spinbase with Docker image: "${docker_image}
# Cleaning previous generation
if [ -z "${undocker_output_directory}" ] || [ -z "${SABAYON_MOLECULE_HOME}" ]; then
echo "SABAYON_MOLECULE_HOME or undocker_output_directory not set, this is bad"
return 1
fi
rm -rf "${SABAYON_MOLECULE_HOME}"/"${undocker_output_directory}"
echo "Exporting the Docker image in: " ${SABAYON_MOLECULE_HOME}/${undocker_output_directory}
curl -s https://api.github.com/repos/mudler/docker-companion/releases/latest \
| grep "browser_download_url.*amd64" \
| cut -d : -f 2,3 \
| tr -d \" \
| wget -i - -O "${SABAYON_MOLECULE_HOME}"/bin/docker-companion \
&& chmod +x "${SABAYON_MOLECULE_HOME}"/bin/docker-companion
# Unpack the image
"${SABAYON_MOLECULE_HOME}"/bin/docker-companion --pull unpack "${docker_image}" "${SABAYON_MOLECULE_HOME}"/"${undocker_output_directory}" || return 1
docker_clean
}
build_sabayon() {
DAILY_TMPDIR=$(mktemp -d --suffix=.iso_build.sh --tmpdir=/tmp)
[[ -z "${DAILY_TMPDIR}" ]] && return 1
DAILY_TMPDIR_REMASTER="${DAILY_TMPDIR}/remaster"
mkdir "${DAILY_TMPDIR_REMASTER}" || return 1
build_spinbase || return 1
local scripts_dir="${SABAYON_MOLECULE_HOME}/scripts"
local inner_chroot="${scripts_dir}/inner_source_chroot_update.sh"
local source_specs=()
for i in ${!SOURCE_SPECS[@]}; do
src="${SABAYON_MOLECULE_HOME}/molecules/${SOURCE_SPECS[i]}"
dst="${DAILY_TMPDIR}/${SOURCE_SPECS[i]}"
cp "${src}" "${dst}" -p || return 1
echo >> "${dst}"
echo "inner_source_chroot_script: ${inner_chroot}" >> "${dst}"
# tweak iso image name
sed -i "s/destination_iso_image_name:.*/destination_iso_image_name: ${SOURCE_SPECS_ISO[i]}/" \
"${dst}" || return 1
echo -n "${dst}: iso: ${SOURCE_SPECS_ISO[i]} "
echo "release: ${SABAYON_RELEASE}"
source_specs+=( "${dst}" )
done
local remaster_specs=()
for i in ${!REMASTER_SPECS[@]}; do
src="${SABAYON_MOLECULE_HOME}/molecules/${REMASTER_SPECS[i]}"
dst="${DAILY_TMPDIR_REMASTER}/${REMASTER_SPECS[i]}"
cp "${src}" "${dst}" -p || return 1
# tweak iso image name
sed -i "s/destination_iso_image_name:.*/destination_iso_image_name: ${REMASTER_SPECS_ISO[i]}/" \
"${dst}" || return 1
echo -n "${dst}: iso: ${REMASTER_SPECS_ISO[i]} "
echo "release: ${SABAYON_RELEASE}"
remaster_specs+=( "${dst}" )
done
for i in ${!REMASTER_TAR_SPECS[@]}; do
src="${SABAYON_MOLECULE_HOME}/molecules/${REMASTER_TAR_SPECS[i]}"
dst="${DAILY_TMPDIR_REMASTER}/${REMASTER_TAR_SPECS[i]}"
cp "${src}" "${dst}" -p || return 1
# tweak tar name
sed -i "s/tar_name:.*/tar_name: ${REMASTER_TAR_SPECS_TAR[i]}/" "${dst}" || return 1
echo -n "${dst}: tar: ${REMASTER_TAR_SPECS_TAR[i]} "
echo "release: ${SABAYON_RELEASE}"
remaster_specs+=( "${dst}" )
done
local done_images=0
local done_iso=0
local done_something=0
if [ ${#source_specs[@]} != 0 ]; then
(
flock --timeout $((24 * 3600)) -x 9
if [ "${?}" != "0" ]; then
echo "Timed out during source_specs lock contention" >&2
exit 1
fi
molecule --nocolor "${source_specs[@]}" || exit 1
) 9> /tmp/.iso_build.sh.source_specs.lock || return 1
done_something=1
done_iso=1
fi
if [ ${#remaster_specs[@]} != 0 ]; then
molecule --nocolor "${remaster_specs[@]}" || return 1
done_something=1
done_iso=1
fi
# package phases keep loading dbus, let's kill pids back
ps ax | grep -- "/usr/bin/dbus-daemon --fork .* --session" | awk '{ print $1 }' | xargs kill 2> /dev/null
if [ "${done_something}" = "1" ]; then
if [ -n "${MAKE_TORRENTS}" ]; then
flock -x /tmp/.iso_build.sh.make_torrents.lock \
"${SABAYON_MOLECULE_HOME}"/scripts/make_torrents.sh || return 1
fi
if [ "${done_iso}" = "1" ]; then
cp -p "${SABAYON_MOLECULE_HOME}"/iso/*"${ISO_TAG}"* \
"${SABAYON_MOLECULE_HOME}"/iso_rsync/ || return 1
fi
date > "${SABAYON_MOLECULE_HOME}"/iso_rsync/RELEASE_DATE_"${ISO_TAG}"
# remove old ISO images?
if [ -n "${OLD_ISO_TAG}" ]; then
echo "Removing old ISO images tagged ${OLD_ISO_TAG} locally"
rm -rf "${SABAYON_MOLECULE_HOME}"/{iso,iso_rsync}/"${DISTRO_NAME}"*"${OLD_ISO_TAG}"*
echo "Removing old ISO images tagged ${OLD_ISO_TAG} remotely"
remove_from_mirrors "${DISTRO_NAME}*${OLD_ISO_TAG}*"
remove_from_mirrors "RELEASE_DATE_${OLD_ISO_TAG}"
fi
fi
if [ -n "${CHANGELOG_DATES}" ]; then
flock -x /tmp/.iso_build.sh.make_git_logs.lock \
"${SABAYON_MOLECULE_HOME}"/scripts/make_git_logs.sh \
"${CHANGELOG_DIR}" ${CHANGELOG_DATES}
fi
return 0
}
mail_failure() {
local out=${1}
local log_file=${2}
local log_cont=
# get the last 64 lines of the file
if [ -f "${log_file}" ]; then
log_cont=$(tail -n 64 "${log_file}" 2> /dev/null)
fi
echo "Hello there,
iso_build.sh execution failed (miserably) with exit status: ${out}.
Log file is at: ${log_file}
Last log lines:
[... snip ...]
${log_cont}
[... snip ...]
Thanks,
Sun" | /bin/mail -s "${ACTION} images build script failure" root
}
mail_success() {
echo "Hello there,
New ${ACTION} images tagged as ${ISO_TAG} have been built and pushed to mirrors.
http://www.sabayon.org/latest (node/306) will be updated in 24 hours automatically.
" | /bin/mail -s "Action required: ${ACTION} ${ISO_TAG} images built" root
}
out=0
if [ -n "${DO_STDOUT}" ]; then
if [ -z "${DO_PUSHONLY}" ]; then
build_sabayon
out=${?}
fi
if [ "${out}" = "0" ]; then
move_to_mirrors
out=${?}
fi
else
if [ -z "${DO_PUSHONLY}" ]; then
build_sabayon &> "${LOG_FILE}"
out=${?}
fi
if [ "${out}" = "0" ]; then
move_to_mirrors &>> "${LOG_FILE}"
out=${?}
fi
if [ "${out}" != "0" ]; then
# mail root
mail_failure "${out}" "${LOG_FILE}"
else
if [ "${ACTION}" = "monthly" ] || [ "${ACTION}" = "release" ]; then
mail_success
fi
fi
fi
echo "EXIT_STATUS: ${out}"
exit ${out}