Control: tags 1001603 + patch
Control: tags 1001603 + pending

Dear maintainer,

I've prepared an NMU for rpmlint (versioned as 2.3.0+ds1-0.1) and
uploaded it to DELAYED/7. Please feel free to tell me if I
should delay it longer.

Regards.

diff -Nru rpmlint-2.2.0+ds1/configs/Fedora/users-groups.toml rpmlint-
2.3.0+ds1/configs/Fedora/users-groups.toml
--- rpmlint-2.2.0+ds1/configs/Fedora/users-groups.toml  2021-12-12
09:54:14.000000000 -0500
+++ rpmlint-2.3.0+ds1/configs/Fedora/users-groups.toml  2022-05-29
12:46:55.000000000 -0400
@@ -1,5 +1,5 @@
 # generated using tools/generate-fedora-users-groups.py on 2021-03-23
 
-StandardUsers = ['pkiuser', 'sshd', 'cyrus', 'keystone', 'squid', 'lp',
'root', 'dovecot', 'oprofile', 'ldap', 'arpwatch', 'retrace', 'vdsm', 'nut',
'hacluster', 'polkituser', 'mailman', 'saned', 'adm', 'mailnull', 'rtkit',
'postfix', 'cimsrvr', 'postgres', 'vhostmd', 'smmsp', 'dbus', 'rpcuser',
'nslcd', 'named', 'radvd', 'ntp', 'systemd-resolve', 'nova', 'tss',
'wildfly', 'ricci', 'mysql', 'apache', 'usbmuxd', 'systemd-network', 'vcsa',
'sabayon', 'quantum', 'katello', 'xfs', 'halt', 'tomcat', 'beagleindex',
'jbosson-agent', 'fax', 'haldaemon', 'pulse', 'hsqldb', 'cassandra',
'pegasus', 'clamav', 'piranha', 'mongodb', 'netdump', 'activemq',
'ovirtagent', 'bin', 'aeolus', 'sync', 'radiusd', 'rpm', 'webalizer',
'nocpulse', 'elasticsearch', 'games', 'pvm', 'wnn', 'snortd', 'privoxy',
'nscd', 'gdm', 'prelude-manager', 'cinder', 'shutdown', 'rpc', 'condor',
'#systemd-journal-gateway', 'heat', 'qemu', 'myproxy', 'avahi', 'operator',
'majordomo', 'puppet', 'exim', 'sanlock', 'rhevm', 'swift', 'wallaby',
'ftp', 'ident', 'frontpage', 'ats', 'mail', 'ceilometer', 'news',
'distcache', 'ovirt', 'ceph', 'desktop', 'uucp', 'glance', 'jonas',
'haproxy', 'abrt', 'quagga', 'stap-server', 'dhcpd', 'nobody', 'luci',
'bacula', 'avahi-autoipd', 'gopher', 'tcpdump', 'daemon', 'amandabackup',
'jetty']
+StandardUsers = ['pkiuser', 'sshd', 'cyrus', 'keystone', 'squid', 'lp',
'root', 'dovecot', 'oprofile', 'ldap', 'arpwatch', 'retrace', 'vdsm', 'nut',
'hacluster', 'polkituser', 'mailman', 'saned', 'adm', 'mailnull', 'rtkit',
'postfix', 'cimsrvr', 'postgres', 'vhostmd', 'smmsp', 'dbus', 'rpcuser',
'nslcd', 'named', 'radvd', 'ntp', 'systemd-resolve', 'nova', 'tss',
'wildfly', 'ricci', 'mysql', 'apache', 'usbmuxd', 'systemd-network', 'vcsa',
'sabayon', 'quantum', 'katello', 'xfs', 'halt', 'tomcat', 'beagleindex',
'jbosson-agent', 'fax', 'haldaemon', 'pulse', 'hsqldb', 'cassandra',
'pegasus', 'clamav', 'piranha', 'mongodb', 'netdump', 'activemq',
'ovirtagent', 'bin', 'aeolus', 'sync', 'radiusd', 'rpm', 'webalizer',
'nocpulse', 'elasticsearch', 'games', 'pvm', 'wnn', 'snortd', 'privoxy',
'nscd', 'gdm', 'prelude-manager', 'cinder', 'shutdown', 'rpc', 'condor',
'#systemd-journal-gateway', 'heat', 'qemu', 'myproxy', 'avahi', 'operator',
'majordomo', 'puppet', 'exim', 'sanlock', 'rhevm', 'swift', 'wallaby',
'ftp', 'ident', 'frontpage', 'ats', 'mail', 'ceilometer', 'news',
'distcache', 'ovirt', 'ceph', 'desktop', 'uucp', 'glance', 'jonas',
'haproxy', 'abrt', 'quagga', 'stap-server', 'dhcpd', 'nobody', 'luci',
'bacula', 'avahi-autoipd', 'gopher', 'tcpdump', 'daemon', 'amandabackup',
'jetty', 'ergo']
 
-StandardGroups = ['pkiuser', 'sshd', 'keystone', 'squid', 'pppusers',
'kvm', 'popusers', 'lp', 'root', 'dovecot', 'oprofile', 'disk', 'ldap',
'arpwatch', 'retrace', 'nut', 'polkituser', 'audio', 'mailman', 'stapusr',
'saned', 'adm', 'mailnull', 'rtkit', 'postfix', 'utmp', 'cimsrvr', 'wheel',
'postgres', 'vhostmd', 'smmsp', 'realtime', 'kmem', 'rpcuser', 'dbus',
'screen', 'utempter', 'video', 'named', 'radvd', 'ntp', 'man', 'systemd-
resolve', 'nova', 'tss', 'sys', 'cdrom', 'wildfly', 'ricci', 'mysql',
'apache', 'usbmuxd', 'jbosson', 'systemd-network', 'vcsa', 'console',
'sabayon', 'quantum', 'katello', 'haclient', 'xfs', 'tomcat', 'beagleindex',
'fax', 'haldaemon', 'systemd-journal', 'pulse', 'hsqldb', 'cassandra',
'pegasus', 'clamav', 'piranha', 'mongodb', 'netdump', 'activemq',
'ovirtagent', 'bin', 'saslauth', 'aeolus', 'radiusd', 'mem', 'rpm',
'webalizer', 'floppy', 'nocpulse', 'elasticsearch', 'games', 'pvm', 'wnn',
'tty', 'snortd', 'slipusers', 'nscd', 'gdm', 'privoxy', 'mock', 'prelude-
manager', 'cinder', 'dialout', 'rpc', 'condor', '#systemd-journal-gateway',
'heat', 'qemu', 'stapsys', 'avahi', 'myproxy', 'majordomo', 'tape',
'puppet', 'exim', 'sanlock', 'rhevm', 'swift', 'wallaby', 'ftp', 'ident',
'frontpage', 'ats', 'mail', 'ceilometer', 'news', 'distcache', 'stapdev',
'users', 'ovirt', 'ceph', 'desktop', 'uucp', 'glance', 'jonas', 'postdrop',
'haproxy', 'abrt', 'quagga', 'stap-server', 'lock', 'dhcpd', 'nobody',
'wbpriv', 'luci', 'quaggavt', 'bacula', 'avahi-autoipd', 'gopher', 'wine',
'tcpdump', 'dip', 'daemon', 'slocate', 'jetty']
+StandardGroups = ['pkiuser', 'sshd', 'keystone', 'squid', 'pppusers',
'kvm', 'popusers', 'lp', 'root', 'dovecot', 'oprofile', 'disk', 'ldap',
'arpwatch', 'retrace', 'nut', 'polkituser', 'audio', 'mailman', 'stapusr',
'saned', 'adm', 'mailnull', 'rtkit', 'postfix', 'utmp', 'cimsrvr', 'wheel',
'postgres', 'vhostmd', 'smmsp', 'realtime', 'kmem', 'rpcuser', 'dbus',
'screen', 'utempter', 'video', 'named', 'radvd', 'ntp', 'man', 'systemd-
resolve', 'nova', 'tss', 'sys', 'cdrom', 'wildfly', 'ricci', 'mysql',
'apache', 'usbmuxd', 'jbosson', 'systemd-network', 'vcsa', 'console',
'sabayon', 'quantum', 'katello', 'haclient', 'xfs', 'tomcat', 'beagleindex',
'fax', 'haldaemon', 'systemd-journal', 'pulse', 'hsqldb', 'cassandra',
'pegasus', 'clamav', 'piranha', 'mongodb', 'netdump', 'activemq',
'ovirtagent', 'bin', 'saslauth', 'aeolus', 'radiusd', 'mem', 'rpm',
'webalizer', 'floppy', 'nocpulse', 'elasticsearch', 'games', 'pvm', 'wnn',
'tty', 'snortd', 'slipusers', 'nscd', 'gdm', 'privoxy', 'mock', 'prelude-
manager', 'cinder', 'dialout', 'rpc', 'condor', '#systemd-journal-gateway',
'heat', 'qemu', 'stapsys', 'avahi', 'myproxy', 'majordomo', 'tape',
'puppet', 'exim', 'sanlock', 'rhevm', 'swift', 'wallaby', 'ftp', 'ident',
'frontpage', 'ats', 'mail', 'ceilometer', 'news', 'distcache', 'stapdev',
'users', 'ovirt', 'ceph', 'desktop', 'uucp', 'glance', 'jonas', 'postdrop',
'haproxy', 'abrt', 'quagga', 'stap-server', 'lock', 'dhcpd', 'nobody',
'wbpriv', 'luci', 'quaggavt', 'bacula', 'avahi-autoipd', 'gopher', 'wine',
'tcpdump', 'dip', 'daemon', 'slocate', 'jetty', 'ergo']
diff -Nru rpmlint-2.2.0+ds1/configs/openSUSE/opensuse.toml rpmlint-
2.3.0+ds1/configs/openSUSE/opensuse.toml
--- rpmlint-2.2.0+ds1/configs/openSUSE/opensuse.toml    2021-12-12
09:54:14.000000000 -0500
+++ rpmlint-2.3.0+ds1/configs/openSUSE/opensuse.toml    2022-05-29
12:46:55.000000000 -0400
@@ -146,7 +146,6 @@
     'ldconfig-post.*/ddiwrapper/wine/',
     'glibc\.\S+: \w: statically-linked-binary
/usr/sbin/glibc_post_upgrade',
     ' symlink-should-be-relative ',
-    ' binary-or-shlib-defines-rpath .*ORIGIN',
     'libzypp.*shlib-policy-name-error.*libzypp',
     'libtool.*shlib-policy.*',
 
@@ -177,7 +176,6 @@
     ' preun-without-chkconfig ',
     ' no-dependency-on locales',
     ' shlib-policy-name-error',
-    ' binary-or-shlib-defines-rpath',
     ' executable-marked-as-config-file',
     ' log-files-without-logrotate',
     ' hardcoded-prefix-tag',
diff -Nru rpmlint-2.2.0+ds1/configs/openSUSE/scoring.toml rpmlint-
2.3.0+ds1/configs/openSUSE/scoring.toml
--- rpmlint-2.2.0+ds1/configs/openSUSE/scoring.toml     2021-12-12
09:54:14.000000000 -0500
+++ rpmlint-2.3.0+ds1/configs/openSUSE/scoring.toml     2022-05-29
12:46:55.000000000 -0400
@@ -34,3 +34,5 @@
 obsolete-insserv-requirement = 10000
 deprecated-init-script = 10000
 deprecated-boot-script = 10000
+# Temporarily disable once boo#1199268 gets fixed
+# binary-or-shlib-defines-rpath = 10000
diff -Nru rpmlint-2.2.0+ds1/configs/openSUSE/users-groups.toml rpmlint-
2.3.0+ds1/configs/openSUSE/users-groups.toml
--- rpmlint-2.2.0+ds1/configs/openSUSE/users-groups.toml        2021-12-12
09:54:14.000000000 -0500
+++ rpmlint-2.3.0+ds1/configs/openSUSE/users-groups.toml        2022-05-29
12:46:55.000000000 -0400
@@ -45,6 +45,7 @@
     'dovecot',
     'elasticsearch',
     'epmd',
+    'ergo',
     'festival',
     'ffums',
     'firebird',
@@ -68,6 +69,7 @@
     'icecream',
     'icinga',
     'icingacmd',
+    'icingaweb2',
     'ifdrwww',
     'intermezzo',
     'iouyap',
@@ -265,6 +267,7 @@
     'ec2-api',
     'elasticsearch',
     'epmd',
+    'ergo',
     'fax',
     'festival',
     'fetchmail',
