123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320 |
- #!/usr/bin/python -tt
- # vim: ai ts=4 sts=4 et sw=4
- # Copyright (c) 2009 Intel Corporation
- #
- # 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 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., 59
- # Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- """Overview of ini2yaml
- (1) ini2yaml reads the ini file and divides it into segments.
- (2) Parses the 'header' segment. Write out the key,value pairs
- (3) Expand the 'Files' if found
- (4) Parse the sub-packages segments if found
- """
- import os
- import sys
- import re
- import shutil
- import optparse
- from ConfigParser import RawConfigParser
- # spectacle modules
- from spectacle.convertor import *
- from spectacle.dumper import *
- from spectacle import logger
- class SBConvertor(Convertor):
- """ Convertor for SpecBuild ini files """
- def __init__(self):
- sb_cv_table = {
- 'BuildRequires': 'PkgBR',
- 'PkgConfig': 'PkgConfigBR',
- 'Extras': 'ExtraSources',
- 'Extra': 'extra',
- }
- Convertor.__init__(self, sb_cv_table)
- class SBConfigParser(RawConfigParser):
- """ SpecBuild ini specific parser """
- # keys whose value need to split to list
- multi_keys = ('Sources',
- 'Patches',
- 'Extras',
- 'LocaleOptions',
- )
- # keys whose value may have ver numbers
- reqs_keys = ('BuildRequires',
- 'PreRequires',
- 'Requires',
- 'PostRequires',
- 'PkgConfig',
- 'Provides',
- 'Obsoletes',
- 'Conflicts',
- )
- # keys whose value need to be expand(reading extra file)
- expand_keys = ('Files',
- 'Description',
- 'PostMakeExtras',
- 'PostMakeInstallExtras',
- )
- # boolean keys
- bool_keys = ('UseAsNeeded',
- 'NoAutoReq',
- 'NoAutoProv',
- 'AddCheck',
- )
- # keys need to be placed to 'extra'
- extra_keys = ['Files',
- 'PostMakeExtras',
- 'PostMakeInstallExtras',
- ]
- # must have keys
- must_keys = {'Release': '1',
- 'Configure': 'configure',
- }
- def __init__(self, include_files):
- RawConfigParser.__init__(self)
- if include_files:
- self.extra_keys.remove('Files')
- self.record_used_files = []
- self._check_Makefile()
- def _check_Makefile(self):
- """ Check whether Makefile in working dir should be moved """
- if os.path.exists('Makefile'):
- try:
- cont = file('Makefile').read()
- if re.search('\s+spec-builder\s+', cont):
- # The Makefile is for spec-builder
- self.record_used_files.append('Makefile')
- except:
- pass
- def read(self, filenames):
- """ override super read to record input files """
- if isinstance(filenames, basestring):
- filenames = [filenames]
- self.record_used_files.extend(filenames)
- return RawConfigParser.read(self, filenames)
- def optionxform(self, option):
- # Capitalize the first char
- lead = option[0]
- if lead.upper() != lead:
- return lead.upper() + option[1:]
- else:
- return option
- def _expand_single(self, filename):
- """ Helper function to expand *.desc """
- if os.path.exists(filename):
- self.record_used_files.append(filename)
- return file(filename).read().strip()
- else:
- logger.warning("Warning: missing expected file %s" % filename)
- return None
- def _cook_config(self):
- """ Helper function to update fields for spec-builder specific ones
- """
- all_items = {}
- main_extra = {} # for extra keys of main pkg
- for section in self.sections():
- items = self._sections[section]
- # Convert space seperated string to list
- for key in self.multi_keys:
- if key in items:
- self.set(section, key, map(str.strip, items[key].split()))
- # Convert dependent like entry to list
- for key in self.reqs_keys:
- if key in items:
- reqs = []
- for entry in re.findall('\S+\s+[<>=]+\s+\S+|\S+', items[key]):
- reqs.append(entry.split(',')[0])
- self.set(section, key, reqs)
- # special cases for 'ConfigOptions'
- if 'ConfigOptions' in items:
- self.set(section, 'ConfigOptions',
- map(lambda s: '--'+s,
- [opt for opt in map(str.strip, items['ConfigOptions'].split('--')) if opt]))
- # special cases for 'LocaleOptions'
- if 'LocaleOptions' in items and 'LocaleName' not in items:
- self.set(section, 'LocaleName', '%{name}')
- # Convert boolean keys
- for key in self.bool_keys:
- if key in items:
- if items[key].upper() in ('NO', 'FALSE', '0'):
- del items[key]
- else:
- self.set(section, key, 'yes')
- # Convert keys which need expanding from external file
- for key in self.expand_keys:
- if key in items:
- content = self._expand_single(items[key])
- if content:
- if key == 'Files':
- # 'Files' need split to list
- self.set(section, key, content.split('\n'))
- else:
- self.set(section, key, content)
- else:
- # if file empty or file not exists, remove the empty key
- del items[key]
- # move extra keys to 'extra' key
- extra = {}
- for key in self.extra_keys:
- if key in items:
- extra[key] = items[key]
- del items[key]
- if extra:
- if section not in ('header', 'configuration'):
- self.set(section, 'extra', extra)
- else:
- main_extra.update(extra)
- for section in self.sections():
- if section in ('header', 'configuration'):
- all_items.update(dict(self.items(section)))
- if main_extra:
- all_items['extra'] = main_extra
- # Checking must-have keys
- for key, default in self.must_keys.iteritems():
- if key not in all_items:
- all_items[key] = default
- # Re-structure sub packages to inner level
- if 'SubPackages' in all_items:
- subpkg_list = all_items['SubPackages'].split()
- all_items['SubPackages'] = []
- for subpkg in subpkg_list:
- try:
- all_items['SubPackages'].append(dict(self.items(subpkg)))
- all_items['SubPackages'][-1].update({'Name': subpkg})
- except NoSectionError, e:
- logger.warning('Needed section for sub-package %s not found' % subpkg)
- raise e
- return all_items
- def cooked_items(self):
- """ return all items, cooked to the input of convertor """
- return self._cook_config()
- def parse_options(args):
- import spectacle.__version__
- usage = "Usage: %prog [options] [ini-path]"
- parser = optparse.OptionParser(usage, version=spectacle.__version__.VERSION)
- parser.add_option("-o", "--output", type="string",
- dest="outfile_path", default=None,
- help="Path of output yaml file")
- parser.add_option("-f", "--include-files", action="store_true",
- dest="include_files", default=False,
- help="To store files list in YAML file")
- return parser.parse_args()
- if __name__ == '__main__':
- """ Main Function """
- (options, args) = parse_options(sys.argv[1:])
- if not args:
- # no ini-path specified, search in CWD
- import glob
- inils = glob.glob('*.ini')
- if not inils:
- logger.error('Cannot find valid spec-builder file(*.ini) in current directory, please specify one.')
- elif len(inils) > 1:
- logger.error('Find multiple spec-builder files(*.ini) in current directory, please specify one.')
- ini_fpath = inils[0]
- else:
- ini_fpath = args[0]
- # Check if the input file exists
- if not os.path.exists(ini_fpath):
- # input file does not exist
- logger.error("%s: File does not exist" % ini_fpath)
- # check the working path
- if ini_fpath.find('/') != -1 and os.path.dirname(ini_fpath) != os.path.curdir:
- wdir = os.path.dirname(ini_fpath)
- logger.info('Changing to working dir: %s' % wdir)
- os.chdir(wdir)
- ini_fname = os.path.basename(ini_fpath)
- if options.outfile_path:
- out_fpath = options.outfile_path
- else:
- if ini_fname.endswith('.ini'):
- out_fpath = ini_fname[:-3] + 'yaml'
- else:
- out_fpath = ini_fname + '.yaml'
- """Read the input file"""
- config = SBConfigParser(include_files = options.include_files)
- config.read(ini_fname)
- convertor = SBConvertor()
- """Dump them to spectacle file"""
- dumper = SpectacleDumper(format='yaml', opath = out_fpath)
- spec_fpath = dumper.dump(convertor.convert(config.cooked_items()))
- logger.info('Yaml file %s created' % out_fpath)
- if spec_fpath:
- logger.info('Spec file %s was created with extra data' % spec_fpath)
- # move old spec-builder files to backup dir
- backDir = 'spec-builder.backup'
- try:
- os.mkdir(backDir)
- except:
- pass
- if os.path.exists(backDir) and not os.path.isfile(backDir):
- logger.info('The following used spec-builder files are moved to dir: %s' % backDir)
- for file in config.record_used_files:
- logger.info('\t' + os.path.basename(file))
- shutil.move(file, backDir)
|