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 <[email protected]>
+
+- 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