import subprocess import requests import string from pathlib import Path from email.utils import parsedate_to_datetime from datetime import datetime, timedelta, timezone NAME = 'linux-zen' REPO = 'extra' # Script to update the PKGBUILD to the latest [extra]/linux-zen def get_current_version(): pkgbuild = Path('.SRCINFO').read_text('utf8') pkgver = pkgbuild.split('pkgver =', 1)[1].splitlines()[0].strip() pkgrel = pkgbuild.split('pkgrel =', 1)[1].splitlines()[0].strip() return pkgver, pkgrel def get_pkg_info(pkgname): url = f"https://archlinux.org/packages/{REPO}/x86_64/{pkgname}/json/" response = requests.get(url, timeout=10) return response.json() def get_arch_archive_age(filename): """Check if a package file is on the Arch Linux Archive and return its age as a datetime.timedelta, or timedelta(0) if it's a 404""" url = f"https://archive.archlinux.org/packages/.all/{filename}" response = requests.head(url, timeout=10) if not response.ok: return timedelta(0) now = datetime.now(timezone.utc) last_modified = parsedate_to_datetime(response.headers['Last-Modified']) return now - last_modified class Template(string.Template): delimiter="%" def arr(name, values): delimiter = '\n' + ' ' * (len(name) + 4) values = [f"'{value}'" if ':' in value else value for value in values] return f"{name}=({delimiter.join(values)})" def update(kern_info): headers_info = get_pkg_info(f'{NAME}-headers') docs_info = get_pkg_info(f'{NAME}-docs') template = Template(Path('PKGBUILD.template').read_text('utf8')) kernver, zenver = kern_info['pkgver'].rsplit('.', 1) pkgrel = kern_info['pkgrel'] padded_kernver = kernver if len(kernver.split('.')) == 3 else kernver + '.0' pkgbuild = template.substitute( PKGVER=kern_info['pkgver'], KERNVER=kernver, ZENVER=zenver, PKGREL=pkgrel, KERNNAME=f"{padded_kernver}-{zenver}-{pkgrel}-zen", URL=kern_info['url'], KERN_PKG=kern_info['filename'], KERN_PKGDESC=kern_info['pkgdesc'], KERN_DEPENDS=arr("depends", kern_info['depends']), KERN_CONFLICTS=arr("conflicts", kern_info['conflicts'] + ['"${_pkgname}"']), KERN_OPTDEPENDS=arr("optdepends", kern_info['optdepends']), KERN_PROVIDES=arr("provides", kern_info['provides']), KERN_REPLACES=arr("replaces", kern_info['replaces']), HEADERS_PKG=headers_info['filename'], HEADERS_PKGDESC=headers_info['pkgdesc'], HEADERS_DEPENDS=arr("depends", headers_info['depends']), HEADERS_CONFLICTS=arr( "conflicts", headers_info['conflicts'] + ['"${_pkgname}-headers"'] ), HEADERS_OPTDEPENDS=arr("optdepends", headers_info['optdepends']), HEADERS_PROVIDES=arr("provides", headers_info['provides']), HEADERS_REPLACES=arr("replaces", headers_info['replaces']), DOCS_PKG=docs_info['filename'], DOCS_PKGDESC=docs_info['pkgdesc'], DOCS_DEPENDS=arr("depends", docs_info['depends']), DOCS_CONFLICTS=arr( "conflicts", docs_info['conflicts'] + ['"${_pkgname}-docs"'] ), DOCS_OPTDEPENDS=arr("optdepends", docs_info['optdepends']), DOCS_PROVIDES=arr("provides", docs_info['provides']), DOCS_REPLACES=arr("replaces", docs_info['replaces']), ) # Delete empty arrays: pkgbuild = '\n'.join( line for line in pkgbuild.splitlines() if not line.endswith('=()') ) Path('PKGBUILD').write_text(pkgbuild + '\n', 'utf8') # Update source sha256sums and then delete the files: subprocess.check_call(['updpkgsums']) for info in [kern_info, headers_info, docs_info]: Path(info['filename']).unlink(missing_ok=True) # srcinfo with open('.SRCINFO', 'w', encoding='utf8') as f: f.write(subprocess.check_output(['makepkg', '--printsrcinfo']).decode()) # commit and push subprocess.check_call(['git', 'add', 'PKGBUILD', '.SRCINFO']) subprocess.check_call( ['git', 'commit', '-m', f"{kern_info['pkgver']}-{kern_info['pkgrel']}"] ) subprocess.check_call(['git', 'push']) if __name__ == '__main__': # Minimum age of a kernel package file on the Arch Linux Archive before we consider # updating to it. This is to avoid things like the mirror being partially updated, # or the kernel pulling in a dependency not yet in the users' mirror, etc. MINIMUM_PACKAGE_AGE = timedelta(days=1) kern_info = get_pkg_info(NAME) current_version = get_current_version() latest_version = kern_info['pkgver'], kern_info['pkgrel'] arch_archive_age = get_arch_archive_age(kern_info['filename']) if (current_version != latest_version) and arch_archive_age > MINIMUM_PACKAGE_AGE: print(f"{NAME}-versioned-bin is out of date!") update(kern_info) else: print(f"{NAME}-versioned-bin is up to date")