xwayland/ci: Enforce various code style checks

Make sure the code change does not contain tab characters nor stray
newlines.

This is contributed by Peter Hutterer, adapted from the libinput similar
CI check.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/2121>
(cherry picked from commit 9c31b4ad8f)
This commit is contained in:
Olivier Fourdan 2026-01-15 14:26:15 +01:00 committed by Alan Coopersmith
parent 22dcaf44d4
commit e1cd42dcaa
2 changed files with 140 additions and 0 deletions

View file

@ -334,6 +334,13 @@ check-commits:
junit: results.xml
allow_failure: true
check-whitespace:
extends:
- .fdo.ci-fairy
stage: test
script:
- .gitlab-ci/whitespace-check.py $(git ls-files hw/xwayland)
#
# Workflow rules needed due to:
# https://gitlab.freedesktop.org/freedesktop/freedesktop/-/issues/438

133
.gitlab-ci/whitespace-check.py Executable file
View file

@ -0,0 +1,133 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: MIT
from pathlib import Path
from dataclasses import dataclass
import argparse
import itertools
import os
import re
import sys
@dataclass
class WhitespaceError:
message: str
lineno: int
nlines: int = 1
column: None | int = None
ncolumns: int = 1
def test_tab_indent(lines: list[str]) -> list[WhitespaceError]:
errors = []
for idx, l in enumerate(lines):
if re.match("^\t+.*", l):
errors.append(
WhitespaceError(
"Tab indent", idx, ncolumns=2
)
)
return errors
def test_duplicate_empty_lines(lines: list[str]) -> list[WhitespaceError]:
errors = []
for idx, (l1, l2) in enumerate(itertools.pairwise(lines)):
if not l1 and not l2:
errors.append(WhitespaceError("Duplicated empty lines", idx, nlines=2))
return errors
def test_tab_after_space(lines: list[str]) -> list[WhitespaceError]:
errors = []
for idx, l in enumerate(lines):
index = l.find(" \t")
if index > -1:
errors.append(
WhitespaceError(
"Tab after space", idx, nlines=index, column=index, ncolumns=2
)
)
return errors
def test_trailing_whitespace(lines: list[str]) -> list[WhitespaceError]:
errors = []
for idx, l in enumerate(lines):
if l.rstrip() != l:
errors.append(WhitespaceError("Trailing whitespace", idx))
return errors
def test_empty_line_between_braces(lines: list[str]) -> list[WhitespaceError]:
errors = []
for idx in range(len(lines) - 3):
l1 = lines[idx]
l2 = lines[idx + 1]
l3 = lines[idx + 2]
if l1.strip() == "}" and l3.strip() == "}" and l2.strip() == "":
errors.append(WhitespaceError("Empty line between closing braces", idx + 1))
return errors
def main():
parser = argparse.ArgumentParser(description="Whitespace checker script")
parser.add_argument(
"files",
metavar="FILES",
type=Path,
nargs="+",
help="The files to check",
)
args = parser.parse_args()
have_errors: bool = False
if os.isatty(sys.stderr.fileno()):
red = "\x1b[0;31m"
reset = "\x1b[0m"
else:
red = ""
reset = ""
for file in args.files:
lines = [l.rstrip("\n") for l in file.open().readlines()]
errors = []
errors.extend(test_tab_indent(lines))
errors.extend(test_tab_after_space(lines))
errors.extend(test_trailing_whitespace(lines))
if any(file.name.endswith(suffix) for suffix in [".c", ".h"]):
if not file.parts[0] == "include":
errors.extend(test_duplicate_empty_lines(lines))
errors.extend(test_empty_line_between_braces(lines))
for e in errors:
print(f"{red}ERROR: {e.message} in {file}:{reset}", file=sys.stderr)
print(f"{'-' * 72}", file=sys.stderr)
lineno = max(0, e.lineno - 5)
for idx, l in enumerate(lines[lineno : lineno + 10]):
if e.lineno <= lineno + idx < e.lineno + e.nlines:
prefix = "->"
hl = red
nohl = reset
else:
prefix = " "
hl = ""
nohl = ""
print(f"{hl}{lineno + idx:3d}: {prefix} {l.rstrip()}{nohl}")
print(f"{'-' * 72}", file=sys.stderr)
if errors:
have_errors = True
if have_errors:
sys.exit(1)
if __name__ == "__main__":
main()