#!/usr/bin/python # # Copyright 2013, Intel Inc. # # 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; version 2 of the License. # # 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 Library 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. # native ''' Created on 05 fevr. 2013 @author: ronan@fridu.net ''' import os import shutil import errno RECIPES_SOURCE_DIR = os.path.dirname( os.path.realpath( __file__ ) ) RECIPES_DIR_DEST = os.path.join( RECIPES_SOURCE_DIR, "../meta-tizen-ivi" ) GIT_COMMAND = "git://%s/%s;tag=%s;nobranch=1" import sys import platform from urllib import urlopen from xml.etree import ElementTree try: import cmdln except: print >> sys.stderr, 'Error spec2yocto require "python-cmdln" please install it.' sys.exit( 1 ) import fcntl import subprocess import shlex import re import select import tempfile import ConfigParser # Very useful to debug spec2yocto, print the subprocess EXEC_COMMAND line. DEBUG_RUN = False CONFIGURATION_FILE_PATH = os.path.expanduser( os.path.join( "~", ".spec2yoctorc" ) ) class Spec2yoctoConfig( object ): ''' Parse the file "spec2yocto_configure", ''' def __init__( self ): self.__config_parser = ConfigParser.ConfigParser() self.__config_parser.optionxform = str if not os.path.isfile( CONFIGURATION_FILE_PATH ): print >> sys.stderr, "Warning CONFIGURATION_FILE_PATH \"%s\" do not exist." % (CONFIGURATION_FILE_PATH) print >> sys.stderr," a sample is available in directory \"proto-meta-Tizen_generic/.spec2yoctorc\"" sys.exit(1) self.__config_file = open( CONFIGURATION_FILE_PATH , 'rw' ) self.__config_parser.readfp( self.__config_file ) def get_current_project( self ): ''' return the list of the manifest_meta, manifest_meta can be a file or URL. ''' return self.__get_value( "project", "current" , None ) def get_manifest_meta_list( self, projet ): ''' return the list of the manifest_meta, manifest_meta can be a file or URL. ''' meta_manifests_res = [] list_of_meta_manifest = self.__get_list( projet, "manifest", [] ) for meta_manifest in list_of_meta_manifest: meta_manifests_res.append( meta_manifest.replace( " ", "" ) ) return meta_manifests_res def get_manifest_uri( self, meta_manifest ): ''' return the uri of the manifest. ''' res = self.__get_value( meta_manifest, "uri" , None ) res = os.path.expanduser( res ) res = os.path.expandvars( res ) return res def get_manifest_priority( self, meta_manifest ): ''' return the priority of the manifest. ''' return self.__get_value( meta_manifest, "priority" , 0 ) def get_manifest_default_git_src( self, meta_manifest ): ''' return the default_git_src of the manifest. ''' return self.__get_value( meta_manifest, "default_git_src" , None ) def is_valide_project( self, projet ): ''' check if project is configurate in the conf file. ''' return ( projet in self.__config_parser.sections() ) def get_project_arch( self, projet ): ''' return the default arch of the project. ''' return self.__get_value( projet, "arch", None ) def get_manifest_buildtarget(self, meta_manifest): ''' return the default buildtarget of the project. ''' return self.__get_value( meta_manifest, "buildtarget", None ) def get_working_dir( self, projet ): ''' return the working dir of the project. ''' res = self.__get_value( projet, "working_dir", "/tmp" ) res = os.path.expanduser( res ) res = os.path.expandvars( res ) return res def get_list(self, project, list_name): """ Returns the corresponding list. """ res_list = self.__get_list( project, list_name, [] ) res = [] for element in res_list: res.extend(self.__get_list(element, "list", [])) return res def get_substitute( self , project = None ): res = {} for package in self.__config_parser.options( "substitute" ): package_replace = self.__get_value( "substitute", package, None ) if package_replace is not None: res[package] = package_replace return res def __get_list( self, section, option, default_value ): ''' generic fonction to get list value. ''' if ( section in self.__config_parser.sections() ) and \ ( option in self.__config_parser.options( section ) ): tmp_res = str( self.__config_parser.get( section, option ) ) return tmp_res.replace( " ", "" ).split( "," ) else: return default_value def get_whitelist( self , project ): ''' ''' packages_dico={} whitelist_list=self.__get_list(project,"whitelist", None) for whitelist_v in whitelist_list: whitelist_uri = self.__get_value(whitelist_v,"uri", None ) if whitelist_uri.startswith( "http" ): whitelist_file=download_url( whitelist_uri ) else: f=open(whitelist_uri,'r') whitelist_file=f.read() f.close() for w_pkg in whitelist_file.split("\n"): if len(w_pkg)>1: pkg,path=w_pkg.split("\t") packages_dico[pkg]=path return packages_dico def __get_value( self, section, option, default_value ): ''' generic fonction to get value. ''' if ( section in self.__config_parser.sections() ) and \ ( option in self.__config_parser.options( section ) ): tmp_res = self.__config_parser.get( section, option ) return tmp_res else: return default_value def get_recipes_sources_directory( self, project ): ''' return a list of the recipes directory needed to build the image. ''' res = self.__get_value( project, 'recipes_dir_sources', None ) res = os.path.expanduser( res ) res = os.path.expandvars( res ) return res def get_recipes_group_directory( self, project ): res = self.__get_value( project, 'recipes_dir_group', None ) res = os.path.expanduser( res ) res = os.path.expandvars( res ) return res def get_group( self , project = None ): if project is None: project = self.get_current_project() return self.__get_list( project, 'group', [] ) def get_target_cpu( self , project = None ): ''' return target cpu. ''' if project is None: project = self.get_current_project() return self.__get_value( project, 'arch' , None ) def get_bb_autoreconf_blacklist( self , project = None ): ''' return a list of package with no autoreconf. ''' if project is None: project = self.get_current_project() blacklist_list = self.__get_list( project, "blacklist_autoreconf", [] ) res = [] for blacklist in blacklist_list: res.extend( self.__get_list( blacklist, "blacklist", [] ) ) return res def get_provided_extra( self , project = None ): if project is None: project = self.get_current_project() provided_extra_list = self.__get_list( project, "provided-extra", [] ) provided_extra_dico={} for provided_extra in provided_extra_list: for package in self.__config_parser.options( provided_extra ): provided_list = self.__get_list( provided_extra, package, [] ) provided_extra_dico[package] = provided_list return provided_extra_dico def get_ignore_depend( self ): ''' return the ignore package to ignore for depends (build require). ''' return self.__get_list( 'depends', 'ignore', [] ) def get_ignore_rdepend( self ): ''' return the ignore package to ignore for rdepends (require). ''' return self.__get_list( 'rdepends', 'ignore', [] ) def get_native_depend( self ): ''' some buildRequire mean depends on native package not runtime. ''' return self.__get_list( 'depends', 'native', [] ) def get_cross_depend( self ): ''' some buildRequire mean depends on native package not runtime. ''' return self.__get_list( 'depends', 'cross', [] ) def get_libtool_cross( self ): ''' some buildRequire mean depends on libtool-cross package not runtime. ''' return self.__get_list( 'depends', 'libtool_cross', [] ) def get_inherit_gettext( self ): ''' some buildRequire mean inherit_gettext package not depends runtime. ''' return self.__get_list( 'depends', 'inherit_gettext', [] ) def get_inherit(self, package): ''' some buildRequire mean inherit_cmake package not depends runtime. ''' return [package] def get_group_uri( self, project ): return self.__get_value( project, 'group_uri', None ) SPEC2YOCTO_CONFIG = Spec2yoctoConfig() # Implementation taken from http://hetland.org def levenshtein( a, b ): """Calculates the Levenshtein distance between a and b.""" n, m = len( a ), len( b ) if n > m: # Make sure n <= m, to use O(min(n,m)) space a, b = b, a n, m = m, n current = range( n + 1 ) for i in range( 1, m + 1 ): previous, current = current, [i] + [0] * n for j in range( 1, n + 1 ): add, delete = previous[j] + 1, current[j - 1] + 1 change = previous[j - 1] if a[j - 1] != b[i - 1]: change = change + 1 current[j] = min( add, delete, change ) return current[n] def get_packaging_files( package_path ): res = [] for tmp_res in os.listdir( package_path ): if tmp_res.endswith( ".spec" ) and os.path.isfile( package_path + "/" + tmp_res ): res.append( tmp_res ) return res def findBestSpecFile( package_path, package_name ): """ Find the name of the spec file which matches best with `package_name` """ package_spec_dir = package_path package_spec_dir = os.path.expanduser( package_spec_dir ) package_spec_dir = os.path.expandvars( package_spec_dir ) specFileList = get_packaging_files( package_path ) specFile = None if len( specFileList ) < 1: # No spec file in list specFile = None elif len( specFileList ) == 1: # Only one spec file specFile = specFileList[0] else: sameStart = [] for spec in specFileList: if str( spec[:-5] ) == str( package_name ): # This spec file has the same name as the package specFile = spec break elif spec.startswith( package_name ): # This spec file has a name which looks like the package sameStart.append( spec ) if specFile is None: if len( sameStart ) > 0: # Sort the list of 'same start' by the Levenshtein distance sameStart.sort( key = lambda x: levenshtein( x, package_name ) ) specFile = sameStart[0] else: # No spec file starts with the name of the package, # sort the whole spec file list by the Levenshtein distance specFileList.sort( key = lambda x: levenshtein( x, package_name ) ) specFile = specFileList[0] if specFile is None: msg = "Found no spec file matching package name '%s'" % package_name print msg return -1 spec_full_path = os.path.join( package_spec_dir, specFile ) return spec_full_path def findSpecPatchFiles( patch_dir_path, package_name_list ): """ Find the name of the patch for the spec file which matches best with `package_name` """ patch_list = [] patch_dir_path = os.path.expanduser( patch_dir_path ) patch_dir_path = os.path.expandvars( patch_dir_path ) if package_name_list is not None: for patch_name in set( package_name_list ): for patch_extend in ["", "-yocto"]: patch_file = patch_name + patch_extend + ".spec.patch" patch_path = os.path.join( patch_dir_path, patch_file ) if os.path.isfile( patch_path ): patch_list.append( patch_path ) return patch_list class SubprocessCrt( object ): ''' usefull class to control subprocess ''' def __init__( self ): ''' Initialize subprocess. ''' self.output_res = "" self.__idle_time = 0 def get_last_res( self ): ''' return the last subprocess output. ''' return self.output_res def __read_subprocess_output( self, outputs, f_stdout, f_stderr ): ''' read the stdout, stderr of the subprocess ''' timed_out = True select_timeout = 60 for file_d in select.select( [f_stdout, f_stderr], [], [], select_timeout )[0]: timed_out = False output = file_d.read() if f_stdout == file_d: self.output_res += output else: if DEBUG_RUN and ( len( output ) > 0 ): print "ERROR ****", output, len( output ) for line in output.split( "\n" ): if not line == b"" or not output.endswith( "\n" ): outputs[file_d]["EOF"] = False if line == b"" and not output.endswith( "\n" ): outputs[file_d]["EOF"] = True elif line != "" : res_clean = line.decode( "utf8", "replace" ).rstrip() if DEBUG_RUN: print res_clean if timed_out: self.__idle_time += select_timeout else: self.__idle_time = 0 def exec_subprocess( self, command ): ''' Execute the "command" in a sub process, the "command" must be a valid bash command. _args and _kwargs are for compatibility. ''' self.output_res = "" # need Python 2.7.3 to do shlex.split(command) splitted_command = shlex.split( str( command ) ) a_process = subprocess.Popen( splitted_command, stdout = subprocess.PIPE, stderr = subprocess.PIPE ) f_stdout = a_process.stdout f_stderr = a_process.stderr flags = fcntl.fcntl( f_stdout, fcntl.F_GETFL ) if not f_stdout.closed: fcntl.fcntl( f_stdout, fcntl.F_SETFL, flags | os.O_NONBLOCK ) flags = fcntl.fcntl( f_stderr, fcntl.F_GETFL ) if not f_stderr.closed: fcntl.fcntl( f_stderr, fcntl.F_SETFL, flags | os.O_NONBLOCK ) outputs = {f_stdout: {"EOF": False}, f_stderr: {"EOF": False}} while ( ( not outputs[f_stdout]["EOF"] and not outputs[f_stderr]["EOF"] ) or ( a_process.poll() == None ) ): try: self.__read_subprocess_output( outputs, f_stdout, f_stderr ) except select.error as error: # see http://bugs.python.org/issue9867 if error.args[0] == errno.EINTR: print "Got select.error: %s" % unicode( error ) continue else: raise Exception() # maybe a_process.wait() is better ? poll_res = a_process.poll() if poll_res != 0: return poll_res return self.output_res class RePattern: ''' def of usefull re pattern to parse spec file. ''' pattern_patch = r'([pP]atch[\d]*)[\s]*:[\s]*.*' patternUrlSourceFile = r'Source[\d]*[\s]*:[\s]*([http,ftp].*/)(.*)' patternUrlPatchFile = r'Patch[\d]*[\s]*:[\s]*([http,ftp].*/)(.*)' patternPatch = r'[pP]atch([\d]*)[\s]*:[\s]*(.*)' patternSource = r'Source([\d]*)[\s]*:[\s]*(.*)' patternPatchCommand = r'#(patch)([\d]*)(.*)' patternDescription = r'^Summary:\s*(.*)' patternUrl = r'^Url:\s*(.*)' patternGroup = r'^Group:\s*(.*)' patternLicense = r'^License:\s*(.*)' patternVersion = r'^Version:\s*(.*)' patternFiles = r'^%files\s*(.*)' patternName = r'^Name:\s*(.*)' patternPackage = r'^%package\s*(.*)' provides_package = r'^Provides:\s*(.*)' buildPkgconfig = r'pkgconfig\((.*)\).*' pkgRe = r'([^ \t\n\r\f\v,]+)(?:\s+(<|>|<=|>=|=|==)\s+([^ \t\n\r\f\v,]+))?' buildRequiresPackage = r'^BuildRequires:\s*(.*)' requiresPackage = r'^Requires(?:\(\w+\))?:\s*(.*)' paternDevel = "(.*)-devel" pkgconfig_name = "/usr/lib/pkgconfig/([^*]*).pc" def __init__( self ): ''' init RePattern ''' def get_macro_directory_path( current_cpu ): ''' return all the valid macro directory. ''' macro_paths = "" for macro_dir in ["lib/*", "lib/fileattrs/*", "lib/platform/%s-linux/macros" % current_cpu, "lib/tizen/*", "etc/*", "user/.rpmmacros", "yocto/*"]: macro_paths += os.path.join( "/usr/share/spec2yocto/macro", macro_dir ) + " " return macro_paths class SpecParser: ''' spec file parser ''' mPkgConfigDico = {} msubprocess = SubprocessCrt() def __init__( self, package_spec_path, package_pn = None ): ''' init the SpecParser ''' self.__introduction_section = "introduction_section" self.__package = "%package" self.__description = "%description" self.__prep_flag = "%prep" self.__build_flag = "%build" self.__install_flag = "%install" self.__clean_flag = "%clean" self.__files_flag = "%files" self.__check_flag = "%check" #pkg_preinst, pkg_postinst, pkg_prerm, and pkg_postrm self.__post_flag = "%post" self.__preun_flag = "%preun" self.__postun_flag = "%postun" self.__pre_flag = "%pre" self.__verifyscript_flag = "%verifyscript" self.__changelog_flag = "%changelog" self.__list_section = [self.__package, self.__description, self.__prep_flag, self.__build_flag, self.__install_flag, self.__clean_flag, self.__files_flag, self.__check_flag, self.__post_flag, self.__preun_flag, self.__postun_flag, self.__pre_flag, self.__verifyscript_flag, self.__changelog_flag] self.__package_spec_path = package_spec_path self.__package_pn = package_pn self.__parsed_spec_file = None self.__order_list = [] self.__spect_dico = {} self.__patchs = [] self.__order_raw_list = [] self.__raw_spect_dico = {} self.__cpu = SPEC2YOCTO_CONFIG.get_target_cpu() self.__cpu_native = platform.machine() self.__convert_spec_file() self.__parse_parsed_spec_file() self.__base_name = self.get_name() self.__pkg_config = [] def __find_patch( self ): ''' find the patchs of the spec file. ''' self.__patchs = [] with open( self.__package_spec_path ) as file_d: spec_file = file_d.read() res_tmp = re.findall( RePattern.pattern_patch, spec_file ) for a_res in res_tmp: self.__patchs.append( a_res.replace( "Patch", "patch" ) ) def __is_native_build( self ): ''' return True if the package is native. ''' res_1 = ( self.__package_pn is not None ) if not res_1: return res_1 res_2 = self.__package_pn.endswith( "-native" ) return res_2 def init_rpmspec_command( self ): ''' init rpmspec_command to parse spec file. ''' rpmspec_command = "rpmspec " if self.__is_native_build(): current_cpu = self.__cpu_native else: current_cpu = self.__cpu rpmspec_command += " --macros=\"%s\" " % get_macro_directory_path( current_cpu ) rpmspec_command += " --define='buildroot ${D}' " rpmspec_command += " --define='optflags \\$CFLAGS' " if self.__is_native_build(): # Not the better way to do this rpmspec_command += " --define='basearch i386' " # I guess other tool must be set for native build. rpmspec_command += " --define='__cc gcc' " # the default value of the macro is %{nil} base_prefix = os.getenv( "base_prefix" ) if ( base_prefix != "" ) and ( base_prefix is not None ): rpmspec_command += " --define='_buildPrefix %s' " % base_prefix rpmspec_command += " --define='%find_lang echo no find_lang for package native'" rpmspec_command += " --define='setup #setup' " rpmspec_command += " --define='setup0 #setup0' " package_dir = os.path.dirname( self.__package_spec_path ) rpmspec_command += " --define='SOURCES ${S}/packaging/' " rpmspec_command += " --define='_sourcedir ${S}/packaging/' " rpmspec_command += " --define='BUILD_BASENAME %{basename}' " rpmspec_command += " --define='find_lang #find_lang' " rpmspec_command += " --define='fdupes #fdupes' " rpmspec_command += " --define='lang_package #lang_package' " rpmspec_command += " --define='with_wayland 1' " # need to be change. package_name = os.path.basename( self.__package_spec_path )[:-5] if package_name in SPEC2YOCTO_CONFIG.get_bb_autoreconf_blacklist() : oe_runconf2 = '''oe_runconf2''' rpmspec_command += " --define='%%_configure %s'" % oe_runconf2 return rpmspec_command def __convert_spec_file( self ): ''' init convert spec to expand spec file. ''' tmp_package_spec_path = self.__package_spec_path # we can't use python rpm API to parse the spec file so we need to exec rpmspec\ # in a subprocess and parse the result. rpmspec_command = self.init_rpmspec_command() # it's import to remove all "Source" url because if rpm dan't find the source,\ # it try to downloads the file from the url. with open( tmp_package_spec_path, 'r' ) as current_spec_file: current_spec_string = current_spec_file.read() res_url_source_files = re.findall( RePattern.patternUrlSourceFile, current_spec_string ) if len( res_url_source_files ) > 0: for res_url in res_url_source_files: long_url = res_url[0] + res_url[1] short_url = res_url[1] current_spec_string = current_spec_string.replace( long_url, short_url ) with tempfile.NamedTemporaryFile( mode = 'w', suffix = '.tmp', prefix = os.path.basename( tmp_package_spec_path ) + ".", dir = os.path.dirname( tmp_package_spec_path ), delete = False ) as tmp_spec_file: tmp_spec_file.write( current_spec_string ) tmp_package_spec_path = tmp_spec_file.name # same case as "Source" with open( tmp_package_spec_path, 'r' ) as current_spec_file: current_spec_string = current_spec_file.read() res_url_patch_file = re.findall( RePattern.patternUrlPatchFile, current_spec_string ) if len( res_url_patch_file ) > 0: for res_url in res_url_patch_file: long_url = res_url[0] + res_url[1] short_url = res_url[1] current_spec_string = current_spec_string.replace( long_url, short_url ) if ( tmp_package_spec_path != self.__package_spec_path ) \ and os.path.isfile( tmp_package_spec_path ) \ and not DEBUG_RUN: os.remove( tmp_package_spec_path ) with tempfile.NamedTemporaryFile( mode = 'w', suffix = '.tmp', prefix = os.path.basename( tmp_package_spec_path ) + ".", dir = os.path.dirname( tmp_package_spec_path ), delete = False ) as tmp_spec_file: tmp_spec_file.write( current_spec_string ) tmp_package_spec_path = tmp_spec_file.name self.__find_patch() for a_patch in self.__patchs: if a_patch == "patch0": rpmspec_command += " --define='%patch #patch' " rpmspec_command += " --define='%s #%s' " % ( a_patch, a_patch ) rpmspec_command += " --define='debug_package %{nil}'" rpmspec_command += " --parse %s " % tmp_package_spec_path if DEBUG_RUN: print "rpmspec_command :", rpmspec_command self.__parsed_spec_file = SpecParser.msubprocess.exec_subprocess( rpmspec_command ) if ( tmp_package_spec_path != self.__package_spec_path ) \ and os.path.isfile( tmp_package_spec_path ) \ and not DEBUG_RUN: os.remove( tmp_package_spec_path ) if self.__parsed_spec_file == 1: print >> sys.stderr, "" print >> sys.stderr, "ERROR CMD: %s" % rpmspec_command print >> sys.stderr, "parse error for spec file %s" % ( tmp_package_spec_path ) self.__parsed_spec_file = None return 1 if DEBUG_RUN: if not os.path.isdir( "/tmp/parsed_spec" ): os.makedirs( "/tmp/parsed_spec" ) if self.__package_pn is None: tmp_path = os.path.basename( self.__package_spec_path ) package_parsed_spec_path = os.path.join( "/tmp/parsed_spec", tmp_path ) else: tmp_path = "%s.spec" % self.__package_pn package_parsed_spec_path = os.path.join( "/tmp/parsed_spec", tmp_path ) with open( package_parsed_spec_path, "w" ) as file_d: file_d.write( self.__parsed_spec_file ) def __test_section( self, line ): ''' test if the line is the start of a new section. ''' for sect in self.__list_section: if line.startswith( sect ): return True return False def __parse_parsed_spec_file( self ): ''' parse a spec file by section after rpmspec. ''' # ordered dico is not provide yet... self.__order_list = [] self.__spect_dico = {} current_section = self.__introduction_section self.__spect_dico[current_section] = [] self.__order_list.append( current_section ) if self.__parsed_spec_file is None: return 1 for line in self.__parsed_spec_file.split( "\n" ): if self.__test_section( line ) : if line in self.__spect_dico.keys(): print "line %s" % line print "--------------------------------------" print "parsedSpecFile: %s" % self.__package_spec_path print "--------------------------------------" error_msg = "ERROR for the spec file \"%s\" this section \"%s\" is not unique." print error_msg % ( self.__parsed_spec_file, line ) # raise Exception() current_section = line self.__spect_dico[current_section] = [] self.__order_list.append( current_section ) self.__spect_dico[current_section].append( line ) def parse_raw_spec_file( self ): ''' parse a spec file by section before rpmspec. ''' # need to be rewrite # ordered dico is not provide yet... self.__order_raw_list = [] self.__raw_spect_dico = {} current_section = self.__introduction_section self.__raw_spect_dico[current_section] = [] self.__order_raw_list.append( current_section ) with open( self.__package_spec_path, "r" ) as file_d: parsed_raw_spec_file = file_d.read() for line in parsed_raw_spec_file.split( "\n" ): if self.__test_section( line ) : if line in self.__raw_spect_dico.keys(): print "line %s" % line print "--------------------------------------" print "parsedSpecFile: %s" % self.__package_spec_path print "--------------------------------------" error_msg = "ERROR for the spec file \"%s\" this section \"%s\" is not unique." print error_msg % ( self.__parsed_spec_file, line ) raise Exception() current_section = line self.__raw_spect_dico[current_section] = [] self.__order_raw_list.append( current_section ) self.__raw_spect_dico[current_section].append( line ) def get_prep_section( self ): ''' return the prep section of the spec file. ''' res_prep_section = "cd ${S}\n" pattern_patch_dico = {} pattern_source_dico = {} for line in self.__spect_dico[self.__introduction_section][1:]: for patch_id, files_name in re.findall( RePattern.patternPatch, line ): if patch_id == "": patch_id = "0" pattern_patch_dico[patch_id] = files_name for source_id, files_name in re.findall( RePattern.patternSource, line ): if source_id == "": source_id = "0" pattern_source_dico[source_id] = files_name for line in self.__spect_dico[self.__prep_flag][1:]: if line.startswith( "#setup" ): splited_line = line.split() for i in range( len( splited_line ) ): if splited_line[i].startswith( "-a" ): if len( splited_line[i] ) > len( "-a" ): setup_id = splited_line[i].replace( "-a", "" ) else: setup_id = splited_line[i + 1] res_prep_section += "#extracte source %s \n" % setup_id res_prep_section += "pushd ${S}\n" source = os.path.basename( pattern_source_dico[setup_id] ) # not a good way to do this if source.endswith( "rpmlintrc" ): res_prep_section += "cp ${S}/packaging/%s .\n" % source else: file_name = os.path.basename( pattern_source_dico[setup_id] ) res_prep_section += "unp ${S}/packaging/%s \n" % file_name res_prep_section += "popd \n" elif splited_line[i].startswith( "-b" ): if len( splited_line[i] ) > len( "-b" ): setup_id = splited_line[i].replace( "-b", "" ) else: setup_id = splited_line[i + 1] res_prep_section += "#extracte source %s \n" % ( setup_id ) res_prep_section += "pushd ${S}/../\n" source = os.path.basename( pattern_source_dico[setup_id] ) if source.endswith( "rpmlintrc" ): res_prep_section += "cp ${S}/packaging/%s .\n" % source else: res_prep_section += "unp ${S}/packaging/%s \n" % source res_prep_section += "popd \n" res_prep_section += "chmod -Rf a+rX,u+w,g-w,o-w ${S}\n" elif line.startswith( "#patch" ): res_findall = re.findall( RePattern.patternPatchCommand, line ) # should be rewrite for patch_name, patch_id, EXEC_COMMAND in res_findall: if patch_id == '': patch_id = "0" files_name = pattern_patch_dico[patch_id] if "-p" not in EXEC_COMMAND: EXEC_COMMAND += " -p0" if files_name.endswith( ".bz2" ): bzcat_cmd = "bzcat ${S}/packaging/%s | patch -s %s --fuzz=2\n" bzcat_val = ( files_name, EXEC_COMMAND.replace( " -b", " -b --suffix" ) ) res_prep_section += bzcat_cmd % bzcat_val else: cat_cmd = "cat ${S}/packaging/%s | patch -s %s --fuzz=2\n" cat_val = ( files_name, EXEC_COMMAND.replace( " -b", " -b --suffix" ) ) res_prep_section += cat_cmd % cat_val res_prep_section += line + "\n" return res_prep_section def get_build_section( self ): ''' return the build section of the spec file. ''' res_build_section = "cd ${S}\n" if self.__build_flag not in self.__spect_dico.keys(): return 1 for line in self.__spect_dico[self.__build_flag][1:]: res_build_section += line + "\n" return res_build_section def get_raw_build_section( self ): ''' return the raw build section of the spec file. ''' res_raw_build_section = "" if self.__build_flag not in self.__spect_dico.keys(): return "" for line in self.__raw_spect_dico[self.__build_flag][1:]: res_raw_build_section += line + "\n" return res_raw_build_section def get_clean_raw( self ): ''' clean the raw spec file to generate spec file for yocto packaging. ''' res_clean_raw = "" for sect in self.__order_raw_list: if sect == self.__introduction_section: for line in self.__raw_spect_dico[sect]: if line.startswith("Version:"): res_clean_raw += "Version: git\n" else: have_findall_source = len( re.findall( RePattern.patternSource , line ) ) > 0 have_findall_patch = len( re.findall( RePattern.patternPatch, line ) ) > 0 if not( have_findall_source or have_findall_patch ): res_clean_raw += line + "\n" elif sect == self.__prep_flag: res_clean_raw += line + "%prep\n" res_clean_raw += line + "#FAKE\n" elif sect == self.__build_flag: res_clean_raw += line + "%build\n" res_clean_raw += line + "#FAKE\n" elif sect == self.__install_flag: res_clean_raw += line + "%install\n" res_clean_raw += line + "#FAKE\n" elif sect == self.__check_flag: pass elif sect == self.__clean_flag: pass elif sect == self.__changelog_flag: pass elif sect.startswith( "%files" ): for line in self.__raw_spect_dico[sect]: if line.startswith( '%manifest ' ): res_clean_raw += line[len('%manifest '):] + "\n" elif line.startswith( '%doc ' ): pass elif line.startswith( '%ghost ' ): pass elif line.startswith( '%exclude ' ): pass elif line.startswith( '%license' ): pass else: res_clean_raw += line + "\n" else: for line in self.__raw_spect_dico[sect]: res_clean_raw += line + "\n" clean_raw_command = self.init_rpmspec_command() tmp_package_spec_path = self.__package_spec_path with tempfile.NamedTemporaryFile( mode = 'w', suffix = '.tmp', prefix = os.path.basename( tmp_package_spec_path ) + ".", dir = os.path.dirname( tmp_package_spec_path ), delete = False ) as tmp_spec_file: tmp_spec_file.write( res_clean_raw ) tmp_package_spec_path = tmp_spec_file.name clean_raw_command += " --define='debug_package %{nil}'" clean_raw_command += " --define='docs_package %{nil}'" clean_raw_command += " --parse %s " % tmp_package_spec_path if DEBUG_RUN: print "clean_raw_command :", clean_raw_command parsed_spec_file = SpecParser.msubprocess.exec_subprocess( clean_raw_command ) if os.path.isfile( tmp_package_spec_path ) and not DEBUG_RUN: os.remove( tmp_package_spec_path ) if parsed_spec_file == 1: print >> sys.stderr, "parse error for spec file %s" % ( tmp_package_spec_path ) parsed_spec_file = None return 1 fake_dbg = ''' %%package -n %s-dbg Summary: #FAKE - Debugging files Group: devel %%description -n %s-dbg #FAKE %%files -n %s-dbg %%defattr(-,-,-,-) ''' % ( self.__base_name, self.__base_name, self.__base_name ) work_dir = os.getenv( "WORKDIR" ) if work_dir is None: return parsed_spec_file base_root = os.path.join( work_dir, "package" ) for root, dirs, files in os.walk( base_root ): if root.endswith( ".debug" ): if DEBUG_RUN: print "find directory %s " % dirs for a_file in files: fake_dbg += os.path.join( root, a_file ).replace( base_root, "" ) + "\n" #Test don't add dbg files #return parsed_spec_file + fake_dbg return parsed_spec_file def get_install_section( self ): ''' return the install section. ''' res_install_section = "cd ${S}\n" for line in self.__spect_dico[self.__install_flag][1:]: res_install_section += line + "\n" return res_install_section def get_description( self ): ''' return the description of the spec file. ''' for line in self.__spect_dico[self.__introduction_section] : description = re.findall( RePattern.patternDescription, line ) if len( description ) > 0: return description[0] return "" def get_homepage( self ): ''' return the homepage of the spec file project. ''' for line in self.__spect_dico[self.__introduction_section] : description = re.findall( RePattern.patternUrl, line ) if len( description ) > 0: return description[0] return "" def get_section( self ): ''' return the section of the spec file project. ''' for line in self.__spect_dico[self.__introduction_section] : description = re.findall( RePattern.patternGroup, line ) if len( description ) > 0: return description[0] return "System/Base" def get_license( self ): ''' return the licence of the package. ''' for line in self.__spect_dico[self.__introduction_section] : description = re.findall( RePattern.patternLicense, line ) if len( description ) > 0: res_license = description[0] if ";" in res_license: res_license = res_license.replace( ";", "" ) return res_license return "" def get_version(self): ''' Return the version of the package. ''' for line in self.__spect_dico[self.__introduction_section] : description = re.findall(RePattern.patternVersion, line) if len( description ) > 0: return description[0] return "" def get_section_key(self, __flag): ''' Return the list of "__flag" sections of the spec file. ''' res_section = [] for section_key in self.__spect_dico.keys(): if section_key.startswith(__flag): res_section.append(section_key) return res_section def get_script_section_key_pre(self): ''' Return the list of pre script section of the spec file. get_section_key() can't be used in this case since it will also return the %preun and %prep results. ''' res_script_section = [] for section_key in self.__spect_dico.keys(): if section_key.startswith("%pre") and \ not section_key.startswith("%preun") and \ not section_key.startswith("%prep"): res_script_section.append(section_key) return res_script_section def get_script_section_key_post(self): ''' Return the list of post script section of the spec file. get_section_key() can't be used in this case since it will also return the %postun results. ''' res_script_section = [] for section_key in self.__spect_dico.keys(): if section_key.startswith("%post") and not section_key.startswith("%postun"): res_script_section.append(section_key) return res_script_section def get_files_list_from_section( self, package_section_name ): ''' return a list of file ''' res_list = [] config_list=[] manifest_list=[] dir_list=[] for line in self.__spect_dico[package_section_name][1:]: if not line.startswith( "%" ) and not line == "": line = line.replace( "//", "/" ) res_list.append( line ) elif line.startswith( "%attr(" ): line = line.replace( "//", "/" ) pkg_f_clean=line.split(")") pkg_f=pkg_f_clean[-1].strip() res_list.append( pkg_f ) elif line.startswith( "%doc " ): line = line.replace( "//", "/" ) res_list.append( line.replace( "%doc ", "" ) ) elif line.startswith( "%dir " ): line = line.replace( "//", "/" ) file_name = line.replace( "%dir ", "" ) dir_list.append( file_name ) res_list.append( file_name ) elif line.startswith( "%config " ): line = line.replace( "//", "/" ) file_name = line.replace( "%config ", "" ) config_list.append( file_name ) res_list.append( file_name ) elif line.startswith( "%manifest " ): line = line.replace( "//", "/" ) file_name = line.replace( "%manifest ", "" ) manifest_list.append( file_name ) #res_list.append( file_name ) elif line.startswith( "%config(noreplace) " ): line = line.replace( "//", "/" ) res_list.append( line.replace( "%config(noreplace) ", "" ) ) elif line.startswith( "%config(" ): line = line.replace( "//", "/" ) pkg_f_clean=line.split(")") pkg_f=pkg_f_clean[-1].strip() res_list.append( pkg_f ) else: pass #return res_list,config_list return res_list,config_list, manifest_list, dir_list def get_script_from_section(self, __flag): ''' Return the pre/post script section of the spec file. ''' res_script_section = "" if __flag in self.__spect_dico.keys(): for line in self.__spect_dico[__flag][1:]: res_script_section += line + "\n" return res_script_section def get_files_packages( self ): ''' return a dictinaire with package for key and list of files fo value. ''' res_dico = {} for package_section_name in self.get_section_key("%file"): tmp_package_name = package_section_name # Need to get info of the first line. if "-f " in tmp_package_name: tmp_split = tmp_package_name.split( "-f " ) tmp_package_name = tmp_split[0] package = re.findall( RePattern.patternFiles, tmp_package_name ) if len( package ) > 0: if "-n " in package[0]: package_name = package[0].replace( "-n ", "" ) else: package_name = self.__base_name pkg_ext = package[0].replace( " ", "" ) if len( pkg_ext ) > 0: package_name += "-" + pkg_ext else: package_name = self.__base_name package_name = package_name.replace( " ", "" ) res_list,config_list, manifest_list, dir_list = self.get_files_list_from_section( package_section_name ) res_dico[ package_name ] = res_list,config_list, manifest_list, dir_list #db_src=self.__base_name+"-debugsource" #if db_src not in res_dico: # res_dico[db_src] = [] #dbinfo=self.__base_name+"-debug" #if dbinfo not in res_dico: # res_dico[dbinfo] = [] return res_dico def get_name( self ): ''' return the name of the package ''' for line in self.__spect_dico[self.__introduction_section]: description = re.findall( RePattern.patternName, line ) if len( description ) > 0: return description[0] return "" def get_provides( self ): ''' return all provide service by each package of the spec file. ''' provide_res = {} provide_res[self.__base_name] = [] provide_res[self.__base_name].append( [self.__base_name] ) for k in self.__spect_dico.keys(): package = re.findall( RePattern.patternPackage, k ) if len( package ) > 0: package_name = self.__clean_package_name( package[0] ) provide_res[ package_name ] = [] provide_res[ package_name ].append( [package_name] ) if len( package ) > 0 or ( k == self.__introduction_section ): for line in self.__spect_dico[k]: provides = re.findall( RePattern.provides_package, line ) for provides_line in provides: for tmp_clean in self.__clean_package_line( provides_line ): if k == self.__introduction_section: provide_res[self.__base_name].append( tmp_clean ) else: provide_res[package_name].append( tmp_clean ) return provide_res def __clean_package_name( self, package_name ): ''' return the package name from spec declaration. ''' # re should be better. if "-n " in package_name: package_name = package_name.replace( "-n ", "" ).replace( " ", "" ) else: package_name = self.__base_name + "-" + package_name return package_name def get_rdepends( self ): ''' return all require service by each package of the spec file. ''' rdepends_res = {} for k in self.__spect_dico.keys(): package = re.findall( RePattern.patternPackage, k ) if len( package ) > 0: package_name = self.__clean_package_name( package[0] ) else: package_name = self.__base_name if len( package ) > 0 or ( k == self.__introduction_section ): requires_list = self.get_requires( self.__spect_dico[k] ) rdepends_res[package_name] = requires_list return rdepends_res def get_depends( self ): ''' return all build require service by each package of the spec file. ''' depends_res = {} for k in self.__spect_dico.keys(): package = re.findall( RePattern.patternPackage, k ) if len( package ) > 0: package_name = self.__clean_package_name( package[0] ) if len( package ) > 0 or ( k == self.__introduction_section ): build_requires_list = self.get_build_requires( self.__spect_dico[k] ) if ( k == self.__introduction_section ): depends_res[self.__base_name] = build_requires_list else: depends_res[package_name] = build_requires_list return depends_res def __clean_package_line( self, package_line ): ''' return package list from package declaration in spec file. ''' res_first = re.findall( RePattern.pkgRe, package_line ) if len( res_first ) == 0: print "__clean_package_line faild for %s" % self.__package_spec_path raise Exception() # should be rewrite cleaner. res_final = [] for init_res in res_first: init_res = list( init_res ) init_res[0] = init_res[0].replace( ",", "" ) res_final.append( init_res ) return res_final def get_build_requires( self, lines ): ''' return the line of every build requires. ''' package_replacement = SPEC2YOCTO_CONFIG.get_substitute() build_requires_res = [] pkgconfig = 0 for line in lines: build_requires = re.findall( RePattern.buildRequiresPackage, line ) for tmp_res in build_requires: # If a dependency uses pkgconfig, explicitely add pkgconfig as a dependency. if pkgconfig == 0 and 'pkgconfig' in tmp_res: build_requires_res.append(['pkgconfig', '', '']) pkgconfig = 1 for tmp_clean in self.__clean_package_line( tmp_res ): if len( tmp_clean ) >= 1: if tmp_clean[0] in package_replacement.keys(): tmp_clean[0] = package_replacement[tmp_clean[0]] build_requires_res.append( tmp_clean ) return build_requires_res def get_requires( self, lines ): ''' return the line of every requires. ''' package_replacement = SPEC2YOCTO_CONFIG.get_substitute() requires_res = [] for line in lines: build_requires = re.findall( RePattern.requiresPackage, line ) for tmp_res in build_requires: for tmp_clean in self.__clean_package_line( tmp_res ): if len( tmp_clean ) >= 1: if tmp_clean[0] in package_replacement.keys(): tmp_clean[0] = package_replacement[tmp_clean[0]] requires_res.append( tmp_clean ) return requires_res class MetaSpec: ''' meta spec file for generate yocto bb. ''' mProvidesDico = {} mExtraRProvidesDico = {} mCrossPackageBlacklist = [] mInitialPackageBlacklist = [] mNativePackageBlacklist = [] mOePackageBlacklist = [] def __init__( self, package_recipes_dir, package_name, package_meta_path, package_spec_path, package_git_srv_src, package_git_srv_path, package_git_tag ): ''' init the MetaSpec class ''' self.__package_name = package_name.replace( "_", "-" ) self.__package_meta_path=package_meta_path self.__package_git_srv_src = package_git_srv_src self.__package_git_srv_path = package_git_srv_path self.__package_spec_path = package_spec_path self.__git_tag = package_git_tag self.__spec_parser = SpecParser( self.__package_spec_path ) self.__package_spec_name = self.__spec_parser.get_name() self.__packages_dico = self.__spec_parser.get_files_packages() self.__provides_dico = self.__spec_parser.get_provides() self.setm_provided_dico() self.__rdepends_dico = self.__spec_parser.get_rdepends() self.__package_name = self.__spec_parser.get_name().replace( "_", "-" ) self.__package_recipes_dir = os.path.join(package_recipes_dir,self.__package_meta_path) self.__base_file = self.__package_name + ".inc" #self.__base_depends_file = self.__package_name + "-depends.inc" #self.__base_rdepends_file = self.__package_name + "-rdepends.inc" #self.__base_provides_file = self.__package_name + "-rprovides.inc" self.__extra_conf_file = self.__package_name + "-extraconf.inc" #self.__extra_native_conf_file = self.__package_name + "-native-extraconf.inc" #self.__extra_oe_conf_file = self.__package_name + "-oe-extraconf.inc" self.__git_native_file = self.__package_name + "-native_git.bb" self.__git_oe_file = self.__package_name + "_git.bb" self.__createRecipes() def setm_provided_dico( self ): ''' add provides_list for package_name to mProvidesDico ''' provides_list = [] for k_provide in self.__provides_dico.keys(): for p_provide in self.__provides_dico[k_provide]: provides_list.append( p_provide[0] ) for p_provide in self.__packages_dico.keys(): provides_list.extend( self.__packages_dico[p_provide][0] ) for package in self.__packages_dico.keys(): for pkg_file in self.__packages_dico[package][0]: pkgconfig_name_res = re.findall( RePattern.pkgconfig_name, pkg_file ) for tmp_res in pkgconfig_name_res: provides_list.append( "pkgconfig(%s)" % tmp_res ) if self.__package_name not in MetaSpec.mProvidesDico.keys(): MetaSpec.mProvidesDico[self.__package_name] = [] MetaSpec.mProvidesDico[self.__package_name].extend( provides_list ) def set_mextra_provided_dico( self ): ''' add provides_list for package_name to mExtraRProvidesDico ''' provides_list = [] for k_provide in self.__provides_dico.keys(): for p_provide in self.__provides_dico[k_provide]: provides_list.append( p_provide[0] ) for p_provide in self.__packages_dico.keys(): provides_list.extend( self.__packages_dico[p_provide][0] ) MetaSpec.mExtraRProvidesDico[self.__package_name] = provides_list def __create_base_file( self ): ''' create the base file of the bb file. ''' bb_path = os.path.join( self.__package_recipes_dir, self.__base_file ) with open( bb_path, "w" ) as file_d: _description = self.__spec_parser.get_description() _homepage = self.__spec_parser.get_homepage() _section = self.__spec_parser.get_section() _priority = "10" _license = self.__spec_parser.get_license() _version = self.__spec_parser.get_version() file_d.write( "DESCRIPTION = \"%s\"\n" % _description ) if len( _homepage ) < 2: _homepage = "http://nohomepage.org" file_d.write( "HOMEPAGE = \"%s\"\n" % _homepage ) file_d.write( "SECTION = \"%s\"\n" % _section ) file_d.write( "LICENSE = \"%s\"\n" % _license ) file_d.write( "PV = \"%s\"\n" % _version ) file_d.write( "\n" ) file_d.write( "SRC_URI = \"\"\n" ) file_d.write( "\n" ) file_d.write( "S = \"${WORKDIR}/git\"\n" ) file_d.write( "\n" ) file_d.write( "inherit manifest autotools-brokensep\n" ) file_d.write( "\n" ) file_d.write( "BBCLASSEXTEND = \"\"\n" ) self.__create_provides_file( file_d) self.__create_rdepends( file_d) self.__create_depends( file_d) self.__create_patch( file_d) self.__create_configure( file_d) self. __create_compile( file_d) self.__create_install( file_d) self.__create_script_file( file_d) self.__create_files_packaging( file_d ) file_d.write( "require %s\n\n" % self.__extra_conf_file ) def __create_files_packaging(self,file_d): file_d.write( "PACKAGES = \"${PN}-dbg ${PN}-doc ${PN}-locale\"\n" ) for package in self.__packages_dico.keys(): pkg_yocto_name=package for res_pkg_devel in re.findall( RePattern.paternDevel, pkg_yocto_name ): pkg_yocto_name=pkg_yocto_name.replace("-devel","-dev") if pkg_yocto_name not in [self.__package_name+"-dbg", self.__package_name+"-doc", self.__package_name+"-locale", ]: file_d.write( "PACKAGES += \" %s \"\n" % pkg_yocto_name ) file_d.write( "\n" ) _license = self.__spec_parser.get_license() for package in self.__packages_dico.keys(): pkg_yocto_name=package for res_pkg_devel in re.findall( RePattern.paternDevel, pkg_yocto_name ): pkg_yocto_name=pkg_yocto_name.replace("-devel","-dev") file_d.write( "%s_files = \"\"\n" % pkg_yocto_name ) pkg_list, config_list, manifest_list, dir_list = self.__packages_dico[package] for pkg_f in pkg_list: pkg_f=pkg_f.strip() if pkg_f.startswith( _license ): pass else: pkg_yocto_name = package.replace("-devel","-dev") file_d.write( "%s_files += \"%s\"\n" % ( pkg_yocto_name, pkg_f ) ) pkg_yocto_name_short = pkg_yocto_name.replace( self.__package_name, "${PN}" ) if len(config_list)>0: file_d.write( "CONFFILES_%s = \"\"\n" % ( pkg_yocto_name_short ) ) for pkg_f in config_list: file_d.write( "CONFFILES_%s += \"%s\"\n" % ( pkg_yocto_name_short, pkg_f ) ) if (len(manifest_list) == 1) : file_d.write( "MANIFESTFILES_%s = \"%s\"\n" % ( pkg_yocto_name_short, manifest_list[0] ) ) elif (len(manifest_list) > 1) : msg="ERROR Too many manifest for \"%s\" " % self.__package_name print >> sys.stderr, colorize( msg, "red" ) if len(dir_list)>0: file_d.write( "DIRFILES_%s = \"\"\n" % ( pkg_yocto_name_short ) ) for pkg_f in dir_list: file_d.write( "DIRFILES_%s += \"%s\"\n" % ( pkg_yocto_name_short, pkg_f ) ) file_d.write( "\n" ) for package in self.__packages_dico.keys(): p_parse = package.replace( self.__package_name, "${PN}" ) p_parse = p_parse.replace("-devel","-dev") pkg_yocto_name = package.replace("-devel","-dev") file_d.write( "FILES_%s = \"${%s_files}\"\n" % ( p_parse, pkg_yocto_name ) ) file_d.write( "\n" ) for package in self.__packages_dico.keys(): pkg_yocto_name = package.replace("-devel","-dev") file_d.write( "PKG_%s= \"%s\"\n" % (pkg_yocto_name,pkg_yocto_name) ) file_d.write( "\n" ) def __create_patch( self ,file_d): code=self.__spec_parser.get_prep_section() code=code.replace("\n","\n ") file_d.write( "do_prep() {\n" ) file_d.write( " %s\n" % code ) file_d.write( "}\n" ) file_d.write( "do_patch_append() {\n" ) file_d.write( " bb.build.exec_func('do_prep', d)\n" ) file_d.write( "}\n" ) file_d.write( "\n" ) def __create_configure( self ,file_d): file_d.write( "do_configure() {\n" ) file_d.write( "}\n" ) file_d.write( "\n" ) def __create_compile( self ,file_d): EXTRA_OECONF = None code=self.__spec_parser.get_build_section() code=code.replace("\n","\n ") file_d.write( "do_compile() {\n" ) if code.count("autotools_do_configure") == 1 : code_line=code.replace("\\\n"," ").split("\n") for line in code_line: if "autotools_do_configure" in line: post= line.split("autotools_do_configure")[0] EXTRA_OECONF = line.split("autotools_do_configure")[1] file_d.write( "%sautotools_do_configure\n" % post) else: file_d.write( " %s\n" % line ) elif code.count("autotools_do_configure") > 1 : msg="ERROR more than 1 autotools_do_configure for \"%s\"" % self.__package_name print >> sys.stderr, colorize( msg, "red" ) else: file_d.write( " %s\n" % code ) file_d.write( "}\n" ) if EXTRA_OECONF is not None: while EXTRA_OECONF.count(" "): EXTRA_OECONF=EXTRA_OECONF.replace(" "," ") file_d.write( "EXTRA_OECONF += \"%s\"\n" % EXTRA_OECONF ) file_d.write( "\n" ) def __create_install( self ,file_d): code=self.__spec_parser.get_install_section() code=code.replace("\n","\n ") code=code.replace("\n EOF","\nEOF") file_d.write( "do_install() {\n" ) file_d.write( " export RPM_BUILD_ROOT=${D}\n" ) file_d.write( " %s\n" % code ) file_d.write( "}\n" ) file_d.write( "\n" ) def __create_script_file_section_code( self, spec_section): ''' Returns the command executed in one of the %pre, %post, %preun or %postun section of a spec file. ''' code = self.__spec_parser.get_script_from_section(spec_section) command_list = code.split("\n") formated_code = "" for line in command_list: if line != "": formated_code += " " + line + "\n" return formated_code def __create_script_file_write( self, file_d, code, recipe_section, package_name): ''' Writes the pre/post (un)install sections of the recipe. ''' code=code.replace("/sbin/ldconfig","[ \"x$D\" == \"x\" ] && ldconfig") code=code.replace("${prefix}","$D${prefix}") file_d.write("%s%s() {\n" % (recipe_section, package_name)) file_d.write(" #!/bin/sh -e\n\n") file_d.write("%s\n" % code) file_d.write("}\n") file_d.write("\n") def __create_script_file_session(self, file_d, flag, script_name, script_sections): ''' Add script for the given flag. ''' for section in script_sections: code = "" # If %section is a one line script such as: "%post -p /sbin/ldconfig" if " -p " in section: # Remove the package name if present to only keep the command section_split = section.split(" -p ")[1].split(" -n ") code = " " + section_split[0].strip() else: code = self.__create_script_file_section_code(section) if code != "": # Set the package name package_name = "${PN}" # If the package name is not the project name if " -n " in section: # Remove the command if any to only keep the package name section_split = section.split(" -n ")[1].split(" -p ") package_name = section_split[0].strip() self.__create_script_file_write(file_d, code, script_name, package_name) def __create_script_file(self, file_d): ''' Add the pre/post install/uninstall sections of a spec file to the recipe. ''' script_sections = self.__spec_parser.get_script_section_key_pre() self.__create_script_file_session(file_d, "%pre", "pkg_preinst_", script_sections) script_sections = self.__spec_parser.get_script_section_key_post() self.__create_script_file_session(file_d, "%post", "pkg_postinst_", script_sections) script_sections = self.__spec_parser.get_section_key("%preun") self.__create_script_file_session(file_d, "%preun", "pkg_prerm_", script_sections) script_sections = self.__spec_parser.get_section_key("%postun") self.__create_script_file_session(file_d, "%postun", "pkg_postrm_", script_sections) def __create_provides_file( self ,file_d): ''' generate provide file. ''' file_d.write( "PROVIDES = \"\"\n" ) file_d.write( "\n" ) for k_provide in self.__provides_dico.keys(): pkg_yocto_name=k_provide for res_pkg_devel in re.findall( RePattern.paternDevel, pkg_yocto_name ): pkg_yocto_name=pkg_yocto_name.replace("-devel","-dev") if len( self.__provides_dico[k_provide] ) > 0: file_d.write( "#PROVIDES by %s\n" % pkg_yocto_name.replace(" ","") ) if pkg_yocto_name != self.__package_name: file_d.write( "PROVIDES += \"%s\"\n" % ( pkg_yocto_name ) ) for p_provide in self.__provides_dico[k_provide]: pkg = p_provide[0] pkg_yocto=pkg for res_pkg_devel in re.findall( RePattern.paternDevel, pkg_yocto ): pkg_yocto=pkg_yocto.replace("-devel","-dev") if not len( p_provide ) == 1: provide_text = "# the PROVIDES rules is ignore \"%s %s %s\"\n" file_d.write( provide_text % ( pkg_yocto, p_provide[1], p_provide[2] ) ) if ( pkg == "mktemp" and self.__package_name == "tizen-coreutils" ): continue if pkg_yocto_name != pkg_yocto: file_d.write( "PROVIDES += \"%s\"\n" % ( pkg_yocto ) ) file_d.write( "RPROVIDES_%s += \"%s\"\n" % ( pkg_yocto_name, pkg_yocto ) ) #for res_pkg_devel in re.findall( RePattern.paternDevel, pkg ): # rprovide_text = "RPROVIDES_%s += \"%s\"\n" # file_d.write( rprovide_text % ( k_provide, res_pkg_devel + "-dev" ) ) if len( self.__provides_dico[k_provide] ) > 0: file_d.write( "\n\n" ) def __create_git_native_file( self ): ''' create bb native file. ''' bb_native_path = os.path.join( self.__package_recipes_dir, self.__git_native_file ) with open( bb_native_path, "w" ) as file_d: file_d.write( "require %s\n" % self.__base_file ) file_d.write( "\n" ) file_d.write( "PRIORITY = \"9\"\n" ) file_d.write( "\n" ) file_d.write( "inherit native\n" ) file_d.write( "\n" ) file_d.write( "S = \"${WORKDIR}/git\"\n" ) file_d.write( "\n" ) md5_value = "801f80980d171dd6425610833a22dbe6" file_value = "${COMMON_LICENSE_DIR}/GPL-2.0" file_chksum_text = "LIC_FILES_CHKSUM ??= \"file://%s;md5=%s\"\n" # should be generat file_d.write( file_chksum_text % ( file_value, md5_value ) ) file_d.write( "\n" ) command_source = "SRC_URI += \"%s\"\n" % GIT_COMMAND file_d.write( command_source % ( self.__package_git_srv_src , self.__package_git_srv_path , self.__git_tag ) ) #file_d.write( "require %s\n" % self.__extra_native_conf_file ) file_d.write( "\n" ) def __create_git_oe_file( self ): ''' generate bb file. ''' bb_path = os.path.join( self.__package_recipes_dir, self.__git_oe_file ) with open( bb_path, "w" ) as file_d: file_d.write( "require %s\n" % self.__base_file ) file_d.write( "\n" ) file_d.write( "PRIORITY = \"10\"\n" ) file_d.write( "\n" ) md5_value = "801f80980d171dd6425610833a22dbe6" file_value = "${COMMON_LICENSE_DIR}/GPL-2.0" file_chksum_text = "LIC_FILES_CHKSUM ??= \"file://%s;md5=%s\"\n" # should be generat file_d.write( file_chksum_text % ( file_value, md5_value ) ) file_d.write( "\n" ) command_source = "SRC_URI += \"" + GIT_COMMAND + "\"\n" file_d.write( command_source % ( self.__package_git_srv_src , self.__package_git_srv_path , self.__git_tag ) ) #file_d.write( "require %s\n" % self.__extra_oe_conf_file ) file_d.write( "\n" ) if self.__package_name not in MetaSpec.mNativePackageBlacklist: file_d.write( "BBCLASSEXTEND += \" native \"" ) file_d.write( "\n\n" ) def __createRecipes( self ): ''' generate all bb file. ''' if self.__package_recipes_dir is None: return if not os.path.isdir( self.__package_recipes_dir ): os.makedirs( self.__package_recipes_dir ) # Just touch a file #rdepends_path = os.path.join( self.__package_recipes_dir, self.__base_rdepends_file ) #open( rdepends_path, "a" ).close() #depends_path = os.path.join( self.__package_recipes_dir, self.__base_depends_file ) #open( depends_path, "a" ).close() #provides_path = os.path.join( self.__package_recipes_dir, self.__base_provides_file ) #open( provides_path, "a" ).close() extra_conf_file_path = os.path.join( self.__package_recipes_dir, self.__extra_conf_file ) open( extra_conf_file_path, "a" ).close() #extranative_path = os.path.join( self.__package_recipes_dir, self.__extra_native_conf_file ) #open( extranative_path, "a" ).close() #extra_oe_conf_path = os.path.join( self.__package_recipes_dir, self.__extra_oe_conf_file ) #open( extra_oe_conf_path, "a" ).close() self.__create_base_file() if not self.__package_name not in MetaSpec.mNativePackageBlacklist: bb_native_path = os.path.join( self.__package_recipes_dir, self.__git_native_file ) if os.path.isfile( bb_native_path ): os.unlink( bb_native_path ) #self.__create_provides_file() if self.__package_name not in MetaSpec.mOePackageBlacklist: self.__create_git_oe_file() else: bb_oe_path = os.path.join( self.__package_recipes_dir, self.__git_oe_file ) if os.path.isfile( bb_oe_path ): os.unlink( bb_oe_path ) def __create_rdepends( self ,file_d): ''' generate rdepends file. ''' if self.__package_recipes_dir is None: return if not os.path.isdir( self.__package_recipes_dir ): os.makedirs( self.__package_recipes_dir ) #rdepends_path = os.path.join( self.__package_recipes_dir, self.__base_rdepends_file ) package_replacement = SPEC2YOCTO_CONFIG.get_substitute() if file_d is not None: file_d.write( "RDEPENDS = \"\"\n" ) for k_provide in self.__rdepends_dico.keys(): pkg_yocto_name=k_provide for res_pkg_devel in re.findall( RePattern.paternDevel, pkg_yocto_name ): pkg_yocto_name=pkg_yocto_name.replace("-devel","-dev") res_rdepends = set() k_provide_replace = pkg_yocto_name.replace( self.__package_name, "${PN}" ) if len( self.__rdepends_dico[k_provide] ) > 0: file_d.write( "#RDEPENDS of %s (%s)\n" % ( pkg_yocto_name, k_provide_replace ) ) for provide in self.__rdepends_dico[k_provide]: package_provide = provide[0] res = None for k_package_provide in MetaSpec.mExtraRProvidesDico.keys(): if package_provide in MetaSpec.mExtraRProvidesDico[k_package_provide] \ or package_provide == k_package_provide: res = k_package_provide break if res is None: res = package_provide if res in package_replacement.keys(): res = package_replacement[res] res_rdepends.add( res ) for pkg in res_rdepends: res_pkg_devel = re.findall( RePattern.paternDevel, pkg ) if len( res_pkg_devel ) > 0: rdepends_value = "RDEPENDS_%s += \"%s\"\n" file_d.write( rdepends_value % ( k_provide_replace, res_pkg_devel[0] + "-dev" ) ) else: if not pkg in SPEC2YOCTO_CONFIG.get_ignore_rdepend(): file_d.write( "RDEPENDS_%s += \"%s\"\n" % ( k_provide_replace, pkg ) ) if len( self.__rdepends_dico[k_provide] ) > 0: file_d.write( "\n" ) file_d.write( "\n" ) def __create_depends( self, file_d): ''' create depends file. ''' if self.__package_recipes_dir is None: return if not os.path.isdir( self.__package_recipes_dir ): os.makedirs( self.__package_recipes_dir ) depends_dico = self.__spec_parser.get_depends() #depends_path = os.path.join( self.__package_recipes_dir, self.__base_depends_file ) ignore_depend_list = SPEC2YOCTO_CONFIG.get_ignore_depend() native_depend_list = SPEC2YOCTO_CONFIG.get_native_depend() cross_depend_list = SPEC2YOCTO_CONFIG.get_cross_depend() if file_d is not None: file_d.write( "DEPENDS = \"\"\n" ) res_depends = set() for k_provide in depends_dico.keys(): if len( depends_dico[k_provide] ) > 0: file_d.write( "#DEPENDS of %s\n" % k_provide ) for p_provide in depends_dico[k_provide]: pp_provide = p_provide[0] res = None if pp_provide in ignore_depend_list: continue for k in MetaSpec.mProvidesDico.keys(): if pp_provide in MetaSpec.mProvidesDico[k] or pp_provide == k: res = k break for k_package_provide in MetaSpec.mExtraRProvidesDico.keys(): if pp_provide in MetaSpec.mExtraRProvidesDico[k_package_provide]: res = k_package_provide break if res is None: if pp_provide not in SPEC2YOCTO_CONFIG.get_inherit_gettext() and \ pp_provide not in SPEC2YOCTO_CONFIG.get_inherit("python") and \ pp_provide not in SPEC2YOCTO_CONFIG.get_inherit("cmake") and \ pp_provide not in SPEC2YOCTO_CONFIG.get_inherit("perl") and \ pp_provide not in ignore_depend_list and \ pp_provide not in native_depend_list and \ pp_provide not in cross_depend_list: erro_msg = "No direct provider for package DEPENDS %s : \"%s\"." print erro_msg % ( self.__package_name, pp_provide ) res = pp_provide if res != self.__package_name : res_depends.add( res ) # should be from a configue file. for res in res_depends: pkg_yocto_name=res for res_pkg_devel in re.findall( RePattern.paternDevel, pkg_yocto_name ): pkg_yocto_name=pkg_yocto_name.replace("-devel","-dev") if pkg_yocto_name == "readline-dev": pkg_yocto_name="readline" if pkg_yocto_name in SPEC2YOCTO_CONFIG.get_inherit_gettext(): file_d.write( "#Replace \"DEPENDS\" on gettext by \"inherit gettext\"\n" ) file_d.write( "inherit gettext\n" ) elif pkg_yocto_name in ['cmake']: file_d.write( "inherit tizen_cmake\n" ) elif pkg_yocto_name in ['pkgconfig']: file_d.write( "inherit pkgconfig\n" ) elif pkg_yocto_name in native_depend_list: file_d.write( "DEPENDS_append_class-native = \" %s-native\"\n" % pkg_yocto_name ) file_d.write( "DEPENDS_append_class-target = \" %s-native\"\n" % pkg_yocto_name ) elif pkg_yocto_name in cross_depend_list: file_d.write( "DEPENDS_append_class-native = \" %s\"\n" % pkg_yocto_name ) file_d.write( "DEPENDS_append_class-target = \" %s-cross\"\n" % pkg_yocto_name ) elif pkg_yocto_name in ignore_depend_list: pass elif pkg_yocto_name in SPEC2YOCTO_CONFIG.get_libtool_cross(): file_d.write( "DEPENDS += \"libtool-cross\"\n" ) elif pkg_yocto_name in SPEC2YOCTO_CONFIG.get_inherit("perl"): file_d.write( "inherit perlnative\n" ) elif pkg_yocto_name in SPEC2YOCTO_CONFIG.get_inherit("python"): file_d.write( "inherit pythonnative\n" ) else: file_d.write( "DEPENDS += \"%s\"\n" % pkg_yocto_name ) file_d.write( "\n" ) class HTTPAccessFailure( Exception ): '''Indicate the http access failed''' def download_url( url ): r = urlopen( url ) if r.code != 200: raise HTTPAccessFailure() page = r.read() return page def download_manifest_url( url ): r = urlopen( url ) if r.code != 200: print "ERROR %s " % url raise HTTPAccessFailure() page = r.read() return page def download_build_xml( url ): return download_url( url + "/build.xml" ) def get_project_id( xml ): aElement = ElementTree.fromstring( xml ) for value in aElement: for project in value.getiterator(): if project.tag == "id": return project.text def get_project_arch( xml ): aElement = ElementTree.fromstring( xml ) arch_list = [] for value in aElement: for project in value.getiterator(): if project.tag == "archs": for arch in project.getiterator(): if arch.tag == "arch": arch_list.append( arch.text ) return arch_list def get_project_buildtarget(xml): aElement = ElementTree.fromstring(xml) buildtarget_list = [] for value in aElement: for project in value.getiterator(): if project.tag == "buildtargets": for buildtarget in project.getiterator(): if buildtarget.tag == "buildtarget": buildtarget_list.append(buildtarget.text) return buildtarget_list def clean_name( raw_name ): #if "_" in raw_name: # raw_name = raw_name.replace( "_", "-" ) if "/" in raw_name: return raw_name.split( "/" )[-1] else: return raw_name def clean_revision( raw_name ): if "-" in raw_name: return raw_name.split( "-" )[0] else: return raw_name def patch_the_spec_file( package_spec_path, patch_path, dest_spec_dir, dest_spec_path ): if not package_spec_path == dest_spec_path: shutil.copy2( package_spec_path, dest_spec_path ) if dest_spec_dir.endswith( "/packaging" ): dest_spec_dir = dest_spec_dir[:-len( "/packaging" )] patch_command = "patch -s -p1 --fuzz=2 -d %s -i %s" % ( dest_spec_dir, patch_path ) a_sub_command = SubprocessCrt() res = a_sub_command.exec_subprocess( patch_command ) if res == 1: msg = "The patch \"%s\" can't be apply in directory \"%s\"." msg = msg % ( patch_path, dest_spec_dir ) print >> sys.stderr, colorize( msg, "red" ) print >> sys.stderr, colorize( "command: \"%s\"" % patch_command, "red" ) sys.exit( 1 ) return dest_spec_path def specfile_patcher( package_spec_path, project, package_name_list , dest_spec_path ): working_dir = SPEC2YOCTO_CONFIG.get_working_dir( project ) source_spec_patch_dir = os.path.join( working_dir, "specfile-patch" ) patch_path_list = findSpecPatchFiles( source_spec_patch_dir, package_name_list ) if len( patch_path_list ) > 0: dest_spec_dir = os.path.dirname( dest_spec_path ) if not os.path.isdir( dest_spec_dir ): os.makedirs( dest_spec_dir ) for patch_path in patch_path_list: package_spec_path = patch_the_spec_file( package_spec_path, patch_path, dest_spec_dir, dest_spec_path ) return package_spec_path class package_def: def __init__( self, project, name, git_path, meta_path, revision, priority, git_src ): self.__project = project self.name = name self.git_path = git_path self.meta_path = meta_path self.git_revision = revision self.priority = priority self.git_src = git_src self.__my_meta_spec = None def printMe( self ): print "%s %s %s %s" % ( self.name , self.git_path, self.git_revision, self.git_src ) def create_MetaSpec( self , package_recipes_dir, source_spec_dir ): source_path = os.path.join( source_spec_dir , self.name , "packaging" ) package_spec_path = findBestSpecFile( source_path, self.name ) if package_spec_path == -1: msg = "no initial spec file for package \"%s\" in directory \"%s\"." msg = msg % ( self.name, source_path ) print >> sys.stderr, colorize( msg, "red" ) sys.exit( 1 ) working_dir = SPEC2YOCTO_CONFIG.get_working_dir( self.__project ) specfile_patched_dir = os.path.join( working_dir, "specfile-patched" ) dest_spec_dir = os.path.join( specfile_patched_dir , self.name ) dest_spec_packaging_dir = os.path.join( dest_spec_dir , "packaging" ) dest_spec_path = os.path.join( dest_spec_packaging_dir , os.path.basename( package_spec_path ) ) package_spec_path = specfile_patcher( package_spec_path, self.__project, [self.name, self.name + "-initial"], dest_spec_path ) self.__my_meta_spec = MetaSpec( package_recipes_dir, self.name, self.meta_path, package_spec_path, self.git_src, self.git_path, self.git_revision ) def make_alias_package( project, packages_dico ): alias_package = {} #TO DO need to be do in conf file. alias_package["python-libxml2"] = "libxml2" alias_package["python-magic"] = "file" alias_package["cross-arm-binutils"] = "binutils" alias_package["cross-armv7hl-gcc47-icecream-backend"] = "gcc47" alias_package["libffi47"] = "gcc47" alias_package["crosswalk-bin"] = "crosswalk" for alias in alias_package.keys(): alias_to = alias_package[alias] if alias_to in packages_dico.keys() and alias not in packages_dico.keys(): a_package_def = packages_dico[alias_to] packages_dico[alias] = package_def( project, alias, a_package_def.git_path, a_package_def.meta_path, a_package_def.git_revision, a_package_def.priority, a_package_def.git_src ) return packages_dico class manifestCollection: ''' class for all package in a distro. ''' def __init__( self , project ): ''' init all manifest ''' self.__my_project = project self.__recipes_list = None if not SPEC2YOCTO_CONFIG.is_valide_project( self.__my_project ): msg = "\"%s\" has no configuration in file \"%s\"." msg = msg % ( self.__my_project, CONFIGURATION_FILE_PATH ) print >> sys.stderr, colorize( msg, "red" ) sys.exit( 1 ) #Just get the list of manifest uri. self.__my_manifest_meta_list = SPEC2YOCTO_CONFIG.get_manifest_meta_list( self.__my_project ) self.__my_manifest_file_list = {} #Load the project manifest. self.__update_meta_manifests() self.__my_package_dico = {} self.__generate_package() self.__my_package_dico = make_alias_package( self.__my_project, self.__my_package_dico ) def parse_manifest_xml( self, src ): primaryFile = open( src, "r" ) primaryXML = primaryFile.read() primaryFile.close() aElement = ElementTree.fromstring( primaryXML ) remote = "" packages_dico = {} for value in aElement: for project in value.getiterator(): if project.tag == "project": name = project.attrib['name'] short_name=clean_name( name ) revision = clean_revision( project.attrib['revision'] ) packages_dico[short_name] = [name, revision] elif project.tag == "default": remote = project.attrib['remote'] elif project.tag == "remote": fetch = project.attrib['fetch'] name = project.attrib['name'] else: print "ERROR" return remote, packages_dico def print_list( self ): pkg_list = self.__my_package_dico.keys() pkg_list.sort() for package in pkg_list: self.__my_package_dico[package].printMe() def __generate_package( self ): for meta_manifest in self.__my_manifest_file_list.keys(): manifest_uri = self.__my_manifest_file_list[meta_manifest] manifest_git = SPEC2YOCTO_CONFIG.get_manifest_default_git_src( meta_manifest ) manifest_priority = SPEC2YOCTO_CONFIG.get_manifest_priority( meta_manifest ) remote, packages_dico = self.parse_manifest_xml( manifest_uri ) if manifest_git is not None: remote = manifest_git whitelist_dico = SPEC2YOCTO_CONFIG.get_whitelist(self.__my_project) if len( whitelist_dico.keys() ) != 0: list_packages = set(whitelist_dico.keys()) else: list_packages = set(packages_dico.keys()) blacklist = set(SPEC2YOCTO_CONFIG.get_list(self.__my_project, "blacklist")) list_packages=list_packages.difference(blacklist) for package in list_packages: meta_path=whitelist_dico[package] if package in packages_dico.keys(): [git_path, revision] = packages_dico[package] if package in self.__my_package_dico.keys(): if manifest_priority > self.__my_package_dico[package].priority: self.__my_package_dico[package] = package_def( self.__my_project, package, git_path, meta_path, revision, manifest_priority, remote ) elif manifest_priority == self.__my_package_dico[package].priority: msg = "most of one occurence of package \"%s\" ." msg = msg % ( package ) print >> sys.stderr, colorize( msg, "red" ) sys.exit( 1 ) else: self.__my_package_dico[package] = package_def( self.__my_project, package, git_path, meta_path, revision, manifest_priority, remote ) for package in whitelist_dico.keys(): if package not in self.__my_package_dico.keys(): msg = "package \"%s\" is in the white list but not in the manifest." msg = msg % ( package ) print >> sys.stderr, colorize( msg, "red" ) sys.exit( 1 ) def __update_meta_manifests( self ): ''' find/download all manifest.xml file. ''' for meta_manifest in self.__my_manifest_meta_list: meta_manifest_uri = SPEC2YOCTO_CONFIG.get_manifest_uri( meta_manifest ) if meta_manifest_uri is None: msg = "\"%s\" has no URI configuration in file \"%s\"." msg = msg % ( meta_manifest_uri, CONFIGURATION_FILE_PATH ) print >> sys.stderr, colorize( msg, "red" ) sys.exit( 1 ) if meta_manifest_uri.startswith( "http" ): if meta_manifest_uri.endswith( ".xml" ): meta_manifest_url_path = meta_manifest_uri manifest_name = os.path.basename(meta_manifest_uri) else: xml_str = download_build_xml( meta_manifest_uri ) project_id = get_project_id( xml_str ) list_arch = get_project_arch( xml_str ) list_buildtarget = get_project_buildtarget(xml_str) arch = SPEC2YOCTO_CONFIG.get_project_arch( self.__my_project ) buildtarget = SPEC2YOCTO_CONFIG.get_manifest_buildtarget(meta_manifest) if ( arch == "i586" ) and ( "ia32" in list_arch ): arch = "ia32" buildtarget ="ia32-wayland" elif ( arch is None ) and ( len( list_arch ) > 0 ): arch = list_arch[0] elif ( arch not in list_arch ): arch = list_arch[0] manifest_name = "%s_%s.xml" % ( project_id, buildtarget ) meta_manifest_url_path = "%s/builddata/manifest/%s" meta_manifest_url_path = meta_manifest_url_path % ( meta_manifest_uri, manifest_name ) manifest_xml = download_manifest_url( meta_manifest_url_path ) working_dir = SPEC2YOCTO_CONFIG.get_working_dir( self.__my_project ) meta_manifest_dir = os.path.join( working_dir, "manifest_file" ) meta_manifest_path = os.path.join( meta_manifest_dir, manifest_name ) if not os.path.isdir( meta_manifest_dir ): os.makedirs( meta_manifest_dir ) with open( meta_manifest_path, "w" ) as manifest_xml_file: manifest_xml_file.write( manifest_xml ) else: if not os.path.isfile( meta_manifest_uri ): msg = "In the project \"%s\" the manifest \"%s\" is not a valid file." msg = msg % ( self.__my_project, meta_manifest_uri ) print >> sys.stderr, colorize( msg, "red" ) sys.exit( 1 ) else: meta_manifest_path = meta_manifest_uri self.__my_manifest_file_list[ meta_manifest ] = meta_manifest_path def createRecipes( self ): ''' generate recipises. ''' self.__recipes_dir_dest = SPEC2YOCTO_CONFIG.get_recipes_sources_directory( self.__my_project ) #self.__clean_old_bb_files(self.__recipes_dir_dest) if self.__recipes_dir_dest is None: msg = "In the project \"%s\" recipes_dir_sources is not define." msg = msg % ( self.__my_project ) print >> sys.stderr, colorize( msg, "red" ) sys.exit( 1 ) elif not os.path.isdir( self.__recipes_dir_dest ): os.makedirs( self.__recipes_dir_dest ) self.__meta_spec_dico = {} self.__meta_spec_boot_strap_dico = {} self.__set_oe_package_blacklist() self.__set_native_package_blacklist() self.__init_depends() self.__init_MetaSpec() def __clean_old_bb_files( self ,path): for root, dirs, files in os.walk(path): for a_file in files: if a_file.endswith(".bb"): os.unlink( os.path.join(path, root, a_file) ) def __set_oe_package_blacklist( self ): ''' load oe_package_blacklist ''' list_package = SPEC2YOCTO_CONFIG.get_list(self.__my_project, "runtime_blacklist") MetaSpec.mOePackageBlacklist.extend( list_package ) def __set_native_package_blacklist( self ): ''' load oe_package_blacklist ''' list_package = SPEC2YOCTO_CONFIG.get_list(self.__my_project, "native_blacklist") MetaSpec.mNativePackageBlacklist.extend( list_package ) def __init_MetaSpec( self ): pkg_list = self.__my_package_dico.keys() pkg_list.sort() working_dir = SPEC2YOCTO_CONFIG.get_working_dir( self.__my_project ) source_spec_dir = os.path.join( working_dir, "specfile-initial" ) for package in pkg_list: self.__my_package_dico[package].create_MetaSpec( self.__recipes_dir_dest, source_spec_dir ) def __init_depends( self ): ''' init depends ''' self.__load_package_provided_extra() pkg_list = self.__my_package_dico.keys() pkg_list.sort() def __load_package_provided_extra( self ): ''' load_package_provided_extra ''' provided_extra_dico = SPEC2YOCTO_CONFIG.get_provided_extra( self.__my_project ) for k_package in provided_extra_dico.keys(): raw_list=provided_extra_dico[k_package] if k_package not in MetaSpec.mProvidesDico.keys(): MetaSpec.mProvidesDico[k_package] = [] MetaSpec.mProvidesDico[k_package].extend( raw_list ) if k_package not in MetaSpec.mExtraRProvidesDico.keys(): MetaSpec.mExtraRProvidesDico[k_package] = [] MetaSpec.mExtraRProvidesDico[k_package].extend( raw_list ) TERMINAL_COLORS = {"black": "\033[30;1m", "red": "\033[31;1m", "green": "\033[32;1m", "yellow": "\033[33;1m", "blue": "\033[34;1m", "magenta": "\033[35;1m", "cyan": "\033[36;1m", "white": "\033[37;1m", "default": "\033[0m"} def colorize( text, color = "green" ): """ Return a colorized copy of `text`. See Utils.TERMINAL_COLORS.keys() for available colors. """ return TERMINAL_COLORS.get( color, "" ) + text + TERMINAL_COLORS["default"] def check_group_file( project ): working_dir = SPEC2YOCTO_CONFIG.get_working_dir( project ) group_uri = SPEC2YOCTO_CONFIG.get_group_uri( project ) if group_uri.startswith( "http" ): group_file_path = os.path.join( working_dir, "group/group.xml" ) group_xml = download_url( group_uri ) with open( group_file_path, "w" ) as group_file: group_file.write( group_xml ) return group_file_path else: return group_uri def parse_group_xml( src ): groupFile = open( src, "r" ) groupXML = groupFile.read() groupFile.close() aElement = ElementTree.fromstring( groupXML ) packages_dico = {} for group in aElement: if group.tag == "group": group_name=None list_package=[] for element in group: if element.tag == "name": group_name = element.text elif element.tag == "packagelist": for packagereq in element: list_package.append(packagereq.text) packages_dico[group_name]=list_package return packages_dico def dump_group(project,group_dico): recipes_group_directory = SPEC2YOCTO_CONFIG.get_recipes_group_directory( project ) for group in group_dico.keys(): group_str = group.replace( " ", "-" ) path = os.path.join( recipes_group_directory, "packagegroup-tizen-%s.bb" % group_str ) with open(path,"w") as group_file: group_file.write( "SUMMARY = \"%s\"\n" % group ) group_file.write( "DESCRIPTION = \"%s\"\n" % group ) group_file.write( "LICENSE = \"MIT\"\n" ) group_file.write( "DEPENDS = \"virtual/kernel\"\n" ) group_file.write( "PR = \"r1\"\n" ) group_file.write( "inherit packagegroup\n" ) group_file.write( "\n" ) group_file.write( "PACKAGE_ARCH = \"${MACHINE_ARCH}\"\n" ) group_file.write( "\n" ) group_file.write( "RDEPENDS_${PN} = \"\" \n\n" ) for pkg in group_dico[group]: group_file.write( "RDEPENDS_${PN} += \"%s\"\n" % pkg ) def generateBuildStatus( project_path ): res_native = {} res = {} if not os.path.isdir( project_path ): msg = "The path \"%s\" is not a directory." msg = msg % ( project_path ) print >> sys.stderr, colorize( msg, "red" ) sys.exit( 1 ) for package_path in os.listdir( project_path ): project_full_path = os.path.join( project_path, package_path ) if ( package_path == "build_stats" ) and os.path.isfile( project_full_path ) : pass elif os.path.isdir( project_full_path ): BN, PV, PR = cleanPackageName( package_path ) res_status = check_package_status( project_full_path ) if BN.endswith("-native"): res_native[BN] = [PV ] + res_status else: res[BN] = [PV ] + res_status # ignorefiles elif package_path in ["."]: pass else: msg = "This directory should not contain the file \"%s\"." msg = msg % ( package_path ) print >> sys.stderr, colorize( msg, "red" ) sys.exit( 1 ) return res_native, res def cleanPackageName( package_path ): if package_path.count( "-" ) < 2: msg = "unknow format for package \"%s\"." msg = msg % ( package_path ) print >> sys.stderr, colorize( msg, "red" ) sys.exit( 1 ) PR=package_path[package_path.rindex("-")+1:] package_path=package_path[:package_path.rindex("-")] PV=package_path[package_path.rindex("-")+1:] BN=package_path[:package_path.rindex("-")] return BN, PV, PR def check_package_status( project_full_path ): tasks_order = ["do_fetch", "do_unpack", "do_patch", "do_populate_lic", "do_configure", "do_compile", "do_install", "do_populate_sysroot", "do_package", "do_packagedata", "do_package_write_rpm", "do_rootfs"] max_index=-1 for package_task in os.listdir( project_full_path ): if package_task in tasks_order: task_index = tasks_order.index( package_task ) if task_index > max_index: max_index = task_index if max_index == -1: msg = "No log task in \"%s\"." msg = msg % ( project_full_path ) print >> sys.stderr, colorize( msg, "red" ) sys.exit( 1 ) last_task = tasks_order[max_index][3:] task_status = "" status = "unknow" with open( os.path.join( project_full_path, tasks_order[max_index] ) ) as status_file: for line in status_file: if line.startswith( "Status: " ): status = line[len( "Status: " ):].replace( "\n", "" ).replace( " ", "" ) break if last_task == "package_write_rpm" and status == "PASSED": status = "OK" return [last_task, status] def clean_Packagegroup( project,group_dico ): group_dico_tmp = {} package_replacement = SPEC2YOCTO_CONFIG.get_substitute( project ) for group in group_dico.keys(): group_dico_tmp[group] = [] for package in group_dico[group]: if package in package_replacement.keys(): group_dico_tmp[group].append( package_replacement[package] ) else: group_dico_tmp[group].append( package ) return group_dico_tmp def check_debugmode( opts_debug ): global DEBUG_RUN if opts_debug == "no": DEBUG_RUN = False elif opts_debug == "yes": DEBUG_RUN = True class spec2yoctoCommandline( cmdln.Cmdln ): name = "spec2yocto" version = "0.1" def do_manifestToList( self, subcmd, opts, project = None ): """${cmd_name}: print the list of package in projects. ${cmd_usage}-- ${cmd_option_list} """ if project is None: project = SPEC2YOCTO_CONFIG.get_current_project() pkg_co = manifestCollection( project ) pkg_co.print_list() def do_createRecipes( self, subcmd, opts, project = None ): """${cmd_name}: create all packages recipes. ${cmd_usage}-- ${cmd_option_list} """ if project is None: project = SPEC2YOCTO_CONFIG.get_current_project() pkg_co = manifestCollection( project ) pkg_co.createRecipes() @cmdln.option( "--package_pn", action = "store", default = None, help = "select the package_pn." ) def do_findBestSpecFile( self, subcmd, opts, package_path ): """${cmd_name}: print the speec file associate to package. ${cmd_usage}-- ${cmd_option_list} """ res = findBestSpecFile( package_path, opts.package_pn ) print res @cmdln.option( "--package_pn", action = "append", default = None, help = "select the package_pn." ) def do_findSpecPatchFiles( self, subcmd, opts, patch_dir, ): """${cmd_name}: print patch from "specfile-patch" directory associate to package. ${cmd_usage}-- ${cmd_option_list} """ res = findSpecPatchFiles( patch_dir, opts.package_pn ) print " ".join( res ) @cmdln.option( "--package_pn", action = "append", default = None, help = "select the package_pn." ) @cmdln.option( "--project", action = "store", default = None, help = "select the package_pn." ) def do_specfile_patcher( self, subcmd, opts, package_spec_path ): """${cmd_name}: patch the spec file with patch from "specfile-patch" directory. ${cmd_usage}-- ${cmd_option_list} """ if opts.project is None: project = SPEC2YOCTO_CONFIG.get_current_project() else: project = opts.project res = specfile_patcher( package_spec_path, project, opts.package_pn, package_spec_path ) def do_createPackagegroup( self, subcmd, opts, project = None ): """${cmd_name}: print the list of package in projects. ${cmd_usage}-- ${cmd_option_list} """ if project is None: project = SPEC2YOCTO_CONFIG.get_current_project() res = SPEC2YOCTO_CONFIG.get_group( project ) group_file_path = check_group_file( project ) group_dico= parse_group_xml( group_file_path ) group_dico = clean_Packagegroup( project, group_dico ) dump_group(project,group_dico) @cmdln.option( "--debug", action = "store", default = None, help = "run the in debug mode.[yes/no]" ) @cmdln.option( "--project", action = "store", default = None, help = "select the project." ) @cmdln.option( "--package_pn", action = "store", default = None, help = "select the package_pn." ) def do_prep( self, subcmd, opts, spec_path ): """${cmd_name}: print the bash code of the %prep section of a spec file. ${cmd_usage}-- ${cmd_option_list} """ check_debugmode( opts.debug ) if opts.project is None: project = SPEC2YOCTO_CONFIG.get_current_project() else: project = opts.project res = SpecParser( spec_path, package_pn = opts.package_pn ).get_prep_section() print res res = 0 @cmdln.option( "--debug", action = "store", default = None, help = "run the in debug mode.[yes/no]" ) @cmdln.option( "--project", action = "store", default = None, help = "select the project." ) @cmdln.option( "--package_pn", action = "store", default = None, help = "select the package_pn." ) def do_compile( self, subcmd, opts, spec_path ): """${cmd_name}: print the bash code of the %build section of a spec file. ${cmd_usage}-- ${cmd_option_list} """ check_debugmode( opts.debug ) if opts.project is None: project = SPEC2YOCTO_CONFIG.get_current_project() else: project = opts.project res = SpecParser( spec_path, package_pn = opts.package_pn ).get_build_section() if res != 1: print res @cmdln.option( "--debug", action = "store", default = None, help = "run the in debug mode.[yes/no]" ) @cmdln.option( "--project", action = "store", default = None, help = "select the project." ) @cmdln.option( "--package_pn", action = "store", default = None, help = "select the package_pn." ) def do_install( self, subcmd, opts, spec_path ): """${cmd_name}: print the bash code of the %install section of a spec file. ${cmd_usage}-- ${cmd_option_list} """ check_debugmode( opts.debug ) if opts.project is None: project = SPEC2YOCTO_CONFIG.get_current_project() else: project = opts.project res = SpecParser( spec_path, package_pn = opts.package_pn ).get_install_section() if res != 1: print res @cmdln.option( "--debug", action = "store", default = None, help = "run the in debug mode.[yes/no]" ) def do_generateBuildStatus( self, subcmd, opts, project_path ): """${cmd_name}: print the status and the the build state of packages, builded in a single command. exemple: build/tmp-eglibc/buildstats/core-image-minimal-qemux86/XXXX/ ${cmd_usage}-- ${cmd_option_list} """ check_debugmode( opts.debug ) res_native, res = generateBuildStatus( project_path ) res_native_keys = res_native.keys() res_keys = res.keys() res_native_keys.sort() res_keys.sort() for r in res_native_keys: print r + "\t" + "\t".join( res_native[r] ) print for r in res_keys: print r + "\t" + "\t".join( res[r] ) @cmdln.option( "--debug", action = "store", default = None, help = "run the in debug mode.[yes/no]" ) def do_generatePseudoSpecfile( self, subcmd, opts, spec_path ): """${cmd_name}: generate a spec file use by yocto, for packaging rpm. ${cmd_usage}-- ${cmd_option_list} """ check_debugmode( opts.debug ) a_spec_parser = SpecParser( spec_path ) a_spec_parser.parse_raw_spec_file() res = a_spec_parser.get_clean_raw() if res != 1: print res @cmdln.option( "--debug", action = "store", default = None, help = "run the in debug mode.[yes/no]" ) @cmdln.option( "--project", action = "store", default = None, help = "select the project." ) def do_working_dir( self, subcmd, opts ): """${cmd_name}: return the proto directory. ${cmd_usage}-- ${cmd_option_list} """ check_debugmode( opts.debug ) if opts.project is None: project = SPEC2YOCTO_CONFIG.get_current_project() else: project = opts.project working_dir = SPEC2YOCTO_CONFIG.get_working_dir( project ) if working_dir != 1: print working_dir def main(): commandline = spec2yoctoCommandline() try: res = commandline.main() except ValueError as ve: print print >> sys.stderr, colorize( str( ve ), "red" ) res = 1 except EnvironmentError as ioe: # commandline.do_help([sys.argv[0]]) print print >> sys.stderr, colorize( str( ioe ), "red" ) if hasattr( ioe, "spec2yocto_config_error" ): msg = "See '--config' option" print >> sys.stderr, colorize( msg, "red" ) res = 1 # except Exception as e_all : # print # print >> sys.stderr, colorize( str( e_all ), "red" ) # res = 1 sys.exit( res ) if __name__ == '__main__': main()