#!/usr/bin/env python3 """ Fedora Package Maintainers Fetcher This script fetches all Fedora package maintainers from the Pagure API at src.fedoraproject.org and produces an alphabetically sorted list of unique maintainer usernames. This script was 99.9% written by Cursor with Claude 4 Sonnet. The 'fork' and 'namespace' params to the API query were added manually. """ import requests import time import sys from typing import Set, List def get_fedora_package_maintainers() -> List[str]: """ Fetch all Fedora package maintainers from the Pagure API. Returns: A sorted list of unique maintainer usernames """ base_url = "https://src.fedoraproject.org/api/0/projects" maintainers: Set[str] = set() page = 1 per_page = 100 # Max allowed by API according to documentation while True: # Make API request params = { 'fork': False, 'namespace': 'rpms', 'page': page, 'per_page': per_page } try: print(f"Fetching page {page}...", end=" ", flush=True) response = requests.get(base_url, params=params, timeout=30) response.raise_for_status() data = response.json() projects = data.get('projects', []) # If no projects returned, we've reached the end if not projects: print("No more projects found.") break # Extract maintainers from each project projects_with_owners = 0 for project in projects: access_users = project.get('access_users', {}) owners = access_users.get('owner', []) if owners: # Only count projects that have owners maintainers.update(owners) projects_with_owners += 1 print(f"Found {len(projects)} projects ({projects_with_owners} with owners), " f"total unique maintainers: {len(maintainers)}") # Check pagination info if available pagination = data.get('pagination', {}) if pagination: current_page = pagination.get('page', page) total_pages = pagination.get('pages', page) if current_page >= total_pages: print(f"Reached last page ({total_pages})") break else: # Fallback: check if we got fewer projects than requested if len(projects) < per_page: print("Got fewer projects than requested, assuming last page") break page += 1 # Be nice to the API - small delay between requests time.sleep(0.1) except requests.exceptions.RequestException as e: print(f"\nError fetching page {page}: {e}") if page > 1: print("Continuing with data collected so far...") else: print("Failed to fetch any data. Please check your internet connection.") return [] break except (KeyError, ValueError) as e: print(f"\nError parsing response on page {page}: {e}") if page > 1: print("Continuing with data collected so far...") else: print("Failed to parse API response.") return [] break # Convert to sorted list sorted_maintainers = sorted(list(maintainers)) return sorted_maintainers def main() -> int: """Main function to run the script.""" print("Fedora Package Maintainers Fetcher") print("=" * 40) print("Fetching all package maintainers from src.fedoraproject.org...") print("This may take several minutes as there are thousands of packages...\n") try: maintainers = get_fedora_package_maintainers() if not maintainers: print("No maintainers found or failed to fetch data.") return 1 print(f"\n{'='*60}") print(f"RESULTS: Found {len(maintainers)} unique package maintainers") print(f"{'='*60}") # Save to file output_file = 'fedora_maintainers.txt' try: with open(output_file, 'w') as f: for maintainer in maintainers: f.write(f"{maintainer}\n") print(f"Results saved to '{output_file}'") except IOError as e: print(f"Warning: Could not save to file: {e}") # Display first 20 maintainers print(f"\nFirst 20 maintainers (alphabetically):") print("-" * 40) for maintainer in maintainers[:20]: print(maintainer) if len(maintainers) > 20: print(f"... and {len(maintainers) - 20} more") print(f"\nSee '{output_file}' for the complete list.") return 0 except KeyboardInterrupt: print("\n\nOperation interrupted by user.") return 1 except Exception as e: print(f"An unexpected error occurred: {e}") return 1 if __name__ == "__main__": sys.exit(main())