Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package zypper-changelog-plugin for 
openSUSE:Factory checked in at 2024-05-27 11:54:22
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/zypper-changelog-plugin (Old)
 and      /work/SRC/openSUSE:Factory/.zypper-changelog-plugin.new.24587 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "zypper-changelog-plugin"

Mon May 27 11:54:22 2024 rev:6 rq:1176775 version:0.4

Changes:
--------
--- 
/work/SRC/openSUSE:Factory/zypper-changelog-plugin/zypper-changelog-plugin.changes
  2022-12-08 16:52:09.559782276 +0100
+++ 
/work/SRC/openSUSE:Factory/.zypper-changelog-plugin.new.24587/zypper-changelog-plugin.changes
       2024-05-27 12:02:29.316512509 +0200
@@ -1,0 +2,8 @@
+Fri May 24 12:26:41 UTC 2024 - Zoltan Balogh <zbal...@suse.com>
+
+- Fixing bsc#1223985 - zypper-changelog-plugin exhausts all memory 
+- Fixing bsc#1217299 - zypp:plugins/zypper-changelog-plugin: Bug repodata is 
now using zstd compression
+- Optimized memory usage, more error handling, better structure and 
+  improved comments 
+
+-------------------------------------------------------------------

Old:
----
  zypper-changelog-plugin-0.3.tar.gz

New:
----
  zypper-changelog-plugin-0.4.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ zypper-changelog-plugin.spec ++++++
--- /var/tmp/diff_new_pack.bmsHR6/_old  2024-05-27 12:02:29.772529250 +0200
+++ /var/tmp/diff_new_pack.bmsHR6/_new  2024-05-27 12:02:29.772529250 +0200
@@ -1,7 +1,7 @@
 #
 # spec file for package zypper-changelog-plugin
 #
-# Copyright (c) 2022 SUSE LLC
+# Copyright (c) 2024 SUSE LLC
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -17,13 +17,13 @@
 
 
 Name:           zypper-changelog-plugin
-Version:        0.3
+Version:        0.4
 Release:        0
 Summary:        Changelog listing tool
 License:        GPL-2.0-only
 Group:          System/Packages
 URL:            https://github.com/bzoltan1/zypper-changelog-plugin.git
-Source:         zypper-changelog-plugin-0.3.tar.gz
+Source:         zypper-changelog-plugin-0.4.tar.gz
 Requires:       /usr/bin/python3
 Requires:       python3-requests
 BuildArch:      noarch

++++++ zypper-changelog-plugin-0.3.tar.gz -> zypper-changelog-plugin-0.4.tar.gz 
++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/zypper-changelog-plugin-0.3/zypper-changelog 
new/zypper-changelog-plugin-0.4/zypper-changelog
--- old/zypper-changelog-plugin-0.3/zypper-changelog    2021-01-17 
17:12:02.848290488 +0100
+++ new/zypper-changelog-plugin-0.4/zypper-changelog    2024-05-24 
19:46:00.014751434 +0200
@@ -1,4 +1,4 @@
-#!/usr/bin/env python3
+#!/usr/bin/python3
 # -*- coding: utf-8 -*-
 # Copyright © 2018 SUSE LLC
 #
@@ -31,100 +31,147 @@
 import xml.etree.ElementTree as ET
 import tempfile
 import difflib
+from time import sleep
 
 
 def log_text(text):
-    print(text)
+    """Print debug information if debug mode is enabled."""
+    if args.debug:
+        print(text)
 
 
 def parse_args():