diff -Nru rpmlint-2.2.0+ds1/debian/changelog rpmlint-
2.3.0+ds1/debian/changelog
--- rpmlint-2.2.0+ds1/debian/changelog  2021-12-15 14:25:08.000000000 -0500
+++ rpmlint-2.3.0+ds1/debian/changelog  2022-05-29 12:54:07.000000000 -0400
@@ -1,3 +1,14 @@
+rpmlint (2.3.0+ds1-0.1) unstable; urgency=medium
+
+  * Non-maintainer upload.
+  * New upstream release.
+  * debian/control: Update dependency accordingly.
+  * debian/copyright: Update Files-Excluded field.
+  * debian/rpmlint.maintscript: Purge obsolete conffile on upgrade.
+    (Closes: #1001603)
+
+ -- Boyuan Yang <[email protected]>  Sun, 29 May 2022 12:54:07 -0400
+
 rpmlint (2.2.0+ds1-0.2) unstable; urgency=high
 
   * Non-maintainer upload.
diff -Nru rpmlint-2.2.0+ds1/debian/control rpmlint-2.3.0+ds1/debian/control
--- rpmlint-2.2.0+ds1/debian/control    2021-12-15 14:20:28.000000000 -0500
+++ rpmlint-2.3.0+ds1/debian/control    2022-05-29 12:49:09.000000000 -0400
@@ -13,6 +13,8 @@
  dh-sequence-python3,
  iso-codes,
  pkg-config,
+ python3-enchant,
+ python3-magic,
  python3-pybeam,
  python3-pytest <!nocheck>,
  python3-pytest-cov <!nocheck>,
@@ -26,7 +28,7 @@
  python3,
  rpm,
  rpm2cpio,
-Standards-Version: 4.5.0
+Standards-Version: 4.6.1
 Homepage: https://github.com/rpm-software-management/rpmlint
 Vcs-Git: https://salsa.debian.org/pkg-rpm-team/rpmlint.git
 Vcs-Browser: https://salsa.debian.org/pkg-rpm-team/rpmlint
@@ -41,11 +43,11 @@
  rpm2cpio,
  ${misc:Depends},
  ${python3:Depends},
+ python3-enchant,
+ python3-magic,
 Recommends:
  appstream-util,
  groff-base,
- python3-enchant,
- python3-magic,
  rpm,
 Description: RPM package checker
  rpmlint is a tool for checking common errors in rpm packages.  rpmlint
diff -Nru rpmlint-2.2.0+ds1/debian/copyright rpmlint-
2.3.0+ds1/debian/copyright
--- rpmlint-2.2.0+ds1/debian/copyright  2021-12-15 14:20:28.000000000 -0500
+++ rpmlint-2.3.0+ds1/debian/copyright  2022-05-29 12:46:37.000000000 -0400
@@ -2,10 +2,10 @@
 Upstream-Name: rpmlint
 Source: https://github.com/rpm-software-management/rpmlint
 Files-Excluded:
- tests/binary/*
- tests/ldd/*
- tests/pyc/*
- tests/readelf/*
+ test/binary/*
+ test/ldd/*
+ test/pyc/*
+ test/readelf/*
 
 Files: *
 Copyright: 2013 Frédéric Lepied <[email protected]>
diff -Nru rpmlint-2.2.0+ds1/debian/rpmlint.maintscript rpmlint-
2.3.0+ds1/debian/rpmlint.maintscript
--- rpmlint-2.2.0+ds1/debian/rpmlint.maintscript        1969-12-31
19:00:00.000000000 -0500
+++ rpmlint-2.3.0+ds1/debian/rpmlint.maintscript        2022-05-29
12:53:45.000000000 -0400
@@ -0,0 +1 @@
+rm_conffile /etc/rpmlint/config 2.3.0~ rpmlint
diff -Nru rpmlint-2.2.0+ds1/.github/workflows/main.yml rpmlint-
2.3.0+ds1/.github/workflows/main.yml
--- rpmlint-2.2.0+ds1/.github/workflows/main.yml        2021-12-12
09:54:14.000000000 -0500
+++ rpmlint-2.3.0+ds1/.github/workflows/main.yml        2022-05-29
12:46:55.000000000 -0400
@@ -16,12 +16,11 @@
         container:
           - 'registry.fedoraproject.org/fedora:latest'
           - 'registry.fedoraproject.org/fedora:rawhide'
-          - 'registry.opensuse.org/opensuse/leap-dnf:15.3'
-          - 'registry.opensuse.org/opensuse/tumbleweed-dnf:latest'
+          - 'registry.opensuse.org/opensuse/tumbleweed:latest'
         include:
           - container: 'registry.fedoraproject.org/fedora:latest'
             build-type: 'no-optional-deps'
-          - container: 'registry.opensuse.org/opensuse/tumbleweed-
dnf:latest'
+          - container: 'registry.opensuse.org/opensuse/tumbleweed:latest'
             build-type: 'no-optional-deps'
       fail-fast: false
 
@@ -30,7 +29,7 @@
       options: --security-opt seccomp=unconfined
 
     steps:
-      - run: dnf --assumeyes install
+      - run: zypper -n install
               cpio gzip
               bzip2 xz
               binutils glibc glibc-32bit glibc-locale
@@ -49,21 +48,21 @@
               python3-flake8-import-order
               python3-flake8-quotes
               python3-pyxdg
-              python3-zstd
+              python3-zstandard
               python3-toml
               python3-pip
               rpm-build
               git
         if: ${{ contains(matrix.container, 'opensuse') }}
-      - run: dnf --assumeyes install
+      - run: zypper -n install
               checkbashisms dash
               desktop-file-utils
               appstream-glib
               myspell-en_US myspell-cs_CZ
               python3-pyenchant
         if: ${{ contains(matrix.container, 'opensuse') && matrix.build-type
== 'normal' }}
-      - run: dnf --assumeyes install python3-flake8-comprehensions
-        if: ${{ contains(matrix.container, 'opensuse/tumbleweed') }}
+      - run: zypper -n install python3-flake8-comprehensions
+        if: ${{ contains(matrix.container, 'opensuse') }}
       - run: dnf --nogpgcheck --assumeyes install
               /usr/bin/cpio
               /usr/bin/bzip2
@@ -86,7 +85,7 @@
               python3-flake8-import-order
               python3-pyxdg
               python3-toml
-              python3-zstd
+              python3-zstandard
               python3-pip
               rpm-build
               git
diff -Nru rpmlint-2.2.0+ds1/.packit/rpmlint.spec rpmlint-
2.3.0+ds1/.packit/rpmlint.spec
--- rpmlint-2.2.0+ds1/.packit/rpmlint.spec      2021-12-12
09:54:14.000000000 -0500
+++ rpmlint-2.3.0+ds1/.packit/rpmlint.spec      2022-05-29
12:46:55.000000000 -0400
@@ -1,7 +1,7 @@
 %{!?python3: %global python3 %{__python3}}
 
 Name:           rpmlint
-Version:        2.2.0
+Version:        2.3.0
 Release:        0%{?dist}
 Summary:        Tool for checking common errors in RPM packages
 
@@ -28,7 +28,7 @@
 BuildRequires:  python3-pyxdg
 BuildRequires:  python3-rpm
 BuildRequires:  python3-toml
-BuildRequires:  python3-zstd
+BuildRequires:  python3-zstandard
 %else
 BuildRequires:  python3dist(setuptools)
 # For tests
@@ -42,7 +42,7 @@
 BuildRequires:  python3dist(pyxdg)
 BuildRequires:  python3dist(rpm)
 BuildRequires:  python3dist(toml)
-BuildRequires:  python3dist(zstd)
+BuildRequires:  python3dist(zstandard)
 %endif
 
 # Rest of the test dependencies
diff -Nru rpmlint-2.2.0+ds1/README.md rpmlint-2.3.0+ds1/README.md
--- rpmlint-2.2.0+ds1/README.md 2021-12-12 09:54:14.000000000 -0500
+++ rpmlint-2.3.0+ds1/README.md 2022-05-29 12:46:55.000000000 -0400
@@ -5,6 +5,7 @@
 [![Total
alerts](https://img.shields.io/lgtm/alerts/g/rpm-software-management/rpmlint.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/rpm-software-management/rpmlint/alerts/
)
 [![Language grade:
Python](https://img.shields.io/lgtm/grade/python/g/rpm-software-management/rpmlint.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/rpm-software-management/rpmlint/context:python
)
 [![Coverage
Status](https://coveralls.io/repos/github/rpm-software-management/rpmlint/badge.svg?branch=main)](https://coveralls.io/github/rpm-software-management/rpmlint?branch=main
)
+[![repology](https://repology.org/badge/latest-versions/rpmlint.svg)](https://repology.org/project/rpmlint/versions
)
 
 `rpmlint` is a tool for checking common errors in RPM packages.
 `rpmlint` can be used to test individual packages before uploading or to
check
@@ -26,8 +27,8 @@
 For installation on your machine you will need the following packages:
 
 Mandatory:
-- Python 3.6 or newer
-- python3-setuptools, python3-toml, python3-pyxdg, python3-beam
+- Python 3.8 or newer
+- python3-setuptools, python3-toml, python3-pyxdg, python3-pybeam
 - rpm and its python bindings
 - binutils, cpio, gzip, bzip, xz and zstd
 
@@ -121,8 +122,11 @@
     setBadness('check', 0)
     addFilter('test-i-ignore')
     
-The location of `rpmlintrc` can be set using `--rpmlintrc` option. Or you
can have any `*.rpmlintrc` or 
-`*-rpmlintrc` file in the current working directory.  The best practice is
to store the name in `$PACKAGE_NAME.rpmlintrc`.
+The location of `rpmlintrc` can be set using `--rpmlintrc` option.
+Or it can load any `*.rpmlintrc` or `*-rpmlintrc` that are located in the
same
+folder as check RPM file (or a specfile). Note the auto-loading happens
only
+when one RPM file (or a specfile) is used.
+The best practice is to store the name in `$PACKAGE_NAME.rpmlintrc`.
 
 `setBadness` overrides a default badness for a given check and `addFilter`
ignores all errors
 that match the given regular expression (one cannot filter out errors that
are listed in `BlockedFilters`
diff -Nru rpmlint-2.2.0+ds1/rpmlint/checks/AbstractCheck.py rpmlint-
2.3.0+ds1/rpmlint/checks/AbstractCheck.py
--- rpmlint-2.2.0+ds1/rpmlint/checks/AbstractCheck.py   2021-12-12
09:54:14.000000000 -0500
+++ rpmlint-2.3.0+ds1/rpmlint/checks/AbstractCheck.py   2022-05-29
12:46:55.000000000 -0400
@@ -43,6 +43,9 @@
         if self.use_threads:
             # NOTE: the speed benefit of the ThreadPoolExecutor is limited
due to
             # Global Interpreter Lock (GIL).
+
+            # start with the biggest files first
+            filenames = sorted(filenames, key=lambda x: pkg.files[x].size,
reverse=True)
             with concurrent.futures.ThreadPoolExecutor() as executor:
                 futures = []
                 for filename in filenames:
diff -Nru rpmlint-2.2.0+ds1/rpmlint/checks/AlternativesCheck.py rpmlint-
2.3.0+ds1/rpmlint/checks/AlternativesCheck.py
--- rpmlint-2.2.0+ds1/rpmlint/checks/AlternativesCheck.py       2021-12-12
09:54:14.000000000 -0500
+++ rpmlint-2.3.0+ds1/rpmlint/checks/AlternativesCheck.py       2022-05-29
12:46:55.000000000 -0400
@@ -30,11 +30,6 @@
 
     def __init__(self, config, output):
         super().__init__(config, output)
-        # Containers for scriptlets as they will be used on multiple places
-        self.post = None
-        self.postun = None
-        self.install_binaries = {}
-        self.slave_binaries = []
 
     def check(self, pkg):
         if pkg.is_source:
@@ -45,6 +40,8 @@
             self._check_libalternatives_requirements(pkg)
             self._check_libalternatives_filelist(pkg)
 
+        self.install_binaries = {}
+        self.slave_binaries = []
         # populate scriptlets
         self.post = byte_to_string(pkg.header[rpm.RPMTAG_POSTIN])
         self.postun = byte_to_string(pkg.header[rpm.RPMTAG_POSTUN])
diff -Nru rpmlint-2.2.0+ds1/rpmlint/checks/AppDataCheck.py rpmlint-
2.3.0+ds1/rpmlint/checks/AppDataCheck.py
--- rpmlint-2.2.0+ds1/rpmlint/checks/AppDataCheck.py    2021-12-12
09:54:14.000000000 -0500
+++ rpmlint-2.3.0+ds1/rpmlint/checks/AppDataCheck.py    2022-05-29
12:46:55.000000000 -0400
@@ -17,7 +17,7 @@
         super().__init__(config, output,
r'/usr/share/appdata/.*\.(appdata|metainfo).xml$')
 
     def check_file(self, pkg, filename):
-        root = pkg.dirName()
+        root = pkg.dir_name()
         f = root + filename
         cmd = self.cmd + f
 
diff -Nru rpmlint-2.2.0+ds1/rpmlint/checks/BashismsCheck.py rpmlint-
2.3.0+ds1/rpmlint/checks/BashismsCheck.py
--- rpmlint-2.2.0+ds1/rpmlint/checks/BashismsCheck.py   2021-12-12
09:54:14.000000000 -0500
+++ rpmlint-2.3.0+ds1/rpmlint/checks/BashismsCheck.py   2022-05-29
12:46:55.000000000 -0400
@@ -10,16 +10,16 @@
         super().__init__(config, output, r'.*')
         self.use_threads = True
         self._detect_early_fail_option()
+        self.file_cache = {}
 
     def _detect_early_fail_option(self):
-        self.has_early_fail_option = False
         output = subprocess.check_output(['checkbashisms', '--help'],
                                          shell=True, encoding='utf8')
         # FIXME: remove in the future
         self.use_early_fail = '[-e]' in output
 
     def check_file(self, pkg, filename):
-        root = pkg.dirName()
+        root = pkg.dir_name()
         pkgfile = pkg.files[filename]
         filepath = root + filename
 
@@ -28,7 +28,14 @@
                 pkgfile.magic.startswith('POSIX shell script')):
             return
 
-        self.check_bashisms(pkg, filepath, filename)
+        # There are package likes Linux kernel where there are common
+        # shell scripts present in multiple packages
+        # (kernel-source, kernel-source-vanilla).
+        if pkgfile.md5 not in self.file_cache:
+            self.file_cache[pkgfile.md5] = list(self.check_bashisms(pkg,
filepath, filename))
+
+        for warning in self.file_cache[pkgfile.md5]:
+            self.output.add_info('W', pkg, warning, filename)
 
     def check_bashisms(self, pkg, filepath, filename):
         """
@@ -36,13 +43,14 @@
 
         We need to see if it is valid syntax of bash and if there are no
         potential bash issues.
+        Return a warning message or None if there is no problem.
         """
         try:
             r = subprocess.run(['dash', '-n', filepath],
                                stderr=subprocess.DEVNULL,
                                env=ENGLISH_ENVIROMENT)
             if r.returncode == 2:
-                self.output.add_info('W', pkg, 'bin-sh-syntax-error',
filename)
+                yield 'bin-sh-syntax-error'
             elif r.returncode == 127:
                 raise FileNotFoundError(filename)
         except UnicodeDecodeError:
@@ -57,7 +65,7 @@
                                stderr=subprocess.DEVNULL,
                                env=ENGLISH_ENVIROMENT)
             if r.returncode == 1:
-                self.output.add_info('W', pkg, 'potential-bashisms',
filename)
+                yield 'potential-bashisms'
             elif r.returncode == 2:
                 raise FileNotFoundError(filename)
         except UnicodeDecodeError:
diff -Nru rpmlint-2.2.0+ds1/rpmlint/checks/BinariesCheck.py rpmlint-
2.3.0+ds1/rpmlint/checks/BinariesCheck.py
--- rpmlint-2.2.0+ds1/rpmlint/checks/BinariesCheck.py   2021-12-12
09:54:14.000000000 -0500
+++ rpmlint-2.3.0+ds1/rpmlint/checks/BinariesCheck.py   2022-05-29
12:46:55.000000000 -0400
@@ -3,7 +3,6 @@
 import re
 import stat
 
-import rpm
 from rpmlint.arparser import ArParser
 from rpmlint.checks.AbstractCheck import AbstractCheck
 from rpmlint.lddparser import LddParser
@@ -20,7 +19,6 @@
     """
     Checks for binary files in the package.
     """
-    srcname_regex = re.compile(r'(.*?)-[0-9]')
     validso_regex = re.compile(r'(\.so\.\d+(\.\d+)*|\d\.so)$')
     soversion_regex = re.compile(r'.*?(-(?P<pkgversion>[0-9][.0-
9]*))?\.so(\.(?P<soversion>[0-9][.0-9]*))?')
     usr_lib_regex = re.compile(r'^/usr/lib(64)?/')
@@ -33,18 +31,21 @@
     la_file_regex = re.compile(r'\.la$')
     invalid_dir_ref_regex = re.compile(r'/(home|tmp)(\W|$)')
     usr_arch_share_regex =
re.compile(r'/share/.*/(?:x86|i.86|x86_64|ppc|ppc64|s390|s390x|ia64|m68k|arm
|aarch64|mips|riscv)')
+    python_module_regex = re.compile(r'.*\.\w*(python|pypy)\w*(-
\w+){4}\.so')
 
     lto_text_like_sections = {'.preinit_array', '.init_array',
'.fini_array'}
     # The following sections are part of the RX ABI and do correspond to
.text, .data and .bss
     lto_text_like_sections |= {'P', 'D_1', 'B_1'}
 
     # The list is taken from glibc: sysdeps/${arch}/stackinfo.h
-    default_executable_stack_archs =
re.compile(r'alpha|arm.*|hppa|i.86|m68k|microblaze|mips|ppc64|ppc64le|s390|s
390x|sh|sparc|x86_64')
+    default_executable_stack_archs =
re.compile(r'alpha|arm.*|hppa|i.86|m68k|microblaze|mips|ppc|s390|s390x|sh|sp
arc|x86_64')
+
+    rpath_origin = '$ORIGIN'
 
     def __init__(self, config, output):
         super().__init__(config, output)
         self.checked_files = 0
-        self.system_lib_paths = config.configuration['SystemLibPaths']
+        self.system_lib_paths =
tuple(config.configuration['SystemLibPaths'])
         self.pie_exec_regex_list = []
         for regex in config.configuration['PieExecutables']:
             self.pie_exec_regex_list.append(re.compile(regex))
@@ -108,10 +109,10 @@
         If so then print a corresponding error with the matching line
numbers.
         """
         if self.la_file_regex.search(fname):
-            lines = pkg.grep(self.invalid_dir_ref_regex, fname)
-            if lines:
+            line = pkg.grep(self.invalid_dir_ref_regex, fname)
+            if line:
                 self.output.add_info('E', pkg, 'invalid-la-file', fname,
-                                     '(line %s)' % ', '.join(lines))
+                                     f'(line {line})')
 
     def _check_binary_in_noarch(self, pkg, bin_name):
         """
@@ -197,13 +198,13 @@
                         not self.versioned_dir_regex.search(fn):
                     self.output.add_info('E', pkg, 'non-versioned-file-in-
library-package', f)
 
-    def _check_no_binary(self, pkg, has_binary, multi_pkg,
has_file_in_lib64):
+    def _check_no_binary(self, pkg, has_binary, has_file_in_lib64):
         """
         Check if the arch dependent package contains any binaries.
 
         Print an error if there is no binary and it's not noarch.
         """
-        if not has_binary and not multi_pkg and not has_file_in_lib64 and \
+        if not has_binary and not has_file_in_lib64 and \
                 pkg.arch != 'noarch':
             self.output.add_info('E', pkg, 'no-binary')
 
@@ -226,7 +227,7 @@
         if has_usr_lib_file and not has_binary_in_usr_lib:
             self.output.add_info('W', pkg, 'only-non-binary-in-usr-lib')
 
-    def _check_no_text_in_archive(self, pkg, pkgfile_path, path):
+    def _check_no_text_in_archive(self, pkg, pkgfile):
         """
         For an archive, test if any .text sections is non-empty.
         """
@@ -238,7 +239,7 @@
             # Starting with glibc 2.34, some static libraries were moved to
libc
             # and there are empty archives for backward compatibility. Skip
these
             # libraries.
-            stem = Path(path).stem
+            stem = Path(pkgfile.name).stem
             if stem in GLIBC_EMPTY_ARCHIVES or (stem.endswith('_p') and
stem[:-2] in GLIBC_EMPTY_ARCHIVES):
                 return
 
@@ -250,10 +251,10 @@
                          sn.startswith('.data')) and
                             section.size > 0):
                         return
-            self.output.add_info('E', pkg, 'lto-no-text-in-archive', path)
+            self.output.add_info('E', pkg, 'lto-no-text-in-archive',
pkgfile.name)
             return
 
-    def _check_missing_symtab_in_archive(self, pkg, pkgfile_path, path):
+    def _check_missing_symtab_in_archive(self, pkg, pkgfile):
         """
         FIXME Add test coverage.
         """
@@ -263,29 +264,27 @@
                     if section.name == '.symtab':
                         return
 
-            self.output.add_info('E', pkg, 'static-library-without-symtab',
path)
+            self.output.add_info('E', pkg, 'static-library-without-symtab',
pkgfile.name)
 
-    def _check_missing_debug_info_in_archive(self, pkg, pkgfile_path,
path):
+    def _check_missing_debug_info_in_archive(self, pkg, pkgfile):
         if self.is_archive:
             for elf_file in self.readelf_parser.section_info.elf_files:
                 for section in elf_file:
                     if section.name.startswith('.debug_'):
                         return
-            self.output.add_info('E', pkg, 'static-library-without-
debuginfo', path)
+            self.output.add_info('E', pkg, 'static-library-without-
debuginfo', pkgfile.name)
 
     # Check for LTO sections
-    def _check_lto_section(self, pkg, pkgfile_path, path):
+    def _check_lto_section(self, pkg, pkgfile):
         for elf_file in self.readelf_parser.section_info.elf_files:
             for section in elf_file:
                 if '.gnu.lto_.' in section.name:
-                    self.output.add_info('E', pkg, 'lto-bytecode', path)
+                    self.output.add_info('E', pkg, 'lto-bytecode',
pkgfile.name)
                     return
 
-    def _check_executable_stack(self, pkg, pkgfile_path, path):
+    def _check_executable_stack(self, pkg, pkgfile):
         """
         Check if the stack is declared as executable which is usually an
error.
-
-        FIXME Add test coverage.
         """
 
         # Skip architectures that have non-executable stack by default
@@ -293,12 +292,12 @@
             return
 
         # Do not check kernel modules and archives
-        if not self.is_archive and not any(path.startswith(p) for p in
KERNEL_MODULES_PATHS):
+        if not self.is_archive and not any(pkgfile.name.startswith(p) for p
in KERNEL_MODULES_PATHS):
             stack_headers = [h for h in
self.readelf_parser.program_header_info.headers if h.name == 'GNU_STACK']
             if not stack_headers:
-                self.output.add_info('E', pkg, 'missing-PT_GNU_STACK-
section', path)
+                self.output.add_info('E', pkg, 'missing-PT_GNU_STACK-
section', pkgfile.name)
             elif 'E' in stack_headers[0].flags:
-                self.output.add_info('E', pkg, 'executable-stack', path)
+                self.output.add_info('E', pkg, 'executable-stack',
pkgfile.name)
 
     def _check_soname_symlink(self, pkg, shlib, soname):
         """
@@ -319,7 +318,7 @@
             if path.name.startswith('lib') or path.name.startswith('ld-'):
                 self.output.add_info('E', pkg, 'no-ldconfig-symlink',
shlib)
 
-    def _check_shared_library(self, pkg, pkgfile_path, path):
+    def _check_shared_library(self, pkg, pkgfile):
         """
         Various checks for the shared library.
 
@@ -335,12 +334,12 @@
 
         soname = self.readelf_parser.dynamic_section_info.soname
         if not soname:
-            self.output.add_info('W', pkg, 'no-soname', path)
+            self.output.add_info('W', pkg, 'no-soname', pkgfile.name)
         else:
             if not self.validso_regex.search(soname):
-                self.output.add_info('E', pkg, 'invalid-soname', path,
soname)
+                self.output.add_info('E', pkg, 'invalid-soname',
pkgfile.name, soname)
             else:
-                self._check_soname_symlink(pkg, path, soname)
+                self._check_soname_symlink(pkg, pkgfile.name, soname)
 
                 # check if the major version of the library is in the
package
                 # name (check only for lib* packages)
@@ -362,9 +361,9 @@
 
         # check if the object code in the library is compiled with PIC
         if self.readelf_parser.dynamic_section_info['TEXTREL']:
-            self.output.add_info('E', pkg, 'shlib-with-non-pic-code', path)
+            self.output.add_info('E', pkg, 'shlib-with-non-pic-code',
pkgfile.name)
 
-    def _check_dependency(self, pkg, pkgfile_path, path):
+    def _check_dependency(self, pkg, pkgfile):
         """
         FIXME Add test coverage.
         """
@@ -375,15 +374,20 @@
         # following issues are errors for shared libs and warnings for
executables
         if not self.is_dynamically_linked:
             return
+
+        # Skip python packages
+        if self.python_module_regex.fullmatch(pkgfile.name):
+            return
+
         if not self.is_archive and not self.readelf_parser.is_debug:
             info_type = 'E' if self.readelf_parser.is_shlib else 'W'
             for symbol in self.ldd_parser.undefined_symbols:
-                self.output.add_info(info_type, pkg, 'undefined-non-weak-
symbol', path, symbol)
+                self.output.add_info(info_type, pkg, 'undefined-non-weak-
symbol', pkgfile.name, symbol)
             for dependency in self.ldd_parser.unused_dependencies:
                 self.output.add_info(info_type, pkg, 'unused-direct-shlib-
dependency',
-                                     path, dependency)
+                                     pkgfile.name, dependency)
 
-    def _check_library_dependency_location(self, pkg, pkgfile_path, path):
+    def _check_library_dependency_location(self, pkg, pkgfile):
         """
         FIXME Add test coverage.
         """
@@ -393,17 +397,17 @@
         if not self.is_archive:
             for dependency in self.ldd_parser.dependencies:
                 if dependency.startswith('/opt/'):
-                    self.output.add_info('E', pkg, 'linked-against-opt-
library', path, dependency)
+                    self.output.add_info('E', pkg, 'linked-against-opt-
library', pkgfile.name, dependency)
                     break
 
         nonusr = ('/bin', '/lib', '/sbin')
-        if path.startswith(nonusr):
+        if pkgfile.name.startswith(nonusr):
             for dependency in self.ldd_parser.dependencies:
                 if dependency.startswith('/usr/'):
-                    self.output.add_info('W', pkg, 'linked-against-usr-
library', path, dependency)
+                    self.output.add_info('W', pkg, 'linked-against-usr-
library', pkgfile.name, dependency)
                     break
 
-    def _check_security_functions(self, pkg, pkgfile_path, path):
+    def _check_security_functions(self, pkg, pkgfile):
         setgid =
any(self.readelf_parser.symbol_table_info.get_functions_for_regex(self.setgi
d_call_regex))
         setuid =
any(self.readelf_parser.symbol_table_info.get_functions_for_regex(self.setui
d_call_regex))
         setgroups =
any(self.readelf_parser.symbol_table_info.get_functions_for_regex(self.setgr
oups_call_regex))
@@ -411,24 +415,31 @@
         gethostbyname =
any(self.readelf_parser.symbol_table_info.get_functions_for_regex(self.getho
stbyname_call_regex))
 
         if setgid and setuid and not setgroups:
-            self.output.add_info('E', pkg, 'missing-call-to-setgroups-
before-setuid', path)
+            is_uid = stat.S_ISUID & pkgfile.mode
+            self.output.add_info('W' if is_uid else 'E', pkg, 'missing-
call-to-setgroups-before-setuid', pkgfile.name)
 
         if mktemp:
-            self.output.add_info('E', pkg, 'call-to-mktemp', path)
+            self.output.add_info('E', pkg, 'call-to-mktemp', pkgfile.name)
 
         if gethostbyname:
-            self.output.add_info('W', pkg, 'binary-or-shlib-calls-
gethostbyname', path)
+            self.output.add_info('W', pkg, 'binary-or-shlib-calls-
gethostbyname', pkgfile.name)
 
-    def _check_rpath(self, pkg, pkgfile_path, path):
-        for runpath in self.readelf_parser.dynamic_section_info.runpath:
-            if runpath in self.system_lib_paths or not
self.usr_lib_regex.search(runpath):
-                self.output.add_info('E', pkg, 'binary-or-shlib-defines-
rpath', path, runpath)
-                return
+    def _check_rpath(self, pkg, pkgfile):
+        for runpaths in self.readelf_parser.dynamic_section_info.runpaths:
+            for runpath in runpaths.split(':'):
+                if self.rpath_origin in runpath:
+                    runpath = runpath.replace(self.rpath_origin,
str(Path(pkgfile.name).parent))
+                    runpath = str(Path(runpath).resolve())
+                if not runpath.startswith(self.system_lib_paths) and not
self.usr_lib_regex.search(runpath):
+                    self.output.add_info('E', pkg, 'binary-or-shlib-
defines-rpath', pkgfile.name, runpath)
+                    return
 
-    def _check_library_dependency(self, pkg, pkgfile_path, path):
+    def _check_library_dependency(self, pkg, pkgfile):
         if self.is_archive:
             return
-        if any(path.startswith(p) for p in KERNEL_MODULES_PATHS):
+        elif any(pkgfile.name.startswith(p) for p in KERNEL_MODULES_PATHS):
+            return
+        elif self.python_module_regex.fullmatch(pkgfile.name):
             return
 
         dyn_section = self.readelf_parser.dynamic_section_info
@@ -438,10 +449,10 @@
                 msg = 'shared-library-without-dependency-information'
             else:
                 msg = 'statically-linked-binary'
-            self.output.add_info('E', pkg, msg, path)
+            self.output.add_info('E', pkg, msg, pkgfile.name)
         else:
             # linked against libc ?
-            if 'libc.' not in dyn_section.runpath and \
+            if 'libc.' not in dyn_section.runpaths and \
                (not dyn_section.soname or
                 ('libc.' not in dyn_section.soname and
                  not self.ldso_soname_regex.search(dyn_section.soname))):
@@ -452,9 +463,9 @@
                     msg = 'library-not-linked-against-libc'
                 else:
                     msg = 'program-not-linked-against-libc'
-                self.output.add_info('W', pkg, msg, path)
+                self.output.add_info('W', pkg, msg, pkgfile.name)
 
-    def _check_forbidden_functions(self, pkg, pkgfile_path, path):
+    def _check_forbidden_functions(self, pkg, pkgfile):
         forbidden_functions = self.config.configuration['WarnOnFunction']
         if forbidden_functions:
             for name, func in forbidden_functions.items():
@@ -474,10 +485,10 @@
         if not forbidden_calls:
             return
 
-        strings_parser = StringsParser(pkgfile_path)
+        strings_parser = StringsParser(pkgfile.path)
         failed_reason = strings_parser.parsing_failed_reason
         if failed_reason:
-            self.output.add_info('E', pkg, 'strings-failed', path,
failed_reason)
+            self.output.add_info('E', pkg, 'strings-failed', pkgfile.name,
failed_reason)
             return
 
         forbidden_functions_filtered = []
@@ -493,15 +504,13 @@
                 forbidden_functions_filtered.append(fn)
 
         for fn in forbidden_functions_filtered:
-            self.output.add_info('W', pkg, fn, path,
forbidden_functions[fn]['f_name'])
+            self.output.add_info('W', pkg, fn, pkgfile.name,
forbidden_functions[fn]['f_name'])
 
-    def _check_executable_shlib(self, pkg, pkgfile_path, path):
-        if not self.is_exec and self.readelf_parser.is_shlib:
-            interp = [h for h in
self.readelf_parser.program_header_info.headers if h.name == 'INTERP']
-            if interp:
-                self.output.add_info('E', pkg, 'shared-library-not-
executable', path)
+    def _check_executable_shlib(self, pkg, pkgfile):
+        if not (pkgfile.mode & stat.S_IEXEC) and
self.readelf_parser.is_shlib:
+            self.output.add_info('E', pkg, 'shared-library-not-executable',
pkgfile.name)
 
-    def _check_optflags(self, pkg, pkgfile_path, path):
+    def _check_optflags(self, pkg, pkgfile):
         if self.is_archive:
             return
 
@@ -515,21 +524,21 @@
             missing = [mo for mo in mandatory_optflags if mo not in tokens]
             forbidden = [f for f in forbidden_optflags if f in tokens]
             if missing:
-                self.output.add_info('W', pkg, 'missing-mandatory-
optflags', path, ' '.join(missing))
+                self.output.add_info('W', pkg, 'missing-mandatory-
optflags', pkgfile.name, ' '.join(missing))
             if forbidden:
-                self.output.add_info('E', pkg, 'forbidden-optflags', path,
' '.join(forbidden))
+                self.output.add_info('E', pkg, 'forbidden-optflags',
pkgfile.name, ' '.join(forbidden))
 
-    def _is_standard_archive(self, pkg, pkgfile_path, path):
+    def _is_standard_archive(self, pkg, pkgfile):
         # skip Klee bytecode archives
-        if pkgfile_path.endswith('.bca'):
+        if pkgfile.path.endswith('.bca'):
             return False
 
         # return false for e.g. Rust or Go packages that are archives
         # but files in the archive are not an ELF container
-        ar_parser = ArParser(pkgfile_path)
+        ar_parser = ArParser(pkgfile.path)
         failed_reason = ar_parser.parsing_failed_reason
         if failed_reason:
-            self.output.add_info('E', pkg, 'ar-failed', path,
failed_reason)
+            self.output.add_info('E', pkg, 'ar-failed', pkgfile.name,
failed_reason)
             return False
 
         needles = ('__.PKGDEF', '_go_.o', 'lib.rmeta')
@@ -543,38 +552,40 @@
         self.is_pie_exec = 'pie executable' in magic
         self.is_nonstandard_archive = False
 
-    def run_elf_checks(self, pkg, pkgfile_path, path):
-        if self.is_archive and not self._is_standard_archive(pkg,
pkgfile_path, path):
+    def run_elf_checks(self, pkg, pkgfile):
+        if self.is_archive and not self._is_standard_archive(pkg, pkgfile):
             self.is_nonstandard_archive = True
             return
 
-        self.readelf_parser = ReadelfParser(pkgfile_path, path)
+        self.readelf_parser = ReadelfParser(pkgfile.path, pkgfile.name)
         failed_reason = self.readelf_parser.parsing_failed_reason()
         if failed_reason:
-            self.output.add_info('E', pkg, 'readelf-failed', path,
failed_reason)
+            self.output.add_info('E', pkg, 'readelf-failed', pkgfile.name,
failed_reason)
             return
 
         if not self.is_archive:
             if self.is_dynamically_linked:
                 is_installed_pkg = isinstance(pkg, InstalledPkg) or
isinstance(pkg, FakePkg)
-                self.ldd_parser = LddParser(pkgfile_path, path,
is_installed_pkg)
+                self.ldd_parser = LddParser(pkgfile.path, pkgfile.name,
is_installed_pkg)
                 failed_reason = self.ldd_parser.parsing_failed_reason
                 if failed_reason:
-                    self.output.add_info('E', pkg, 'ldd-failed', path,
failed_reason)
+                    self.output.add_info('E', pkg, 'ldd-failed',
pkgfile.name, failed_reason)
                     return
 
-            self.objdump_parser = ObjdumpParser(pkgfile_path, path)
-            failed_reason = self.objdump_parser.parsing_failed_reason
-            if failed_reason:
-                self.output.add_info('E', pkg, 'objdump-failed', path,
failed_reason)
-                return
+            if (self.config.configuration['MandatoryOptflags'] or
+                    self.config.configuration['ForbiddenOptflags']):
+                self.objdump_parser = ObjdumpParser(pkgfile.path,
pkgfile.name)
+                failed_reason = self.objdump_parser.parsing_failed_reason
+                if failed_reason:
+                    self.output.add_info('E', pkg, 'objdump-failed',
pkgfile.name, failed_reason)
+                    return
 
         # NOTE: the speed benefit of the ThreadPoolExecutor is limited due
to
         # Global Interpreter Lock (GIL).
         with concurrent.futures.ThreadPoolExecutor() as executor:
             futures = []
             for fn in self.check_functions:
-                futures.append(executor.submit(fn, pkg, pkgfile_path,
path))
+                futures.append(executor.submit(fn, pkg, pkgfile))
             concurrent.futures.wait(futures)
             for future in futures:
                 err = future.exception()
@@ -583,7 +594,6 @@
 
     def check_binary(self, pkg):
         exec_files = []
-        multi_pkg = False
         pkg_has_lib = False
         pkg_has_binary = False
         pkg_has_binary_in_usrlib = False
@@ -593,7 +603,6 @@
         #  go through the all files, run files checks and collect data that
are
         #  needed later
         for fname, pkgfile in pkg.files.items():
-
             # Common tests first
             self._check_libtool_wrapper(pkg, fname, pkgfile)
             self._check_invalid_la_file(pkg, fname)
@@ -658,7 +667,7 @@
             self._detect_attributes(pkgfile.magic)
 
             # run ELF checks
-            self.run_elf_checks(pkg, pkgfile.path, fname)
+            self.run_elf_checks(pkg, pkgfile)
 
             if self.is_nonstandard_archive:
                 continue
@@ -686,19 +695,11 @@
 
                 self._check_non_pie(pkg, fname)
 
-        # find out if we have a multi-package
-        srpm = pkg[rpm.RPMTAG_SOURCERPM]
-        if srpm:
-            srcname = self.srcname_regex.search(srpm)
-            if srcname:
-                multi_pkg = (pkg.name != srcname.group(1))
-
         # run checks for the whole package
         # it uses data collected in the previous for-cycle
         self._check_exec_in_library(pkg, pkg_has_lib, exec_files)
         self._check_non_versioned(pkg, pkg_has_lib, exec_files)
-        self._check_no_binary(pkg, pkg_has_binary, multi_pkg,
-                              pkg_has_file_in_lib64)
+        self._check_no_binary(pkg, pkg_has_binary, pkg_has_file_in_lib64)
         self._check_noarch_with_lib64(pkg, pkg_has_file_in_lib64)
         self._check_only_non_binary_in_usrlib(pkg, pkg_has_usrlib_file,
                                               pkg_has_binary_in_usrlib)
diff -Nru rpmlint-2.2.0+ds1/rpmlint/checks/BuildDateCheck.py rpmlint-
2.3.0+ds1/rpmlint/checks/BuildDateCheck.py
--- rpmlint-2.2.0+ds1/rpmlint/checks/BuildDateCheck.py  2021-12-12
09:54:14.000000000 -0500
+++ rpmlint-2.3.0+ds1/rpmlint/checks/BuildDateCheck.py  1969-12-31
19:00:00.000000000 -0500
@@ -1,32 +0,0 @@
-import re
-import stat
-import time
-
-from rpmlint.checks.AbstractCheck import AbstractFilesCheck
-
-
-class BuildDateCheck(AbstractFilesCheck):
-    """
-    Check that the file doesn't contain the current date or time.
-
-    If so, it causes the package to rebuild when it's not needed.
-    """
-    def __init__(self, config, output):
-        super().__init__(config, output, r'.*')
-        self.looksliketime = re.compile('(2[0-3]|[01]?[0-9]):([0-5]?[0-
9]):([0-5]?[0-9])')
-        self.istoday = re.compile(time.strftime('%b %e %Y'))
-
-    def check_file(self, pkg, filename):
-        if filename.startswith('/usr/lib/debug') or pkg.is_source or \
-                not stat.S_ISREG(pkg.files[filename].mode):
-            return
-
-        grep_date = pkg.grep(self.istoday, filename)
-
-        if len(grep_date):
-            grep_time = pkg.grep(self.looksliketime, filename)
-
-            if len(grep_time):
-                self.output.add_info('E', pkg, 'file-contains-date-and-
time', filename)
-            else:
-                self.output.add_info('E', pkg, 'file-contains-current-
date', filename)
diff -Nru rpmlint-2.2.0+ds1/rpmlint/checks/BuildRootAndDateCheck.py rpmlint-
2.3.0+ds1/rpmlint/checks/BuildRootAndDateCheck.py
--- rpmlint-2.2.0+ds1/rpmlint/checks/BuildRootAndDateCheck.py   1969-12-31
19:00:00.000000000 -0500
+++ rpmlint-2.3.0+ds1/rpmlint/checks/BuildRootAndDateCheck.py   2022-05-29
12:46:55.000000000 -0400
@@ -0,0 +1,39 @@
+import re
+import stat
+import time
+
+import rpm
+from rpmlint.checks.AbstractCheck import AbstractFilesCheck
+
+
+class BuildRootAndDateCheck(AbstractFilesCheck):
+    """
+    Check that the file doesn't contain the current date or time.
+    And check the file does not contain build root reference.
+
+    If so, it causes the package to rebuild when it's not needed.
+    """
+    def __init__(self, config, output):
+        super().__init__(config, output, r'.*')
+        self.looksliketime = re.compile('(2[0-3]|[01]?[0-9]):([0-5]?[0-
9]):([0-5]?[0-9])')
+        self.istoday = re.compile(time.strftime('%b %e %Y'))
+        self.prepare_regex(rpm.expandMacro('%buildroot'))
+
+    def prepare_regex(self, buildroot):
+        for m in ('name', 'version', 'release', 'NAME', 'VERSION',
'RELEASE'):
+            buildroot = buildroot.replace('%%{%s}' % (m), r'[\w\!-
\.]{1,20}')
+        self.build_root_re = re.compile(buildroot)
+
+    def check_file(self, pkg, filename):
+        if filename.startswith('/usr/lib/debug') or pkg.is_source or \
+                not stat.S_ISREG(pkg.files[filename].mode):
+            return
+
+        data = pkg.read_with_mmap(filename)
+        if self.istoday.search(data):
+            if self.looksliketime.search(data):
+                self.output.add_info('E', pkg, 'file-contains-date-and-
time', filename)
+            else:
+                self.output.add_info('E', pkg, 'file-contains-current-
date', filename)
+        if self.build_root_re.search(data):
+            self.output.add_info('E', pkg, 'file-contains-buildroot',
filename)
diff -Nru rpmlint-2.2.0+ds1/rpmlint/checks/BuildRootCheck.py rpmlint-
2.3.0+ds1/rpmlint/checks/BuildRootCheck.py
--- rpmlint-2.2.0+ds1/rpmlint/checks/BuildRootCheck.py  2021-12-12
09:54:14.000000000 -0500
+++ rpmlint-2.3.0+ds1/rpmlint/checks/BuildRootCheck.py  1969-12-31
19:00:00.000000000 -0500
@@ -1,25 +0,0 @@
-import re
-import stat
-
-import rpm
-from rpmlint.checks.AbstractCheck import AbstractFilesCheck
-
-
-class BuildRootCheck(AbstractFilesCheck):
-    def __init__(self, config, output):
-        super().__init__(config, output, r'.*')
-        self.prepare_regex(rpm.expandMacro('%buildroot'))
-
-    def prepare_regex(self, buildroot):
-        for m in ('name', 'version', 'release', 'NAME', 'VERSION',
'RELEASE'):
-            buildroot = buildroot.replace('%%{%s}' % (m), r'[\w\!-
\.]{1,20}')
-        self.build_root_re = re.compile(buildroot)
-
-    def check_file(self, pkg, filename):
-        if filename.startswith('/usr/lib/debug') or pkg.is_source:
-            return
-        if not stat.S_ISREG(pkg.files[filename].mode):
-            return
-
-        if pkg.grep(self.build_root_re, filename):
-            self.output.add_info('E', pkg, 'file-contains-buildroot',
filename)
diff -Nru rpmlint-2.2.0+ds1/rpmlint/checks/DBusPolicyCheck.py rpmlint-
2.3.0+ds1/rpmlint/checks/DBusPolicyCheck.py
--- rpmlint-2.2.0+ds1/rpmlint/checks/DBusPolicyCheck.py 2021-12-12
09:54:14.000000000 -0500
+++ rpmlint-2.3.0+ds1/rpmlint/checks/DBusPolicyCheck.py 2022-05-29
12:46:55.000000000 -0400
@@ -18,7 +18,7 @@
             try:
                 if any(f.startswith(d) for d in DBUS_DIRECTORIES):
                     send_policy_seen = False
-                    lf = pkg.dirName() + f
+                    lf = pkg.dir_name() + f
                     xml = parse(lf)
                     for policy in xml.getElementsByTagName('policy'):
                         send_policy_seen =
self._check_allow_policy_element(pkg, f, policy) or send_policy_seen
diff -Nru rpmlint-2.2.0+ds1/rpmlint/checks/ErlangCheck.py rpmlint-
2.3.0+ds1/rpmlint/checks/ErlangCheck.py
--- rpmlint-2.2.0+ds1/rpmlint/checks/ErlangCheck.py     2021-12-12
09:54:14.000000000 -0500
+++ rpmlint-2.3.0+ds1/rpmlint/checks/ErlangCheck.py     2022-05-29
12:46:55.000000000 -0400
@@ -20,7 +20,7 @@
                 self.output.add_info('W', pkg, 'beam-compile-info-missed',
filename)
                 return
 
-            compile_state = byte_to_string(str(beam.compileinfo['source']))
+            compile_state = byte_to_string(beam.compileinfo['source'])
             if 'debug_info' not in beam.compileinfo['options']:
                 self.output.add_info('E', pkg, 'beam-compiled-without-
debuginfo', filename)
 
diff -Nru rpmlint-2.2.0+ds1/rpmlint/checks/FilesCheck.py rpmlint-
2.3.0+ds1/rpmlint/checks/FilesCheck.py
--- rpmlint-2.2.0+ds1/rpmlint/checks/FilesCheck.py      2021-12-12
09:54:14.000000000 -0500
+++ rpmlint-2.3.0+ds1/rpmlint/checks/FilesCheck.py      2022-05-29
12:46:55.000000000 -0400
@@ -327,7 +327,6 @@
 
 
 class FilesCheck(AbstractCheck):
-
     man_regex = re.compile(r'/man(?:\d[px]?|n)/')
     info_regex = re.compile(r'(/usr/share|/usr)/info/')
 
@@ -421,7 +420,6 @@
         return (chunk, istext)
 
     def check(self, pkg):
-
         for filename in pkg.header[rpm.RPMTAG_FILENAMES] or ():
             if not is_utf8_bytestr(filename):
                 self.output.add_info('E', pkg, 'filename-not-utf8',
byte_to_string(filename))
@@ -588,7 +586,6 @@
 
             # normal file check
             if stat.S_ISREG(mode):
-
                 # set[ug]id bit check
                 if stat.S_ISGID & mode or stat.S_ISUID & mode:
                     if stat.S_ISUID & mode:
diff -Nru rpmlint-2.2.0+ds1/rpmlint/checks/InitScriptCheck.py rpmlint-
2.3.0+ds1/rpmlint/checks/InitScriptCheck.py
--- rpmlint-2.2.0+ds1/rpmlint/checks/InitScriptCheck.py 2021-12-12
09:54:14.000000000 -0500
+++ rpmlint-2.3.0+ds1/rpmlint/checks/InitScriptCheck.py 2022-05-29
12:46:55.000000000 -0400
@@ -60,7 +60,6 @@
 
 
 class InitScriptCheck(AbstractCheck):
-
     def __init__(self, config, output):
         super().__init__(config, output)
         self.use_deflevels =
self.config.configuration['UseDefaultRunlevels']
@@ -69,7 +68,6 @@
     def check_binary(self, pkg):
         initscript_list = []
         for fname, pkgfile in pkg.files.items():
-
             if not fname.startswith('/etc/init.d/') and \
                     not fname.startswith('/etc/rc.d/init.d/'):
                 continue
diff -Nru rpmlint-2.2.0+ds1/rpmlint/checks/LogrotateCheck.py rpmlint-
2.3.0+ds1/rpmlint/checks/LogrotateCheck.py
--- rpmlint-2.2.0+ds1/rpmlint/checks/LogrotateCheck.py  2021-12-12
09:54:14.000000000 -0500
+++ rpmlint-2.3.0+ds1/rpmlint/checks/LogrotateCheck.py  2022-05-29
12:46:55.000000000 -0400
@@ -17,7 +17,7 @@
 
             if f.startswith('/etc/logrotate.d/'):
                 try:
-                    for n, o in self.parselogrotateconf(pkg.dirName(),
f).items():
+                    for n, o in self.parselogrotateconf(pkg.dir_name(),
f).items():
                         if n in dirs and dirs[n] != o:
                             self.output.add_info('E', pkg, 'logrotate-
duplicate', n)
                         else:
diff -Nru rpmlint-2.2.0+ds1/rpmlint/checks/MenuCheck.py rpmlint-
2.3.0+ds1/rpmlint/checks/MenuCheck.py
--- rpmlint-2.2.0+ds1/rpmlint/checks/MenuCheck.py       2021-12-12
09:54:14.000000000 -0500
+++ rpmlint-2.3.0+ds1/rpmlint/checks/MenuCheck.py       2022-05-29
12:46:55.000000000 -0400
@@ -31,7 +31,6 @@
 
 
 class MenuCheck(AbstractCheck):
-
     def __init__(self, config, output):
         super().__init__(config, output)
         self.valid_sections =
self.config.configuration['ValidMenuSections']
@@ -93,7 +92,7 @@
             elif not update_menus_regex.search(postun):
                 self.output.add_info('E', pkg, 'postun-without-update-
menus')
 
-            directory = pkg.dirName()
+            directory = pkg.dir_name()
             for f in menus:
                 # remove comments and handle cpp continuation lines
                 text = subprocess.run(('/lib/cpp', directory + f),
stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
env=ENGLISH_ENVIROMENT).stdout.decode()
diff -Nru rpmlint-2.2.0+ds1/rpmlint/checks/MenuXDGCheck.py rpmlint-
2.3.0+ds1/rpmlint/checks/MenuXDGCheck.py
--- rpmlint-2.2.0+ds1/rpmlint/checks/MenuXDGCheck.py    2021-12-12
09:54:14.000000000 -0500
+++ rpmlint-2.3.0+ds1/rpmlint/checks/MenuXDGCheck.py    2022-05-29
12:46:55.000000000 -0400
@@ -42,7 +42,7 @@
             self._has_binary(pkg, root, cfp, filename)
 
     def check_file(self, pkg, filename):
-        root = pkg.dirName()
+        root = pkg.dir_name()
         f = root + filename
         try:
             command = subprocess.run(('desktop-file-validate', f),
stdout=subprocess.PIPE, stderr=subprocess.STDOUT, env=ENGLISH_ENVIROMENT)
diff -Nru rpmlint-2.2.0+ds1/rpmlint/checks/PkgConfigCheck.py rpmlint-
2.3.0+ds1/rpmlint/checks/PkgConfigCheck.py
--- rpmlint-2.2.0+ds1/rpmlint/checks/PkgConfigCheck.py  2021-12-12
09:54:14.000000000 -0500
+++ rpmlint-2.3.0+ds1/rpmlint/checks/PkgConfigCheck.py  2022-05-29
12:46:55.000000000 -0400
@@ -27,7 +27,7 @@
             return
 
         try:
-            with open(pkg.dirName() + '/' + filename, 'r', encoding='utf-
8') as pc_file:
+            with open(pkg.dir_name() + '/' + filename, 'r', encoding='utf-
8') as pc_file:
                 for line in pc_file:
                     self._check_invalid_pkgconfig_file(pkg, filename, line)
                     self._check_invalid_libs_dir(pkg, filename, line)
diff -Nru rpmlint-2.2.0+ds1/rpmlint/checks/PostCheck.py rpmlint-
2.3.0+ds1/rpmlint/checks/PostCheck.py
--- rpmlint-2.2.0+ds1/rpmlint/checks/PostCheck.py       2021-12-12
09:54:14.000000000 -0500
+++ rpmlint-2.3.0+ds1/rpmlint/checks/PostCheck.py       2022-05-29
12:46:55.000000000 -0400
@@ -71,7 +71,6 @@
 
 
 class PostCheck(AbstractCheck):
-
     def __init__(self, config, output):
         super().__init__(config, output)
         self.valid_shells = config.configuration['ValidShells']
diff -Nru rpmlint-2.2.0+ds1/rpmlint/checks/SharedLibraryPolicyCheck.py
rpmlint-2.3.0+ds1/rpmlint/checks/SharedLibraryPolicyCheck.py
--- rpmlint-
2.2.0+ds1/rpmlint/checks/SharedLibraryPolicyCheck.py    2021-12-12 
09:54:14.000000000-0500
+++ rpmlint-
2.3.0+ds1/rpmlint/checks/SharedLibraryPolicyCheck.py    2022-05-29 
12:46:55.000000000-0400
@@ -23,7 +23,7 @@
         self.re_soname_strongly_versioned = re.compile(r'-[\d\.]+\.so$')
         # the pkgname is based on soname if ending with number; special
option is flavor build
         self.re_soname_pkg = re.compile(r'^lib\S+(\d+(-(32|64)bit)?)$')
-        self.re_so_files = re.compile(r'\S+.so((.(\d+))+)?$')
+        self.re_so_files = re.compile(r'\S+.so((\.(\d+))*)$')
 
     def _check_missing_policy_lib(self, pkg):
         # check the pkg has any libname
diff -Nru rpmlint-2.2.0+ds1/rpmlint/checks/SignatureCheck.py rpmlint-
2.3.0+ds1/rpmlint/checks/SignatureCheck.py
--- rpmlint-2.2.0+ds1/rpmlint/checks/SignatureCheck.py  2021-12-12
09:54:14.000000000 -0500
+++ rpmlint-2.3.0+ds1/rpmlint/checks/SignatureCheck.py  2022-05-29
12:46:55.000000000 -0400
@@ -17,11 +17,11 @@
     invalid_sig_regex = re.compile(r'invalid OpenPGP signature')
 
     def check(self, pkg):
-        retcode, output = pkg.checkSignature()
+        retcode, output = pkg.check_signature()
 
-        # Skip all signature checks if checkSignature output is empty
+        # Skip all signature checks if check_signature output is empty
         if output is None:
-            print_warning(f'No output from checkSignature() for '
+            print_warning(f'No output from check_signature() for '
                           f'{pkg.filename}. Skipping signature checks.')
             return
 
diff -Nru rpmlint-2.2.0+ds1/rpmlint/checks/SourceCheck.py rpmlint-
2.3.0+ds1/rpmlint/checks/SourceCheck.py
--- rpmlint-2.2.0+ds1/rpmlint/checks/SourceCheck.py     2021-12-12
09:54:14.000000000 -0500
+++ rpmlint-2.3.0+ds1/rpmlint/checks/SourceCheck.py     2022-05-29
12:46:55.000000000 -0400
@@ -33,7 +33,6 @@
     def check_source(self, pkg):
         # process file list
         for fname, pkgfile in pkg.files.items():
-
             self._check_file_ext(fname, pkgfile, pkg)
             self._check_permissions(fname, pkgfile, pkg)
             self._check_compressed_source(fname, pkg)
diff -Nru rpmlint-2.2.0+ds1/rpmlint/checks/SpecCheck.py rpmlint-
2.3.0+ds1/rpmlint/checks/SpecCheck.py
--- rpmlint-2.2.0+ds1/rpmlint/checks/SpecCheck.py       2021-12-12
09:54:14.000000000 -0500
+++ rpmlint-2.3.0+ds1/rpmlint/checks/SpecCheck.py       2022-05-29
12:46:55.000000000 -0400
@@ -172,14 +172,12 @@
         self._check_non_utf8_spec_file(pkg)
 
         # gather info from spec lines
-
         pkg.current_linenum = 0
 
         nbsp = UNICODE_NBSP
 
         # Analyse specfile line by line to check for (E)rrors or (W)arnings
         for line in spec_lines:
-
             pkg.current_linenum += 1
 
             char = line.find(nbsp)
diff -Nru rpmlint-2.2.0+ds1/rpmlint/checks/TagsCheck.py rpmlint-
2.3.0+ds1/rpmlint/checks/TagsCheck.py
--- rpmlint-2.2.0+ds1/rpmlint/checks/TagsCheck.py       2021-12-12
09:54:14.000000000 -0500
+++ rpmlint-2.3.0+ds1/rpmlint/checks/TagsCheck.py       2022-05-29
12:46:55.000000000 -0400
@@ -32,7 +32,6 @@
 
 
 class TagsCheck(AbstractCheck):
-
     def __init__(self, config, output):
         super().__init__(config, output)
         self.valid_groups = config.configuration['ValidGroups']
diff -Nru rpmlint-2.2.0+ds1/rpmlint/cli.py rpmlint-2.3.0+ds1/rpmlint/cli.py
--- rpmlint-2.2.0+ds1/rpmlint/cli.py    2021-12-12 09:54:14.000000000 -0500
+++ rpmlint-2.3.0+ds1/rpmlint/cli.py    2022-05-29 12:46:55.000000000 -0400
@@ -82,6 +82,10 @@
     parser.add_argument('-i', '--installed', nargs='+', default='',
help='installed packages to be validated by rpmlint')
     parser.add_argument('-t', '--time-report', action='store_true',
help='print time report for run checks')
     parser.add_argument('-T', '--profile', action='store_true', help='print
cProfile report')
+    parser.add_argument('--ignore-unused-rpmlintrc', action='store_true',
+                        help='Do not report "unused-rpmlintrc-filter"
errors')
+    parser.add_argument('--checks',
+                        help='Debugging option that enables only selected
checks (separated by comma)')
     lint_modes_parser = parser.add_mutually_exclusive_group()
     lint_modes_parser.add_argument('-s', '--strict', action='store_true',
help='treat all messages as errors')
     lint_modes_parser.add_argument('-P', '--permissive',
action='store_true', help='treat individual errors as non-fatal')
diff -Nru rpmlint-2.2.0+ds1/rpmlint/configdefaults.toml rpmlint-
2.3.0+ds1/rpmlint/configdefaults.toml
--- rpmlint-2.2.0+ds1/rpmlint/configdefaults.toml       2021-12-12
09:54:14.000000000 -0500
+++ rpmlint-2.3.0+ds1/rpmlint/configdefaults.toml       2022-05-29
12:46:55.000000000 -0400
@@ -3,8 +3,7 @@
     "AlternativesCheck",
     "AppDataCheck",
     "BinariesCheck",
-    "BuildDateCheck",
-    'BuildRootCheck',
+    'BuildRootAndDateCheck',
     "ConfigFilesCheck",
     "DBusPolicyCheck",
     'DuplicatesCheck',
diff -Nru rpmlint-2.2.0+ds1/rpmlint/descriptions/BinariesCheck.toml rpmlint-
2.3.0+ds1/rpmlint/descriptions/BinariesCheck.toml
--- rpmlint-2.2.0+ds1/rpmlint/descriptions/BinariesCheck.toml   2021-12-12
09:54:14.000000000 -0500
+++ rpmlint-2.3.0+ds1/rpmlint/descriptions/BinariesCheck.toml   2022-05-29
12:46:55.000000000 -0400
@@ -46,7 +46,7 @@
 to install the relinked file.
 """
 binary-or-shlib-defines-rpath="""
-The binary or shared library defines `RPATH'.
+The binary or shared library defines `RPATH' (or `RUNPATH').
 """
 statically-linked-binary="""
 The package installs a statically linked binary or object file.
diff -Nru rpmlint-2.2.0+ds1/rpmlint/filter.py rpmlint-
2.3.0+ds1/rpmlint/filter.py
--- rpmlint-2.2.0+ds1/rpmlint/filter.py 2021-12-12 09:54:14.000000000 -0500
+++ rpmlint-2.3.0+ds1/rpmlint/filter.py 2022-05-29 12:46:55.000000000 -0400
@@ -43,6 +43,8 @@
         self.error_details.update(self._load_descriptions())
         # Counter of how many issues we encountered
         self.printed_messages = {'I': 0, 'W': 0, 'E': 0}
+        # Number of promoted warnings and infos to errors
+        self.promoted_to_error = 0
         # Messages
         self.results = []
 
@@ -99,6 +101,8 @@
         # allow strict reporting where we override levels and treat
everything
         # as an error
         if self.strict:
+            if level != 'E':
+                self.promoted_to_error += 1
             level = 'E'
 
         if badness is None:
diff -Nru rpmlint-2.2.0+ds1/rpmlint/helpers.py rpmlint-
2.3.0+ds1/rpmlint/helpers.py
--- rpmlint-2.2.0+ds1/rpmlint/helpers.py        2021-12-12
09:54:14.000000000 -0500
+++ rpmlint-2.3.0+ds1/rpmlint/helpers.py        2022-05-29
12:46:55.000000000 -0400
@@ -7,7 +7,8 @@
 from rpmlint.color import Color
 
 
-ENGLISH_ENVIROMENT = dict(os.environ, LC_ALL='en_US.UTF-8')
+ENGLISH_ENVIROMENT = dict(os.environ, LC_ALL='en_US.UTF-8',
+                          LANGUAGE='en_US')
 
 
 def string_center(message, filler=' '):
diff -Nru rpmlint-2.2.0+ds1/rpmlint/__isocodes__.py rpmlint-
2.3.0+ds1/rpmlint/__isocodes__.py
--- rpmlint-2.2.0+ds1/rpmlint/__isocodes__.py   2021-12-12
09:54:14.000000000 -0500
+++ rpmlint-2.3.0+ds1/rpmlint/__isocodes__.py   2022-05-29
12:46:55.000000000 -0400
@@ -2525,6 +2525,7 @@
  'hwo',
  'hy',
  'hya',
+ 'hye',
  'hz',
  'ia',
  'iai',
diff -Nru rpmlint-2.2.0+ds1/rpmlint/lint.py rpmlint-
2.3.0+ds1/rpmlint/lint.py
--- rpmlint-2.2.0+ds1/rpmlint/lint.py   2021-12-12 09:54:14.000000000 -0500
+++ rpmlint-2.3.0+ds1/rpmlint/lint.py   2022-05-29 12:46:55.000000000 -0400
@@ -1,3 +1,4 @@
+from collections import defaultdict
 import cProfile
 import importlib
 import operator
@@ -10,7 +11,7 @@
 from rpmlint.config import Config
 from rpmlint.filter import Filter
 from rpmlint.helpers import print_warning, string_center
-from rpmlint.pkg import FakePkg, getInstalledPkgs, Pkg
+from rpmlint.pkg import FakePkg, get_installed_pkgs, Pkg
 from rpmlint.version import __version__
 
 
@@ -25,7 +26,7 @@
         self.options = options
         self.packages_checked = 0
         self.specfiles_checked = 0
-        self.check_duration = {}
+        self.check_duration = defaultdict(lambda: 0)
         if options['config']:
             self.config = Config(options['config'])
         else:
@@ -86,7 +87,8 @@
             retcode = 66
         elif self.output.printed_messages['E'] > 0 and not
self.config.permissive:
             quit_color = Color.Red
-            retcode = 64
+            all_promoted = self.output.printed_messages['E'] ==
self.output.promoted_to_error
+            retcode = 65 if all_promoted else 64
 
         self._maybe_print_reports()
 
@@ -121,26 +123,30 @@
         return f'{color}{fraction:17.1f}{Color.Reset}'
 
     def _print_time_report(self):
-        THRESHOLD = 1
+        PERCENT_THRESHOLD = 1
+        TIME_THRESHOLD = 0.1
         total = sum(self.check_duration.values())
         checked_files = [check.checked_files for check in
self.checks.values() if check.checked_files]
         total_checked_files = max(checked_files) if checked_files else ''
-        print(f'\n{Color.Bold}Check time report{Color.Reset}
(>{THRESHOLD}%):')
+        print(f'{Color.Bold}Check time report{Color.Reset}
(>{PERCENT_THRESHOLD}% & >{TIME_THRESHOLD}s):')
 
         print(f'{Color.Bold}    {"Check":32s} {"Duration (in s)":>12}
{"Fraction (in %)":>17}  Checked files{Color.Reset}')
         for check, duration in sorted(self.check_duration.items(),
key=operator.itemgetter(1), reverse=True):
             fraction = 100.0 * duration / total
-            if fraction < THRESHOLD:
+            if fraction < PERCENT_THRESHOLD or duration < TIME_THRESHOLD:
                 continue
-            checked_files = self.checks[check].checked_files
-            if not checked_files:
-                checked_files = ''
-            print(f'    {check:32s} {duration:15.2f}
{self._get_color_time_report_value(fraction)} {checked_files:>14}')
-        print(f'    {"TOTAL":32s} {total:15.2f} {100:17.2f}
{total_checked_files:>14}')
+
+            checked_files = ''
+            if check in self.checks:
+                checked = self.checks[check].checked_files
+                if checked:
+                    checked_files = checked
+            print(f'    {check:32s} {duration:15.1f}
{self._get_color_time_report_value(fraction)} {checked_files:>14}')
+        print(f'    {"TOTAL":32s} {total:15.1f} {100:17.1f}
{total_checked_files:>14}\n')
 
     def _print_cprofile(self):
         N = 30
-        print(f'\n{Color.Bold}cProfile report:{Color.Reset}')
+        print(f'{Color.Bold}cProfile report:{Color.Reset}')
         self.profile.disable()
         stats = Stats(self.profile)
         stats.sort_stats('cumulative').print_stats(N)
@@ -152,7 +158,7 @@
     def _load_installed_rpms(self, packages):
         existing_packages = []
         for name in packages:
-            pkg = getInstalledPkgs(name)
+            pkg = get_installed_pkgs(name)
             if pkg:
                 existing_packages.extend(pkg)
             else:
@@ -230,30 +236,21 @@
         for pkg in packages:
             self.validate_file(pkg, pkg == packages[-1])
 
-        # run post check function
-        for checker in self.checks.values():
-            checker.after_checks()
-
     def _expand_filelist(self, files):
         packages = []
         for pkg in files:
-            if pkg.is_file() and self._check_valid_suffix(pkg):
+            if pkg.is_file() and pkg.suffix in ('.rpm', '.spm', '.spec'):
                 packages.append(pkg)
             elif pkg.is_dir():
                 packages.extend(self._expand_filelist(pkg.iterdir()))
         return packages
 
-    @staticmethod
-    def _check_valid_suffix(filename):
-        if any(ext == filename.suffix for ext in ['.rpm', '.spm',
'.spec']):
-            return True
-        return False
-
     def validate_file(self, pname, is_last):
         try:
             if pname.suffix == '.rpm' or pname.suffix == '.spm':
                 with Pkg(pname, self.config.configuration['ExtractDir'],
                          verbose=self.config.info) as pkg:
+                    self.check_duration['rpm2cpio'] += pkg.extraction_time
                     self.run_checks(pkg, is_last)
             elif pname.suffix == '.spec':
                 with FakePkg(pname) as pkg:
@@ -268,16 +265,18 @@
     def run_checks(self, pkg, is_last):
         spec_checks = isinstance(pkg, FakePkg)
         for checker in self.checks:
-            if checker not in self.check_duration:
-                self.check_duration[checker] = 0
             start = time.monotonic()
             fn = self.checks[checker].check_spec if spec_checks else
self.checks[checker].check
             fn(pkg)
             self.check_duration[checker] += time.monotonic() - start
 
-        # validate used filters in rpmlintrc
+        # run post check function and validate used filters in rpmlintrc
         if is_last:
-            self.output.validate_filters(pkg)
+            for checker in self.checks.values():
+                checker.after_checks()
+
+            if not self.options['ignore_unused_rpmlintrc']:
+                self.output.validate_filters(pkg)
 
         if spec_checks:
             self.specfiles_checked += 1
@@ -306,10 +305,15 @@
         SingletonTM
         """
 
+        selected_checks = self.options['checks']
+        if selected_checks:
+            selected_checks = selected_checks.split(',')
+
         for check in self.config.configuration['Checks']:
             if check in self.checks:
                 continue
-            self.checks[check] = self.load_check(check)
+            if not selected_checks or check in selected_checks:
+                self.checks[check] = self.load_check(check)
 
     def load_check(self, name):
         """Load a (check) module by its name, unless it is already
loaded."""
diff -Nru rpmlint-2.2.0+ds1/rpmlint/pkgfile.py rpmlint-
2.3.0+ds1/rpmlint/pkgfile.py
--- rpmlint-2.2.0+ds1/rpmlint/pkgfile.py        2021-12-12
09:54:14.000000000 -0500
+++ rpmlint-2.3.0+ds1/rpmlint/pkgfile.py        2022-05-29
12:46:55.000000000 -0400
@@ -2,7 +2,6 @@
 
 
 class PkgFile(object):
-
     __slots__ = ['name', 'path', 'flags', 'mode', 'user', 'group',
'linkto',
                  'size', 'md5', 'mtime', 'rdev', 'inode', 'requires',
'provides',
                  'lang', 'magic', 'filecaps']
diff -Nru rpmlint-2.2.0+ds1/rpmlint/pkg.py rpmlint-2.3.0+ds1/rpmlint/pkg.py
--- rpmlint-2.2.0+ds1/rpmlint/pkg.py    2021-12-12 09:54:14.000000000 -0500
+++ rpmlint-2.3.0+ds1/rpmlint/pkg.py    2022-05-29 12:46:55.000000000 -0400
@@ -2,6 +2,7 @@
 from collections import namedtuple
 import gzip
 import lzma
+import mmap
 import os
 from pathlib import Path
 import re
@@ -9,6 +10,7 @@
 import stat
 import subprocess
 import tempfile
+import time
 from urllib.parse import urljoin
 
 try:
@@ -22,7 +24,7 @@
 import rpm
 from rpmlint.helpers import byte_to_string, ENGLISH_ENVIROMENT,
print_warning
 from rpmlint.pkgfile import PkgFile
-import zstd
+import zstandard as zstd
 
 
 DepInfo = namedtuple('DepInfo', ('name', 'flags', 'version'))
@@ -380,7 +382,6 @@
 # classes representing package
 
 class AbstractPkg(object):
-
     def cleanup(self):
         pass
 
@@ -392,13 +393,16 @@
 
 
 class Pkg(AbstractPkg):
-
     _magic_from_compressed_re =
re.compile(r'\([^)]+\s+compressed\s+data\b')
 
     def __init__(self, filename, dirname, header=None, is_source=False,
extracted=False, verbose=False):
         self.filename = filename
         self.extracted = extracted
-        self.dirname = self.dir_name(dirname, verbose)
+
+        # record decompression and extraction time
+        start = time.monotonic()
+        self.dirname = self._extract_rpm(dirname, verbose)
+        self.extraction_time = time.monotonic() - start
         self.current_linenum = None
 
         self._req_names = -1
@@ -422,11 +426,11 @@
 
         (self.requires, self.prereq, self.provides, self.conflicts,
          self.obsoletes, self.recommends, self.suggests, self.enhances,
-         self.supplements) = self._gatherDepInfo()
+         self.supplements) = self._gather_dep_info()
 
         self.req_names = [x[0] for x in self.requires + self.prereq]
 
-        self.files = self._gatherFilesInfo()
+        self.files = self._gather_files_info()
         self.config_files = [x.name for x in self.files.values() if
x.is_config]
         self.doc_files = [x.name for x in self.files.values() if x.is_doc]
         self.ghost_files = [x.name for x in self.files.values() if
x.is_ghost]
@@ -470,14 +474,10 @@
             return val
 
     # return the name of the directory where the package is extracted
-    def dirName(self):
+    def dir_name(self):
         return self.dirname
 
-    def dir_name(self, dirname, verbose):
-        return self._extract(dirname, verbose)
-
-    # extract rpm contents
-    def _extract(self, dirname, verbose):
+    def _extract_rpm(self, dirname, verbose):
         if not Path(dirname).is_dir():
             print_warning('Unable to access dir %s' % dirname)
         elif dirname == '/':
@@ -504,7 +504,7 @@
             self.extracted = True
         return dirname
 
-    def checkSignature(self):
+    def check_signature(self):
         ret = subprocess.run(('rpm', '-Kv', self.filename),
                              stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
                              env=ENGLISH_ENVIROMENT)
@@ -519,19 +519,21 @@
             self.__tmpdir.cleanup()
 
     def grep(self, regex, filename):
-        """Grep regex from a file, return matching line numbers."""
-        ret = []
-        lineno = 0
+        """Grep regex from a file, return first matching line number
(starting with 1)."""
+        data = self.read_with_mmap(filename)
+        match = regex.search(data)
+        if match:
+            return data.count('\n', 0, match.start()) + 1
+        else:
+            return None
+
+    def read_with_mmap(self, filename):
+        """Mmap a file, return it's content decoded."""
         try:
-            with open(Path(self.dirName() or '/', filename.lstrip('/'))) as
in_file:
-                for line in in_file:
-                    lineno += 1
-                    if regex.search(line):
-                        ret.append(str(lineno))
-                        break
+            with open(Path(self.dir_name() or '/', filename.lstrip('/')))
as in_file:
+                return mmap.mmap(in_file.fileno(), 0, mmap.MAP_SHARED,
mmap.PROT_READ).read().decode()
         except Exception:
-            pass
-        return ret
+            return ''
 
     def langtag(self, tag, lang):
         """Get value of tag in the given language."""
@@ -544,8 +546,7 @@
         return ret
 
     # extract information about the files
-    def _gatherFilesInfo(self):
-
+    def _gather_files_info(self):
         ret = {}
         flags = self.header[rpm.RPMTAG_FILEFLAGS]
         modes = self.header[rpm.RPMTAG_FILEMODES]
@@ -576,7 +577,7 @@
             for idx, file in enumerate(files):
                 pkgfile = PkgFile(file)
                 pkgfile.path = os.path.normpath(os.path.join(
-                    self.dirName() or '/', pkgfile.name.lstrip('/')))
+                    self.dir_name() or '/', pkgfile.name.lstrip('/')))
                 pkgfile.flags = flags[idx]
                 pkgfile.mode = modes[idx]
                 pkgfile.user = byte_to_string(users[idx])
@@ -655,7 +656,7 @@
                     xs.append(DepInfo(name, flags[loop], evr))
         return xs, prereq
 
-    def _gatherDepInfo(self):
+    def _gather_dep_info(self):
         _requires = []
         _prereq = []
         _provides = []
@@ -720,7 +721,7 @@
         return prog
 
 
-def getInstalledPkgs(name):
+def get_installed_pkgs(name):
     """Get list of installed package objects by name."""
 
     pkgs = []
@@ -759,7 +760,7 @@
     def cleanup(self):
         pass
 
-    def checkSignature(self):
+    def check_signature(self):
         return (0, 'fake: pgp md5 OK')
 
 
@@ -776,13 +777,19 @@
         self.files = {}
         self.ghost_files = {}
 
+    def add_file(self, path, name):
+        pkgfile = PkgFile(name)
+        pkgfile.path = path
+        self.files[name] = pkgfile
+        return pkgfile
+
     def add_file_with_content(self, name, content, **flags):
         """
         Add file to the FakePkg and fill the file with provided
         string content.
         """
         basename = name.replace(os.path.sep, '_')
-        path = os.path.join(self.dirName(), basename)
+        path = os.path.join(self.dir_name(), basename)
         with open(path, 'w') as out:
             out.write(content)
             pkg_file = PkgFile(name)
@@ -806,7 +813,7 @@
         # HACK: reuse the real Pkg's logic
         return Pkg.readlink(self, pkgfile)
 
-    def dirName(self):
+    def dir_name(self):
         if not self.dirname:
             self.__tmpdir =
tempfile.TemporaryDirectory(prefix='rpmlint.%s.' % Path(self.name).name)
             self.dirname = self.__tmpdir.name
diff -Nru rpmlint-2.2.0+ds1/rpmlint/readelfparser.py rpmlint-
2.3.0+ds1/rpmlint/readelfparser.py
--- rpmlint-2.2.0+ds1/rpmlint/readelfparser.py  2021-12-12
09:54:14.000000000 -0500
+++ rpmlint-2.3.0+ds1/rpmlint/readelfparser.py  2022-05-29
12:46:55.000000000 -0400
@@ -76,15 +76,16 @@
     section_regex = re.compile(r'.*\]
(?P<section>\S*)\s*\S+\s*\S*\s*\S*\s*(?P<size>\w*)')
     pic_regex = re.compile(r'\.rela?\.(data|text)')
 
-    def __init__(self, path):
+    def __init__(self, path, extra_flags):
         self.path = path
         self.elf_files = []
         self.parsing_failed_reason = None
         self.pic = False
+        self.extra_flags = extra_flags
         self.parse()
 
     def parse(self):
-        r = subprocess.run(['readelf', '-W', '-S', self.path],
encoding='utf8',
+        r = subprocess.run(['readelf', '-W', '-S', self.path] +
self.extra_flags, encoding='utf8',
                            stdout=subprocess.PIPE, stderr=subprocess.PIPE,
env=ENGLISH_ENVIROMENT)
         if r.returncode != 0:
             self.parsing_failed_reason = r.stderr
@@ -145,14 +146,15 @@
 
     header_regex =
re.compile('\\s+(?P<header>\\w+)(\\s+\\w+){5}\\s+(?P<flags>[RWE ]{3}).*')
 
-    def __init__(self, path):
+    def __init__(self, path, extra_flags):
         self.path = path
         self.headers = []
         self.parsing_failed_reason = None
+        self.extra_flags = extra_flags
         self.parse()
 
     def parse(self):
-        r = subprocess.run(['readelf', '-W', '-l', self.path],
encoding='utf8',
+        r = subprocess.run(['readelf', '-W', '-l', self.path] +
self.extra_flags, encoding='utf8',
                            stdout=subprocess.PIPE, stderr=subprocess.PIPE,
env=ENGLISH_ENVIROMENT)
         if r.returncode != 0:
             self.parsing_failed_reason = r.stderr
@@ -215,17 +217,19 @@
     section_regex =
re.compile('\\s+\\w*\\s+\\((?P<key>[^\\)]+)\\)\\s+(?P<value>.*)')
     soname_regex = re.compile('Library soname: \\[(?P<soname>[^\\]]+)\\]')
     needed_regex = re.compile('Shared library: \\[(?P<library>[^\\]]+)\\]')
-    rpath_regex = re.compile('Library runpath: \\[(?P<path>[^\\]]+)\\]')
+    runpath_regex = re.compile('Library runpath: \\[(?P<path>[^\\]]+)\\]')
+    rpath_regex = re.compile('Library rpath: \\[(?P<path>[^\\]]+)\\]')
 
-    def __init__(self, path):
+    def __init__(self, path, extra_flags):
         self.path = path
         self.sections = []
         self.parsing_failed_reason = None
+        self.extra_flags = extra_flags
         self.parse()
         self.parse_meta()
 
     def parse(self):
-        r = subprocess.run(['readelf', '-W', '-d', self.path],
encoding='utf8',
+        r = subprocess.run(['readelf', '-W', '-d', self.path] +
self.extra_flags, encoding='utf8',
                            stdout=subprocess.PIPE, stderr=subprocess.PIPE,
env=ENGLISH_ENVIROMENT)
         if r.returncode != 0:
             self.parsing_failed_reason = r.stderr
@@ -255,11 +259,17 @@
             if r:
                 self.needed.append(r.group('library'))
 
-        self.runpath = []
+        self.runpaths = []
+
+        # Parse both RUNPATH and RPATH
         for line in self['RUNPATH']:
+            r = self.runpath_regex.search(line)
+            if r:
+                self.runpaths.append(r.group('path'))
+        for line in self['RPATH']:
             r = self.rpath_regex.search(line)
             if r:
-                self.runpath.append(r.group('path'))
+                self.runpaths.append(r.group('path'))
 
     def __getitem__(self, key):
         return [x.value for x in self.sections if x.key == key]
@@ -279,15 +289,16 @@
 
     section_regex = re.compile('\\s+[0-
9]+:\\s\\w+\\s+(\\w+)\\s+(?P<type>\\w+)\\s+(?P<bind>\\w+)\\s+(?P<visibility>
\\w+)\\s+\\w+\\s+(?P<name>\\S+)')
 
-    def __init__(self, path):
+    def __init__(self, path, extra_flags):
         self.path = path
         self.symbols = []
         self.parsing_failed_reason = None
+        self.extra_flags = extra_flags
         self.parse()
 
     def parse(self):
         try:
-            r = subprocess.run(['readelf', '-W', '-s', self.path],
encoding='utf8',
+            r = subprocess.run(['readelf', '-W', '-s', self.path] +
self.extra_flags, encoding='utf8',
                                stdout=subprocess.PIPE,
stderr=subprocess.PIPE, env=ENGLISH_ENVIROMENT)
             if r.returncode != 0:
                 self.parsing_failed_reason = r.stderr
@@ -316,14 +327,15 @@
 
     comment_regex = re.compile('\\s+\\[[\\s[0-9]+\\]\\s+(?P<comment>.*)')
 
-    def __init__(self, path):
+    def __init__(self, path, extra_flags):
         self.path = path
         self.comments = []
         self.parsing_failed_reason = None
+        self.extra_flags = extra_flags
         self.parse()
 
     def parse(self):
-        r = subprocess.run(['readelf', '-p', '.comment', self.path],
encoding='utf8',
+        r = subprocess.run(['readelf', '-p', '.comment', self.path] +
self.extra_flags, encoding='utf8',
                            stdout=subprocess.PIPE, stderr=subprocess.PIPE,
env=ENGLISH_ENVIROMENT)
         if r.returncode != 0:
             self.parsing_failed_reason = r.stderr
@@ -350,11 +362,16 @@
         self.is_shlib = self.so_regex.search(path)
         self.is_debug = path.endswith('.debug')
 
-        self.section_info = ElfSectionInfo(pkgfile_path)
-        self.program_header_info = ElfProgramHeaderInfo(pkgfile_path)
-        self.dynamic_section_info = ElfDynamicSectionInfo(pkgfile_path)
-        self.symbol_table_info = ElfSymbolTableInfo(pkgfile_path)
-        self.comment_section_info = ElfCommentInfo(pkgfile_path)
+        # Do not follow debug info links
+        output = subprocess.check_output('readelf --help', shell=True,
encoding='utf8')
+        flag = '--debug-dump=no-follow-links'
+        extra_flags = [flag] if flag in output else []
+
+        self.section_info = ElfSectionInfo(pkgfile_path, extra_flags)
+        self.program_header_info = ElfProgramHeaderInfo(pkgfile_path,
extra_flags)
+        self.dynamic_section_info = ElfDynamicSectionInfo(pkgfile_path,
extra_flags)
+        self.symbol_table_info = ElfSymbolTableInfo(pkgfile_path,
extra_flags)
+        self.comment_section_info = ElfCommentInfo(pkgfile_path,
extra_flags)
 
     def parsing_failed_reason(self):
         reasons = [self.section_info.parsing_failed_reason,
diff -Nru rpmlint-2.2.0+ds1/rpmlint/rpmdiff.py rpmlint-
2.3.0+ds1/rpmlint/rpmdiff.py
--- rpmlint-2.2.0+ds1/rpmlint/rpmdiff.py        2021-12-12
09:54:14.000000000 -0500
+++ rpmlint-2.3.0+ds1/rpmlint/rpmdiff.py        2022-05-29
12:46:55.000000000 -0400
@@ -5,7 +5,7 @@
 
 import rpm
 from rpmlint.helpers import byte_to_string, print_warning
-from rpmlint.pkg import getInstalledPkgs, Pkg
+from rpmlint.pkg import get_installed_pkgs, Pkg
 
 
 class Rpmdiff(object):
@@ -141,7 +141,7 @@
                 return Pkg(name, tmpdir)
         except TypeError:
             pass
-        inst = getInstalledPkgs(str(name))
+        inst = get_installed_pkgs(str(name))
         if not inst:
             raise KeyError(f'No installed packages by name {name}')
         if len(inst) > 1:
diff -Nru rpmlint-2.2.0+ds1/setup.py rpmlint-2.3.0+ds1/setup.py
--- rpmlint-2.2.0+ds1/setup.py  2021-12-12 09:54:14.000000000 -0500
+++ rpmlint-2.3.0+ds1/setup.py  2022-05-29 12:46:55.000000000 -0400
@@ -9,7 +9,7 @@
     url='https://github.com/rpm-software-management/rpmlint',
     download_url='https://github.com/rpm-software-management/rpmlint',
 
-    version='2.2.0',
+    version='2.3.0',
 
     author='Frédéric Lepied',
     author_email='[email protected]',
@@ -28,8 +28,6 @@
         'Operating System :: POSIX',
         'Operating System :: POSIX :: Linux',
         'Programming Language :: Python',
-        'Programming Language :: Python :: 3.6',
-        'Programming Language :: Python :: 3.7',
         'Programming Language :: Python :: 3.8',
         'Programming Language :: Python :: 3.9',
         'Programming Language :: Python :: 3.10',
@@ -45,8 +43,10 @@
         'pyxdg',
         'rpm',
         'toml',
-        'zstd',
+        'zstandard',
         'importlib-metadata;python_version<"3.8"',
+        'pyenchant',
+        'python-magic'
     ],
     tests_require=[
         'pytest',
diff -Nru rpmlint-2.2.0+ds1/test/test_build_date.py rpmlint-
2.3.0+ds1/test/test_build_date.py
--- rpmlint-2.2.0+ds1/test/test_build_date.py   2021-12-12
09:54:14.000000000 -0500
+++ rpmlint-2.3.0+ds1/test/test_build_date.py   2022-05-29
12:46:55.000000000 -0400
@@ -1,7 +1,7 @@
 import re
 
 import pytest
-from rpmlint.checks.BuildDateCheck import BuildDateCheck
+from rpmlint.checks.BuildRootAndDateCheck import BuildRootAndDateCheck
 from rpmlint.filter import Filter
 
 from Testing import CONFIG, get_tested_package
@@ -11,7 +11,7 @@
 def builddatecheck():
     CONFIG.info = True
     output = Filter(CONFIG)
-    test = BuildDateCheck(CONFIG, output)
+    test = BuildRootAndDateCheck(CONFIG, output)
     return output, test
 
 
diff -Nru rpmlint-2.2.0+ds1/test/test_build_root.py rpmlint-
2.3.0+ds1/test/test_build_root.py
--- rpmlint-2.2.0+ds1/test/test_build_root.py   2021-12-12
09:54:14.000000000 -0500
+++ rpmlint-2.3.0+ds1/test/test_build_root.py   2022-05-29
12:46:55.000000000 -0400
@@ -1,5 +1,5 @@
 import pytest
-from rpmlint.checks.BuildRootCheck import BuildRootCheck
+from rpmlint.checks.BuildRootAndDateCheck import BuildRootAndDateCheck
 from rpmlint.filter import Filter
 
 from Testing import CONFIG, get_tested_package
@@ -9,7 +9,7 @@
 def buildrootcheck():
     CONFIG.info = True
     output = Filter(CONFIG)
-    test = BuildRootCheck(CONFIG, output)
+    test = BuildRootAndDateCheck(CONFIG, output)
     return output, test
 
 
diff -Nru rpmlint-2.2.0+ds1/test/test_ldd_parser.py rpmlint-
2.3.0+ds1/test/test_ldd_parser.py
--- rpmlint-2.2.0+ds1/test/test_ldd_parser.py   2021-12-12
09:54:14.000000000 -0500
+++ rpmlint-2.3.0+ds1/test/test_ldd_parser.py   2022-05-29
12:46:55.000000000 -0400
@@ -27,9 +27,9 @@
     return LddParser(get_full_path(path), system_path, True)
 
 
-def run_elf_checks(test, pkg, fullpath, path):
-    test._detect_attributes(get_magic(fullpath))
-    test.run_elf_checks(pkg, fullpath, path)
+def run_elf_checks(test, pkg, pkgfile):
+    test._detect_attributes(get_magic(pkgfile.path))
+    test.run_elf_checks(pkg, pkgfile)
 
 
 @pytest.mark.skipif(not IS_X86_64, reason='x86-64 only')
@@ -64,38 +64,46 @@
 @pytest.mark.skipif(not IS_X86_64, reason='x86-64 only')
 def test_unused_dependency_in_package(binariescheck):
     output, test = binariescheck
-    run_elf_checks(test, FakePkg('fake'),
get_full_path('libtirpc.so.3.0.0'), '/lib64/x.so')
-    assert not test.readelf_parser.parsing_failed_reason()
-    assert not test.ldd_parser.parsing_failed_reason
-    out = output.print_results(output.results)
-    assert 'E: unused-direct-shlib-dependency ' in out
+    with FakePkg('fake') as pkg:
+        pkgfile = pkg.add_file(get_full_path('libtirpc.so.3.0.0'),
'/lib64/x.so')
+        run_elf_checks(test, pkg, pkgfile)
+        assert not test.readelf_parser.parsing_failed_reason()
+        assert not test.ldd_parser.parsing_failed_reason
+        out = output.print_results(output.results)
+        assert 'E: unused-direct-shlib-dependency ' in out
 
 
 @pytest.mark.skipif(not IS_X86_64, reason='x86-64 only')
 def test_unused_dependency_in_package_for_executable(binariescheck):
     output, test = binariescheck
-    run_elf_checks(test, FakePkg('fake'), get_full_path('appletviewer'),
'/usr/bin/appletviewer')
-    assert not test.readelf_parser.parsing_failed_reason()
-    assert not test.ldd_parser.parsing_failed_reason
-    out = output.print_results(output.results)
-    assert 'W: unused-direct-shlib-dependency ' in out
+    with FakePkg('fake') as pkg:
+        pkgfile = pkg.add_file(get_full_path('appletviewer'),
'/usr/bin/appletviewer')
+        run_elf_checks(test, pkg, pkgfile)
+        assert not test.readelf_parser.parsing_failed_reason()
+        assert not test.ldd_parser.parsing_failed_reason
+        out = output.print_results(output.results)
+        assert 'W: unused-direct-shlib-dependency ' in out
 
 
 @pytest.mark.skipif(not IS_X86_64, reason='x86-64 only')
 def test_opt_dependency(binariescheck):
     output, test = binariescheck
-    run_elf_checks(test, FakePkg('fake'), get_full_path('opt-dependency'),
'/bin/opt-dependency')
-    assert not test.readelf_parser.parsing_failed_reason()
-    assert not test.ldd_parser.parsing_failed_reason
-    out = output.print_results(output.results)
-    assert 'E: linked-against-opt-library /bin/opt-dependency
/opt/libfoo.so' in out
+    with FakePkg('fake') as pkg:
+        pkgfile = pkg.add_file(get_full_path('opt-dependency'), '/bin/opt-
dependency')
+        run_elf_checks(test, pkg, pkgfile)
+        assert not test.readelf_parser.parsing_failed_reason()
+        assert not test.ldd_parser.parsing_failed_reason
+        out = output.print_results(output.results)
+        assert 'E: linked-against-opt-library /bin/opt-dependency
/opt/libfoo.so' in out
 
 
 @pytest.mark.skipif(not IS_X86_64, reason='x86-64 only')
 def test_usr_dependency(binariescheck):
     output, test = binariescheck
-    run_elf_checks(test, FakePkg('fake'), get_full_path('usr-dependency'),
'/bin/usr-dependency')
-    assert not test.readelf_parser.parsing_failed_reason()
-    assert not test.ldd_parser.parsing_failed_reason
-    out = output.print_results(output.results)
-    assert 'W: linked-against-usr-library /bin/usr-dependency
/usr/libfoo.so' in out
+    with FakePkg('fake') as pkg:
+        pkgfile = pkg.add_file(get_full_path('usr-dependency'), '/bin/usr-
dependency')
+        run_elf_checks(test, pkg, pkgfile)
+        assert not test.readelf_parser.parsing_failed_reason()
+        assert not test.ldd_parser.parsing_failed_reason
+        out = output.print_results(output.results)
+        assert 'W: linked-against-usr-library /bin/usr-dependency
/usr/libfoo.so' in out
diff -Nru rpmlint-2.2.0+ds1/test/test_lint.py rpmlint-
2.3.0+ds1/test/test_lint.py
--- rpmlint-2.2.0+ds1/test/test_lint.py 2021-12-12 09:54:14.000000000 -0500
+++ rpmlint-2.3.0+ds1/test/test_lint.py 2022-05-29 12:46:55.000000000 -0400
@@ -22,15 +22,16 @@
     'rpmlintrc': False,
     'installed': '',
     'time_report': False,
-    'profile': False
+    'profile': False,
+    'ignore_unused_rpmlintrc': False,
+    'checks': None
 }
 
 basic_tests = [
     'AlternativesCheck',
     'AppDataCheck',
     'BinariesCheck',
-    'BuildDateCheck',
-    'BuildRootCheck',
+    'BuildRootAndDateCheck',
     'ConfigFilesCheck',
     'DBusPolicyCheck',
     'DuplicatesCheck',
diff -Nru rpmlint-2.2.0+ds1/test/test_objdump_parser.py rpmlint-
2.3.0+ds1/test/test_objdump_parser.py
--- rpmlint-2.2.0+ds1/test/test_objdump_parser.py       2021-12-12
09:54:14.000000000 -0500
+++ rpmlint-2.3.0+ds1/test/test_objdump_parser.py       2022-05-29
12:46:55.000000000 -0400
@@ -28,9 +28,9 @@
     return ObjdumpParser(get_full_path(path), system_path)
 
 
-def run_elf_checks(test, pkg, fullpath, path):
-    test._detect_attributes(get_magic(fullpath))
-    test.run_elf_checks(pkg, fullpath, path)
+def run_elf_checks(test, pkg, pkgfile):
+    test._detect_attributes(get_magic(pkgfile.path))
+    test.run_elf_checks(pkg, pkgfile)
 
 
 def test_basic():
@@ -47,8 +47,11 @@
 @pytest.mark.skipif(not IS_X86_64, reason='x86-64 only')
 def test_executable_stack_package(binariescheck):
     output, test = binariescheck
-    run_elf_checks(test, FakePkg('fake'), get_full_path('executable-
stack'), 'a.out')
-    out = output.print_results(output.results)
 
-    assert 'W: missing-mandatory-optflags a.out -fno-PIE -g -Ofast' in out
-    assert 'E: forbidden-optflags a.out -frounding-math' in out
+    with FakePkg('fake') as pkg:
+        pkgfile = pkg.add_file(get_full_path('executable-stack'), 'a.out')
+        run_elf_checks(test, FakePkg('fake'), pkgfile)
+        out = output.print_results(output.results)
+
+        assert 'W: missing-mandatory-optflags a.out -fno-PIE -g -Ofast' in
out
+        assert 'E: forbidden-optflags a.out -frounding-math' in out
diff -Nru rpmlint-2.2.0+ds1/test/test_readelf_parser.py rpmlint-
2.3.0+ds1/test/test_readelf_parser.py
--- rpmlint-2.2.0+ds1/test/test_readelf_parser.py       2021-12-12
09:54:14.000000000 -0500
+++ rpmlint-2.3.0+ds1/test/test_readelf_parser.py       2022-05-29
12:46:55.000000000 -0400
@@ -5,6 +5,7 @@
 from rpmlint.checks.BinariesCheck import BinariesCheck
 from rpmlint.filter import Filter
 from rpmlint.pkg import FakePkg, get_magic
+from rpmlint.pkgfile import PkgFile
 from rpmlint.readelfparser import ReadelfParser
 
 from Testing import CONFIG, get_tested_path, HAS_32BIT_GLIBC, IS_I686,
IS_X86_64
@@ -28,9 +29,9 @@
     return ReadelfParser(get_full_path(path), system_path)
 
 
-def run_elf_checks(test, pkg, fullpath, path):
-    test._detect_attributes(get_magic(fullpath))
-    test.run_elf_checks(pkg, fullpath, path)
+def run_elf_checks(test, pkg, pkgfile):
+    test._detect_attributes(get_magic(pkgfile.path))
+    test.run_elf_checks(pkg, pkgfile)
 
 
 def test_empty_archive():
@@ -91,68 +92,86 @@
     readelf = readelfparser('rpath-lib.so', '/lib64/rpath-lib.so')
     assert readelf.is_shlib
     assert not readelf.is_archive
-    assert len(readelf.dynamic_section_info.runpath) == 1
-    assert '/tmp/termcap.so.4' in readelf.dynamic_section_info.runpath
+    assert len(readelf.dynamic_section_info.runpaths) == 1
+    assert '/tmp/termcap.so.4' in readelf.dynamic_section_info.runpaths
 
 
 def test_lto_bytecode(binariescheck):
     output, test = binariescheck
-    run_elf_checks(test, FakePkg('fake'), get_full_path('lto-object.o'),
'x.a')
-    assert not test.readelf_parser.parsing_failed_reason()
-    out = output.print_results(output.results)
-    assert 'lto-bytecode' in out
+    with FakePkg('fake') as pkg:
+        pkgfile = pkg.add_file(get_full_path('lto-object.o'), 'x.a')
+        run_elf_checks(test, pkg, pkgfile)
+        assert not test.readelf_parser.parsing_failed_reason()
+        out = output.print_results(output.results)
+        assert 'lto-bytecode' in out
 
 
 def test_lto_archive_text(binariescheck):
     output, test = binariescheck
-    run_elf_checks(test, FakePkg('fake'), get_full_path('stripped-lto.a'),
'x.a')
-    out = output.print_results(output.results)
-    assert 'E: lto-no-text-in-archive' in out
-    assert 'E: static-library-without-debuginfo' in out
+    with FakePkg('fake') as pkg:
+        pkgfile = pkg.add_file(get_full_path('stripped-lto.a'), 'x.a')
+        run_elf_checks(test, pkg, pkgfile)
+        out = output.print_results(output.results)
+        assert 'E: lto-no-text-in-archive' in out
+        assert 'E: static-library-without-debuginfo' in out
 
 
 def test_stripped_archive(binariescheck):
     output, test = binariescheck
-    run_elf_checks(test, FakePkg('fake'), get_full_path('stripped-
archive.a'), 'x.a')
-    out = output.print_results(output.results)
-    assert 'E: static-library-without-symtab' in out
+    with FakePkg('fake') as pkg:
+        pkgfile = pkg.add_file(get_full_path('stripped-archive.a'), 'x.a')
+        run_elf_checks(test, pkg, pkgfile)
+        out = output.print_results(output.results)
+        assert 'E: static-library-without-symtab' in out
 
 
 def test_lto_archive_text_function_sections(binariescheck):
     output, test = binariescheck
-    run_elf_checks(test, FakePkg('fake'), get_full_path('function-
sections.a'), 'x.a')
-    assert 'E: lto-no-text-in-archive' not in
output.print_results(output.results)
+    with FakePkg('fake') as pkg:
+        pkgfile = pkg.add_file(get_full_path('function-sections.a'), 'x.a')
+        run_elf_checks(test, pkg, pkgfile)
+        assert 'E: lto-no-text-in-archive' not in
output.print_results(output.results)
 
 
 def test_lto_archive_init_array(binariescheck):
     output, test = binariescheck
-    run_elf_checks(test, FakePkg('fake'), get_full_path('libbsd-ctor.a'),
'x.a')
-    assert 'E: lto-no-text-in-archive' not in
output.print_results(output.results)
+    with FakePkg('fake') as pkg:
+        pkgfile = pkg.add_file(get_full_path('libbsd-ctor.a'), 'x.a')
+        run_elf_checks(test, pkg, pkgfile)
+        assert 'E: lto-no-text-in-archive' not in
output.print_results(output.results)
 
 
 def test_lto_archive_preinit_array(binariescheck):
     output, test = binariescheck
-    run_elf_checks(test, FakePkg('fake'), get_full_path('libclang_rt.asan-
preinit-x86_64.a'), 'x.a')
-    assert 'E: lto-no-text-in-archive' not in
output.print_results(output.results)
+    with FakePkg('fake') as pkg:
+        pkgfile = pkg.add_file(get_full_path('libclang_rt.asan-preinit-
x86_64.a'), 'x.a')
+        run_elf_checks(test, pkg, pkgfile)
+        assert 'E: lto-no-text-in-archive' not in
output.print_results(output.results)
 
 
 def test_lto_archive_with_only_data(binariescheck):
     output, test = binariescheck
-    run_elf_checks(test, FakePkg('fake'), get_full_path('only-data.a'),
'x.a')
-    assert 'E: lto-no-text-in-archive' not in
output.print_results(output.results)
+    with FakePkg('fake') as pkg:
+        pkgfile = pkg.add_file(get_full_path('only-data.a'), 'x.a')
+        run_elf_checks(test, pkg, pkgfile)
+        assert 'E: lto-no-text-in-archive' not in
output.print_results(output.results)
 
 
 def test_archive_with_debuginfo(binariescheck):
     output, test = binariescheck
-    run_elf_checks(test, FakePkg('fake'), get_full_path('archive-with-
debuginfo.a'), 'x.a')
-    assert 'E: static-library-without-debuginfo' not in
output.print_results(output.results)
+    with FakePkg('fake') as pkg:
+        pkgfile = pkg.add_file(get_full_path('archive-with-debuginfo.a'),
'x.a')
+        run_elf_checks(test, pkg, pkgfile)
+        assert 'E: static-library-without-debuginfo' not in
output.print_results(output.results)
 
 
 @pytest.mark.skipif(not IS_X86_64, reason='x86-64 only')
 def test_executable_stack(binariescheck):
     output, test = binariescheck
-    run_elf_checks(test, FakePkg('fake'), get_full_path('executable-
stack'), 'a.out')
-    assert 'E: executable-stack' in output.results[0]
+    with FakePkg('fake') as pkg:
+        pkgfile = pkg.add_file(get_full_path('executable-stack'),
'/lib64/my/a.out')
+        run_elf_checks(test, pkg, pkgfile)
+        assert 'E: executable-stack /lib64/my/a.out' in output.results[0]
 
 
 def test_readelf_failure():
@@ -162,102 +181,129 @@
 
 def test_readelf_failure_in_package(binariescheck):
     output, test = binariescheck
-    run_elf_checks(test, FakePkg('fake'), get_full_path('not-existing.so'),
'/lib64/not-existing.so')
-    out = output.print_results(output.results)
-    assert 'readelf-failed /lib64/not-existing.so' in out
+    with FakePkg('fake') as pkg:
+        pkgfile = pkg.add_file(get_full_path('not-existing.so'),
'/lib64/not-existing.so')
+        run_elf_checks(test, pkg, pkgfile)
+        out = output.print_results(output.results)
+        assert 'readelf-failed /lib64/not-existing.so' in out
 
 
 def test_readelf_single_error_message(binariescheck):
     output, test = binariescheck
-    run_elf_checks(test, FakePkg('fake'), get_full_path('small_archive.a'),
'/lib64/small_archive.a')
-    out = output.print_results(output.results)
-    filtered = [line for line in out.splitlines() if 'Not an ELF file' in
line]
-    assert len(filtered) == 1
+    with FakePkg('fake') as pkg:
+        pkgfile = pkg.add_file(get_full_path('small_archive.a'),
'/lib64/small_archive.a')
+        run_elf_checks(test, pkg, pkgfile)
+        out = output.print_results(output.results)
+        filtered = [line for line in out.splitlines() if 'Not an ELF file'
in line]
+        assert len(filtered) == 1
 
 
 @pytest.mark.skipif(not IS_X86_64, reason='x86-64 only')
 def test_no_soname(binariescheck):
     output, test = binariescheck
-    run_elf_checks(test, FakePkg('fake'), get_full_path('no-soname.so'),
'/lib64/no-soname.so')
-    out = output.print_results(output.results)
-    assert 'no-soname /lib64/no-soname.so' in out
+    with FakePkg('fake') as pkg:
+        pkgfile = pkg.add_file(get_full_path('no-soname.so'), '/lib64/no-
soname.so')
+        run_elf_checks(test, pkg, pkgfile)
+        out = output.print_results(output.results)
+        assert 'no-soname /lib64/no-soname.so' in out
 
 
 @pytest.mark.skipif(not IS_X86_64, reason='x86-64 only')
 def test_invalid_soname(binariescheck):
     output, test = binariescheck
-    run_elf_checks(test, FakePkg('fake'), get_full_path('invalid-
soname.so'), '/lib64/invalid-soname.so')
-    out = output.print_results(output.results)
-    assert 'invalid-soname /lib64/invalid-soname.so' in out
-    assert 'E: shlib-with-non-pic-code /lib64/invalid-soname.so' not in out
+    with FakePkg('fake') as pkg:
+        pkgfile = pkg.add_file(get_full_path('invalid-soname.so'),
'/lib64/invalid-soname.so')
+        run_elf_checks(test, pkg, pkgfile)
+        out = output.print_results(output.results)
+        assert 'invalid-soname /lib64/invalid-soname.so' in out
+        assert 'E: shlib-with-non-pic-code /lib64/invalid-soname.so' not in
out
 
 
 @pytest.mark.skipif(not IS_I686 and (not IS_X86_64 or not HAS_32BIT_GLIBC),
reason='i686 glibc only')
 def test_non_pic_code_library(binariescheck):
     output, test = binariescheck
-    run_elf_checks(test, FakePkg('fake'), get_full_path('non-pic-shared-
m32.so'), '/usr/lib/non-pic-shared-m32.so')
-    out = output.print_results(output.results)
-    assert 'E: shlib-with-non-pic-code' in out
+    with FakePkg('fake') as pkg:
+        pkgfile = pkg.add_file(get_full_path('non-pic-shared-m32.so'),
'/usr/lib/non-pic-shared-m32.so')
+        run_elf_checks(test, pkg, pkgfile)
+        out = output.print_results(output.results)
+        assert 'E: shlib-with-non-pic-code' in out
 
 
 @pytest.mark.skipif(not IS_X86_64, reason='x86-64 only')
 def test_no_ldconfig_symlink(binariescheck):
     output, test = binariescheck
 
-    run_elf_checks(test, FakePkg('libfake'), get_full_path('libutil-
2.29.so'), '/lib64/libutil-2.29.so')
-    out = output.print_results(output.results)
-    assert 'no-ldconfig-symlink /lib64/libutil-2.29.so' in out
-    assert 'E: shlib-policy-name-error SONAME: libutil.so.1, expected
package suffix: 1' in out
+    with FakePkg('libfake') as pkg:
+        pkgfile = pkg.add_file(get_full_path('libutil-2.29.so'),
'/lib64/libutil-2.29.so')
+        run_elf_checks(test, pkg, pkgfile)
+        out = output.print_results(output.results)
+        assert 'no-ldconfig-symlink /lib64/libutil-2.29.so' in out
+        assert 'E: shlib-policy-name-error SONAME: libutil.so.1, expected
package suffix: 1' in out
 
 
 @pytest.mark.skipif(not IS_X86_64, reason='x86-64 only')
 def test_call_mktemp(binariescheck):
     output, test = binariescheck
 
-    run_elf_checks(test, FakePkg('fake'), get_full_path('call-mktemp'),
'/bin/call-mktemp')
-    out = output.print_results(output.results)
-    assert 'E: call-to-mktemp /bin/call-mktemp' in out
+    with FakePkg('fake') as pkg:
+        pkgfile = pkg.add_file(get_full_path('call-mktemp'), '/bin/call-
mktemp')
+        run_elf_checks(test, pkg, pkgfile)
+        out = output.print_results(output.results)
+        assert 'E: call-to-mktemp /bin/call-mktemp' in out
 
 
 @pytest.mark.skipif(not IS_X86_64, reason='x86-64 only')
 def test_call_setgroups(binariescheck):
     output, test = binariescheck
 
-    run_elf_checks(test, FakePkg('fake'), get_full_path('call-setgroups'),
'/bin/call-setgroups')
-    out = output.print_results(output.results)
-    assert 'E: missing-call-to-setgroups-before-setuid /bin/call-setgroups'
in out
+    with FakePkg('fake') as pkg:
+        pkgfile = PkgFile('/bin/call-setgroups')
+        pkgfile.path = get_full_path('call-setgroups')
+        pkg.files[pkgfile.name] = pkgfile
+        run_elf_checks(test, pkg, pkgfile)
+        out = output.print_results(output.results)
+        assert 'E: missing-call-to-setgroups-before-setuid /bin/call-
setgroups' in out
 
 
 @pytest.mark.skipif(not IS_X86_64, reason='x86-64 only')
 def test_call_gethostbyname(binariescheck):
     output, test = binariescheck
 
-    run_elf_checks(test, FakePkg('fake'), get_full_path('hostname'),
'/usr/bin/hostname')
-    out = output.print_results(output.results)
-    assert 'W: binary-or-shlib-calls-gethostbyname' in out
+    with FakePkg('fake') as pkg:
+        pkgfile = pkg.add_file(get_full_path('hostname'),
'/usr/bin/hostname')
+        run_elf_checks(test, pkg, pkgfile)
+        out = output.print_results(output.results)
+        assert 'W: binary-or-shlib-calls-gethostbyname' in out
 
 
 @pytest.mark.skipif(not IS_X86_64, reason='x86-64 only')
 def test_missing_dependency(binariescheck):
     output, test = binariescheck
 
-    run_elf_checks(test, FakePkg('fake'), get_full_path('no-
dependency.so'), '/lib64/no-dependency.so')
-    out = output.print_results(output.results)
-    assert 'E: shared-library-without-dependency-information' in out
+    with FakePkg('fake') as pkg:
+        pkgfile = pkg.add_file(get_full_path('no-dependency.so'),
'/lib64/no-dependency.so')
+        run_elf_checks(test, pkg, pkgfile)
+        out = output.print_results(output.results)
+        assert 'E: shared-library-without-dependency-information' in out
 
 
 def test_bca_files(binariescheck):
     output, test = binariescheck
 
-    run_elf_checks(test, FakePkg('fake'),
get_full_path('libkleeRuntimeFreeStanding.bca'),
'/usr/lib64/klee/runtime/libkleeRuntimeFreeStanding.bca')
-    out = output.print_results(output.results)
-    assert 'E: ' not in out
+    with FakePkg('fake') as pkg:
+        pkgfile =
pkg.add_file(get_full_path('libkleeRuntimeFreeStanding.bca'),
'/usr/lib64/klee/runtime/libkleeRuntimeFreeStanding.bca')
+        run_elf_checks(test, pkg, pkgfile)
+        out = output.print_results(output.results)
+        assert 'E: ' not in out
 
 
 @pytest.mark.skipif(not IS_X86_64, reason='x86-64 only')
 def test_shlib_policy_name_error(binariescheck):
     output, test = binariescheck
 
-    run_elf_checks(test, FakePkg('libgame'), get_full_path('libgame.so'),
'/lib64/libgame.so')
-    out = output.print_results(output.results)
-    assert 'libgame: E: shlib-policy-name-error SONAME: libgame2-
1.9.so.10.0.0, expected package suffix: 1_9-10_0_0' in out
+    with FakePkg('libgame') as pkg:
+        pkgfile = pkg.add_file(get_full_path('libgame.so'),
'/lib64/libgame.so')
+        run_elf_checks(test, pkg, pkgfile)
+        out = output.print_results(output.results)
+        print(out)
+        assert 'libgame: E: shlib-policy-name-error SONAME: libgame2-
1.9.so.10.0.0, expected package suffix: 1_9-10_0_0' in out
diff -Nru rpmlint-2.2.0+ds1/test/test_spellchecking.py rpmlint-
2.3.0+ds1/test/test_spellchecking.py
--- rpmlint-2.2.0+ds1/test/test_spellchecking.py        2021-12-12
09:54:14.000000000 -0500
+++ rpmlint-2.3.0+ds1/test/test_spellchecking.py        2022-05-29
12:46:55.000000000 -0400
@@ -4,6 +4,11 @@
 from Testing import HAS_CZECH_DICTIONARY, HAS_ENGLISH_DICTIONARY
 
 
+def get_suggestions(suggestion):
+    suggestion = suggestion.split(' -> ')[-1]
+    return sorted(suggestion.split(', '))
+
+
 @pytest.mark.skipif(not rpmlint.spellcheck.ENCHANT, reason='Missing enchant
bindings')
 @pytest.mark.skipif(not HAS_ENGLISH_DICTIONARY, reason='Missing English
dictionary')
 def test_spelldict(capsys):
@@ -45,13 +50,15 @@
     text = "I don't think tihs tetx is correct English"
     result = spell.spell_check(text, 'Description({}):')
     assert len(result) == 2
-    assert result['tihs'] == 'Description(en_US): tihs -> this, hits, ties'
+    assert result['tihs'].startswith('Description(en_US): tihs -> ')
+    assert get_suggestions(result['tihs']) == ['hits', 'this', 'ties']
 
     # different language, one typo
     text = 'Příčerně žluťoučký kůň'
     result = spell.spell_check(text, 'Summary({}):', 'cs_CZ')
     assert len(result) == 1
-    assert result['Příčerně'] == 'Summary(cs_CZ): Příčerně -> Příčetně,
Příčeně, Příšerně'
+    assert result['Příčerně'].startswith('Summary(cs_CZ): Příčerně -> ')
+    assert get_suggestions(result['Příčerně']) == ['Příčeně', 'Příčetně',
'Příšerně']
 
     # non-existing language, should return nothing:
     text = 'Weird english text'
diff -Nru rpmlint-2.2.0+ds1/test/test_tags.py rpmlint-
2.3.0+ds1/test/test_tags.py
--- rpmlint-2.2.0+ds1/test/test_tags.py 2021-12-12 09:54:14.000000000 -0500
+++ rpmlint-2.3.0+ds1/test/test_tags.py 2022-05-29 12:46:55.000000000 -0400
@@ -141,9 +141,10 @@
     test.check(get_tested_package(package, tmpdir))
     out = output.print_results(output.results)
     # Test if package has a summary longer than 80 characters
-    assert 'E: summary-too-long   lorem Ipsum is simply dummy text of the
printing and typesetting industry' in out
+    assert 'E: summary-too-long' in out
     # Test if package has leading space at the beginning of the summary
-    assert 'E: summary-has-leading-spaces   lorem Ipsum is simply dummy
text of the printing and typesetting industry' in out
+    # where non-breaking space is used (U+00A0).
+    assert b'E: summary-has-leading-spaces \xc2\xa0\xc2\xa0lorem'.decode()
in out
     # Test if package has a shorter description than Summary
     assert 'W: description-shorter-than-summary' in out
     # Test if a package has a Version: tag
diff -Nru rpmlint-2.2.0+ds1/tools/generate-fedora-users-groups.py rpmlint-
2.3.0+ds1/tools/generate-fedora-users-groups.py
--- rpmlint-2.2.0+ds1/tools/generate-fedora-users-groups.py     2021-12-12
09:54:14.000000000 -0500
+++ rpmlint-2.3.0+ds1/tools/generate-fedora-users-groups.py     2022-05-29
12:46:55.000000000 -0400
@@ -1,5 +1,5 @@
 #!/usr/bin/python3
-""" This sciptt is used to generate values for
+""" This script is used to generate values for
     config/Fedora/configs/Fedora/users-groups.toml
 """
 import os

Attachment: signature.asc
Description: This is a digitally signed message part

Reply via email to