buildframework/helium/sf/python/pythoncore/lib/archive/builders.py
changeset 587 85df38eb4012
child 588 c7c26511138f
equal deleted inserted replaced
217:0f5e3a7fb6af 587:85df38eb4012
       
     1 #============================================================================ 
       
     2 #Name        : builders.py 
       
     3 #Part of     : Helium 
       
     4 
       
     5 #Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     6 #All rights reserved.
       
     7 #This component and the accompanying materials are made available
       
     8 #under the terms of the License "Eclipse Public License v1.0"
       
     9 #which accompanies this distribution, and is available
       
    10 #at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
    11 #
       
    12 #Initial Contributors:
       
    13 #Nokia Corporation - initial contribution.
       
    14 #
       
    15 #Contributors:
       
    16 #
       
    17 #Description:
       
    18 #===============================================================================
       
    19 
       
    20 """
       
    21 This modules contains the archive builders.
       
    22 An archive builder is a class that is able to use data from a configuration
       
    23 and generate a set of shell commands.
       
    24 """
       
    25 import archive.tools
       
    26 import archive.selectors
       
    27 import archive.mappers
       
    28 import archive.scanners
       
    29 import logging
       
    30 import pathaddition.relative
       
    31 import buildtools
       
    32 import os
       
    33 import codecs
       
    34 import fileutils
       
    35 
       
    36 _logger = logging.getLogger('archive')
       
    37 _logger.setLevel(logging.INFO)
       
    38 
       
    39 class ArchivePreBuilder(buildtools.PreBuilder):
       
    40     """ Processes an archive build specification. """
       
    41     def __init__(self, config_set, config_name, writerType='ant', index = None):
       
    42         buildtools.PreBuilder.__init__(self, config_set)
       
    43         self.configs = config_set.getConfigurations()
       
    44         self.spec_name = config_name
       
    45         self.index = index
       
    46         self.writerType = writerType
       
    47         self.listToFindPrefix = []
       
    48 
       
    49     def build_manifest(self, config):
       
    50         """ Generate a manifest file from the a configuration. """
       
    51         _logger.info('Processing archive config: ' + config['name'])
       
    52         _scanners = archive.scanners.get_scanners(config.get_list('scanners', ['default']), config)
       
    53         
       
    54         content_list = {}
       
    55     
       
    56         if not os.path.exists(config['temp.build.dir']):
       
    57             os.makedirs(config['temp.build.dir'])
       
    58         manifest_file_path = os.path.abspath(os.path.join(config['temp.build.dir'], config['name'] + '_includefile.txt'))
       
    59         out = codecs.open(manifest_file_path, 'w+', 'utf-8')
       
    60         
       
    61         # zip.root.dir can be set to root.dir so that when zipping from another dir,
       
    62         # the manifest is relative to that dir
       
    63         (_, root_dir) = os.path.splitdrive(os.path.normpath(config.get('zip.root.dir', config['root.dir'])))
       
    64         _logger.info("   * Scanning")
       
    65         for scanner in _scanners:
       
    66             _logger.debug("Scanner %s" % scanner)
       
    67             for subpath in scanner.scan():
       
    68                 (_, subpath) = os.path.splitdrive(subpath)
       
    69                 if pathaddition.relative.abs2rel(subpath, root_dir):
       
    70                     _logger.debug(subpath)
       
    71                     subpath = subpath[len(root_dir):]
       
    72                     if subpath.startswith(os.sep):
       
    73                         subpath = subpath[1:]
       
    74                 # normpath is to remove any occurances of "..\.." before checking for duplicates
       
    75                 subpath = os.path.normpath(subpath)
       
    76                 if subpath not in content_list:
       
    77                     out.write(u"".join([subpath, u'\n']))
       
    78                     content_list[subpath] = True
       
    79     
       
    80         out.close()
       
    81         return manifest_file_path
       
    82 
       
    83     def manifest_to_commands(self, config, manifest):
       
    84         """ Generate return a command list. Commands are stored in a two dimension array."""
       
    85         _logger.info("   * Generating commands")
       
    86         tool = archive.tools.get_tool(config['archive.tool'])
       
    87         mapper_name = 'default'
       
    88         if config.has_key('mapper'):
       
    89             mapper_name = config['mapper']
       
    90         mapper = archive.mappers.get_mapper(mapper_name, config, tool)
       
    91         return mapper.create_commands(manifest)
       
    92     
       
    93     def create_command_list(self, commands):
       
    94         """ Convert a two dimensions array of command to a CommandList object. """
       
    95         stages = buildtools.CommandList()
       
    96         newstage = False
       
    97         for cmds_stage in commands:
       
    98             _logger.debug("Stage: %s" % cmds_stage)
       
    99             for cmd in cmds_stage:
       
   100                 stages.addCommand(cmd, newstage)
       
   101                 newstage = False
       
   102             newstage = True
       
   103         return stages
       
   104     
       
   105     def writeTopLevel(self, build_file_path, output_path, xml_file):
       
   106         """Creates a build tool config makefile that executes archieve build."""
       
   107         config_name_list = []
       
   108         for config in self.configs:
       
   109             config_name_list.append(config['name'])
       
   110             if not os.path.exists(config['archives.dir']):
       
   111                 os.makedirs(config['archives.dir'])
       
   112             
       
   113         writer = buildtools.get_writer(self.writerType, build_file_path)
       
   114         writer.writeTopLevel(config_name_list, self.spec_name, output_path, xml_file)
       
   115         writer.close()
       
   116 
       
   117     def getCommonUncRoots(self, uncPaths):
       
   118         """get common UNC roots"""
       
   119         commonRoots = {}
       
   120         for p_path in uncPaths:
       
   121             commonRoots["\\\\" + os.sep.join(p_path[2:].split(os.sep)[0:2]) + os.sep] = 1
       
   122         return commonRoots.keys()
       
   123 
       
   124     def getPrefix(self, dir, commonUncRoots):
       
   125         """get prefix"""
       
   126         for root in commonUncRoots:
       
   127             if dir.startswith(root):
       
   128                 return root
       
   129         raise Exception("Could not find root for %s." % dir)
       
   130     
       
   131     def checkRootDirValue(self, builder, parse_xml_file, build_drive, config_type):
       
   132         """Checks UNC path in root.dir and adds the substituted drive into EMAKEROOT."""
       
   133         substDrives = []
       
   134         if build_drive:
       
   135             substDrives.append(build_drive + os.sep)
       
   136         
       
   137         # Read all the config's root.dir to get UNC Path if any
       
   138         # Of course this is only on windows platform
       
   139         if os.sep == '\\':
       
   140             for config in self.configs:
       
   141                 (drive, root_dir) = os.path.splitdrive(os.path.normpath(config['root.dir']))
       
   142                 _logger.debug("drive=%s, root_dir=%s" % (drive, root_dir))
       
   143                 if drive == "":
       
   144                     self.listToFindPrefix.append(root_dir)
       
   145         
       
   146             commonUncRoots = self.getCommonUncRoots(self.listToFindPrefix)
       
   147             _logger.debug("Common roots %s" % (commonUncRoots))
       
   148             driveMapping = {}
       
   149             for root in commonUncRoots:
       
   150                 _logger.info("Substing %s" % (root))
       
   151                 driveMapping[root] = self.substUncPath(root)
       
   152                 _logger.debug("%s subst as %s" % (root, driveMapping[root]))
       
   153                 substDrives.append(driveMapping[root] + os.sep)
       
   154 
       
   155             for config in self.configs:
       
   156                 (drive, root_dir) = os.path.splitdrive(os.path.normpath(config['root.dir']) + os.sep) 
       
   157                 if drive == "":
       
   158                     for root in driveMapping:
       
   159                         if root_dir.startswith(root):
       
   160                             config['root.dir'] = os.path.normpath(driveMapping[root] + os.sep + root_dir[len(root):len(root_dir)])
       
   161                             _logger.info("Updated %s in %s" % (root_dir, config['root.dir']))
       
   162                             config['unsubst.dir'] = driveMapping[root]
       
   163                             break                
       
   164                 elif drive != build_drive:
       
   165                     if config['root.dir'] not in substDrives:
       
   166                         substDrives.append(config['root.dir'])
       
   167         else:
       
   168             for config in self.configs:
       
   169                 if config['root.dir'].startswith('\\\\'):
       
   170                     _logger.error("UNC path are not supported under this platform: %s" % (config['root.dir']))
       
   171         builder.writeToXML(parse_xml_file, self.configs, config_type)
       
   172         return os.path.pathsep.join(substDrives)
       
   173        
       
   174 
       
   175     def substUncPath(self, path):
       
   176         """substitute UNC path"""
       
   177         freedrive = fileutils.get_next_free_drive()
       
   178         fileutils.subst(freedrive, path)
       
   179         return freedrive
       
   180 
       
   181     def cleanupSubstDrives(self):
       
   182         """ Read all the config's root.dir to get UNC Path if any"""
       
   183         drives = {}
       
   184         for config in self.configs:
       
   185             _logger.debug("Checking configuration...")
       
   186             _logger.debug("unsubst.dir: %s" % 'unsubst.dir' in config)
       
   187             _logger.debug("drives: %s" % drives)
       
   188             if 'unsubst.dir' in config and not config['unsubst.dir'] in drives:
       
   189                 _logger.debug("Found drive to unsubst %s" % (config['unsubst.dir']))
       
   190                 self.unSubStituteDrives(config['unsubst.dir'])
       
   191                 drives[config['unsubst.dir']] = config['unsubst.dir']
       
   192                     
       
   193     def unSubStituteDrives(self, drive):
       
   194         """un-substitute Drives"""
       
   195         _logger.info("Unsubsting %s" % (drive))
       
   196         fileutils.unsubst(drive)
       
   197         
       
   198     def write(self, outputname):
       
   199         """Creates a build tool configuration file that executes archive build operations.
       
   200 
       
   201         The input to each archive build operation is an includefile that lists
       
   202         all the files to be included in the archive. These text files are
       
   203         generated before the build file by scanning the filesystem.
       
   204         """
       
   205         stages = buildtools.CommandList()
       
   206 
       
   207         commands = []
       
   208         if self.index > len(self.configs):
       
   209             raise Exception("index not found in configuration")
       
   210         config = self.configs[self.index]
       
   211         stages = self.manifest_to_commands(config, self.build_manifest(config))
       
   212                 
       
   213         # merging the commands            
       
   214         while len(commands) < len(stages):
       
   215             commands.append([])
       
   216         for i in range(len(stages)):
       
   217             commands[i].extend(stages[i])
       
   218 
       
   219         writer = buildtools.get_writer(self.writerType, outputname)
       
   220         writer.write(self.create_command_list(commands))
       
   221         writer.close()