Initial support for productcompose files

It requires to have a "default.productcompose" file in 000package-groups
to enable support for real
This commit is contained in:
Adrian Schröter 2024-02-02 11:42:44 +01:00
parent de9a894eb5
commit 9b449f91cb
No known key found for this signature in database
GPG Key ID: 918D8C954C08DB67
3 changed files with 102 additions and 0 deletions

View File

@ -43,6 +43,7 @@ class CommandLineInterface(ToolBase.CommandLineInterface):
return update_project(conf.config['apiurl'], project, opts.fixate)
@cmdln.option('-f', '--force', action='store_true', help='continue even if build is in progress')
@cmdln.option('-d', '--dry', help='no modifications uploaded')
@cmdln.option('-p', '--project', help='target project')
@cmdln.option('-s', '--scope', help='scope on which to operate ({}, staging:$letter)'.format(', '.join(SCOPES)))
@cmdln.option('--no-checkout', action='store_true', help='reuse checkout in cache')

View File

@ -15,6 +15,7 @@ class Group(object):
self.pkglist = pkglist
self.architectures = pkglist.all_architectures
self.conditional = None
self.flavors = dict()
self.packages = dict()
self.locked = set()
self.solved_packages = None
@ -312,6 +313,37 @@ class Group(object):
def filter_already_selected(self, modules):
self._filter_already_selected(modules, self.recommends)
def tocompose(self, prefix, arch, ignore_broken=False, comment=None):
packages = self.solved_packages.get(arch, dict())
name = self.name
missing = dict()
if arch == '*':
missing = self.not_found
content = ''
unresolvable = self.unresolvable.get(arch, dict())
for name in sorted(list(packages) + list(missing) + list(unresolvable)):
if name in self.silents:
continue
if name in missing:
if ignore_broken and name not in self.required:
content += prefix + "#- " + name + " is missing\n"
continue
if name in unresolvable:
if ignore_broken and name not in self.required:
content += prefix + "#- " + name + " is unresolvable: " + unresolvable[name] + "\n"
continue
content += prefix + "- " + name
if comment:
content += " # " + comment
content += "\n"
content += "\n"
return content
def toxml(self, arch, ignore_broken=False, comment=None):
packages = self.solved_packages.get(arch, dict())

View File

@ -63,6 +63,8 @@ class PkgListGen(ToolBase.ToolBase):
self.output_dir = '.'
self.lockjobs = dict()
self.ignore_broken = False
self.productcompose_dir = None
self.skip_productcompose = False
self.unwanted = set()
self.output = None
self.locales = set()
@ -133,6 +135,48 @@ class PkgListGen(ToolBase.ToolBase):
x = ET.tostring(x, pretty_print=True, encoding='unicode')
fh.write(x)
def write_productcompose(self):
self._check_supplements()
summary = dict()
archs = ['*'] + self.all_architectures
# a single file covering all builds via multibuild flavors
with open(os.path.join(self.productcompose_dir, 'default.productcompose'), 'a') as opfh:
opfh.write("# The following is generated by openSUSE-release-tools\n")
for name in self.groups:
group = self.groups[name]
if not group.solved:
continue
opfh.write(f"# {group.comment}\n")
for arch in archs:
opfh.write(f"- name: {name}")
if arch != '*':
opfh.write(f"_{arch}")
opfh.write('\n')
opfh.write(' flavors:\n')
for f in group.flavors:
opfh.write(f" - {f}\n")
if arch == '*':
for included_arch in self.all_architectures:
opfh.write(' - ' + f + '_' + included_arch + '\n')
else:
opfh.write(' - ' + f + '_' + arch + '\n')
opfh.write(' architectures:\n')
opfh.write(' - ' + arch + '\n')
opfh.write(' packages:\n')
opfh.write(group.tocompose(' ', arch, group.ignore_broken))
# write main group including all sets
opfh.write("- name: main\n add:\n")
for name in self.groups:
group = self.groups[name]
if not group.solved:
continue
for f in group.flavors:
opfh.write(' - ' + f + '\n')
for included_arch in self.all_architectures:
opfh.write(' - ' + f + '_' + included_arch + '\n')
return summary
def write_all_groups(self):
self._check_supplements()
summary = dict()
@ -152,6 +196,7 @@ class PkgListGen(ToolBase.ToolBase):
x = ET.tostring(x, pretty_print=True, encoding='unicode')
x = re.sub(r'\s*<!-- reason:', ' <!-- reason:', x)
fh.write(x)
return summary
def solve_module(self, groupname, includes, excludes, use_recommends):
@ -536,6 +581,7 @@ class PkgListGen(ToolBase.ToolBase):
use_recommends = settings.get('recommends', global_use_recommends)
self.solve_module(groupname, includes, excludes, use_recommends)
g = self.groups[groupname]
g.flavors = [groupname] # main flavor of productcompose _multibuild flavor
# the default is a little double negated but Factory has ignore_broken
# as default and we only disable it for single groups (for now)
g.ignore_broken = not settings.get('require_all', not self.ignore_broken)
@ -564,6 +610,8 @@ class PkgListGen(ToolBase.ToolBase):
module.solved_packages[arch].pop(p, None)
self._collect_unsorted_packages(modules, self.groups.get('unsorted'))
if not self.skip_productcompose:
self.write_productcompose()
return self.write_all_groups()
def strip_medium_from_staging(self, path):
@ -623,6 +671,7 @@ class PkgListGen(ToolBase.ToolBase):
group = target_config.get('pkglistgen-group', '000package-groups')
product = target_config.get('pkglistgen-product', '000product')
productcompose = target_config.get('pkglistgen-product', '000productcompose')
release = target_config.get('pkglistgen-release', '000release-packages')
oldrepos = target_config.get('pkglistgen-repos', '000update-repos')
@ -666,6 +715,7 @@ class PkgListGen(ToolBase.ToolBase):
group_dir = os.path.join(cache_dir, group)
product_dir = os.path.join(cache_dir, product)
self.productcompose_dir = os.path.join(cache_dir, productcompose)
release_dir = os.path.join(cache_dir, release)
oldrepos_dir = os.path.join(cache_dir, oldrepos)
@ -687,6 +737,25 @@ class PkgListGen(ToolBase.ToolBase):
file_utils.copy_directory_contents(group_dir, product_dir, ignore_list)
file_utils.change_extension(product_dir, '.spec.in', '.spec')
file_utils.change_extension(product_dir, '.product.in', '.product')
fn = os.path.join(group_dir, 'default.productcompose')
if os.path.isfile(fn):
if not os.path.isdir(self.productcompose_dir):
os.mkdir(self.productcompose_dir) # currently always creating it local at least
lines = open(fn).readlines()
new_lines = []
for line in lines:
if line.startswith('# The following is generated by openSUSE-release-tools'):
break
new_lines.append(line)
open(os.path.join(self.productcompose_dir, 'default.productcompose'), 'w').write(''.join(new_lines))
if git_url:
logging.debug(subprocess.check_output(
['git', 'add', self.productcompose_dir, f"{self.productcompose_dir}/default.productcompose"],
cwd=cache_dir, encoding='utf-8'))
self.skip_productcompose = False
else:
# No template file, so we don't create one either
self.skip_productcompose = True
logging.debug('-> do_update')
# make sure we only calculcate existant architectures