This moves the dnf and dnf5 code into a new osbuild module called solver. The dnf specific code is in dnf.py and dnf5 is in dnf5.py At runtime the osbuild-depsolve-dnf script reads a config file from /usr/lib/osbuild/solver.json and imports the selected solver. This currently just contains a 'use_dnf5' bool but can be extended to support other configuration options or depsolvers. At build time a config file is selected from tools/solver-dnf.json or tools/solver-dnf5.json and installed. Currently dnf5 is not installed, it will be added when dnf5 5.2.1.0 becomes available in rawhide (Fedora 41). The error messages have been normalized since the top level functions in osbuild-depsolve-dnf do not know which version of dnf is being used.
78 lines
1.8 KiB
Python
Executable file
78 lines
1.8 KiB
Python
Executable file
import abc
|
|
import os
|
|
import urllib.error
|
|
import urllib.parse
|
|
import urllib.request
|
|
|
|
|
|
class Solver(abc.ABC):
|
|
@abc.abstractmethod
|
|
def dump(self):
|
|
pass
|
|
|
|
@abc.abstractmethod
|
|
def depsolve(self, arguments):
|
|
pass
|
|
|
|
@abc.abstractmethod
|
|
def search(self, args):
|
|
pass
|
|
|
|
|
|
class SolverBase(Solver):
|
|
# put any shared helpers in here
|
|
pass
|
|
|
|
|
|
class SolverException(Exception):
|
|
pass
|
|
|
|
|
|
class GPGKeyReadError(SolverException):
|
|
pass
|
|
|
|
|
|
class TransactionError(SolverException):
|
|
pass
|
|
|
|
|
|
class RepoError(SolverException):
|
|
pass
|
|
|
|
|
|
class MarkingError(SolverException):
|
|
pass
|
|
|
|
|
|
class DepsolveError(SolverException):
|
|
pass
|
|
|
|
|
|
def modify_rootdir_path(path, root_dir):
|
|
if path and root_dir:
|
|
# if the root_dir is set, we need to translate the key path to be under this directory
|
|
return os.path.join(root_dir, path.lstrip("/"))
|
|
return path
|
|
|
|
|
|
def read_keys(paths, root_dir=None):
|
|
keys = []
|
|
for path in paths:
|
|
url = urllib.parse.urlparse(path)
|
|
if url.scheme == "file":
|
|
path = url.path
|
|
path = modify_rootdir_path(path, root_dir)
|
|
try:
|
|
with open(path, mode="r", encoding="utf-8") as keyfile:
|
|
keys.append(keyfile.read())
|
|
except Exception as e:
|
|
raise GPGKeyReadError(f"error loading gpg key from {path}: {e}") from e
|
|
elif url.scheme in ["http", "https"]:
|
|
try:
|
|
resp = urllib.request.urlopen(urllib.request.Request(path))
|
|
keys.append(resp.read().decode())
|
|
except urllib.error.URLError as e:
|
|
raise GPGKeyReadError(f"error reading remote gpg key at {path}: {e}") from e
|
|
else:
|
|
raise GPGKeyReadError(f"unknown url scheme for gpg key: {url.scheme} ({path})")
|
|
return keys
|