Skip to content

Instantly share code, notes, and snippets.

@ispanos
Created October 10, 2023 19:23
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ispanos/4e5dfeae98adccf71b42906c049d8abe to your computer and use it in GitHub Desktop.
Save ispanos/4e5dfeae98adccf71b42906c049d8abe to your computer and use it in GitHub Desktop.
dnf 'exclusively' installed packages
import subprocess
import re
import sys
def get_pks_repoquery():
# Use repoquery to create a list of userinstalled packages
return set(subprocess.check_output(
'dnf repoquery --userinstalled --qf "%{name}"', shell=True, text=True
).splitlines())
def line_to_packages(line):
_, command = line.split(':', 1)
command = command.strip()
arguments = command.split()
if "install" in arguments:
arguments.remove("install")
if "remove" in arguments:
arguments.remove("remove")
if "autoremove" in arguments:
arguments.remove("autoremove")
if "-y" in arguments:
arguments.remove("-y")
# remove flags from arguments
packages = [arg for arg in arguments if arg[0:2] != "--"]
return packages
def get_trans_dict():
# Get the list of transaction IDs where packages were installed
transactions = subprocess.check_output(
"dnf history", shell=True, text=True
).splitlines()
transactions_dict = {}
# Ignore 1st transaction (made by anaconda?)
for transaction in transactions[1:]:
if re.match(r'^-+$', transaction) is not None:
continue
line = transaction.split('|')
id = int(line[0])
date = line[2].strip()
action = line[3].strip()
transactions_dict[id] = {'date': date, 'action': action}
return transactions_dict
def get_pkgs_in_trans(id):
transaction = subprocess.check_output(
f"dnf history info {id}", shell=True, text=True).splitlines()
for line in transaction:
if "User" in line and "System <unset>" in line:
# Special kinds of packages that
# are installed by "shadow" transactions.
return None
if "Command Line" in line:
if "--disablerepo=*" in line or "groupupdate" in line:
print(f"Transaction id: {id}", file=sys.stderr)
print("Ignoring the following dnf command:", file=sys.stderr)
print(line, file=sys.stderr)
return None
return line_to_packages(line)
def get_pkgs_from_history():
transactions_dict = get_trans_dict()
installed_packages = set()
removed_packages = set()
for i in range(2, 1+max(transactions_dict.keys())):
if transactions_dict[i]['action'] not in ['Removed', 'Install']:
continue
packages = get_pkgs_in_trans(i)
if not packages:
continue
if transactions_dict[i]['action'] == 'Install':
installed_packages.update(packages)
if transactions_dict[i]['action'] == 'Removed':
for package in packages:
if package not in installed_packages:
removed_packages.update(packages)
else:
installed_packages.remove(package)
return installed_packages, removed_packages
installed_packages, removed_packages = get_pkgs_from_history()
# print("Installed packages:")
# for p in sorted(installed_packages):
# # print(f"- \"{p}\"")
# print(f"- {p}")
# print()
# print("Removed packages:")
# for p in removed_packages:
# print(f"- {p}")
print("\n"*2)
print("history + repoquery - their intesection")
for i in get_pks_repoquery().symmetric_difference(installed_packages):
print(i)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment