Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 38 additions & 15 deletions skills/ego-lint/scripts/check-schema.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,27 @@ set -euo pipefail

EXT_DIR="$(cd "${1:-.}" && pwd)"

# Extract the schema id from a .gschema.xml file.
# Uses a <schema>-specific grep to avoid picking up <enum id=> or other
# elements that appear before <schema id=> in files with multiple top-level
# elements (e.g. caffeine's schema has three <enum> elements first).
# Extract ALL schema ids from a .gschema.xml file.
# Filters to <schema\b lines to avoid matching <enum id=> or other elements.
extract_all_schema_ids() {
local file="$1"
grep -P '<schema\b' "$file" | grep -oP 'id="[^"]*"' | sed 's/id="//;s/"//'
}

# Extract the first schema id from a .gschema.xml file.
# For single-schema files this is the only schema. For multi-schema files
# (e.g. a main schema + .keybindings sub-schema), prefer using
# extract_all_schema_ids() + targeted matching instead.
extract_schema_id() {
local file="$1"
grep -P '<schema\b' "$file" | grep -oP 'id="[^"]*"' | head -1 | sed 's/id="//;s/"//'
extract_all_schema_ids "$file" | head -1
}

# Return true (0) if a specific schema ID exists anywhere in a .gschema.xml file.
schema_id_in_file() {
local file="$1"
local target_id="$2"
extract_all_schema_ids "$file" | grep -qxF "$target_id"
}

METADATA="$EXT_DIR/metadata.json"
Expand Down Expand Up @@ -63,24 +77,33 @@ echo "PASS|schema/exists|Found ${#schema_files[@]} schema file(s)"
# Validate schema IDs match metadata
if [[ "$has_settings_schema" == true ]]; then
for schema_file in "${schema_files[@]}"; do
# Extract schema id from XML (use extract_schema_id to avoid matching <enum id=> etc.)
schema_id="$(extract_schema_id "$schema_file")"
if [[ "$schema_id" == "$settings_schema" ]]; then
echo "PASS|schema/id-matches|Schema ID '$schema_id' matches metadata.json settings-schema"
# Check whether settings-schema appears as ANY <schema id=> in the file.
# Multi-schema XML (e.g. main schema + .keybindings sub-schema) must not
# fail just because a sub-schema appears first.
if schema_id_in_file "$schema_file" "$settings_schema"; then
echo "PASS|schema/id-matches|Schema ID '$settings_schema' found in $(basename "$schema_file")"
else
echo "FAIL|schema/id-matches|Schema ID '$schema_id' does not match metadata.json settings-schema '$settings_schema'"
all_ids="$(extract_all_schema_ids "$schema_file" | paste -sd ' ')"
echo "FAIL|schema/id-matches|settings-schema '$settings_schema' not found in $(basename "$schema_file") (found: ${all_ids})"
fi
done
fi

# Validate schema filename convention: <schema-id>.gschema.xml
# Validate schema filename convention: <settings-schema>.gschema.xml
# When settings-schema is defined in metadata.json, the file MUST be named
# after that ID (the primary schema). For extensions without settings-schema,
# fall back to the first schema ID found in the file.
for schema_file in "${schema_files[@]}"; do
schema_id="$(extract_schema_id "$schema_file")"
if [[ -n "$schema_id" ]]; then
expected_filename="${schema_id}.gschema.xml"
if [[ "$has_settings_schema" == true ]]; then
ref_id="$settings_schema"
else
ref_id="$(extract_schema_id "$schema_file")"
fi
if [[ -n "$ref_id" ]]; then
expected_filename="${ref_id}.gschema.xml"
actual_filename="$(basename "$schema_file")"
if [[ "$actual_filename" == "$expected_filename" ]]; then
echo "PASS|schema/filename-convention|Schema filename matches ID: $actual_filename"
echo "PASS|schema/filename-convention|Schema filename matches settings-schema: $actual_filename"
else
echo "FAIL|schema/filename-convention|Schema filename '$actual_filename' MUST be '$expected_filename'"
fi
Expand Down
6 changes: 6 additions & 0 deletions tests/fixtures/multi-schema@test/extension.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { Extension } from 'resource:///org/gnome/shell/extensions/extension.js';

export default class MultiSchemaExtension extends Extension {
enable() {}
disable() {}
}
8 changes: 8 additions & 0 deletions tests/fixtures/multi-schema@test/metadata.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"uuid": "multi-schema@test",
"name": "Multi-Schema Test",
"description": "Tests that schema/id-matches passes when settings-schema appears after a sub-schema (e.g. .keybindings) in gschema.xml",
"shell-version": ["48"],
"settings-schema": "org.gnome.shell.extensions.multi-schema",
"url": "https://github.com/test/multi-schema"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<schemalist>
<!-- Sub-schema appears FIRST — this is what caused the PaperWM FP -->
<schema id="org.gnome.shell.extensions.multi-schema.keybindings"
path="/org/gnome/shell/extensions/multi-schema/keybindings/">
<key name="move-left" type="as">
<default>["&lt;Super&gt;Left"]</default>
<summary>Move left keybinding</summary>
</key>
</schema>
<!-- Main schema appears SECOND — must match settings-schema in metadata.json -->
<schema id="org.gnome.shell.extensions.multi-schema"
path="/org/gnome/shell/extensions/multi-schema/">
<key name="enable-feature" type="b">
<default>true</default>
<summary>Enable feature</summary>
</key>
</schema>
</schemalist>
9 changes: 9 additions & 0 deletions tests/run-tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -466,6 +466,15 @@ assert_exit_code "exits with 1 (has failures)" 1
assert_output_contains "fails on schema filename" "\[FAIL\].*schema/filename-convention"
echo ""

# --- multi-schema (sub-schema appears before main schema in XML) ---
echo "=== multi-schema ==="
run_lint "multi-schema@test"
assert_output_not_contains "no schema/id-matches FAIL for multi-schema XML" "\[FAIL\].*schema/id-matches"
assert_output_not_contains "no schema/filename-convention FAIL for multi-schema XML" "\[FAIL\].*schema/filename-convention"
assert_output_contains "id-matches passes for multi-schema XML" "\[PASS\].*schema/id-matches"
assert_output_contains "filename-convention passes for multi-schema XML" "\[PASS\].*schema/filename-convention"
echo ""

# --- gnome46-compat ---
echo "=== gnome46-compat ==="
run_lint "gnome46-compat@test"
Expand Down
Loading