EVOLUTION-MANAGER
Edit File: spec.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> """ Spec class, handles the read/write of the spec file """ import datetime import os import re import sys from jinja2 import Template from r2spec import get_logger, get_rpm_tag, R2specError def format_description(description): """ Format the description as required by rpm """ step = 75 cnt = 0 out = [] char = 0 while cnt < len(description) and char < description.rfind(" "): if len(description[cnt:]) >= step: char = description[cnt: cnt + step].rfind(" ") + cnt out.append(description[cnt: char]) cnt = char + 1 else: out.append(description[cnt:]) cnt += len(description[cnt:]) return "\n".join(out) def format_dependencies(dependencies): """ Format the dependencies cleanning them as much as possible for rpm. """ ignorelist = ['R'] # Regular expression used to determine whether the string is a # version number versionmotif = re.compile('\d\.\d\.?\d?') char = { '\r': '', '(': ' ', ')': ' ', ',': ' ', ' ': ' ', } for key in char.keys(): dependencies = dependencies.replace(key, char[key]) dep_list = [] for dep in dependencies.split(' '): if dep.strip(): if not ">" in dep \ and not "<" in dep \ and not "=" in dep \ and len(versionmotif.findall(dep)) == 0 \ and dep.strip() not in ignorelist: dep = 'R-%s' % dep.strip() dep_list.append(dep) return ' '.join(dep_list).strip() class Spec: """ Spec Class Write the spec file. """ def __init__(self, settings, package=None, no_check=False, no_suggest=False): """ Constructor. """ self.package = package self.settings = settings self.__dict = {} self.log = get_logger() self.spec = None self.no_check = no_check self.no_suggest = no_suggest def add_files(self, files): """ Add to a spec file the given files list. :arg files, list of the files missing from the spec for the rpm to build. This list is generated by the parse_error method from the Build object. """ self.log.info('Add files to the %file section') files.reverse() files = self.generate_files(files) cnt = 0 add = False self.spec = self.spec.split("\n") while cnt < len(self.spec): row = self.spec[cnt] if row.startswith('%changelog'): self.spec.insert(cnt, "") cnt = cnt + 1 add = False if row.startswith('%defattr'): add = True if add: for filename in files: cnt = cnt + 1 self.spec.insert(cnt, filename) cnt = cnt + 1 self.spec = "\n".join(self.spec) def clean_files_section(self): """ Remove all the content of the %files section. """ self.log.info('Clean the spec %files section') cnt = 0 remove = False self.spec = self.spec.split('\n') while cnt < len(self.spec): row = self.spec[cnt] if row.startswith('%changelog'): remove = False if remove: del self.spec[cnt] cnt = cnt - 1 if row.startswith('%defattr'): remove = True cnt = cnt + 1 self.spec = "\n".join(self.spec) def fill_spec_info(self): """ Fills the different variable required for the spec file. """ self.log.info('Filling spec variable from info collected') self.__dict['packname'] = self.package.name self.__dict['arch'] = self.package.arch self.__dict['version'] = self.package.down_version self.__dict['summary'] = self.package.get('Title') self.__dict['license'] = self.package.get('License') self.__dict['URL'] = self.package.url self.__dict['source0'] = self.package.source0 self.__dict['depends'] = format_dependencies( self.package.get('Depends')) self.__dict['imports'] = format_dependencies( self.package.get('Imports')) if not self.no_suggest: self.__dict['suggests'] = format_dependencies( self.package.get('Suggests')) else: self.__dict['suggests'] = "" self.__dict['description'] = format_description( self.package.get('Description')) self.__dict['date'] = datetime.datetime.now( ).strftime("%a %b %d %Y") self.__dict['name'] = self.settings.get('packager') self.__dict['email'] = self.settings.get('email') self.__dict['no_check'] = self.no_check def generate_files(self, files): """ Generate the list of files to add to the spec. :arg files, list of the files missing from the spec for the rpm to build. This list is generated by the parse_error method from the Build object. """ # TODO: deal with case where there no conventionnal file in # the sources: cf gdata macros = { '/usr/share/': '%{_datadir}/', '/usr/lib/': '%{_libdir}/', '/usr/lib64/': '%{_libdir}/', } doc = ['doc', 'html', 'news', 'copying', 'licence', 'citation'] packname = self.package.name linedocs = [] linefiles = [] for filename in files: #print filename if 'R/library/' in filename: folder, name = filename.split('R/library/%s/' % packname) name = name.strip().split('/')[0] if name.lower() in doc: linedocs.append("%doc " + "%%{rlibdir}/%s/" % packname + name) else: linefiles.append("%%{rlibdir}/%s/" % packname + name) else: linefiles.append(filename.strip()) fileout = [] for doc in set(linedocs): fileout.append(doc) for files in set(linefiles): fileout.append(files) return fileout def get_template(self): """ Read the empty template and fills it with the information retrieved. """ template = '%s/specfile.tpl' % os.path.dirname(__file__) self.log.info('Filling spec template') try: stream = open(template, 'r') tplfile = stream.read() stream.close() mytemplate = Template(tplfile) self.spec = mytemplate.render(self.__dict) except IOError, err: self.log.debug('ERROR: %s' % err) raise R2specError('Cannot read the file %s' % template) def get_specfile(self): """ Return the path to the spec file. """ specdir = get_rpm_tag('_specdir') specname = 'R-%s.spec' % self.package.name return '%s/%s' % (specdir, specname) def read_specfile(self): """ Read the specfile present in the spec directory. """ specfile = self.get_specfile() if os.path.exists(specfile) and os.path.isfile(specfile): self.log.info('Reading file %s' % specfile) try: stream = open(specfile, 'r') self.spec = stream.read() stream.close() except IOError, err: self.log.info('Cannot read the file %s' % specfile) self.log.debug('ERROR: %s' % err) def write_spec(self, verbose=False): """ Write down the spec to the spec directory as returned by rpm. """ specfile = self.get_specfile() self.log.info('Writing file %s' % specfile) try: stream = open(specfile, 'w') stream.write(self.spec) stream.close() self.log.debug('Spec file writen: %s' % specfile) if verbose: print 'Spec file writen: %s' % specfile except IOError, err: self.log.info('Cannot write the file %s' % specfile) self.log.debug('ERROR: %s' % err)