From b2edd9011ce2ae213dd708cee4df4b140fbc9f8a Mon Sep 17 00:00:00 2001 From: Mike Bonnet Date: Dec 12 2011 20:36:07 +0000 Subject: add "koji wrapper-rpm --create-build" which creates a new build to contain the wrapper rpms --- diff --git a/builder/kojid b/builder/kojid index a1af3ce..797ec22 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 668500e..8f08722 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 3b520ef..261b907 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 2a116a9..9428301 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 54a0a89..79e38da 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 6a58544..7350f43 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 1aaf93f..ab6f7dc 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 d65557d..0c545ad 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