#!/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 ]