libdnf icon indicating copy to clipboard operation
libdnf copied to clipboard

libdnf5 (python): `TransactionItem.get_reason_change_group_id()` is always empty?

Open supakeen opened this issue 2 years ago • 2 comments

Hi, I have the following code snippet which looks up some groups/packages; stuffs them into a transaction and then needs the reason for installation:

#!/usr/bin/python3
import sys

import libdnf5 as dnf5

from libdnf5.base import GoalProblem_NO_PROBLEM as NO_PROBLEM

base = dnf5.base.Base()

conf = base.get_config()
conf.fastestmirror = True
conf.install_weak_deps = True
conf.zchunk = False
conf.config_file_path = "/dev/null"
conf.cachedir = "/tmp/dnf-test"

base.setup()

repo_sack = base.get_repo_sack()

repo = repo_sack.create_repo("my-repo")

repo_conf = repo.get_config()
repo_conf.name = "fedora"
repo_conf.metalink = (
    "https://mirrors.fedoraproject.org/metalink?repo=fedora-38&arch=x86_64"
)

repo_sack.update_and_load_enabled_repos(load_system=False)

rpm_sack = base.get_rpm_package_sack()
rpm_sack.clear_user_excludes()

goal = dnf5.base.Goal(base)
goal.reset()

settings = dnf5.base.GoalJobSettings()
settings.group_with_name = True

for thing in sys.argv[1:]:
    goal.add_install(thing, settings)

transaction = goal.resolve()

if transaction.get_problems() != NO_PROBLEM:
    print("\n".join(transaction.get_resolve_logs_as_strings()))
    raise SystemExit()

tis = [
    ti
    for ti in transaction.get_transaction_packages()
    if dnf5.base.transaction.transaction_item_action_is_inbound(ti.get_action())
]

reasons = [
    "NONE",
    "DEPENDENCY",
    "USER",
    "CLEAN",
    "WEAK_DEPENDENCY",
    "GROUP",
    "EXTERNAL_USER",
]

for ti in tis:
    print(
        ti.get_package().get_name(),
        "--",
        reasons[ti.get_reason()],
        repr(ti.get_reason_change_group_id()),
    )

Call with python3 script.py '@core'. The output is (abbreviated):

user@muja images € ./dnf5-test.py '@core'
sudo -- GROUP ''
curl -- GROUP ''
...
audit-libs -- DEPENDENCY ''
glibc -- DEPENDENCY ''
libselinux -- DEPENDENCY ''
openldap -- DEPENDENCY ''
openssl-libs -- DEPENDENCY ''
pam-libs -- DEPENDENCY ''
zlib -- DEPENDENCY ''
dhcp-common -- DEPENDENCY ''
...

I would have expected the transaction items that have a get_reason() of GROUP to have a filled in get_reason_change_group_id(). Perhaps I have set up base incorrectly?

Similary, this has the same behavior in dnf(4):

#!/usr/bin/env python
import sys

import dnf

base = dnf.Base()
conf = base.conf
conf.cachedir = "/tmp/my_cache_dir"
conf.substitutions["releasever"] = "38"
conf.substitutions["basearch"] = "x86_64"

base.repos.add_new_repo(
    "my-repo",
    conf,
    baseurl=[
        "http://download.fedoraproject.org/pub/fedora/linux/releases/$releasever/Everything/$basearch/os/"
    ],
)
base.fill_sack()

base.install_specs(sys.argv[1:])
base.resolve()

tis = [
    ti
    for ti in base.transaction
    if ti.action in dnf.transaction.FORWARD_ACTIONS
]

for ti in tis:
    print(ti, ti.reason, ti.get_group())

supakeen avatar Jul 14 '23 18:07 supakeen

The field reason_change_group_id is currently utilized only by dnf5 mark group <groupid> <packageid> command to change the reason of an installed package to the group. In dnf5 it is not possible to mark a package as group-installed without specifying a group-id. An example use-case could be as follows:

# dnf install rpm-build                          # installs rpm-build with reason USER
# dnf install @rpm-development-tools             # rpm-build is part of rpm-development-tools but will stay on the system with USER reason
# dnf mark group rpm-development-tools rpm-build # will change the reason of rpm-build to GROUP. Here you will see reason_change_group_id in the transaction item set.

m-blaha avatar Jul 17 '23 08:07 m-blaha

The field reason_change_group_id is currently utilized only by dnf5 mark group <groupid> <packageid> command to change the reason of an installed package to the group. In dnf5 it is not possible to mark a package as group-installed without specifying a group-id. An example use-case could be as follows:

# dnf install rpm-build                          # installs rpm-build with reason USER
# dnf install @rpm-development-tools             # rpm-build is part of rpm-development-tools but will stay on the system with USER reason
# dnf mark group rpm-development-tools rpm-build # will change the reason of rpm-build to GROUP. Here you will see reason_change_group_id in the transaction item set.

Understood. I'm looking for a way to ask DNF 'I added install @core to my goal' to then get the packages that should be marked as group installed to @core. It seems DNF fills this in in during the resolve of the transaction: https://github.com/rpm-software-management/dnf5/blob/main/libdnf5/base/transaction.cpp#L435 (note: I am unfamiliar with libdnf!).

How does libdnf when doing an install know how to mark the packages? E.g. if I run the transaction it seems that the packages are marked correctly, I'd like to find that information without running the transaction.

My usecase is that I'm doing depsolving for a list of (user-requested) installs and excludes, resolving this to a set of RPMs, installing those through RPM. I then need to fix up the dnf state database after that. This works 'ok' so for user, weak, weak-dependency marked packages but for group I am unable to access which group things should belong to and so can't mark them correctly.

supakeen avatar Jul 17 '23 09:07 supakeen