feat: initial noctalia-greeter release
QuickShell QML login greeter for greetd, styled after noctalia-shell lockscreen. Runs under niri compositor as _greeter user. Theme is live-synced from noctalia config via runit service. - shell.qml: QuickShell greeter UI + greetd auth flow - sync/: inotifywait theme sync daemon + runit service - greetd/: niri compositor config + wrapper scripts - install.sh: deployment helper - test/check-syntax.sh: 19 syntax/structural checks (0 failures) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
197
test/check-syntax.sh
Executable file
197
test/check-syntax.sh
Executable file
@@ -0,0 +1,197 @@
|
||||
#!/bin/sh
|
||||
# test/check-syntax.sh — static syntax checks for noctalia-greeter
|
||||
# No runtime required. Run from repo root or any location.
|
||||
set -e
|
||||
|
||||
REPO_DIR="$(cd "$(dirname "$0")/.." && pwd)"
|
||||
PASS=0
|
||||
FAIL=0
|
||||
|
||||
ok() { echo " [PASS] $1"; PASS=$((PASS+1)); }
|
||||
fail() { echo " [FAIL] $1"; echo " $2"; FAIL=$((FAIL+1)); }
|
||||
|
||||
echo "=== noctalia-greeter syntax checks ==="
|
||||
echo ""
|
||||
|
||||
# ── Shell scripts ──────────────────────────────────────────────────────────────
|
||||
echo "-- Shell syntax (bash -n) --"
|
||||
|
||||
for f in \
|
||||
"sync/noctalia-greeter-sync" \
|
||||
"sync/run" \
|
||||
"greetd/start-greeter.sh" \
|
||||
"install.sh"
|
||||
do
|
||||
path="$REPO_DIR/$f"
|
||||
if [ ! -f "$path" ]; then
|
||||
fail "$f" "file not found: $path"
|
||||
elif out=$(bash -n "$path" 2>&1); then
|
||||
ok "$f"
|
||||
else
|
||||
fail "$f" "$out"
|
||||
fi
|
||||
done
|
||||
|
||||
# ── Embedded Python snippet ────────────────────────────────────────────────────
|
||||
echo ""
|
||||
echo "-- Python snippet in noctalia-greeter-sync --"
|
||||
|
||||
SYNC="$REPO_DIR/sync/noctalia-greeter-sync"
|
||||
if [ -f "$SYNC" ]; then
|
||||
# Extract python3 heredoc: lines between 'python3 -c "' and closing '"'
|
||||
PY_SNIPPET=$(sed -n '/python3 -c "/,/^" /{ /python3 -c "/d; /^" /d; p }' "$SYNC")
|
||||
if [ -n "$PY_SNIPPET" ]; then
|
||||
if out=$(echo "$PY_SNIPPET" | python3 -c "
|
||||
import ast, sys
|
||||
src = sys.stdin.read()
|
||||
try:
|
||||
ast.parse(src)
|
||||
print('ok')
|
||||
except SyntaxError as e:
|
||||
print('SyntaxError: ' + str(e))
|
||||
sys.exit(1)
|
||||
" 2>&1); then
|
||||
ok "embedded python snippet (ast.parse)"
|
||||
else
|
||||
fail "embedded python snippet" "$out"
|
||||
fi
|
||||
else
|
||||
fail "embedded python snippet" "could not extract snippet from $SYNC"
|
||||
fi
|
||||
else
|
||||
fail "embedded python snippet" "sync script not found"
|
||||
fi
|
||||
|
||||
# ── Niri config ────────────────────────────────────────────────────────────────
|
||||
echo ""
|
||||
echo "-- Niri config (niri validate) --"
|
||||
|
||||
KDL="$REPO_DIR/greetd/niri-greeter.kdl"
|
||||
if [ ! -f "$KDL" ]; then
|
||||
fail "niri-greeter.kdl" "file not found"
|
||||
elif ! command -v niri >/dev/null 2>&1; then
|
||||
echo " [SKIP] niri-greeter.kdl — niri not in PATH"
|
||||
elif out=$(niri validate -c "$KDL" 2>&1); then
|
||||
ok "niri-greeter.kdl"
|
||||
else
|
||||
fail "niri-greeter.kdl" "$out"
|
||||
fi
|
||||
|
||||
# ── QML structural check ───────────────────────────────────────────────────────
|
||||
echo ""
|
||||
echo "-- QML structural check --"
|
||||
|
||||
QML="$REPO_DIR/shell.qml"
|
||||
if [ ! -f "$QML" ]; then
|
||||
fail "shell.qml" "file not found"
|
||||
elif command -v qmllint >/dev/null 2>&1; then
|
||||
if out=$(qmllint "$QML" 2>&1); then
|
||||
ok "shell.qml (qmllint)"
|
||||
else
|
||||
fail "shell.qml (qmllint)" "$out"
|
||||
fi
|
||||
else
|
||||
# Fallback: brace/bracket balance via Python
|
||||
if out=$(python3 - "$QML" << 'EOF'
|
||||
import sys
|
||||
|
||||
path = sys.argv[1]
|
||||
src = open(path).read()
|
||||
depth = 0
|
||||
in_str = False
|
||||
str_char = None
|
||||
i = 0
|
||||
errors = []
|
||||
|
||||
while i < len(src):
|
||||
c = src[i]
|
||||
if in_str:
|
||||
if c == '\\':
|
||||
i += 2
|
||||
continue
|
||||
if c == str_char:
|
||||
in_str = False
|
||||
else:
|
||||
if c in ('"', "'"):
|
||||
in_str = True
|
||||
str_char = c
|
||||
elif c == '{':
|
||||
depth += 1
|
||||
elif c == '}':
|
||||
depth -= 1
|
||||
if depth < 0:
|
||||
line = src[:i].count('\n') + 1
|
||||
errors.append(f"line {line}: unexpected '}}' (depth went negative)")
|
||||
depth = 0
|
||||
i += 1
|
||||
|
||||
if depth != 0:
|
||||
errors.append(f"unbalanced braces: depth={depth} at EOF")
|
||||
|
||||
# Check imports present
|
||||
required = ["import Quickshell", "Quickshell.Services.Greetd", "ShellRoot"]
|
||||
for r in required:
|
||||
if r not in src:
|
||||
errors.append(f"missing expected token: '{r}'")
|
||||
|
||||
if errors:
|
||||
for e in errors:
|
||||
print(e)
|
||||
sys.exit(1)
|
||||
else:
|
||||
print("ok")
|
||||
EOF
|
||||
2>&1); then
|
||||
ok "shell.qml (brace balance + required imports)"
|
||||
else
|
||||
fail "shell.qml" "$out"
|
||||
fi
|
||||
fi
|
||||
|
||||
# ── Required files present ─────────────────────────────────────────────────────
|
||||
echo ""
|
||||
echo "-- Required files present --"
|
||||
|
||||
for f in \
|
||||
"shell.qml" \
|
||||
"sync/noctalia-greeter-sync" \
|
||||
"sync/run" \
|
||||
"greetd/niri-greeter.kdl" \
|
||||
"greetd/start-greeter.sh" \
|
||||
"greetd/config.toml.example" \
|
||||
"install.sh" \
|
||||
"README.md"
|
||||
do
|
||||
path="$REPO_DIR/$f"
|
||||
if [ -f "$path" ]; then
|
||||
ok "$f exists"
|
||||
else
|
||||
fail "$f" "missing: $path"
|
||||
fi
|
||||
done
|
||||
|
||||
# ── Permissions check ──────────────────────────────────────────────────────────
|
||||
echo ""
|
||||
echo "-- Executable bits --"
|
||||
|
||||
for f in \
|
||||
"sync/noctalia-greeter-sync" \
|
||||
"sync/run" \
|
||||
"greetd/start-greeter.sh" \
|
||||
"install.sh"
|
||||
do
|
||||
path="$REPO_DIR/$f"
|
||||
if [ ! -f "$path" ]; then
|
||||
fail "$f" "not found"
|
||||
elif [ -x "$path" ]; then
|
||||
ok "$f is executable"
|
||||
else
|
||||
fail "$f" "not executable (chmod +x $path)"
|
||||
fi
|
||||
done
|
||||
|
||||
# ── Summary ────────────────────────────────────────────────────────────────────
|
||||
echo ""
|
||||
echo "=== Results: $PASS passed, $FAIL failed ==="
|
||||
|
||||
[ "$FAIL" -eq 0 ]
|
||||
Reference in New Issue
Block a user