114 lines
4.3 KiB
Python
Executable file
114 lines
4.3 KiB
Python
Executable file
#!/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)
|