configurationengine/source/plugins/symbian/ConeImagePlugin/imageplugin/generators.py
changeset 0 2e8eeb919028
child 3 e7e0ae78773e
equal deleted inserted replaced
-1:000000000000 0:2e8eeb919028
       
     1 #
       
     2 # Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     3 # All rights reserved.
       
     4 # This component and the accompanying materials are made available
       
     5 # under the terms of "Eclipse Public License v1.0"
       
     6 # which accompanies this distribution, and is available
       
     7 # at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 #
       
     9 # Initial Contributors:
       
    10 # Nokia Corporation - initial contribution.
       
    11 #
       
    12 # Contributors:
       
    13 #
       
    14 # Description: 
       
    15 #
       
    16 '''
       
    17 Generator classes
       
    18 '''
       
    19 
       
    20 
       
    21 import re
       
    22 import os
       
    23 import sys
       
    24 import logging
       
    25 import subprocess
       
    26 import shutil
       
    27 
       
    28 ROOT_PATH = os.path.dirname(os.path.abspath(__file__))
       
    29 from cone.public import utils, exceptions
       
    30 
       
    31 class InvalidInputFileException(RuntimeError):
       
    32     """
       
    33     Exception thrown in case of an invalid input file list.
       
    34     """
       
    35     pass
       
    36 
       
    37 class OutputGenerator(object):
       
    38     def __init__(self,outputpath,**kwargs):
       
    39         self._configuration = None
       
    40         self._subpath = ''
       
    41         self._contentpath = ''
       
    42         self._command = ''
       
    43         self._inputs = []
       
    44         for arg in kwargs.keys():
       
    45             setattr(self, arg, kwargs[arg])
       
    46         self._outputpath = outputpath
       
    47 
       
    48     def __str__(self):
       
    49         return "Generator for output %s: %s"  % (self.path,self.get_command())
       
    50 
       
    51     def generate(self, context=None):
       
    52         command = self.get_command()
       
    53         if command:
       
    54             return command.execute()
       
    55         else:
       
    56             return 0
       
    57 
       
    58     def get_outputpath(self):
       
    59         """
       
    60         Get the confml ref value from configuration if the outputpath is actually a ref
       
    61         """
       
    62         if self._outputpath and ConfmlRefs.is_confml_ref(self._outputpath):
       
    63              oref = ConfmlRefs.get_confml_ref(self._outputpath)
       
    64              opath = self.configuration.get_default_view().get_feature(oref).get_value()
       
    65              if opath == None: 
       
    66                  logging.getLogger('cone.imageml').warning('Output path not set.')
       
    67                  return self._outputpath 
       
    68                  #raise exceptions.NotBound("Output path reference has no value %s" % oref)
       
    69              (drive,opath) = os.path.splitdrive(opath)
       
    70              opath = utils.resourceref.norm(opath)
       
    71              opath = utils.resourceref.remove_begin_slash(opath)
       
    72              return opath
       
    73         else:
       
    74              return self._outputpath
       
    75 
       
    76     def set_outputpath(self, value): 
       
    77         self._outputpath = value
       
    78 
       
    79     def del_outputpath(self): 
       
    80         self._outputpath = None
       
    81 
       
    82     def get_subpath(self):
       
    83         return self._subpath
       
    84 
       
    85     def set_subpath(self, value): 
       
    86         self._subpath = value
       
    87 
       
    88     def del_subpath(self): 
       
    89         self._subpath = None
       
    90 
       
    91     def get_inputs(self): 
       
    92         return self._inputs
       
    93 
       
    94     def set_inputs(self, value): 
       
    95         self._inputs = value
       
    96 
       
    97     def del_inputs(self): 
       
    98         self._inputs = []
       
    99 
       
   100     def get_configuration(self): 
       
   101         return self._configuration
       
   102 
       
   103     def set_configuration(self, value): 
       
   104         self._configuration= value
       
   105         for input in self.inputs:
       
   106             input.configuration = self.configuration
       
   107 
       
   108     def del_configuration(self): 
       
   109         self._configuration= None
       
   110 
       
   111     @property
       
   112     def path(self):
       
   113         return utils.resourceref.join_refs([self.subpath, self.outputpath])
       
   114 
       
   115     def get_command(self):
       
   116         (_,ext) = os.path.splitext(self.path)
       
   117         if ext == '.mbm':
       
   118             return BmconvCommand(self)
       
   119         elif ext == '.mif':
       
   120             return MifconvCommand(self)
       
   121         elif ext == '.gif':
       
   122             return CopyCommand(self)
       
   123         else:
       
   124             return None
       
   125     
       
   126     def get_refs(self):
       
   127         refs = []
       
   128         for input in self.inputs:
       
   129             refs.extend(input.get_refs())
       
   130         return refs
       
   131 
       
   132     configuration = property(get_configuration, set_configuration, del_configuration)
       
   133     inputs = property(get_inputs, set_inputs, del_inputs)
       
   134     outputpath = property(get_outputpath, set_outputpath, del_outputpath)
       
   135     subpath = property(get_subpath, set_subpath, del_subpath)
       
   136 
       
   137 class Command(object):
       
   138     def __init__(self,generator):
       
   139         self._generator = generator
       
   140         self._workdir = 'conversion_workdir'
       
   141 
       
   142     def execute(self):
       
   143         """ Execute this command """
       
   144         pass
       
   145 
       
   146     def get_command(self, input_files):
       
   147         """ return the command as an array """
       
   148         return []
       
   149 
       
   150     def create_workdir(self, input_files):
       
   151         """
       
   152         Extract the necessary input files from storage to a working directory
       
   153         @param input_files: The input files (a list of InputFile objects) 
       
   154         """
       
   155         if not os.path.exists(self._workdir):
       
   156             os.makedirs(self._workdir)
       
   157         
       
   158         for file in input_files:
       
   159             self.import_to_work(file.filename)
       
   160 
       
   161     def clean_workdir(self):
       
   162         """
       
   163         Clean up working directory 
       
   164         """
       
   165         if os.path.exists(self._workdir):
       
   166             shutil.rmtree(self._workdir)
       
   167 
       
   168     def import_to_work(self,storage_filename):
       
   169         """
       
   170         Convert a storage filename to a work filename
       
   171         """
       
   172         workfile = self.workfilename(storage_filename)
       
   173         res = self._generator.configuration.get_resource(storage_filename,"rb")
       
   174         workfile = open(workfile,"wb")
       
   175         workfile.write(res.read())
       
   176         res.close()
       
   177         workfile.close()
       
   178 
       
   179     def workfilename(self,filename):
       
   180         """
       
   181         Convert a storage filename to a work filename
       
   182         """
       
   183         (_,workname) = os.path.split(filename)
       
   184         return os.path.join(self.workdir,workname)
       
   185 
       
   186     def quote_needed(self,str):
       
   187         """
       
   188         Add quotes around str if it has spaces
       
   189         """
       
   190         if str.split(' ',1) > 1:
       
   191             return '"%s"' % str
       
   192         else:
       
   193             return str
       
   194         
       
   195     @property
       
   196     def tool(self):
       
   197         return ''
       
   198 
       
   199     @property
       
   200     def generator(self):
       
   201         return self._generator
       
   202 
       
   203     @property
       
   204     def workdir(self):
       
   205         return self._workdir
       
   206     
       
   207     def _get_filtered_input_files(self):
       
   208         """
       
   209         Get the list of InputFile objects and with ignored
       
   210         (optional empty or invalid files) entries filtered out.
       
   211         
       
   212         Raise InvalidInputFileException if the input file list is invalid.
       
   213         """
       
   214         # Get all input files
       
   215         input_files = []
       
   216         for input in self.generator.inputs:
       
   217             input_files.extend(input.files)
       
   218         
       
   219         # Check if all are empty
       
   220         all_empty = True
       
   221         for file in input_files:
       
   222             if not file.is_empty():
       
   223                 all_empty = False
       
   224                 break
       
   225         if all_empty:
       
   226             return []
       
   227         
       
   228         # Create the filtered list
       
   229         result = []
       
   230         for file in input_files:
       
   231             if file.is_empty():
       
   232                 if file.is_optional():
       
   233                     # Optional file is empty: no error
       
   234                     pass
       
   235                 else:
       
   236                     raise InvalidInputFileException("Input file empty but not optional")
       
   237             else:
       
   238                 if not file.is_valid():
       
   239                     raise InvalidInputFileException("Invalid input file: '%s'" % file.path)
       
   240                 else:
       
   241                     result.append(file)
       
   242         return result 
       
   243 
       
   244 class BmconvCommand(Command):
       
   245     def __init__(self,generator):
       
   246         super(BmconvCommand, self).__init__(generator)
       
   247 
       
   248     def execute(self):
       
   249         """
       
   250         Execute the command in the current working directory
       
   251         """
       
   252         input_files = self._get_filtered_input_files()
       
   253         if len(input_files) == 0: return 0
       
   254         self.create_workdir(input_files)
       
   255         
       
   256         if not os.path.exists(os.path.dirname(self.generator.path)):
       
   257             os.makedirs(os.path.dirname(self.generator.path))
       
   258         
       
   259         command = self.get_command(input_files)
       
   260         p = subprocess.Popen(command,
       
   261                              stdout=subprocess.PIPE,
       
   262                              stderr=subprocess.PIPE)
       
   263         
       
   264         # Wait for the process to return
       
   265         out, err = [ e.splitlines() for e in p.communicate() ]
       
   266         for outl in out:
       
   267             if outl not in err:
       
   268                 logging.getLogger('cone.bmconv').info(outl)
       
   269         for outl in err:
       
   270             logging.getLogger('cone.bmconv').error(outl)
       
   271         if p.returncode != 0:
       
   272             logging.getLogger('cone.bmconv').error("Command returned with returncode %s: %s" % (p.returncode, ' '.join(command)))
       
   273         else:
       
   274             logging.getLogger('cone.bmconv').info("Command returned with returncode %s: %s" % (p.returncode, ' '.join(command)))
       
   275         if p.returncode == 0:
       
   276         	self.clean_workdir()
       
   277         return p.returncode 
       
   278 
       
   279     def get_command(self, input_files):
       
   280         command = [self.tool]
       
   281         """ Add palette file """
       
   282         if hasattr(self._generator,'palette'):
       
   283             command.append('/p%s' % os.path.abspath(self.generator.palette))
       
   284 
       
   285         """ Add output file """
       
   286         """ Add output file as compressed if needed """
       
   287         if self.rom:
       
   288             if self.compress:
       
   289                 command.append('/s')
       
   290             else:
       
   291                 command.append('/r')
       
   292         else:
       
   293             pass
       
   294         command.append(os.path.normpath(self.generator.path))
       
   295         
       
   296         
       
   297         for inputfile in input_files:
       
   298             depth = ''
       
   299             if inputfile.depth:
       
   300                 depth = '/%s' % inputfile.depth
       
   301             command.append('%s%s' % (depth,self.workfilename(inputfile.filename)))
       
   302         return command
       
   303 
       
   304     @property
       
   305     def tool(self):
       
   306         if hasattr(self._generator,'tool'):
       
   307             return os.path.abspath(self._generator.tool)
       
   308         elif hasattr(self._generator, 'tooldir'):
       
   309             return os.path.abspath(os.path.join(self._generator.tooldir, 'bmconv'))
       
   310         else:
       
   311             return 'bmconv'
       
   312 
       
   313     @property
       
   314     def rom(self):
       
   315         if hasattr(self._generator,'rom') and self._generator.rom.lower() == 'true':
       
   316             return True
       
   317         else:
       
   318             return False
       
   319 
       
   320     @property
       
   321     def compress(self):
       
   322         if hasattr(self._generator,'compress') and self._generator.compress.lower() == 'true':
       
   323             return True
       
   324         else:
       
   325             return False
       
   326 
       
   327 class MifconvCommand(Command):
       
   328     def __init__(self,generator):
       
   329         super(MifconvCommand, self).__init__(generator)
       
   330 
       
   331     def execute(self):
       
   332         """
       
   333         Execute the command in the current working directory
       
   334         """
       
   335         input_files = self._get_filtered_input_files()
       
   336         if len(input_files) == 0: return 0
       
   337         self.create_workdir(input_files)
       
   338         
       
   339         runenv = None
       
   340         runshell = True
       
   341         if os.path.dirname(self.tool):
       
   342             runenv = {}
       
   343             runenv['path'] = os.path.dirname(self.tool)
       
   344             runshell = True
       
   345         if not os.path.exists(os.path.dirname(self.generator.path)):
       
   346             os.makedirs(os.path.dirname(self.generator.path))
       
   347         
       
   348         command = self.get_command(input_files)
       
   349         p = subprocess.Popen(command,
       
   350                              stdout=subprocess.PIPE,
       
   351                              stderr=subprocess.PIPE,
       
   352                              env=runenv,
       
   353                              shell=runshell)
       
   354         
       
   355         # Wait for the process to return
       
   356         out, err = [ e.splitlines() for e in p.communicate() ]
       
   357         for outl in out:
       
   358             if outl not in err:
       
   359                 logging.getLogger('cone.mifconv').info(outl)
       
   360         for outl in err:
       
   361             logging.getLogger('cone.mifconv').error(outl)
       
   362         if p.returncode != 0:
       
   363             logging.getLogger('cone.mifconv').error("Command returned with returncode %s: %s" % (p.returncode, ' '.join(command)))
       
   364         else:
       
   365             logging.getLogger('cone.mifconv').info("Command returned with returncode %s: %s" % (p.returncode, ' '.join(command)))
       
   366         if p.returncode == 0:
       
   367 	        self.clean_workdir()
       
   368         return p.returncode 
       
   369 
       
   370     def get_command(self, input_files):
       
   371         command = [self.tool]
       
   372         
       
   373         """ Add output file """
       
   374         command.append(os.path.normpath(self.generator.path))
       
   375         
       
   376         """ Add temp_path """
       
   377         command.append("/t%s" % self.temppath)
       
   378         
       
   379         # Add tool directory if given
       
   380         if hasattr(self._generator,'tooldir'):
       
   381             command.append('/S%s' % os.path.abspath(self.generator.tooldir))
       
   382         
       
   383         """ Get input files """
       
   384         for inputfile in input_files:
       
   385             depth = 'c8'
       
   386             if inputfile.depth:
       
   387                 depth = inputfile.depth
       
   388             command.append('/%s' % depth)
       
   389             command.append( '%s' % self.workfilename(inputfile.filename))
       
   390         return command
       
   391 
       
   392     @property
       
   393     def tool(self):
       
   394         if hasattr(self._generator,'tool'):
       
   395             return os.path.abspath(self._generator.tool)
       
   396         elif hasattr(self._generator, 'tooldir'):
       
   397             return os.path.abspath(os.path.join(self._generator.tooldir, 'mifconv'))
       
   398         else:
       
   399             return 'mifconv'
       
   400 
       
   401     @property
       
   402     def temppath(self):
       
   403         if hasattr(self._generator,'temp'):
       
   404             return os.path.abspath(self._generator.temp)
       
   405         else:
       
   406             return self.workdir
       
   407 
       
   408 class CopyCommand(object):
       
   409     def __init__(self,generator):
       
   410         self._generator = generator
       
   411 
       
   412     def execute(self):
       
   413         pass
       
   414 
       
   415     @property
       
   416     def tool(self):
       
   417         return 'copy'
       
   418 
       
   419 class InputFile(object):
       
   420     def __init__(self,path,**kwargs):
       
   421         self.configuration = None
       
   422         self._depth = None
       
   423         for arg in kwargs.keys():
       
   424             if arg == 'depth':
       
   425                 # Special handling for depth ('depth' is a property that
       
   426                 # expands refs using '_depth' as the base)
       
   427                 self._depth = kwargs[arg]
       
   428             else:
       
   429                 setattr(self, arg, kwargs[arg])
       
   430         self._path= path
       
   431 
       
   432     def get_input(self): 
       
   433         """ 
       
   434         Get the confml ref value from configuration if the outputpath is actually a ref 
       
   435         """
       
   436         if self._path and self.configuration is not None:
       
   437             dview = self.configuration.get_default_view()
       
   438             def expand(ref, index):
       
   439                 value = dview.get_feature(ref).get_original_value()
       
   440                 if value is None:   return ''
       
   441                 else:               return value
       
   442             return utils.expand_delimited_tokens(self._path, expand)
       
   443         else:
       
   444             return self._path
       
   445 
       
   446     def set_input(self, value): self._path = value
       
   447 
       
   448     def del_input(self): self._path = None
       
   449 
       
   450     @property 
       
   451     def type(self):
       
   452         return 'file'
       
   453     
       
   454     @property
       
   455     def depth(self):
       
   456         if self._depth and self.configuration:
       
   457             dview = self.configuration.get_default_view()
       
   458             return utils.expand_refs_by_default_view(self._depth, dview)
       
   459         else:
       
   460             return self._depth or ''
       
   461 
       
   462     @property 
       
   463     def files(self):
       
   464         """ 
       
   465         Return a list of file names 
       
   466         """
       
   467         return [self]
       
   468         
       
   469     @property 
       
   470     def filename(self):
       
   471         """ 
       
   472         Return a the path to the layer specific filename
       
   473         """ 
       
   474         if self.configuration and self.path:
       
   475             content = self.configuration.layered_content().flatten()
       
   476             inputpath = self.path
       
   477             return content.get(inputpath)
       
   478         else:
       
   479             return self.path
       
   480 
       
   481     path = property(get_input, set_input, del_input, "The input 'path'.")
       
   482     
       
   483     def is_valid(self):
       
   484         """
       
   485         Return whether the input file is valid (not empty
       
   486         and exists in project content).
       
   487         """
       
   488         return not self.is_empty() and self.filename
       
   489     
       
   490     def is_empty(self):
       
   491         """
       
   492         Return whether the input file is empty.
       
   493         """
       
   494         return self.path in ('', None)
       
   495     
       
   496     def is_optional(self):
       
   497         """
       
   498         Return whether the input file is optional.
       
   499         """
       
   500         return hasattr(self, 'optional') \
       
   501             and self.optional.lower() in ('1', 't', 'true', 'yes', 'y')
       
   502     
       
   503     def get_refs(self):
       
   504         return utils.extract_delimited_tokens(self._path)
       
   505     
       
   506     def __repr__(self):
       
   507         return "InputFile(path=%r, optional=%r)" % (self._path, self.is_optional())
       
   508 
       
   509 class InputDir(InputFile):
       
   510     def __init__(self,path,**kwargs):
       
   511         super(InputDir,self).__init__(path,**kwargs)
       
   512         self._files = []
       
   513         self._include = None
       
   514         self._exclude = None
       
   515 
       
   516     def get_include(self): 
       
   517         return self._include.get('pattern',[])
       
   518 
       
   519     def set_include(self, value): 
       
   520         self._include = value
       
   521 
       
   522     def del_include(self): 
       
   523         self._include = None
       
   524 
       
   525     def get_exclude(self):
       
   526         return self._exclude.get('pattern',[])
       
   527 
       
   528     def set_exclude(self, value): 
       
   529         self._exclude = value
       
   530 
       
   531     def del_exclude(self): 
       
   532         self._exclude = None
       
   533 
       
   534     @property 
       
   535     def type(self): 
       
   536         return 'dir'
       
   537 
       
   538     @property 
       
   539     def files(self):
       
   540         """ 
       
   541         Return a list of file names under this directory definition
       
   542         """ 
       
   543         if self.configuration:
       
   544             inputlist = []
       
   545             content = self.configuration.layered_content().flatten()
       
   546             contentfiles = content.keys()
       
   547             
       
   548             folderfiles = utils.resourceref.filter_resources(contentfiles, "^%s" % self.path)
       
   549             for inputfilter in self.include:
       
   550                 folderfiles = utils.resourceref.filter_resources(folderfiles, inputfilter)
       
   551             for excludefilter in self.exclude:
       
   552                 folderfiles = utils.resourceref.neg_filter_resources(folderfiles, excludefilter)
       
   553             folderfiles.sort()
       
   554             for filename in folderfiles:
       
   555                 inputlist.append(InputFile(filename, **self.__dict__))
       
   556             return inputlist
       
   557         else:
       
   558             return []
       
   559 
       
   560     include = property(get_include, set_include, del_include)
       
   561     exclude = property(get_exclude, set_exclude, del_exclude)
       
   562 
       
   563 
       
   564 
       
   565 class ConfmlRefs(object):
       
   566     
       
   567     ref_pattern = re.compile('^\$\{(.*)\}$')
       
   568 
       
   569     @classmethod
       
   570     def is_confml_ref(cls, variableref):
       
   571         """
       
   572         
       
   573         Returns true if the given variable ref is a confml reference
       
   574         """
       
   575         return cls.ref_pattern.match(variableref) != None
       
   576 
       
   577     @classmethod
       
   578     def get_confml_ref(cls, variableref):
       
   579         """
       
   580         
       
   581         Returns true if the given variable ref is a confml reference
       
   582         """
       
   583         matchref = cls.ref_pattern.match(variableref)
       
   584         if matchref:
       
   585             return matchref.group(1)
       
   586         else:
       
   587             return None