Since the implementations have been made generic and dropped to osclib.core there is not point in having wrappers in StagingAPI with the same args.
290 lines
12 KiB
Python
290 lines
12 KiB
Python
# Copyright (C) 2015 SUSE Linux GmbH
|
|
#
|
|
# This program is free software; you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation; either version 2 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License along
|
|
# with this program; if not, write to the Free Software Foundation, Inc.,
|
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
|
|
from osclib.config_command import ConfigCommand
|
|
from osclib.core import source_file_load
|
|
from osclib.core import source_file_save
|
|
import time
|
|
import re
|
|
from xml.etree import cElementTree as ET
|
|
|
|
|
|
class FreezeCommand(object):
|
|
|
|
def __init__(self, api):
|
|
self.api = api
|
|
self.projectlinks = []
|
|
|
|
def set_links(self):
|
|
url = self.api.makeurl(['source', self.prj, '_meta'])
|
|
f = self.api.retried_GET(url)
|
|
root = ET.parse(f).getroot()
|
|
links = root.findall('link')
|
|
links.reverse()
|
|
self.projectlinks = [link.get('project') for link in links]
|
|
|
|
def set_bootstrap_copy(self):
|
|
url = self.api.makeurl(['source', self.prj, '_meta'])
|
|
|
|
f = self.api.retried_GET(url)
|
|
oldmeta = ET.parse(f).getroot()
|
|
|
|
meta = ET.fromstring(self.prj_meta_for_bootstrap_copy(self.prj))
|
|
meta.find('title').text = oldmeta.find('title').text
|
|
meta.find('description').text = oldmeta.find('description').text
|
|
for person in oldmeta.findall('person'):
|
|
# the xml has a fixed structure
|
|
meta.insert(2, ET.Element('person', role=person.get('role'), userid=person.get('userid')))
|
|
|
|
self.api.retried_PUT(url, ET.tostring(meta))
|
|
|
|
def create_bootstrap_aggregate(self):
|
|
self.create_bootstrap_aggregate_meta()
|
|
self.create_bootstrap_aggregate_file()
|
|
|
|
def bootstrap_packages(self):
|
|
url = self.api.makeurl(['build', '{}:0-Bootstrap'.format(self.api.crings), '_result'])
|
|
f = self.api.retried_GET(url)
|
|
root = ET.parse(f).getroot().find('result')
|
|
l = list()
|
|
for e in root.findall('status'):
|
|
name = e.get('package')
|
|
if name in ['rpmlint-mini-AGGR']:
|
|
continue
|
|
l.append(name)
|
|
l.sort()
|
|
return l
|
|
|
|
def create_bootstrap_aggregate_file(self):
|
|
url = self.api.makeurl(['source', self.prj, 'bootstrap-copy', '_aggregate'])
|
|
|
|
root = ET.Element('aggregatelist')
|
|
a = ET.SubElement(root, 'aggregate',
|
|
{'project': '{}:0-Bootstrap'.format(self.api.crings)})
|
|
|
|
for package in self.bootstrap_packages():
|
|
p = ET.SubElement(a, 'package')
|
|
p.text = package
|
|
|
|
ET.SubElement(a, 'repository', {'target': 'bootstrap_copy', 'source': 'standard'})
|
|
ET.SubElement(a, 'repository', {'target': 'standard', 'source': 'nothing'})
|
|
ET.SubElement(a, 'repository', {'target': 'images', 'source': 'nothing'})
|
|
|
|
self.api.retried_PUT(url, ET.tostring(root))
|
|
|
|
def create_bootstrap_aggregate_meta(self):
|
|
url = self.api.makeurl(['source', self.prj, 'bootstrap-copy', '_meta'])
|
|
|
|
root = ET.Element('package', {'project': self.prj, 'name': 'bootstrap-copy'})
|
|
ET.SubElement(root, 'title')
|
|
ET.SubElement(root, 'description')
|
|
f = ET.SubElement(root, 'build')
|
|
# this one is to toggle
|
|
ET.SubElement(f, 'disable', {'repository': 'bootstrap_copy'})
|
|
# this one is the global toggle
|
|
ET.SubElement(f, 'disable')
|
|
|
|
self.api.retried_PUT(url, ET.tostring(root))
|
|
|
|
def build_switch_bootstrap_copy(self, state):
|
|
url = self.api.makeurl(['source', self.prj, 'bootstrap-copy', '_meta'])
|
|
pkgmeta = ET.parse(self.api.retried_GET(url)).getroot()
|
|
|
|
for f in pkgmeta.find('build'):
|
|
if f.get('repository', None) == 'bootstrap_copy':
|
|
f.tag = state
|
|
pass
|
|
self.api.retried_PUT(url, ET.tostring(pkgmeta))
|
|
|
|
def verify_bootstrap_copy_codes(self, codes):
|
|
url = self.api.makeurl(['build', self.prj, '_result'], {'package': 'bootstrap-copy'})
|
|
|
|
root = ET.parse(self.api.retried_GET(url)).getroot()
|
|
for result in root.findall('result'):
|
|
if result.get('repository') == 'bootstrap_copy':
|
|
status = result.find('status')
|
|
if status is None:
|
|
return False
|
|
if not status.get('code') in codes:
|
|
return False
|
|
return True
|
|
|
|
def perform(self, prj, copy_bootstrap=True):
|
|
self.prj = prj
|
|
|
|
# Depending on what eventually lives in config this may need to change.
|
|
ConfigCommand(self.api).perform([prj], clear=True)
|
|
|
|
if self.api.is_adi_project(prj):
|
|
src_prj = self.api.find_devel_project_from_adi_frozenlinks(self.prj)
|
|
if src_prj is None:
|
|
raise Exception("{} does not have a valid frozenlinks".format(self.prj))
|
|
else:
|
|
self.api.update_adi_frozenlinks(self.prj, src_prj)
|
|
return
|
|
|
|
self.set_links()
|
|
|
|
self.freeze_prjlinks()
|
|
|
|
build_status = self.api.get_flag_in_prj(prj, flag='build')
|
|
|
|
# If there is not a bootstrap repository, there is not
|
|
# anything more to do.
|
|
if not self.is_bootstrap():
|
|
return
|
|
|
|
if copy_bootstrap:
|
|
self.set_bootstrap_copy()
|
|
self.create_bootstrap_aggregate()
|
|
print("waiting for scheduler to disable...")
|
|
while not self.verify_bootstrap_copy_codes(['disabled']):
|
|
time.sleep(1)
|
|
self.build_switch_bootstrap_copy('enable')
|
|
print("waiting for scheduler to copy...")
|
|
while not self.verify_bootstrap_copy_codes(['finished', 'succeeded']):
|
|
time.sleep(1)
|
|
self.build_switch_bootstrap_copy('disable')
|
|
|
|
# Update the version information found in the Test-DVD package, to match openSUSE-release
|
|
if self.api.item_exists(prj, "openSUSE-release"):
|
|
version = self.api.package_version(prj, 'openSUSE-release')
|
|
for arch in ['x86_64', 'ppc64le']:
|
|
self.update_product_version(prj, 'Test-DVD-' + arch, arch, version)
|
|
|
|
# Set the original build status for the project
|
|
self.api.build_switch_prj(prj, build_status)
|
|
|
|
def update_product_version(self, project, product, arch, version):
|
|
if not self.api.item_exists(project, product):
|
|
return None
|
|
|
|
kiwifile = source_file_load(self.api.apiurl, project, product, 'PRODUCT-'+arch+'.kiwi')
|
|
|
|
tmpkiwifile = re.sub(r'<productinfo name="VERSION">.*</productinfo>', '<productinfo name="VERSION">%s</productinfo>' % version, kiwifile)
|
|
newkiwifile = re.sub(r'<productvar name="VERSION">.*</productvar>', '<productvar name="VERSION">%s</productvar>' % version, tmpkiwifile)
|
|
|
|
source_file_save(self.api.apiurl, project, product, 'PRODUCT-' + arch + '.kiwi', newkiwifile)
|
|
|
|
def prj_meta_for_bootstrap_copy(self, prj):
|
|
root = ET.Element('project', {'name': prj})
|
|
ET.SubElement(root, 'title')
|
|
ET.SubElement(root, 'description')
|
|
links = self.projectlinks or ['{}:1-MinimalX'.format(self.api.crings)]
|
|
for lprj in links:
|
|
ET.SubElement(root, 'link', {'project': lprj})
|
|
f = ET.SubElement(root, 'build')
|
|
# this one stays
|
|
ET.SubElement(f, 'disable', {'repository': 'bootstrap_copy'})
|
|
# this one is the global toggle
|
|
ET.SubElement(f, 'disable')
|
|
f = ET.SubElement(root, 'publish')
|
|
ET.SubElement(f, 'disable')
|
|
f = ET.SubElement(root, 'debuginfo')
|
|
ET.SubElement(f, 'enable')
|
|
|
|
r = ET.SubElement(root, 'repository', {'name': 'bootstrap_copy'})
|
|
ET.SubElement(r, 'path', {'project': self.api.cstaging, 'repository': 'standard'})
|
|
for arch in self.api.cstaging_archs:
|
|
a = ET.SubElement(r, 'arch')
|
|
a.text = arch
|
|
|
|
r = ET.SubElement(root, 'repository', {'name': 'standard', 'linkedbuild': 'all', 'rebuild': 'direct'})
|
|
ET.SubElement(r, 'path', {'project': prj, 'repository': 'bootstrap_copy'})
|
|
for arch in self.api.cstaging_archs:
|
|
a = ET.SubElement(r, 'arch')
|
|
a.text = arch
|
|
|
|
r = ET.SubElement(root, 'repository', {'name': 'images', 'linkedbuild': 'all'})
|
|
ET.SubElement(r, 'path', {'project': prj, 'repository': 'standard'})
|
|
|
|
if prj.startswith('SUSE:'):
|
|
a = ET.SubElement(r, 'arch')
|
|
a.text = 'local'
|
|
a = ET.SubElement(r, 'arch')
|
|
a.text = 'x86_64'
|
|
|
|
if 'ppc64le' in self.api.cstaging_archs:
|
|
a = ET.SubElement(r, 'arch')
|
|
a.text = 'ppc64le'
|
|
|
|
return ET.tostring(root)
|
|
|
|
def freeze_prjlinks(self):
|
|
sources = {}
|
|
flink = ET.Element('frozenlinks')
|
|
|
|
for lprj in self.projectlinks:
|
|
fl = ET.SubElement(flink, 'frozenlink', {'project': lprj})
|
|
sources = self.receive_sources(lprj, sources, fl)
|
|
|
|
url = self.api.makeurl(['source', self.prj, '_project', '_frozenlinks'], {'meta': '1'})
|
|
self.api.retried_PUT(url, ET.tostring(flink))
|
|
|
|
def receive_sources(self, prj, sources, flink):
|
|
url = self.api.makeurl(['source', prj], {'view': 'info', 'nofilename': '1'})
|
|
f = self.api.retried_GET(url)
|
|
root = ET.parse(f).getroot()
|
|
|
|
for si in root.findall('sourceinfo'):
|
|
package = self.check_one_source(flink, si)
|
|
sources[package] = 1
|
|
return sources
|
|
|
|
def check_one_source(self, flink, si):
|
|
package = si.get('package')
|
|
|
|
# If the package is an internal one (e.g _product)
|
|
if package.startswith('_'):
|
|
return None
|
|
|
|
# Ignore packages with an origing (i.e. with an origin
|
|
# different from the current project)
|
|
if si.find('originproject') != None:
|
|
return None
|
|
|
|
# we have to check if its a link within the staging project
|
|
# in this case we need to keep the link as is, and not freezing
|
|
# the target. Otherwise putting kernel-source into staging prj
|
|
# won't get updated kernel-default (and many other cases)
|
|
for linked in si.findall('linked'):
|
|
if linked.get('project') in self.projectlinks:
|
|
# take the unexpanded md5 from Factory / 13.2 link
|
|
url = self.api.makeurl(['source', self.api.project, package],
|
|
{'view': 'info', 'nofilename': '1'})
|
|
# print(package, linked.get('package'), linked.get('project'))
|
|
f = self.api.retried_GET(url)
|
|
proot = ET.parse(f).getroot()
|
|
lsrcmd5 = proot.get('lsrcmd5')
|
|
if lsrcmd5 is None:
|
|
raise Exception("{}/{} is not a link but we expected one".format(self.api.project, package))
|
|
ET.SubElement(flink, 'package', {'name': package, 'srcmd5': lsrcmd5, 'vrev': si.get('vrev')})
|
|
return package
|
|
if package in ['rpmlint-mini-AGGR']:
|
|
return package # we should not freeze aggregates
|
|
ET.SubElement(flink, 'package', {'name': package, 'srcmd5': si.get('srcmd5'), 'vrev': si.get('vrev')})
|
|
return package
|
|
|
|
def is_bootstrap(self):
|
|
"""Check if there is a bootstrap copy repository."""
|
|
url = self.api.makeurl(['source', self.prj, '_meta'])
|
|
root = ET.parse(self.api.retried_GET(url)).getroot()
|
|
|
|
for repo in root.findall('.//repository'):
|
|
if 'bootstrap_copy' == repo.get('name'):
|
|
return True
|
|
return False
|