Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package product-composer for 
openSUSE:Factory checked in at 2024-03-08 18:10:23
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/product-composer (Old)
 and      /work/SRC/openSUSE:Factory/.product-composer.new.1770 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "product-composer"

Fri Mar  8 18:10:23 2024 rev:8 rq:1156330 version:0.4.2

Changes:
--------
--- /work/SRC/openSUSE:Factory/product-composer/product-composer.changes        
2024-03-07 18:32:55.632786828 +0100
+++ 
/work/SRC/openSUSE:Factory/.product-composer.new.1770/product-composer.changes  
    2024-03-08 18:10:32.249134803 +0100
@@ -1,0 +2,8 @@
+Fri Mar  8 10:40:48 UTC 2024 - Adrian Schröter <adr...@suse.de>
+
+- update to version 0.4.2
+  * generate also diskusage data now (done by mls)
+  * code cleanup
+- add missing dependency to python-zstandard
+
+-------------------------------------------------------------------

Old:
----
  product-composer-0.4.1.obscpio

New:
----
  product-composer-0.4.2.obscpio

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

Other differences:
------------------
++++++ product-composer.spec ++++++
--- /var/tmp/diff_new_pack.DsDBeS/_old  2024-03-08 18:10:33.065164791 +0100
+++ /var/tmp/diff_new_pack.DsDBeS/_new  2024-03-08 18:10:33.069164937 +0100
@@ -17,7 +17,7 @@
 
 
 Name:           product-composer
-Version:        0.4.1
+Version:        0.4.2
 Release:        0
 Summary:        Product Composer
 License:        GPL-2.0-or-later
@@ -31,6 +31,7 @@
 Requires:       python3-PyYAML
 Requires:       python3-pydantic
 Requires:       python3-rpm
+Requires:       python3-zstandard
 # build for signdummy
 Requires:       build
 Requires:       createrepo

++++++ _service ++++++
--- /var/tmp/diff_new_pack.DsDBeS/_old  2024-03-08 18:10:33.097165966 +0100
+++ /var/tmp/diff_new_pack.DsDBeS/_new  2024-03-08 18:10:33.101166114 +0100
@@ -2,8 +2,8 @@
   <service name="obs_scm" mode="manual">
     <param name="url">https://github.com/openSUSE/product-composer</param>
     <param name="scm">git</param>
-    <param name="version">0.4.1</param>
-    <param name="revision">0.4.1</param>
+    <param name="version">0.4.2</param>
+    <param name="revision">0.4.2</param>
   </service>
   <service name="set_version" mode="manual" />
   <service name="tar" mode="buildtime" />

++++++ product-composer-0.4.1.obscpio -> product-composer-0.4.2.obscpio ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/product-composer-0.4.1/src/productcomposer/__main__.py 
new/product-composer-0.4.2/src/productcomposer/__main__.py
--- old/product-composer-0.4.1/src/productcomposer/__main__.py  2024-03-07 
16:46:38.000000000 +0100
+++ new/product-composer-0.4.2/src/productcomposer/__main__.py  2024-03-08 
11:50:36.000000000 +0100
@@ -3,6 +3,8 @@
     python -m productcomposer  ...
 
 """
+
+
 def main():
     """ Execute the application.
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/product-composer-0.4.1/src/productcomposer/__version__.py 
new/product-composer-0.4.2/src/productcomposer/__version__.py
--- old/product-composer-0.4.1/src/productcomposer/__version__.py       
2024-03-07 16:46:38.000000000 +0100
+++ new/product-composer-0.4.2/src/productcomposer/__version__.py       
2024-03-08 11:50:36.000000000 +0100
@@ -5,7 +5,7 @@
     <https://semver.org/>
     <https://www.python.org/dev/peps/pep-0440>
 
-Major versions introduce significant changes to the API, and backwards 
+Major versions introduce significant changes to the API, and backwards
 compatibility is not guaranteed. Minor versions are for new features and other
 backwards-compatible changes to the API. Patch versions are for bug fixes and
 internal code changes that do not affect the API. Development versions are
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/product-composer-0.4.1/src/productcomposer/api/parse.py 
new/product-composer-0.4.2/src/productcomposer/api/parse.py
--- old/product-composer-0.4.1/src/productcomposer/api/parse.py 2024-03-07 
16:46:38.000000000 +0100
+++ new/product-composer-0.4.2/src/productcomposer/api/parse.py 2024-03-08 
11:50:36.000000000 +0100
@@ -6,7 +6,7 @@
 
 def main(name="World") -> str:
     """ Execute the command.
-    
+
     :param name: name to use in greeting
     """
     logger.debug("executing hello command")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/product-composer-0.4.1/src/productcomposer/cli.py 
