#!/usr/bin/env python3 # -*- coding: utf-8 -*- import argparse import os import pyalpm from arch import ArchDatabase, ArchPackage from aur import AURPackage, AURLoader class Styling: """Output styling constants.""" ENDC = '\x1b[0m' BOLD = '\x1b[1m' UPTODATE = '\x1b[38;2;0;200;0m' NEEDS_UPDATE = '\x1b[38;2;200;0;0m' FLAGGED = '\x1b[38;2;200;200;0m' NEEDS_DOWNGRADE = '\x1b[38;2;0;0;200m' DELETED = '\x1b[38;2;200;0;0m' URL = '\x1b[38;2;200;200;200m' class AURChecker: """ Read local Arch Linux package databases/repositories and compare the version of each containing package against the AUR package with the same name to determine and print a status for each package. """ STATUS_UPTODATE = "uptodate" STATUS_NEEDS_UPDATE = "needs update" STATUS_NEEDS_DOWNGRADE = "needs downgrade" STATUS_DELETED = "deleted" def check(directory): """Check all databases/repositories in a directory.""" databases = ArchDatabase.find_databases(directory) for database in databases: AURChecker.check_database(database) def check_database(database): """Check a database/repository.""" print(Styling.BOLD + "# repository {}".format(database.get_name()) + Styling.ENDC) # Load AUR data aur_data = AURLoader.load_package_data([p.get_name() for p in database.get_packages()]) # Convert AUR data to AUR packages aur_packages = {} for values in aur_data: aur_package = AURChecker.create_aur_package(values) aur_packages[aur_package.get_name()] = aur_package # Compare database packages with AUR packages for package in database.get_packages(): status_messages = {} if package.get_name() in aur_packages: aur_package = aur_packages[package.get_name()] status = AURChecker.compare(package, aur_package) status_messages[AURChecker.STATUS_UPTODATE] = Styling.UPTODATE + "up-do-date" + Styling.ENDC status_messages[AURChecker.STATUS_NEEDS_UPDATE] = Styling.NEEDS_UPDATE + "needs update to {}\n".format(aur_package.get_version()) + Styling.URL + " {}{}".format(AURLoader.AUR_URL, aur_package.get_url_path()) + Styling.ENDC status_messages[AURChecker.STATUS_NEEDS_DOWNGRADE] = Styling.NEEDS_DOWNGRADE + "local is newer" + Styling.ENDC else: status = AURChecker.STATUS_DELETED status_messages[AURChecker.STATUS_DELETED] = Styling.DELETED + "deleted" + Styling.ENDC message = " – {} {}: {}".format(package.get_name(), package.get_version(), status_messages[status]) if aur_package and aur_package.get_out_of_date(): message = Styling.FLAGGED + "{} (flagged)".format(message) + Styling.ENDC print(message) def compare(package, aur_package): """Compare package two versions and return status.""" result = pyalpm.vercmp(package.get_version(), aur_package.get_version()) if result < 0: return AURChecker.STATUS_NEEDS_UPDATE elif result > 0: return AURChecker.STATUS_NEEDS_DOWNGRADE else: return AURChecker.STATUS_UPTODATE def create_aur_package(values): aur_package = AURPackage(values['Name']) aur_package.set_version(values['Version']) aur_package.set_desc(values['Description']) aur_package.set_url(values['URL']) aur_package.set_license(values['License']) aur_package.set_maintainer(values['Maintainer']) aur_package.set_votes(values['NumVotes']) aur_package.set_url_path(values['URLPath']) aur_package.set_package_base(values['PackageBase']) aur_package.set_out_of_date(values['OutOfDate']) aur_package.set_last_modified(values['LastModified']) return aur_package if __name__ == "__main__": parser = argparse.ArgumentParser("Read local Arch Linux package databases/repositories and compare the version of each containing package against the AUR package with the same name to determine and print a status for each package.") parser.add_argument('folder', help="source folder containing one or several databases/repositories (subdirectories possible)") args = parser.parse_args() AURChecker.check(args.folder)