Skip to content

Instantly share code, notes, and snippets.

@CaseOf
Last active May 1, 2025 23:24
Show Gist options
  • Save CaseOf/7c15e3e93a58ff3264cb8c9a1b56c3d3 to your computer and use it in GitHub Desktop.
Save CaseOf/7c15e3e93a58ff3264cb8c9a1b56c3d3 to your computer and use it in GitHub Desktop.
Gentoo PYTHON_COMPAT additions post-sync to given ebuilds script generated by Claude 3.7 Sonnet
#!/bin/bash
#
# Script name: fix-python-compat.sh
# Description: Adds specified Python versions to PYTHON_COMPAT variables in Gentoo ebuilds
# Location: /etc/portage/postsync.d/fix-python-compat
# Make sure to:
# - chmod +x /etc/portage/postsync.d/fix-python-compat
# - Have pkgdev installed: emerge --ask dev-util/pkgdev
#
# Configuration - add packages and Python versions here
declare -A PACKAGES_TO_FIX
PACKAGES_TO_FIX=(
# Format options:
# [category/package]="python_version1 python_version2 ..." # All versions
# [category/package::version]="python_version1 python_version2 ..." # Specific version
# [category/package::version1,version2]="python_version1 python_version2 ..." # Multiple specific versions
#
# Examples:
["dev-python/example"]="python3_11 python3_12" # All versions
["app-misc/another-package::2.0"]="python3_12" # Only version 2.0
["dev-python/specific::1.2,1.3,1.4"]="python3_11 python3_12" # Only versions 1.2, 1.3, and 1.4
["sci-libs/example::3.1-r2"]="python3_11" # Only version 3.1 revision 2
["app-admin/tool::1.0,1.0-r1,1.0-r2"]="python3_12" # Base version 1.0 and specific revisions
# Add more packages as needed
)
# Path to the Gentoo repository
PORTDIR="${PORTDIR:-/var/db/repos/gentoo}"
# Log file
LOG_FILE="/var/log/portage/python-compat-fixes.log"
BACKUP_DIR="/var/backup/portage-ebuilds/$(date +%Y%m%d)"
# Create log and backup directories if they don't exist
mkdir -p "$(dirname "$LOG_FILE")"
mkdir -p "$BACKUP_DIR"
# Log function
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" | tee -a "$LOG_FILE"
}
# Function to check if a version matches any pattern in a comma-separated list
matches_version() {
local version="$1"
local patterns="$2"
local pattern
IFS=',' read -ra PATTERN_ARRAY <<< "$patterns"
for pattern in "${PATTERN_ARRAY[@]}"; do
# Handle exact matches (including revision)
if [[ "$version" == "$pattern" ]]; then
return 0 # Exact match found
fi
# Handle base version match (ignoring revision)
base_version="${version%%-r*}"
if [[ "$pattern" == "$base_version" && "$version" =~ -r[0-9]+ ]]; then
return 0 # Base version matches and we have a revision
fi
# Handle specific revision match
if [[ "$pattern" =~ ^([0-9][0-9a-z._]*)-r([0-9]+)$ ]]; then
base_pattern="${BASH_REMATCH[1]}"
rev_pattern="${BASH_REMATCH[2]}"
if [[ "$version" =~ ^${base_pattern}-r${rev_pattern}$ ]]; then
return 0 # Revision-specific match
fi
fi
done
return 1 # No match
}
# Check for required dependencies
check_dependencies() {
local missing_deps=false
# Check for pkgdev
if ! command -v pkgdev >/dev/null 2>&1; then
log "WARNING: pkgdev is not installed. Manifest files won't be updated."
log "Install pkgdev with: emerge --ask dev-util/pkgdev"
missing_deps=true
fi
# Return status
if [ "$missing_deps" = true ]; then
return 1
fi
return 0
}
log "Starting Python compatibility fixes"
# Check dependencies
check_dependencies
# Process each package
for package_key in "${!PACKAGES_TO_FIX[@]}"; do
python_versions="${PACKAGES_TO_FIX[$package_key]}"
# Check if we have a version constraint
package="$package_key"
version_constraint=""
if [[ "$package_key" == *"::"* ]]; then
# Split at the :: delimiter
package="${package_key%%::*}"
version_constraint="${package_key#*::}"
log "Processing package: $package - Versions: $version_constraint - Adding Python versions: $python_versions"
else
log "Processing package: $package - All versions - Adding Python versions: $python_versions"
fi
# Find all ebuilds for this package
package_dir="$PORTDIR/$package"
if [ ! -d "$package_dir" ]; then
log "ERROR: Package directory not found: $package_dir"
continue
fi
# Process each ebuild file
for ebuild in "$package_dir"/*.ebuild; do
if [ ! -f "$ebuild" ]; then
log "No ebuilds found for $package"
continue
fi
ebuild_name=$(basename "$ebuild")
# Extract version from ebuild filename (including revision numbers)
ebuild_version=$(echo "$ebuild_name" | sed -r 's/^[^0-9]*-([0-9][0-9a-z._]*(-r[0-9]+)?)\.ebuild$/\1/')
# If we have a version constraint, check if this ebuild matches
if [ -n "$version_constraint" ]; then
if ! matches_version "$ebuild_version" "$version_constraint"; then
log "Skipping ebuild $ebuild_name (doesn't match version constraint: $version_constraint)"
continue
fi
fi
log "Examining ebuild: $ebuild_name (version: $ebuild_version)"
# Check if the ebuild contains PYTHON_COMPAT
if grep -q "PYTHON_COMPAT=" "$ebuild"; then
# Create backup
backup_file="$BACKUP_DIR/$(dirname "$package")_${ebuild_name}.bak"
mkdir -p "$(dirname "$backup_file")"
cp "$ebuild" "$backup_file"
log "Created backup: $backup_file"
# Process the PYTHON_COMPAT line
needs_update=false
for py_ver in $python_versions; do
if ! grep -q "PYTHON_COMPAT=.*$py_ver" "$ebuild"; then
needs_update=true
log "Need to add $py_ver to $ebuild_name"
fi
done
if [ "$needs_update" = true ]; then
# Update the PYTHON_COMPAT line
# This sed command finds the PYTHON_COMPAT line and adds the new versions before the closing parenthesis
for py_ver in $python_versions; do
# Check if it already contains this version
if ! grep -q "PYTHON_COMPAT=.*$py_ver" "$ebuild"; then
sed -i.tmp -r "s/(PYTHON_COMPAT=\([^)]*)/\1 $py_ver/" "$ebuild"
# Clean up the tmp file
rm -f "${ebuild}.tmp"
log "Added $py_ver to PYTHON_COMPAT in $ebuild_name"
fi
done
log "Updated ebuild: $ebuild_name"
# Update manifest after modifying the ebuild
if command -v pkgdev >/dev/null 2>&1; then
log "Updating Manifest for $package_dir"
(
cd "$(dirname "$package_dir")" || { log "ERROR: Failed to change directory to $(dirname "$package_dir")"; return 1; }
if ! pkgdev manifest -f "$(basename "$package_dir")"; then
log "ERROR: Failed to update Manifest for $package_dir"
else
log "Successfully updated Manifest for $package_dir"
fi
)
else
log "WARNING: pkgdev is not installed. Manifest files won't be updated."
log "Install pkgdev with: emerge --ask dev-util/pkgdev"
fi
else
log "Ebuild already includes specified Python versions: $ebuild_name"
fi
else
log "WARNING: No PYTHON_COMPAT found in $ebuild_name"
fi
done
done
log "Python compatibility fixes completed"
# Update eix database if it's installed
if command -v eix-update >/dev/null 2>&1; then
log "Updating eix database..."
if ! eix-update; then
log "WARNING: Failed to update eix database"
else
log "Successfully updated eix database"
fi
else
log "Note: eix is not installed. No need to update its database."
fi
exit 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment