diff mbox series

[v2,2/2] support: add a kernel version configuration helper script

Message ID 20241108231236.2838-2-git@jdknight.me
State Superseded
Headers show
Series [v2,1/2] linux: support each linux latest lts version | expand

Commit Message

James Knight Nov. 8, 2024, 11:12 p.m. UTC
Provides a helper script which can be used to quickly synchronize the
kernel versions defined in the Linux's `Config.in` file based on the
contents populated inside `linux.hash`.

The goal of this script is to help the maintenance effort required when
possibly supporting all active Linux LTS versions in the tree at a
given time.

Signed-off-by: James Knight <git@jdknight.me>
---
Changes v1 -> v2:
  - Introduced in the v2 of this series.

This is optional. No worries if not desired.
---
 support/scripts/sync-kernel-versions.py | 142 ++++++++++++++++++++++++
 1 file changed, 142 insertions(+)
 create mode 100755 support/scripts/sync-kernel-versions.py

Comments

Arnout Vandecappelle Aug. 29, 2025, 4:54 p.m. UTC | #1
On 09/11/2024 00:12, James Knight wrote:
> Provides a helper script which can be used to quickly synchronize the
> kernel versions defined in the Linux's `Config.in` file based on the
> contents populated inside `linux.hash`.
> 
> The goal of this script is to help the maintenance effort required when
> possibly supporting all active Linux LTS versions in the tree at a
> given time.
> 
> Signed-off-by: James Knight <git@jdknight.me>

  I just merged a script that does it much better, because it downloads the sha 
file from kernel.org and updates the hash file from that. See
utils/bump-stable-kernel-versions

  Regards,
  Arnout

