From: Pietro Monteiro <[email protected]>

Use a container image with all dependencies pre-installed. Copy
autoregen.py from the builder repository.  Fail if any files change.

ChangeLog:

        * .forgejo/workflows/sanity-checks.yaml (container): Use
        ghcr.io/pietro/autoregen:main
        (gcc_autoregen): New step.

contrib/ChangeLog:

        * autoregen.py: New file.

Signed-off-by: Pietro Monteiro <[email protected]>
---
 .forgejo/workflows/sanity-checks.yaml |  29 +++--
 contrib/autoregen.py                  | 146 ++++++++++++++++++++++++++
 2 files changed, 169 insertions(+), 6 deletions(-)
 create mode 100755 contrib/autoregen.py

diff --git a/.forgejo/workflows/sanity-checks.yaml 
b/.forgejo/workflows/sanity-checks.yaml
index 361c497e9905..96f086103a0c 100644
--- a/.forgejo/workflows/sanity-checks.yaml
+++ b/.forgejo/workflows/sanity-checks.yaml
@@ -1,3 +1,4 @@
+---
 on:
   pull_request:
     types: [opened, synchronize, reopened]
@@ -5,16 +6,16 @@ on:
 jobs:
   testjob:
     runs-on: sourceware-runner
+    container:
+      # 
https://github.com/pietro/autoregen/commit/db236a893de214a2e2283ba298131a2aacfad760
+      # https://github.com/pietro/autoregen/actions/runs/18791697341
+      # 
https://github.com/pietro/autoregen/pkgs/container/autoregen/555274365?tag=main
+      image: 
ghcr.io/pietro/autoregen@sha256:5b62e8d87c597bd65b36e83c39d28cde475f414d2b3dccd1361686779af7a5c8
     outputs:
       styleoutput: ${{ steps.check_gnu_style.outputs.styleresult }}
       verifyoutput: ${{ steps.gcc_verify.outputs.verifyresult }}
+      autoregenoutput: ${{ steps.gcc_autoregen.outputs.autoregenresult }}
     steps:
-      - name: install dependencies
-        run: |
-          echo "Installing node.js"
-          apt-get update
-          apt-get install -qq -y nodejs git python3 python3-git 
python3-termcolor python3-unidiff
-
       # Checkout GCC sources, request an history depth of 100,
       # hopefully sufficient for all patch series (the default is 1)
       - uses: actions/checkout@v4
@@ -42,8 +43,24 @@ jobs:
           ./contrib/gcc-changelog/git_check_commit.py 
${FORGEJO_BASE_REF}..${FORGEJO_SHA}
           echo "verifyresult=pass" | tee -a $FORGEJO_OUTPUT
 
+      - name: check generated files
+        id: gcc_autoregen
+        continue-on-error: true
+        run: |
+          ./contrib/autoregen.py
+          CHANGED=$(git diff --name-only)
+          if [ -n "${CHANGED}" ]; then
+          echo "The following files changed:"
+          echo "${CHANGED}"
+          exit 1
+          else
+          echo "Files regenerated correctly and no differences found."
+          echo "autoregenresult=pass" | tee -a $FORGEJO_OUTPUT
+          fi
+
       - name: final-result
         run: |
           echo "Computing final result"
           test "${{ steps.check_gnu_style.outputs.styleresult }}" = "pass"
           test "${{ steps.gcc_verify.outputs.verifyresult }}" = "pass"