-    p = ArgumentParser(prog='zypper-changelog',
-                       description='Shows the changelog' +
-                       'of one ore more packages.',
-                       formatter_class=argparse.RawDescriptionHelpFormatter)
-    p.add_argument('-d', '--debug',
-                   default=False, action='store_true', dest='debug',
-                   help='debug mode')
-    p.add_argument('-c', '--commits',
-                   default=False, action='store_true', dest='commits',
-                   help='Lists only the headline of the change commits')
-    p.add_argument('-e', '--expression',
-                   default=False, action='store_true', dest='expression',
-                   help='Enable regular expression in package name')
-    p.add_argument("-p", "--packages", dest="packages", default='',
-                   help="Package name \
-                              or regular expression to match packages.")
-    p.add_argument("-r", "--repositories",
-                   dest="repos", default="oss",
-                   help="Comma separated list of repositores \
-                              to search for changelogs.")
-    p.add_argument("-a", "--all",
-                   dest="all", default=False,
-                   action='store_true',
-                   help="Lists changelogs for all packages")
-    p.add_argument("-u", "--update",
-                   dest="update", default=False,
-                   action='store_true',
-                   help="Lists changelogs for all packages to be updated")
+    """Parse command line arguments."""
+    p = ArgumentParser(
+        prog='zypper changelog',
+        description='Shows the changelog of one or more packages.',
+        formatter_class=argparse.RawDescriptionHelpFormatter
+    )
+    p.add_argument(
+        '-d', '--debug',
+        default=False, action='store_true', dest='debug',
+        help='Enable debug mode for detailed output'
+    )
+    p.add_argument(
+        '-c', '--commits',
+        default=False, action='store_true', dest='commits',
+        help='List only the headline of the change commits'
+    )
+    p.add_argument(
+        '-e', '--expression',
+        default=False, action='store_true', dest='expression',
+        help='Enable regular expression in package name'
+    )
+    p.add_argument(
+        "-p", "--packages", dest="packages", default='',
+        help="Package name or regular expression to match packages."
+    )
+    p.add_argument(
+        "-r", "--repositories",
+        dest="repos", default="ALL",
+        help="Comma separated list of repositories to search for changelogs."
+    )
+    p.add_argument(
+        "-a", "--all",
+        dest="all", default=False,
+        action='store_true',
+        help="List changelogs for all packages"
+    )
+    p.add_argument(
+        "-u", "--update",
+        dest="update", default=True,
+        action='store_true',
+        help="List changelogs for all packages to be updated"
+    )
+    p.add_argument(
+        "--arch", dest="arch", default="all",
+        help=(
+            "Comma separated list of architectures to include "
+            "(default is all)."
+        )
+    )
     if len(sys.argv[1:]) == 0:
         p.print_help()
         p.exit()
     return p
 
 
-def readRpmHeader(ts, filename):
-    # Read an rpm header
+def read_rpm_header(ts, filename):
+    """Read the RPM header from a file."""
     fd = os.open(filename, os.O_RDONLY)
     h = None
     try:
         h = ts.hdrFromFdno(fd)
     except rpm.error as e:
-        print(e)
-        h = None
-    os.close(fd)
+        log_text(f"Error reading RPM header: {e}")
+    finally:
+        os.close(fd)
     return h
 
 
 def get_updates():
-    update_list, repo_list = (set([]), set([]))
+    """Fetch the list of updates from zypper."""
+    update_list, repo_list = set(), set()
     arch = ''
-    zypp_process = subprocess.Popen(["zypper",
-                                     "-x",
-                                     "list-updates"],
-                                    stdout=subprocess.PIPE,
-                                    stderr=subprocess.PIPE)
-    stdout_value, stderr_value = zypp_process.communicate()
-    updates_tree = ET.ElementTree(ET.fromstring(stdout_value))
-    updates_root = updates_tree.getroot()
-    for update in updates_root.iter('update'):
-        update_list.add(update.get('name'))
-        repo_list.add(update.find('source').get('alias'))
-        if update.get('arch') not in ('src', 'noarch'):
-            arch = update.get('arch')
+    try:
+        zypp_process = subprocess.Popen(
+            ["zypper", "-x", "--non-interactive", "list-updates"],
+            stdout=subprocess.PIPE, stderr=subprocess.PIPE
+        )
+        stdout_value, stderr_value = zypp_process.communicate()
+        updates_tree = ET.ElementTree(ET.fromstring(stdout_value))
+        updates_root = updates_tree.getroot()
+        for update in updates_root.iter('update'):
+            update_list.add(update.get('name'))
+            repo_list.add(update.find('source').get('alias'))
+            if update.get('arch') not in ('src', 'noarch'):
+                arch = update.get('arch')
+    except Exception as e:
+        log_text(f"Error fetching updates: {e}")
     return update_list, repo_list, arch
 
 
 def local_changelog(package):
