diff --git a/builder/kojid b/builder/kojid
index a1af3ce5..797ec226 100755
--- a/builder/kojid
+++ b/builder/kojid
@@ -1140,7 +1140,7 @@ class MavenTask(MultiPlatformTask):
rpm_results = None
spec_url = self.opts.get('specfile')
if spec_url:
- rpm_results = self.buildWrapperRPM(spec_url, self.build_task_id, build_tag, build_info, repo_id)
+ rpm_results = self.buildWrapperRPM(spec_url, self.build_task_id, target_info, build_info, repo_id)
if self.opts.get('scratch'):
self.session.host.moveMavenBuildToScratch(self.id, maven_results, rpm_results)
@@ -1352,11 +1352,10 @@ class BuildMavenTask(BaseBuildTask):
'files': output_files}
class WrapperRPMTask(BaseBuildTask):
- """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."""
+ """Build a wrapper rpm around archives output from a Maven or Windows build.
+ May either be called as a subtask or as a separate
+ top-level task. In the latter case it can either associate the new rpms
+ with the existing build or create a new build."""
Methods = ['wrapperRPM']
@@ -1376,10 +1375,10 @@ class WrapperRPMTask(BaseBuildTask):
raise koji.BuildError, "%s is not allowed to be defined in spec file" % tag
def checkHost(self, hostdata):
- tag = self.params[1]
- return self.checkHostArch(tag, hostdata)
+ target = self.params[1]
+ return self.checkHostArch(target['build_tag'], hostdata)
- def handler(self, spec_url, build_tag, build, task, opts=None):
+ def handler(self, spec_url, build_target, build, task, opts=None):
if not opts:
opts = {}
@@ -1499,6 +1498,7 @@ class WrapperRPMTask(BaseBuildTask):
repo_info = self.session.repoInfo(repo_id, strict=True)
event_id = repo_info['create_event']
+ build_tag = self.session.getTag(build_target['build_tag'], strict=True)
br_arch = self.find_arch('noarch', self.session.host.getHost(), self.session.getBuildConfig(build_tag['id'], event=event_id))
buildroot = BuildRoot(self.session, self.options, build_tag['id'], br_arch, self.id, install_group='wrapper-rpm-build', repo_id=repo_id)
@@ -1529,12 +1529,12 @@ class WrapperRPMTask(BaseBuildTask):
localpath = self.localPath(relpath)
# RPM requires all SOURCE files in the srpm to be in the same directory, so
# we flatten any directory structure of the output files here.
- # If multiple files in the build have the same basename, the last one
- # listed will be the one that ends up in the srpm, which is rarely the right
- # thing to do. In this case the build should be putting the output into a
- # zipfile or tarball so that rpmbuild can then expand it in %setup, which
- # will preserve the directory structure.
- shutil.copy(localpath, specdir)
+ # If multiple files in the build have the same basename, duplicate files will
+ # have their relative path prepended to their name, with / replaced with -.
+ destpath = os.path.join(specdir, os.path.basename(relpath))
+ if os.path.exists(destpath):
+ destpath = os.path.join(specdir, relpath.replace('/', '-'))
+ shutil.copy(localpath, destpath)
# change directory to the specdir to the template can reference files there
os.chdir(specdir)
@@ -1570,7 +1570,31 @@ class WrapperRPMTask(BaseBuildTask):
shutil.move(srpm, self.workdir)
srpm = os.path.join(self.workdir, os.path.basename(srpm))
- buildroot.build(srpm)
+ self.new_build_id = None
+ if opts.get('create_build') and not opts.get('scratch'):
+ h = koji.get_rpm_header(srpm)
+ data = koji.get_header_fields(h, ['name', 'version', 'release', 'epoch'])
+ data['task_id'] = self.id
+ self.logger.info("Reading package config for %(name)s" % data)
+ pkg_cfg = self.session.getPackageConfig(build_target['dest_tag'], data['name'])
+ if not opts.get('skip_tag'):
+ # Make sure package is on the list for this tag
+ if pkg_cfg is None:
+ raise koji.BuildError, "package %s not in list for tag %s" \
+ % (data['name'], build_target['dest_tag_name'])
+ elif pkg_cfg['blocked']:
+ raise koji.BuildError, "package %s is blocked for tag %s" \
+ % (data['name'], build_target['dest_tag_name'])
+ self.new_build_id = self.session.host.initBuild(data)
+
+ try:
+ buildroot.build(srpm)
+ except (SystemExit, ServerExit, KeyboardInterrupt):
+ raise
+ except:
+ if self.new_build_id:
+ self.session.host.failBuild(self.id, self.new_build_id)
+ raise
resultdir = buildroot.resultdir()
srpm = None
@@ -1582,6 +1606,8 @@ class WrapperRPMTask(BaseBuildTask):
if not srpm:
srpm = filename
else:
+ if self.new_build_id:
+ self.session.host.failBuild(self.id, self.new_build_id)
raise koji.BuildError, 'multiple srpms found in %s: %s, %s' % \
(resultdir, srpm, filename)
elif filename.endswith('.rpm'):
@@ -1589,27 +1615,64 @@ class WrapperRPMTask(BaseBuildTask):
elif filename.endswith('.log'):
logs.append(filename)
else:
+ if self.new_build_id:
+ self.session.host.failBuild(self.id, self.new_build_id)
raise koji.BuildError, 'unexpected file found in %s: %s' % \
(resultdir, filename)
if not srpm:
+ if self.new_build_id:
+ self.session.host.failBuild(self.id, self.new_build_id)
raise koji.BuildError, 'no srpm found'
if not rpms:
+ if self.new_build_id:
+ self.session.host.failBuild(self.id, self.new_build_id)
raise koji.BuildError, 'no rpms found'
- for rpm in [srpm] + rpms:
- self.uploadFile(os.path.join(resultdir, rpm))
+ try:
+ for rpm in [srpm] + rpms:
+ self.uploadFile(os.path.join(resultdir, rpm))
+ except (SystemExit, ServerExit, KeyboardInterrupt):
+ raise
+ except:
+ if self.new_build_id:
+ self.session.host.failBuild(self.id, self.new_build_id)
+ raise
results = {'buildroot_id': buildroot.id,
'srpm': srpm,
'rpms': rpms,
'logs': logs}
- if not task and not opts.get('scratch'):
- # Called as a standalone top-level task, so import the rpms now.
+ if not task:
+ # Called as a standalone top-level task, so handle the rpms now.
# Otherwise we let the parent task handle it.
- self.session.host.importWrapperRPMs(self.id, build['id'], results)
+ uploaddir = self.getUploadDir()
+ relsrpm = uploaddir + '/' + srpm
+ relrpms = [uploaddir + '/' + r for r in rpms]
+ rellogs = [uploaddir + '/' + l for l in logs]
+ if opts.get('scratch'):
+ self.session.host.moveBuildToScratch(self.id, relsrpm, relrpms, {'noarch': rellogs})
+ else:
+ if opts.get('create_build'):
+ brmap = dict.fromkeys([relsrpm] + relrpms, buildroot.id)
+ try:
+ self.session.host.completeBuild(self.id, self.new_build_id,
+ relsrpm, relrpms, brmap, {'noarch': rellogs})
+ except (SystemExit, ServerExit, KeyboardInterrupt):
+ raise
+ except:
+ self.session.host.failBuild(self.id, self.new_build_id)
+ raise
+ if not opts.get('skip_tag'):
+ tag_task_id = self.session.host.subtask(method='tagBuild',
+ arglist=[build_target['dest_tag'],
+ self.new_build_id, False, None, True],
+ label='tag', parent=self.id, arch='noarch')
+ self.wait(tag_task_id)
+ else:
+ self.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
diff --git a/cli/koji b/cli/koji
index 668500ef..8f087229 100755
--- a/cli/koji
+++ b/cli/koji
@@ -1058,10 +1058,12 @@ def handle_maven_build(options, session, args):
return watch_tasks(session,[task_id],quiet=options.quiet)
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."""
+ """Build wrapper rpms for any archives associated with a build."""
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("--create-build", action="store_true", help=_("Create a new build to contain wrapper rpms"))
+ parser.add_option("--skip-tag", action="store_true", help=_("If creating a new build, don't tag it"))
parser.add_option("--scratch", action="store_true", help=_("Perform a scratch build"))
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"))
@@ -1071,9 +1073,6 @@ def handle_wrapper_rpm(options, session, args):
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]
@@ -1084,6 +1083,10 @@ def handle_wrapper_rpm(options, session, args):
if build_opts.background:
priority = 5
opts = {}
+ if build_opts.create_build:
+ opts['create_build'] = True
+ if build_opts.skip_tag:
+ opts['skip_tag'] = True
if build_opts.scratch:
opts['scratch'] = True
task_id = session.wrapperRPM(build_id, url, target, priority, opts=opts)
diff --git a/hub/kojihub.py b/hub/kojihub.py
index 3b520efe..261b9076 100644
--- a/hub/kojihub.py
+++ b/hub/kojihub.py
@@ -6663,8 +6663,8 @@ class RootExports(object):
def wrapperRPM(self, build, url, target, priority=None, channel='maven', opts=None):
"""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.
+ build: The build to generate wrapper rpms for. Must be in the COMPLETE state and have no
+ rpms already associated with it.
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.
@@ -6675,7 +6675,6 @@ class RootExports(object):
returns the task ID
"""
- context.session.assertPerm('admin')
if not context.opts.get('EnableMaven'):
raise koji.GenericError, "Maven support not enabled"
@@ -6683,7 +6682,7 @@ class RootExports(object):
opts = {}
build = self.getBuild(build, strict=True)
- if list_rpms(build['id']) and not opts.get('scratch'):
+ if list_rpms(build['id']) and not (opts.get('scratch') or opts.get('create_build')):
raise koji.PreBuildError, 'wrapper rpms for %s have already been built' % koji.buildLabel(build)
build_target = self.getBuildTarget(target)
if not build_target:
@@ -6699,7 +6698,7 @@ class RootExports(object):
taskOpts['priority'] = koji.PRIO_DEFAULT + priority
taskOpts['channel'] = channel
- return make_task('wrapperRPM', [url, build_tag, build, None, opts], **taskOpts)
+ return make_task('wrapperRPM', [url, build_target, build, None, opts], **taskOpts)
def winBuild(self, vm, url, target, opts=None, priority=None, channel='vm'):
"""
@@ -9595,8 +9594,8 @@ class HostExports(object):
import_archive(filepath, buildinfo, type, typeInfo)
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."""
+ """Import the wrapper rpms and associate them with the given build. The build
+ must not have any existing rpms associated with it."""
if not context.opts.get('EnableMaven'):
raise koji.GenericError, "Maven support not enabled"
host = Host()
diff --git a/koji/__init__.py b/koji/__init__.py
index 2a116a97..94283019 100644
--- a/koji/__init__.py
+++ b/koji/__init__.py
@@ -2036,12 +2036,12 @@ def taskLabel(taskInfo):
extra = build_tag['name']
elif method == 'wrapperRPM':
if taskInfo.has_key('request'):
- build_tag = taskInfo['request'][1]
+ build_target = taskInfo['request'][1]
build = taskInfo['request'][2]
if build:
- extra = '%s, %s' % (build_tag['name'], buildLabel(build))
+ extra = '%s, %s' % (build_target['name'], buildLabel(build))
else:
- extra = build_tag['name']
+ extra = build_target['name']
elif method == 'winbuild':
if taskInfo.has_key('request'):
vm = taskInfo['request'][0]
diff --git a/koji/tasks.py b/koji/tasks.py
index 54a0a890..79e38dad 100644
--- a/koji/tasks.py
+++ b/koji/tasks.py
@@ -519,9 +519,9 @@ class DependantTask(BaseTaskHandler):
self.wait(subtasks, all=True)
class MultiPlatformTask(BaseTaskHandler):
- def buildWrapperRPM(self, spec_url, build_task_id, build_tag, build, repo_id, **opts):
+ def buildWrapperRPM(self, spec_url, build_task_id, build_target, build, repo_id, **opts):
task = self.session.getTaskInfo(build_task_id)
- arglist = [spec_url, build_tag, build, task, {'repo_id': repo_id}]
+ arglist = [spec_url, build_target, build, task, {'repo_id': repo_id}]
rpm_task_id = self.session.host.subtask(method='wrapperRPM',
arglist=arglist,
diff --git a/vm/kojivmd b/vm/kojivmd
index 6a58544c..7350f43c 100755
--- a/vm/kojivmd
+++ b/vm/kojivmd
@@ -363,7 +363,7 @@ class WinBuildTask(MultiPlatformTask):
rpm_results = None
spec_url = opts.get('specfile')
if spec_url:
- rpm_results = self.buildWrapperRPM(spec_url, task_id, build_tag, build_info, repo_id,
+ rpm_results = self.buildWrapperRPM(spec_url, task_id, target_info, build_info, repo_id,
channel='default')
if opts.get('scratch'):
diff --git a/www/kojiweb/index.py b/www/kojiweb/index.py
index 1aaf93fc..ab6f7dcc 100644
--- a/www/kojiweb/index.py
+++ b/www/kojiweb/index.py
@@ -375,7 +375,7 @@ _TASKS = ['build',
# Tasks that can exist without a parent
_TOPLEVEL_TASKS = ['build', 'buildNotification', 'chainbuild', 'maven', 'wrapperRPM', 'winbuild', 'newRepo', 'tagBuild', 'tagNotification', 'waitrepo', 'createLiveCD', 'createAppliance']
# Tasks that can have children
-_PARENT_TASKS = ['build', 'chainbuild', 'maven', 'winbuild', 'newRepo']
+_PARENT_TASKS = ['build', 'chainbuild', 'maven', 'winbuild', 'newRepo', 'wrapperRPM']
def tasks(req, owner=None, state='active', view='tree', method='all', hostID=None, channelID=None, start=None, order='-id'):
values = _initValues(req, 'Tasks', 'tasks')
@@ -574,8 +574,8 @@ def taskinfo(req, taskID):
deps = [server.getTaskInfo(depID, request=True) for depID in params[0]]
values['deps'] = deps
elif task['method'] == 'wrapperRPM':
- buildTag = params[1]
- values['buildTag'] = buildTag
+ buildTarget = params[1]
+ values['buildTarget'] = buildTarget
if params[3]:
wrapTask = server.getTaskInfo(params[3]['id'], request=True)
values['wrapTask'] = wrapTask
diff --git a/www/kojiweb/taskinfo.chtml b/www/kojiweb/taskinfo.chtml
index d65557d6..0c545ad1 100644
--- a/www/kojiweb/taskinfo.chtml
+++ b/www/kojiweb/taskinfo.chtml
@@ -132,7 +132,12 @@ $value
#end if
#elif $task.method == 'wrapperRPM'
Spec File URL: $params[0]
+ #if 'locked' in $buildTarget
+ #set $buildTag = $buildTarget
Build Tag: $buildTag.name
+ #else
+ Build Target: $buildTarget.name
+ #end if
#if $params[2]
Build: $koji.buildLabel($params[2])
#end if