bioarchlinux-tools/cleaner/repocleaner
2023-02-09 13:09:49 +08:00

144 lines
3.4 KiB
Python
Executable file

#!/usr/bin/env python3
import os
from collections import defaultdict
import re
import subprocess
import sys
from pathlib import Path
from typing import Set, List, Dict, Tuple
import archpkg
repo_path: Path = Path('/usr/share/lilac/Repo')
gitrepo_path: Path = Path('/usr/share/lilac/Packages/BioArchLinux').expanduser()
max_keep: int = 1
DRY_RUN: bool = False
re_package = re.compile(r'package(?:_(.+))?\s*\(')
def search_pkgbuild_for_pkgname(
pkgbuild: Path,
) -> Set[str]:
ret = set()
try:
with open(pkgbuild) as f:
for l in f:
l = l.strip()
m = re_package.match(l)
if m:
if m.group(1):
ret.add(m.group(1).strip())
else:
ret.add(pkgbuild.parent.name)
except FileNotFoundError:
pass
return ret
def get_all_pkgnames() -> Set[str]:
# also see lilac2.packages.get_all_pkgnames
packages: Set[str] = set()
for ly in gitrepo_path.glob('*/lilac.yaml'):
pkgfile = ly.with_name('package.list')
if pkgfile.exists():
with open(pkgfile) as f:
packages.update(f.read().split())
continue
pkgbuild = ly.with_name('PKGBUILD')
new = search_pkgbuild_for_pkgname(pkgbuild)
if new:
packages.update(new)
else:
packages.add(pkgbuild.parent.name)
return packages
def remove_pkg(path: Path) -> None:
if DRY_RUN:
return
try:
path.unlink()
except FileNotFoundError:
pass
sig = path.with_name(path.name + '.sig')
if sig.exists():
try:
sig.unlink()
except FileNotFoundError:
pass
def clean(path: Path, all_packages: Set[str]) -> None:
pkgs: Dict[str, List[Tuple[archpkg.PkgNameInfo, Path]]] = defaultdict(list)
debug_pkgs: List[Path] = []
for f in path.iterdir():
if f.name[0] == '.':
continue
if f.name.endswith(('.pkg.tar.xz', '.pkg.tar.zst')):
pkg = archpkg.PkgNameInfo.parseFilename(f.name)
if pkg.name.endswith('-debug'):
debug_pkgs.append(f)
continue
else:
name = pkg.name
if name not in all_packages:
print('package %s removed, removing file %s.' % (pkg.name, f))
remove_pkg(f)
else:
pkgs[pkg.name].append((pkg, f))
for v in pkgs.values():
try:
# some files may have been deleted already
v = [x for x in v if x[1].exists()]
v.sort(key=lambda x: x[1].stat().st_mtime)
except TypeError:
print('Bad things happen: %s' % v)
raise
for _, f in v[:-max_keep]:
print('remove old package file %s.' % f)
remove_pkg(f)
for f in debug_pkgs:
pkgname = f.name.replace('-debug-', '-')
if not f.with_name(pkgname).exists():
print('Removing debug package %s.' % f)
remove_pkg(f)
def main() -> None:
os.chdir(gitrepo_path)
try:
error = False
out = subprocess.check_output(['git', 'pull'],
stderr = subprocess.STDOUT)
except subprocess.CalledProcessError as e:
out = e.output
error = True
for line in out.decode('utf-8', errors='backslashreplace').splitlines():
if 'Already up-to-date.' in line:
continue
print(line)
if error:
sys.exit(1)
all_packages = get_all_pkgnames()
for d in repo_path.iterdir():
if d.is_dir():
clean(d, all_packages)
if __name__ == '__main__':
if len(sys.argv) == 1:
pass
elif len(sys.argv) == 2 and sys.argv[1] == '-n':
DRY_RUN = True
else:
sys.exit('bad argument')
main()