-    zypp_process = subprocess.Popen(["rpm",
-                                     "-q",
-                                     "%s" % package],
-                                    stdout=subprocess.PIPE,
-                                    stderr=subprocess.PIPE)
-    stdout_value, stderr_value = zypp_process.communicate()
-    newest = stdout_value.decode("utf-8").strip().split('\n')[-1]
-    search_result = re.search("^%s-(.*)-.*" % re.escape(package), newest)
-    if search_result:
-        # Multiple version of the same package may be installed
-        # and we want to see the changelog of the latest.
-        last_version = search_result.group(1)
-    zypp_process = subprocess.Popen(["rpm",
-                                     "-q",
-                                     "--changelog",
-                                     "%s-%s" % (package, last_version)],
-                                    stdout=subprocess.PIPE,
-                                    stderr=subprocess.PIPE)
-    stdout_value, stderr_value = zypp_process.communicate()
-    return stdout_value.decode("utf-8")
+    """Retrieve the changelog for a locally installed package."""
+    try:
+        zypp_process = subprocess.Popen(
+            ["rpm", "-q", package],
+            stdout=subprocess.PIPE, stderr=subprocess.PIPE
+        )
+        stdout_value, stderr_value = zypp_process.communicate()
+        newest = stdout_value.decode("utf-8").strip().split('\n')[-1]
+        search_result = re.search(f"^{re.escape(package)}-(.*)-.*", newest)
+        if search_result:
+            last_version = search_result.group(1)
+            zypp_process = subprocess.Popen(
+                ["rpm", "-q", "--changelog", f"{package}-{last_version}"],
+                stdout=subprocess.PIPE, stderr=subprocess.PIPE
+            )
+            stdout_value, stderr_value = zypp_process.communicate()
+            return stdout_value.decode("utf-8")
+    except Exception as e:
+        log_text(f"Error fetching local changelog: {e}")
+    return ""
+
+
+def fetch_rpm_header(url, end, retries=3, backoff_factor=1):
+    """Fetch the RPM header from a remote repository."""
+    for attempt in range(retries):
+        try:
+            response = requests.get(
+                url, headers={'Range': f'bytes=0-{end}'}, timeout=5
+            )
+            response.raise_for_status()
+            return response.content
+        except requests.exceptions.RequestException as e:
+            log_text(f"Error fetching RPM header (attempt {attempt + 1}): {e}")
+            sleep(backoff_factor * (2 ** attempt))
+    return None
+
+
+def decode_if_bytes(value):
+    """Decode a value if it is in bytes."""
+    return value.decode("utf-8") if isinstance(value, bytes) else value
 
 
 parser = parse_args()
@@ -139,113 +186,127 @@
 if args.packages:
     package_list = args.packages.split(",")
 
-list_of_xml_files = []
+arch_list = args.arch.split(",")
 
+list_of_xml_files = []
 # Find the cache file of the repositories
 for root, dirs, files in os.walk("/var/cache/zypp/raw/"):
     for file in files:
-        if file.endswith("primary.xml.gz"):
-            for repository in repository_list:
-                if repository in root:
-                    list_of_xml_files.append(os.path.join(root, file))
-
-ts = rpm.TransactionSet("", (rpm._RPMVSF_NOSIGNATURES or
-                        rpm.RPMVSF_NOHDRCHK or
-                        rpm._RPMVSF_NODIGESTS or
-                        rpm.RPMVSF_NEEDPAYLOAD))
+        if file.endswith("primary.xml.zst") or file.endswith("primary.xml.gz"):
+            if args.repos == "ALL":
+                list_of_xml_files.append(os.path.join(root, file))
+            else:
+                for repository in repository_list:
+                    log_text(f"Enabled repository: {repository}")
+                    if repository in root:
+                        list_of_xml_files.append(os.path.join(root, file))
+
+# Initialize the RPM transaction set
+ts = rpm.TransactionSet("", (
+    rpm._RPMVSF_NOSIGNATURES or rpm.RPMVSF_NOHDRCHK or
+    rpm._RPMVSF_NODIGESTS or rpm.RPMVSF_NEEDPAYLOAD
+))
 
