no longer build myplc-docs master
authorThierry Parmentelat <thierry.parmentelat@inria.fr>
Thu, 18 Dec 2025 15:25:48 +0000 (16:25 +0100)
committerThierry Parmentelat <thierry.parmentelat@inria.fr>
Thu, 18 Dec 2025 15:25:48 +0000 (16:25 +0100)
20 files changed:
build.common
config.lxc/devel.pkgs
config.mlab/nodeimage.pkgs
config.mlab/runtime.pkgs
config.nornet/nodeimage.pkgs
config.onelab/nodeimage.pkgs
config.planetlab/bootcd.pkgs
config.planetlab/nodeimage.pkgs
config.planetlab/runtime.pkgs
create-vm.sh
fedora-mirror.sh
lbuild-initvm.sh
lbuild-nightly.sh
lxc.mk
mirroring/centos6/yum.repos.d/building.repo.in [deleted file]
mirroring/f37/yum.repos.d/building.repo.in [deleted file]
mirroring/f39/yum.repos.d/building.repo.in [deleted file]
mirroring/f41/yum.repos.d/building.repo.in [new file with mode: 0644]
mirroring/f43/yum.repos.d/building.repo.in [new file with mode: 0644]
pkgs.py

index 9d59dcb..4273892 100644 (file)
@@ -65,7 +65,7 @@ function pl_getReleaseName () {
         [Ss]L*)
             releasename=sl$release
             ;;
-        wheezy|jessie|trusty|xenial|bionic|focal|jammy)
+        wheezy|jessie|trusty|xenial|bionic|focal|jammy|noble)
             releasename=$distro
             ;;
         *)
index 8a72ab1..a7575dd 100644 (file)
@@ -29,6 +29,7 @@ package: libtool
 # package: mysql mysql-devel mysql-server
 # package: python2 python-unversioned-command python2-devel
 package: python3 python3-devel
+package>=f41: python3-setuptools
 # package: doxygen
 package: cronie
 package: xmlsec1 xmlsec1-openssl
@@ -133,3 +134,7 @@ package: texlive-ec
 # needed so the spawned container actually starts its networking
 package: NetworkManager
 package: hostname
+# hard requirement, this no longer gets pulled
+package>=f43: python3-rpm
+# comfort, remove zillion warnings about missing langpacks
+package>=f41: glibc-langpack-en
index fae3b30..931a8f8 100644 (file)
@@ -18,7 +18,7 @@ package: python
 package: cpio
 package: e2fsprogs
 package: ed
-package: file     
+package: file
 package: glibc
 package: hdparm
 package: initscripts
@@ -95,7 +95,7 @@ package>=f8 package>=centos6: util-linux-ng
 package=centos5: util-linux
 
 package<=f8 package=centos5: termcap libtermcap vixie-cron
-package>=centos6: compat-libtermcap 
+package>=centos6: compat-libtermcap
 package>=f10: cronie
 
 package=centos6: epel-release
index 3ebc1a5..07f6601 100644 (file)
@@ -4,7 +4,7 @@ groupdesc: Test Vserver for MyPlc Native
 package: openssh-clients curl
 package: emacs-nox
 package: bind-utils
-package: file 
+package: file
 
 # while runing the tests, try to work around a glitch with yum by running yum=complete-transaction
 package: yum-utils
index 64bd4f7..6e3aa48 100644 (file)
@@ -28,7 +28,7 @@ package: python
 package: cpio
 package: e2fsprogs
 package: ed
-package: file     
+package: file
 package: glibc
 package: hdparm
 package: initscripts
index 253fc57..b51e85c 100644 (file)
@@ -18,7 +18,7 @@ package: python
 package: cpio
 package: e2fsprogs
 package: ed
-package: file     
+package: file
 package: glibc
 package: hdparm
 package: initscripts
index e4d228a..9863a33 100644 (file)
@@ -52,7 +52,7 @@ package: btrfs-progs
 # make this explicit for f14 as we need mkfs.ext2 in bm
 package: e2fsprogs
 # used to be installed until f12, make it explicit for f14, might come in handy
-package>=f14: rsyslog 
+package>=f14: rsyslog
 package: strace lsof
 
 # 03/2015: let's move on
index 0879fcb..2b27008 100644 (file)
@@ -18,7 +18,7 @@ package: python
 package: cpio
 package: e2fsprogs
 package: ed
-package: file     
+package: file
 package: glibc
 package: hdparm
 package: initscripts
index 398795b..c0f1cc3 100644 (file)
@@ -6,7 +6,8 @@ package: emacs-nox
 # for host
 package: bind-utils
 # for host, on jammy
-package=jammy: bind9-dnsutils
+package=jammy: bind9-dnsutils bind9-utils
+package=noble: bind9-dnsutils bind9-utils
 package: file
 
 # while runing the tests, try to work around a glitch with yum by running yum=complete-transaction
index 658f416..8d8cc4b 100755 (executable)
@@ -28,7 +28,7 @@ LOGS=$HOME/machines
 
 DOMAIN=pl.sophia.inria.fr
 
-DEFAULT_DISTRO=f39
+DEFAULT_DISTRO=f43
 DEFAULT_MEMORY=16384
 
 CONFIRM=
index c3d6d70..03ebb09 100755 (executable)
@@ -14,10 +14,14 @@ root=/mirror/
 
 
 us_fedora_url=rsync://mirrors.kernel.org/fedora
-eu_fedora_url=rsync://mirror1.hs-esslingen.de/fedora/linux
 
-default_distroname="f39"
-all_distronames="f37 f39"
+# used to be this one
+# eu_fedora_url=rsync://mirror1.hs-esslingen.de/fedora/linux
+# browse content at https://mirror.in2p3.fr/pub/fedora/linux/releases/
+eu_fedora_url=rsync://mirror.in2p3.fr/pub/fedora/linux
+
+default_distroname="f43"
+all_distronames="f41 f43"
 
 global_arch="x86_64"
 
index 1d64ce0..a6ea96f 100755 (executable)
@@ -30,7 +30,7 @@ function lxcroot () {
 
 # XXX fixme : when creating a 32bits VM we need to call linux32 as appropriate...s
 
-DEFAULT_FCDISTRO=f39
+DEFAULT_FCDISTRO=f43
 DEFAULT_PLDISTRO=lxc
 DEFAULT_PERSONALITY=linux64
 DEFAULT_MEMORY=3072
@@ -44,8 +44,9 @@ VIF_GUEST=eth0
 
 ##########
 FEDORA_MIRROR="http://mirror.onelab.eu/"
+# dnf-yum no longer exists in recent fedora
 FEDORA_MIRROR_KEYS="http://mirror.onelab.eu/keys/"
-FEDORA_PREINSTALLED="dnf dnf-yum passwd rsyslog vim-minimal dhclient chkconfig rootfiles policycoreutils openssh-server openssh-clients"
+FEDORA_PREINSTALLED="dnf passwd rsyslog vim-minimal dhclient chkconfig rootfiles policycoreutils openssh-server openssh-clients"
 DEBIAN_PREINSTALLED="openssh-server openssh-client"
 
 ########## networking utilities
@@ -82,7 +83,7 @@ function package_method () {
     case $fcdistro in
         f[0-9]*|centos[0-9]*|sl[0-9]*)
             echo dnf ;;
-        wheezy|jessie|trusty|xenial|bionic|focal|jammy)
+        wheezy|jessie|trusty|xenial|bionic|focal|jammy|noble)
             echo debootstrap ;;
         *)
             echo "Unknown package_method for distro $fcdistro" ;;
@@ -105,7 +106,7 @@ function network_config_method () {
             echo networkmanager ;;
         wheezy|jessie|trusty|xenial|bionic)
             echo interfaces ;;
-        focal|jammy)
+        focal|jammy|noble)
             echo systemd ;;
         *)
             echo "Unknown network_config_method for distro $fcdistro" ;;
@@ -202,6 +203,8 @@ function fedora_download() {
     # copy yum config and repo files
     cp /etc/yum.conf $INSTALL_ROOT/etc/
     cp /etc/yum.repos.d/fedora{,-updates}.repo $INSTALL_ROOT/etc/yum.repos.d/
+    # on boxes managed by Francis's upgrade script, we use other mirrors
+    #cp /etc/yum.repos.d/so-fedora{,-updates}.repo $INSTALL_ROOT/etc/yum.repos.d/
 
     # append fedora repo files with hardwired releasever and basearch
     if [ -z "$USE_UPSTREAM_REPOS" ]; then
@@ -249,7 +252,11 @@ function fedora_download() {
     # So ideally if we want to be able to build f12 images from f18 we need an rpm that has
     # this patch undone, like we have in place on our f14 boxes (our f14 boxes need a f18-like rpm)
 
-    DNF="dnf --installroot=$INSTALL_ROOT --nogpgcheck -y --releasever=${fedora_release}"
+    DNF="dnf --installroot=$INSTALL_ROOT --no-best --nogpgcheck -y --releasever=${fedora_release}"
+    # dnf-yum no longer exists in recent fedora
+    case $fedora_release in
+        f41|f43) FEDORA_PREINSTALLED="$FEDORA_PREINSTALLED dnf-yum" ;;
+    esac
     echo "$DNF install $FEDORA_PREINSTALLED"
     $DNF install $FEDORA_PREINSTALLED || { echo "Failed to download rootfs, aborting." ; return 1; }
 
@@ -417,7 +424,7 @@ function debian_mirror () {
     case $fcdistro in
         wheezy|jessie)
             echo http://ftp2.fr.debian.org/debian/ ;;
-        trusty|xenial|bionic|focal|jammy)
+        trusty|xenial|bionic|focal|jammy|noble)
             echo http://www-ftp.lip6.fr/pub/linux/distributions/Ubuntu/archive/ ;;
         *) echo unknown distro $fcdistro; exit 1;;
     esac
@@ -913,7 +920,8 @@ function wait_for_ssh () {
     local lxc=$1; shift
 
     # if run in public_ip mode, we know the IP of the guest and it is specified here
-    [ -n "$1" ] && { guest_ip=$1; shift; }
+    local specified_ip
+    [ -n "$1" ] && { specified_ip=$1; shift; }
 
     #wait max 2 min for sshd to start
     local success=""
@@ -922,14 +930,19 @@ function wait_for_ssh () {
 
     local counter=1
     while [ "$current_time" -lt "$stop_time" ] ; do
-        echo "$counter-th attempt to reach sshd in container $lxc ..."
-        [ -z "$guest_ip" ] && guest_ip=$(guest_ipv4 $lxc) || :
+        if [ -n "$specified_ip" ]; then
+            guest_ip="${specified_ip}"
+        else
+            guest_ip=$(guest_ipv4 $lxc) || :
+        fi
+        echo "$counter-th attempt to reach sshd in container $lxc on address $guest_ip ..."
         [ -n "$guest_ip" ] && ssh -o "StrictHostKeyChecking no" $guest_ip arch && {
             success=true; echo "SSHD in container $lxc is UP on IP $guest_ip"; break ; } || :
         # some of our boxes have gone through a long upgrade historically, and
         # so they don't end up with the same gid mapping for the ssh_keys
         # group as the ones in the guest that result from a fresh install
-        virsh -c lxc:/// lxc-enter-namespace $lxc /bin/bash -c "chown root:ssh_keys /etc/ssh/*_key" || :
+        # 2024 : lxc-enter-namespace is broken anyways
+        # virsh -c lxc:/// lxc-enter-namespace $lxc /bin/bash -c "chown root:ssh_keys /etc/ssh/*_key" || :
         counter=$(($counter+1))
         sleep 10
         current_time=$(date +%s)
@@ -1090,6 +1103,7 @@ function main () {
         NETMASK=$(masklen_to_netmask $MASKLEN)
         GATEWAY=$(ip route show | grep default | awk '{print $3}' | head -1)
         VIF_HOST="vif$(echo $GUEST_HOSTNAME | cut -d. -f1)"
+        [[ -z "$GUEST_IP" ]] && { echo "could not resolve $GUEST_HOSTNAME - exiting" ; exit 1 ; }
     fi
 
     setup_lxc $lxc $fcdistro $pldistro $personality
index 9991abe..e676d70 100755 (executable)
@@ -11,7 +11,7 @@ COMMAND=$(basename $0)
 export PATH=$PATH:/bin:/sbin
 
 # default values, tunable with command-line options
-DEFAULT_FCDISTRO=f39
+DEFAULT_FCDISTRO=f43
 DEFAULT_PLDISTRO=lxc
 DEFAULT_PERSONALITY=linux64
 DEFAULT_MAILDEST="thierry.parmentelat at inria.fr"
@@ -97,18 +97,23 @@ function guest_ipv4() {
 function summary () {
     from=$1; shift
     echo "******************** BEG SUMMARY"
-    python3 - $from <<EOF
-#!/usr/bin/env python3
+    python - $from <<EOF
 # read a full log and tries to extract the interesting stuff
 
 import sys, re
 m_show_line = re.compile(
-".* (BEG|END) (RPM|LXC).*|.*'boot'.*|\* .*| \* .*|.*is not installed.*|.*PROPFIND.*|.* (BEG|END).*:run_log.*|.* Within LXC (BEG|END) .*|.* MAIN (BEG|END).*")
-m_installing_any = re.compile('\r  (Installing:[^\]]*]) ')
-m_installing_err = re.compile('\r  (Installing:[^\]]*])(..+)')
-m_installing_end = re.compile('Installed:.*')
-m_installing_doc1 = re.compile("(.*)install-info: No such file or directory for /usr/share/info/\S+(.*)")
-m_installing_doc2 = re.compile("(.*)grep: /usr/share/info/dir: No such file or directory(.*)")
+r".* (BEG|END) (RPM|LXC).*|.*'boot'.*|\* .*| \* .*"
+"|.*is not installed.*"
+"|.*PROPFIND.*"
+"|.* (BEG|END).*:run_log.*"
+"|.* Within LXC (BEG|END) .*"
+"|.* MAIN (BEG|END).*"
+)
+m_installing_any = re.compile(r"\r  (Installing:[^\]]*]) ")
+m_installing_err = re.compile(r"\r  (Installing:[^\]]*])(..+)")
+m_installing_end = re.compile(r"Installed:.*")
+m_installing_doc1 = re.compile(r"(.*)install-info: No such file or directory for /usr/share/info/\S+(.*)")
+m_installing_doc2 = re.compile(r"(.*)grep: /usr/share/info/dir: No such file or directory(.*)")
 
 def summary (filename):
 
diff --git a/lxc.mk b/lxc.mk
index 32dd1a5..9d9fb47 100644 (file)
--- a/lxc.mk
+++ b/lxc.mk
@@ -56,7 +56,8 @@ ALL += myplc
 # together with the utility script docbook2drupal.sh
 myplc-docs-MODULES := myplc plcapi nodemanager monitor
 myplc-docs-SPEC := myplc-docs.spec
-ALL += myplc-docs
+# with f43 myplc-docs won't build anymore
+#ALL += myplc-docs
 
 # using some other name than myplc-release, as this is a make target already
 release-MODULES := myplc
diff --git a/mirroring/centos6/yum.repos.d/building.repo.in b/mirroring/centos6/yum.repos.d/building.repo.in
deleted file mode 100644 (file)
index cfc65cf..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-[base]
-name=CentOS-$releasever - Base
-baseurl=@MIRRORURL@/centos/6.4/os/$basearch/
-gpgcheck=1
-gpgkey=@MIRRORURL@/centos/RPM-GPG-KEY-CentOS-6
-
-[updates]
-name=CentOS-$releasever - Updates
-baseurl=@MIRRORURL@/centos/6.4/updates/$basearch/
-gpgcheck=1
-gpgkey=@MIRRORURL@/centos/RPM-GPG-KEY-CentOS-6
-
-[epel]
-name=Extra Packages for Enterprise Linux 6 - $basearch
-baseurl=@MIRRORURL@/fedora-epel/6/i386/
-failovermethod=priority
-enabled=1
-gpgcheck=1
-gpgkey=@MIRRORURL@/fedora-epel/RPM-GPG-KEY-EPEL-6
diff --git a/mirroring/f37/yum.repos.d/building.repo.in b/mirroring/f37/yum.repos.d/building.repo.in
deleted file mode 100644 (file)
index 540ff79..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-[fedora]
-name=Fedora 37 - $basearch
-baseurl=@MIRRORURL@/fedora/releases/37/Everything/$basearch/os/
-enabled=1
-metadata_expire=7d
-gpgcheck=1
-gpgkey=http://mirror.onelab.eu/keys/RPM-GPG-KEY-fedora-37-primary
-
-[updates]
-name=Fedora 37 - $basearch - Updates
-baseurl=@MIRRORURL@/fedora/updates/37/Everything/$basearch/
-enabled=1
-metadata_expire=7d
-gpgcheck=1
-gpgkey=http://mirror.onelab.eu/keys/RPM-GPG-KEY-fedora-37-primary
-
-[modular]
-name=Fedora 37 - $basearch - Updates
-baseurl=@MIRRORURL@/fedora/updates/37/Modular/$basearch/
-enabled=1
-metadata_expire=7d
-gpgcheck=1
-gpgkey=http://mirror.onelab.eu/keys/RPM-GPG-KEY-fedora-37-primary
diff --git a/mirroring/f39/yum.repos.d/building.repo.in b/mirroring/f39/yum.repos.d/building.repo.in
deleted file mode 100644 (file)
index d13dddc..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-[fedora]
-name=Fedora 39 - $basearch
-baseurl=@MIRRORURL@/fedora/releases/39/Everything/$basearch/os/
-enabled=1
-metadata_expire=7d
-gpgcheck=1
-gpgkey=http://mirror.onelab.eu/keys/RPM-GPG-KEY-fedora-39-primary
-
-[updates]
-name=Fedora 39 - $basearch - Updates
-baseurl=@MIRRORURL@/fedora/updates/39/Everything/$basearch/
-enabled=1
-metadata_expire=7d
-gpgcheck=1
-gpgkey=http://mirror.onelab.eu/keys/RPM-GPG-KEY-fedora-39-primary
-
-[modular]
-name=Fedora 39 - $basearch - Updates
-baseurl=@MIRRORURL@/fedora/updates/39/Modular/$basearch/
-enabled=1
-metadata_expire=7d
-gpgcheck=1
-gpgkey=http://mirror.onelab.eu/keys/RPM-GPG-KEY-fedora-39-primary
diff --git a/mirroring/f41/yum.repos.d/building.repo.in b/mirroring/f41/yum.repos.d/building.repo.in
new file mode 100644 (file)
index 0000000..a4d90d8
--- /dev/null
@@ -0,0 +1,23 @@
+[fedora]
+name=Fedora 41 - $basearch
+baseurl=@MIRRORURL@/fedora/releases/41/Everything/$basearch/os/
+enabled=1
+metadata_expire=7d
+gpgcheck=1
+gpgkey=http://mirror.onelab.eu/keys/RPM-GPG-KEY-fedora-41-primary
+
+[updates]
+name=Fedora 41 - $basearch - Updates
+baseurl=@MIRRORURL@/fedora/updates/41/Everything/$basearch/
+enabled=1
+metadata_expire=7d
+gpgcheck=1
+gpgkey=http://mirror.onelab.eu/keys/RPM-GPG-KEY-fedora-41-primary
+
+[modular]
+name=Fedora 41 - $basearch - Updates
+baseurl=@MIRRORURL@/fedora/updates/41/Modular/$basearch/
+enabled=1
+metadata_expire=7d
+gpgcheck=1
+gpgkey=http://mirror.onelab.eu/keys/RPM-GPG-KEY-fedora-41-primary
diff --git a/mirroring/f43/yum.repos.d/building.repo.in b/mirroring/f43/yum.repos.d/building.repo.in
new file mode 100644 (file)
index 0000000..25d7e57
--- /dev/null
@@ -0,0 +1,23 @@
+[fedora]
+name=Fedora 43 - $basearch
+baseurl=@MIRRORURL@/fedora/releases/43/Everything/$basearch/os/
+enabled=1
+metadata_expire=7d
+gpgcheck=1
+gpgkey=http://mirror.onelab.eu/keys/RPM-GPG-KEY-fedora-43-primary
+
+[updates]
+name=Fedora 43 - $basearch - Updates
+baseurl=@MIRRORURL@/fedora/updates/43/Everything/$basearch/
+enabled=1
+metadata_expire=7d
+gpgcheck=1
+gpgkey=http://mirror.onelab.eu/keys/RPM-GPG-KEY-fedora-43-primary
+
+[modular]
+name=Fedora 43 - $basearch - Updates
+baseurl=@MIRRORURL@/fedora/updates/43/Modular/$basearch/
+enabled=1
+metadata_expire=7d
+gpgcheck=1
+gpgkey=http://mirror.onelab.eu/keys/RPM-GPG-KEY-fedora-43-primary
diff --git a/pkgs.py b/pkgs.py
index 3291dbe..4ba02af 100755 (executable)
--- a/pkgs.py
+++ b/pkgs.py
@@ -36,7 +36,7 @@ import re
 
 default_arch = 'x86_64'
 known_archs = ['i386', 'i686', 'x86_64']
-default_fcdistro = 'f39'
+default_fcdistro = 'f43'
 known_fcdistros = [
     'centos5', 'centos6',
     # oldies but we have references to that in the pkgs files
@@ -45,7 +45,7 @@ known_fcdistros = [
     # these ones are still relevant;
     # f32 is mentioned to be able to use create-vms with that distro
     # as we're running into issues to build a minimal f33 from a f29 host
-    'f29', 'f31', 'f32', 'f33', 'f35', 'f37', 'f39',
+    'f29', 'f31', 'f32', 'f33', 'f35', 'f37', 'f39', 'f41', 'f43',
     # scientific linux
     'sl6',
     # debians
@@ -56,12 +56,13 @@ known_fcdistros = [
     'bionic',  # 18.04 LTS
     'focal',   # 20.04 LTS
     'jammy',   # 22.04 LTS
+    'noble',   # 24.04 LTS
 ]
 default_pldistro = 'onelab'
 
 known_keywords = [
     'group', 'groupname', 'groupdesc',
-     'package', 'pip', 'gem',
+    'package', 'pip', 'gem',
     'nodeyumexclude', 'plcyumexclude', 'yumexclude',
     'precious', 'junk', 'mirror',
 ]
@@ -107,25 +108,25 @@ class PkgsParser:
             return self.version <= version
         else:
             raise Exception(
-                'Internal error - unexpected qualifier {}'.format(qualifier))
+                f'Internal error - unexpected qualifier {qualifier}')
 
     m_comment = re.compile(r'\A\s*#')
     m_blank = re.compile(r'\A\s*\Z')
 
     m_ident = re.compile(r'\A'+re_ident+r'\Z')
     re_qualified = r'\s*'
-    re_qualified += r'(?P<plus_minus>[+-]?)'
-    re_qualified += r'\s*'
-    re_qualified += r'(?P<keyword>{re_ident})'.format(re_ident=re_ident)
-    re_qualified += r'\s*'
-    re_qualified += r'(?P<qualifier>>=|<=|=)'
-    re_qualified += r'\s*'
-    re_qualified += r'(?P<fcdistro>{re_ident}[0-9]+)'.format(re_ident=re_ident)
-    re_qualified += r'\s*'
-    m_qualified = re.compile(r'\A{re_qualified}\Z'.format(re_qualified=re_qualified))
+    re_qualified += rf'(?P<plus_minus>[+-]?)'
+    re_qualified += rf'\s*'
+    re_qualified += rf'(?P<keyword>{re_ident})'
+    re_qualified += rf'\s*'
+    re_qualified += rf'(?P<qualifier>=|<=|>=)'
+    re_qualified += rf'\s*'
+    re_qualified += rf'(?P<fcdistro>{re_ident}[0-9]+)'
+    re_qualified += rf'\s*'
+    m_qualified = re.compile(rf'\A{re_qualified}\Z')
 
     re_old = '[a-z]+[+-][a-z]+[0-9]+'
-    m_old = re.compile(r'\A{}\Z'.format(re_old))
+    m_old = re.compile(rf'\A{re_old}\Z')
 
     # returns a tuple (included, excluded)
     def parse(self, filename):
@@ -144,7 +145,7 @@ class PkgsParser:
                             ########## single ident
                             if self.m_ident.match(left):
                                 if left not in known_keywords:
-                                    raise Exception("Unknown keyword {left}".format(**locals()))
+                                    raise Exception(f"Unknown keyword {left}")
                                 elif left == self.keyword:
                                     included += rights.split()
                             else:
@@ -152,9 +153,9 @@ class PkgsParser:
                                 if m:
                                     (plus_minus, kw, qual, fcdistro) = m.groups()
                                     if kw not in known_keywords:
-                                        raise Exception("Unknown keyword in {left}".format(**locals()))
+                                        raise Exception(f"Unknown keyword in {left}")
                                     if fcdistro not in known_fcdistros:
-                                        raise Exception('Unknown fcdistro {fcdistro}'.format(**locals()))
+                                        raise Exception(f'Unknown fcdistro {fcdistro}')
                                     # skip if another keyword
                                     if kw != self.keyword: continue
                                     # does this fcdistro match ?
@@ -165,32 +166,31 @@ class PkgsParser:
                                     # skip if the qualifier does not fit
                                     if not self.match (qual, version):
                                         if self.options.verbose:
-                                            print('{filename}:{lineno}:qualifer {left} does not apply'
-                                                  .format(**locals()), file=stderr)
+                                            print(f'{filename}:{lineno}:qualifer {left} does not apply',
+                                                  file=stderr)
                                         continue
                                     # we're in, let's add (default) or remove (if plus_minus is minus)
                                     if plus_minus == '-':
                                         if self.options.verbose:
-                                            print('{filename}:{lineno}: from {left}, excluding {rights}'
-                                                  .format(**locals()), file=stderr)
+                                            print(f'{filename}:{lineno}: from {left}, excluding {rights}',
+                                                  file=stderr)
                                         excluded += rights.split()
                                     else:
                                         if self.options.verbose:
-                                            print('{filename}:{lineno}: from {left}, including {rights}'\
-                                                  .format(**locals()), file=stderr)
+                                            print(f'{filename}:{lineno}: from {left}, including {rights}',
+                                                  file=stderr)
                                         included += rights.split()
                                 elif self.m_old.match(left):
-                                    raise Exception('Old-fashioned syntax not supported anymore {left}'.\
-                                                    format(**locals()))
+                                    raise Exception(f'Old-fashioned syntax not supported anymore {left}')
                                 else:
-                                    raise Exception('error in left expression {left}'.format(**locals()))
+                                    raise Exception(f'error in left expression {left}')
 
                     except Exception as e:
                         ok = False
-                        print("{filename}:{lineno}:syntax error: {e}".format(**locals()), file=stderr)
+                        print(f"{filename}:{lineno}:syntax error: {e}", file=stderr)
         except Exception as exc:
             ok = False
-            print('Could not parse file', filename, exc, file=stderr)
+            print(f'Could not parse file {filename} {exc=}', file=stderr)
         return (ok, included, excluded)
 
     def run (self):
@@ -224,7 +224,7 @@ def main ():
     parser = OptionParser(usage=usage)
     parser.add_option(
         '-a', '--arch', dest='arch', action='store', default=default_arch,
-        help='target arch, e.g. i386 or x86_64, default={}'.format(default_arch))
+        help=f'target arch, e.g. i386 or x86_64, default={default_arch}')
     parser.add_option(
         '-f', '--fcdistro', dest='fcdistro', action='store', default=default_fcdistro,
         help='fcdistro, e.g. f12 or centos5')