diff --git a/lt_rebase.sh b/lt_rebase.sh index ed4cb12..8ac5284 100755 --- a/lt_rebase.sh +++ b/lt_rebase.sh @@ -148,4 +148,37 @@ if [ ! -z "$REPO_STATUS" ]; then git commit -m "[CIQ] $(git describe --tags --abbrev=0) - rebased configs" fi +SPEC_FILE="./ciq/SPECS/kernel.spec" +if [ -f "$SPEC_FILE" ] ; then + echo "Updating kernel.spec version variables and changelog..." + # Set default values for DISTLOCALVERSION and DIST if not set + DISTLOCALVERSION=${DISTLOCALVERSION:-".1.0.0"} + DIST=${DIST:-".el9_clk"} + + # Get the directory where this script is located + SCRIPT_DIR="$(dirname "$(realpath "${BASH_SOURCE[0]}")")" + + # Path to update_lt_spec.py in the same directory as this script + UPDATE_LT_SPEC="$SCRIPT_DIR/update_lt_spec.py" + + if [ ! -f "$UPDATE_LT_SPEC" ]; then + echo "ERROR: update_lt_spec.py not found at $UPDATE_LT_SPEC" + exit 1 + fi + + # Call update_lt_spec.py to update the spec file + "$UPDATE_LT_SPEC" \ + --srcgit . \ + --spec-file "$SPEC_FILE" \ + --distlocalversion "$DISTLOCALVERSION" \ + --dist "$DIST" \ + --commit + + if [ $? -ne 0 ]; then + echo "ERROR: update_lt_spec.py failed" + exit 1 + fi + + echo "Spec file updated successfully" +fi diff --git a/update_lt_spec.py b/update_lt_spec.py new file mode 100755 index 0000000..2a0b18b --- /dev/null +++ b/update_lt_spec.py @@ -0,0 +1,261 @@ +#!/usr/bin/env python3 +# +# coding: utf-8 +# +# Update kernel.spec for LT (Long Term) kernel rebases. +# This script updates version variables and replaces the changelog +# to reflect the new upstream kernel version. + +import argparse +import os +import sys +import time + +try: + import git +except ImportError: + print("ERROR: GitPython is not installed. Install it with: pip install GitPython") + sys.exit(1) + +from ciq_helpers import last_git_tag + + +def calculate_lt_rebase_versions(upstream_tag, distlocalversion, dist): + """Calculate version strings for LT rebase. + + Arguments: + upstream_tag: Git tag from git describe (e.g., 'v6.12.74') + distlocalversion: DISTLOCALVERSION string (e.g., '.1.0.0') + dist: DIST string (e.g., '.el9_clk') + + Returns: + Tuple of (full_kernel_version, tag_version, spectarfile_release, new_tag, major_version) + """ + # Remove 'v' prefix if present + full_kernel_version = upstream_tag.lstrip("v") + tag_version = f"{full_kernel_version}-1" + spectarfile_release = f"{tag_version}{distlocalversion}{dist}" + new_tag = f"ciq_kernel-{tag_version}" + major_version = full_kernel_version.split(".")[0] + + return full_kernel_version, tag_version, spectarfile_release, new_tag, major_version + + +def update_spec_file( + spec_path, + full_kernel_version, + spectarfile_release, + lt_tag_version, + lt_new_tag, + lt_major_version, + upstream_tag, + srcgit, + distlocalversion, + dist, +): + """Update the spec file with new version information and changelog. + + Arguments: + spec_path: Path to kernel.spec file + full_kernel_version: Full kernel version (e.g., '6.12.77') + spectarfile_release: Value for tarfile_release variable + lt_tag_version: Tag version (e.g., '6.12.77-1') + lt_new_tag: New tag name (e.g., 'ciq_kernel-6.12.77-1') + lt_major_version: Major version number (e.g., '6') + upstream_tag: Git tag name (e.g., 'v6.12.77') + srcgit: Git repository object + distlocalversion: DISTLOCALVERSION string + dist: DIST string + """ + # Read the spec file + try: + with open(spec_path, "r") as f: + spec = f.read().splitlines() + except IOError as e: + print(f"ERROR: Failed to read spec file {spec_path}: {e}") + sys.exit(1) + + # Get git user info, checking both repo-level and global config + try: + name = srcgit.git.config("user.name") + email = srcgit.git.config("user.email") + except git.exc.GitCommandError as e: + print("ERROR: Failed to read git config. Please ensure user.name and user.email are configured.") + print(' Run: git config --global user.name "Your Name"') + print(' Run: git config --global user.email "your.email@example.com"') + print(f" Error details: {e}") + sys.exit(1) + + new_spec = [] + for line in spec: + # Update version variables + if line.startswith("%define specrpmversion"): + line = f"%define specrpmversion {full_kernel_version}" + new_spec.append(line) + continue + + if line.startswith("%define specversion"): + line = f"%define specversion {full_kernel_version}" + new_spec.append(line) + continue + + if line.startswith("%define tarfile_release"): + line = f"%define tarfile_release {spectarfile_release}" + new_spec.append(line) + continue + + # Replace changelog + if line.startswith("%changelog"): + new_spec.append(line) + + # Generate changelog header + changelog_date = time.strftime("%a %b %d %Y") + changelog_header = f"* {changelog_date} {name} <{email}> - {lt_tag_version}{distlocalversion}{dist}" + new_spec.append(changelog_header) + new_spec.append( + f"-- Rebased changes for Linux {full_kernel_version} (https://github.com/ctrliq/kernel-src-tree/releases/tag/{lt_new_tag})" + ) + + # Add all commits from upstream tag to HEAD + try: + commit_logs = srcgit.git.log("--no-merges", "--pretty=format:-- %s (%an)", f"{upstream_tag}..HEAD") + for log_line in commit_logs.split("\n"): + if log_line.strip(): + new_spec.append(log_line) + except git.exc.GitCommandError as e: + print(f"ERROR: Failed to get git log from {upstream_tag}..HEAD: {e}") + sys.exit(1) + + new_spec.append("") + new_spec.append( + f"-- Linux {full_kernel_version} (https://cdn.kernel.org/pub/linux/kernel/v{lt_major_version}.x/ChangeLog-{full_kernel_version})" + ) + new_spec.append("") + new_spec.append("") + + # Preserve trailing comments from original spec file + in_changelog = False + for orig_line in spec: + if orig_line.startswith("%changelog"): + in_changelog = True + continue + if in_changelog and (orig_line.startswith("#") or orig_line.startswith("###")): + new_spec.append(orig_line) + + # Skip the rest of the original changelog + break + + new_spec.append(line) + + # Write the updated spec file + try: + with open(spec_path, "w") as f: + for line in new_spec: + f.write(line + "\n") + except IOError as e: + print(f"ERROR: Failed to write spec file {spec_path}: {e}") + sys.exit(1) + + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description="Update kernel.spec for LT kernel rebase") + parser.add_argument("--srcgit", required=True, help="Location of srcgit repository") + parser.add_argument("--spec-file", required=True, help="Path to kernel.spec file") + parser.add_argument( + "--distlocalversion", default=".1.0.0", help="DISTLOCALVERSION for tarfile_release (default: .1.0.0)" + ) + parser.add_argument("--dist", default=".el9_clk", help="DIST for tarfile_release (default: .el9_clk)") + parser.add_argument("--commit", action="store_true", help="Commit the spec file changes to git") + args = parser.parse_args() + + # Initialize git repository + srcgit_path = os.path.abspath(args.srcgit) + try: + srcgit = git.Repo(srcgit_path) + except git.exc.InvalidGitRepositoryError: + print(f"ERROR: {srcgit_path} is not a valid git repository") + sys.exit(1) + except git.exc.NoSuchPathError: + print(f"ERROR: Path does not exist: {srcgit_path}") + sys.exit(1) + + # Get the last git tag + try: + upstream_tag = last_git_tag(srcgit) + except Exception as e: + print(f"ERROR: Failed to get last git tag: {e}") + sys.exit(1) + + print(f"Using last tag: {upstream_tag}") + + # Validate tag format (should be like 'v6.12.74' or '6.12.74') + tag_without_v = upstream_tag.lstrip("v") + tag_parts = tag_without_v.split(".") + if len(tag_parts) != 3: + print(f"ERROR: Invalid tag format: {upstream_tag}") + print(" Expected format: vX.Y.Z or X.Y.Z (e.g., v6.12.74)") + sys.exit(1) + + # Validate that parts are numeric + try: + for part in tag_parts: + int(part) + except ValueError: + print(f"ERROR: Invalid tag format: {upstream_tag}") + print(" Tag version parts must be numeric") + sys.exit(1) + + # Calculate version strings + full_kernel_version, tag_version, spectarfile_release, new_tag, major_version = calculate_lt_rebase_versions( + upstream_tag, args.distlocalversion, args.dist + ) + + print("\nLT Rebase Version Information:") + print(f" Full Kernel Version: {full_kernel_version}") + print(f" Tag Version: {tag_version}") + print(f" Spec tarfile_release: {spectarfile_release}") + print(f" New Tag: {new_tag}") + print(f" Major Version: {major_version}\n") + + # Verify spec file exists + spec_path = os.path.abspath(args.spec_file) + if not os.path.exists(spec_path): + print(f"ERROR: Spec file not found: {spec_path}") + sys.exit(1) + + # Update the spec file + print(f"Updating spec file: {spec_path}") + update_spec_file( + spec_path, + full_kernel_version, + spectarfile_release, + tag_version, + new_tag, + major_version, + upstream_tag, + srcgit, + args.distlocalversion, + args.dist, + ) + + print("Spec file updated successfully") + + # Optionally commit the changes + if args.commit: + print("Committing changes...") + spec_path_rel = os.path.relpath(spec_path, srcgit.working_tree_dir) + srcgit.git.add(spec_path_rel) + + # Check if there are changes to commit + if srcgit.is_dirty(path=spec_path_rel): + commit_message = f"[CIQ] {upstream_tag} - updated spec" + try: + srcgit.git.commit("-m", commit_message) + print(f"Committed: {commit_message}") + except git.exc.GitCommandError as e: + print(f"ERROR: Failed to commit changes: {e}") + sys.exit(1) + else: + print("No changes to commit") + + print("\nDone!")