1# This file is part of Buildbot. Buildbot is free software: you can 2# redistribute it and/or modify it under the terms of the GNU General Public 3# License as published by the Free Software Foundation, version 2. 4# 5# This program is distributed in the hope that it will be useful, but WITHOUT 6# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 7# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 8# details. 9# 10# You should have received a copy of the GNU General Public License along with 11# this program; if not, write to the Free Software Foundation, Inc., 51 12# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 13# 14# Portions Copyright Buildbot Team Members 15# Portions Copyright Dan Radez <dradez+buildbot@redhat.com> 16# Portions Copyright Steve 'Ashcrow' Milner <smilner+buildbot@redhat.com> 17 18import os 19 20from twisted.internet import defer 21 22from buildbot import config 23from buildbot.process import buildstep 24from buildbot.process import logobserver 25 26 27class RpmBuild(buildstep.ShellMixin, buildstep.BuildStep): 28 29 """ 30 RpmBuild build step. 31 """ 32 33 renderables = ['dist'] 34 name = "rpmbuilder" 35 haltOnFailure = 1 36 flunkOnFailure = 1 37 description = ["RPMBUILD"] 38 descriptionDone = ["RPMBUILD"] 39 40 def __init__(self, 41 specfile=None, 42 topdir='`pwd`', 43 builddir='`pwd`', 44 rpmdir='`pwd`', 45 sourcedir='`pwd`', 46 specdir='`pwd`', 47 srcrpmdir='`pwd`', 48 dist='.el6', 49 define=None, 50 autoRelease=False, 51 vcsRevision=False, 52 **kwargs): 53 kwargs = self.setupShellMixin(kwargs, prohibitArgs=['command']) 54 super().__init__(**kwargs) 55 56 self.dist = dist 57 58 self.base_rpmbuild = ( 59 ('rpmbuild --define "_topdir {}" --define "_builddir {}"' 60 ' --define "_rpmdir {}" --define "_sourcedir {}"' 61 ' --define "_specdir {}" --define "_srcrpmdir {}"').format(topdir, builddir, rpmdir, 62 sourcedir, specdir, 63 srcrpmdir)) 64 65 if define is None: 66 define = {} 67 for k, v in define.items(): 68 self.base_rpmbuild += " --define \"{} {}\"".format(k, v) 69 70 self.specfile = specfile 71 self.autoRelease = autoRelease 72 self.vcsRevision = vcsRevision 73 74 if not self.specfile: 75 config.error("You must specify a specfile") 76 77 self.addLogObserver( 78 'stdio', logobserver.LineConsumerLogObserver(self.logConsumer)) 79 80 @defer.inlineCallbacks 81 def run(self): 82 83 rpm_extras_dict = {} 84 rpm_extras_dict['dist'] = self.dist 85 86 if self.autoRelease: 87 relfile = '{}.release'.format(os.path.basename(self.specfile).split('.')[0]) 88 try: 89 with open(relfile, 'r') as rfile: 90 rel = int(rfile.readline().strip()) 91 except (IOError, TypeError, ValueError): 92 rel = 0 93 rpm_extras_dict['_release'] = rel 94 with open(relfile, 'w') as rfile: 95 rfile.write(str(rel + 1)) 96 97 if self.vcsRevision: 98 revision = self.getProperty('got_revision') 99 # only do this in the case where there's a single codebase 100 if revision and not isinstance(revision, dict): 101 rpm_extras_dict['_revision'] = revision 102 103 self.rpmbuild = self.base_rpmbuild 104 105 # The unit tests expect a certain order, so we sort the dict to keep 106 # format the same every time 107 for k, v in sorted(rpm_extras_dict.items()): 108 self.rpmbuild = '{0} --define "{1} {2}"'.format( 109 self.rpmbuild, k, v) 110 111 command = '{} -ba {}'.format(self.rpmbuild, self.specfile) 112 113 cmd = yield self.makeRemoteShellCommand(command=command) 114 115 yield self.runCommand(cmd) 116 117 stdio_log = yield self.getLog('stdio') 118 yield stdio_log.finish() 119 120 yield self.addCompleteLog('RPM Command Log', "\n".join(self.rpmcmdlog)) 121 if self.rpmerrors: 122 yield self.addCompleteLog('RPM Errors', "\n".join(self.rpmerrors)) 123 124 return cmd.results() 125 126 def logConsumer(self): 127 rpm_prefixes = ['Provides:', 'Requires(', 'Requires:', 128 'Checking for unpackaged', 'Wrote:', 129 'Executing(%', '+ ', 'Processing files:'] 130 rpm_err_pfx = [' ', 'RPM build errors:', 'error: '] 131 self.rpmcmdlog = [] 132 self.rpmerrors = [] 133 134 while True: 135 stream, line = yield 136 for pfx in rpm_prefixes: 137 if line.startswith(pfx): 138 self.rpmcmdlog.append(line) 139 break 140 for err in rpm_err_pfx: 141 if line.startswith(err): 142 self.rpmerrors.append(line) 143 break 144