new/product-composer-0.4.2/src/productcomposer/cli.py
--- old/product-composer-0.4.1/src/productcomposer/cli.py       2024-03-07 
16:46:38.000000000 +0100
+++ new/product-composer-0.4.2/src/productcomposer/cli.py       2024-03-08 
11:50:36.000000000 +0100
@@ -9,10 +9,8 @@
 from argparse import ArgumentParser
 from xml.etree import ElementTree as ET
 
-import rpm
 import yaml
 
-from . import __version__
 from .core.logger import logger
 from .core.PkgSet import PkgSet
 from .core.Package import Package
@@ -37,6 +35,7 @@
 # per package override via supportstatus.txt file
 supportstatus_override = {}
 
+
 def main(argv=None) -> int:
     """ Execute the application CLI.
 
@@ -85,6 +84,7 @@
     args.func(args)
     return 0
 
+
 def die(msg, details=None):
     if msg:
         print("ERROR: " + msg)
@@ -92,11 +92,13 @@
         print(details)
     raise SystemExit(1)
 
+
 def warn(msg, details=None):
     print("WARNING: " + msg)
     if details:
         print(details)
 
+
 def note(msg):
     print(msg)
 
@@ -121,7 +123,7 @@
         directory = os.path.dirname(args.filename)
     reposdir = args.reposdir if args.reposdir else directory + "/repos"
 
-    supportstatus_fn = os.path.join(directory,'supportstatus.txt')
+    supportstatus_fn = os.path.join(directory, 'supportstatus.txt')
     if os.path.isfile(supportstatus_fn):
         parse_supportstatus(supportstatus_fn)
 
@@ -140,6 +142,7 @@
 def verify(args):
     parse_yaml(args.filename, args.flavor)
 
+
 def parse_yaml(filename, flavor):
 
     with open(filename, 'r') as file:
@@ -175,12 +178,14 @@
 
     return yml
 
+
 def parse_supportstatus(filename):
     with open(filename, 'r') as file:
         for line in file.readlines():
             a = line.strip().split(' ')
             supportstatus_override[a[0]] = a[1]
 
+
 def get_product_dir(yml, flavor, release):
     name = yml['name'] + "-" + str(yml['version'])
     if 'product_directory_name' in yml:
@@ -202,9 +207,9 @@
 
 def run_helper(args, cwd=None, stdout=None, stdin=None, failmsg=None):
     if stdout is None:
-        stdout=subprocess.PIPE
+        stdout = subprocess.PIPE
     if stdin is None:
-        stdin=subprocess.PIPE
+        stdin = subprocess.PIPE
     popen = subprocess.Popen(args, stdout=stdout, stdin=stdin, cwd=cwd)
     if popen.wait():
         output = popen.stdout.read()
@@ -214,12 +219,13 @@
             die("Failed to run" + args[0], details=output)
     return popen.stdout.read() if stdout == subprocess.PIPE else ''
 
+
 def create_tree(outdir, product_base_dir, yml, pool, flavor, vcs=None, 
disturl=None):
     if not os.path.exists(outdir):
         os.mkdir(outdir)
 
     maindir = outdir + '/' + product_base_dir
-    rpmdir = maindir # we may offer to set it up in sub directories
+    rpmdir = maindir  # we may offer to set it up in sub directories
     if not os.path.exists(rpmdir):
         os.mkdir(rpmdir)
 
@@ -238,7 +244,7 @@
             debugdir = outdir + '/' + product_base_dir + '-Debug'
             os.mkdir(debugdir)
         elif yml['debug'] == 'drop':
-            debugdir = None 
+            debugdir = None
         elif yml['debug'] != 'include':
             die("Bad debug option, must be either 'include', 'split' or 
'drop'")
 
@@ -246,9 +252,9 @@
         link_rpms_to_tree(rpmdir, yml, pool, arch, flavor, debugdir, sourcedir)
 
     for arch in yml['architectures']:
-        unpack_meta_rpms(rpmdir, yml, pool, arch, flavor, medium=1) # only for 
first medium am
+        unpack_meta_rpms(rpmdir, yml, pool, arch, flavor, medium=1)  # only 
for first medium am
 
-    repos=[]
+    repos = []
     if disturl:
         match = re.match("^obs://([^/]*)/([^/]*)/.*", disturl)
         if match:
@@ -258,13 +264,13 @@
             repos = [repo]
     if vcs:
         repos.append(vcs)
- 
-    default_content=["pool"]
+
+    default_content = ["pool"]
     for file in os.listdir(rpmdir):
         if not file.startswith('gpg-pubkey-'):
             continue
 
-        args=['gpg', '--no-keyring', '--no-default-keyring', '--with-colons',
+        args = ['gpg', '--no-keyring', '--no-default-keyring', '--with-colons',
               '--import-options', 'show-only', '--import', '--fingerprint']
         out = run_helper(args, stdin=open(f'{rpmdir}/{file}', 'rb'),
                          failmsg="Finger printing of gpg file")
@@ -293,38 +299,23 @@
     # the tools read the subdirectory of the rpmdir from environment variable
     os.environ['ROOT_ON_CD'] = '.'
     if os.path.exists("/usr/bin/mk_changelog"):
-        args = [ "/usr/bin/mk_changelog", rpmdir ]
+        args = ["/usr/bin/mk_changelog", rpmdir]
         run_helper(args)
 
     # ARCHIVES.gz
     if os.path.exists("/usr/bin/mk_listings"):
-        args = [ "/usr/bin/mk_listings", rpmdir ]
+        args = ["/usr/bin/mk_listings", rpmdir]
         run_helper(args)
 
     # media.X structures FIXME
     mediavendor = yml['vendor'] + ' - ' + product_base_dir
     mediaident = product_base_dir
     # FIXME: calculate from product provides
-    mediaproducts = [ yml['vendor'] + '-' + yml['name'] + ' ' + 
str(yml['version']) + '-1' ]
+    mediaproducts = [yml['vendor'] + '-' + yml['name'] + ' ' + 
str(yml['version']) + '-1']
     create_media_dir(maindir, mediavendor, mediaident, mediaproducts)
 
-    # CHECKSUMS file
     create_checksums_file(maindir)
 
-    # repodata/appdata
-    # currently not supported in ALP?
-#   if os.path.exists("/usr/bin/openSUSE-appstream-process"):
-#       args = [ "/usr/bin/openSUSE-appstream-process",
-#                rpmdir, rpmdir + "/repodata" ]
-#       run_helper(args)
-
-    # repodata/*susedata*
-#   if os.path.exists("/usr/bin/add_product_susedata"):
-#       args = [ "/usr/bin/add_product_susedata",
-#                '-p', #  diskusage data
-#                '-d', rpmdir ]
-#       run_helper(args)
-
     create_susedata_xml(rpmdir, yml)
 
     process_updateinfos(rpmdir, yml, pool, flavor, debugdir, sourcedir)
@@ -340,7 +331,7 @@
         licensedir = rpmdir + ".license"
         if not os.path.exists(licensedir):
             os.mkdir(licensedir)
-        args = [ 'tar', 'xf', rpmdir + licensefilename, '-C', licensedir ]
+        args = ['tar', 'xf', rpmdir + licensefilename, '-C', licensedir]
         output = run_helper(args, failmsg="extract license tar ball")
         if not os.path.exists(licensedir + "/license.txt"):
             die("No license.txt extracted", details=output)
@@ -358,38 +349,38 @@
             os.unlink(rpmdir + '/license.tar.gz')
 
     # detached signature
-    args = [ '/usr/lib/build/signdummy', '-d', rpmdir + "/repodata/repomd.xml" 
]
+    args = ['/usr/lib/build/signdummy', '-d', rpmdir + "/repodata/repomd.xml"]
     run_helper(args, failmsg="create detached signature")
-    args = [ '/usr/lib/build/signdummy', '-d', maindir + '/CHECKSUMS' ]
+    args = ['/usr/lib/build/signdummy', '-d', maindir + '/CHECKSUMS']
     run_helper(args, failmsg="create detached signature for CHECKSUMS")
 
     # pubkey
     with open(rpmdir + "/repodata/repomd.xml.key", 'w') as pubkey_file:
-        args = [ '/usr/lib/build/signdummy', '-p' ]
+        args = ['/usr/lib/build/signdummy', '-p']
         run_helper(args, stdout=pubkey_file, failmsg="write signature public 
key")
 
     # do we need an ISO file?
     if 'iso' in yml:
         for workdir in [maindir, sourcedir, debugdir]:
             application_id = re.sub(r'^.*/', '', maindir)
-            args = [ '/usr/bin/mkisofs', '-quiet', '-p', 'Product Composer - 
http://www.github.com/openSUSE/product-composer' ]
-            args += [ '-r', '-pad', '-f', '-J', '-joliet-long' ]
+            args = ['/usr/bin/mkisofs', '-quiet', '-p', 'Product Composer - 
http://www.github.com/openSUSE/product-composer']
+            args += ['-r', '-pad', '-f', '-J', '-joliet-long']
             # FIXME: do proper multi arch handling
             isolinux = 'boot/' + yml['architectures'][0] + 
'/loader/isolinux.bin'
             if os.path.isfile(workdir + '/' + isolinux):
-                args += [ '-no-emul-boot', '-boot-load-size', '4', 
'-boot-info-table' ]
-                args += [ '-hide', 'glump', '-hide-joliet', 'glump' ]
-                args += [ '-eltorito-alt-boot', '-eltorito-platform', 'efi' ]
-                args += [ '-no-emul-boot' ]
-                #args += [ '-sort', $sort_file ]
-                #args += [ '-boot-load-size', 
block_size("boot/"+arch+"/loader") ]
-                args += [ '-b', isolinux]
+                args += ['-no-emul-boot', '-boot-load-size', '4', 
'-boot-info-table']
+                args += ['-hide', 'glump', '-hide-joliet', 'glump']
+                args += ['-eltorito-alt-boot', '-eltorito-platform', 'efi']
+                args += ['-no-emul-boot']
+                # args += [ '-sort', $sort_file ]
+                # args += [ '-boot-load-size', 
block_size("boot/"+arch+"/loader") ]
+                args += ['-b', isolinux]
             if 'publisher' in yml['iso']:
-                args += [ '-publisher', yml['iso']['publisher'] ]
+                args += ['-publisher', yml['iso']['publisher']]
             if 'volume_id' in yml['iso']:
-                args += [ '-V', yml['iso']['volume_id'] ]
-            args += [ '-A', application_id ]
-            args += [ '-o', workdir + '.iso', workdir ]
+                args += ['-V', yml['iso']['volume_id']]
+            args += ['-A', application_id]
+            args += ['-o', workdir + '.iso', workdir]
             run_helper(args, cwd=maindir, failmsg="create iso file")
 
     # create SBOM data
@@ -397,37 +388,40 @@
         spdx_distro = "ALP"
         spdx_distro += "-" + str(yml['version'])
         # SPDX
-        args = [ "/usr/lib/build/generate_sbom",
+        args = ["/usr/lib/build/generate_sbom",
                  "--format", 'spdx',
                  "--distro", spdx_distro,
-                 "--product", rpmdir 
+                 "--product", rpmdir
                ]
         with open(rpmdir + ".spdx.json", 'w') as sbom_file:
             run_helper(args, stdout=sbom_file, failmsg="run generate_sbom for 
SPDX")
 
         # CycloneDX
-        args = [ "/usr/lib/build/generate_sbom",
+        args = ["/usr/lib/build/generate_sbom",
                  "--format", 'cyclonedx',
                  "--distro", spdx_distro,
-                 "--product", rpmdir 
+                 "--product", rpmdir
                ]
         with open(rpmdir + ".cdx.json", 'w') as sbom_file:
             run_helper(args, stdout=sbom_file, failmsg="run generate_sbom for 
CycloneDX")
 
 # create media info files
+
+
 def create_media_dir(maindir, vendorstr, identstr, products):
     media1dir = maindir + '/' + 'media.1'
     if not os.path.isdir(media1dir):
-        os.mkdir(media1dir) # we do only support seperate media atm
+        os.mkdir(media1dir)  # we do only support seperate media atm
     with open(media1dir + '/media', 'w') as media_file:
         media_file.write(vendorstr + "\n")
         media_file.write(identstr + "\n")
         media_file.write("1\n")
     if products:
         with open(media1dir + '/products', 'w') as products_file:
-            for productname in products: 
+            for productname in products:
                 products_file.write('/ ' + productname + "\n")
 
+
 def create_checksums_file(maindir):
     with open(maindir + '/CHECKSUMS', 'a') as chksums_file:
         for subdir in ('boot', 'EFI', 'docu', 'media.1'):
@@ -439,13 +433,55 @@
                     run_helper([chksums_tool, relname], cwd=maindir, 
stdout=chksums_file)
 
 # create a fake package entry from an updateinfo package spec
+
+
 def create_updateinfo_package(pkgentry):
     entry = Package()
     for tag in 'name', 'epoch', 'version', 'release', 'arch':
         setattr(entry, tag, pkgentry.get(tag))
     return entry
 
+def generate_du_data(pkg, maxdepth):
+    dirs = pkg.get_directories()
+    seen = set()
+    dudata_size = {}
+    dudata_count = {}
+    for dir, filedatas in pkg.get_directories().items():
+        if dir == '':
+            dir = '/usr/src/packages/'
+        size = 0
+        count = 0
+        for filedata in filedatas:
+            (basename, filesize, cookie) = filedata
+            if cookie:
+                if cookie in seen:
+                    next
+                seen.add(cookie)
+                size += filesize
+                count += 1
+        dir = '/' + dir.strip('/')
+        subdir = ''
+        depth = 0
+        for comp in dir.split('/'):
+            if comp == '' and subdir != '':
+                next
+            subdir += comp + '/'
+            if subdir not in dudata_size:
+                dudata_size[subdir] = 0
+                dudata_count[subdir] = 0
+            dudata_size[subdir] += size
+            dudata_count[subdir] += count
+            depth += 1
+            if depth > maxdepth:
+                break
+    dudata = []
+    for dir, size in sorted(dudata_size.items()):
+        dudata.append((dir, size, dudata_count[dir]))
+    return dudata
+
 # Create the main susedata.xml with support and disk usage informations
+
+
 def create_susedata_xml(rpmdir, yml):
     # get supported translations based on local packages
     i18ndir = '/usr/share/locale/en_US/LC_MESSAGES/'
@@ -464,9 +500,9 @@
                                                   languages=['en_US'])
 
     # read repomd.xml
-    ns='{http://linux.duke.edu/metadata/repo}'
+    ns = '{http://linux.duke.edu/metadata/repo}'
     tree = ET.parse(rpmdir + '/repodata/repomd.xml')
-    primary_fn = 
tree.find(f".//{ns}data[@type='primary']/{ns}location").attrib['href']
+    primary_fn = 
tree.find(f".//{ns}data[@type='primary']/{ns}location").get('href')
 
     # read compressed primary.xml
     openfunction = None
@@ -479,7 +515,7 @@
     else:
         die(f"unsupported primary compression type ({primary_fm})")
     tree = ET.parse(openfunction(rpmdir + '/' + primary_fn, 'rb'))
-    ns='{http://linux.duke.edu/metadata/common}'
+    ns = '{http://linux.duke.edu/metadata/common}'
 
     # Create susedata structure
     susedata = ET.Element('susedata')
@@ -487,9 +523,9 @@
     # go for every rpm file of the repo via the primary
     count = 0
     for pkg in tree.findall(f".//{ns}package[@type='rpm']"):
-        name    = pkg.find(f'{ns}name').text
-        pkgid   = pkg.find(f'{ns}checksum').text
-        arch    = pkg.find(f'{ns}arch').text
+        name = pkg.find(f'{ns}name').text
+        pkgid = pkg.find(f'{ns}checksum').text
+        arch = pkg.find(f'{ns}arch').text
         version = pkg.find(f'{ns}version').attrib
 
         package = ET.SubElement(susedata, 'package')
@@ -499,6 +535,16 @@
         ET.SubElement(package, 'version', version)
         if name in supportstatus and supportstatus[name] is not None:
             ET.SubElement(package, 'keyword').text = 
f'support_{supportstatus[name]}'
+        location = pkg.find(f'{ns}location').get('href')
+        if os.path.exists(rpmdir + '/' + location):
+            p = Package()
+            p.location = rpmdir + '/' + location
+            dudata = generate_du_data(p, 3)
+            if dudata:
+                duelement = ET.SubElement(package, 'diskusage')
+                dirselement = ET.SubElement(duelement, 'dirs')
+                for duitem in dudata:
+                    ET.SubElement(dirselement, 'dir', { 'name': duitem[0], 
'size': str(duitem[1]), 'count': str(duitem[2]) })
         count += 1
 
         # look for pattern category
@@ -513,7 +559,7 @@
             isummary = i18ntrans[lang].gettext(summary)
             idescription = i18ntrans[lang].gettext(description)
             icategory = i18ntrans[lang].gettext(category) if category else None
-            if isummary == summary and idescription == description:
+            if isummary == summary and idescription == description and 
icategory == category:
                 continue
             if lang not in i18ndata:
                 i18ndata[lang] = ET.Element('susedata')
@@ -546,7 +592,7 @@
 
     for lang in i18ndata:
         i18ndata[lang].set('packages', str(i18ndata_count[lang]))
-        susedata_fn=rpmdir + f'/susedata.{lang}.xml'
+        susedata_fn = rpmdir + f'/susedata.{lang}.xml'
         ET.indent(i18ndata[lang], space="    ", level=0)
 
         with open(susedata_fn, 'x') as sd_file:
@@ -656,6 +702,7 @@
     cr.excludes = ["boot"]
     cr.run_cmd(cwd=rpmdir, stdout=subprocess.PIPE)
 
+
 def unpack_one_meta_rpm(rpmdir, rpm, medium):
     tempdir = rpmdir + "/temp"
     os.mkdir(tempdir)
@@ -666,9 +713,10 @@
         shutil.copytree(skel_dir, rpmdir, dirs_exist_ok=True)
     shutil.rmtree(tempdir)
 
+
 def unpack_meta_rpms(rpmdir, yml, pool, arch, flavor, medium):
     missing_package = False
-    for unpack_pkgset_name in yml.get('unpack', [ 'unpack' ]):
+    for unpack_pkgset_name in yml.get('unpack', ['unpack']):
         unpack_pkgset = create_package_set(yml, arch, flavor, 
unpack_pkgset_name)
         for sel in unpack_pkgset:
             rpm = pool.lookup_rpm(arch, sel.name, sel.op, sel.epoch, 
sel.version, sel.release)
@@ -681,11 +729,12 @@
     if missing_package and not 'ignore_missing_packages' in 
yml['build_options']:
         die('Abort due to missing packages')
 
+
 def create_package_set_compat(yml, arch, flavor, setname):
     if setname == 'main':
-        oldname = 'packages' 
+        oldname = 'packages'
     elif setname == 'unpack':
-        oldname = 'unpack_packages' 
+        oldname = 'unpack_packages'
     else:
         return None
     if oldname not in yml:
@@ -701,9 +750,10 @@
                     continue
             pkgset.add_specs(entry['packages'])
         else:
-            pkgset.add_specs([ str(entry) ])
+            pkgset.add_specs([str(entry)])
     return pkgset
 
+
 def create_package_set(yml, arch, flavor, setname):
     if 'packagesets' not in yml:
         pkgset = create_package_set_compat(yml, arch, flavor, setname)
@@ -752,6 +802,7 @@
         pkgsets[setname] = PkgSet(setname)      # instantiate
     return pkgsets[setname]
 
+
 def link_rpms_to_tree(rpmdir, yml, pool, arch, flavor, debugdir=None, 
sourcedir=None):
     singlemode = True
     if 'take_all_available_versions' in yml['build_options']:
@@ -790,7 +841,7 @@
                 if srpm:
                     link_entry_into_dir(srpm, sourcedir)
                 else:
-                    details=f"         required by  {rpm}"
+                    details = f"         required by  {rpm}"
                     warn(f"source rpm package {srcrpm} not found", 
details=details)
                     missing_package = True
 
@@ -806,6 +857,7 @@
     if missing_package and not 'ignore_missing_packages' in 
yml['build_options']:
         die('Abort due to missing packages')
 
+
 def link_file_into_dir(filename, directory):
     if not os.path.exists(directory):
         os.mkdir(directory)
@@ -823,12 +875,14 @@
     link_file_into_dir(entry.location, directory + '/' + entry.arch)
     add_entry_to_report(entry, directory)
 
+
 def add_entry_to_report(entry, directory):
     outname = directory + '/' + entry.arch + '/' + 
os.path.basename(entry.location)
     # first one wins, see link_file_into_dir
     if outname not in tree_report:
         tree_report[outname] = entry
 
+
 def write_report_file(directory, outfile):
     root = ET.Element('report')
     if not directory.endswith('/'):
@@ -855,6 +909,7 @@
     tree = ET.ElementTree(root)
     tree.write(outfile)
 
+
 if __name__ == "__main__":
     try:
         status = main()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/product-composer-0.4.1/src/productcomposer/core/Package.py 
new/product-composer-0.4.2/src/productcomposer/core/Package.py
--- old/product-composer-0.4.1/src/productcomposer/core/Package.py      
2024-03-07 16:46:38.000000000 +0100
+++ new/product-composer-0.4.2/src/productcomposer/core/Package.py      
2024-03-08 11:50:36.000000000 +0100
@@ -6,6 +6,7 @@
 import rpm
 import functools
 
+
 @functools.total_ordering
 class Package:
     def __init__(self, location=None, rpm_ts=None):
@@ -49,7 +50,7 @@
         h = self._read_rpm_header()
         if h is None:
             return None
-        return [ dep.DNEVR()[2:] for dep in rpm.ds(h, 'provides') ]
+        return [dep.DNEVR()[2:] for dep in rpm.ds(h, 'provides')]
 
     def _read_rpm_header(self, rpm_ts=None):
         if self.location is None:
@@ -113,4 +114,36 @@
             return '<' in op
         return '=' in op
 
+    def get_directories(self):
+        h = self._read_rpm_header()
+        if h is None:
+            return None
+        dirs = {}
+        filedevs = h['filedevices']
+        fileinos= h['fileinodes']
+        filesizes = h['filesizes']
+        filemodes = h['filemodes']
+        dirnames = h['dirnames']
+        dirindexes = h['dirindexes']
+        basenames = h['basenames']
+        if not basenames:
+            return dirs
+        for basename, dirindex, filesize, filemode, filedev, fileino in 
zip(basenames, dirindexes, filesizes, filemodes, filedevs, fileinos):
+            dirname = dirnames[dirindex]
+            if isinstance(basename, bytes):
+                basename = basename.decode('utf-8')
+            if isinstance(dirname, bytes):
+                dirname = dirname.decode('utf-8')
+            if dirname != '' and not dirname.endswith('/'):
+                dirname += '/'
+            if not dirname in dirs:
+                dirs[dirname] = []
+            cookie = f"{filedev}/{fileino}"
+            if (filemode & 0o170000) != 0o100000:
+                filesize = 0
+            dirs[dirname].append((basename, filesize, cookie))
+        return dirs
+            
+            
+
 # vim: sw=4 et
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/product-composer-0.4.1/src/productcomposer/core/PkgSelect.py 
new/product-composer-0.4.2/src/productcomposer/core/PkgSelect.py
--- old/product-composer-0.4.1/src/productcomposer/core/PkgSelect.py    
2024-03-07 16:46:38.000000000 +0100
+++ new/product-composer-0.4.2/src/productcomposer/core/PkgSelect.py    
2024-03-08 11:50:36.000000000 +0100
@@ -5,21 +5,22 @@
 import re
 import rpm
 
+
 class PkgSelect:
-    def __init__(self, spec, supportstatus = None):
+    def __init__(self, spec, supportstatus=None):
         self.supportstatus = supportstatus
         match = re.match(r'([^><=]*)([><=]=?)(.*)', spec.replace(' ', ''))
         if match:
-            self.name  = match.group(1)
-            self.op    = match.group(2)
-            epoch      = '0'
-            version    = match.group(3)
-            release    = None
+            self.name = match.group(1)
+            self.op = match.group(2)
+            epoch = '0'
+            version = match.group(3)
+            release = None
             if ':' in version:
                 (epoch, version) = version.split(':', 2)
             if '-' in version:
                 (version, release) = version.rsplit('-', 2)
-            self.epoch   = epoch 
+            self.epoch = epoch
             self.version = version
             self.release = release
         else:
@@ -31,7 +32,7 @@
 
     def matchespkg(self, arch, pkg):
         return pkg.matches(arch, self.name, self.op, self.epoch, self.version, 
self.release)
-    
+
     @staticmethod
     def _sub_ops(op1, op2):
         if '>' in op2:
@@ -113,7 +114,7 @@
             if '>' in self.op and '<' not in other.op:
                 return other
             if '<' in other.op and '>' not in self.op:
-                return self 
+                return self
             if '<' not in other.op and '>' not in self.op:
                 return None
         elif cmp > 0:
@@ -143,7 +144,7 @@
         if self.epoch and self.epoch != '0':
             evr = self.epoch + ':' + evr
         return self.name + ' ' + self.op + ' ' + evr
-    
+
     def __hash__(self):
         if self.op:
             return hash((self.name, self.op, self.epoch, self.version, 
self.release))
@@ -154,5 +155,5 @@
         if self.name != other.name:
             return False
         return str(self) == str(other)
-        
+
 # vim: sw=4 et
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/product-composer-0.4.1/src/productcomposer/core/PkgSet.py 
new/product-composer-0.4.2/src/productcomposer/core/PkgSet.py
--- old/product-composer-0.4.1/src/productcomposer/core/PkgSet.py       
2024-03-07 16:46:38.000000000 +0100
+++ new/product-composer-0.4.2/src/productcomposer/core/PkgSet.py       
2024-03-08 11:50:36.000000000 +0100
@@ -4,6 +4,7 @@
 
 from .PkgSelect import PkgSelect
 
+
 class PkgSet:
     def __init__(self, name):
         self.name = name
@@ -25,7 +26,7 @@
             sel = PkgSelect(spec, supportstatus=self.supportstatus)
             self.pkgs.append(sel)
         self.byname = None
-    
+
     def add(self, other):
         s1 = set(self)
         for sel in other.pkgs:
@@ -90,5 +91,5 @@
 
     def __iter__(self):
         return iter(self.pkgs)
-        
+
 # vim: sw=4 et
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/product-composer-0.4.1/src/productcomposer/core/Pool.py 
new/product-composer-0.4.2/src/productcomposer/core/Pool.py
--- old/product-composer-0.4.1/src/productcomposer/core/Pool.py 2024-03-07 
16:46:38.000000000 +0100
+++ new/product-composer-0.4.2/src/productcomposer/core/Pool.py 2024-03-08 
11:50:36.000000000 +0100
@@ -8,6 +8,7 @@
 from .Package import Package
 from .Updateinfo import Updateinfo
 
+
 class Pool:
     def __init__(self):
         self.rpms = {}
@@ -44,11 +45,11 @@
                 elif filename.endswith('.rpm'):
                     pkg = self.make_rpm(fname, rpm_ts=ts)
                     self.add_rpm(pkg, os.path.join(reldirpath, filename))
-        
+
     def lookup_all_rpms(self, arch, name, op=None, epoch=None, version=None, 
release=None):
         if name not in self.rpms:
             return []
-        return [ rpm for rpm in self.rpms[name] if rpm.matches(arch, name, op, 
epoch, version, release) ]
+        return [rpm for rpm in self.rpms[name] if rpm.matches(arch, name, op, 
epoch, version, release)]
 
     def lookup_rpm(self, arch, name, op=None, epoch=None, version=None, 
release=None):
         return max(self.lookup_all_rpms(arch, name, op, epoch, version, 
release), default=None)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/product-composer-0.4.1/src/productcomposer/core/Updateinfo.py 
new/product-composer-0.4.2/src/productcomposer/core/Updateinfo.py
--- old/product-composer-0.4.1/src/productcomposer/core/Updateinfo.py   
2024-03-07 16:46:38.000000000 +0100
+++ new/product-composer-0.4.2/src/productcomposer/core/Updateinfo.py   
2024-03-08 11:50:36.000000000 +0100
@@ -5,6 +5,7 @@
 
 from xml.etree import ElementTree as ET
 
+
 @functools.total_ordering
 class Updateinfo:
     def __init__(self, location=None):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/product-composer-0.4.1/src/productcomposer/core/logger.py 
new/product-composer-0.4.2/src/productcomposer/core/logger.py
--- old/product-composer-0.4.1/src/productcomposer/core/logger.py       
2024-03-07 16:46:38.000000000 +0100
+++ new/product-composer-0.4.2/src/productcomposer/core/logger.py       
2024-03-08 11:50:36.000000000 +0100
@@ -20,8 +20,8 @@
     def __init__(self, name=None):
         """ Initialize this logger.
 
