klayout/macbuild/KLayoutNightlyBuild.Bash

284 lines
8.2 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/bin/bash
#----------------------------------------------------------------------
# File: KLayoutNightlyBuild.Bash
#
# What: The Bash contents for "KLayoutNightlyBuild.app" script bundle
# that invokes 'nightlyBuild.py' for automation.
#
# Last modified: 2025-11-05
#----------------------------------------------------------------------
dryrun="no"
#-------------------------------------------------------------------------
# Tool logging
#-------------------------------------------------------------------------
set -Eeuo pipefail
export LANG=en_US.UTF-8
export LC_ALL=en_US.UTF-8
LOG="/tmp/KLayoutNightlyBuild.$(date +%Y%m%d-%H%M%S).log"
{
echo "=== START $(date) ==="
echo "whoami: $(whoami)"
echo "pwd: $(pwd)"
echo "shell: $SHELL"
echo "osvers: $(sw_vers -productVersion)"
echo "ENV (partial):"
env | grep -E '^(PATH|HOME|LANG|LC_|MyEmail)' | sort
} >>"$LOG" 2>&1
BASH_XTRACEFD=9
exec 9>>"$LOG"
set -x
exec >>"$LOG" 2>&1
#-------------------------------------------------------------------------
# Detect and set the OS name.
#-------------------------------------------------------------------------
osvers=$(sw_vers -productVersion)
osname=$(sw_vers -productName)
case "$osvers" in
12.*) osname="Monterey" ;;
13.*) osname="Ventura" ;;
14.*) osname="Sonoma" ;;
15.*) osname="Sequoia" ;;
26.*) osname="Tahoe" ;;
*) osname="Unknown" ;;
esac
#-------------------------------------------------------------------------
# Set PATH
# to use /opt/local/bin/addr2line -> gaddr2line in MacPorts.
#-------------------------------------------------------------------------
export PATH=/opt/local/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
#-------------------------------------------------------------------------
# Decide PYBIN (priority: env → MacPorts → Homebrew → Anaconda → /usr/bin)
# KLAYOUT_PYBIN or PYBIN
#-------------------------------------------------------------------------
PYBIN_CANDIDATES=()
# launchctl setenv KLAYOUT_PYBIN ... will work
[[ -n "${KLAYOUT_PYBIN:-}" ]] && PYBIN_CANDIDATES+=("$KLAYOUT_PYBIN")
[[ -n "${PYBIN:-}" ]] && PYBIN_CANDIDATES+=("$PYBIN")
# candidates
PYBIN_CANDIDATES+=(
/opt/local/bin/python3 # MacPorts
/usr/local/bin/python3 # Homebrew (Intel)
/opt/homebrew/bin/python3 # Homebrew (Apple Silicon)
/Applications/anaconda3/bin/python3 # Anaconda
/usr/bin/python3 # System
)
PYBIN=""
for p in "${PYBIN_CANDIDATES[@]}"; do
if [[ -n "$p" && -x "$p" ]]; then
PYBIN="$p"
break
fi
done
if [[ -z "$PYBIN" ]]; then
echo "[FATAL] python3 not found. Tried: ${PYBIN_CANDIDATES[*]}"
exit 127
fi
echo "[INFO] Using PYBIN=$PYBIN"
"$PYBIN" -V || true
#-------------------------------------------------------------------------
# Set build parameters
#-------------------------------------------------------------------------
workdir=$HOME/GitWork/klayout
passbox=$HOME/Dropbox/PrivatePassBox
drylog=nightlyBuild-dryrun.log
jobsCSV=nightlyBuild.csv
#-------------------------------------------------------------------------
# Set mailer (postfix) parameters
#
# launchctl setenv MyEmail1 "my_real_email_address_1"
# launchctl setenv MyEmail2 "my_real_email_address_2"
#
# launchctl getenv MyEmail1
# launchctl getenv MyEmail2
#-------------------------------------------------------------------------
if [[ -z "${MyEmail1:-}" || -z "${MyEmail2:-}" ]]; then
if [[ -f "$HOME/.klayout_env" ]]; then
# shellcheck disable=SC1090
source "$HOME/.klayout_env"
fi
fi
# Re-check
MyEmail1_val="${MyEmail1:-}"
MyEmail2_val="${MyEmail2:-}"
if [[ -z "$MyEmail1_val" ]]; then
echo "[FATAL] MyEmail1 is not set. Run: launchctl setenv MyEmail1 'you@example.com'"
exit 64
fi
if [[ -z "$MyEmail2_val" ]]; then
echo "[WARN] MyEmail2 is not set. Cc will be empty."
fi
title="Status of KLayout <nightlyBuild.py>"
addrFrom=$MyEmail1_val
addrTo=$MyEmail1_val
addrCc=$MyEmail2_val
mailer="sendmail"
sleeptime=5
####----------------------------------------------------------------------
#### Initialize
####----------------------------------------------------------------------
function Initialize()
{
cd "$workdir"
echo "[$(date '+%Y-%m-%d %H:%M:%S')] PATH=$PATH PYBIN=$PYBIN" >> "$workdir/nightlyBuild-env.log"
if [ -f "$jobsCSV" ]; then
targetOp="--qttarget=$jobsCSV"
else
targetOp=""
fi
if [ -L ./nightlyBuild.py ]; then
echo "OK! nightlyBuild.py symbolic link exists ..."
else
ln -s ./macbuild/nightlyBuild.py .
fi
if [ "$dryrun" == "yes" ]; then
cmd=( "./nightlyBuild.py" $targetOp --build --pymod --dryrun )
dryout="> $drylog"
else
cmd=( "./nightlyBuild.py" $targetOp --build --pymod --test )
dryout=""
fi
line1="### Initialized Nightly Build ###"
line2=" OS: $osname"
msg1=$(printf "%s\n%s\n%s\n" "$line1" "$line2" "${cmd[*]}")
SendMail "$msg1"
}
####----------------------------------------------------------------------
#### Upload log files
####----------------------------------------------------------------------
function UploadLog()
{
shopt -s nullglob
logfiles=(*.log)
[ ${#logfiles[@]} -gt 0 ] && cp -p "${logfiles[@]}" "$passbox"
shopt -u nullglob
}
####----------------------------------------------------------------------
#### Build
####----------------------------------------------------------------------
function Build()
{
# Prepare build log file
buildlogfile="$workdir/nightlyBuild-$(date +%Y%m%d-%H%M%S).log"
timestamp_start=$(date "+%Y-%m-%d %H:%M:%S")
echo "===== Nightly Build Started at $timestamp_start =====" > $buildlogfile
# Start caffeinate in background to prevent sleep
# -d : Prevent display sleep
# -i : Prevent idle sleep
# -m : Prevent disk sleep
# -s : Prevent system sleep
# -u : Declare user activity (optional)
#caffeinate -dimsu &
caffeinate -imsu &
caff_pid=$!
logmsg1="Started caffeinate (PID=$caff_pid) to prevent sleep during build"
echo "$logmsg1" | tee -a $buildlogfile
# Prepare trap cleanup message
cleanupmsg="Cleaning up caffeinate (PID=$caff_pid)"
# Set trap
trap "echo '$cleanupmsg' | tee -a $buildlogfile; kill $caff_pid 2>/dev/null || true; wait $caff_pid 2>/dev/null || true" INT TERM EXIT
# Run the build and test command
build_test_cmd=( "$PYBIN" "${cmd[@]}" )
echo "Executing: ${build_test_cmd[*]} $dryout" | tee -a "$buildlogfile"
if [ "$dryrun" == "yes" ]; then
"${build_test_cmd[@]}" >"$drylog" 2>&1
else
"${build_test_cmd[@]}"
fi
build_status=$?
# Stop caffeinate
kill "$caff_pid" 2>/dev/null || true
wait "$caff_pid" 2>/dev/null || true
logmsg2="Stopped caffeinate (PID=$caff_pid)"
echo "$logmsg2" | tee -a $buildlogfile
# Clear trap
trap - INT TERM EXIT
# Build result handling
timestamp_end=$(date "+%Y-%m-%d %H:%M:%S")
echo "===== Nightly Build Ended at $timestamp_end =====" >> $buildlogfile
if [ $build_status -ne 0 ]; then
line1="!!! Failed Nightly Build !!!"
line2=" OS: $osname"
msg2=$(printf "%s\n%s\n%s\n" "$line1" "$line2" "${cmd[*]}")
echo "$msg2" >> $buildlogfile
UploadLog
else
line1="### Succeeded Nightly Build ###"
line2=" OS: $osname"
msg2=$(printf "%s\n%s\n%s\n" "$line1" "$line2" "${cmd[*]}")
echo "$msg2" >> $buildlogfile
if [ "$dryrun" == "yes" ]; then
UploadLog
fi
fi
# Send mail with entire build log
SendMail "$(cat $buildlogfile)"
return $build_status
}
####----------------------------------------------------------------------
#### Send mail
####----------------------------------------------------------------------
function SendMail() {
$mailer -i -t <<EOF
From: $addrFrom
To: $addrTo
Cc: $addrCc
Subject: $title
Content-Type: text/plain; charset=UTF-8
$1
EOF
}
####----------------------------------------------------------------------
#### Sleep
####----------------------------------------------------------------------
function Sleep()
{
sleep $1
# 10 = 10s => 10 seconds
# 5m => 5 minutes
}
####----------------------------------------------------------------------
#### Main
####----------------------------------------------------------------------
Initialize
Build
exit $?
# EOF