#!/usr/bin/env python3 from argparse import ArgumentParser from configparser import ConfigParser from os import PathLike from pathlib import Path from typing import Iterator, List, Optional, Set DEFAULT_PACKAGES_FILENAME = "packages.ini" FORMATS = ("list", "line") DISTRIBUTIONS = ("focal", "bullseye", "jammy", "bookworm") SETTINGS_SECTION = "=settings" DEVELOPMENT_SECTION = "=development" def load_packages( raw: str, distribution: str, development: bool = False, exclude: Optional[List[str]] = None, ) -> Set[str]: if distribution not in DISTRIBUTIONS: raise ValueError(f"Invalid distribution '{distribution}'") manager = ConfigParser(default_section=SETTINGS_SECTION) manager.read_string(raw) packages = set() exclude = set(exclude or []) for section, entries in manager.items(): if not development and section == DEVELOPMENT_SECTION or section in exclude: continue for package, distributions in entries.items(): if distribution in distributions.split(", "): packages.add(package) return packages def list_packages_files( paths: List[PathLike], ) -> Iterator[Path]: for path_like in paths: path = Path(path_like) if path.is_dir(): path = path / DEFAULT_PACKAGES_FILENAME if not path.is_file(): raise ValueError(f"{path} is not a file!") yield path def list_packages( paths: List[PathLike], distribution: str, development: bool = False, exclude: Optional[List[str]] = None, ) -> Set[str]: packages = set() for package_file in list_packages_files(paths): raw = package_file.read_text() packages.update(load_packages(raw, distribution, development, exclude)) return set(sorted(packages)) def run(): parser = ArgumentParser() parser.add_argument( "-f", "--format", choices=FORMATS, help="print packages list in a specific format.", default="list", ) parser.add_argument( "-d", "--dev", help="include development packages.", action="store_true", ) parser.add_argument( "-e", "--exclude", help="exclude packages sections.", action="append", ) parser.add_argument( "distribution", choices=DISTRIBUTIONS, help="list packages for the given distribution.", ) parser.add_argument( "path", nargs="+", help="list packages from given files or directories.", ) args = parser.parse_args() packages = list_packages(args.path, args.distribution, args.dev, args.exclude) if args.format == "list": print("\n".join(packages)) else: print(" ".join(packages)) if __name__ == "__main__": run()