2019-10-09 13:40:59 +02:00
|
|
|
from urllib.parse import quote
|
|
|
|
from urllib.error import HTTPError
|
2018-04-26 13:28:25 +02:00
|
|
|
|
2019-10-09 13:40:59 +02:00
|
|
|
from lxml import etree as ET
|
2014-02-17 13:32:34 +01:00
|
|
|
|
2014-02-28 11:45:06 +01:00
|
|
|
from osc import oscerr
|
|
|
|
from osc.core import makeurl
|
|
|
|
from osc.core import http_GET
|
2014-02-17 13:32:34 +01:00
|
|
|
|
2014-02-18 13:30:39 +01:00
|
|
|
|
2014-03-10 13:37:29 +01:00
|
|
|
def _is_int(x):
|
|
|
|
return isinstance(x, int) or x.isdigit()
|
|
|
|
|
2014-03-10 13:38:05 +01:00
|
|
|
|
|
|
|
class RequestFinder(object):
|
2014-02-17 13:32:34 +01:00
|
|
|
|
2014-08-07 12:39:41 +02:00
|
|
|
def __init__(self, api):
|
2014-03-06 18:22:19 +01:00
|
|
|
"""
|
|
|
|
Store the list of submit request together with the source project
|
|
|
|
|
|
|
|
Example:
|
|
|
|
{
|
|
|
|
212454: {
|
|
|
|
'project': 'openSUSE:Factory',
|
|
|
|
},
|
|
|
|
223870: {
|
|
|
|
'project': 'openSUSE:Factory',
|
|
|
|
'staging': 'openSUSE:Factory:Staging:A',
|
|
|
|
}
|
|
|
|
}
|
|
|
|
"""
|
2014-08-07 12:39:41 +02:00
|
|
|
self.api = api
|
2014-03-03 17:20:40 +01:00
|
|
|
self.srs = {}
|
|
|
|
|
2019-10-09 11:10:08 +02:00
|
|
|
def load_request(self, request_id):
|
2014-03-10 13:37:29 +01:00
|
|
|
if not _is_int(request_id):
|
2019-10-09 11:10:08 +02:00
|
|
|
return None
|
2014-03-10 11:24:47 +01:00
|
|
|
|
2014-08-07 12:39:41 +02:00
|
|
|
url = makeurl(self.api.apiurl, ['request', str(request_id)])
|
2014-02-17 13:32:34 +01:00
|
|
|
try:
|
|
|
|
f = http_GET(url)
|
2018-04-26 13:28:25 +02:00
|
|
|
except HTTPError:
|
2014-02-17 13:32:34 +01:00
|
|
|
return None
|
|
|
|
|
|
|
|
root = ET.parse(f).getroot()
|
|
|
|
|
2014-03-10 11:24:47 +01:00
|
|
|
if root.get('id', None) != str(request_id):
|
2014-02-17 13:32:34 +01:00
|
|
|
return None
|
|
|
|
|
2019-10-09 11:10:08 +02:00
|
|
|
return root
|
|
|
|
|
|
|
|
def find_request_id(self, request_id):
|
|
|
|
"""
|
|
|
|
Look up the request by ID to verify if it is correct
|
|
|
|
:param request_id: ID of the added request
|
|
|
|
"""
|
|
|
|
|
|
|
|
root = self.load_request(request_id)
|
2019-10-09 13:40:59 +02:00
|
|
|
if root is None:
|
2019-10-09 11:10:08 +02:00
|
|
|
return False
|
|
|
|
|
2014-02-17 13:32:34 +01:00
|
|
|
project = root.find('action').find('target').get('project')
|
2015-02-19 10:57:55 +01:00
|
|
|
if (project != self.api.project and not project.startswith(self.api.cstaging)):
|
|
|
|
msg = 'Request {} is not for {}, but for {}'
|
|
|
|
msg = msg.format(request_id, self.api.project, project)
|
2014-03-03 17:20:40 +01:00
|
|
|
raise oscerr.WrongArgs(msg)
|
2014-03-06 18:22:19 +01:00
|
|
|
self.srs[int(request_id)] = {'project': project}
|
2014-03-03 17:20:40 +01:00
|
|
|
|
2014-02-17 13:32:34 +01:00
|
|
|
return True
|
|
|
|
|
2014-03-03 17:20:40 +01:00
|
|
|
def find_request_package(self, package):
|
2014-02-17 13:32:34 +01:00
|
|
|
"""
|
|
|
|
Look up the package by its name and return the SR#
|
|
|
|
:param package: name of the package
|
|
|
|
"""
|
|
|
|
|
2017-08-31 16:33:26 -05:00
|
|
|
query = 'types=submit,delete&states=new,review&project={}&view=collection&package={}'
|
2018-04-26 13:28:25 +02:00
|
|
|
query = query.format(self.api.project, quote(package))
|
2014-08-07 12:39:41 +02:00
|
|
|
url = makeurl(self.api.apiurl, ['request'], query)
|
2014-02-17 13:32:34 +01:00
|
|
|
f = http_GET(url)
|
2014-03-03 17:20:40 +01:00
|
|
|
|
2014-02-17 13:32:34 +01:00
|
|
|
root = ET.parse(f).getroot()
|
|
|
|
|
2015-05-15 12:08:05 +02:00
|
|
|
requests = []
|
2014-03-03 17:20:40 +01:00
|
|
|
for sr in root.findall('request'):
|
2015-07-31 03:28:01 +02:00
|
|
|
# Check the target matches - OBS query is case insensitive, but OBS is not
|
|
|
|
rq_target = sr.find('action').find('target')
|
|
|
|
if package != rq_target.get('package') or self.api.project != rq_target.get('project'):
|
2014-03-06 16:59:27 +01:00
|
|
|
continue
|
|
|
|
|
2015-10-04 10:38:56 +02:00
|
|
|
request = sr.get('id')
|
2014-03-05 17:20:29 +01:00
|
|
|
state = sr.find('state').get('name')
|
|
|
|
|
2015-10-14 17:38:09 +08:00
|
|
|
self.srs[int(request)] = {'project': self.api.project, 'state': state}
|
2015-05-15 12:08:05 +02:00
|
|
|
requests.append(request)
|
2014-03-05 11:13:29 +01:00
|
|
|
|
2015-05-15 12:08:05 +02:00
|
|
|
if len(requests) > 1:
|
|
|
|
msg = 'There are multiple requests for package "{}": {}'
|
|
|
|
msg = msg.format(package, ', '.join(requests))
|
|
|
|
raise oscerr.WrongArgs(msg)
|
2014-03-07 11:37:20 +01:00
|
|
|
|
2015-10-04 10:38:56 +02:00
|
|
|
request = int(requests[0]) if requests else None
|
2015-05-15 12:08:05 +02:00
|
|
|
return request
|
2014-03-03 17:20:40 +01:00
|
|
|
|
2016-07-18 17:43:02 +08:00
|
|
|
def find_request_project(self, source_project, newcand):
|
2014-02-17 13:32:34 +01:00
|
|
|
"""
|
|
|
|
Look up the source project by its name and return the SR#(s)
|
|
|
|
:param source_project: name of the source project
|
2016-07-18 17:43:02 +08:00
|
|
|
:param newcand: the review state of staging-group must be new
|
2014-02-17 13:32:34 +01:00
|
|
|
"""
|
|
|
|
|
2017-08-31 16:33:26 -05:00
|
|
|
query = 'types=submit,delete&states=new,review&project={}&view=collection'.format(self.api.project)
|
2014-08-07 12:39:41 +02:00
|
|
|
url = makeurl(self.api.apiurl, ['request'], query)
|
2014-02-17 13:32:34 +01:00
|
|
|
f = http_GET(url)
|
|
|
|
root = ET.parse(f).getroot()
|
|
|
|
|
|
|
|
ret = None
|
2014-03-03 17:20:40 +01:00
|
|
|
for sr in root.findall('request'):
|
2016-07-18 17:43:02 +08:00
|
|
|
# ensure staging tool don't picks the processed request again
|
|
|
|
if newcand:
|
2016-07-25 22:28:48 +08:00
|
|
|
staging_group_states = [review.get('state') for review in sr.findall('review') if review.get('by_group') == self.api.cstaging_group]
|
2016-07-18 17:43:02 +08:00
|
|
|
if 'new' not in staging_group_states:
|
|
|
|
continue
|
2014-03-03 17:20:40 +01:00
|
|
|
for act in sr.findall('action'):
|
|
|
|
src = act.find('source')
|
|
|
|
if src is not None and src.get('project') == source_project:
|
|
|
|
request = int(sr.attrib['id'])
|
2014-03-10 16:27:29 +01:00
|
|
|
state = sr.find('state').get('name')
|
2015-02-19 10:57:55 +01:00
|
|
|
self.srs[request] = {'project': self.api.project, 'state': state}
|
2014-02-17 13:32:34 +01:00
|
|
|
ret = True
|
|
|
|
|
|
|
|
return ret
|
|
|
|
|
2016-07-18 17:43:02 +08:00
|
|
|
def find(self, pkgs, newcand):
|
2014-02-17 13:32:34 +01:00
|
|
|
"""
|
|
|
|
Search for all various mutations and return list of SR#s
|
|
|
|
:param pkgs: mesh of argumets to search for
|
2016-07-18 17:43:02 +08:00
|
|
|
:param newcand: the review state of staging-group must be new
|
2014-02-17 13:32:34 +01:00
|
|
|
|
2014-03-03 17:20:40 +01:00
|
|
|
This function is only called for its side effect.
|
|
|
|
"""
|
2014-02-17 13:32:34 +01:00
|
|
|
for p in pkgs:
|
2019-10-09 12:58:44 +02:00
|
|
|
if _is_int(p) and self.find_request_id(p):
|
2014-02-17 13:32:34 +01:00
|
|
|
continue
|
2019-10-09 12:58:44 +02:00
|
|
|
if self.find_request_package(p):
|
2014-02-17 13:32:34 +01:00
|
|
|
continue
|
2016-07-18 17:43:02 +08:00
|
|
|
if self.find_request_project(p, newcand):
|
2014-02-17 13:32:34 +01:00
|
|
|
continue
|
2014-03-03 17:20:40 +01:00
|
|
|
raise oscerr.WrongArgs('No SR# found for: {}'.format(p))
|
|
|
|
|
2014-03-04 18:22:37 +01:00
|
|
|
def find_via_stagingapi(self, pkgs):
|
|
|
|
"""
|
|
|
|
Search for all various mutations and return list of SR#s. Use
|
|
|
|
and instance of StagingAPI to direct the search, this makes
|
|
|
|
sure that the SR# are inside a staging project.
|
|
|
|
:param pkgs: mesh of argumets to search for
|
|
|
|
|
|
|
|
This function is only called for its side effect.
|
|
|
|
"""
|
|
|
|
|
2019-11-08 11:45:21 +01:00
|
|
|
url = self.api.makeurl(['staging', self.api.project, 'staging_projects'], { 'requests': 1 })
|
|
|
|
status = ET.parse(self.api.retried_GET(url)).getroot()
|
|
|
|
|
2014-03-04 18:22:37 +01:00
|
|
|
for p in pkgs:
|
|
|
|
found = False
|
2019-11-08 11:45:21 +01:00
|
|
|
for staging in status.findall('staging_project'):
|
2019-11-08 18:04:40 +01:00
|
|
|
for request in staging.findall('staged_requests/request'):
|
|
|
|
if request.get('package') == p or request.get('id') == p:
|
|
|
|
self.srs[int(request.get('id'))] = {'staging': staging.get('name')}
|
|
|
|
found = True
|
|
|
|
break
|
2014-03-04 18:22:37 +01:00
|
|
|
if not found:
|
|
|
|
raise oscerr.WrongArgs('No SR# found for: {}'.format(p))
|
|
|
|
|
2014-03-03 17:20:40 +01:00
|
|
|
@classmethod
|
2016-07-18 17:43:02 +08:00
|
|
|
def find_sr(cls, pkgs, api, newcand=False):
|
2014-03-03 17:20:40 +01:00
|
|
|
"""
|
|
|
|
Search for all various mutations and return list of SR#s
|
|
|
|
:param pkgs: mesh of argumets to search for
|
2014-08-07 12:39:41 +02:00
|
|
|
:param api: StagingAPI instance
|
2016-07-18 17:43:02 +08:00
|
|
|
:param newcand: the review state of staging-group must be new
|
2014-03-03 17:20:40 +01:00
|
|
|
"""
|
2014-08-07 12:39:41 +02:00
|
|
|
finder = cls(api)
|
2016-07-18 17:43:02 +08:00
|
|
|
finder.find(pkgs, newcand)
|
2014-03-03 17:20:40 +01:00
|
|
|
return finder.srs
|
2014-03-04 16:50:49 +01:00
|
|
|
|
|
|
|
@classmethod
|
2014-08-07 12:39:41 +02:00
|
|
|
def find_staged_sr(cls, pkgs, api):
|
2014-03-04 16:50:49 +01:00
|
|
|
"""
|
|
|
|
Search for all various mutations and return a single SR#s.
|
2014-03-04 18:22:37 +01:00
|
|
|
:param pkgs: mesh of argumets to search for (SR#|package name)
|
2014-08-07 12:39:41 +02:00
|
|
|
:param api: StagingAPI instance
|
2014-03-04 16:50:49 +01:00
|
|
|
"""
|
2014-08-07 12:39:41 +02:00
|
|
|
finder = cls(api)
|
2014-03-04 18:22:37 +01:00
|
|
|
finder.find_via_stagingapi(pkgs)
|
|
|
|
return finder.srs
|