+          test "${{ steps.gcc_autoregen.outputs.autoregenresult }}" = "pass"
diff --git a/contrib/autoregen.py b/contrib/autoregen.py
new file mode 100755
index 000000000000..7ac17c1b9dd8
--- /dev/null
+++ b/contrib/autoregen.py
@@ -0,0 +1,146 @@
+#!/usr/bin/env python3
+
+# This script helps to regenerate files managed by autotools and
+# autogen in binutils-gdb and gcc repositories.
+
+# It can be used by buildbots to check that the current repository
+# contents has been updated correctly, and by developers to update
+# such files as expected.
+
+import os
+import shutil
+import subprocess
+from pathlib import Path
+
+
+# On Gentoo, vanilla unpatched autotools are packaged separately.
+# We place the vanilla names first as we want to prefer those if both exist.
+AUTOCONF_NAMES = ["autoconf-vanilla-2.69", "autoconf-2.69", "autoconf"]
+AUTOMAKE_NAMES = ["automake-vanilla-1.15", "automake-1.15.1", "automake"]
+ACLOCAL_NAMES = ["aclocal-vanilla-1.15", "aclocal-1.15.1", "aclocal"]
+AUTOHEADER_NAMES = ["autoheader-vanilla-2.69", "autoheader-2.69", "autoheader"]
+AUTORECONF_NAMES = ["autoreconf-vanilla-2.69", "autoreconf-2.69", "autoreconf"]
+
+# Pick the first for each list that exists on this system.
+AUTOCONF_BIN = next(name for name in AUTOCONF_NAMES if shutil.which(name))
+AUTOMAKE_BIN = next(name for name in AUTOMAKE_NAMES if shutil.which(name))
+ACLOCAL_BIN = next(name for name in ACLOCAL_NAMES if shutil.which(name))
+AUTOHEADER_BIN = next(name for name in AUTOHEADER_NAMES if shutil.which(name))
+AUTORECONF_BIN = next(name for name in AUTORECONF_NAMES if shutil.which(name))
+
+AUTOGEN_BIN = "autogen"
+
+# autoconf-wrapper and automake-wrapper from Gentoo look at this environment 
variable.
+# It's harmless to set it on other systems though.
+EXTRA_ENV = {
+    "WANT_AUTOCONF": AUTOCONF_BIN.split("-", 1)[1] if "-" in AUTOCONF_BIN else 
"",
+    "WANT_AUTOMAKE": AUTOMAKE_BIN.split("-", 1)[1] if "-" in AUTOMAKE_BIN else 
"",
+    "AUTOCONF": AUTOCONF_BIN,
+    "ACLOCAL": ACLOCAL_BIN,
+    "AUTOMAKE": AUTOMAKE_BIN,
+    "AUTOGEN": AUTOGEN_BIN,
+}
+ENV = os.environ.copy()
+ENV.update(EXTRA_ENV)
+
+
+# Directories we should skip entirely because they're vendored or have 
different
+# autotools versions.
+SKIP_DIRS = [
+    # readline and minizip are maintained with different autotools versions
+    "readline",
+    "minizip",
+]
+
+MANUAL_CONF_DIRS = [
+    ".",
+    # autoreconf does not update aclocal.m4
+    "fixincludes",
+    ]
+
+# Run the shell command CMD.
+#
+# Print the command on stdout prior to running it.
+def run_shell(cmd: str):
+    print(f"+ {cmd}", flush=True)
+    res = subprocess.run(
+        f"{cmd}",
+        shell=True,
+        encoding="utf8",
+        env=ENV,
+    )
+    res.check_returncode()
+
+
+def regenerate_with_autoreconf():
+    run_shell(f"{AUTORECONF_BIN} -f")
+
+def regenerate_with_autogen():
+    run_shell(f"{AUTOGEN_BIN} Makefile.def")
+
+def regenerate_manually():
+    configure_lines = open("configure.ac").read().splitlines()
+    if folder.stem == "fixincludes" or any(
+            True for line in configure_lines if 
line.startswith("AC_CONFIG_MACRO_DIR")
+    ):
+        include_arg = ""
+        include_arg2 = ""
+        if (folder / ".." / "config").is_dir():
+            include_arg = "-I../config"
+
+        if folder.stem == "fixincludes":
+            include_arg = "-I.."
+            include_arg2 = "-I../config"
+
+        # aclocal does not support the -f short option for force
+        run_shell(f"{ACLOCAL_BIN} --force {include_arg} {include_arg2}")
+
+    if (folder / "config.in").is_file() or any(
+        True for line in configure_lines if 
line.startswith("AC_CONFIG_HEADERS")
+    ):
+        run_shell(f"{AUTOHEADER_BIN} -f")
+
+    # apparently automake is somehow unstable -> skip it for gotools
+    if any(
+        True for line in configure_lines if line.startswith("AM_INIT_AUTOMAKE")
+    ) and not str(folder).endswith("gotools"):
+        run_shell(f"{AUTOMAKE_BIN} -f")
+
+    run_shell(f"{AUTOCONF_BIN} -f")
+
+
+run_shell(f"{AUTOCONF_BIN} --version")
+run_shell(f"{AUTOMAKE_BIN} --version")
+run_shell(f"{ACLOCAL_BIN} --version")
+run_shell(f"{AUTOHEADER_BIN} --version")
+
+print(f"Extra environment: {EXTRA_ENV}", flush=True)
+
+config_folders: list[Path] = []
+autogen_folders: list[Path] = []
+repo_root = Path.cwd()
+
+for root, _, files in os.walk("."):
+    for file in files:
+        if file == "configure.ac":
+            config_folders.append(Path(root).resolve())
+        if file == "Makefile.tpl":
+            autogen_folders.append(Path(root).resolve())
+
+for folder in sorted(autogen_folders):
+    print(f"Entering directory {folder}", flush=True)
+    os.chdir(folder)
+    regenerate_with_autogen()
+
+for folder in sorted(config_folders):
+    if folder.stem in SKIP_DIRS:
+        print(f"Skipping directory {folder}", flush=True)
+        continue
+
+    print(f"Entering directory {folder}", flush=True)
+    os.chdir(folder)
+
+    if str(folder.relative_to(repo_root)) in MANUAL_CONF_DIRS:
+        regenerate_manually()
+    else:
+        regenerate_with_autoreconf()
-- 
2.54.0

Reply via email to