[applied] fedabipkgdiff: Fix getting the latest RPM version of a given Fedora distro

Message ID 874iwoq6ki.fsf@redhat.com
State New
Headers
Series [applied] fedabipkgdiff: Fix getting the latest RPM version of a given Fedora distro |

Commit Message

Dodji Seketeli June 10, 2025, 9:39 a.m. UTC
  Hello,

When doing:
    $ fedabipkgdiff --debug --self-compare -a --from fc40 hdf-libs

then fedabipkgdiff considers self-comparing the
hdf-libs-4.2.16.2-1.fc40app2 package instead of self-comparing
hdf-libs-4.2.16.2-1.fc40.  Note the "fc40app2" distro sub-string of
the release string, instead of "fc40".

This is because the Brew.get_package_latest_build method looks for a
N-V-R which release string /contains/ the distro sub-string.  So the
hdf-libs-4.2.16.2-1.fc40app2 N-V-R matches the search and the sorting
makes it come after the hdf-libs-4.2.16.2-1.fc40 N-V-R.

This patch makes Brew.get_package_latest_build use
get_distro_from_string and makes sure the latter is being tight/strict
enough when getting the distro sub-string from the release string.

	* tools/fedabipkgdiff (get_distro_from_string): Make this properly
	get the distro sub-string from the release string, even for
	release strings like "1.eln123" and '1.2.fc40app2'.  The distro
	sub-strings returned for these two examples are 'eln123' and None.
	None is returned in the later case because it doesn't follow the
	"proper" Fedora scheme for distro sub-strings of the Release
	string.

Signed-off-by: Dodji Seketeli <dodji@redhat.com>
Applied to the mainline.
---
 tools/fedabipkgdiff | 69 +++++++++++++++++++++++----------------------
 1 file changed, 36 insertions(+), 33 deletions(-)
  

Patch

diff --git a/tools/fedabipkgdiff b/tools/fedabipkgdiff
index 932d8542..fedb1925 100755
--- a/tools/fedabipkgdiff
+++ b/tools/fedabipkgdiff
@@ -180,20 +180,52 @@  def is_distro_valid(distro):
     """
     return re.match(r'^(fc|el)\d{1,2}$', distro) is not None
 
+def log_call(func):
+    """A decorator that logs a method invocation
+
+    Method's name and all arguments, either positional or keyword arguments,
+    will be logged by logger.debug. Also, return value from the decorated
+    method will be logged just after the invocation is done.
+
+    This decorator does not catch any exception thrown from the decorated
+    method. If there is any exception thrown from decorated method, you can
+    catch them in the caller and obviously, no return value is logged.
+
+    :param callable func: a callable object to decorate
+    """
+    def proxy(*args, **kwargs):
+        logger.debug('Call %s, args: %s, kwargs: %s',
+                     func.__name__,
+                     args if args else '',
+                     kwargs if kwargs else '')
+        start = timer()
+        result = func(*args, **kwargs)
+        end = timer();
+        elapsed_type = timedelta(seconds=end-start)
+        logger.debug('Result from %s: %s, in: %s',
+                     func.__name__, result, elapsed_type)
+        return result
+    return proxy
 
 def get_distro_from_string(str):
-    """Get the part of a string that designates the Fedora distro version number
+    """Get the part of a string that designates the Fedora or
+       Enterprise Linux distro version number from a release string.
 
     For instance, when passed the string '2.3.fc12', this function
-    returns the string 'fc12'.
+    returns the string 'fc12'.  It also works for e.g, '1.eln123',
+    returning eln123.
+
+    Please note that if the release string is not for a package that
+    ought to be in Fedora or EL proper, this function returns None.
 
     :param str the string to consider
     :return: The sub-string of the parameter that represents the
     Fedora distro version number, or None if the parameter does not
     contain such a sub-string.
+
     """
 
-    m = re.match(r'(.*)((fc|el)\d{1,2})(.*)', str)
+    m = re.match(r'(.*)((fc|el|eln)\d{1,3})$', str)
     if not m:
         return None
 
@@ -245,35 +277,6 @@  def cmp_nvr(left, right):
         (left_nvr['epoch'], left_nvr['version'], left_nvr['release']),
         (right_nvr['epoch'], right_nvr['version'], right_nvr['release']))
 
-
-def log_call(func):
-    """A decorator that logs a method invocation
-
-    Method's name and all arguments, either positional or keyword arguments,
-    will be logged by logger.debug. Also, return value from the decorated
-    method will be logged just after the invocation is done.
-
-    This decorator does not catch any exception thrown from the decorated
-    method. If there is any exception thrown from decorated method, you can
-    catch them in the caller and obviously, no return value is logged.
-
-    :param callable func: a callable object to decorate
-    """
-    def proxy(*args, **kwargs):
-        logger.debug('Call %s, args: %s, kwargs: %s',
-                     func.__name__,
-                     args if args else '',
-                     kwargs if kwargs else '')
-        start = timer()
-        result = func(*args, **kwargs)
-        end = timer();
-        elapsed_type = timedelta(seconds=end-start)
-        logger.debug('Result from %s: %s, in: %s',
-                     func.__name__, result, elapsed_type)
-        return result
-    return proxy
-
-
 def delete_download_cache():
     """Delete download cache directory"""
     download_dir = get_download_dir()
@@ -887,7 +890,7 @@  class Brew(object):
         :raises NoCompleteBuilds: if there is no latest build of a package.
         """
         package = self.getPackage(package_name)
-        selector = lambda item: item['release'].find(distro) > -1
+        selector = lambda item: get_distro_from_string(item['release']) == distro
 
         builds = self.listBuilds(packageID=package['id'],
                                  selector=selector,