-# Get the available respostories from the xml outout of zypper
+# Get the available repositories from the XML output of zypper
 # and find the URLs of the repositories
-zypp_process = subprocess.Popen(["zypper",
-                                 "-x",
-                                 "lr"],
-                                stdout=subprocess.PIPE,
-                                stderr=subprocess.PIPE)
+zypp_process = subprocess.Popen(
+    ["zypper", "-x", "lr"],
+    stdout=subprocess.PIPE, stderr=subprocess.PIPE
+)
 stdout_value, stderr_value = zypp_process.communicate()
 repo_tree = ET.ElementTree(ET.fromstring(stdout_value))
 repo_root = repo_tree.getroot()
+
 for files in list_of_xml_files:
+    print(files)
     for repo in repo_root.iter('repo'):
         if repo.get('alias') in files:
             mirror_url = repo.find('url').text
+            log_text(f"Mirror URL: {mirror_url}")
+
+    try:
+        zstdcat_process = subprocess.Popen(
+            ["zstdcat", files],
+            stdout=subprocess.PIPE, stderr=subprocess.PIPE
+        )
+        stdout_value, stderr_value = zstdcat_process.communicate()
+
+    except Exception as e:
+        log_text(f"Error decompressing XML file: {e}")
+        continue
 
-    zcat_process = subprocess.Popen(["zcat",
-                                     "%s" % files],
-                                    stdout=subprocess.PIPE,
-                                    stderr=subprocess.PIPE)
-    stdout_value, stderr_value = zcat_process.communicate()
+    try:
+        tree = ET.ElementTree(ET.fromstring(stdout_value))
+    except ET.ParseError as e:
+        log_text(f"Error parsing XML file: {e}")
+        continue
 
-    tree = ET.ElementTree(ET.fromstring(stdout_value))
     root = tree.getroot()
     xml_ns = root.tag.split('}')[0].strip('{')
 
-    # Loop thru the packages listed in the repository cache files
+
+
+    # Loop through the packages listed in the repository cache files
     for package in root.findall('doc:package', namespaces={'doc': xml_ns}):
+#        print(package[0].text)
+
         if not args.all:
-            # skip foreign arch and source packages
-            if args.update and package[1].text not in ('%s' % arch, 'noarch'):
+            # Skip foreign arch and source packages
+            if args.update and package[1].text not in (arch, 'noarch'):
                 continue
             if args.expression:
-                match = False
-                for package_item in package_list:
-                    pattern = re.compile(package_item)
-                    if pattern.match("%s" % package[0].text):
-                        match = True
-                if not match:
+                if not any(
+                    re.compile(p).match(package[0].text) for p in package_list
+                ):
                     continue
             else:
                 if package[0].text not in package_list:
                     continue
-        # Find the segment/offset of the header part of the rpm package
-        for field in package[11].findall('rpm:header-range',
-                                         namespaces={'rpm':
-                                                     'http://linux.duke.edu' +
-                                                     '/metadata/rpm'}):
+        for field in package[11].findall(
+            'rpm:header-range',
+            namespaces={'rpm': 'http://linux.duke.edu/metadata/rpm'}
+        ):
             start = field.get('start')
             end = field.get('end')
-            url = '%s/%s' % (mirror_url, package[10].get('href'))
-            log_text(url)
-            try:
-                # Fetch the rpm header as it contains the changelogs
-                rpm_header = requests.get(url,
-                                          headers={'Range':
-                                                   'bytes=0-%s' % (end)})
-                rpm_header.raise_for_status()
-            except requests.exceptions.HTTPError as e:
-                log_text(e)
+            url = f'{mirror_url}/{package[10].get("href")}'
+            log_text(f"URL to fetch the rpm header from: {url}")
+
+            rpm_header_content = fetch_rpm_header(url, end)
+            if rpm_header_content is None:
                 continue