> ---
> Changes v1 -> v2:
>    - Introduced in the v2 of this series.
> 
> This is optional. No worries if not desired.
> ---
>   support/scripts/sync-kernel-versions.py | 142 ++++++++++++++++++++++++
>   1 file changed, 142 insertions(+)
>   create mode 100755 support/scripts/sync-kernel-versions.py
> 
> diff --git a/support/scripts/sync-kernel-versions.py b/support/scripts/sync-kernel-versions.py
> new file mode 100755
> index 0000000000000000000000000000000000000000..2684b052657b0b98ac0265cd1b74a514d03ba9ca
> --- /dev/null
> +++ b/support/scripts/sync-kernel-versions.py
> @@ -0,0 +1,142 @@
> +#!/usr/bin/env python3
> +#
> +# Provides a script to allow the automatic updating of a Linux
> +# package's `Config.in` file based on the version information detailed
> +# in a `linux.hash` file.
> +
> +from pathlib import Path
> +import argparse
> +import re
> +
> +
> +# searching for a version pattern inside a `linux.hash` file
> +LINUX_VERSION_PATTERN = r'.*-([1-9]+.*)\.t.*'
> +
> +
> +def main():
> +    # argument parsing
> +    parser = argparse.ArgumentParser()
> +    parser.add_argument('--dry-run', action='store_true',
> +                        help='Do not change any files')
> +    parser.add_argument('--verbose', action='store_true',
> +                        help='Output additional information')
> +    args = parser.parse_args()
> +
> +    # helpers
> +    def verbose(msg):
> +        if args.verbose:
> +            print(f'(verbose) {msg}')
> +
> +    # find the linux package folder
> +    br_dir = Path(__file__).parent.parent.parent
> +
> +    linux_pkg_dir = br_dir / 'linux'
> +    if not linux_pkg_dir.is_dir():
> +        print('unable to find the linux package folder')
> +        return 1
> +
> +    linux_conf = linux_pkg_dir / 'Config.in'
> +    if not linux_conf.is_file():
> +        print('unable to find the linux configuration file')
> +        return 1
> +
> +    linux_hash = linux_pkg_dir / 'linux.hash'
> +    if not linux_hash.is_file():
> +        print('unable to find the linux hash file')
> +        return 1
> +
> +    # extract expected linux entries from the hash file
> +    try:
> +        with linux_hash.open(encoding='utf-8') as f:
> +            raw_hash_output = f.readlines()
> +    except OSError as e:
> +        print(f'error reading file {linux_hash}: {e}')
> +        return 1
> +
> +    entries = {}
> +    for hash_entry in raw_hash_output:
> +        if hash_entry.startswith('sha'):
> +            _, _, fname = hash_entry.strip().split(maxsplit=2)
> +            if fname.startswith('linux-'):
> +                verbose(f'detected linux entry: {fname}')
> +
> +                match = re.search(LINUX_VERSION_PATTERN, fname)
> +                if match:
> +                    vnum = match.group(1)
> +                    ventry = extract_ventry(vnum)
> +                    entries[ventry] = vnum
> +                    verbose(f'detected linux version ({fname}): {vnum}')
> +                else:
> +                    verbose(f'unable to detect linux version: {fname}')
> +
> +    # read the existing Linux configuration file
> +    conf_contents = []
> +    has_updated = False
> +    process_cfg = None
> +    try:
> +        with linux_conf.open(encoding='utf-8') as f:
> +            lines = f.read().splitlines()
> +            for line in lines:
> +                # wait until we are processing the kernel version section
> +                if process_cfg is None:
> +                    if 'config BR2_LINUX_KERNEL_VERSION' in line:
> +                        process_cfg = True
> +
> +                # if we are processing, check each version entry for any
> +                # updates that are required
> +                elif process_cfg:
> +                    # stop if the section is done
> +                    if not line:
> +                        process_cfg = False
> +                    # check if this is a linux configuration entry that
> +                    # might need to be updated
> +                    elif 'default "' in line:
> +                        front, raw_version, tail = line.split(maxsplit=2)
> +                        vnum = raw_version.replace('"', '')
> +                        if '.' in vnum:
> +                            ventry = extract_ventry(vnum)
> +                            if ventry in entries:
> +                                new_vnum = entries[ventry]
> +                                # if the version is outdated, replace the line
> +                                if vnum != new_vnum:
> +                                    print(f'Sync: {vnum} -> {new_vnum}')
> +                                    line = f'\t{front} "{new_vnum}" {tail}'
> +                                    has_updated = True
> +
> +                conf_contents.append(line)
> +
> +    except OSError as e:
> +        print(f'error reading file {linux_conf}: {e}')
> +        return 1
> +
> +    # update the linux configuration file if we have new changes
> +    if has_updated and not args.dry_run:
> +        print(f'Updating: {linux_conf}')
> +        try:
> +            with linux_conf.open('w', encoding='utf-8', newline='') as f:
> +                for line in conf_contents:
> +                    f.write(f'{line}\n')
> +
> +        except OSError as e:
> +            print(f'error writing file {linux_conf}: {e}')
> +            return 1
> +
> +    if not has_updated:
> +        print('No outdated versions.')
> +
> +    return 0
> +
> +
> +def extract_ventry(vnum):
> +    vmaj, vmin, _ = vnum.split('.', maxsplit=2)
> +
> +    ventry = f'{vmaj}.{vmin}'
> +    if '-' in vnum:
> +        _, postfix = vnum.split('-', maxsplit=1)
> +        ventry += f'-{postfix}'
> +
> +    return ventry
> +
> +
> +if __name__ == "__main__":
> +    raise SystemExit(main())
diff mbox series

Patch

