Files
eepp/projects/scripts/xvfb-run-eepp
Martín Lucas Golini c2b1a91d90 Added the pending flex support tests.
Added xvfb-run-eepp with better defaults than xvfb-run, updated documentation.
2026-05-31 13:14:30 -03:00

247 lines
6.8 KiB
Bash
Executable File

#!/bin/sh
# xvfb-run-eepp: xvfb-run variant with race-safe automatic display selection.
# Defaults tuned for eepp GUI tests:
# --auto-servernum enabled by default
# --server-args "-screen 0 1280x1024x24" enabled by default
# ASAN_OPTIONS includes detect_leaks=0 for the child process
set -e
PROGNAME=${0##*/}
SERVERNUM=99
MAX_SERVERNUM=599
AUTO_SERVERNUM=yes
AUTHFILE=
ERRORFILE=/dev/null
STARTWAIT=3
XVFBARGS="-screen 0 1280x1024x24"
LISTENTCP="-nolisten tcp"
XAUTHPROTO=.
LOCKDIR=
XVFB_RUN_TMPDIR=
XVFBPID=
DEFCOLUMNS=$(stty size 2>/dev/null | awk '{print $2}') || true
case "$DEFCOLUMNS" in
*[!0-9]*|'') DEFCOLUMNS=80 ;;
esac
message() {
echo "$PROGNAME: $*" | fmt -t -w "${COLUMNS:-$DEFCOLUMNS}"
}
error() {
message "error: $*" >&2
}
usage() {
[ -n "$*" ] && message "usage error: $*"
cat <<EOF_USAGE
Usage: $PROGNAME [OPTION ...] COMMAND
Run COMMAND in a virtual X server environment.
Defaults differ from Debian xvfb-run:
--auto-servernum is enabled by default
--server-args defaults to "$XVFBARGS"
ASAN_OPTIONS gets detect_leaks=0 for COMMAND
Options:
-a --auto-servernum try to get a free server number, starting at --server-num [default]
--no-auto-servernum use exactly --server-num
-e FILE --error-file=FILE file used to store xauth errors and Xvfb output (default: $ERRORFILE)
-f FILE --auth-file=FILE file used to store auth cookie
-h --help display this usage message and exit
-n NUM --server-num=NUM first/exact server number to use (default: $SERVERNUM)
--max-server-num=NUM highest server number to try in auto mode (default: $MAX_SERVERNUM)
-l --listen-tcp enable TCP port listening in Xvfb
-p PROTO --xauth-protocol=PROTO X authority protocol name to use (default: xauth default)
-s ARGS --server-args=ARGS arguments to pass to Xvfb (default: "$XVFBARGS")
-w DELAY --wait=DELAY seconds to wait for Xvfb to start when xdpyinfo is unavailable (default: $STARTWAIT)
EOF_USAGE
}
cleanup() {
status=$?
if [ -n "$XVFBPID" ]; then
kill "$XVFBPID" >/dev/null 2>&1 || true
wait "$XVFBPID" >/dev/null 2>&1 || true
fi
if [ -n "$AUTHFILE" ]; then
XAUTHORITY=$AUTHFILE xauth remove ":$SERVERNUM" >"$ERRORFILE" 2>&1 || true
fi
[ -n "$XVFB_RUN_TMPDIR" ] && rm -rf "$XVFB_RUN_TMPDIR" || true
[ -n "$LOCKDIR" ] && rmdir "$LOCKDIR" >/dev/null 2>&1 || true
exit "$status"
}
is_display_busy() {
n=$1
# Xorg/Xvfb convention: lock file plus socket. Check both because stale
# lock files and still-existing sockets can happen independently.
[ -e "/tmp/.X$n-lock" ] && return 0
[ -e "/tmp/.X11-unix/X$n" ] && return 0
return 1
}
claim_display() {
n=$1
lock="${TMPDIR:-/tmp}/$PROGNAME-display-$n.lock"
# mkdir is atomic on local filesystems and avoids the race in classic
# xvfb-run -a, where many jobs can pick the same currently-free display.
if mkdir "$lock" 2>/dev/null; then
LOCKDIR=$lock
SERVERNUM=$n
# Helpful for manual cleanup/debugging. Not used as synchronization.
echo "$$" > "$LOCKDIR/pid" 2>/dev/null || true
return 0
fi
return 1
}
find_and_claim_display() {
i=$SERVERNUM
while [ "$i" -le "$MAX_SERVERNUM" ]; do
if ! is_display_busy "$i" && claim_display "$i"; then
echo "$i"
return 0
fi
i=$((i + 1))
done
return 1
}
wait_for_xvfb() {
if command -v xdpyinfo >/dev/null 2>&1; then
i=0
# Poll for up to about 10 seconds. Avoid requiring sleep fractions.
while [ "$i" -lt 100 ]; do
DISPLAY=:$SERVERNUM XAUTHORITY=$AUTHFILE xdpyinfo >/dev/null 2>&1 && return 0
kill -0 "$XVFBPID" >/dev/null 2>&1 || return 1
sleep 0.1 2>/dev/null || sleep 1
i=$((i + 1))
done
return 1
fi
sleep "$STARTWAIT"
kill -0 "$XVFBPID" >/dev/null 2>&1
}
ARGS=$(getopt --options +ae:f:hn:lp:s:w: \
--long auto-servernum,no-auto-servernum,error-file:,auth-file:,help,server-num:,max-server-num:,listen-tcp,xauth-protocol:,server-args:,wait: \
--name "$PROGNAME" -- "$@")
GETOPT_STATUS=$?
if [ "$GETOPT_STATUS" -ne 0 ]; then
error "internal error; getopt exited with status $GETOPT_STATUS"
exit 6
fi
eval set -- "$ARGS"
SHOWHELP=
while :; do
case "$1" in
-a|--auto-servernum) AUTO_SERVERNUM=yes ;;
--no-auto-servernum) AUTO_SERVERNUM=no ;;
-e|--error-file) ERRORFILE=$2; shift ;;
-f|--auth-file) AUTHFILE=$2; shift ;;
-h|--help) SHOWHELP=yes ;;
-n|--server-num) SERVERNUM=$2; shift ;;
--max-server-num) MAX_SERVERNUM=$2; shift ;;
-l|--listen-tcp) LISTENTCP= ;;
-p|--xauth-protocol) XAUTHPROTO=$2; shift ;;
-s|--server-args) XVFBARGS=$2; shift ;;
-w|--wait) STARTWAIT=$2; shift ;;
--) shift; break ;;
*) error "internal error; getopt permitted '$1' unexpectedly"; exit 6 ;;
esac
shift
done
if [ "$SHOWHELP" ]; then
usage
exit 0
fi
if [ "$#" -eq 0 ]; then
usage "need a command to run" >&2
exit 2
fi
case "$SERVERNUM:$MAX_SERVERNUM" in
*[!0-9:]*|:*|*:)
error "server numbers must be numeric"
exit 2
;;
esac
if ! command -v xauth >/dev/null 2>&1; then
error "xauth command not found"
exit 3
fi
if ! command -v Xvfb >/dev/null 2>&1; then
error "Xvfb command not found"
exit 3
fi
if [ "$AUTO_SERVERNUM" = yes ]; then
if ! SERVERNUM=$(find_and_claim_display); then
error "could not find a free X display between $SERVERNUM and $MAX_SERVERNUM"
exit 4
fi
else
if is_display_busy "$SERVERNUM"; then
error "display :$SERVERNUM is already busy"
exit 4
fi
if ! claim_display "$SERVERNUM"; then
error "display :$SERVERNUM is already claimed by another $PROGNAME process"
exit 4
fi
fi
trap cleanup EXIT INT TERM HUP
if [ -z "$AUTHFILE" ]; then
XVFB_RUN_TMPDIR=$(mktemp -d "${TMPDIR:-/tmp}/$PROGNAME.XXXXXXXX") || {
error "could not create temporary directory"
exit 4
}
AUTHFILE=$(mktemp "$XVFB_RUN_TMPDIR/Xauthority.XXXXXXXX") || {
error "could not create Xauthority file"
exit 4
}
fi
MCOOKIE=$(mcookie)
XAUTHORITY=$AUTHFILE xauth add ":$SERVERNUM" "$XAUTHPROTO" "$MCOOKIE" >"$ERRORFILE" 2>&1
# shellcheck disable=SC2086 # XVFBARGS and LISTENTCP intentionally split like xvfb-run.
Xvfb ":$SERVERNUM" $XVFBARGS $LISTENTCP -auth "$AUTHFILE" >"$ERRORFILE" 2>&1 &
XVFBPID=$!
if ! wait_for_xvfb; then
error "Xvfb failed to start on display :$SERVERNUM; see $ERRORFILE"
exit 1
fi
set +e
ASAN_OPTIONS="${ASAN_OPTIONS:+$ASAN_OPTIONS:}detect_leaks=0" \
DISPLAY=:$SERVERNUM \
XAUTHORITY=$AUTHFILE \
"$@"
RETVAL=$?
set -e
exit "$RETVAL"