diff --git a/.github/workflows/check_templ.yml b/.github/workflows/check_templ.yml deleted file mode 100644 index a3a7ba66b2..0000000000 --- a/.github/workflows/check_templ.yml +++ /dev/null @@ -1,28 +0,0 @@ -name: Compare file templates with file names -on: - push: - pull_request: - -# https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#concurrency -# Ensure that only one commit will be running tests at a time on each PR -concurrency: - group: ${{ github.ref }}-${{ github.workflow }} - cancel-in-progress: true - -jobs: - template-check: - runs-on: ubuntu-24.04 - steps: - - name: Checkout - uses: actions/checkout@v7 - with: - persist-credentials: false - fetch-depth: 0 - - name: Setup Python - uses: actions/setup-python@v7 - with: - python-version: 3.12 - - name: Compare file templates with file names - run: python scripts/lv_templ_check.py --fix - - name: Check that repository is clean - run: git diff --exit-code >/dev/null 2>&1 || (echo "Please fix template issues using scripts/lv_templ_check.py"; false) diff --git a/.github/workflows/static_checks.yml b/.github/workflows/static_checks.yml index da222cb752..f56c4cc4f0 100644 --- a/.github/workflows/static_checks.yml +++ b/.github/workflows/static_checks.yml @@ -125,6 +125,15 @@ jobs: continue-on-error: true run: python scripts/static_checks/check_comments.py src/core + # ------------------------------------------------------------------ + # The file name dependent parts of every lv_*.c/lv_*.h file + # (@file comment, include guards) must match the file name + # ------------------------------------------------------------------ + - name: "Check: file templates match file names" + id: file-template + continue-on-error: true + run: python scripts/static_checks/check_file_template.py + # ------------------------------------------------------------------ # Final gate – fail the job if any step above failed. # This gives us full output from every check before failing. @@ -141,7 +150,8 @@ jobs: steps.defconfigs.outcome == 'failure' || steps.labeler-globs.outcome == 'failure' || steps.labeler-labels.outcome == 'failure' || - steps.comments.outcome == 'failure' + steps.comments.outcome == 'failure' || + steps.file-template.outcome == 'failure' run: | echo "Policy check results:" @@ -167,6 +177,7 @@ jobs: print_result "labeler-globs" "${{ steps.labeler-globs.outcome }}" print_result "labeler-labels" "${{ steps.labeler-labels.outcome }}" print_result "comments" "${{ steps.comments.outcome }}" + print_result "file-template" "${{ steps.file-template.outcome }}" echo "---------------------" echo "One or more policy checks failed. See above for details." diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index f15e6f9c63..98bc41ab72 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -36,7 +36,7 @@ repos: # that depend on the file name are correct. - id: template-check name: Comparing file templates with file names - entry: python scripts/lv_templ_check.py --fix --quiet + entry: python scripts/static_checks/check_file_template.py --fix --quiet stages: [ commit ] language: system pass_filenames: false diff --git a/scripts/lv_templ_check.py b/scripts/static_checks/check_file_template.py similarity index 68% rename from scripts/lv_templ_check.py rename to scripts/static_checks/check_file_template.py index c8c107b8a5..f5320c8ed4 100644 --- a/scripts/lv_templ_check.py +++ b/scripts/static_checks/check_file_template.py @@ -1,19 +1,29 @@ -import re +#!/usr/bin/env python3 +""" +Check that the file-name dependent parts of the lv_templ.c/lv_templ.h +templates match the actual file name. + +Usage: + check_file_template.py [--fix] [-q] [-v] +""" + import argparse import os +import re import traceback +from pathlib import Path + +SCRIPT_PATH = Path(__file__).resolve() +LVGL_ROOT_DIR = SCRIPT_PATH.parents[2] ignored_file_prefixes = { "lv_conf_template.h", "lv_conf_cmsis.h", "lv_test_perf_conf.h", - "lv_font_" + "lv_font_", } -ignored_top_dirs = { - ".git", - "docs" -} +ignored_top_dirs = {".git", "docs"} h_filename_pattern = re.compile(r"lv_[\w.]*\.h") h_pattern = re.compile( @@ -21,15 +31,11 @@ h_pattern = re.compile( r"@file +(\S*).+?" r"\*/\s+?#ifndef +(\w+_H)\s+#define +(\w+_H).+" r"#endif */\* *([^*]+?) *\*/\s*", - flags=re.DOTALL + flags=re.DOTALL, ) c_filename_pattern = re.compile(r"lv_[\w.]*\.c") -c_pattern = re.compile( - r"\s*/\*\*.+?" - r"@file +(\S*)", - flags=re.DOTALL -) +c_pattern = re.compile(r"\s*/\*\*.+?" r"@file +(\S*)", flags=re.DOTALL) file_comment_help_f = """\ '{0}' should have at the top: @@ -59,6 +65,7 @@ instead, has: # regex, arg parsing and other stuff skipped here. + def ignore_file(basename): result = False @@ -71,38 +78,32 @@ def ignore_file(basename): def ignore_dir(path): - result = False + rel = os.path.relpath(path, LVGL_ROOT_DIR) + return rel.split(os.sep)[0] in ignored_top_dirs - for top_dir in ignored_top_dirs: - sub_path = os.path.join('lvgl', top_dir) - if sub_path in path: - result = True - break - - return result def debug(*args_, **kwargs): if args.verbose: print(*args_, **kwargs) + arg_parser = argparse.ArgumentParser() arg_parser.add_argument("--fix", action="store_true", help="fix incorrect files") -arg_parser.add_argument("-q", "--quiet", action="store_true", help="don't print mismatch info") +arg_parser.add_argument( + "-q", "--quiet", action="store_true", help="don't print mismatch info" +) arg_parser.add_argument("-v", "--verbose", action="store_true", help="print debug info") args = arg_parser.parse_args() -cfg_project_dir = '..' -base_dir = os.path.abspath(os.path.dirname(__file__)) -project_dir = os.path.abspath(os.path.join(base_dir, cfg_project_dir)) -debug(f'ignore dirs [{ignored_top_dirs}]') +debug(f"ignore dirs [{ignored_top_dirs}]") ok = True -for root, dirs, basenames in os.walk(project_dir): +for root, dirs, basenames in os.walk(LVGL_ROOT_DIR): if ignore_dir(root): continue - debug(f'root [{root}]') + debug(f"root [{root}]") for basename in basenames: if ignore_file(basename): continue @@ -116,74 +117,74 @@ for root, dirs, basenames in os.walk(project_dir): # ------------------------------------------------------------- if h_filename_pattern.fullmatch(basename): a_file_was_processed = True - debug(f'Opening H file [{path}]') + debug(f"Opening H file [{path}]") try: - with open(path, 'rb') as f: - cont = f.read().decode('utf-8') + with open(path, "rb") as f: + cont = f.read().decode("utf-8") except: - print(f'Error attempting UTF-8 decode on [{path}].') + print(f"Error attempting UTF-8 decode on [{path}].") traceback.print_exc() continue m = h_pattern.fullmatch(cont) if m is not None: - debug(' Match.') + debug(" Match.") if m[1] != basename: file_ok = False if not args.quiet: print(file_comment_help_f.format(path, basename, m[1])) guard_name = f"LV_{basename[3:-2].upper()}_H" - if any(m[i] != guard_name for i in range(2, 4+1)): + if any(m[i] != guard_name for i in range(2, 4 + 1)): file_ok = False if not args.quiet: print(guard_help_f.format(path, guard_name, m[2], m[3], m[4])) replacements = (basename, guard_name, guard_name, guard_name) else: - debug(f' No match with regex [{h_pattern.pattern}].') + debug(f" No match with regex [{h_pattern.pattern}].") # ------------------------------------------------------------- # C File? # ------------------------------------------------------------- elif c_filename_pattern.fullmatch(basename): a_file_was_processed = True - debug(f'Opening C file [{path}]') + debug(f"Opening C file [{path}]") try: - with open(path, 'rb') as f: - cont = f.read().decode('utf-8') + with open(path, "rb") as f: + cont = f.read().decode("utf-8") except: - print(f'Error attempting UTF-8 decode on [{path}].') + print(f"Error attempting UTF-8 decode on [{path}].") traceback.print_exc() continue m = c_pattern.match(cont) if m is not None: - debug(' Match.') + debug(" Match.") if m[1] != basename: file_ok = False if not args.quiet: print(file_comment_help_f.format(path, basename, m[1])) - replacements = (basename, ) + replacements = (basename,) else: - debug(f' No match with regex [{c_pattern.pattern}].') + debug(f" No match with regex [{c_pattern.pattern}].") if a_file_was_processed: if not file_ok: - debug(f'NOT OK [{path}]') + debug(f"NOT OK [{path}]") ok = False if args.fix: for i in reversed(range(0, len(replacements))): span = m.regs[i + 1] repl = replacements[i] - cont = cont[:span[0]] + repl + cont[span[1]:] + cont = cont[: span[0]] + repl + cont[span[1] :] with open(path, "w") as f: f.write(cont) else: - debug(f'OK [{path}]') + debug(f"OK [{path}]") if not ok: