Created
March 5, 2021 14:35
-
-
Save gicmo/5450b6641ffa504aab1932fdfdcec359 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python3 | |
import argparse | |
import json | |
import os | |
import sys | |
import tempfile | |
import dnf | |
import dnf.conf | |
import dnf.conf.read | |
import osbuild.util.osrelease as ostrelease | |
class DepSolver: | |
def __init__(self, arch, relver, dirs): | |
self.base = dnf.Base() | |
self.arch = arch | |
self.basearch = dnf.rpm.basearch(arch) | |
conf = self.base.conf | |
conf.config_file_path = "/dev/null" | |
conf.persistdir = dirs["persistdir"] | |
conf.cachedir = dirs["cachedir"] | |
conf.substitutions["arch"] = arch | |
conf.substitutions["basearch"] = self.basearch | |
conf.substitutions["releasever"] = relver | |
conf.reposdir = [dirs["repodir"]] | |
self.repos = self.read_repos() | |
def read_repos(self): | |
conf = self.base.conf | |
reader = dnf.conf.read.RepoReader(conf, {}) | |
return {r.id: r for r in reader} | |
def reset(self): | |
base = self.base | |
base.reset(goal=True, repos=True, sack=True) | |
for repo in self.repos.values(): | |
base.repos.add(repo) | |
base.fill_sack(load_system_repo=False) | |
def filter(self, pkg): | |
sack = self.base.sack | |
return dnf.subject.Subject(pkg).get_best_query(sack).filter(latest=True) | |
def install(self, packages, excludes=None, optional=False): | |
self.base.install_specs(packages, exclude=(excludes or [])) | |
def resolve(self): | |
self.base.resolve() | |
dependencies = [] | |
for tsi in self.base.transaction: | |
# Avoid using the install_set() helper, as it does not guarantee | |
# a stable order | |
if tsi.action not in dnf.transaction.FORWARD_ACTIONS: | |
continue | |
package = tsi.pkg | |
dependencies.append({ | |
"name": package.name, | |
"epoch": package.epoch, | |
"version": package.version, | |
"release": package.release, | |
"arch": package.arch, | |
"repo_id": package.reponame, | |
"path": package.relativepath, | |
"remote_location": package.remote_location() | |
}) | |
return dependencies | |
def list_packages(text, solver): | |
parser = argparse.ArgumentParser() | |
parser.add_argument("--optional", action="store_true", default=False) | |
parser.add_argument("--except", dest="excludes", action="append") | |
parser.add_argument("packages", help="The template to process", nargs="*") | |
packages = [] | |
for line in text: | |
cmd, args = line[0], parser.parse_args(line[1:]) | |
if cmd != "installpkg": | |
print(f"{cmd} ignored", file=sys.stderr) | |
continue | |
pkgs = solver.install(args.packages, None, args.optional) | |
packages += pkgs | |
return packages | |
INSTALL = [ | |
"redhat-release", | |
"glibc", "glibc-minimal-langpack", "nss-altfiles", | |
"dracut-config-generic", "dracut-network", | |
"basesystem", "bash", "platform-python", | |
"shadow-utils", "chrony", "setup", "shadow-utils", | |
"sudo", "systemd", "coreutils", "util-linux", | |
"curl", "vim-minimal", | |
"rpm", "rpm-ostree", "polkit", | |
"lvm2", "cryptsetup", "pinentry", | |
"e2fsprogs", "dosfstools", | |
"keyutils", "gnupg2", | |
"attr", "xz", "gzip", | |
"firewalld", "iptables", | |
"NetworkManager", "NetworkManager-wifi", "NetworkManager-wwan", | |
"wpa_supplicant", | |
"dnsmasq", "traceroute", | |
"hostname", "iproute", "iputils", | |
"openssh-clients", "procps-ng", "rootfiles", | |
"openssh-server", "passwd", | |
"policycoreutils", "policycoreutils-python-utils", | |
"selinux-policy-targeted", "setools-console", | |
"less", "tar", "rsync", | |
"fwupd", "usbguard", | |
"bash-completion", "tmux", | |
"ima-evm-utils", | |
"audit", | |
"podman", "container-selinux", "skopeo", "criu", | |
"slirp4netns", "fuse-overlayfs", | |
"clevis", "clevis-dracut", "clevis-luks", | |
"greenboot", "greenboot-grub2", "greenboot-rpm-ostree-grub2", "greenboot-reboot", "greenboot-status", | |
"grub2", "grub2-efi-x64", "efibootmgr", "shim-x64", "microcode_ctl", | |
"iwl1000-firmware", "iwl100-firmware", "iwl105-firmware", "iwl135-firmware", | |
"iwl2000-firmware", "iwl2030-firmware", "iwl3160-firmware", "iwl5000-firmware", | |
"iwl5150-firmware", "iwl6000-firmware", "iwl6050-firmware", "iwl7260-firmware", | |
] | |
EXCLUDES = ["rng-tools", "subscription-manager"] | |
def main(): | |
parser = argparse.ArgumentParser() | |
parser.add_argument("--basearch", help="Set the `basearch` variable", default="x86_64") | |
parser.add_argument("--product", help="Set the `product` variable", default="fedora") | |
parser.add_argument("--dnf-cache", metavar="PATH", type=os.path.abspath, default=None, | |
help="Path to DNF cache-directory to use") | |
parser.add_argument("--repo-dir", metavar="PATH", type=os.path.abspath, | |
default="/etc/yum.repos.d", | |
help="Path to DNF repositories directory") | |
parser.add_argument("--os-version", metavar="PATH", default=None, | |
help="OS version to use for dnf") | |
args = parser.parse_args() | |
variables = { | |
"basearch": args.basearch, | |
"product": args.product | |
} | |
packages = [] | |
os_version = args.os_version | |
if not os_version: | |
release = ostrelease.parse_files(*ostrelease.DEFAULT_PATHS) | |
os_version = release["VERSION_ID"] | |
with tempfile.TemporaryDirectory(dir="/var/tmp") as tmp: | |
persistdir = os.path.join(tmp, "dnf-persist") | |
cachedir = args.dnf_cache or os.path.join(tmp, "dnf-cache") | |
dirs = { | |
"persistdir": persistdir, | |
"cachedir": cachedir, | |
"repodir": args.repo_dir | |
} | |
solver = DepSolver(args.basearch, os_version, dirs) | |
solver.reset() | |
solver.install(INSTALL, EXCLUDES) | |
solver.install(["tuned"]) | |
packages = solver.resolve() | |
json.dump(packages, sys.stdout, indent=2) | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment