Allow wrapperRPM to be called as a subtask of a maven build of as a standalone top-level task (by an admin). Subsequent wrapperRPM calls will replace the set of rpms associated with an existing build.
This commit is contained in:
parent
6fc2cca9ff
commit
e7ce66059b
5 changed files with 239 additions and 87 deletions
|
|
@ -2126,6 +2126,11 @@ class BuildMavenTask(BaseTaskHandler):
|
|||
'jars': jars}
|
||||
|
||||
class WrapperRPMTask(BaseTaskHandler):
|
||||
"""Build a wrapper rpm around jars output from a Maven build.
|
||||
Can either be called as a subtask of a maven task or as a separate
|
||||
top-level task. In the latter case it will permanently delete any
|
||||
existing rpms associated with the build and replace them with the
|
||||
newly-built rpms."""
|
||||
|
||||
Methods = ['wrapperRPM']
|
||||
|
||||
|
|
@ -2147,12 +2152,32 @@ class WrapperRPMTask(BaseTaskHandler):
|
|||
def handler(self, spec_url, build_tag, build, task):
|
||||
values = {}
|
||||
|
||||
jarnames = [filename for filename in session.listTaskOutput(task['id']) if \
|
||||
filename.endswith('.jar')]
|
||||
jars = []
|
||||
for jarname in jarnames:
|
||||
jars.append(os.path.join(koji.pathinfo.task(task['id']), jarname))
|
||||
jars.sort()
|
||||
if task:
|
||||
# called as a subtask of a maven build
|
||||
jarnames = [filename for filename in session.listTaskOutput(task['id']) if \
|
||||
filename.endswith('.jar')]
|
||||
jars = []
|
||||
for jarname in jarnames:
|
||||
jars.append(os.path.join(koji.pathinfo.task(task['id']), jarname))
|
||||
jars.sort()
|
||||
else:
|
||||
# called as a top-level task to create or replace wrapper rpms on an existing build
|
||||
# verify that the build is complete
|
||||
if not build['state'] == koji.BUILD_STATES['COMPLETE']:
|
||||
raise koji.BuildError, 'cannot call wrapperRPM on a build that did not complete successfully'
|
||||
|
||||
# get the list of jars from the build instead of the task, because the task output directory may
|
||||
# have already been cleaned up
|
||||
jarinfos = [archive for archive in session.listArchives(buildID=build['id'], type='maven') if \
|
||||
archive['filename'].endswith('.jar')]
|
||||
jars = []
|
||||
for jarinfo in jarinfos:
|
||||
jars.append(os.path.join(koji.pathinfo.mavenbuild(build, jarinfo), jarinfo['filename']))
|
||||
jars.sort()
|
||||
|
||||
if not jars:
|
||||
raise koji.BuildError, 'no jars found for %s' % (task and koji.taskLabel(task) or koji.buildLabel(build))
|
||||
|
||||
values['jars'] = [os.path.basename(jarpath) for jarpath in jars]
|
||||
|
||||
if build:
|
||||
|
|
@ -2277,15 +2302,22 @@ class WrapperRPMTask(BaseTaskHandler):
|
|||
for rpm in [srpm] + rpms:
|
||||
self.uploadFile(os.path.join(resultdir, rpm))
|
||||
|
||||
results = {'buildroot_id': buildroot.id,
|
||||
'srpm': srpm,
|
||||
'rpms': rpms,
|
||||
'logs': logs}
|
||||
|
||||
if not task:
|
||||
# Called as a standalone top-level task, so import the rpms now.
|
||||
# Otherwise we let the parent task handle it.
|
||||
session.host.importWrapperRPMs(self.id, build['id'], results)
|
||||
|
||||
# no need to upload logs, they've already been streamed to the hub
|
||||
# during the build process
|
||||
|
||||
buildroot.expire()
|
||||
|
||||
return {'buildroot_id': buildroot.id,
|
||||
'srpm': srpm,
|
||||
'rpms': rpms,
|
||||
'logs': logs}
|
||||
return results
|
||||
|
||||
class TagBuildTask(BaseTaskHandler):
|
||||
|
||||
|
|
|
|||
34
cli/koji
34
cli/koji
|
|
@ -846,6 +846,40 @@ def handle_maven_build(options, session, args):
|
|||
session.logout()
|
||||
return watch_tasks(session,[task_id])
|
||||
|
||||
def handle_wrapper_rpm(options, session, args):
|
||||
"""[admin] Build wrapper rpms for any jars associated with the build. Any existing rpms will be deleted from the database and the filesystem."""
|
||||
usage = _("usage: %prog wrapper-rpm [options] target build-id|n-v-r URL")
|
||||
usage += _("\n(Specify the --help global option for a list of other help options)")
|
||||
parser = OptionParser(usage=usage)
|
||||
parser.add_option("--nowait", action="store_true", help=_("Don't wait on build"))
|
||||
parser.add_option("--background", action="store_true", help=_("Run the build at a lower priority"))
|
||||
|
||||
(build_opts, args) = parser.parse_args(args)
|
||||
if len(args) < 3:
|
||||
parser.error(_("You must provide a build target, a build ID or NVR, and a SCM URL to a specfile fragment"))
|
||||
assert False
|
||||
activate_session(session)
|
||||
if not session.hasPerm('admin'):
|
||||
print "This action requires admin privileges"
|
||||
return 1
|
||||
|
||||
target = args[0]
|
||||
build_id = args[1]
|
||||
if build_id.isdigit():
|
||||
build_id = int(build_id)
|
||||
url = args[2]
|
||||
priority = None
|
||||
if build_opts.background:
|
||||
priority = 5
|
||||
task_id = session.wrapperRPM(build_id, url, target, priority)
|
||||
print "Created task:", task_id
|
||||
print "Task info: %s/taskinfo?taskID=%s" % (options.weburl, task_id)
|
||||
if _running_in_bg() or build_opts.nowait:
|
||||
return
|
||||
else:
|
||||
session.logout()
|
||||
return watch_tasks(session,[task_id])
|
||||
|
||||
def handle_resubmit(options, session, args):
|
||||
"""Retry a canceled or failed task, using the same parameter as the original task."""
|
||||
usage = _("usage: %prog resubmit [options] taskID")
|
||||
|
|
|
|||
232
hub/kojihub.py
232
hub/kojihub.py
|
|
@ -2629,6 +2629,69 @@ def get_rpm(rpminfo,strict=False):
|
|||
return None
|
||||
return dict(zip(fields,row))
|
||||
|
||||
def list_rpms(buildID=None, buildrootID=None, componentBuildrootID=None, hostID=None, arches=None, queryOpts=None):
|
||||
"""List RPMS. If buildID and/or buildrootID are specified,
|
||||
restrict the list of RPMs to only those RPMs that are part of that
|
||||
build, or were built in that buildroot. If componentBuildrootID is specified,
|
||||
restrict the list to only those RPMs that will get pulled into that buildroot
|
||||
when it is used to build another package. A list of maps is returned, each map
|
||||
containing the following keys:
|
||||
|
||||
- id
|
||||
- name
|
||||
- version
|
||||
- release
|
||||
- nvr (synthesized for sorting purposes)
|
||||
- arch
|
||||
- epoch
|
||||
- payloadhash
|
||||
- size
|
||||
- buildtime
|
||||
- build_id
|
||||
- buildroot_id
|
||||
|
||||
If componentBuildrootID is specified, two additional keys will be included:
|
||||
- component_buildroot_id
|
||||
- is_update
|
||||
|
||||
If no build has the given ID, or the build generated no RPMs,
|
||||
an empty list is returned."""
|
||||
fields = [('rpminfo.id', 'id'), ('rpminfo.name', 'name'), ('rpminfo.version', 'version'),
|
||||
('rpminfo.release', 'release'),
|
||||
("rpminfo.name || '-' || rpminfo.version || '-' || rpminfo.release", 'nvr'),
|
||||
('rpminfo.arch', 'arch'),
|
||||
('rpminfo.epoch', 'epoch'), ('rpminfo.payloadhash', 'payloadhash'),
|
||||
('rpminfo.size', 'size'), ('rpminfo.buildtime', 'buildtime'),
|
||||
('rpminfo.build_id', 'build_id'), ('rpminfo.buildroot_id', 'buildroot_id')]
|
||||
joins = []
|
||||
clauses = []
|
||||
|
||||
if buildID != None:
|
||||
clauses.append('rpminfo.build_id = %(buildID)i')
|
||||
if buildrootID != None:
|
||||
clauses.append('rpminfo.buildroot_id = %(buildrootID)i')
|
||||
if componentBuildrootID != None:
|
||||
fields.append(('buildroot_listing.buildroot_id as component_buildroot_id',
|
||||
'component_buildroot_id'))
|
||||
fields.append(('buildroot_listing.is_update', 'is_update'))
|
||||
joins.append('buildroot_listing ON rpminfo.id = buildroot_listing.rpm_id')
|
||||
clauses.append('buildroot_listing.buildroot_id = %(componentBuildrootID)i')
|
||||
if hostID != None:
|
||||
joins.append('buildroot ON rpminfo.buildroot_id = buildroot.id')
|
||||
clauses.append('buildroot.host_id = %(hostID)i')
|
||||
if arches != None:
|
||||
if isinstance(arches, list) or isinstance(arches, tuple):
|
||||
clauses.append('rpminfo.arch IN %(arches)s')
|
||||
elif isinstance(arches, str):
|
||||
clauses.append('rpminfo.arch = %(arches)s')
|
||||
else:
|
||||
raise koji.GenericError, 'invalid type for "arches" parameter: %s' % type(arches)
|
||||
|
||||
query = QueryProcessor(columns=[f[0] for f in fields], aliases=[f[1] for f in fields],
|
||||
tables=['rpminfo'], joins=joins, clauses=clauses,
|
||||
values=locals(), opts=queryOpts)
|
||||
return query.execute()
|
||||
|
||||
def get_maven_build(buildInfo=None, mavenInfo=None, strict=False):
|
||||
"""
|
||||
Retrieve Maven-specific information about a build.
|
||||
|
|
@ -3464,6 +3527,22 @@ def import_build_in_place(build):
|
|||
_dml(update,locals())
|
||||
return build_id
|
||||
|
||||
def _import_wrapper(task_id, build_info, rpm_results):
|
||||
"""Helper function to import wrapper rpms for a Maven build"""
|
||||
rpm_buildroot_id = rpm_results['buildroot_id']
|
||||
rpm_task_dir = koji.pathinfo.task(task_id)
|
||||
|
||||
for rpm_path in [rpm_results['srpm']] + rpm_results['rpms']:
|
||||
rpm_path = os.path.join(rpm_task_dir, rpm_path)
|
||||
rpm_info = import_rpm(rpm_path, build_info, rpm_buildroot_id)
|
||||
import_rpm_file(rpm_path, build_info, rpm_info)
|
||||
add_rpm_sig(rpm_info['id'], koji.rip_rpm_sighdr(rpm_path))
|
||||
|
||||
for log in rpm_results['logs']:
|
||||
# assume we're only importing noarch packages
|
||||
import_build_log(os.path.join(rpm_task_dir, log),
|
||||
build_info, subdir='noarch')
|
||||
|
||||
def _get_archive_type_by_name(name, strict=True):
|
||||
select = """SELECT id, name, description, extensions FROM archivetypes
|
||||
WHERE name = %(name)s"""
|
||||
|
|
@ -4587,6 +4666,36 @@ class RootExports(object):
|
|||
|
||||
return make_task('maven', [url, target, opts], **taskOpts)
|
||||
|
||||
def wrapperRPM(self, build, url, target, priority=None, channel='maven'):
|
||||
"""Create a top-level wrapperRPM task
|
||||
|
||||
build: The build to generate wrapper rpms for. Must be in the COMPLETE state, and have
|
||||
associated Maven jars.
|
||||
url: SCM URL to a specfile fragment
|
||||
target: The build target to use when building the wrapper rpm. The build_tag of the target will
|
||||
be used to populate the buildroot in which the rpms are built.
|
||||
priority: the amount to increase (or decrease) the task priority, relative
|
||||
to the default priority; higher values mean lower priority; only
|
||||
admins have the right to specify a negative priority here
|
||||
channel: the channel to allocate the task to (defaults to the "maven" channel)
|
||||
|
||||
returns the task ID
|
||||
"""
|
||||
context.session.assertPerm('admin')
|
||||
|
||||
build = self.getBuild(build, strict=True)
|
||||
build_target = self.getBuildTarget(target)
|
||||
if not build_target:
|
||||
raise koji.PreBuildError, 'no such build target: %s' % target
|
||||
build_tag = self.getTag(build_target['build_tag'], strict=True)
|
||||
|
||||
taskOpts = {}
|
||||
if priority:
|
||||
taskOpts['priority'] = koji.PRIO_DEFAULT + priority
|
||||
taskOpts['channel'] = channel
|
||||
|
||||
return make_task('wrapperRPM', [url, build_tag, build, None], **taskOpts)
|
||||
|
||||
def hello(self,*args):
|
||||
return "Hello World"
|
||||
|
||||
|
|
@ -5296,68 +5405,7 @@ class RootExports(object):
|
|||
mapping[int(key)] = mapping[key]
|
||||
return readFullInheritance(tag,event,reverse,stops,jumps)
|
||||
|
||||
def listRPMs(self, buildID=None, buildrootID=None, componentBuildrootID=None, hostID=None, arches=None, queryOpts=None):
|
||||
"""List RPMS. If buildID and/or buildrootID are specified,
|
||||
restrict the list of RPMs to only those RPMs that are part of that
|
||||
build, or were built in that buildroot. If componentBuildrootID is specified,
|
||||
restrict the list to only those RPMs that will get pulled into that buildroot
|
||||
when it is used to build another package. A list of maps is returned, each map
|
||||
containing the following keys:
|
||||
|
||||
- id
|
||||
- name
|
||||
- version
|
||||
- release
|
||||
- nvr (synthesized for sorting purposes)
|
||||
- arch
|
||||
- epoch
|
||||
- payloadhash
|
||||
- size
|
||||
- buildtime
|
||||
- build_id
|
||||
- buildroot_id
|
||||
|
||||
If componentBuildrootID is specified, two additional keys will be included:
|
||||
- component_buildroot_id
|
||||
- is_update
|
||||
|
||||
If no build has the given ID, or the build generated no RPMs,
|
||||
an empty list is returned."""
|
||||
fields = [('rpminfo.id', 'id'), ('rpminfo.name', 'name'), ('rpminfo.version', 'version'),
|
||||
('rpminfo.release', 'release'),
|
||||
("rpminfo.name || '-' || rpminfo.version || '-' || rpminfo.release", 'nvr'),
|
||||
('rpminfo.arch', 'arch'),
|
||||
('rpminfo.epoch', 'epoch'), ('rpminfo.payloadhash', 'payloadhash'),
|
||||
('rpminfo.size', 'size'), ('rpminfo.buildtime', 'buildtime'),
|
||||
('rpminfo.build_id', 'build_id'), ('rpminfo.buildroot_id', 'buildroot_id')]
|
||||
joins = []
|
||||
clauses = []
|
||||
|
||||
if buildID != None:
|
||||
clauses.append('rpminfo.build_id = %(buildID)i')
|
||||
if buildrootID != None:
|
||||
clauses.append('rpminfo.buildroot_id = %(buildrootID)i')
|
||||
if componentBuildrootID != None:
|
||||
fields.append(('buildroot_listing.buildroot_id as component_buildroot_id',
|
||||
'component_buildroot_id'))
|
||||
fields.append(('buildroot_listing.is_update', 'is_update'))
|
||||
joins.append('buildroot_listing ON rpminfo.id = buildroot_listing.rpm_id')
|
||||
clauses.append('buildroot_listing.buildroot_id = %(componentBuildrootID)i')
|
||||
if hostID != None:
|
||||
joins.append('buildroot ON rpminfo.buildroot_id = buildroot.id')
|
||||
clauses.append('buildroot.host_id = %(hostID)i')
|
||||
if arches != None:
|
||||
if isinstance(arches, list) or isinstance(arches, tuple):
|
||||
clauses.append('rpminfo.arch IN %(arches)s')
|
||||
elif isinstance(arches, str):
|
||||
clauses.append('rpminfo.arch = %(arches)s')
|
||||
else:
|
||||
raise koji.GenericError, 'invalid type for "arches" parameter: %s' % type(arches)
|
||||
|
||||
query = QueryProcessor(columns=[f[0] for f in fields], aliases=[f[1] for f in fields],
|
||||
tables=['rpminfo'], joins=joins, clauses=clauses,
|
||||
values=locals(), opts=queryOpts)
|
||||
return query.execute()
|
||||
listRPMs = staticmethod(list_rpms)
|
||||
|
||||
def listBuildRPMs(self,build):
|
||||
"""Get information about all the RPMs generated by the build with the given
|
||||
|
|
@ -6841,20 +6889,7 @@ class HostExports(object):
|
|||
build_info, subdir='maven2')
|
||||
|
||||
if rpm_results:
|
||||
rpm_task_id = rpm_results['task_id']
|
||||
rpm_buildroot_id = rpm_results['buildroot_id']
|
||||
rpm_task_dir = koji.pathinfo.task(rpm_task_id)
|
||||
|
||||
for rpm_path in [rpm_results['srpm']] + rpm_results['rpms']:
|
||||
rpm_path = os.path.join(rpm_task_dir, rpm_path)
|
||||
rpm_info = import_rpm(rpm_path, build_info, rpm_buildroot_id)
|
||||
import_rpm_file(rpm_path, build_info, rpm_info)
|
||||
add_rpm_sig(rpm_info['id'], koji.rip_rpm_sighdr(rpm_path))
|
||||
|
||||
for log in rpm_results['logs']:
|
||||
# assume we're only importing noarch packages
|
||||
import_build_log(os.path.join(rpm_task_dir, log),
|
||||
build_info, subdir='noarch')
|
||||
_import_wrapper(rpm_results['task_id'], build_info, rpm_results)
|
||||
|
||||
# update build state
|
||||
st_complete = koji.BUILD_STATES['COMPLETE']
|
||||
|
|
@ -6865,6 +6900,51 @@ class HostExports(object):
|
|||
# send email
|
||||
build_notification(task_id, build_id)
|
||||
|
||||
def importWrapperRPMs(self, task_id, build_id, rpm_results):
|
||||
"""Import the wrapper rpms and associate them with the given build. Any existing
|
||||
rpms are deleted before import."""
|
||||
host = Host()
|
||||
host.verify()
|
||||
task = Task(task_id)
|
||||
task.assertHost(host.id)
|
||||
|
||||
build_info = get_build(build_id, strict=True)
|
||||
|
||||
if build_info['state'] != koji.BUILD_STATES['COMPLETE']:
|
||||
raise koji.GenericError, 'cannot import wrapper rpms for %s: build state is %s, not complete' % \
|
||||
(koji.buildLabel(build_info), koji.BUILD_STATES[build_info['state']].lower())
|
||||
|
||||
rpms = list_rpms(buildID=build_info['id'])
|
||||
rpmfiles = []
|
||||
for rpm in rpms:
|
||||
# delete rpminfo from the database
|
||||
# this will fail if the rpm has ever been used in a buildroot, which is what we want
|
||||
delete = """DELETE FROM rpmdeps WHERE rpm_id=%(id)i"""
|
||||
_dml(delete, rpm)
|
||||
delete = """DELETE FROM rpmfiles WHERE rpm_id=%(id)i"""
|
||||
_dml(delete, rpm)
|
||||
delete = """DELETE FROM rpmsigs WHERE rpm_id=%(id)i"""
|
||||
_dml(delete, rpm)
|
||||
delete = """DELETE FROM rpminfo WHERE id=%(id)i"""
|
||||
_dml(delete, rpm)
|
||||
rpm_path = os.path.join(koji.pathinfo.build(build_info), koji.pathinfo.rpm(rpm))
|
||||
rpmfiles.append(rpm_path)
|
||||
|
||||
for rpm_path in rpmfiles:
|
||||
os.remove(rpm_path)
|
||||
if not os.listdir(os.path.dirname(rpm_path)):
|
||||
# also remove empty directories
|
||||
os.removedirs(os.path.dirname(rpm_path))
|
||||
|
||||
for log in rpm_results['logs']:
|
||||
# remove previously imported build logs too
|
||||
log_path = os.path.join(koji.pathinfo.build_logs(build_info), 'noarch',
|
||||
os.path.basename(log))
|
||||
if os.path.exists(log_path):
|
||||
os.remove(log_path)
|
||||
|
||||
_import_wrapper(task.id, build_info, rpm_results)
|
||||
|
||||
def failBuild(self, task_id, build_id):
|
||||
"""Mark the build as failed. If the current state is not
|
||||
'BUILDING', or the current competion_time is not null, a
|
||||
|
|
|
|||
|
|
@ -1733,7 +1733,11 @@ def taskLabel(taskInfo):
|
|||
elif method == 'wrapperRPM':
|
||||
if taskInfo.has_key('request'):
|
||||
build_tag = taskInfo['request'][1]
|
||||
extra = build_tag['name']
|
||||
build = taskInfo['request'][2]
|
||||
if build:
|
||||
extra = '%s, %s' % (build_tag['name'], buildLabel(build))
|
||||
else:
|
||||
extra = build_tag['name']
|
||||
elif method == 'buildNotification':
|
||||
if taskInfo.has_key('request'):
|
||||
build = taskInfo['request'][1]
|
||||
|
|
|
|||
|
|
@ -123,7 +123,9 @@ $value
|
|||
#if $params[2]
|
||||
<strong>Build:</strong> <a href="buildinfo?buildID=$params[2].id">$koji.buildLabel($params[2])</a><br/>
|
||||
#end if
|
||||
#if $params[3]
|
||||
<strong>Task:</strong> <a href="taskinfo?taskID=$wrapTask.id">$koji.taskLabel($wrapTask)</a>
|
||||
#end if
|
||||
#elif $task.method == 'newRepo'
|
||||
<strong>Tag:</strong> <a href="taginfo?tagID=$tag.id">$tag.name</a>
|
||||
#elif $task.method == 'prepRepo'
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue