231 lines
9.4 KiB
Python
Executable File
231 lines
9.4 KiB
Python
Executable File
#! /usr/bin/python3
|
|
#
|
|
# Copyright (c) 2011-2015, Intel Corporation
|
|
# All rights reserved.
|
|
#
|
|
# Redistribution and use in source and binary forms, with or without modification,
|
|
# are permitted provided that the following conditions are met:
|
|
#
|
|
# 1. Redistributions of source code must retain the above copyright notice, this
|
|
# list of conditions and the following disclaimer.
|
|
#
|
|
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
# this list of conditions and the following disclaimer in the documentation and/or
|
|
# other materials provided with the distribution.
|
|
#
|
|
# 3. Neither the name of the copyright holder nor the names of its contributors
|
|
# may be used to endorse or promote products derived from this software without
|
|
# specific prior written permission.
|
|
#
|
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
|
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
|
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
import argparse
|
|
import re
|
|
import sys
|
|
import tempfile
|
|
import os
|
|
import logging
|
|
import subprocess
|
|
|
|
import EddParser
|
|
from PFWScriptGenerator import PfwScriptTranslator
|
|
import hostConfig
|
|
|
|
|
|
def parseArgs():
|
|
argparser = argparse.ArgumentParser(description="Parameter-Framework XML \
|
|
Settings file generator.\n\
|
|
Exit with the number of (recoverable or not) \
|
|
error that occured.")
|
|
argparser.add_argument('--toplevel-config',
|
|
help="Top-level parameter-framework configuration file. Mandatory.",
|
|
metavar="TOPLEVEL_CONFIG_FILE",
|
|
required=True)
|
|
argparser.add_argument('--criteria',
|
|
help="Criteria file, in '<type> <name> : <value> <value...>' \
|
|
format. Mandatory.",
|
|
metavar="CRITERIA_FILE",
|
|
type=argparse.FileType('r'),
|
|
required=True)
|
|
argparser.add_argument('--initial-settings',
|
|
help="Initial XML settings file (containing a \
|
|
<ConfigurableDomains> tag",
|
|
nargs='?',
|
|
default=None,
|
|
metavar="XML_SETTINGS_FILE")
|
|
argparser.add_argument('--add-domains',
|
|
help="List of single domain files (each containing a single \
|
|
<ConfigurableDomain> tag",
|
|
metavar="XML_DOMAIN_FILE",
|
|
nargs='*',
|
|
dest='xml_domain_files',
|
|
default=[])
|
|
argparser.add_argument('--add-edds',
|
|
help="List of files in EDD syntax (aka \".pfw\" files)",
|
|
metavar="EDD_FILE",
|
|
type=argparse.FileType('r'),
|
|
nargs='*',
|
|
default=[],
|
|
dest='edd_files')
|
|
argparser.add_argument('--schemas-dir',
|
|
help="Directory of parameter-framework XML Schemas for generation \
|
|
validation",
|
|
default=None)
|
|
argparser.add_argument('--target-schemas-dir',
|
|
help="Ignored. Kept for retro-compatibility")
|
|
argparser.add_argument('--validate',
|
|
help="Validate the settings against XML schemas",
|
|
action='store_true')
|
|
argparser.add_argument('--verbose',
|
|
action='store_true')
|
|
|
|
return argparser.parse_args()
|
|
|
|
def parseCriteria(criteriaFile):
|
|
# Parse a criteria file
|
|
#
|
|
# This file define one criteria per line; they should respect this format:
|
|
#
|
|
# <type> <name> : <values>
|
|
#
|
|
# Where <type> is 'InclusiveCriterion' or 'ExclusiveCriterion';
|
|
# <name> is any string w/o whitespace
|
|
# <values> is a list of whitespace-separated values, each of which is any
|
|
# string w/o a whitespace
|
|
criteria_pattern = re.compile(
|
|
r"^(?P<type>(?:Inclusive|Exclusive)Criterion)\s*" \
|
|
r"(?P<name>\S+)\s*:\s*" \
|
|
r"(?P<values>.*)$")
|
|
criterion_inclusiveness_table = {
|
|
'InclusiveCriterion' : "inclusive",
|
|
'ExclusiveCriterion' : "exclusive"}
|
|
|
|
all_criteria = []
|
|
for line_number, line in enumerate(criteriaFile):
|
|
match = criteria_pattern.match(line)
|
|
if not match:
|
|
raise ValueError("The following line is invalid: {}:{}\n{}".format(
|
|
criteriaFile.name, line_number, line))
|
|
|
|
criterion_name = match.groupdict()['name']
|
|
criterion_type = match.groupdict()['type']
|
|
criterion_values = re.split("\s*", match.groupdict()['values'])
|
|
|
|
criterion_inclusiveness = criterion_inclusiveness_table[criterion_type]
|
|
|
|
all_criteria.append({
|
|
"name" : criterion_name,
|
|
"inclusive" : criterion_inclusiveness,
|
|
"values" : criterion_values})
|
|
|
|
return all_criteria
|
|
|
|
def parseEdd(EDDFiles):
|
|
parsed_edds = []
|
|
|
|
for edd_file in EDDFiles:
|
|
try:
|
|
root = EddParser.Parser().parse(edd_file)
|
|
except EddParser.MySyntaxError as ex:
|
|
logging.critical(str(ex))
|
|
logging.info("EXIT ON FAILURE")
|
|
exit(2)
|
|
|
|
try:
|
|
root.propagate()
|
|
except EddParser.MyPropagationError as ex:
|
|
logging.critical(str(ex))
|
|
logging.info("EXIT ON FAILURE")
|
|
exit(1)
|
|
|
|
parsed_edds.append((edd_file.name, root))
|
|
return parsed_edds
|
|
|
|
def generateDomainCommands(logger, all_criteria, initial_settings, xml_domain_files, parsed_edds):
|
|
# create and inject all the criteria
|
|
logger.info("Creating all criteria")
|
|
for criterion in all_criteria:
|
|
yield ["createSelectionCriterion", criterion['inclusive'],
|
|
criterion['name']] + criterion['values']
|
|
|
|
yield ["start"]
|
|
|
|
# Import initial settings file
|
|
if initial_settings:
|
|
logger.info("Importing initial settings file {}".format(initial_settings))
|
|
yield ["importDomainsWithSettingsXML", initial_settings]
|
|
|
|
# Import each standalone domain files
|
|
for domain_file in xml_domain_files:
|
|
logger.info("Importing single domain file {}".format(domain_file))
|
|
yield ["importDomainWithSettingsXML", domain_file]
|
|
|
|
# Generate the script for each EDD file
|
|
for filename, parsed_edd in parsed_edds:
|
|
logger.info("Translating and injecting EDD file {}".format(filename))
|
|
translator = PfwScriptTranslator()
|
|
parsed_edd.translate(translator)
|
|
for command in translator.getScript():
|
|
yield command
|
|
|
|
def main():
|
|
logging.root.setLevel(logging.INFO)
|
|
args = parseArgs()
|
|
|
|
all_criteria = parseCriteria(args.criteria)
|
|
|
|
#
|
|
# EDD files (aka ".pfw" files)
|
|
#
|
|
parsed_edds = parseEdd(args.edd_files)
|
|
|
|
# We need to modify the toplevel configuration file to account for differences
|
|
# between development setup and target (installation) setup, in particular, the
|
|
# TuningMwith ode must be enforced, regardless of what will be allowed on the target
|
|
fake_toplevel_config = tempfile.NamedTemporaryFile(mode='w', delete=False, suffix=".xml",
|
|
prefix="TMPdomainGeneratorPFConfig_")
|
|
|
|
install_path = os.path.dirname(os.path.realpath(args.toplevel_config))
|
|
hostConfig.configure(infile=args.toplevel_config,
|
|
outfile=fake_toplevel_config,
|
|
structPath=install_path)
|
|
fake_toplevel_config.close()
|
|
|
|
# Create the connector. Pipe its input to us in order to write commands;
|
|
# connect its output to stdout in order to have it dump the domains
|
|
# there; connect its error output to stderr.
|
|
connector = subprocess.Popen(["domainGeneratorConnector",
|
|
fake_toplevel_config.name,
|
|
'verbose' if args.verbose else 'no-verbose',
|
|
'validate' if args.validate else 'no-validate',
|
|
args.schemas_dir],
|
|
stdout=sys.stdout, stdin=subprocess.PIPE, stderr=sys.stderr)
|
|
|
|
initial_settings = None
|
|
if args.initial_settings:
|
|
initial_settings = os.path.realpath(args.initial_settings)
|
|
|
|
for command in generateDomainCommands(logging, all_criteria, initial_settings,
|
|
args.xml_domain_files, parsed_edds):
|
|
connector.stdin.write('\0'.join(command))
|
|
connector.stdin.write("\n")
|
|
|
|
# Closing the connector's input triggers the domain generation
|
|
connector.stdin.close()
|
|
connector.wait()
|
|
os.remove(fake_toplevel_config.name)
|
|
return connector.returncode
|
|
|
|
# If this file is directly executed
|
|
if __name__ == "__main__":
|
|
exit(main())
|