diff --git a/support/scripts/sync-kernel-versions.py b/support/scripts/sync-kernel-versions.py
new file mode 100755
index 0000000000000000000000000000000000000000..2684b052657b0b98ac0265cd1b74a514d03ba9ca
--- /dev/null
+++ b/support/scripts/sync-kernel-versions.py
@@ -0,0 +1,142 @@ 
+#!/usr/bin/env python3
+#
+# Provides a script to allow the automatic updating of a Linux
+# package's `Config.in` file based on the version information detailed
+# in a `linux.hash` file.
+
+from pathlib import Path
+import argparse
+import re
+
+
+# searching for a version pattern inside a `linux.hash` file
+LINUX_VERSION_PATTERN = r'.*-([1-9]+.*)\.t.*'
+
+
+def main():
+    # argument parsing
+    parser = argparse.ArgumentParser()
+    parser.add_argument('--dry-run', action='store_true',
+                        help='Do not change any files')
+    parser.add_argument('--verbose', action='store_true',
+                        help='Output additional information')
+    args = parser.parse_args()
+
+    # helpers
+    def verbose(msg):
+        if args.verbose:
+            print(f'(verbose) {msg}')
+
+    # find the linux package folder
+    br_dir = Path(__file__).parent.parent.parent
+
+    linux_pkg_dir = br_dir / 'linux'
+    if not linux_pkg_dir.is_dir():
+        print('unable to find the linux package folder')
+        return 1
+
+    linux_conf = linux_pkg_dir / 'Config.in'
+    if not linux_conf.is_file():
+        print('unable to find the linux configuration file')
+        return 1
+
+    linux_hash = linux_pkg_dir / 'linux.hash'
+    if not linux_hash.is_file():
+        print('unable to find the linux hash file')
+        return 1
+
+    # extract expected linux entries from the hash file
+    try:
+        with linux_hash.open(encoding='utf-8') as f:
+            raw_hash_output = f.readlines()
+    except OSError as e:
+        print(f'error reading file {linux_hash}: {e}')
+        return 1
+
+    entries = {}
+    for hash_entry in raw_hash_output:
+        if hash_entry.startswith('sha'):
+            _, _, fname = hash_entry.strip().split(maxsplit=2)
+            if fname.startswith('linux-'):
+                verbose(f'detected linux entry: {fname}')
+
+                match = re.search(LINUX_VERSION_PATTERN, fname)
+                if match:
+                    vnum = match.group(1)
+                    ventry = extract_ventry(vnum)
+                    entries[ventry] = vnum
+                    verbose(f'detected linux version ({fname}): {vnum}')
+                else:
+                    verbose(f'unable to detect linux version: {fname}')
+
+    # read the existing Linux configuration file
+    conf_contents = []
+    has_updated = False
+    process_cfg = None
+    try:
+        with linux_conf.open(encoding='utf-8') as f:
+            lines = f.read().splitlines()
+            for line in lines:
+                # wait until we are processing the kernel version section
+                if process_cfg is None:
+                    if 'config BR2_LINUX_KERNEL_VERSION' in line:
+                        process_cfg = True
+
+                # if we are processing, check each version entry for any
+                # updates that are required
+                elif process_cfg:
+                    # stop if the section is done
+                    if not line:
+                        process_cfg = False
+                    # check if this is a linux configuration entry that
+                    # might need to be updated
+                    elif 'default "' in line:
+                        front, raw_version, tail = line.split(maxsplit=2)
+                        vnum = raw_version.replace('"', '')
+                        if '.' in vnum:
+                            ventry = extract_ventry(vnum)
+                            if ventry in entries:
+                                new_vnum = entries[ventry]
+                                # if the version is outdated, replace the line
+                                if vnum != new_vnum:
+                                    print(f'Sync: {vnum} -> {new_vnum}')
+                                    line = f'\t{front} "{new_vnum}" {tail}'
+                                    has_updated = True
+
+                conf_contents.append(line)
+
+    except OSError as e:
+        print(f'error reading file {linux_conf}: {e}')
+        return 1
+
+    # update the linux configuration file if we have new changes
+    if has_updated and not args.dry_run:
+        print(f'Updating: {linux_conf}')
+        try:
+            with linux_conf.open('w', encoding='utf-8', newline='') as f:
+                for line in conf_contents:
+                    f.write(f'{line}\n')
+
+        except OSError as e:
+            print(f'error writing file {linux_conf}: {e}')
+            return 1
+
+    if not has_updated:
+        print('No outdated versions.')
+
+    return 0
+
+
+def extract_ventry(vnum):
+    vmaj, vmin, _ = vnum.split('.', maxsplit=2)
+
+    ventry = f'{vmaj}.{vmin}'
+    if '-' in vnum:
+        _, postfix = vnum.split('-', maxsplit=1)
+        ventry += f'-{postfix}'
+
+    return ventry
+
+
+if __name__ == "__main__":
+    raise SystemExit(main())