1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
| import subprocess import sys import tempfile import os
VERSION = "1.0.0" SCRIPTNAME = os.path.basename(sys.argv[0])
PRINT_ORDER = ["stable", "testing", "unstable"]
def usage(): print(f"""NAME {SCRIPTNAME} - check how mixed (or unmixed) your system is
SYNOPSIS {SCRIPTNAME} [OPTION]
DESCRIPTION The script uses apt-show-versions to gather information about package repositories (names, quantity and percent of the packages in system) used in the current Debian install.
-m, --show-missing Print package names that are not found in any repository. These normally consist of obsolete packages or packages installed outside APT.
-h, --help Show usage and exit. -V, --version Show version info and exit. """) sys.exit(0)
def version(): print(f"{SCRIPTNAME} {VERSION}") sys.exit(0)
import subprocess
def pick_preferred_repo(pkg_name: str, repo: str) -> str: for pref in ["stable", "unstable"]: if repo.startswith(pref): return pref
if repo.startswith("testing"): try: output = subprocess.check_output( ["apt", "list", "-a", pkg_name], text=True, stderr=subprocess.DEVNULL ) except subprocess.CalledProcessError: return "missing"
PRIORITY = ["stable", "unstable", "testing"]
for line in output.splitlines(): line = line.strip() if "[installed" not in line: continue
if "unstable" in line: return "unstable"
return "testing"
return "missing"
def main(): show_missing = False if len(sys.argv) > 1: arg = sys.argv[1] if arg in ("-h", "--help"): usage() elif arg in ("-V", "--version"): version() elif arg in ("-m", "--show-missing"): show_missing = True
for dep in ["apt-show-versions", "bc"]: if not shutil.which(dep): print(f"Install {dep} first.", file=sys.stderr) sys.exit(1)
raw = subprocess.check_output( ["apt-show-versions"], text=True, errors="ignore" ).splitlines()
packages = {} for line in raw: if " not installed" in line: continue parts = line.split() pkg = parts[0].split(":")[0] repo_field = parts[0].split("/")[1] if "/" in parts[0] else "" repo = pick_preferred_repo(pkg, repo_field) packages[pkg] = repo
total = len(packages) counts = {r: 0 for r in PRINT_ORDER + ["missing"]} for repo in packages.values(): counts[repo] += 1
print("==========================================================") lsb = subprocess.getoutput("lsb_release -sd") host = os.uname().nodename print(f"Package status of {host} - {lsb}") print("----------------------------------------------------------")
first = True for repo in PRINT_ORDER: if counts[repo] == 0: continue percent = counts[repo] / total * 100 if first: print(f"{percent:6.2f} % {repo:<18} {counts[repo]:9d} \t packages") first = False else: print(f"{percent:6.2f} % {repo:<18} {counts[repo]:9d} \t \" ")
if counts["missing"] > 0: percent = counts["missing"] / total * 100 print(f"{percent:6.2f} % {'not in any repo':<18} {counts['missing']:9d} \t \" ")
print("----------------------------------------------------------") if show_missing and counts["missing"] > 0: print("Packages not in any repo") for pkg, repo in packages.items(): if repo == "missing": print(f"\t{pkg}") print("----------------------------------------------------------")
print(f"100.00 % \t total \t {total:17d} \t packages") print("----------------------------------------------------------")
if __name__ == "__main__": import shutil main()
|