EVOLUTION-MANAGER
Edit File: rpackage.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> """ R packages class. """ import ConfigParser import os import re import shutil import sys import tarfile import urllib2 from tarfile import TarError from r2spec import get_logger, get_rpm_tag, R2specError def package_in_repo(url, name): """ Browse the given url of an R repo for the package name provided. Returns the version found upstream if the package is found, None otherwise. :arg url, the url to the PACKAGES file of a R repo. :arg name, the name of the R package. """ log = get_logger() try: stream = urllib2.urlopen(url) content = stream.read() stream.close() sourcemotif = re.compile("Package:\s+%s\n" % name) result = sourcemotif.search(content) if result is not None: log.info("Package found in : %s" % url) versionmotif = re.compile("Package:\s+%s\nVersion:(.*)" % name) version = versionmotif.search(content).group(1).strip() return (version) else: log.info("Not Found: %s in %s" % (name, url)) except IOError, ex: print 'Could not contact the repository at url: %s' % url log.debug('Error: %s' % ex) return None class RPackage(object): """ This class represent information available for R packages. """ def __init__(self, name=None, url=None, source0=None): """ Constructor. """ self.name = name parser = ConfigParser.ConfigParser() parser.read('/etc/R2spec/repos.cfg') self.config = parser self.log = get_logger() self.description = {} self.up_version = None self.down_version = None self.source = None self.arch = None self.url = url self.source0 = source0 def determine_arch(self): """ Determine if the package is arch or noarch by looking at the sources. Set arch to True if the package is arch dependant. Set arch to False if the package is noarch. Let arch to None if could not determine. """ self.log.info('Determining if the package is arch dependant or not') extensions = ['c', 'C', 'cp', 'cpp', 'h', 'H',] if os.path.exists(self.name): for root, dirs, files in os.walk(self.name): for entry in files: if '.' in entry: extension = entry.rsplit('.', 1)[1] if extension in extensions \ or 'f' in extension \ or 'F' in extension: self.arch = True self.log.info('Package is arch dependant') return self.arch = False self.log.info('Package is not arch dependant') return else: self.log.info( 'Could not find the extracted source to search the arch') def download(self, force=False): """ Download the source of the package into the source directory which we retrieve from rpm directly. arg force, boolean whether to force the download of the sources even if they are on the system already. """ sourcedir = get_rpm_tag('_sourcedir') if not os.path.exists(sourcedir): raise R2specError('Folder "%s" does not exist but is required for ' 'R2spec/R2rpm to work' % sourcedir) sources = '%s/%s' % (sourcedir, self.source) if not force and os.path.exists(sources) and os.path.isfile(sources): self.log.info( "Sources are already present, no need to re-download") return url = self.source0.rsplit('/', 1)[0] url = '%s/%s' % (url,self.source) self.log.info('Downloading %s' % url) remotefile = urllib2.urlopen(url) localfile = open(sources, 'w') localfile.write(remotefile.read()) localfile.close() def extract_sources(self): """ Extract the sources into the current directory. """ sourcedir = get_rpm_tag('_sourcedir') tarball = "%s/%s" % (sourcedir, self.source) self.log.info("Opening: %s" % tarball) try: tar = tarfile.open(tarball) tar.extractall() tar.close() except TarError, err: self.log.debug("Error while extracting the tarball") self.log.debug("ERROR: %s" % err) def get(self, key): """ Retrieve the given key from the description information known about the R package. Return an empty string if the key is not known. :arg key, the key to retrieve from the DESCRIPTION file of the R package """ if key and key in self.description.keys(): return self.description[key] else: return '' def get_description(self): """ This function extracts the source and reads the description from in them. """ description = '%s/DESCRIPTION' % self.name self.log.info('Loading "%s"' % description) if os.path.exists(self.name) and os.path.isfile(description): try: stream = open(description, 'r') content = stream.read() stream.close() except IOError, err: self.log.info( 'An error occured while reading the DESCRIPTION file: %s' \ % description) self.log.debug('ERROR: %s' % err) key = None for row in content.split('\n'): if row.strip(): pattern = re.compile("\w:*") if pattern.match(row): key, value = row.split(':', 1) self.description[key.strip()] = value.strip() else: self.description[key] = self.description[key] + ' ' + \ row.strip() else: self.log.info('Could not find a DESCRIPTION file "%s" to read' \ % description) def read_config(self): """ Read the general configuration containing the repo information """ parser = ConfigParser.ConfigParser() configfile = '/etc/R2spec/config' parser.read(configfile) self.config = parser def remove_sources(self): """ Remove the source we extracted in the current working directory. """ self.log.info('Removing extracted sources: "%s"' % self.name) try: shutil.rmtree(self.name) except (IOError, OSError), err: self.log.info('Could not remove the extracted sources: "%s"'\ % self.name) self.log.debug('ERROR: %s' % err) def search_package_in_repo(self): """ Search a package in all R repositories listed in the general configuration file. """ repo = None version = None for section in self.config.sections(): if section.startswith('repo:'): version = package_in_repo(self.config.get(section, 'package'), self.name) if version: repo = section break if version is None: self.log.info( 'Could not find package "%s" in any of the congifure repos' \ % self.name) raise R2specError( 'Could not find package "%s" in any of the configured repos' \ % self.name) self.up_version = version self.down_version = version.replace('-', '.') self.url = self.config.get(repo, 'url') self.source0 = self.config.get(repo, 'source') if self.up_version != self.down_version: self.source0 = self.source0.replace('%{version}', self.up_version) self.source = '%s_%s.tar.gz' % (self.name,self.up_version) def set_repo(self, reponame): """ This function find the URL and Source0 tag for the spec file from the configuration file of the repositories. :arg reponame, the name of the repository in which this package is """ for section in self.config.sections(): if section == 'repo:%s' % reponame: """ Not sure why this format is getting filled out...""" self.url = self.config.get(section, 'url' % (self.name)) self.source0 = self.config.get(section, 'source') break