--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/configurationengine/source/plugins/common/ConeCommandPlugin/commandplugin/commandml.py Thu Mar 11 17:04:37 2010 +0200
@@ -0,0 +1,539 @@
+#
+# Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+# All rights reserved.
+# This component and the accompanying materials are made available
+# under the terms of "Eclipse Public License v1.0"
+# which accompanies this distribution, and is available
+# at the URL "http://www.eclipse.org/legal/epl-v10.html".
+#
+# Initial Contributors:
+# Nokia Corporation - initial contribution.
+#
+# Contributors:
+#
+# Description:
+#
+##
+# @author <author>
+'''
+ConE plugin to run external applications/tools with given parameters in .commandml file. Notice that values can be also
+fecthed from ConfML to maximize portability and minimize maintenance.
+'''
+
+import re
+import os
+import sys
+import logging
+import types
+
+import subprocess
+import __init__
+
+from cone.public import exceptions,plugin,utils,api, settings
+
+class CommandImpl(plugin.ImplBase):
+ """
+ Plugin implementation class.
+ """
+
+ IMPL_TYPE_ID = "commandml"
+
+
+ def __init__(self,ref,configuration, reader):
+ """
+ Overloading the default constructor
+ """
+ plugin.ImplBase.__init__(self,ref,configuration)###3
+ self.desc = ""
+ self.logger = logging.getLogger('cone.commandml(%s)' % self.ref)
+ self.reader = reader
+
+
+ def generate(self, context=None):
+ """
+ Generate the given implementation.
+ """
+ self.create_output()
+ return
+
+ def generate_layers(self,layers):
+ """
+ Generate the given Configuration layers.
+ """
+ self.logger.info('Generating layers %s' % layers)
+ self.create_output(layers)
+ return
+
+ def create_output(self, layers=None):
+ """
+ Function to generate output files.
+ """
+
+ tmpDict = self.__create_helper_variables()
+
+ for element in self.reader.elements:
+ #Element can be either command or condition.
+ element.set_logger(self.logger)
+ element.execute(tmpDict)
+ return
+
+ def __create_helper_variables(self):
+ """
+ Internal function to create dictionary containing most often used ConE "environment" variables.
+ """
+ tmp = {}
+ tmp["%CONE_OUT%"] = self.output
+ tmp["%CONE_OUT_ABSOLUTE%"] = os.path.abspath(self.output)
+ return tmp
+
+ def has_ref(self, refs):
+ """
+ @returns True if the implementation uses the given ref as input value.
+ Otherwise return False.
+ """
+
+ # return true for now so that content copying is not filtered
+ return None
+
+class CommandImplReader(plugin.ReaderBase):
+ """
+ Parses a single commandml file
+ """
+ NAMESPACE = 'http://www.s60.com/xml/commandml/1'
+ FILE_EXTENSIONS = ['commandml']
+
+ def __init__(self):
+ """
+ Constructor
+ """
+ self.output_dir = None
+ self.input_dir = None
+ self.namespaces = [self.NAMESPACE]
+ self.dview = None
+ self.elements = []
+ self.tags = None
+
+ @classmethod
+ def read_impl(cls, resource_ref, configuration, etree):
+ reader = CommandImplReader()
+ reader.set_default_view(configuration.get_default_view())
+ reader.from_etree(etree)
+ impl = CommandImpl(resource_ref, configuration, reader)
+ if reader.tags:
+ impl.set_tags(reader.tags)
+ return impl
+
+ def set_default_view(self, dview):
+ """
+ Function to set default view that is needed when solving out ConfML reference information
+ """
+ self.dview = dview
+
+ def from_etree(self, etree):
+ """
+ Parser function for commandml element.
+ """
+ self.parse_tree(etree)
+
+ def parse_tree(self, etree):
+ """
+ General parse function for condition and command elements.
+ """
+ elements = list(etree)
+ for element in elements:
+ if element.tag == "{%s}condition" % self.namespaces[0]:
+ self.elements.append(self.parse_condition(element))
+ elif element.tag == "{%s}command" % self.namespaces[0]:
+ self.elements.append(self.parse_command(element))
+ else:
+ pass
+ self.tags = self.parse_tags(etree)
+
+ def parse_condition(self, etree):
+ """
+ Parse function for condition element.
+ """
+ condition = Condition()
+ condition.set_condition(etree.get("value"))
+ condition.set_commands(self.parse_commands(etree))
+ condition.set_default_view(self.dview)
+ return condition
+
+ def parse_commands(self,etree):
+ """
+ Parser function for commands.
+ """
+ commands = []
+ for com_elem in etree.findall("{%s}command" % self.namespaces[0]):
+ commands.append(self.parse_command(com_elem))
+ return commands
+
+ def parse_command(self,etree):
+ """
+ Parser function for single command.
+ """
+ cmd = Command()
+ cmd.set_executable(etree.get("executable"))
+ cmd.set_shell(etree.get("shell"))
+ cmd.set_bufsize(etree.get("bufsize"))
+ cmd.set_cwd(etree.get("cwd"))
+ cmd.set_all_envs(etree.get("env"))
+ cmd.set_all_arguments(self.parse_arguments(etree))
+ cmd.set_all_pipes(self.parse_pipes(etree))
+ cmd.set_filters(self.parse_filters(etree))
+ cmd.set_default_view(self.dview)
+ return cmd
+
+ def parse_arguments(self,etree):
+ """
+ Parser function for command's arguments.
+ """
+ arguments = []
+ for argument in etree.findall("{%s}argument" % self.namespaces[0]):
+ value = argument.get("value")
+ if value:
+ arguments.append(value)
+ return arguments
+
+ def parse_pipes(self,etree):
+ """
+ Parser function for command's pipes.
+ """
+ pipes = {}
+ for argument in etree.findall("{%s}pipe" % self.namespaces[0]):
+ name = argument.get("name")
+ value = argument.get("value")
+ if name:
+ pipes[name] = value
+ return pipes
+
+ def parse_filters(self,etree):
+ """
+ Parser function for command's filters.
+ """
+ filters = []
+ for argument in etree.findall("{%s}filter" % self.namespaces[0]):
+ f = Filter()
+ f.set_severity(argument.get("severity"))
+ f.set_condition(argument.get("condition"))
+ f.set_input(argument.get("input"))
+ f.set_formatter(argument.get("formatter"))
+ filters.append(f)
+ return filters
+
+ def parse_tags(self,etree):
+ tags = {}
+ for tag in etree.getiterator("{%s}tag" % self.namespaces[0]):
+ tagname = tag.get('name','')
+ tagvalue = tag.get('value')
+ values = tags.get(tagname,[])
+ values.append(tagvalue)
+ tags[tagname] = values
+ return tags
+
+
+class Condition(object):
+ """
+ Condition class is a simple wrapper class for commands so that commands are executed
+ only if condition is True. Otherwise class does nothing. Class has similar interface
+ than Command class so that they can be used similar way from plugin perspective.
+ """
+
+ def __init__(self):
+ self.condition = None
+ self.commands = []
+ self.logger = None
+ self.dview = None
+
+ def set_condition(self, condition):
+ self.condition = condition
+
+ def set_default_view(self, dview):
+ self.dview = dview
+
+ def set_commands(self, commands):
+ self.commands = commands
+
+ def set_logger(self, logger):
+ self.logger = logger
+ for cmd in self.commands:
+ cmd.set_logger(logger)
+
+ def add_command(self, command):
+ self.command.append(command)
+
+ def execute(self, replaceDict=None):
+ if self.__solve_condition(self.condition):
+ #Condition is true -> running command
+ for command in self.commands:
+ command.execute(replaceDict)
+ else:
+ self.logger.info("Ignoring %s because it is evaluated as False." % self.condition)
+
+ def __solve_condition(self, condition_str):
+ """
+ Internal function to handle condition
+ """
+ if condition_str != "":
+ #Expanding ConfML information
+ modstr = utils.expand_delimited_tokens(
+ condition_str,
+ lambda ref, index: repr(self.dview.get_feature(ref).get_value()))
+ return eval(modstr)
+ else:
+ #Empty condition is true always.
+ return True
+
+class Command(object):
+ """
+ Command is a class that executes actual commands. It provides ways to handle input, output and error
+ streams and to control execution parameters.
+ """
+
+ def __init__(self):
+ """
+ Constructor
+ """
+ self.executable = None
+ self.shell = False
+ self.bufsize = 0
+ self.cwd = None
+ self.envs = None
+ self.arguments = []
+ self.pipes = {}
+ self.streams = {}
+ self.filters = []
+ self.logger = None
+ self.dview = None
+
+ def set_executable(self, executable):
+ self.executable = executable
+
+ def set_shell(self, shell):
+ if shell and shell.lower() in ('true', 'yes', '1', 1, True):
+ self.shell = True
+ else:
+ self.shell = False
+
+ def set_bufsize(self, bufsize):
+ if bufsize:
+ self.bufsize = int(bufsize)
+
+ def set_cwd(self, cwd):
+ self.cwd = cwd
+
+ def set_all_envs(self, envs):
+ if envs:
+ self.envs = eval(envs)
+ def set_default_view(self, dview):
+ self.dview = dview
+
+ def set_env(self, name, value):
+ self.envs[name] = value
+
+ def set_all_arguments(self, args):
+ self.arguments = args
+
+ def get_arguments_string(self):
+ """
+ Function to return arguments as a string
+ """
+ arg_string = ""
+ for value in self.arguments:
+ arg_string += value
+ arg_string += " "
+ return arg_string
+
+ def get_pipe(self, name, mode='w'):
+ """
+ Function to return pipe based on the pipe name in requested mode.
+ """
+ if self.pipes.has_key(name) and isinstance(self.pipes[name], types.IntType):
+ #Subprocess pipe
+ return self.pipes[name]
+ elif self.pipes.has_key(name) and isinstance(self.pipes[name], types.StringType):
+ return file(self.pipes[name], mode)
+ else:
+ return None
+
+ def set_streams(self, stdin, stdout, stderr):
+ self.streams["stdin"] = stdin
+ self.streams["stdout"] = stdout
+ self.streams["stderr"] = stderr
+
+ def get_streams(self, name, mode="r"):
+ if self.streams.has_key(name) and self.streams[name]:
+ #OK for streams set with subprocess.PIPE
+ return self.streams[name]
+ else:
+ #For file objects
+ return self.get_pipe(name, mode)
+
+ def set_filters(self, filters):
+ self.filters = filters
+ for f in self.filters:
+ f.set_command(self)
+
+ def get_filters(self):
+ return self.filters
+
+ def set_argument(self, value):
+ self.arguments.append(value)
+
+ def set_all_pipes(self, pipes):
+ for pipe in pipes.keys():
+ self.set_pipe(pipe, pipes[pipe])
+
+ def set_pipe(self, name, value):
+ if value == "PIPE":
+ #Creating new stream for this.
+ self.pipes[name] = subprocess.PIPE
+ elif value == "STDOUT":
+ self.pipes[name] = subprocess.STDOUT
+ else:
+ #Setting filename
+ self.pipes[name] = value
+ #self.pipes[name] = file(value, 'w')
+
+ def handle_filters(self):
+ """
+ """
+ for filter in self.filters:
+ filter.report(self.logger)
+
+ def execute(self, replaceDict=None):
+ self.solve_refs()
+
+ exit_code = 0
+ try:
+ try:
+ if self.cwd is not None:
+ cwd = self.__replace_helper_variables(self.cwd, replaceDict)
+ else:
+ cwd = self.cwd
+ command_str = self.executable + " " + self.__replace_helper_variables(self.get_arguments_string(), replaceDict)
+ self.logger.info("Running command: \"%s\"" % command_str)
+ self.logger.info("with args: shell=%s envs=%s cwd=%s bufsize=%s stdin=%s stdout=%s stderr=%s" \
+ % (self.shell, self.envs, cwd, self.bufsize, \
+ self.get_pipe("stdin", 'r'),self.get_pipe("stdout"), self.get_pipe("stderr")))
+ pid = subprocess.Popen(command_str, shell=self.shell, env=self.envs, cwd=cwd,\
+ bufsize=self.bufsize, stdin = self.get_pipe("stdin", 'r'),\
+ stdout = self.get_pipe("stdout"), stderr = self.get_pipe("stderr"))
+ #Waiting for process to complete
+ retcode = pid.wait()
+ #Storing stream information for possible further processing.
+ self.set_streams(pid.stdin, pid.stdout, pid.stderr)
+
+ if retcode < 0:
+ self.logger.error("Child was terminated by signal %s" % (-retcode))
+ else:
+ self.logger.info("Child returned: %s" % retcode)
+ except OSError, e:
+ self.logger.error("Execution failed: %s", repr(e))
+ self.handle_filters()
+ except Exception,e:
+ utils.log_exception(self.logger, "Failed to execute command: %s" % e)
+
+ def set_logger(self, logger):
+ self.logger = logger
+
+ def __replace_helper_variables(self, inputstr, dictionary):
+ retstr = inputstr
+ for key in dictionary.keys():
+ retstr = retstr.replace(key, dictionary[key])
+ return retstr
+
+ def solve_refs(self):
+ """
+ Function to solve references just before generation.
+ """
+
+ self.executable = self.__solve_ref(self.executable)
+ self.shell = self.__solve_ref(self.shell)
+ self.bufsize = self.__solve_ref(self.bufsize)
+ self.cwd = self.__solve_ref(self.cwd)
+ for argument in self.arguments:
+ self.arguments[self.arguments.index(argument)] = self.__solve_ref(argument)
+ for pipe in self.pipes.keys():
+ self.pipes[pipe] = self.__solve_ref(self.pipes[pipe])
+
+ def __solve_ref(self, inputstr):
+ """
+ Internal function to solve whether input is ref or just normal input string.
+ For refs actual ConfML value is resolved and returned. Non-refs are returned
+ as such.
+ """
+ if inputstr and isinstance(inputstr, types.StringType):
+ return utils.expand_refs_by_default_view(inputstr, self.dview)
+ else:
+ return inputstr
+
+
+
+class Filter(object):
+ """
+ Filter class handles printing information to ConE log using filtering information.
+ Filtering severity, condition and the format of output can be configured in command ml.
+ """
+
+ def __init__(self):
+ self.severity = None
+ self.condition = None
+ self.input = None
+ self.command = None
+ self.formatter = None
+
+ def set_severity(self, severity):
+ self.severity = severity
+
+ def set_condition(self, condition):
+ self.condition = condition
+
+ def set_input(self, input):
+ self.input = input
+
+ def set_command(self, command):
+ self.command = command
+
+ def set_formatter(self, formatter):
+ self.formatter = formatter
+
+ def report(self, logger):
+ input_pipe = self.command.get_streams(self.input)
+ if isinstance(input_pipe, types.FileType):
+ #Subprocess.PIPE and file descriptors supported only.
+ data = input_pipe.read()
+ pattern = re.compile(self.condition)
+ for line in data.splitlines():
+ mo = pattern.match(line)
+ if mo:
+ lf = self.__get_logger_function(logger)
+ if self.formatter:
+ lf(self.formatter % mo.groupdict())
+ else:
+ lf(line)
+
+ def __get_logger_function(self, logger):
+ if self.severity == "info":
+ return logger.info
+ elif self.severity == "warning":
+ return logger.warning
+ elif self.severity == "debug":
+ return logger.debug
+ elif self.severity == "exception":
+ return logger.exception
+ elif self.severity == "error":
+ return logger.error
+ elif self.severity == "critical":
+ return logger.critical
+ else:
+ #Default
+ return logger.info
+
+
+
+
+
+
+
+