--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/configurationengine/source/plugins/common/ConeContentPlugin/contentplugin/contentmlparser.py Thu Mar 11 17:04:37 2010 +0200
@@ -0,0 +1,452 @@
+#
+# 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 Teemu Rytkonen
+'''
+A plugin implementation for content selection from ConfigurationLayers.
+'''
+
+
+import re
+import os
+import sys
+import logging
+import shutil
+import copy
+import xml.parsers.expat
+
+try:
+ from cElementTree import ElementTree
+except ImportError:
+ try:
+ from elementtree import ElementTree
+ except ImportError:
+ try:
+ from xml.etree import cElementTree as ElementTree
+ except ImportError:
+ from xml.etree import ElementTree
+
+import __init__
+
+from cone.public import exceptions,plugin,utils,api
+
+class ContentOutput(object):
+ def __init__(self, **kwargs):
+ self._dir = kwargs.get('dir',None)
+ self._file = kwargs.get('file',None)
+ self.flatten = kwargs.get('flatten',False)
+ self.inputs = kwargs.get('inputs', [])
+ self.configuration = None
+
+ def set_configuration(self, configuration):
+ self.configuration = configuration
+ for input in self.inputs:
+ input.configuration = self.configuration
+
+ def get_configuration(self, configuration):
+ self.configuration = configuration
+
+ def path_convert(self, path):
+ (drive, tail) = os.path.splitdrive(path)
+ return tail.lstrip('\\/')
+
+ def get_dir(self):
+ if self.configuration and ConfmlRefs.is_confml_ref(self._dir):
+ parts = self._dir.split(ConfmlRefs.ref_separator)
+ for (index, part) in enumerate(parts):
+ if ConfmlRefs.is_confml_ref(part):
+ ref = ConfmlRefs.get_confml_ref(part)
+ parts[index] = self.configuration.get_default_view().get_feature(ref).value
+ parts[index] = self.path_convert(parts[index])
+ else:
+ parts[index] = part
+ return (os.sep).join(parts)
+ else:
+ return self.path_convert(self._dir)
+
+ def set_dir(self, dir):
+ self._dir = dir
+
+ def get_file(self):
+ if self.configuration and self._file != None and ConfmlRefs.is_confml_ref(self._file):
+ parts = self._file.split(ConfmlRefs.ref_separator)
+ for (index, part) in enumerate(parts):
+ if ConfmlRefs.is_confml_ref(part):
+ ref = ConfmlRefs.get_confml_ref(part)
+ parts[index] = self.configuration.get_default_view().get_feature(ref).value
+ parts[index] = self.path_convert(parts[index])
+ else:
+ parts[index] = part
+ return (os.sep).join(parts)
+ else:
+ return self._file
+
+ def set_file(self, file):
+ self._file = file
+
+ dir = property(get_dir, set_dir)
+ file = property(get_file, set_file)
+
+ def get_refs(self):
+ refs = []
+ for input in self.inputs:
+ refs.extend(input.get_refs())
+ return refs
+
+
+class ContentInput(object):
+ def __init__(self, **kwargs):
+ self._dir = kwargs.get('dir',None)
+ self._file = kwargs.get('file',None)
+ self._include = kwargs.get('include', {})
+ self._exclude = kwargs.get('exclude', {})
+ self.configuration = None
+
+ @property
+ def dir(self):
+
+ if self.configuration and ConfmlRefs.is_confml_ref(self._dir):
+ cref = ConfmlRefs.get_confml_ref(self._dir)
+ return self.configuration.get_default_view().get_feature(cref).value
+ else:
+ return self._dir
+
+ @property
+ def file(self):
+
+ if self._file and self.configuration and ConfmlRefs.is_confml_ref(self._file):
+ cref = ConfmlRefs.get_confml_ref(self._file)
+ return self.configuration.get_default_view().get_feature(cref).value
+ else:
+ return self._file
+
+
+ def _dereference_dict(self, data):
+ if self.configuration:
+ # Make a deep copy of the data, or otherwise get_refs() will
+ # return the correct refs only on the first call, as the
+ # references are replaced here
+ data = copy.deepcopy(data)
+
+ dview = self.configuration.get_default_view()
+ for key in data:
+ key_list = data.get(key)
+ for (index,elem) in enumerate(key_list):
+ if ConfmlRefs.is_confml_ref(elem):
+ cref = ConfmlRefs.get_confml_ref(elem)
+ try:
+ # change None value to empty string
+ cvalue = dview.get_feature(cref).value or ''
+ if utils.is_list(cvalue):
+ cvalue = ", ".join(cvalue)
+ key_list[index] = cvalue
+ except exceptions.NotFound:
+ logging.getLogger('cone.content').error("Feature ref '%s' in include key '%s' not found." % (cref,key))
+ return data
+
+ @property
+ def include(self):
+ return self._dereference_dict(self._include)
+
+ @property
+ def exclude(self):
+ return self._dereference_dict(self._exclude)
+
+ def get_filelist(self):
+ filelist = []
+ if self.file:
+ filelist.append(self.file)
+ for elem in self.include.get('files',[]):
+ elem = elem.lower().split(',')
+ filelist += [selem.strip() for selem in elem]
+ return filelist
+
+ def get_include_pattern(self):
+ return self.include.get('pattern',[''])[0]
+
+ def get_exclude_pattern(self):
+ return self.exclude.get('pattern',[''])[0]
+
+ def get_refs(self):
+ refs = []
+ if self._dir is not None:
+ refs.extend(utils.extract_delimited_tokens(self._dir))
+ if self._file is not None:
+ refs.extend(utils.extract_delimited_tokens(self._file))
+ for value_list in self._include.itervalues():
+ for value in value_list:
+ refs.extend(utils.extract_delimited_tokens(value))
+ for value_list in self._exclude.itervalues():
+ for value in value_list:
+ refs.extend(utils.extract_delimited_tokens(value))
+ return refs
+
+
+class ExternalContentInput(ContentInput):
+ def __init__(self, **kwargs):
+ super(ExternalContentInput,self).__init__(**kwargs)
+
+class ContentParserBase(object):
+ """
+ Parses a single content implml file
+ """
+ NAMESPACES = ['http://www.s60.com/xml/content/1']
+ INCLUDE_ATTR = ['pattern']
+ EXCLUDE_ATTR = ['pattern']
+ def __init__(self):
+ self.namespaces = self.NAMESPACES
+
+ def parse_phase(self,etree):
+ phase = ""
+ phase = etree.get('phase')
+ return phase
+
+ def parse_desc(self,etree):
+ desc = ""
+ desc_elem = etree.find("{%s}desc" % self.namespaces[0])
+ if desc_elem != None:
+ desc = desc_elem.text
+ return desc
+
+ 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
+
+ def parse_input_include(self,etree):
+ include_elem = etree.getiterator("{%s}include" % self.namespaces[0])
+ include = {}
+ for f in include_elem:
+ for key in f.keys():
+ # Add the attribute if it is found to include dict
+ include[key] = []
+ include[key].append(f.get(key))
+ return include
+
+ def parse_input_exclude(self,etree):
+ elem = etree.getiterator("{%s}exclude" % self.namespaces[0])
+ exclude = {}
+ for f in elem:
+ for key in f.keys():
+ # Add the attribute if it is found
+ exclude[key] = []
+ exclude[key].append(f.get(key))
+ return exclude
+
+class Content1Parser(ContentParserBase):
+ """
+ Parses a single content implml file
+ """
+ NAMESPACES = ['http://www.s60.com/xml/content/1']
+ def __init__(self):
+ super(ContentParserBase,self).__init__()
+ self.namespaces = self.NAMESPACES
+
+ def parse_input(self,etree):
+ input_elem = etree.find("{%s}input" % self.namespaces[0])
+ input_dir = ""
+ input_file = ""
+ if input_elem != None:
+ if input_elem.get('dir'):
+ input_dir = input_elem.get('dir')
+ if input_elem.get('file'):
+ input_dir = input_elem.get('file')
+ includes = self.parse_input_include(etree)
+ excludes = self.parse_input_exclude(etree)
+ return ContentInput(dir=input_dir, include=includes, exclude=excludes, file=input_file)
+ return None
+
+ def parse_outputs(self,etree):
+ output_elem = etree.find("{%s}output" % self.namespaces[0])
+ output_dir = ""
+ output_flatten = False
+ inputs = []
+ if output_elem != None:
+ output_dir = output_elem.get('dir','')
+ output_flatten = output_elem.get('flatten','') == "true"
+ input = self.parse_input(etree)
+ if input:
+ inputs.append(input)
+ return [ContentOutput(dir=output_dir, flatten=output_flatten, inputs=inputs)]
+
+class Content2Parser(ContentParserBase):
+ """
+ Parses a single content implml file
+ """
+ NAMESPACES = ['http://www.s60.com/xml/content/2']
+ def __init__(self):
+ super(ContentParserBase,self).__init__()
+ self.namespaces = self.NAMESPACES
+
+
+ def parse_input(self,input_elem):
+ input = None
+ input_dir = ''
+ input_file = ''
+ if input_elem != None:
+ if input_elem.get('dir'):
+ input_dir = input_elem.get('dir')
+ if input_elem.get('file'):
+ input_file= input_elem.get('file')
+ includes = self.parse_input_include(input_elem)
+ excludes = self.parse_input_exclude(input_elem)
+ input = ContentInput(dir=input_dir, include=includes, exclude=excludes, file=input_file)
+ return input
+
+ def parse_external_input(self,input_elem):
+ input = None
+ input_dir = ''
+ if input_elem != None:
+ if input_elem.get('dir'):
+ input_dir = input_elem.get('dir')
+ includes = self.parse_input_include(input_elem)
+ excludes = self.parse_input_exclude(input_elem)
+ input = ExternalContentInput(dir=input_dir, include=includes, exclude=excludes)
+ return input
+
+ def parse_outputs(self,etree):
+ outputs = []
+ for output_elem in etree.getiterator("{%s}output" % self.namespaces[0]):
+ inputs = []
+ output_dir = output_elem.get('dir','')
+ output_file = output_elem.get('file','')
+ output_flatten = output_elem.get('flatten','') == "true"
+ for input_elem in output_elem.getiterator("{%s}input" % self.namespaces[0]):
+ inputs.append(self.parse_input(input_elem))
+ for input_elem in output_elem.getiterator("{%s}externalinput" % self.namespaces[0]):
+ inputs.append(self.parse_external_input(input_elem))
+ outputs.append(ContentOutput(dir=output_dir, flatten=output_flatten, inputs=inputs, file=output_file))
+ return outputs
+
+
+class ContentImplReader(object):
+ """
+ Parses a single content implml file
+ """
+ PARSERS = {'http://www.s60.com/xml/content/1' : Content1Parser,
+ 'http://www.s60.com/xml/content/2' : Content2Parser}
+ def __init__(self):
+ self.desc = None
+ self.outputs = None
+ self.phase = None
+
+ def fromstring(self, xml_as_string):
+ etree = ElementTree.fromstring(xml_as_string)
+ # Loop through parsers and try to find a match
+ (namespace,elemname) = get_elemname(etree.tag)
+ pclass = self.PARSERS.get(namespace, None)
+ self.parser = pclass()
+ self.desc = self.parser.parse_desc(etree)
+ self.outputs = self.parser.parse_outputs(etree)
+ self.phase = self.parser.parse_phase(etree)
+ self.tags = self.parser.parse_tags(etree)
+ return
+
+namespace_pattern = re.compile("{(.*)}(.*)")
+nonamespace_pattern = re.compile("(.*)")
+
+def get_elemname(tag):
+
+ ns = namespace_pattern.match(tag)
+ nn = nonamespace_pattern.match(tag)
+ if ns:
+ namespace = ns.group(1)
+ elemname = ns.group(2)
+ return (namespace,elemname)
+ elif nn:
+ namespace = ""
+ elemname = nn.group(1)
+ return (namespace,elemname)
+ else:
+ raise exceptions.ParseError("Could not parse tag %s" % tag)
+
+class ConfmlRefs(object):
+
+ ref_pattern = re.compile('^\$\{(.*)\}$')
+ cref_pattern = re.compile('.+\..+')
+ ref_separator = '/'
+
+ @classmethod
+ def is_ref_like(cls, variableref):
+ """
+
+ Returns true if the given variable represents a ref
+ """
+ return cls.cref_pattern.match(variableref) != None
+
+ @classmethod
+ def is_confml_ref(cls, variableref):
+ """
+
+ Returns true if the given variable ref is a confml reference
+ """
+
+ pos = variableref.find(cls.ref_separator)
+ if pos == -1:
+ return cls.ref_pattern.match(variableref) != None
+ else:
+ return cls.is_confml_refs(variableref)
+
+ @classmethod
+ def is_confml_refs(cls, variableref):
+ """
+
+ Returns true if the given variable ref is a confml reference
+ """
+ ret = False
+ parts = variableref.split(cls.ref_separator)
+ for p in parts:
+ if cls.is_confml_ref(p) == True:
+ ret = True
+ return ret
+
+
+ @classmethod
+ def get_confml_ref(cls, variableref):
+ """
+
+ Returns true if the given variable ref is a confml reference
+ """
+ pos = variableref.find(cls.ref_separator)
+ if pos == -1:
+ matchref = cls.ref_pattern.match(variableref)
+ if matchref:
+ return matchref.group(1)
+ else:
+ return cls.get_confml_refs(variableref)
+
+ @classmethod
+ def get_confml_refs(cls, variableref):
+ """
+
+ Returns an array of confml refs based on variableref
+ """
+ parts = variableref.split(cls.ref_separator)
+ ret = []
+ for p in parts:
+ matchref = cls.ref_pattern.match(p)
+ if matchref:
+ ref = matchref.group(1)
+ if not ref in ret:
+ ret.append(matchref.group(1))
+ else:
+ ret.append(p)
+ return ret
\ No newline at end of file