-            # Dump the header to a temporary file as the ts.hdrFromFdno
-            # needs a real file to process
-            header_file, header_filename = tempfile.mkstemp()
+
+            with tempfile.NamedTemporaryFile(delete=False) as f:
+                f.write(rpm_header_content)
+                f.flush()
+                header_filename = f.name
             try:
-                with os.fdopen(header_file, 'w+b') as f:
-                    f.write(rpm_header.content)
-                    f.flush()
-                f.close()
-                h = readRpmHeader(ts, '%s' % header_filename)
+                h = read_rpm_header(ts, header_filename)
             finally:
                 os.remove(header_filename)
             if h is None:
                 continue
-            # Parse the changelog, time and contributor's name
             changelog_name = h[rpm.RPMTAG_CHANGELOGNAME]
             changelog_time = h[rpm.RPMTAG_CHANGELOGTIME]
             changelog_text = h[rpm.RPMTAG_CHANGELOGTEXT]
             changelog = ''
-            for (name, time, text) in zip(changelog_name,
-                                          changelog_time,
-                                          changelog_text):
-                dt = datetime.datetime.fromtimestamp(time).strftime("%a %b " +
-                                                                    "%d %Y")
+            for name, time, text in zip(
+                changelog_name, changelog_time, changelog_text
+            ):
+                name = decode_if_bytes(name)
+                text = decode_if_bytes(text)
+                dt = datetime.datetime.fromtimestamp(time).strftime(
+                    "%a %b %d %Y"
+                )
                 if args.commits:
-                    changelog += "* %s %s\n" % (dt, name)
+                    changelog += f"* {dt} {name}\n"
                 else:
-                    changelog += "* %s %s\n%s\n\n" % (dt, name, text)
+                    changelog += f"* {dt} {name}\n{text}\n\n"
             if args.update:
                 local = str(local_changelog(package[0].text))
                 diff = difflib.ndiff(local.split('\n'), changelog.split('\n'))
-                for l in diff:
-                    if l.startswith('+ '):
-                        print(l.replace('+ ', ''))
+                for line in diff:
+                    if line.startswith('+ '):
+                        print(line.replace('+ ', ''))
             else:
                 print(changelog)
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/zypper-changelog-plugin-0.3/zypper-changelog-plugin.changes 
new/zypper-changelog-plugin-0.4/zypper-changelog-plugin.changes
--- old/zypper-changelog-plugin-0.3/zypper-changelog-plugin.changes     
2022-12-08 07:20:56.746357798 +0100
+++ new/zypper-changelog-plugin-0.4/zypper-changelog-plugin.changes     
2024-05-24 15:40:43.714097916 +0200
@@ -1,7 +1,15 @@
 -------------------------------------------------------------------
+Fri May 24 12:26:41 UTC 2024 - Zoltan Balogh <zbal...@suse.com>
+
+- Fixing bsc#1223985 - zypper-changelog-plugin exhausts all memory 
+- Fixing bsc#1217299 - zypp:plugins/zypper-changelog-plugin: Bug repodata is 
now using zstd compression
+- Optimized memory usage, more error handling, better structure and 
+  improved comments 
+
+-------------------------------------------------------------------
 Thu Dec  8 06:20:17 UTC 2022 - Zoltan Balogh <zbal...@suse.com>
 
-- Fixing #1206081 -  The zypper changelog plugin fails for packages not 
installed
+- Fixing bsc#1206081 -  The zypper changelog plugin fails for packages not 
installed
 
 -------------------------------------------------------------------
 Wed Nov 16 06:35:11 UTC 2022 - Zoltan Balogh <zbal...@suse.com>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/zypper-changelog-plugin-0.3/zypper-changelog-plugin.spec 
