Skip to content

Commit 82ffa41

Browse files
committed
build: compile plugins in parallel with a central dist merge
compile-multiple.sh ran one Nuitka standalone build per plugin strictly sequentially (~50 min for the 23 Windows plugins). It now compiles up to LFMP_COMPILE_JOBS plugins at once (default 4, the Windows runner's vCPU count): a warm-up run primes Nuitka's download/cache dir, then the rest run through an xargs pool, and a failing compile still aborts the build. compile-one.sh no longer flattens each plugin's .dist into the shared group directory (concurrent runs would race on the shared runtime files such as python3xx.dll). compile-multiple.sh now performs that merge once, serially, after all compiles finish. On Windows the task list is pre-filtered to plugins carrying a .windows marker so the pool is not padded with no-op invocations.
1 parent 74f1d69 commit 82ffa41

2 files changed

Lines changed: 78 additions & 27 deletions

File tree

build/compile-multiple.sh

Lines changed: 72 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,23 @@
11
#!/usr/bin/env bash
2-
# 2025021702
2+
# 2026053001
33

44
# This script can run in a container (absolute paths) or in a Windows-VM.
55

66
set -e -x
77

88
if uname -a | grep -q "_NT"; then
99
# We are on Windows.
10+
IS_WINDOWS='yes'
1011
REPO_DIR="$LFMP_DIR_REPOS"
12+
COMPILE_DIR="$LFMP_DIR_COMPILED"
1113
else
1214
# We are in a container.
15+
IS_WINDOWS='no'
1316
REPO_DIR="/repos"
17+
COMPILE_DIR="/compiled"
1418
fi
1519

16-
if ! uname -a | grep -q "_NT"; then
20+
if [ "$IS_WINDOWS" = 'no' ]; then
1721
# We are in a container.
1822
source /opt/venv/bin/activate
1923
PY_TAG="py$(python3 -c 'import sys; print(f"{sys.version_info.major}{sys.version_info.minor}")')"
@@ -26,10 +30,23 @@ if ! uname -a | grep -q "_NT"; then
2630
fi
2731
python3 --version
2832

29-
# Loop through each plugin in the list.
33+
SCRIPT_DIR="$(dirname "$0")"
34+
COMPILE_ONE="$SCRIPT_DIR/compile-one.sh"
35+
36+
# Number of plugins to compile concurrently. Defaults to 4 (the GitHub Windows
37+
# runner has 4 vCPUs). Override with LFMP_COMPILE_JOBS.
38+
JOBS="${LFMP_COMPILE_JOBS:-4}"
39+
40+
# Capture the optional user-provided plugin list once. The per-group logic
41+
# below mirrors the original behaviour: when a list is given it applies to
42+
# check-plugins only; event-plugins and notification-plugins are skipped.
43+
USER_PLUGIN_LIST="$LFMP_COMPILE_PLUGINS"
44+
45+
# Build a flat list of "<group> <plugin>" tasks to compile.
46+
TASKS=()
3047
for PLUGINS in event-plugins notification-plugins check-plugins ; do
31-
if [[ ! -z "$LFMP_COMPILE_PLUGINS" && "$PLUGINS" != "check-plugins" ]]; then
32-
# if check-plugin list is given, skip event-plugins and notification-plugins to save time
48+
if [[ -n "$USER_PLUGIN_LIST" && "$PLUGINS" != "check-plugins" ]]; then
49+
# if a check-plugin list is given, skip event-plugins and notification-plugins to save time
3350
echo "✅ Skipping $REPO_DIR/monitoring-plugins/$PLUGINS..."
3451
continue
3552
fi
@@ -39,30 +56,68 @@ for PLUGINS in event-plugins notification-plugins check-plugins ; do
3956
fi
4057
echo "✅ Processing $PLUGINS..."
4158

42-
# If $LFMP_COMPILE_PLUGINS is empty, find all plugin directories under
43-
# $REPO_DIR/monitoring-plugins/$PLUGINS/ and create a space-separated list.
44-
if [[ -z "$LFMP_COMPILE_PLUGINS" ]]; then
59+
if [[ -z "$USER_PLUGIN_LIST" ]]; then
4560
echo "✅ No plugin list provided. Discovering all plugins..."
46-
# Find directories immediately under $PLUGINS/, extract their basenames, and join them with commas.
47-
LFMP_COMPILE_PLUGINS=$(
61+
# List the directories immediately under $PLUGINS/ by basename.
62+
# avoid using `find` as this is sometimes problematic in Github runners
63+
GROUP_PLUGINS=$(
4864
for d in "$REPO_DIR/monitoring-plugins/$PLUGINS"/*; do
4965
[ -d "$d" ] && basename "$d"
5066
done | sort
51-
) # avoid using `find` as this is sometimes problematic in Github runners
52-
echo "✅ Found '$LFMP_COMPILE_PLUGINS'"
67+
)
68+
echo "✅ Found '$GROUP_PLUGINS'"
69+
else
70+
GROUP_PLUGINS="$USER_PLUGIN_LIST"
5371
fi
5472

55-
for PLUGIN in $LFMP_COMPILE_PLUGINS; do
73+
for PLUGIN in $GROUP_PLUGINS; do
5674
if [ "$PLUGIN" == "example" ]; then
5775
continue
5876
fi
59-
if [[ -d "$REPO_DIR/monitoring-plugins/$PLUGINS/$PLUGIN" ]]; then
60-
bash $(dirname "$0")/compile-one.sh $PLUGINS $PLUGIN
61-
else
77+
if [[ ! -d "$REPO_DIR/monitoring-plugins/$PLUGINS/$PLUGIN" ]]; then
6278
echo "✅ Directory $REPO_DIR/$PLUGINS/$PLUGIN does not exist. Ignoring..."
79+
continue
80+
fi
81+
# On Windows only plugins carrying a `.windows` marker get compiled
82+
# (compile-one.sh enforces this too). Filter them out here so the
83+
# parallel pool below is not filled with immediate no-op invocations.
84+
if [[ "$IS_WINDOWS" = 'yes' && ! -f "$REPO_DIR/monitoring-plugins/$PLUGINS/$PLUGIN/.windows" ]]; then
85+
echo "✅ Ignoring '$PLUGIN' on Windows (no .windows marker)"
86+
continue
87+
fi
88+
TASKS+=("$PLUGINS $PLUGIN")
89+
done
90+
done
91+
92+
# Compile. The first plugin runs alone to warm up Nuitka's download/cache dir
93+
# (depends.exe, ccache, ...), so the parallel batch that follows does not race
94+
# on first-time downloads. The rest run up to $JOBS at a time. xargs returns
95+
# non-zero if any invocation fails, so `set -e` aborts the whole build.
96+
if (( ${#TASKS[@]} > 0 )); then
97+
echo "✅ Compiling ${#TASKS[@]} plugin(s), up to $JOBS in parallel..."
98+
read -r WARM_GROUP WARM_PLUGIN <<< "${TASKS[0]}"
99+
bash "$COMPILE_ONE" "$WARM_GROUP" "$WARM_PLUGIN"
100+
if (( ${#TASKS[@]} > 1 )); then
101+
printf '%s\n' "${TASKS[@]:1}" | xargs -P "$JOBS" -L 1 bash "$COMPILE_ONE"
102+
fi
103+
fi
104+
105+
# Merge each plugin's standalone `*.dist` directory into the shared, flattened
106+
# group directory to save disk space (important on Github runners). Done here,
107+
# serially, after all parallel compiles finished, so the shared runtime files
108+
# the plugins all carry (python3xx.dll etc.) are never written concurrently.
109+
# The special `/.` suffix copies only the *contents* of each dist directory.
110+
for PLUGINS in event-plugins notification-plugins check-plugins ; do
111+
GROUP_DIR="$COMPILE_DIR/$PLUGINS"
112+
[ -d "$GROUP_DIR" ] || continue
113+
for DIST in "$GROUP_DIR"/*.dist ; do
114+
[ -d "$DIST" ] || continue
115+
if [ -n "$(ls --almost-all "$DIST")" ]; then
116+
echo "✅ cp --archive $DIST/. $GROUP_DIR/"
117+
\cp --archive "$DIST"/. "$GROUP_DIR"/
63118
fi
119+
rm -rf "$DIST"
64120
done
65-
LFMP_COMPILE_PLUGINS=""
66121
done
67122

68123
# On RHEL? Then also compile the Linuxfabrik Type Enforcement Policy

build/compile-one.sh

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#!/usr/bin/env bash
2-
# 2025021602
2+
# 2026053001
33

44
# This script can run in a container (absolute paths) or in a Windows-VM.
55

@@ -43,12 +43,8 @@ if [[ -e "$COMPILE_DIR/$PLUGINS/$PLUGIN.dist/$PLUGIN.bin" ]]; then
4343
mv "$COMPILE_DIR/$PLUGINS/$PLUGIN.dist/$PLUGIN.bin" "$COMPILE_DIR/$PLUGINS/$PLUGIN.dist/$PLUGIN"
4444
fi
4545

46-
# move files to a merged flattened directory to save disk space if directory exists and is not empty.
47-
if [[ -d "$COMPILE_DIR/$PLUGINS/$PLUGIN.dist" && -n "$(ls --almost-all $COMPILE_DIR/$PLUGINS/$PLUGIN.dist)" ]]; then
48-
# Note that we use the special /.' suffix to copy **only the contents** of the *.dist directory (preserving attributes).
49-
# Unfortunately, mv does not have a built‐in equivalent to "move the contents of a directory" using the/.' trick.
50-
# Therefore we copy and remove later to save disk space, important in github runners.
51-
echo "✅ cp --archive $COMPILE_DIR/$PLUGINS/$PLUGIN.dist/. $COMPILE_DIR/$PLUGINS/"
52-
\cp --archive --verbose $COMPILE_DIR/$PLUGINS/$PLUGIN.dist/. $COMPILE_DIR/$PLUGINS/
53-
rm -rf $COMPILE_DIR/$PLUGINS/$PLUGIN.dist
54-
fi
46+
# The compiled plugin is left in its own `$PLUGIN.dist` directory on purpose.
47+
# Flattening every plugin's dist into the shared `$COMPILE_DIR/$PLUGINS/`
48+
# directory is done centrally by compile-multiple.sh *after* all plugins are
49+
# built, so that several compile-one.sh runs can execute in parallel without
50+
# racing on the shared runtime files (python3xx.dll etc.) they all carry.

0 commit comments

Comments
 (0)