-        Loggers with the same name refer to the same underlying object. 
-        Names are hierarchical, e.g. 'parent.child' defines a logger that is a 
+        Loggers with the same name refer to the same underlying object.
+        Names are hierarchical, e.g. 'parent.child' defines a logger that is a
         descendant of 'parent'.
 
         :param name: logger name (application name by default)
@@ -38,16 +38,16 @@
         """ Start logging to a stream.
 
         Until the logger is started, no messages will be emitted. This applies
-        to all loggers with the same name and any child loggers. 
+        to all loggers with the same name and any child loggers.
 
         Multiple streams can be logged to by calling start() for each one.
         Calling start() more than once for the same stream will result in
         duplicate records to that stream.
 
         Messages less than the given priority level will be ignored. The
-        default level conforms to the *nix convention that a successful run 
-        should produce no diagnostic output. Call setLevel() to change the 
-        logger's priority level after it has been stared. Available levels and 
+        default level conforms to the *nix convention that a successful run
+        should produce no diagnostic output. Call setLevel() to change the
+        logger's priority level after it has been stared. Available levels and
         their suggested meanings:
 
             DEBUG - output useful for developers
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/product-composer-0.4.1/src/productcomposer/wrappers/common.py 
new/product-composer-0.4.2/src/productcomposer/wrappers/common.py
--- old/product-composer-0.4.1/src/productcomposer/wrappers/common.py   
2024-03-07 16:46:38.000000000 +0100
+++ new/product-composer-0.4.2/src/productcomposer/wrappers/common.py   
2024-03-08 11:50:36.000000000 +0100
@@ -6,7 +6,6 @@
 
 import os
 import subprocess
-from abc import ABC
 from abc import abstractmethod
 
 from pydantic import BaseModel

++++++ product-composer.obsinfo ++++++
--- /var/tmp/diff_new_pack.DsDBeS/_old  2024-03-08 18:10:33.225170670 +0100
+++ /var/tmp/diff_new_pack.DsDBeS/_new  2024-03-08 18:10:33.229170817 +0100
@@ -1,5 +1,5 @@
 name: product-composer
-version: 0.4.1
-mtime: 1709826398
-commit: d4343d718c9ebcc9bcdce68b133b0c84979c870e
+version: 0.4.2
+mtime: 1709895036
+commit: 2e1933d5752f59d07883338de554c829ba7daeb2
 

Reply via email to