move the 'freeze' command in a file on its own and implement issue 1515

This commit is contained in:
Stephan Kulow 2014-02-15 16:39:11 +01:00
parent c82d7c03ad
commit b2fff384b2
4 changed files with 252 additions and 58 deletions

View File

@ -267,7 +267,6 @@ def _staging_get_rings(self, opts):
ret[entry.attrib['name']] = prj
return ret
def _staging_one_request(self, rq, opts):
if (opts.verbose):
ET.dump(rq)
@ -309,59 +308,6 @@ def _staging_one_request(self, rq, opts):
self._staging_change_review_state(opts, id, 'accepted', by_group='factory-staging', message=msg)
def _staging_check_one_source(self, flink, si, opts):
package = si.get('package')
# 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 link
url = makeurl(opts.apiurl, ['source', 'openSUSE:Factory', package], { 'view': 'info', 'nofilename': '1' })
#print package, linked.get('package'), linked.get('project')
f = http_GET(url)
proot = ET.parse(f).getroot()
ET.SubElement(flink, 'package', { 'name': package, 'srcmd5': proot.get('lsrcmd5'), 'vrev': si.get('vrev') })
return package
ET.SubElement(flink, 'package', { 'name': package, 'srcmd5': si.get('srcmd5'), 'vrev': si.get('vrev') })
return package
def _staging_receive_sources(self, prj, sources, flink, opts):
url = makeurl(opts.apiurl, ['source', prj], { 'view': 'info', 'nofilename': '1' } )
f = http_GET(url)
root = ET.parse(f).getroot()
for si in root.findall('sourceinfo'):
package = self._staging_check_one_source(flink, si, opts)
sources[package] = 1
return sources
def _staging_freeze_prjlink(self, prj, opts):
url = makeurl(opts.apiurl, ['source', prj, '_meta'])
f = http_GET(url)
root = ET.parse(f).getroot()
sources = dict()
flink = ET.Element('frozenlinks')
links = root.findall('link')
links.reverse()
self.projectlinks = []
for link in links:
self.projectlinks.append(link.get('project'))
for lprj in self.projectlinks:
fl = ET.SubElement(flink, 'frozenlink', { 'project': lprj } )
sources = self._staging_receive_sources(lprj, sources, fl, opts)
url = makeurl(opts.apiurl, ['source', prj, '_project', '_frozenlinks'], { 'meta': '1' } )
f = http_PUT(url, data=ET.tostring(flink))
root = ET.parse(f).getroot()
print ET.tostring(root)
@cmdln.option('-e', '--everything', action='store_true',
help='during check do not stop on first first issue and show them all')
@cmdln.option('-p', '--parent', metavar='TARGETPROJECT',
@ -442,7 +388,8 @@ def do_staging(self, subcmd, opts, *args):
project = args[1]
self._staging_submit_devel(project, opts)
elif cmd in ['freeze']:
self._staging_freeze_prjlink(args[1], opts)
import osclib.freeze_command
osclib.freeze_command.FreezeCommand(opts.apiurl).perform(args[1])
elif cmd in ['select']:
# TODO: have an api call for that
stprj = 'openSUSE:Factory:Staging:%s' % args[1]

192
osclib/freeze_command.py Normal file
View File

@ -0,0 +1,192 @@
import osc
from osc import cmdln
from osc.core import *
import time
class FreezeCommand:
def __init__(self, apiurl):
self.apiurl = apiurl
def set_links(self):
url = makeurl(self.apiurl, ['source', self.prj, '_meta'])
f = http_GET(url)
root = ET.parse(f).getroot()
sources = dict()
flink = ET.Element('frozenlinks')
links = root.findall('link')
links.reverse()
self.projectlinks = []
for link in links:
self.projectlinks.append(link.get('project'))
def set_bootstrap_copy(self):
url = makeurl(self.apiurl, ['source', self.prj, '_meta'])
meta = self.prj_meta_for_bootstrap_copy(self.prj)
http_PUT(url, data=meta)
def create_bootstrap_aggregate(self):
self.create_bootstrap_aggregate_meta()
self.create_bootstrap_aggregate_file()
def bootstrap_packages(self):
url = makeurl(self.apiurl, ['source', 'openSUSE:Factory:Rings:0-Bootstrap'])
f = http_GET(url)
root = ET.parse(f).getroot()
l = list()
for e in root.findall('entry'):
name = e.get('name')
if name in ['rpmlint-mini-AGGR']: continue
l.append(name)
l.sort()
return l
def create_bootstrap_aggregate_file(self):
url = makeurl(self.apiurl, ['source', self.prj, 'bootstrap-copy', '_aggregate'])
root = ET.Element('aggregatelist')
a = ET.SubElement(root, 'aggregate', { 'project': "openSUSE:Factory:Rings:0-Bootstrap" } )
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' } )
http_PUT(url, data=ET.tostring(root))
def create_bootstrap_aggregate_meta(self):
url = makeurl(self.apiurl, ['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')
http_PUT(url, data=ET.tostring(root))
def build_switch_bootstrap_copy(self, state):
url = makeurl(self.apiurl, ['source', self.prj, 'bootstrap-copy', '_meta'])
pkgmeta = ET.parse(http_GET(url)).getroot()
for f in pkgmeta.find('build'):
if f.get('repository', None) == 'bootstrap_copy':
f.tag = state
pass
http_PUT(url, data=ET.tostring(pkgmeta))
def verify_bootstrap_copy_code(self, code):
url = makeurl(self.apiurl, ['build', self.prj, '_result'], { 'package': 'bootstrap-copy' })
root = ET.parse(http_GET(url)).getroot()
for result in root.findall('result'):
if result.get('repository') == 'bootstrap_copy':
if not result.get('code') in ['published', 'unpublished']:
print ET.tostring(result)
return False
if result.find('status').get('code') != code:
print ET.tostring(result)
return False
return True
def perform(self, prj):
self.prj = prj
self.set_links()
self.freeze_prjlinks()
if 'openSUSE:Factory:Rings:1-MinimalX' in self.projectlinks \
and not 'openSUSE:Factory:Rings:0-Bootstrap' in self.projectlinks:
self.set_bootstrap_copy()
self.create_bootstrap_aggregate()
print "waiting for scheduler to disable..."
while not self.verify_bootstrap_copy_code('disabled'):
time.sleep(1)
self.build_switch_bootstrap_copy('enable')
print "waiting for scheduler to copy..."
while not self.verify_bootstrap_copy_code('succeeded'):
time.sleep(1)
self.build_switch_bootstrap_copy('disable')
def prj_meta_for_bootstrap_copy(self, prj):
root = ET.Element('project', { 'name': prj })
ET.SubElement(root, 'title')
ET.SubElement(root, 'description')
ET.SubElement(root, 'link', { 'project': 'openSUSE:Factory:Rings:1-MinimalX' })
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': 'openSUSE:Factory', 'repository': 'ports' })
a = ET.SubElement(r, 'arch')
a.text = 'i586'
a = ET.SubElement(r, 'arch')
a.text = 'x86_64'
r = ET.SubElement(root, 'repository', { 'name': 'standard', 'linkedbuild': 'all', 'rebuild': 'direct' })
ET.SubElement(r, 'path', { 'project': prj, 'repository': 'bootstrap_copy' })
a = ET.SubElement(r, 'arch')
a.text = 'i586'
a = ET.SubElement(r, 'arch')
a.text = 'x86_64'
r = ET.SubElement(root, 'repository', { 'name': 'images', 'linkedbuild': 'all', 'rebuild': 'direct' })
ET.SubElement(r, 'path', { 'project': prj, 'repository': 'standard' })
a = ET.SubElement(r, 'arch')
a.text = 'x86_64'
return ET.tostring(root)
def freeze_prjlinks(self):
sources = dict()
flink = ET.Element('frozenlinks')
for lprj in self.projectlinks:
fl = ET.SubElement(flink, 'frozenlink', { 'project': lprj } )
sources = self.receive_sources(lprj, sources, fl)
url = makeurl(self.apiurl, ['source', self.prj, '_project', '_frozenlinks'], { 'meta': '1' } )
http_PUT(url, data=ET.tostring(flink))
def receive_sources(self, prj, sources, flink):
url = makeurl(self.apiurl, ['source', prj], { 'view': 'info', 'nofilename': '1' } )
f = http_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')
# 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 link
url = makeurl(self.apiurl, ['source', 'openSUSE:Factory', package], { 'view': 'info', 'nofilename': '1' })
#print package, linked.get('package'), linked.get('project')
f = http_GET(url)
proot = ET.parse(f).getroot()
ET.SubElement(flink, 'package', { 'name': package, 'srcmd5': proot.get('lsrcmd5'), 'vrev': si.get('vrev') })
return package
ET.SubElement(flink, 'package', { 'name': package, 'srcmd5': si.get('srcmd5'), 'vrev': si.get('vrev') })
return package

View File

@ -9,6 +9,9 @@ import sys
import contextlib
import unittest
import httpretty
import difflib
import subprocess
import tempfile
# mock is part of python3.3
try:
import unittest.mock
@ -30,6 +33,15 @@ class TestApiCalls(unittest.TestCase):
"""
return os.path.join(os.getcwd(), 'tests/fixtures')
def _get_fixture_path(self, filename):
return os.path.join(self._get_fixtures_dir(), filename)
def _get_fixture_content(self, filename):
response = open(self._get_fixture_path(filename), 'r')
content = response.read()
response.close()
return content
def _register_pretty_url_get(self, url, filename):
"""
Register specified get url with specific filename in fixtures
@ -37,9 +49,7 @@ class TestApiCalls(unittest.TestCase):
:param filename: name of the fixtures file
"""
response = open(os.path.join(self._get_fixtures_dir(), filename), 'r')
content = response.read()
response.close()
content = self._get_fixture_content(filename)
httpretty.register_uri(httpretty.GET,
url,
@ -274,6 +284,22 @@ class TestApiCalls(unittest.TestCase):
data = f.read().strip()
self.assertEqual(sys.stdout.getvalue().strip(), data)
def test_bootstrap_copy(self):
import osclib.freeze_command
fc = osclib.freeze_command.FreezeCommand('http://localhost')
fp = self._get_fixture_path('staging-meta-for-bootstrap-copy.xml')
fixture = subprocess.check_output('/usr/bin/xmllint --format %s' % fp, shell=True)
f = tempfile.NamedTemporaryFile(delete=False)
f.write(fc.prj_meta_for_bootstrap_copy('openSUSE:Factory:Staging:A'))
f.close()
output = subprocess.check_output('/usr/bin/xmllint --format %s' % f.name, shell=True)
for line in difflib.unified_diff(fixture.split("\n"), output.split("\n")):
print line
self.assertEqual(output, fixture)
# Here place all mockable functions
@contextlib.contextmanager

View File

@ -0,0 +1,29 @@
<project name="openSUSE:Factory:Staging:A">
<title></title>
<description></description>
<link project="openSUSE:Factory:Rings:1-MinimalX"/>
<build>
<disable repository="bootstrap_copy"/>
<disable/>
</build>
<publish>
<disable/>
</publish>
<debuginfo>
<enable/>
</debuginfo>
<repository name="bootstrap_copy">
<path project="openSUSE:Factory" repository="ports"/>
<arch>i586</arch>
<arch>x86_64</arch>
</repository>
<repository linkedbuild="all" name="standard" rebuild="direct">
<path project="openSUSE:Factory:Staging:A" repository="bootstrap_copy"/>
<arch>i586</arch>
<arch>x86_64</arch>
</repository>
<repository linkedbuild="all" name="images" rebuild="direct">
<path project="openSUSE:Factory:Staging:A" repository="standard"/>
<arch>x86_64</arch>
</repository>
</project>