Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Document base initialization for API users including reading config and variables #2219

Open
xylle opened this issue Mar 9, 2025 · 5 comments

Comments

@xylle
Copy link

xylle commented Mar 9, 2025

Hello,
I work with "Rocky Linux 9.0 (Blue Onyx)", python 3.9.10 and dnf 4.10.0
I make a plugin for dnf, and it's work an expected

import dnf
import json
from dnfpluginscore import _, logger

@dnf.plugin.register_command
class JsonUpdatesCommand(dnf.cli.Command):
    aliases = ('json-updates',)
    summary = _('Lister les mises à jour disponibles en JSON')

    def __init__(self, cli):
        super(JsonUpdatesCommand, self).__init__(cli)

    def configure(self):
        pass

    def run(self):
        self.base.fill_sack(load_system_repo=True, load_available_repos=True)
        query = self.base.sack.query().upgrades()

        updates = []
        for pkg in query:
            installed_query = self.base.sack.query().installed().filter(name=pkg.name)
            installed_pkg = next(iter(installed_query), None)
            if installed_pkg:
                installed_version = f"{installed_pkg.version}-{installed_pkg.release}"
            else:
                installed_version = "Non installé"
            updates.append({
                'paquet': pkg.name,
                'version_installee': installed_version,
                'version_disponible': f'{pkg.version}-{pkg.release}'
            })

        print(json.dumps(updates, indent=2))


def load_commands():
    return [JsonUpdatesCommand]

Partial output :

[
  {
    "paquet": "yum",
    "version_installee": "4.10.0-5.el9_0",
    "version_disponible": "4.14.0-17.el9"
  },
  {
    "paquet": "python3-dnf",
    "version_installee": "4.10.0-5.el9_0",
    "version_disponible": "4.14.0-17.el9"
  },
....

When I want to make a python script for the same thing, he doesn't work

#!/usr/bin/env python3

import dnf

base = dnf.Base()
base.fill_sack(load_system_repo=True, load_available_repos=True)
q = base.sack.query()
i = q.upgrades()

packages = list(i)
print("Installed package:")
for pkg in i:
    print(pkg, pkg.reponame)

The list of pkg update are empty on the same server
When I try i = q.installed() in place of i = q.upgrades(), I have the list of installed package.

@m-blaha
Copy link
Member

m-blaha commented Mar 10, 2025

I think you miss loading repository configurations in your example. You need to add base.read_all_repos() before the base.fill_sack() step:

...
base = dnf.Base()
base.read_all_repos()
base.fill_sack(load_system_repo=True, load_available_repos=True)
...

Without it, there are no repositories available (except for the "system repo" loaded from the rpmdb), thus no upgrades available.

@xylle
Copy link
Author

xylle commented Mar 10, 2025

Thanks, the first time I try :

...
base = dnf.Base()
base.read_all_repos()
base.fill_sack()
...

I have some error missing file in cache

...
base = dnf.Base()
base.read_all_repos()
base.fill_sack(load_system_repo=True, load_available_repos=True)
...

With this, it's works as expected.
it's possible to put this into documentation ?

@xylle
Copy link
Author

xylle commented Mar 10, 2025

I have some error in repo file : mirrorlist line finish with $rltype

[baseos]
name=Rocky Linux $releasever - BaseOS
mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=$basearch&repo=BaseOS-$releasever$rltype
#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/BaseOS/$basearch/os/
gpgcheck=1
enabled=1
countme=1
metadata_expire=6h
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-9

When I make dnf check-update I have no error, but with the script I have 404 error.
If I remove $rltype, it's work with cli and script

@m-blaha
Copy link
Member

m-blaha commented Mar 11, 2025

Regarding the fill_sack parameters - that's strange since True is the default value for both parameters, and I'd have expected both lines to behave the same.

And regarding the "error" in the repo file - you need to read the variable definitions (then DNF would correctly substitute the $rltype string with its actual value). You should probably also read the configuration file:

...
base = dnf.Base()
# read the configuration from /etc/dnf/dnf.conf
base.conf.read(priority=dnf.conf.PRIO_MAINCONFIG)
# update variable substitutions from /etc/dnf/vars (or other location configured via varsdir)
base.conf.substitutions.update_from_etc(base.conf.installroot, varsdir=base.conf.varsdir)
base.read_all_repos()
base.fill_sack(load_system_repo=True, load_available_repos=True)
...

I guess the DNF API usage should be better documented...

@xylle
Copy link
Author

xylle commented Mar 12, 2025

Thank you, it's working with $rltype.
I put the code for future research

    base = dnf.Base()
    # base.conf.read()
    
    # read the configuration from /etc/dnf/dnf.conf
    base.conf.read(priority=dnf.conf.PRIO_MAINCONFIG)
    # update variable substitutions from /etc/dnf/vars (or other location configured via varsdir)
    base.conf.substitutions.update_from_etc(base.conf.installroot, varsdir=base.conf.varsdir)

    # Charge les dépôts système ET disponibles pour obtenir les upgrades
    base.read_all_repos()
    base.fill_sack(load_system_repo=True, load_available_repos=True)
    
    upgrades = base.sack.query().upgrades()

Could you please add this code to the example in the documentation?

@m-blaha m-blaha changed the title DNF python usage : plugin vs script Document base initialization for API users including reading config and variables Mar 13, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants