From c887a6f7d87f37b8689c3e7a0a801af52d2fd28e Mon Sep 17 00:00:00 2001 From: Chocobo1 Date: Fri, 13 Dec 2024 16:21:22 +0800 Subject: [PATCH] GHA CI: add checks for grid items order Now all items under `QGridLayout` are required to be sorted. This allow us to omit tabstop order. The tabstop order will follow the layout order. The script can be invoked to fix wrong grid items order in .ui files: ```console python check_grid_items_order.py file.ui ``` --- .github/workflows/ci_python.yaml | 4 +- .../pre-commit/check_grid_items_order.py | 93 +++++++++++++++++++ .../pre-commit/check_translation_tag.py | 6 +- .pre-commit-config.yaml | 6 ++ 4 files changed, 105 insertions(+), 4 deletions(-) create mode 100755 .github/workflows/helper/pre-commit/check_grid_items_order.py diff --git a/.github/workflows/ci_python.yaml b/.github/workflows/ci_python.yaml index 268dd1ecf32..e3183da5ad8 100644 --- a/.github/workflows/ci_python.yaml +++ b/.github/workflows/ci_python.yaml @@ -34,7 +34,7 @@ jobs: - name: Lint code (auxiliary scripts) run: | pyflakes $PY_FILES - bandit --skip B314,B405 $PY_FILES + bandit --skip B101,B314,B405 $PY_FILES - name: Format code (auxiliary scripts) run: | @@ -61,7 +61,7 @@ jobs: echo $PY_FILES echo "PY_FILES=$PY_FILES" >> "$GITHUB_ENV" - - name: Check typings (search engine) + - name: Check typings (search engine) run: | MYPYPATH="src/searchengine/nova3" \ mypy \ diff --git a/.github/workflows/helper/pre-commit/check_grid_items_order.py b/.github/workflows/helper/pre-commit/check_grid_items_order.py new file mode 100755 index 00000000000..30d6fd05710 --- /dev/null +++ b/.github/workflows/helper/pre-commit/check_grid_items_order.py @@ -0,0 +1,93 @@ +#!/usr/bin/env python3 + +# A pre-commit hook for checking items order in grid layouts +# Copyright (C) 2024 Mike Tzou (Chocobo1) +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# In addition, as a special exception, the copyright holders give permission to +# link this program with the OpenSSL project's "OpenSSL" library (or with +# modified versions of it that use the same license as the "OpenSSL" library), +# and distribute the linked executables. You must obey the GNU General Public +# License in all respects for all of the code used other than "OpenSSL". If you +# modify file(s), you may extend this exception to your version of the file(s), +# but you are not obligated to do so. If you do not wish to do so, delete this +# exception statement from your version. + +from collections.abc import Callable, Sequence +from typing import Optional +import argparse +import re +import xml.etree.ElementTree as ElementTree +import sys + + +def traversePostOrder(root: ElementTree.Element, visitFunc: Callable[[ElementTree.Element], None]) -> None: + stack = [(root, False)] + + while len(stack) > 0: + (element, visit) = stack.pop() + if visit: + visitFunc(element) + else: + stack.append((element, True)) + stack.extend((child, False) for child in reversed(element)) + + +def modifyElement(element: ElementTree.Element) -> None: + def getSortKey(e: ElementTree.Element) -> tuple[int, int]: + if e.tag == 'item': + return (int(e.attrib['row']), int(e.attrib['column'])) + return (-1, -1) # don't care + + if element.tag == 'layout' and element.attrib['class'] == 'QGridLayout' and len(element) > 0: + element[:] = sorted(element, key=getSortKey) + + # workaround_2a: ElementTree will unescape `"` and we need to escape it back + if element.tag == 'string' and element.text is not None: + element.text = element.text.replace('"', '"') + + +def main(argv: Optional[Sequence[str]] = None) -> int: + parser = argparse.ArgumentParser() + parser.add_argument('filenames', nargs='*', help='Filenames to check') + args = parser.parse_args(argv) + + for filename in args.filenames: + with open(filename, 'r+') as f: + orig = f.read() + root = ElementTree.fromstring(orig) + traversePostOrder(root, modifyElement) + ElementTree.indent(root, ' ') + + # workaround_1: cannot use `xml_declaration=True` since it uses single quotes instead of Qt preferred double quotes + ret = f'\n{ElementTree.tostring(root, 'unicode')}\n' + + # workaround_2b: ElementTree will turn `"` into `&quot;`, so revert it back + ret = ret.replace('&quot;', '"') + + # workaround_3: Qt prefers no whitespaces in self-closing tags + ret = re.sub('<(.+) +/>', r'<\1/>', ret) + + if ret != orig: + f.seek(0) + f.write(ret) + f.truncate() + + return 0 + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/.github/workflows/helper/pre-commit/check_translation_tag.py b/.github/workflows/helper/pre-commit/check_translation_tag.py index f3d4457e2a0..4be80df492d 100755 --- a/.github/workflows/helper/pre-commit/check_translation_tag.py +++ b/.github/workflows/helper/pre-commit/check_translation_tag.py @@ -26,9 +26,11 @@ # but you are not obligated to do so. If you do not wish to do so, delete this # exception statement from your version. -from typing import Optional, Sequence +from collections.abc import Sequence +from typing import Optional import argparse import re +import sys def main(argv: Optional[Sequence[str]] = None) -> int: @@ -67,4 +69,4 @@ def main(argv: Optional[Sequence[str]] = None) -> int: if __name__ == '__main__': - exit(main()) + sys.exit(main()) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index a4c84ea2d41..e0bc4565d67 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,12 @@ repos: - repo: local hooks: + - id: check-grid-order + name: Check items order in grid layouts + entry: .github/workflows/helper/pre-commit/check_grid_items_order.py + language: script + files: \.ui$ + - id: check-translation-tag name: Check newline characters in tag entry: .github/workflows/helper/pre-commit/check_translation_tag.py