new/zypper-changelog-plugin-0.4/zypper-changelog-plugin.spec
--- old/zypper-changelog-plugin-0.3/zypper-changelog-plugin.spec        
1970-01-01 01:00:00.000000000 +0100
+++ new/zypper-changelog-plugin-0.4/zypper-changelog-plugin.spec        
2024-05-24 14:31:00.614706491 +0200
@@ -0,0 +1,51 @@
+#
+# spec file for package zypper-changelog-plugin
+#
+# Copyright (c) 2022 SUSE LLC
+#
+# All modifications and additions to the file contributed by third parties
+# remain the property of their copyright owners, unless otherwise agreed
+# upon. The license for this file, and modifications and additions to the
+# file, is the same license as for the pristine package itself (unless the
+# license for the pristine package is not an Open Source License, in which
+# case the license is the MIT License). An "Open Source License" is a
+# license that conforms to the Open Source Definition (Version 1.9)
+# published by the Open Source Initiative.
+
+# Please submit bugfixes or comments via https://bugs.opensuse.org/
+#
+
+
+Name:           zypper-changelog-plugin
+Version:        0.4
+Release:        0
+Summary:        Changelog listing tool
+License:        GPL-2.0-only
+Group:          System/Packages
+URL:            https://github.com/bzoltan1/zypper-changelog-plugin.git
+Source:         zypper-changelog-plugin-0.4.tar.gz
+Requires:       /usr/bin/python3
+Requires:       python3-requests
+BuildArch:      noarch
+
+%description
+This tool is to show the changelog of packages in the repository
+
+%prep
+%setup -q
+
+%build
+
+%install
+mkdir -p %{buildroot}%{_bindir}/
+install -m 755 zypper-changelog %{buildroot}%{_bindir}/zypper-changelog
+mkdir -p %{buildroot}/usr/lib/zypper/commands %{buildroot}/%{_mandir}/man8
+install -m 644 zypper-changelog.8 %{buildroot}/%{_mandir}/man8/
+
+%files
+%license LICENSE
+%doc README.md
+%{_bindir}/zypper-changelog
+%{_mandir}/man8/*
+
+%changelog
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/zypper-changelog-plugin-0.3/zypper-changelog.spec 
new/zypper-changelog-plugin-0.4/zypper-changelog.spec
--- old/zypper-changelog-plugin-0.3/zypper-changelog.spec       2020-05-06 
14:30:43.897154403 +0200
+++ new/zypper-changelog-plugin-0.4/zypper-changelog.spec       1970-01-01 
01:00:00.000000000 +0100
@@ -1,43 +0,0 @@
-#
-# spec file for package zypper-changelog
-#
-# Copyright (c) 2020 SUSE LLC
-#
-# All modifications and additions to the file contributed by third parties
-# remain the property of their copyright owners, unless otherwise agreed
-# upon. The license for this file, and modifications and additions to the
-# file, is the same license as for the pristine package itself (unless the
-# license for the pristine package is not an Open Source License, in which
-# case the license is the MIT License). An "Open Source License" is a
-# license that conforms to the Open Source Definition (Version 1.9)
-# published by the Open Source Initiative.
-
-# Please submit bugfixes or comments via https://bugs.opensuse.org/
-#
-
-
-Name:           zypper-changelog
-Version:        0.1 
-Release:        1%{?dist}
-Summary:        Changelog listing tool
-License:        GPL-2.0-or-later 
-URL:            https://github.com/bzoltan1/zypper-changelog.git
-Source:         zypper-changelog-0.1.tar.gz
-Requires:       python3
-BuildArch:      noarch
-
-%description
-This tool is to show the changelog of packages in the repository
-%prep
-%setup -q
-
-%install
-mkdir -p %{buildroot}%{_bindir}/
-install -m 755 zypper-changelog %{buildroot}%{_bindir}/zypper-changelog
-
-%files
-%doc README.md
-%license LICENSE
-%{_bindir}/zypper-changelog
-
-%changelog

Reply via email to