Merge pull request #14796 from omacom/fix/user-units-not-shipped

Enable first-run units one at a time, and test that units are shipped
This commit is contained in:
Emir Beganović authored and GitHub committed 2026-10-10 02:43:32 +02:00
commit 7cc6a55f24
3 files changed
+71 -2

No files matched your search

+27
View File
@@ -108,6 +108,7 @@ pass "default bar widget ids resolve to manifests and entry points"
ROOT="$ROOT" python3 <<'PY'
import os
import re
import sys
from pathlib import Path
@@ -173,6 +174,32 @@ for source, destination, legacy in package_defaults:
if destination and (source not in pkgbuild or destination not in pkgbuild):
errors.append(f"PKGBUILD does not explicitly install {source} -> {destination}")
# A user unit has to be on the machine before anything turns it on: shipped in
# /usr/lib/systemd/user, or copied out of default/ by the command enabling it.
def installs_first(text):
source = re.search(r'(\w+)="[^"\n]*default/systemd/user/', text)
held = rf"|\$\{{?{source[1]}\b" if source else ""
copy = re.search(rf"^[ \t]*(?:sudo[ \t]+)?(?:install|cp)\b[^\n]*(?:default/systemd/user/{held})", text, re.MULTILINE)
enable = text.find("systemctl --user enable")
return bool(copy) and (enable < 0 or copy.start() < enable)
named = 'unit="$OMARCHY_PATH/default/systemd/user/a.service"\n'
if installs_first(named + "systemctl --user enable a.service\n"):
errors.append("unit check accepts a command that names a unit's source but never installs it")
if installs_first(named + 'systemctl --user enable a.service\ninstall -Dm644 "$unit" "$target"\n'):
errors.append("unit check accepts a command that installs a unit after enabling it")
scripts = [path.read_text(errors="ignore") for folder in ("bin", "install", "migrations")
for path in (root / folder).rglob("*") if path.is_file()]
for unit in sorted(path.name for path in (root / "default/systemd/user").glob("*.service")):
if f"/usr/lib/systemd/user/{unit}" in pkgbuild:
continue
named = [text for text in scripts if unit in text]
if not any(installs_first(text) for text in named):
errors.append(f"PKGBUILD does not ship default/systemd/user/{unit} and no command installs it")
elif any("systemctl --user enable" in text and not installs_first(text) for text in named):
errors.append(f"{unit} is enabled without being shipped by PKGBUILD or installed first")
# Existing users have an absolute wants symlink to the old unit path, and the
# migration that repoints it only runs for users who run an update -- the
# opposite of who the notifier is for. Dropping this alias strands them.
+35
View File
@@ -33,3 +33,38 @@ if grep -F 'skip-first-run-update-notification' "$ROOT/install/user/first-run/wi
fi
pass "first-run uses one lifecycle completion marker"
# systemctl enables none of a list when one unit in it is unknown, so a unit
# missing from a build must cost first-run only that unit.
cat >"$mock_bin/systemctl" <<'SH'
#!/bin/bash
[[ $* != *"$OMARCHY_TEST_MISSING_UNIT"* ]] || exit 1
printf '%s\n' "$*" >>"$OMARCHY_TEST_CALLS"
SH
cat >"$mock_bin/omarchy-hook-install" <<'SH'
#!/bin/bash
echo "hook $*" >>"$OMARCHY_TEST_CALLS"
SH
chmod +x "$mock_bin/systemctl" "$mock_bin/omarchy-hook-install"
enable_user_units() {
rm -f "$test_tmp/calls"
PATH="$mock_bin:$PATH" OMARCHY_TEST_CALLS="$test_tmp/calls" OMARCHY_TEST_MISSING_UNIT="$1" \
bash "$ROOT/install/user/first-run/enable-user-units.sh"
}
enable_user_units no-such-unit || fail "first-run enables its user units"
clean_run=$(<"$test_tmp/calls")
grep -Fq 'hook theme-set' <<<"$clean_run" || fail "first-run installs the theme hook"
mapfile -t units < <(sed -n 's/^--user enable --now //p' <<<"$clean_run")
for unit in "${units[@]}"; do
[[ $unit != *" "* ]] || fail "first-run enables each unit on its own" "$unit"
if enable_user_units "$unit"; then
fail "first-run reports a unit it could not enable" "$unit"
fi
[[ $(<"$test_tmp/calls") == "$(grep -Fvx -- "--user enable --now $unit" <<<"$clean_run")" ]] ||
fail "a unit missing from the build costs first-run only that unit" "$unit"
done
(( ${#units[@]} > 1 )) || fail "first-run enables each unit on its own"
pass "a unit missing from the build costs first-run only that unit"