EVOLUTION-MANAGER
Edit File: build.py
#-*- coding: utf-8 -*- # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # # (C) 2011 - Pierre-Yves Chibon <pingou@pingoured.fr> """ Build related class and methods. """ import os import subprocess import shutil import sys from r2spec import get_logger, BuildDepencenciesError, BuildError, get_mock_root class Build: """ Build class Builds the specfile and handles the errors """ def __init__(self): """ Constructor. """ self.specname = '' self.outcode = None self.rpm = None self.buildlog = None self.log = get_logger() self.files = [] # stores the files for the %file section self.deps = [] # stores missing dependencies def build(self, specname, rpmarg='ba', mock_config=False, mock_resultdir=None): """ Builds the given specfile and returns the errors if any. :arg specname, the full path to the spec file to build. :arg rpmarg, the rpmbuild argument used to construct the rpm :arg mock, if not None the package will be built using mock and using the given configuration. """ self.log.info('Building the rpm (this may take some time)') self.buildlog = '%s.build.log' % specname if mock_config is None or mock_config is False: cmd = 'LANG=C rpmbuild -%s %s > %s 2>&1' % (rpmarg, specname, self.buildlog) self.log.debug(cmd) self.outcode = subprocess.call(cmd, shell=True) else: cmd = 'LANG=C rpmbuild -bs %s > %s 2>&1' % ( specname, self.buildlog) self.log.debug(cmd) self.outcode = subprocess.call(cmd, shell=True) self.get_rpm() name = specname.rsplit('R-', 1)[1].split('.spec')[0] mockcommand = 'mock -r %s --uniqueext=%s --rebuild %s' % ( mock_config, name, self.rpm[0]) if mock_resultdir: mockcommand = '%s --cleanup-after --resultdir=%s/%s' % (mockcommand, mock_resultdir, name) cmd = 'LANG=C %s >> %s.build.log 2>&1' % ( mockcommand, specname) self.log.debug(cmd) self.outcode = subprocess.call(cmd, shell=True) if self.outcode == 30: # When mock stop while building the cache, then check # the root.log self.log.debug('mock failed while building the cache') filename = 'root.log' else: filename = 'build.log' if mock_resultdir: self.buildlog = '%s/%s/%s' % (mock_resultdir, name, filename) else: directory = get_mock_root() self.buildlog = '/%s/%s-%s/result/%s' % ( directory, mock_config, name, filename) self.log.debug('buildlog %s' % self.buildlog) def get_rpm(self): """ Parses the build.log to extract the rpm generated. """ try: stream = open(self.buildlog, 'r') log = stream.read() stream.close() logs = log.split("\n") for line in logs: if 'Wrote: ' in line and '.rpm' in line: rpm = line.split('Wrote:')[1].strip() if self.rpm is None: self.rpm = [] self.rpm.append(rpm) else: self.rpm.append(rpm) except IOError, err: self.log.info('Could not read the file "%s"' % self.buildlog) self.log.debug('ERROR: %s' % err) def remove_logs(self): """ Remove the log file generated while building the RPM. """ if os.path.exists(self.buildlog): os.remove(self.buildlog) else: self.log.info('No log file to remove') def parse_error(self, specname): """Parses the build.log to extract the error Generates a file list (file installed but not found) Throw an error Package not found Throw an error Build Time error :arg specname, the path to the spec file. """ try: stream = open(self.buildlog, 'r') log = stream.read() stream.close() except IOError, err: self.log.info('An error occured during the build') self.log.debug('ERROR: %s' % err) print 'Stopping' return(1) logs = log.split('\n') flagfile = False flagdep = False for row in logs: if row == '': flagfile = False if 'Child returncode was: 1' in row \ or 'Installed' in row \ or 'Failed' in row: flagfile = False if flagfile: self.files.append(row) if flagdep: entry = row.split('is needed')[0].replace('\t', '').strip() if entry not in self.deps: self.deps.append(entry) if 'Installed (but unpackaged) file(s) found:' in row: flagfile = True if 'Failed build dependencies:' in row: flagdep = True if 'Error: No Package' in row: raise BuildDepencenciesError(row) if len(self.deps) != 0: dep = " ".join(self.deps) raise BuildDepencenciesError('Dependencies missing: %s' % dep) if len(self.deps) == 0 and len(self.files) == 0 and self.outcode == 1: log = '%s.build.log' % specname raise BuildError( 'An error occured at build time, see the log in %s' % log) return self.files