PK-¹ƒFkÒm•cuppa/__init__.py # Copyright Jamie Allsop 2011-2015 # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) def run( *args, **kwargs ): import cuppa.core cuppa.core.run( *args, **kwargs ) def add_option( *args, **kwargs ): import cuppa.core cuppa.core.add_option( *args, **kwargs ) import cuppa.build_with_header_library from cuppa.build_with_header_library import header_library_dependency PK'™¯FoS‡ÒŠŠ cuppa/tree.py# Copyright Jamie Allsop 2015-2015 # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) #------------------------------------------------------------------------------- # Tree #------------------------------------------------------------------------------- def get_all_children( node ): return node.all_children() def filter_out( path, ignore_filter ): for ignore in ignore_filter: if path.startswith( ignore ): return True return False # process_callback should have the signature process( node ) def process_tree( root, process_callback, ignore_filter=[], visited=set() ): path = str( root ) children = get_all_children( root ) if path in visited and children: process_callback( root ) return visited.add( path ) if filter_out( path, ignore_filter ): return process_callback( root ) if children: for child in children[:-1]: process_tree( child, process_callback, ignore_filter, visited ) process_tree( children[-1], process_callback, ignore_filter, visited ) def print_tree( root, ignore_filter=[], margin=[0], visited=set() ): path = str( root ) children = get_all_children( root ) def get_margin(m): return [" ","| "][m] margins = list(map(get_margin, margin[:-1])) if path in visited and children: print ''.join(margins + ['+-[', path, ']']) return visited.add( path ) if filter_out( path, ignore_filter ): return print ''.join(margins + ['+-', path]) if children: margin.append(1) for child in children[:-1]: print_tree( child, ignore_filter, margin, visited ) margin[-1] = 0 print_tree( children[-1], ignore_filter, margin, visited ) margin.pop() PKDkRG?Ç Âð<ð<cuppa/location.py# Copyright Jamie Allsop 2014-2015 # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) #------------------------------------------------------------------------------- # Location #------------------------------------------------------------------------------- import os import urlparse import urllib import zipfile import tarfile import shutil import re import shlex import subprocess import ntpath import fnmatch import hashlib import platform import pip.vcs import pip.download import pip.exceptions import scms.subversion import scms.git import scms.mercurial from cuppa.colourise import as_notice, as_info, as_warning, as_error from cuppa.log import logger class LocationException(Exception): def __init__(self, value): self.parameter = value def __str__(self): return repr(self.parameter) def path_leaf(path): base, leaf = ntpath.split( path ) return leaf or ntpath.basename( base ) def get_common_top_directory_under( path ): dirs = os.listdir( path ) top_dir = os.path.join( path, dirs[0] ) if len(dirs) == 1 and os.path.isdir( top_dir ): return dirs[0] return None class Location(object): def get_cached_archive( self, cache_root, path ): logger.debug( "Checking for cached archive [{}]...".format( as_info( path ) ) ) for archive in os.listdir(cache_root): if fnmatch.fnmatch( archive, path ): logger.debug( "Found cached archive [{}] skipping download".format( as_info( archive ) ) ) return os.path.join( cache_root, archive ) return None def remove_common_top_directory_under( self, path ): dirs = os.listdir( path ) if not dirs: raise LocationException( "Uncompressed archive [{}] is empty".format( path ) ) top_dir = os.path.join( path, dirs[0] ) if len(dirs) == 1 and os.path.isdir( top_dir ): logger.debug( "Removing redundant top directory [{}] from [{}]".format( as_info( dirs[0] ), as_info( path ) ) ) # we have a single top-level directory move_dirs = os.listdir( top_dir ) for d in move_dirs: shutil.move( os.path.join( top_dir, d ), os.path.join( path, d ) ) shutil.rmtree( top_dir ) return True return False def extract( self, filename, target_dir ): os.makedirs( target_dir ) if tarfile.is_tarfile( filename ): logger.debug( "Extracting [{}] into [{}]".format( as_info( filename ), as_info( target_dir ) ) ) try: with tarfile.TarFile( filename ) as tf: tf.extractall( target_dir ) except tarfile.ReadError: command = "tar -xf {filename}".format( filename=filename ) if subprocess.call( shlex.split( command ), cwd=target_dir ) != 0: raise LocationException( "Could not untar downloaded file from [{}]".format( filename ) ) if zipfile.is_zipfile( filename ): logger.debug( "Extracting [{}] into [{}]".format( as_info( filename ), as_info( target_dir ) ) ) with zipfile.ZipFile( filename ) as zf: zf.extractall( target_dir ) while self.remove_common_top_directory_under( target_dir ): pass def url_is_download_archive_url( self, path ): base, download = os.path.split( path ) if download == "download": return pip.download.is_archive_file( base ) else: return pip.download.is_archive_file( path ) def folder_name_from_path( self, path ): def is_url( path ): return isinstance( path, urlparse.ParseResult ) def name_from_url( url ): return '#'.join( [ url.scheme, url.netloc, urllib.unquote( url.path ) ] ) def short_name_from_url( url ): return re.sub( r'[\\/+:() ]', r'#', urllib.unquote( url.path ) ) def name_from_path( path ): folder_name = os.path.splitext( path_leaf( path ) )[0] name, ext = os.path.splitext( folder_name ) if ext == ".tar": folder_name = name return folder_name local_folder = is_url( path ) and name_from_url( path ) or name_from_path( path ) local_folder = re.sub( r'[\\/+:() ]', r'#', local_folder ) if platform.system() == "Windows": # Windows suffers from MAX_PATH limitations so we'll use a hash to shorten the name hasher = hashlib.md5() hasher.update( local_folder ) digest = hasher.hexdigest() short_digest = digest[-8:] name_hint = self._name_hint if not name_hint: name_hint = is_url( path ) and short_name_from_url( path ) or local_folder name_hint = name_hint[:8] local_folder = name_hint + short_digest return local_folder def get_local_directory( self, cuppa_env, location, sub_dir, branch, full_url ): local_directory = None base = cuppa_env['download_root'] if not os.path.isabs( base ): base = os.path.join( cuppa_env['working_dir'], base ) if location.startswith( 'file:' ): location = pip.download.url_to_path( location ) if not pip.download.is_url( location ): if pip.download.is_archive_file( location ): local_folder = self.folder_name_from_path( location ) local_directory = os.path.join( base, local_folder ) if os.path.exists( local_directory ): try: os.rmdir( local_directory ) except: return local_directory, False self.extract( location, local_directory ) else: local_directory = branch and os.path.join( location, branch ) or location return local_directory, False else: local_folder = self.folder_name_from_path( full_url ) local_directory = os.path.join( base, local_folder ) if full_url.scheme.startswith( 'http' ) and self.url_is_download_archive_url( full_url.path ): logger.debug( "[{}] is an archive download".format( as_info( location ) ) ) local_dir_with_sub_dir = os.path.join( local_directory, sub_dir ) # First we check to see if we already downloaded and extracted this archive before if os.path.exists( local_dir_with_sub_dir ): try: # If not empty this will fail os.rmdir( local_dir_with_sub_dir ) except: # Not empty so we'll return this as the local_directory return local_directory, True # If not we then check to see if we cached the download cached_archive = self.get_cached_archive( cuppa_env['cache_root'], local_folder ) if cached_archive: logger.debug( "Cached archive [{}] found for [{}]".format( as_info( cached_archive ), as_info( location ) ) ) self.extract( cached_archive, local_dir_with_sub_dir ) else: logger.info( "Downloading [{}]...".format( as_info( location ) ) ) filename, headers = urllib.urlretrieve( location ) name, extension = os.path.splitext( filename ) logger.info( "[{}] successfully downloaded to [{}]".format( as_info( location ), as_info( filename ) ) ) self.extract( filename, local_dir_with_sub_dir ) if cuppa_env['cache_root']: cached_archive = os.path.join( cuppa_env['cache_root'], local_folder ) logger.debug( "Caching downloaded file as [{}]".format( as_info( cached_archive ) ) ) shutil.copyfile( filename, cached_archive ) elif '+' in full_url.scheme: vc_type = location.split('+', 1)[0] backend = pip.vcs.vcs.get_backend( vc_type ) if backend: vcs_backend = backend( location ) rev_options = self.get_rev_options( vc_type, vcs_backend ) local_dir_with_sub_dir = os.path.join( local_directory, sub_dir ) if os.path.exists( local_directory ): url, repository, branch, revision = self.get_info( location, local_dir_with_sub_dir, full_url ) version = self.ver_rev_summary( branch, revision, self._full_url.path )[0] logger.debug( "Updating [{}] in [{}]{} at [{}]".format( as_info( location ), as_notice( local_dir_with_sub_dir ), ( rev_options and " on {}".format( as_notice( str(rev_options) ) ) or "" ), as_info( version ) ) ) try: vcs_backend.update( local_dir_with_sub_dir, rev_options ) logger.debug( "Successfully updated [{}]".format( as_info( location ) ) ) except pip.exceptions.InstallationError as error: logger.warn( "Could not update [{}] in [{}]{} due to error [{}]".format( as_warning( location ), as_warning( local_dir_with_sub_dir ), ( rev_options and " at {}".format( as_warning( str(rev_options) ) ) or "" ), as_warning( str(error) ) ) ) else: action = "Cloning" if vc_type == "svn": action = "Checking out" logger.info( "{} [{}] into [{}]".format( action, as_info( location ), as_info( local_dir_with_sub_dir ) ) ) try: vcs_backend.obtain( local_dir_with_sub_dir ) logger.debug( "Successfully retrieved [{}]".format( as_info( location ) ) ) except pip.exceptions.InstallationError as error: logger.error( "Could not retrieve [{}] into [{}]{} due to error [{}]".format( as_error( location ), as_error( local_dir_with_sub_dir ), ( rev_options and " to {}".format( as_error( str(rev_options) ) ) or ""), as_error( str( error ) ) ) ) raise LocationException( "Error obtaining [{}]: {}".format( location, error ) ) return local_directory, True def get_rev_options( self, vc_type, vcs_backend ): url, rev = vcs_backend.get_url_rev() if vc_type == 'git': if rev: return [rev] else: return ['origin/master'] elif vc_type == 'hg' and rev: return vcs_backend.get_rev_options( url, rev ) elif vc_type == 'bzr' and rev: return ['-r', rev] return [] def get_info( self, location, local_directory, full_url ): url = location repository = urlparse.urlunparse( ( full_url.scheme, full_url.netloc, '', '', '', '' ) ) branch = urllib.unquote( full_url.path ) revision = None info = ( url, repository, branch, revision ) vcs_directory = local_directory try: info = scms.git.info( vcs_directory ) return info except scms.git.GitException: pass try: info = scms.subversion.info( vcs_directory ) return info except scms.subversion.SubversionException: pass try: info = scms.mercurial.info( vcs_directory ) return info except scms.mercurial.MercurialException: pass return info def ver_rev_summary( self, branch, revision, full_url_path ): if branch and revision: version = ' rev. '.join( [ str(branch), str(revision) ] ) elif branch and revision: version = ' rev. '.join( [ str(branch), str(revision) ] ) else: version = os.path.splitext( path_leaf( urllib.unquote( full_url_path ) ) )[0] name, ext = os.path.splitext( version ) if ext == ".tar": version = name version = version revision = "not under version control" return version, revision def __init__( self, cuppa_env, location, branch=None, extra_sub_path=None, name_hint=None ): self._location = location self._full_url = urlparse.urlparse( location ) self._sub_dir = "" self._name_hint = name_hint if extra_sub_path: if os.path.isabs( extra_sub_path ): raise LocationException() else: self._sub_dir = os.path.normpath( extra_sub_path ) ## Get the location for the source dependency. If the location is a URL or an Archive we'll need to ## retrieve the URL and extract the archive. get_local_directory() returns the location of the source ## once this is done local_directory, use_sub_dir = self.get_local_directory( cuppa_env, location, self._sub_dir, branch, self._full_url ) self._base_local_directory = local_directory self._local_directory = use_sub_dir and os.path.join( local_directory, self._sub_dir ) or local_directory ## Now that we have a locally accessible version of the dependency we can try to collate some information ## about it to allow us to specify what we are building with. self._url, self._repository, self._branch, self._revision = self.get_info( self._location, self._local_directory, self._full_url ) self._version, self._revision = self.ver_rev_summary( self._branch, self._revision, self._full_url.path ) logger.debug( "Using [{}]{} at [{}] stored in [{}]".format( as_info( location ), ( branch and ":[{}]".format( as_info( str(branch) ) ) or "" ), as_info( self._version ), as_notice( self._local_directory ) ) ) def local( self ): return self._local_directory def base_local( self ): return self._base_local_directory def sub_dir( self ): return self._sub_dir def location( self ): return self._location def url( self ): return self._url def branch( self ): return self._branch def repository( self ): return self._repository def version( self ): return str(self._version) def revisions( self ): return [ self._revision ] PK{QGÙó†  cuppa/log.py # Copyright Jamie Allsop 2015-2015 # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) #------------------------------------------------------------------------------- # Log #------------------------------------------------------------------------------- import logging from cuppa.colourise import as_error_label, as_warning_label, as_emphasised logging.TRACE = 5 def trace( self, message, *args, **kwargs ): if self.isEnabledFor( logging.TRACE ): self._log( logging.TRACE, message, args, **kwargs ) logging.Logger.trace = trace logger = logging.getLogger('cuppa') logger.setLevel( logging.INFO ) class _formatter(logging.Formatter): @classmethod def warn_fmt( cls ): return "{} %(message)s".format( as_warning_label("%(name)s: %(module)s: [%(levelname)s]") ) @classmethod def error_fmt( cls ): return "{} %(message)s".format( as_error_label("%(name)s: %(module)s: [%(levelname)s]") ) @classmethod def critical_fmt( cls ): return "{} %(message)s".format( as_error_label( as_emphasised( "%(name)s: %(module)s: [%(levelname)s]") ) ) def __init__( self, fmt="%(name)s: %(module)s: [%(levelname)s] %(message)s" ): logging.Formatter.__init__( self, fmt ) self._warn_fmt = self.warn_fmt() self._error_fmt = self.error_fmt() self._critical_fmt = self.critical_fmt() def format( self, record ): orig_fmt = self._fmt if record.levelno == logging.WARN: self._fmt = self._warn_fmt elif record.levelno == logging.ERROR: self._fmt = self._error_fmt elif record.levelno == logging.CRITICAL: self._fmt = self._critical_fmt result = logging.Formatter.format( self, record ) self._fmt = orig_fmt return result _log_handler = logging.StreamHandler() def initialise_logging(): logging.addLevelName( logging.TRACE, 'trace' ) logging.addLevelName( logging.DEBUG, 'debug' ) logging.addLevelName( logging.INFO, 'info' ) logging.addLevelName( logging.WARN, 'warn' ) logging.addLevelName( logging.ERROR, 'error' ) logging.addLevelName( logging.CRITICAL, 'critical' ) _log_handler.setFormatter( _formatter() ) logger.addHandler( _log_handler ) def reset_logging_format(): _log_handler.setFormatter( _formatter() ) def set_logging_level( level ): if level == "trace": logger.setLevel( logging.TRACE ) elif level == "debug": logger.setLevel( logging.DEBUG ) elif level == "warn": logger.setLevel( logging.WARN ) elif level == "error": logger.setLevel( logging.ERROR ) else: logger.setLevel( logging.INFO ) PK{QGr.Ì}œœcuppa/timer.py # Copyright Jamie Allsop 2013-2015 # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) #------------------------------------------------------------------------------- # Timer #------------------------------------------------------------------------------- # Python Standard Library Imports import os import timeit import time import sys from cuppa.colourise import as_emphasised, as_colour, emphasise_time_by_digit nanosecs_multiple = 1000000000 def wall_time_nanosecs(): return int( timeit.default_timer()*nanosecs_multiple ) def process_times_nanosecs(): process = time.clock() user, system, children_user, children_system, real = os.times() return int( process*nanosecs_multiple), int( user*nanosecs_multiple ), int( system*nanosecs_multiple ) class CpuTimes(object): def __init__( self, wall, process, system, user ): self.wall = wall self.process = process self.system = system self.user = user def __add__( self, other ): if isinstance( other, self.__class__ ): return CpuTimes( self.wall + other.wall, self.process + other.process, self.system + other.system, self.user + other.user ) else: raise TypeError("Unsupported operand type(s) for +: '{}' and '{}'").format(self.__class__, type(other)) def __sub__( self, other ): if isinstance( other, self.__class__ ): return CpuTimes( self.wall - other.wall, self.process - other.process, self.system - other.system, self.user - other.user ) else: raise TypeError("Unsupported operand type(s) for -: '{}' and '{}'").format(self.__class__, type(other)) class Timer(object): @classmethod def _current_time( cls ): wall = wall_time_nanosecs() process, user, system = process_times_nanosecs() return CpuTimes( wall, process, system, user ) @classmethod def _elapsed_time( cls, current, start ): return current - start def __init__( self ): self.start() def elapsed( self ): if not self._stopped: self._current = self._current_time() return self._elapsed_time( self._current, self._start ) def start( self ): self._stopped = False self._start = self._current_time() def stop( self ): self._stopped = True self._current = self._current_time() def resume( self ): self.start() def as_duration_string( total_nanosecs ): secs, remainder = divmod( total_nanosecs, 1000000000 ) millisecs, remainder = divmod( remainder, 1000000 ) microsecs, nanosecs = divmod( remainder, 1000 ) hours, remainder = divmod( secs, 3600 ) minutes, secs = divmod( remainder, 60 ) duration = "%02d:%02d:%02d.%03d,%03d,%03d" % ( hours, minutes, secs, millisecs, microsecs, nanosecs ) return duration def as_wall_cpu_percent_string( cpu_times ): wall_cpu_percent = "n/a" if cpu_times.wall: percent = "{:.2f}".format( float(cpu_times.process) * 100 / cpu_times.wall ) wall_cpu_percent = "%6s%%" % percent.upper() return wall_cpu_percent def write_time( cpu_times, emphasise=False ): def write( text ): if not emphasise: sys.stdout.write( text ) else: sys.stdout.write( as_emphasised( text ) ) write( " Time:" ) write( " Wall [ {}".format( emphasise_time_by_digit( as_duration_string( cpu_times.wall ) ) ) ) write( " ] CPU [ {}".format( emphasise_time_by_digit( as_duration_string( cpu_times.process ) ) ) ) write( " ] CPU/Wall [ {}".format( as_colour( 'time', as_wall_cpu_percent_string( cpu_times ) ) ) ) write( " ]" ) PKq‚RG#ho##"cuppa/build_with_header_library.py# Copyright Jamie Allsop 2014-2015 # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) #------------------------------------------------------------------------------- # build_with_header_library #------------------------------------------------------------------------------- import os import cuppa.location from cuppa.log import logger from cuppa.colourise import as_notice, as_error class HeaderLibraryException(Exception): def __init__(self, value): self.parameter = value def __str__(self): return repr(self.parameter) class base(object): _name = None _cached_locations = {} _includes = None _sys_includes = None @classmethod def add_options( cls, add_option ): location_name = cls._name + "-location" branch_name = cls._name + "-branch" include_name = cls._name + "-include" sys_include_name = cls._name + "-sys-include" add_option( '--' + location_name, dest=location_name, type='string', nargs=1, action='store', help = cls._name + ' location to build against' ) add_option( '--' + branch_name, dest=branch_name, type='string', nargs=1, action='store', help = cls._name + ' branch to build against. Providing a branch is optional' ) add_option( '--' + include_name, dest=include_name, type='string', nargs=1, action='store', help = cls._name + ' include sub-directory to be added to the include path. Optional' ) add_option( '--' + sys_include_name, dest=sys_include_name, type='string', nargs=1, action='store', help = cls._name + ' include sub-directory to be added to the system include path. Optional' ) @classmethod def add_to_env( cls, env, add_dependency ): add_dependency( cls._name, cls.create ) @classmethod def location_id( cls, env ): location = env.get_option( cls._name + "-location" ) branch = env.get_option( cls._name + "-branch" ) if not location and branch: location = env['branch_root'] if not location and branch: location = env['thirdparty'] if not location: logger.debug( "No location specified for dependency [{}]. Dependency not available.".format( cls._name.title() ) ) return None return (location, branch) @classmethod def _get_location( cls, env ): location_id = cls.location_id( env ) if not location_id: return None if location_id not in cls._cached_locations: location = location_id[0] branch = location_id[1] try: cls._cached_locations[location_id] = cuppa.location.Location( env, location, branch ) except cuppa.location.LocationException as error: logger.error( "Could not get location for [{}] at [{}] with branch [{}]. Failed with error [{}]" .format( as_notice( cls._name.title() ), as_notice( str(location) ), as_notice( str(branch) ), as_error( error ) ) ) return None return cls._cached_locations[location_id] @classmethod def create( cls, env ): location = cls._get_location( env ) if not location: return None if not cls._includes: include = env.get_option( cls._name + "-include" ) cls._includes = include and [include] or [] if not cls._sys_includes: sys_include = env.get_option( cls._name + "-sys-include" ) cls._sys_includes = sys_include and [sys_include] or [] return cls( env, location, includes=cls._includes, sys_includes=cls._sys_includes) def __init__( self, env, location, includes=[], sys_includes=[] ): self._location = location if not includes and not sys_includes: includes = [self._location.local()] self._includes = [] for include in includes: if include: self._includes.append( os.path.isabs(include) and include or os.path.join( self._location.local(), include ) ) self._sys_includes = [] for include in sys_includes: if include: self._sys_includes.append( os.path.isabs(include) and include or os.path.join( self._location.local(), include ) ) def __call__( self, env, toolchain, variant ): env.AppendUnique( INCPATH = self._includes ) env.AppendUnique( SYSINCPATH = self._sys_includes ) def name( self ): return self._name def version( self ): return str(self._location.version()) def repository( self ): return self._location.repository() def branch( self ): return self._location.branch() def revisions( self ): return self._location.revisions() def header_library_dependency( name ): return type( 'BuildWith' + name.title(), ( base, ), { '_name': name } ) PK5¿®F©‚yy cuppa/path.py# Copyright Jamie Allsop 2015-2015 # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) #------------------------------------------------------------------------------- # Path #------------------------------------------------------------------------------- # Python Standard import os.path def split_common( path1, path2 ): drive1, p1 = os.path.splitdrive( path1 ) drive2, p2 = os.path.splitdrive( path2 ) if drive1 != drive2: return None, path1, path2 p1_elements = p1.split( os.path.sep ) p2_elements = p2.split( os.path.sep ) p1_len = len( p1_elements ) p2_len = len( p2_elements ) max_index = min( p1_len, p2_len ) index = 0 common = [ drive1 ] while index < max_index: if p1_elements[index] == p2_elements[index]: common.append( p1_elements[index] ) index = index+1 else: break; return os.path.join( '', *common ), os.path.join( '', *p1_elements[index:] ), os.path.join( '', *p2_elements[index:] ) PKø¹±FÕç‰Ùð ð cuppa/progress.py # Copyright Jamie Allsop 2013-2015 # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) #------------------------------------------------------------------------------- # Progress #------------------------------------------------------------------------------- class NotifyProgress(object): _callbacks = set() _sconstruct_begin = None _sconstruct_end = None _begin = {} _end = {} _started = {} _finished = {} @classmethod def register_callback( cls, env, callback ): if env: if not 'cuppa_progress_callbacks' in env: env['cuppa_progress_callbacks'] = set() env['cuppa_progress_callbacks'].add( callback ) else: cls._callbacks.add( callback ) @classmethod def call_callbacks( cls, event, sconscript, variant, env, target, source ): if 'cuppa_progress_callbacks' in env: for callback in env['cuppa_progress_callbacks']: callback( event, sconscript, variant, env, target, source ) for callback in cls._callbacks: callback( event, sconscript, variant, env, target, source ) @classmethod def _variant( cls, env ): return env['build_dir'] @classmethod def _sconscript( cls, env ): return env['sconscript_file'] @classmethod def add( cls, env, target ): default_env = env['default_env'] sconscript_env = env['sconscript_env'] sconscript = cls._sconscript( sconscript_env ) variant = cls._variant( env ) if not cls._sconstruct_begin: cls._sconstruct_begin = progress( '#SconstructBegin', 'sconstruct_begin', None, None, default_env ) if not sconscript in cls._begin: cls._begin[sconscript] = progress( 'Begin', 'begin', sconscript, None, sconscript_env ) begin = cls._begin[sconscript] env.Requires( begin, cls._sconstruct_begin ) if variant not in cls._started: cls._started[variant] = progress( 'Started', 'started', sconscript, env['build_dir'], env ) env.Requires( target, cls._started[variant] ) env.Requires( cls._started[variant], begin ) if variant not in cls._finished: cls._finished[variant] = progress( 'Finished', 'finished', sconscript, env['build_dir'], env ) finished = env.Depends( cls._finished[variant], [ target, '#' + env['sconscript_file'], '#' + env['sconstruct_file'] ] ) if not sconscript in cls._end: cls._end[sconscript] = progress( 'End', 'end', sconscript, None, sconscript_env ) end = env.Requires( cls._end[sconscript], finished ) if not cls._sconstruct_end: cls._sconstruct_end = progress( '#SconstructEnd', 'sconstruct_end', None, None, default_env ) env.Requires( cls._sconstruct_end, end ) def progress( label, event, sconscript, variant, env ): return env.Command( label, [], Progress( event, sconscript, variant, env ) ) class Progress(object): def __init__( self, event, sconscript, variant, env ): self._event = event self._file = sconscript self._variant = variant self._env = env def __call__( self, target, source, env ): NotifyProgress.call_callbacks( self._event, self._file, self._variant, self._env, target, source ) return None PK{QGÅ\qoocuppa/colourise.py # Copyright Declan Traynor 2012 # Copyright Jamie Allsop 2012-2015 # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) #------------------------------------------------------------------------------- # Colouriser #------------------------------------------------------------------------------- import re try: import colorama colorama_available = True except ImportError: print 'Output Colourisation disabled. To enabled, install colorama' colorama_available = False class Colouriser(object): @classmethod def create( cls ): if colorama_available: colorama.init() return cls() def __init__( self ): self.use_colour = False def enable( self ): self.use_colour = True def colour( self, meaning, text ): if not self.use_colour: return text else: return self.start_colour( meaning ) + text + colorama.Style.RESET_ALL def emphasise( self, text ): if not self.use_colour: return text else: return colorama.Style.BRIGHT + text + colorama.Style.RESET_ALL def emphasise_time_by_group( self, time_text ): if not self.use_colour: return time_text else: time_elements = re.findall( r'[0-9]+[:.,]?', time_text ) time_found = False emphasised = self.start_colour('time') empty = re.compile( r'00[:.]|000[,]?' ) for element in time_elements: if not time_found and not empty.match( element ): time_found = True emphasised += self.start_highlight('time') emphasised += element emphasised += colorama.Style.RESET_ALL return emphasised def emphasise_time_by_digit( self, time_text ): if not self.use_colour: return time_text else: time_found = False emphasised = self.start_colour('time') for char in time_text: if not time_found and char.isdigit() and int(char) > 0: time_found = True emphasised += self.start_highlight('time') emphasised += char emphasised += colorama.Style.RESET_ALL return emphasised def highlight( self, meaning, text ): if not self.use_colour: return text else: return self.start_highlight( meaning ) + text + colorama.Style.RESET_ALL def start_colour( self, meaning ): if self.use_colour: return self._start_colour( meaning ) return '' def start_highlight( self, meaning ): if self.use_colour: return self._start_highlight( meaning ) return '' def reset( self ): if self.use_colour: return self._reset() return '' def _reset( self ): return colorama.Style.RESET_ALL ## Make these functions into simple dictionary lookups def _start_colour( self, meaning ): if meaning == 'error': return colorama.Fore.RED elif meaning == 'warning': return colorama.Fore.MAGENTA elif meaning == 'summary': return colorama.Fore.BLACK elif meaning == 'passed': return colorama.Fore.GREEN elif meaning == 'success': return colorama.Fore.GREEN elif meaning == 'unexpected_success': return colorama.Fore.GREEN elif meaning == 'expected_failure': return colorama.Fore.YELLOW elif meaning == 'failure': return colorama.Fore.RED elif meaning == 'failed': return colorama.Fore.RED elif meaning == 'aborted': return colorama.Fore.RED elif meaning == 'skipped': return colorama.Fore.BLACK elif meaning == 'notice': return colorama.Fore.YELLOW elif meaning == 'time': return colorama.Fore.BLUE elif meaning == 'info': return colorama.Fore.BLUE elif meaning == 'message': return '' def _start_highlight( self, meaning ): if meaning == 'error': return colorama.Style.BRIGHT + colorama.Back.RED + colorama.Fore.WHITE elif meaning == 'warning': return colorama.Style.BRIGHT + colorama.Back.MAGENTA + colorama.Fore.WHITE elif meaning == 'summary': return colorama.Style.BRIGHT + colorama.Back.BLACK + colorama.Fore.WHITE elif meaning == 'success': return colorama.Style.BRIGHT + colorama.Back.GREEN + colorama.Fore.WHITE elif meaning == 'unexpected_success': return colorama.Style.BRIGHT + colorama.Back.GREEN + colorama.Fore.BLACK elif meaning == 'passed': return colorama.Style.BRIGHT + colorama.Back.GREEN + colorama.Fore.WHITE elif meaning == 'expected_failure': return colorama.Style.BRIGHT + colorama.Back.YELLOW + colorama.Fore.WHITE elif meaning == 'failure': return colorama.Style.BRIGHT + colorama.Back.RED + colorama.Fore.WHITE elif meaning == 'failed': return colorama.Style.BRIGHT + colorama.Back.RED + colorama.Fore.WHITE elif meaning == 'aborted': return colorama.Style.BRIGHT + colorama.Back.RED + colorama.Fore.BLACK elif meaning == 'skipped': return colorama.Style.BRIGHT + colorama.Back.BLACK + colorama.Fore.WHITE elif meaning == 'notice': return colorama.Style.BRIGHT + colorama.Back.YELLOW + colorama.Fore.WHITE elif meaning == 'time': return colorama.Style.BRIGHT + colorama.Back.BLUE + colorama.Fore.WHITE elif meaning == 'info': return colorama.Style.BRIGHT + colorama.Back.BLUE + colorama.Fore.WHITE elif meaning == 'message': return '' colouriser = Colouriser.create() def as_colour( meaning, text ): return colouriser.colour( meaning, text ) def as_highlighted( meaning, text ): return colouriser.highlight( meaning, text ) def as_emphasised( text ): return colouriser.emphasise( text ) def as_error( text ): return colouriser.colour( 'error', text ) def as_error_label( text ): return colouriser.highlight( 'error', text ) def as_warning( text ): return colouriser.colour( 'warning', text ) def as_warning_label( text ): return colouriser.highlight( 'warning', text ) def as_info( text ): return colouriser.colour( 'info', text ) def as_message( text ): return colouriser.colour( 'message', text ) def as_notice( text ): return colouriser.colour( 'notice', text ) def start_colour( meaning ): return colouriser.start_colour( meaning ) def start_highlight( meaning ): return colouriser.start_highlight( meaning ) def colour_reset(): return colouriser.reset() def emphasise_time_by_group( time_text ): return colouriser.emphasise_time_by_group( time_text ) def emphasise_time_by_digit( time_text ): return colouriser.emphasise_time_by_digit( time_text ) PK{QG“W8­¨¨cuppa/configure.py # Copyright Jamie Allsop 2013-2015 # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) #------------------------------------------------------------------------------- # Configure #------------------------------------------------------------------------------- # standard library Imports import os import ast # Scons Imports import SCons.Script import cuppa.options from cuppa.colourise import as_info, as_notice from cuppa.log import logger SCons.Script.AddOption( '--show-conf', dest='show_conf', action='store_true', help='Show the current values in the configuration file if one exists' ) SCons.Script.AddOption( '--save-conf', dest='save_conf', action='store_true', help='Save the current command-line a configuration file' ) SCons.Script.AddOption( '--update-conf', dest='update_conf', action='store_true', help='Update the configuration file with the current command-line' ) SCons.Script.AddOption( '--remove-settings', type='string', nargs=1, action='callback', callback=cuppa.options.list_parser( 'remove_settings' ), help='Remove the listed settings from the configuration file' ) SCons.Script.AddOption( '--clear-conf', dest='clear_conf', action='store_true', help='Clear the configuration file' ) class never_save(object): pass default_scons_options = { 'debug_explain': False, 'debug_includes': False, 'climb_up': never_save } class Configure(object): def __init__( self, env, conf_path="configure.conf", callback=None ): self._env = env self._conf_path = conf_path self._callback = callback env['configured_options'] = {} self._configured_options = {} def load( self ): self._show = self._env.get_option( 'show_conf' ) self._save = self._env.get_option( 'save_conf' ) self._remove = self._env.get_option( 'remove_settings' ) self._update = self._env.get_option( 'update_conf' ) self._clear = self._env.get_option( 'clear_conf' ) self._configure = self._save or self._remove or self._update self._clean = self._env.get_option( 'clean' ) self._unconfigure = ( self._save and self._clean ) or self._clear if self._unconfigure: self._configure = False logger.info( "{}".format( as_notice( "Clear configuration requested..." ) ) ) if os.path.exists( self._conf_path ): logger.info( "Removing configure file [{}]".format( as_info( self._conf_path ) ) ) os.remove( self._conf_path ) else: logger.info( "Configure file [{}] does not exist. Unconfigure not needed".format( as_info( self._conf_path ) ) ) return elif self._configure: print logger.info( "{}".format( as_notice( "Update configuration requested..." ) ) ) if not self._save: self._loaded_options = self._load_conf() else: self._loaded_options = {} self._env['configured_options'] = self._loaded_options self._env['default_options'].update( self._loaded_options ) def save( self ): if self._configure and not self._clean: if self._save: self._save_conf() else: if self._update: self._update_conf() if self._remove: self._remove_settings() def handle_conf_only( self ): return self._save or self._update or self._remove or self._clear or self._show def action( self ): if self._save: return "save" elif self._update: return "update" elif self._remove: return "remove" elif self._clear: return "clear" elif self._show: return "show" def configure( self, env ): configure = SCons.Script.Configure( env ) if self._callback: self._callback( configure ) env = configure.Finish() def _load_conf( self ): settings = {} if os.path.exists(self._conf_path): with open(self._conf_path) as config_file: logger.info( "Configure file [{}] exists. Load stored settings...".format( as_info( self._conf_path ) ) ) for line in config_file.readlines(): name, value = tuple( l.strip() for l in line.split('=', 1) ) try: value = ast.literal_eval( str(value) ) except: pass self._print_setting( 'loading', name, value ) settings[name] = value if settings: logger.info( "Load complete" ) else: logger.info( "No settings to load, skipping configure" ) return settings def _is_defaulted_scons_option( self, key, value ): if key in default_scons_options: if default_scons_options[key] == value: return True elif default_scons_options[key] == never_save: return True return False def _is_saveable( self, key, value ): return( not key.startswith("__") and not self._is_defaulted_scons_option( key, value ) and not key =='save_conf' and not key =='update_conf' and not key =='remove_settings' and not key =='show_conf' and not key =='clear_conf' ) def _print_setting( self, action, key, value ): logger.info( "{} [{}] = [{}]".format( action, as_notice( key ), as_notice( str(value) ) ) ) def _save_settings( self ): options = self._loaded_options for key, value in SCons.Script.Main.OptionsParser.values.__dict__.items(): if self._is_saveable( key, value ): try: value = ast.literal_eval( str(value) ) except: pass options[key] = value with open(self._conf_path, "w") as config_file: for key, value in options.items(): self._print_setting( 'saving', key, value ) config_file.write( "{} = {}\n".format( key, value ) ) def _remove_settings( self ): initial_option_count = len(self._loaded_options) logger.info( "Remove settings requested for the following options {}".format( self._remove ) ) for setting in self._remove: if setting in self._loaded_options: del self._loaded_options[setting] logger.info( "Removing option [{}] as requested".format( as_notice( "--" + setting ) ) ) if initial_option_count != len(self._loaded_options): self._update_conf() def _save_conf( self ): logger.info( "{}".format( as_notice( "Save current settings..." ) ) ) self._save_settings() logger.info( "{}".format( as_notice( "Save complete" ) ) ) def _update_conf( self ): logger.info( "{}".format( as_notice( "Updating current settings..." ) ) ) self._save_settings() logger.info( "{}".format( as_notice( "Update complete" ) ) ) PKÕf=Göìë!„„cuppa/build_platform.py # Copyright Jamie Allsop 2011-2015 # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) #------------------------------------------------------------------------------- # Build Platform #------------------------------------------------------------------------------- import platform import subprocess import shlex import os.path # Custom import cuppa.modules.registration from cuppa.platforms import * class PlatformException(Exception): def __init__(self, value): self.parameter = value def __str__(self): return repr(self.parameter) class Platform(object): @classmethod def _get_supported_platforms( cls, supported ): cuppa.modules.registration.add_to_env( 'platforms', { 'env': supported } ) @classmethod def _create( cls ): cls._supported = { 'platforms': {} } cls._get_supported_platforms( cls._supported ) system = platform.system() if system not in cls._supported['platforms']: raise PlatformException( 'Platform [' + system + '] not supported. Supported platforms are ' + str(cls._supported['platforms']) ) cls._platform = cls._supported['platforms'][ system ] cls._platform.initialise() @classmethod def supported( cls ): if not hasattr(cls, '_supported'): cls._create() return cls._supported['platforms'] @classmethod def current( cls ): if not hasattr(cls, '_platform'): cls._create() return cls._platform def which( program ): exe = 'which' if platform.system() == "Windows": exe = 'where.exe' command = "{} {}".format( exe, program ) try: path = subprocess.check_output( shlex.split( command ) ) return os.path.dirname( path ) except subprocess.CalledProcessError as error: print "ERROR calling command \"{}\"; Failed with error: {}".format( command, str(error) ) return None def name(): return Platform.current().name() def constants(): return Platform.current().constants() PKîcáFew}»»cuppa/recursive_glob.py # Copyright Jamie Allsop 2012-2015 # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) #------------------------------------------------------------------------------- # RecursiveGlob #------------------------------------------------------------------------------- import fnmatch import re import os import cuppa.utility def glob( start, file_pattern, exclude_dirs_pattern=None, discard_pattern=None ): if cuppa.utility.is_string( file_pattern ): file_pattern = re.compile( fnmatch.translate( file_pattern ) ) if exclude_dirs_pattern: if cuppa.utility.is_string( exclude_dirs_pattern ): exclude_dirs_pattern = re.compile( fnmatch.translate( exclude_dirs_pattern ) ) if discard_pattern: if cuppa.utility.is_string( discard_pattern ): discard_pattern = re.compile( fnmatch.translate( discard_pattern ) ) matches = [] subdir = False for root, dirnames, filenames in os.walk( start ): if exclude_dirs_pattern: # remove any directories from the search that match the exclude regex dirnames[:] = [ d for d in dirnames if not exclude_dirs_pattern.match(d) ] exclude_this_dir = False matches_in_this_dir = [] for filename in filenames: if subdir and discard_pattern and discard_pattern.match( filename ): # if we are in a subdir and it contains a file that matches the discard_pattern # set exclude_this_dir to True so later we can discard any local matches we'd # already encountered while walking the directory exclude_this_dir = True break if file_pattern.match( filename ): matches_in_this_dir.append( os.path.join( root, filename ) ) if not exclude_this_dir: matches += matches_in_this_dir else: # We are excluding this directory and therefore all of its subdirs dirnames[:] = [] # After the first pass through the loop we will be in a subdirectory subdir = True return matches PK-¹ƒF tDøbbcuppa/options.py # Copyright Jamie Allsop 2014-2015 # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) #------------------------------------------------------------------------------- # Options #------------------------------------------------------------------------------- class list_parser(object): def __init__( self, attribute ): self._attribute = attribute def __call__( self, option, opt, value, parser): setattr( parser.values, self._attribute, value.split(',') ) PK±»SGG4*K cuppa/VERSION0.9.0 PKQ¶FRâ{PPcuppa/version.py# Copyright Jamie Allsop 2014-2015 # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) #------------------------------------------------------------------------------- # version.py #------------------------------------------------------------------------------- import sys import os import xmlrpclib import pip from pkg_resources import parse_version def get_version(): module = sys.modules[__name__] if not hasattr( module, '_version' ): version_path = os.path.join( os.path.split( __file__ )[0], 'VERSION' ) with open( version_path ) as version_file: module._version = version_file.read().strip() return module._version def check_current_version(): installed_version = get_version() sys.stdout.write( "cuppa: version {}".format( installed_version ) ) try: pypi = xmlrpclib.ServerProxy('http://pypi.python.org/pypi') latest_available = pypi.package_releases('cuppa')[0] if parse_version( installed_version ) < parse_version( latest_available ): sys.stdout.write( " - " ) sys.stdout.write( "Newer version [{}] available\n".format( latest_available ) ) else: sys.stdout.write( "\n" ) except: pass PKDkRGÏ«*¼)/)/cuppa/output_processor.py # Copyright Jamie Allsop 2011-2015 # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) #------------------------------------------------------------------------------- # Output Processor #------------------------------------------------------------------------------- import subprocess import sys import os import re import time import threading import shlex import colorama import Queue import platform from cuppa.colourise import as_colour, as_emphasised, as_highlighted from cuppa.log import logger def command_available( command ): try: with open(os.devnull) as devnull: subprocess.Popen( shlex.split( command ), stdout=devnull, stderr=devnull ).communicate() except OSError as e: if e.errno == os.errno.ENOENT: return False return True class AutoFlushFile: def __init__( self, f ): self.f = f def flush( self ): self.f.flush() def write( self, x ): self.f.write(x) self.f.flush() class LineConsumer: def __init__( self, call_readline, processor=None ): self.call_readline = call_readline self.processor = processor def __call__( self ): for line in iter( self.call_readline, "" ): line = line.rstrip() if line: if self.processor: line = self.processor( line ) if line: print line else: print line class IncrementalSubProcess: @classmethod def Popen2( cls, stdout_processor, stderr_processor, args_list, **kwargs ): kwargs['stdout'] = subprocess.PIPE kwargs['stderr'] = subprocess.PIPE sys.stdout = AutoFlushFile( colorama.initialise.wrapped_stdout ) sys.stderr = AutoFlushFile( colorama.initialise.wrapped_stderr ) try: process = subprocess.Popen( args_list, **kwargs ) stderr_consumer = LineConsumer( process.stderr.readline, stderr_processor ) stdout_consumer = LineConsumer( process.stdout.readline, stdout_processor ) stderr_thread = threading.Thread( target=stderr_consumer ) stderr_thread.start() stdout_consumer(); stderr_thread.join() process.wait() return process.returncode except Exception as e: logger.error( "output_processor: IncrementalSubProcess.Popen2() failed with error [{}]".format( str(e) ) ) @classmethod def Popen( cls, processor, args_list, **kwargs ): return cls.Popen2( processor, processor, args_list, **kwargs ) class PSpawn(object): def __init__( self, pspawn, sh, escape, cmd, args, env, stdout, stderr ): self._pspawn = pspawn self._sh = sh self._escape = escape self._cmd = cmd self._args = args self._env = env self._stdout = stdout self._stderr = stderr self._exception = None def __call__( self ): try: self._returncode = self._pspawn( self._sh, self._escape, self._cmd, self._args, self._env, self._stdout, self._stderr ) except BaseException: self._exception = sys.exc_info() def returncode( self ): if self._exception != None: logger.error("pspawn terminated with exception [{}]".format( str(self._exception) ) ) raise self._exception return self._returncode class Stream(object): def __init__( self, processor, name ): self._queue = Queue.Queue() self._processor = processor self._name = name def flush( self ): pass def write( self, text ): logger.trace( "output_processor: Stream _queue.put [{}]".format( self._name ) ) self._queue.put( text ) def read( self, block ): try: logger.trace( "output_processor: Stream _queue.get [{}]".format( self._name ) ) text = self._queue.get( block ) if text: for line in text.splitlines(): if self._processor: line = self._processor( line ) if line: print line else: print line self._queue.task_done() except Queue.Empty: logger.trace( "output_processor: Stream Queue.Empty raised [{}]".format( self._name ) ) def join( self ): if self._queue.empty(): logger.trace( "output_processor: Stream _queue.empty() - flush with None [{}]".format( self._name ) ) self._queue.put( None ) self._queue.join() class Reader(object): def __init__( self, stream, finished ): self._stream = stream self._finished = finished def __call__( self ): while not self._finished.is_set(): self._stream.read(True) self._stream.read(False) class Processor: def __init__( self, scons_env ): self.scons_env = scons_env @classmethod def install( cls, env ): global _pspawn _pspawn = env['PSPAWN'] output_processor = cls( env ) if platform.system() == "Windows": env['SPAWN'] = output_processor.windows_spawn else: env['SPAWN'] = output_processor.posix_spawn def posix_spawn( self, sh, escape, cmd, args, env ): processor = SpawnedProcessor( self.scons_env ) returncode = IncrementalSubProcess.Popen( processor, [ arg.strip('"') for arg in args ], env=env ) summary = processor.summary( returncode ) if summary: print summary return returncode def windows_spawn( self, sh, escape, cmd, args, env ): processor = SpawnedProcessor( self.scons_env ) stdout = Stream( processor, "stdout" ) stderr = Stream( processor, "stderr" ) pspawn = PSpawn( _pspawn, sh, escape, cmd, args, env, stdout, stderr ) pspawn_thread = threading.Thread( target=pspawn ) finished = threading.Event() pspawn_thread.start() stdout_thread = threading.Thread( target = Reader( stdout, finished ) ) stdout_thread.start() stderr_thread = threading.Thread( target = Reader( stderr, finished ) ) stderr_thread.start() pspawn_thread.join() logger.trace( "output_processor: Processor - PSPAWN joined" ) finished.set() stdout.join() logger.trace( "output_processor: Processor - STDOUT stream joined" ) stdout_thread.join() logger.trace( "output_processor: Processor - STDOUT thread joined" ) stderr.join() logger.trace( "output_processor: Processor - STDERR stream joined" ) stderr_thread.join() logger.trace( "output_processor: Processor - STDERR thread joined" ) returncode = pspawn.returncode() summary = processor.summary( returncode ) if summary: print summary return returncode class SpawnedProcessor(object): def __init__( self, scons_env ): self._processor = ToolchainProcessor( scons_env['toolchain'], scons_env['minimal_output'], scons_env['ignore_duplicates'] ) def __call__( self, line ): return self._processor( line ) def summary( self, returncode ): return self._processor.summary( returncode ) class ToolchainProcessor: def __init__( self, toolchain, minimal_output, ignore_duplicates ): self.toolchain = toolchain self.minimal_output = minimal_output self.ignore_duplicates = ignore_duplicates self.errors = 0 self.warnings = 0 self.start_time = time.time() self.error_messages = {} self.warning_messages = {} self.ignore_current_message = False def filtered_duplicate( self, line, existing_messages ): if self.ignore_duplicates and line in existing_messages: existing_messages[line] +=1 self.ignore_current_message = True return None else: self.ignore_current_message = False existing_messages[line] = 1 return line def filtered_line( self, line=None, meaning=None ): if meaning == "error": return self.filtered_duplicate( line, self.error_messages ) if meaning == "warning": return self.filtered_duplicate( line, self.warning_messages ) if self.minimal_output or self.ignore_current_message: return None else: return line def __call__( self, line ): ( matches, interpretor, error_id, warning_id ) = self.interpret( line ) if matches: highlights = interpretor['highlight'] display = interpretor['display'] meaning = interpretor['meaning'] file = interpretor['file'] message = '' for match in display: element = matches.group( match ) if match == file and ( meaning == 'error' or meaning == 'warning' ): element = self.normalise_path( element ) element = as_colour( meaning, element ) if match in highlights: element = as_emphasised( element ) message += element message = self.filtered_line( message + "\n", meaning ) if meaning == 'error': if message: message = as_highlighted( meaning, " = Error " + str(error_id) + " = ") + "\n" + message else: self.errors -= 1 elif meaning == 'warning': if message: message = as_highlighted( meaning, " = Warning " + str(warning_id) + " = ") + "\n" + message else: self.warnings -= 1 return message return self.filtered_line( line ) def normalise_path( self, file_path ): normalised_path = file_path if os.path.exists( file_path ): normalised_path = os.path.relpath( os.path.realpath( file_path ) ) # if normalised_path[0] != '.' and normalised_path[0] != os.path.sep: # normalised_path = '.' + os.path.sep + normalised_path # return os.path.abspath( normalised_path ) return normalised_path def interpret( self, line ): Interpretors = self.toolchain.output_interpretors() for interpretor in Interpretors: Regex = interpretor['regex'] Matches = re.match( Regex, line ) if Matches: error_id = 0 warning_id = 0 if interpretor['meaning'] == 'error': self.errors += 1 error_id = self.errors elif interpretor['meaning'] == 'warning': self.warnings += 1 warning_id = self.warnings return ( Matches, interpretor, error_id, warning_id, ) return ( None, None, None, None, ) def summary( self, returncode ): elapsed_time = time.time() - self.start_time Summary = '' if returncode: Summary += as_highlighted( 'summary', " === Process Terminated with status " + str(returncode) + " (Elapsed " + str(elapsed_time) + "s)" + " === ") + "\n" if self.errors: Summary += as_highlighted( 'error', " === Errors " + str(self.errors) + " === ") if self.warnings: Summary += as_highlighted( 'warning', " === Warnings " + str(self.warnings) + " === ") return Summary PK-¹ƒFg¡;ÛHHcuppa/utility.py # Copyright Jamie Allsop 2014-2015 # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) #------------------------------------------------------------------------------- # Utility #------------------------------------------------------------------------------- # Check if an object is a string try: basestring def is_string( x ): return isinstance( x, basestring ) except NameError: def is_string( x ): return isinstance( x, str ) PKDkRG!'„݇݇ cuppa/core.py# Copyright Jamie Allsop 2011-2015 # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) #------------------------------------------------------------------------------- # Core #------------------------------------------------------------------------------- # Python Standard import os.path import os import re import fnmatch import multiprocessing import pkg_resources import collections # Scons import SCons.Script # Custom import cuppa.modules.registration import cuppa.build_platform import cuppa.output_processor import cuppa.recursive_glob import cuppa.configure import cuppa.options import cuppa.version #import cuppa.cpp.stdcpp from cuppa.colourise import colouriser, as_emphasised, as_info, as_error, as_notice from cuppa.log import initialise_logging, set_logging_level, reset_logging_format, logger from cuppa.toolchains import * from cuppa.methods import * from cuppa.dependencies import * from cuppa.profiles import * from cuppa.variants import * from cuppa.project_generators import * SCons.Script.Decider( 'MD5-timestamp' ) def add_option( *args, **kwargs ): SCons.Script.AddOption( *args, **kwargs ) def add_base_options(): add_option( '--raw-output', dest='raw_output', action='store_true', help='Disable output processing like colourisation of output' ) add_option( '--standard-output', dest='standard_output', action='store_true', help='Perform standard output processing but not colourisation of output' ) add_option( '--minimal-output', dest='minimal_output', action='store_true', help='Show only errors and warnings in the output' ) add_option( '--ignore-duplicates', dest='ignore_duplicates', action='store_true', help='Do not show repeated errors or warnings' ) add_option( '--projects', type='string', nargs=1, action='callback', callback=cuppa.options.list_parser( 'projects' ), help='Projects to build (alias for scripts)' ) add_option( '--scripts', type='string', nargs=1, action='callback', callback=cuppa.options.list_parser( 'projects' ), help='Sconscripts to run' ) add_option( '--thirdparty', type='string', nargs=1, action='store', dest='thirdparty', metavar='DIR', help='Thirdparty directory' ) add_option( '--build-root', type='string', nargs=1, action='store', dest='build_root', help='The root directory for build output. If not specified then _build_ is used' ) add_option( '--download-root', type='string', nargs=1, action='store', dest='download_root', help='The root directory for downloading external libraries to. If not specified then _cuppa_ is used' ) add_option( '--cache-root', type='string', nargs=1, action='store', dest='cache_root', help='The root directory for caching downloaded external archived libraries. If not specified then ~/_cuppa_/cache is used' ) add_option( '--runner', type='string', nargs=1, action='store', dest='runner', help='The test runner to use for executing tests. The default is the process test runner' ) add_option( '--dump', dest='dump', action='store_true', help='Dump the default environment and exit' ) add_option( '--parallel', dest='parallel', action='store_true', help='Enable parallel builds utilising the available concurrency. Translates to -j N with N chosen based on the current hardware' ) add_option( '--show-test-output', dest='show-test-output', action='store_true', help='When executing tests display all outout to stdout and stderr as appropriate' ) verbosity_choices = ( 'trace', 'debug', 'info', 'warn', 'error' ) add_option( '--verbosity', dest='verbosity', choices=verbosity_choices, nargs=1, action='store', help='The The verbosity level that you wish to run cuppa at. Default level is info' ) # add_option( '--b2', dest='b2', action='store_true', # help='Execute boost.build by calling b2 or bjam' ) # add_option( '--b2-path', type='string', nargs=1, action='store', # dest='b2_path', # help='Specify a path to bjam or b2' ) decider_choices = ( 'timestamp-newer', 'timestamp-match', 'MD5', 'MD5-timestamp' ) add_option( '--decider', dest='decider', choices=decider_choices, nargs=1, action='store', help='The decider to use for determining if a dependency has changed. Refer to the Scons manual for more details. By default "MD5-timestamp" is used' ) def set_base_options(): SCons.Script.SetOption( 'warn', 'no-duplicate-environment' ) class ConstructException(Exception): def __init__(self, value): self.parameter = value def __str__(self): return repr(self.parameter) class ParseToolchainsOption(object): def __init__( self, supported_toolchains, available_toolchains ): self._supported = supported_toolchains self._available = available_toolchains def __call__(self, option, opt, value, parser): toolchains = set() requested = value.split(',') for toolchain in requested: supported = fnmatch.filter( self._supported, toolchain ) if not supported: logger.warn( "Requested toolchain [{}] does not match any supported, skipping".format( as_info(toolchain) ) ) else: available = fnmatch.filter( self._available, toolchain ) if not available: logger.warn( "Requested toolchain [{}] does not match any available, skipping".format( as_info(toolchain) ) ) else: toolchains.update( available ) if not toolchains: logger.error( "None of the requested toolchains are available" ) parser.values.toolchains = list(toolchains) # class ParseTargetArchsOption(object): # def __init__( self, available_toolchains ): # self._available = available_toolchains # def __call__(self, option, opt, value, parser): # target_archs = set() # requested = value.split(',') # for target_arch in requested: # supported = fnmatch.filter( self._supported, toolchain ) # if not supported: # print "cuppa: requested toolchain(s) [{}] does not match any supported, skipping".format( toolchain ) # else: # available = fnmatch.filter( self._available, toolchain ) # if not available: # print "cuppa: requested toolchain(s) [{}] supported does not match any available, skipping".format( toolchain ) # else: # toolchains.update( available ) # if not toolchains: # print "cuppa: None of the requested toolchains are available" # parser.values.toolchains = list(toolchains) class CuppaEnvironment(collections.MutableMapping): _tools = [] _options = {} _cached_options = {} _methods = {} # Option Interface @classmethod def get_option( cls, option, default=None ): if option in cls._cached_options: return cls._cached_options[ option ] value = SCons.Script.GetOption( option ) source = None if value == None or value == '': if cls._options['default_options'] and option in cls._options['default_options']: value = cls._options['default_options'][ option ] source = "in the sconstruct file" elif default: value = default source = "using default" else: source = "on command-line" if option in cls._options['configured_options']: source = "using configure" if value: logger.debug( "option [{}] set {} as [{}]".format( as_info( option ), source, as_info( str(value) ) ) ) cls._cached_options[option] = value return value @classmethod def _get_option_method( cls, env, option, default=None ): return cls.get_option( option, default ) # Environment Interface @classmethod def default_env( cls ): if not hasattr( cls, '_default_env' ): cls._default_env = SCons.Script.Environment( tools=['default'] + cls._tools ) return cls._default_env @classmethod def create_env( cls, **kwargs ): tools = ['default'] + cls._tools if 'tools' in kwargs: tools = tools + kwargs['tools'] del kwargs['tools'] tools = SCons.Script.Flatten( tools ) env = SCons.Script.Environment( tools = tools, **kwargs ) env['default_env'] = CuppaEnvironment.default_env() for key, option in cls._options.iteritems(): env[key] = option for name, method in cls._methods.iteritems(): env.AddMethod( method, name ) env.AddMethod( cls._get_option_method, "get_option" ) return env @classmethod def dump( cls ): print str( cls._options ) print str( cls._methods ) @classmethod def colouriser( cls ): return colouriser @classmethod def add_tools( cls, tools ): cls._tools.append( tools ) @classmethod def tools( cls ): return cls._tools @classmethod def add_method( cls, name, method ): cls._methods[name] = method @classmethod def add_variant( cls, name, variant ): if not 'variants' in cls._options: cls._options['variants'] = {} cls._options['variants'][name] = variant @classmethod def add_action( cls, name, action ): if not 'actions' in cls._options: cls._options['actions'] = {} cls._options['actions'][name] = action @classmethod def add_supported_toolchain( cls, name ): if not 'supported_toolchains' in cls._options: cls._options['supported_toolchains'] = [] cls._options['supported_toolchains'].append( name ) @classmethod def add_available_toolchain( cls, name, toolchain ): if not 'toolchains' in cls._options: cls._options['toolchains'] = {} cls._options['toolchains'][name] = toolchain @classmethod def add_project_generator( cls, name, project_generator ): if not 'project_generators' in cls._options: cls._options['project_generators'] = {} cls._options['project_generators'][name] = project_generator @classmethod def add_profile( cls, name, profile ): if not 'profiles' in cls._options: cls._options['profiles'] = {} cls._options['profiles'][name] = profile @classmethod def add_dependency( cls, name, dependency ): if not 'dependencies' in cls._options: cls._options['dependencies'] = {} cls._options['dependencies'][name] = dependency # Dict Interface def __getitem__( self, key ): return self._options[key] def __setitem__( self, key, value ): self._options[key] = value def __delitem__( self, key ): del self._options[key] del self._cached_options[key] def __iter__( self ): return iter( self._options ) def __len__( self ): return len( self._options ) def __contains__( self, key ): return key in self._options class Construct(object): platforms_key = 'platforms' variants_key = 'variants' actions_key = 'actions' toolchains_key = 'toolchains' dependencies_key = 'dependencies' profiles_key = 'profiles' methods_key = 'methods' project_generators_key = 'project_generators' def add_platforms( self, env ): platforms = self.platforms_key env[platforms] = cuppa.build_platform.Platform.supported() def add_project_generators( self, env ): cuppa.modules.registration.add_to_env( self.project_generators_key, env ) def add_variants( self, env ): variants = self.variants_key cuppa.modules.registration.add_to_env( variants, env, env.add_variant, env.add_action ) cuppa.modules.registration.add_options( variants ) def colour_items( self, items, colour_func=as_notice ): return "'{}'".format( "', '".join( colour_func( item ) for item in items ) ) def add_toolchains( self, env ): toolchains = self.toolchains_key cuppa.modules.registration.add_to_env( toolchains, env, env.add_available_toolchain, env.add_supported_toolchain ) logger.trace( "supported toolchains are [{}]".format( self.colour_items( env["supported_toolchains"] ) ) ) logger.info( "available toolchains are [{}]".format( self.colour_items( sorted( env[toolchains].keys(), reverse=True ), as_info ) ) ) SCons.Script.AddOption( '--toolchains', type = 'string', nargs = 1, action = 'callback', callback = ParseToolchainsOption( env['supported_toolchains'], env[toolchains].keys() ), help = 'The Toolchains you wish to build against. A comma separate list with wildcards' ' may be provided. For example --toolchains=gcc*,clang37,clang36' ) # TODO # SCons.Script.AddOption( # '--target-arch', # type = 'string', # nargs = 1, # action = 'callback', # callback = ParseTargetArchsOption( env[toolchains] ), # help = 'The Target Archictectures you wish to generate executables for. You may' # ' specify a number a comma separated list of architectures. You may also' # ' restrict an acrhitecture to a specific toolchain by prepending it with a' # ' toolchain name followed by a ":". Only valid architectures for each toolchain' # ' will be built. Example --target-arch=64,vc100:amd64,x86 is valid.' # ) def initialise_options( self, options, default_options, dependencies ): options['default_options'] = default_options or {} # env.AddMethod( self.get_option, "get_option" ) add_base_options() cuppa.modules.registration.add_options( self.toolchains_key ) cuppa.modules.registration.add_options( self.dependencies_key ) cuppa.modules.registration.add_options( self.profiles_key ) cuppa.modules.registration.add_options( self.project_generators_key ) cuppa.modules.registration.add_options( self.methods_key ) if dependencies: for dependency in dependencies.itervalues(): dependency.add_options( SCons.Script.AddOption ) # cuppa.cpp.stdcpp.add_options( SCons.Script.AddOption ) def print_construct_variables( self, env ): keys = { 'raw_output', 'standard_output', 'minimal_output', 'ignore_duplicates', 'working_dir', 'launch_dir', 'launch_offset_dir', 'run_from_launch_dir', 'base_path', 'branch_root', 'branch_dir', 'download_root', 'cache_root', 'thirdparty', 'build_root', 'default_dependencies', 'BUILD_WITH', 'dependencies', 'sconscript_dir', 'sconscript_file', 'build_dir', 'offset_dir', 'parallel', 'show_test_output', 'decider' } for key in keys: if key in env: print "cuppa: Env[%s] = %s" % ( key, env[key] ) def __init__( self, base_path = os.path.abspath( '.' ), branch_root = None, default_options = None, default_projects = None, default_variants = None, default_dependencies = None, default_profiles = None, default_runner = None, configure_callback = None, dependencies = None, tools = [] ): cuppa.version.check_current_version() set_base_options() initialise_logging() cuppa_env = CuppaEnvironment() cuppa_env.add_tools( tools ) self.initialise_options( cuppa_env, default_options, dependencies ) cuppa_env['configured_options'] = {} self._configure = cuppa.configure.Configure( cuppa_env, callback=configure_callback ) verbosity = cuppa_env.get_option( 'verbosity' ) if verbosity: set_logging_level( verbosity ) cuppa_env['sconstruct_file'] = cuppa_env.get_option( 'file' ) if not cuppa_env['sconstruct_file']: for path in [ 'SConstruct', 'Sconstruct', 'sconstruct' ]: if os.path.exists( path ): cuppa_env['sconstruct_file'] = path cuppa_env['raw_output'] = cuppa_env.get_option( 'raw_output' ) and True or False cuppa_env['standard_output'] = cuppa_env.get_option( 'standard_output' ) and True or False if not cuppa_env['raw_output'] and not cuppa_env['standard_output']: cuppa_env.colouriser().enable() reset_logging_format() logger.info( "using sconstruct file [{}]".format( as_notice( cuppa_env['sconstruct_file'] ) ) ) help = cuppa_env.get_option( 'help' ) and True or False self._configure.load() cuppa_env['minimal_output'] = cuppa_env.get_option( 'minimal_output' ) cuppa_env['ignore_duplicates'] = cuppa_env.get_option( 'ignore_duplicates' ) cuppa_env['working_dir'] = os.getcwd() cuppa_env['launch_dir'] = os.path.relpath( SCons.Script.GetLaunchDir(), cuppa_env['working_dir'] ) cuppa_env['run_from_launch_dir'] = cuppa_env['launch_dir'] == "." cuppa_env['launch_offset_dir'] = "." if not cuppa_env['run_from_launch_dir']: levels = len( cuppa_env['launch_dir'].split( os.path.sep ) ) cuppa_env['launch_offset_dir'] = os.path.sep.join( ['..' for i in range(levels)] ) cuppa_env['base_path'] = os.path.normpath( os.path.expanduser( base_path ) ) cuppa_env['branch_root'] = branch_root and os.path.normpath( os.path.expanduser( branch_root ) ) or base_path cuppa_env['branch_dir'] = cuppa_env['branch_root'] and os.path.relpath( cuppa_env['base_path'], cuppa_env['branch_root'] ) or None thirdparty = cuppa_env.get_option( 'thirdparty' ) if thirdparty: thirdparty = os.path.normpath( os.path.expanduser( thirdparty ) ) cuppa_env['thirdparty'] = thirdparty build_root = cuppa_env.get_option( 'build_root', default='_build' ) cuppa_env['build_root'] = os.path.normpath( os.path.expanduser( build_root ) ) download_root = cuppa_env.get_option( 'download_root', default='_cuppa' ) cuppa_env['download_root'] = os.path.normpath( os.path.expanduser( download_root ) ) cache_root = cuppa_env.get_option( 'cache_root', default='~/_cuppa/_cache' ) cuppa_env['cache_root'] = os.path.normpath( os.path.expanduser( cache_root ) ) if not os.path.exists( cuppa_env['cache_root'] ): os.makedirs( cuppa_env['cache_root'] ) cuppa_env['default_projects'] = default_projects cuppa_env['default_variants'] = default_variants and set( default_variants ) or set() cuppa_env['default_dependencies'] = default_dependencies and default_dependencies or [] cuppa_env['BUILD_WITH'] = cuppa_env['default_dependencies'] cuppa_env['dependencies'] = {} cuppa_env['default_profiles'] = default_profiles and default_profiles or [] cuppa_env['BUILD_PROFILE'] = cuppa_env['default_profiles'] cuppa_env['profiles'] = {} test_runner = cuppa_env.get_option( 'runner', default=default_runner and default_runner or 'process' ) cuppa_env['default_runner'] = test_runner cuppa_env['show_test_output'] = cuppa_env.get_option( 'show-test-output' ) and True or False self.add_variants ( cuppa_env ) self.add_toolchains ( cuppa_env ) self.add_platforms ( cuppa_env ) cuppa_env['platform'] = cuppa.build_platform.Platform.current() toolchains = cuppa_env.get_option( 'toolchains' ) cuppa_env[ 'target_architectures' ] = None if not help and not self._configure.handle_conf_only(): default_toolchain = cuppa_env['platform'].default_toolchain() if not toolchains: toolchains = [ cuppa_env[self.toolchains_key][default_toolchain] ] else: toolchains = [ cuppa_env[self.toolchains_key][t] for t in toolchains ] cuppa_env['active_toolchains'] = toolchains def add_dependency( name, dependency ): cuppa_env['dependencies'][name] = dependency cuppa.modules.registration.get_options( "methods", cuppa_env ) if not help and not self._configure.handle_conf_only(): cuppa_env[self.project_generators_key] = {} cuppa.modules.registration.add_to_env( "dependencies", cuppa_env, add_dependency ) cuppa.modules.registration.add_to_env( "profiles", cuppa_env ) cuppa.modules.registration.add_to_env( "methods", cuppa_env ) cuppa.modules.registration.add_to_env( "project_generators", cuppa_env ) for method_plugin in pkg_resources.iter_entry_points( group='cuppa.method.plugins', name=None ): method_plugin.load().add_to_env( cuppa_env ) if dependencies: for name, dependency in dependencies.iteritems(): dependency.add_to_env( cuppa_env, add_dependency ) # TODO - default_profile if cuppa_env.get_option( 'dump' ): cuppa_env.dump() SCons.Script.Exit() job_count = cuppa_env.get_option( 'num_jobs' ) parallel = cuppa_env.get_option( 'parallel' ) parallel_mode = "manually" if job_count==1 and parallel: job_count = multiprocessing.cpu_count() if job_count > 1: SCons.Script.SetOption( 'num_jobs', job_count ) parallel_mode = "automatically" cuppa_env['job_count'] = job_count cuppa_env['parallel'] = parallel if job_count>1: logger.debug( "Running in {} with option [{}] set {} as [{}]".format( as_emphasised("parallel mode"), as_info( "jobs" ), as_emphasised(parallel_mode), as_info( str( SCons.Script.GetOption( 'num_jobs') ) ) ) ) if not help and self._configure.handle_conf_only(): self._configure.save() if not help and not self._configure.handle_conf_only(): self.build( cuppa_env ) if self._configure.handle_conf_only(): print "cuppa: Handling onfiguration only, so no builds will be attempted." print "cuppa: With the current configuration executing 'scons -D' would be equivalent to:" print "" print "scons -D {}".format( self._command_line_from_settings( cuppa_env['configured_options'] ) ) print "" print "cuppa: Nothing to be done. Exiting." SCons.Script.Exit() def _command_line_from_settings( self, settings ): commands = [] for key, value in settings.iteritems(): command = as_emphasised( "--" + key ) if value != True and value != False: if not isinstance( value, list ): command += "=" + as_info( str(value) ) else: command += "=" + as_info( ",".join( value ) ) commands.append( command ) commands.sort() return " ".join( commands ) def get_active_actions_for_variant( self, cuppa_env, active_variants, variant ): available_variants = cuppa_env[ self.variants_key ] available_actions = cuppa_env[ self.actions_key ] specified_actions = {} for key, action in available_actions.items(): if cuppa_env.get_option( action.name() ): specified_actions[ action.name() ] = action if not specified_actions: default_variants = active_variants if default_variants: for variant in default_variants: if available_actions.has_key( variant ): specified_actions[ variant ] = available_actions[ variant ] active_actions = {} for key, action in specified_actions.items(): if key not in available_variants: active_actions[ key ] = action elif key == variant.name(): active_actions[ key ] = action return active_actions def create_build_envs( self, toolchain, cuppa_env ): variants = cuppa_env[ self.variants_key ] target_architectures = cuppa_env[ 'target_architectures' ] if not target_architectures: target_architectures = [ None ] active_variants = {} for key, variant in variants.items(): if cuppa_env.get_option( variant.name() ): active_variants[ variant.name() ] = variant if not active_variants: default_variants = cuppa_env['default_variants'] or toolchain.default_variants() if default_variants: for variant in default_variants: if variants.has_key( variant ): active_variants[ variant ] = variants[ variant ] build_envs = [] for key, variant in active_variants.items(): for target_arch in target_architectures: env, target_arch = toolchain.make_env( cuppa_env, variant, target_arch ) if env: build_envs.append( { 'variant': key, 'target_arch': target_arch, 'env': env } ) if not cuppa_env['raw_output']: cuppa.output_processor.Processor.install( env ) env['toolchain'] = toolchain env['variant'] = variant env['target_arch'] = target_arch env['variant_actions'] = self.get_active_actions_for_variant( cuppa_env, active_variants, variant ) return build_envs def get_sub_sconscripts( self, path, exclude_dirs ): file_regex = re.compile( r'([^.]+[.])?sconscript$', re.IGNORECASE ) discard_if_subdir_contains_regex = re.compile( r'(SC|Sc|sc)onstruct' ) def up_dir( path ): element = next( e for e in path.split(os.path.sep) if e ) return element == ".." exclude_dirs = [ re.escape(d) for d in exclude_dirs if not os.path.isabs(d) and not up_dir(d) ] exclude_dirs = "|".join( exclude_dirs ) exclude_dirs_regex = re.compile( exclude_dirs, re.IGNORECASE ) return cuppa.recursive_glob.glob( path, file_regex, exclude_dirs_pattern= exclude_dirs_regex, discard_pattern=discard_if_subdir_contains_regex ) def build( self, cuppa_env ): projects = cuppa_env.get_option( 'projects' ) toolchains = cuppa_env['active_toolchains'] if projects == None: projects = cuppa_env['default_projects'] if projects == None or not cuppa_env['run_from_launch_dir']: sub_sconscripts = self.get_sub_sconscripts( cuppa_env['launch_dir'], [ cuppa_env['build_root'], cuppa_env['download_root'] ] ) if sub_sconscripts: projects = sub_sconscripts logger.info( "Using sub-sconscripts [{}]".format( self.colour_items( projects ) ) ) elif projects != None: logger.info( "Using default_projects [{}]".format( self.colour_items( projects ) ) ) if projects: sconscripts = [] for project in projects: if os.path.exists( project ) and os.path.isdir( project ): sub_sconscripts = self.get_sub_sconscripts( project, [ cuppa_env['build_root'], cuppa_env['download_root'] ] ) if sub_sconscripts: logger.info( "Reading project folder [{}] and using sub-sconscripts [{}]".format( project, self.colour_items( sub_sconscripts ) ) ) sconscripts.extend( sub_sconscripts ) else: sconscripts.append( project ) for toolchain in toolchains: build_envs = self.create_build_envs( toolchain, cuppa_env ) for build_env in build_envs: for sconscript in sconscripts: decider = cuppa_env.get_option( 'decider' ) if decider: build_env['env'].Decider( decider ) self.call_project_sconscript_files( toolchain, build_env['variant'], build_env['target_arch'], build_env['env'], sconscript ) else: logger.warn( "No projects to build. Nothing to be done" ) def call_project_sconscript_files( self, toolchain, variant, target_arch, sconscript_env, project ): sconscript_file = project if not os.path.exists( project ) or os.path.isdir( project ): sconscript_file = sconscript_file + '.sconscript' if os.path.exists( sconscript_file ) and os.path.isfile( sconscript_file ): logger.debug( "project exists and added to build [{}] using [{},{},{}]".format( as_notice( sconscript_file ), as_notice( toolchain.name() ), as_notice( variant ), as_notice( target_arch ) ) ) path_without_ext = os.path.splitext( sconscript_file )[0] sconstruct_offset_path, sconscript_name = os.path.split( sconscript_file ) name = os.path.splitext( sconscript_name )[0] if name.lower() == "sconscript": path_without_ext = sconstruct_offset_path name = path_without_ext sconscript_env['sconscript_file'] = sconscript_file build_root = sconscript_env['build_root'] # cloned_env = sconscript_env # cloned_env = sconscript_env.Clone() sconscript_env['sconscript_env'] = sconscript_env sconscript_env['sconscript_build_dir'] = path_without_ext sconscript_env['sconscript_toolchain_build_dir'] = os.path.join( path_without_ext, toolchain.name() ) sconscript_env['sconscript_dir'] = os.path.join( sconscript_env['base_path'], sconstruct_offset_path ) sconscript_env['build_dir'] = os.path.normpath( os.path.join( build_root, path_without_ext, toolchain.name(), variant, target_arch, 'working', '' ) ) sconscript_env['abs_build_dir'] = os.path.abspath( sconscript_env['build_dir'] ) sconscript_env['offset_dir'] = sconstruct_offset_path sconscript_env['final_dir'] = '..' + os.path.sep + 'final' + os.path.sep sconscript_env['active_toolchain'] = toolchain def abs_final_dir( abs_build_dir, final_dir ): return os.path.isabs( final_dir ) and final_dir or os.path.normpath( os.path.join( abs_build_dir, final_dir ) ) sconscript_env['abs_final_dir'] = abs_final_dir( sconscript_env['abs_build_dir'], sconscript_env['final_dir'] ) sconscript_env.AppendUnique( INCPATH = [ sconscript_env['offset_dir'] ] ) sconscript_exports = { 'env' : sconscript_env, 'sconscript_env' : sconscript_env, 'build_root' : build_root, 'build_dir' : sconscript_env['build_dir'], 'abs_build_dir' : sconscript_env['abs_build_dir'], 'final_dir' : sconscript_env['final_dir'], 'abs_final_dir' : sconscript_env['abs_final_dir'], 'common_variant_final_dir': '../../../common/final/', 'common_project_final_dir': build_root + '/common/final/', 'project' : name, } self._configure.configure( sconscript_exports['env'] ) cuppa.modules.registration.init_env_for_variant( "methods", sconscript_exports ) SCons.Script.SConscript( [ sconscript_file ], variant_dir = sconscript_exports['build_dir'], duplicate = 0, exports = sconscript_exports ) else: logger.error( "Skipping non-existent project [{}]".format( as_error( sconscript_file ) ) ) def run( *args, **kwargs ): Construct( *args, **kwargs ) PK-¹ƒF2¨Ô**cuppa/platforms/__init__.py # Copyright Jamie Allsop 2011-2015 # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) import cuppa.modules __all__ = cuppa.modules.registration.get_module_list( __file__ ) PKAp=GÑzeþþcuppa/platforms/linux.py # Copyright Jamie Allsop 2011-2015 # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) #------------------------------------------------------------------------------- # Linux Platform #------------------------------------------------------------------------------- from subprocess import Popen, PIPE from re import match, search, MULTILINE from os import path import platform import SCons.Script class LinuxException(Exception): def __init__(self, value): self.parameter = value def __str__(self): return repr(self.parameter) class Linux: @classmethod def add_to_env( cls, args ): args['env']['platforms']['Linux'] = cls() def __init__( self ): self._toolchain = None self.values = {} def default_toolchain( self ): if not self._toolchain: env = SCons.Script.Environment() self._toolchain = env['CC'] return self._toolchain return self._toolchain def __getitem__( self, key ): return self.values.get( key ) def _bit_depth( self, machine ): if machine == "i386": return '32' elif machine == "i686": return '32' elif machine == "x86_64": return '64' else: return 'unknown' def _libc_version( self, machine, system ): libc_file = "libc.so.6" libc_path = "/lib/" + libc_file if not path.exists( libc_path ): multiarch_lib_path = '-'.join( [ machine, system.lower(), 'gnu' ] ) libc_path = "/lib/" + multiarch_lib_path + "/" + libc_file try: libc_version = Popen([libc_path], stdout=PIPE).communicate()[0] return 'libc' + search( r'^GNU C Library [()a-zA-Z ]*([0-9][.0-9]+)', libc_version, MULTILINE ).expand(r'\1').replace('.','') except: print "Could not detect the version of libc installed. You might be missing some development libraries!" return None def initialise( self ): ( system, node, release, version, machine, processor ) = platform.uname() self.values['system'] = system self.values['node'] = node self.values['release'] = release self.values['version'] = version self.values['machine'] = machine self.values['processor'] = processor self.values['os'] = system self.values['architecture'] = machine self.values['os_version'] = match( r'(\d+\.\d+)', release ).group(0) self.values['bit_width'] = self._bit_depth( machine ) self.values['libc_version'] = self._libc_version( machine, system ) self.values['platform_path'] = self.values['architecture'] + '_' + self.values['os'] + '_' + self.values['os_version'] class Constants(object): CLOCK_REALTIME = 0 # System-wide realtime clock. CLOCK_MONOTONIC = 1 # Monotonic system-wide clock. CLOCK_PROCESS_CPUTIME_ID = 2 # High-resolution timer from the CPU. CLOCK_THREAD_CPUTIME_ID = 3 # Thread-specific CPU-time clock. CLOCK_MONOTONIC_RAW = 4 # Monotonic system-wide clock, not adjusted for frequency scaling. CLOCK_REALTIME_COARSE = 5 # System-wide realtime clock, updated only on ticks. CLOCK_MONOTONIC_COARSE = 6 # Monotonic system-wide clock, updated only on ticks. CLOCK_BOOTTIME = 7 # Monotonic system-wide clock that includes time spent in suspension. @classmethod def constants( cls ): return cls.Constants @classmethod def name( cls ): return cls.__name__ PK-¹ƒF:ï8§ § cuppa/platforms/darwin.py # Copyright Jamie Allsop 2014-2015 # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) #------------------------------------------------------------------------------- # Darwin Platform #------------------------------------------------------------------------------- import platform import SCons.Script class DarwinException(Exception): def __init__(self, value): self.parameter = value def __str__(self): return repr(self.parameter) class Darwin: @classmethod def add_to_env( cls, args ): args['env']['platforms']['Darwin'] = cls() def __init__( self ): self._toolchain = "clang" self.values = {} def default_toolchain( self ): if not self._toolchain: env = SCons.Script.Environment() self._toolchain = env['CC'] return self._toolchain return self._toolchain def __getitem__( self, key ): return self.values.get( key ) def _bit_depth( self, machine ): if machine == "i386": return '32' elif machine == "i686": return '32' elif machine == "x86_64": return '64' else: return 'unknown' def initialise( self ): ( system, node, release, version, machine, processor ) = platform.uname() self.values['system'] = system self.values['node'] = node self.values['release'] = release self.values['version'] = version self.values['machine'] = machine self.values['processor'] = processor self.values['os'] = system self.values['architecture'] = machine self.values['os_version'] = release # re.match( r'(\d+\.\d+)', release ).group(0) self.values['bit_width'] = self._bit_depth( machine ) self.values['platform_path'] = self.values['architecture'] + '_' + self.values['os'] + '_' + self.values['os_version'] class Constants(object): CLOCK_REALTIME = 0 # System-wide realtime clock. CLOCK_MONOTONIC = 1 # Monotonic system-wide clock. CLOCK_PROCESS_CPUTIME_ID = 2 # High-resolution timer from the CPU. CLOCK_THREAD_CPUTIME_ID = 3 # Thread-specific CPU-time clock. CLOCK_MONOTONIC_RAW = 4 # Monotonic system-wide clock, not adjusted for frequency scaling. CLOCK_REALTIME_COARSE = 5 # System-wide realtime clock, updated only on ticks. CLOCK_MONOTONIC_COARSE = 6 # Monotonic system-wide clock, updated only on ticks. CLOCK_BOOTTIME = 7 # Monotonic system-wide clock that includes time spent in suspension. @classmethod def constants( cls ): return cls.Constants @classmethod def name( cls ): return cls.__name__ PKDkRGL4TJJcuppa/platforms/windows.py # Copyright Jamie Allsop 2014-2014 # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) #------------------------------------------------------------------------------- # Windows Platform #------------------------------------------------------------------------------- import platform class WindowsException(Exception): def __init__(self, value): self.parameter = value def __str__(self): return repr(self.parameter) class Windows: @classmethod def add_to_env( cls, args ): args['env']['platforms']['Windows'] = cls() def __init__( self ): self._toolchain = None self.values = {} def default_toolchain( self ): if not self._toolchain: self._toolchain = 'vc' return self._toolchain def __getitem__( self, key ): return self.values.get( key ) def _bit_depth( self, machine ): machine = machine.lower() if machine == "x86": return '32' elif machine == "amd64": return '64' else: return 'unknown' def initialise( self ): ( system, node, release, version, machine, processor ) = platform.uname() self.values['system'] = system self.values['node'] = node self.values['release'] = release self.values['version'] = version self.values['machine'] = machine self.values['processor'] = processor self.values['os'] = system self.values['architecture'] = machine self.values['os_version'] = release self.values['bit_width'] = self._bit_depth( machine ) self.values['platform_path'] = self.values['architecture'] + '_' + self.values['os'] + '_' + self.values['os_version'] class Constants(object): pass @classmethod def constants( cls ): return cls.Constants @classmethod def name( cls ): return cls.__name__ PK-¹ƒF2¨Ô**$cuppa/project_generators/__init__.py # Copyright Jamie Allsop 2011-2015 # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) import cuppa.modules __all__ = cuppa.modules.registration.get_module_list( __file__ ) PKöRGKPö~¯@¯@&cuppa/project_generators/codeblocks.py # Copyright Jamie Allsop 2011-2015 # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) #------------------------------------------------------------------------------- # Codeblocks #------------------------------------------------------------------------------- import os from exceptions import Exception import cuppa.path import cuppa.progress import cuppa.tree import cuppa.options from cuppa.colourise import as_error, as_notice from cuppa.log import logger class CodeblocksException(Exception): def __init__(self, value): self.parameter = value def __str__(self): return repr(self.parameter) def ignored_types( env ): return [ env['PROGSUFFIX'], env['LIBSUFFIX'], env['SHLIBSUFFIX'], env['OBJSUFFIX'], env['SHOBJSUFFIX'], '.log' ] class Codeblocks(object): @classmethod def add_options( cls, add_option ): add_option( '--generate-cbs', dest='generate-cbs', action='store_true', help='Tell scons to generate a Codeblocks project', default=False ) add_option( '--generate-cbs-include-thirdparty', dest='generate_cbs_include_thirdparty', action='store_true', help='Include dependencies under the thirdparty directory or in downloaded libraries.', default=False ) add_option( '--generate-cbs-exclude-relative-branches', dest='generate_cbs_exclude_relative_branches', action='store_true', help='Exclude branches outside of the working directory', default=False ) add_option( '--generate-cbs-place-with-sconscript', dest='generate_cbs_place_with_sconscript', action='store_true', help='Exclude branches outside of the working directory', default=False ) add_option( '--generate-cbs-exclude-paths-starting', type='string', nargs=1, action='callback', callback=cuppa.options.list_parser( 'generate_cbs_exclude_paths_starting' ), help='Exclude dependencies starting with the specified paths from the file list for the project' ) @classmethod def add_to_env( cls, env ): try: generate = env.get_option( 'generate-cbs' ) if generate: obj = cls( env, env.get_option( 'generate_cbs_include_thirdparty' ), env.get_option( 'generate_cbs_exclude_relative_branches' ), env.get_option( 'generate_cbs_exclude_paths_starting' ), env.get_option( 'generate_cbs_place_with_sconscript' ) ) env['project_generators']['codeblocks'] = obj except CodeblocksException as error: logger.error( "Failed to create CodeBlocks project generator with error [{}]".format( as_error(error) ) ) def __init__( self, env, include_thirdparty, exclude_branches, excluded_paths_starting, place_cbs_by_sconscript ): self._include_thirdparty = include_thirdparty self._exclude_branches = exclude_branches self._excluded_paths_starting = excluded_paths_starting and excluded_paths_starting or [] self._place_cbs_by_sconscript = place_cbs_by_sconscript self._projects = {} base_include = self._exclude_branches and env['base_path'] or env['branch_root'] base = os.path.realpath( base_include ) download = os.path.realpath( env['download_root'] ) thirdparty = env['thirdparty'] and os.path.realpath( env['thirdparty'] ) or None common, tail1, tail2 = cuppa.path.split_common( base, download ) download_under_base = common and not tail1 thirdparty_under_base = None if thirdparty: common, tail1, tail2 = cuppa.path.split_common( base, thirdparty ) thirdparty_under_base = common and not tail1 self._exclude_paths = self._excluded_paths_starting self._build_root = [ env['build_root'] ] if not self._include_thirdparty: if download_under_base: self._exclude_paths.append( env['download_root'] ) if thirdparty and thirdparty_under_base: self._exclude_paths.append( env['thirdparty'] ) self._include_paths = [ base_include ] if self._include_thirdparty: if not download_under_base: self._include_paths.append( env['download_root'] ) if thirdparty and not thirdparty_under_base: self._include_paths.append( env['thirdparty'] ) self._ignored_types = ignored_types( env ) cuppa.progress.NotifyProgress.register_callback( None, self.on_progress ) logger.debug( "Including Paths Under = {}".format( as_notice( str( self._include_paths ) ) ) ) logger.debug( "Excluding Paths Starting = {}".format( as_notice( str( self._exclude_paths ) ) ) ) def on_progress( self, progress, sconscript, variant, env, target, source ): if progress == 'begin': self.on_sconscript_begin( env, sconscript ) elif progress == 'started': self.on_variant_started( env, sconscript ) elif progress == 'finished': self.on_variant_finished( sconscript, target[0], source ) elif progress == 'end': self.on_sconscript_end( sconscript ) elif progress =='sconstruct_end': self.on_sconstruct_end( env ) def on_sconscript_begin( self, env, sconscript ): pass def on_variant_started( self, env, sconscript ): project = sconscript toolchain = env['toolchain'].name() variant = env['variant'].name() build_root = env['build_root'] working_dir = env['build_dir'] final_dir_offset = env['final_dir'] self.update( env, project, toolchain, variant, build_root, working_dir, final_dir_offset ) def on_variant_finished( self, sconscript, root_node, source ): project = sconscript tree_processor = ProcessNodes( self._projects[project]['path'], self._projects[project]['files'], self._include_paths, self._exclude_paths + self._build_root, self._ignored_types ) cuppa.tree.process_tree( root_node, tree_processor, self._exclude_paths ) self._projects[project]['files'] = tree_processor.file_paths() def on_sconscript_end( self, sconscript ): self.write( sconscript ) def on_sconstruct_end( self, env ): workspace_dir = os.path.join( env['working_dir'], "cbs" ) workspace_path = os.path.join( workspace_dir, "all.workspace" ) if workspace_dir and not os.path.exists( workspace_dir ): os.makedirs( workspace_dir ) logger.debug( "Write workspace [{}]".format( as_notice( workspace_path ) ) ) with open( workspace_path, "w" ) as workspace_file: workspace_file.write( "\n".join( self.create_workspace( self._projects ) ) ) def update( self, env, project, toolchain, variant, build_root, working_dir, final_dir_offset ): logger.debug( "Update project [{}] for [{}, {}]".format( as_notice( project ), as_notice( toolchain) , as_notice( variant ) ) ) if project not in self._projects: title = os.path.splitext( project )[0] directory, filename = os.path.split( title ) cbs_file_name = filename if cbs_file_name in [ 'sconscript', 'SConscript', 'Sconscript' ]: cbs_file_name = os.path.split( directory )[1] if cbs_file_name == ".": cbs_file_name = os.path.split( os.path.abspath( env['sconscript_dir'] ) )[1] if not cbs_file_name: cbs_file_name = "sconscript" if not self._place_cbs_by_sconscript: directory = env['working_dir'] directory = os.path.join( directory, "cbs") project_file = directory + os.path.sep + cbs_file_name + ".cbp" execution_dir = '' if directory: execution_dir = os.path.relpath( os.getcwd(), directory ) execution_dir = ( os.path.pardir + os.path.sep + os.path.join( execution_dir, os.path.split( os.path.abspath( os.getcwd() ) )[1] ) ) self._projects[project] = {} self._projects[project]['title'] = title self._projects[project]['directory'] = directory self._projects[project]['path'] = os.path.join( os.getcwd(), directory ) self._projects[project]['execution_dir'] = execution_dir self._projects[project]['project_file'] = project_file self._projects[project]['working_dir'] = os.path.join( execution_dir, working_dir ) self._projects[project]['final_dir'] = os.path.normpath( os.path.join( self._projects[project]['working_dir'], final_dir_offset ) ) self._projects[project]['variants'] = set() self._projects[project]['toolchains'] = set() self._projects[project]['files'] = set() self._projects[project]['targets'] = {} self._projects[project]['lines_header'] = [] self._projects[project]['lines_footer'] = [] if not self._projects[project]['lines_header']: self._projects[project]['lines_header'] = self.create_header( self._projects[project]['title'], execution_dir ) if not self._projects[project]['lines_footer']: self._projects[project]['lines_footer'] = self.create_footer() self._projects[project]['variants'].add( variant ) self._projects[project]['toolchains'].add( toolchain ) target = "{}-{}".format( toolchain, variant ) test_actions = [ "", "--test" ] for action in test_actions: target_name = target + action if target_name not in self._projects[project]['targets']: self._projects[project]['targets'][target_name] = self.create_target( target_name, project, toolchain, variant, action, self._projects[project]['working_dir'], self._projects[project]['final_dir'] ) def write( self, project ): project_file = self._projects[project]['project_file'] directory = self._projects[project]['directory'] logger.debug( "Write [{}] for [{}]".format( as_notice( self._projects[project]['project_file'] ), as_notice( project ) ) ) if directory and not os.path.exists( directory ): os.makedirs( directory ) lines = [] lines += self._projects[project]['lines_header'] for target in sorted( self._projects[project]['targets'].itervalues() ): lines += target lines += [ '\t\t' ] for filepath in sorted( self._projects[project]['files'] ): lines += [ '\t\t' ] lines += self._projects[project]['lines_footer'] with open( project_file, "w" ) as cbs_file: cbs_file.write( "\n".join( lines ) ) def create_header( self, project, execution_dir ): lines = [ '\n' '\n' '\t\n' '\t' ] lines += [ '\t\t\n' '\n' ] return lines def create_target( self, target, project, toolchain, variant, test, working_dir, final_dir ): lines = [ '\t\t\t\n' '\t\t\t\t' ] return lines def create_workspace( self, projects ): lines = [ '\n' '\n' '\t' ] for project in projects.itervalues(): project_file = project['project_file'] base_path = project['path'] project_file = os.path.relpath( os.path.abspath( project_file ), base_path ) lines += [ '\t\t' ] lines += [ '\t\n' '\n' ] return lines class ProcessNodes(object): def __init__( self, base_path, files, allowed_paths, excluded_paths, ignored_types ): self._base_path = base_path self._files = files self._allowed_paths = allowed_paths self._excluded_paths = excluded_paths self._ignored_types = ignored_types def __call__( self, node ): file_path = str(node) for excluded in self._excluded_paths: if file_path.startswith( excluded ): return path, ext = os.path.splitext( file_path ) if ext and ext in self._ignored_types: return for allowed in self._allowed_paths: prefix = os.path.commonprefix( [ os.path.abspath( file_path ), allowed ] ) # logger.trace( "str(file)=[{}], file.path=[{}], allowed=[{}], prefix=[{}]".format( # as_notice( str(node) ), # as_notice( node.path ), # as_notice( str(allowed) ), # as_notice( str(prefix) ) # ) ) if prefix != allowed: return # logger.trace( "str(file)=[{}], file.path=[{}], allowed=[{}], prefix=[{}]".format( # as_notice( str(node) ), # as_notice( node.path ), # as_notice( str(allowed) ), # as_notice( str(prefix) ) # ) ) file_path = os.path.relpath( os.path.abspath( file_path ), self._base_path ) self._files.add( file_path ) return def file_paths( self ): return self._files PK-¹ƒF2¨Ô**cuppa/profiles/__init__.py # Copyright Jamie Allsop 2011-2015 # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) import cuppa.modules __all__ = cuppa.modules.registration.get_module_list( __file__ ) PK{QGtZGNNcuppa/methods/coverage.py # Copyright Jamie Allsop 2011-2015 # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) #------------------------------------------------------------------------------- # CoverageMethod #------------------------------------------------------------------------------- from SCons.Script import Flatten import cuppa.progress class CoverageMethod(object): def __init__( self ): pass def __call__( self, env, program, sources, final_dir=None ): if final_dir == None: final_dir = env['abs_final_dir'] emitter, builder = env['toolchain'].coverage_runner( program, final_dir ) env['BUILDERS']['CoverageBuilder'] = env.Builder( action=builder, emitter=emitter ) coverage = env.CoverageBuilder( [], Flatten( [ sources ] ) ) cuppa.progress.NotifyProgress.add( env, coverage ) return coverage @classmethod def add_to_env( cls, cuppa_env ): cuppa_env.add_method( "Coverage", cls() ) PK{QG ¯ä‰‰cuppa/methods/build_with.py # Copyright Jamie Allsop 2011-2015 # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) #------------------------------------------------------------------------------- # BuildWithMethod #------------------------------------------------------------------------------- class BuildWithException(Exception): def __init__(self, value): self.parameter = value def __str__(self): return repr(self.parameter) class BuildWithMethod: def __call__( self, env, build_with ): if isinstance( build_with, basestring ): build_with = [ build_with ] for name in build_with: if name in env['dependencies']: dependency_factory = env['dependencies'][name] if not dependency_factory: raise BuildWithException( "The sconscript [{}] requires the dependency [{}] but it is not available." .format( env['sconscript_file'], name ) ) env.AppendUnique( BUILD_WITH = name ) dependency = dependency_factory( env ) if dependency: dependency( env, env['toolchain'], env['variant'].name() ) else: raise BuildWithException( "The sconscript [{}] requires the dependency [{}] but it cannot be created." .format( env['sconscript_file'], name ) ) @classmethod def add_to_env( cls, cuppa_env ): cuppa_env.add_method( "BuildWith", cls() ) @classmethod def init_env_for_variant( cls, sconscript_exports ): env = sconscript_exports['env'] if env['default_dependencies']: env.BuildWith( env['default_dependencies'] ) PK{QGLgücuppa/methods/using.py # Copyright Jamie Allsop 2011-2015 # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) #------------------------------------------------------------------------------- # UseMethod #------------------------------------------------------------------------------- class UseMethod: def __init__( self, dependencies ): self.__dependencies = dependencies def __call__( self, env, dependency ): if dependency in self.__dependencies: return self.__dependencies[ dependency ] return None @classmethod def add_to_env( cls, cuppa_env ): cuppa_env.add_method( "Using", cls( cuppa_env['dependencies'] ) ) PK{QGb%Þš  cuppa/methods/toolchain.py # Copyright Jamie Allsop 2011-2015 # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) #------------------------------------------------------------------------------- # ToolchainMethod #------------------------------------------------------------------------------- class ToolchainMethod: def __init__( self, toolchains ): self.__toolchains = toolchains def __call__( self, env, toolchain ): if toolchain and toolchain in self.__toolchains: return self.__toolchains[ toolchain ] @classmethod def add_to_env( cls, cuppa_env ): cuppa_env.add_method( "Toolchain", cls( cuppa_env['toolchains'] ) ) PK{QGÞÍþLL(cuppa/methods/relative_recursive_glob.py # Copyright Jamie Allsop 2012-2015 # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) #------------------------------------------------------------------------------- # RelativeRecursiveGlob #------------------------------------------------------------------------------- import os import fnmatch import re import cuppa.recursive_glob class RecursiveGlobMethod: default = () def __call__( self, env, pattern, start=default, exclude_dirs=default ): if start == self.default: start = env['sconscript_dir'] start = os.path.expanduser( start ) if not os.path.isabs( start ): start = os.path.join( env['sconscript_dir'], start ) if exclude_dirs == self.default: exclude_dirs = [ env['download_root'], env['build_root' ] ] exclude_dirs_regex = None if exclude_dirs: def up_dir( path ): element = next( e for e in path.split(os.path.sep) if e ) return element == ".." exclude_dirs = [ re.escape(d) for d in exclude_dirs if not os.path.isabs(d) and not up_dir(d) ] exclude_dirs = "|".join( exclude_dirs ) exclude_dirs_regex = re.compile( exclude_dirs ) matches = cuppa.recursive_glob.glob( start, pattern, exclude_dirs_pattern=exclude_dirs_regex ) nodes = [ env.File( os.path.relpath( match, env['sconscript_dir'] ) ) for match in matches ] return nodes @classmethod def add_to_env( cls, cuppa_env ): cuppa_env.add_method( "RecursiveGlob", cls() ) class GlobFilesMethod: def __call__( self, env, pattern ): filenames = [] for filename in os.listdir(env['sconscript_dir']): if fnmatch.fnmatch( filename, pattern): filenames.append( filename ) nodes = [ env.File(f) for f in filenames ] return nodes @classmethod def add_to_env( cls, cuppa_env ): cuppa_env.add_method( "GlobFiles", cls() ) PK-¹ƒF2¨Ô**cuppa/methods/__init__.py # Copyright Jamie Allsop 2011-2015 # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) import cuppa.modules __all__ = cuppa.modules.registration.get_module_list( __file__ ) PK{QGÍpddcuppa/methods/remove_flags.py # Copyright Jamie Allsop 2015-2015 # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) #------------------------------------------------------------------------------- # RemoveFlags method #------------------------------------------------------------------------------- class RemoveFlagsMethod: def __init__( self ): pass def _remove_flags( self, remove, flags ): return [f for f in flags if not f.split('=')[0] in remove] def __call__( self, env, flags ): remove = set( f.split('=')[0] for f in flags ) env.Replace( CCFLAGS = self._remove_flags( remove, env['CCFLAGS'] ) ) env.Replace( CXXFLAGS = self._remove_flags( remove, env['CXXFLAGS'] ) ) env.Replace( CFLAGS = self._remove_flags( remove, env['CFLAGS'] ) ) env.Replace( LINKFLAGS = self._remove_flags( remove, env['LINKFLAGS'] ) ) return None @classmethod def add_to_env( cls, cuppa_env ): cuppa_env.add_method( "RemoveFlags", cls() ) PK{QG¨»»cuppa/methods/target_from.py # Copyright Jamie Allsop 2015-2015 # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) #------------------------------------------------------------------------------- # TargetFrom #------------------------------------------------------------------------------- import os class TargetFromMethod: def __call__( self, env, source, final_dir=None ): target = os.path.splitext( os.path.relpath( source.path, env['build_dir'] ) )[0] return target @classmethod def add_to_env( cls, cuppa_env ): cuppa_env.add_method( "TargetFrom", cls() ) PKDkRG‰h8KKcuppa/methods/stdcpp.py # Copyright Jamie Allsop 2011-2015 # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) #------------------------------------------------------------------------------- # StdCpp method #------------------------------------------------------------------------------- from cuppa.colourise import as_error, as_notice from cuppa.log import logger class StdCppMethod: stdcpp_choices = ( "c++98", "c++03", "c++0x", "c++11", "c++1y", "c++14" ) @classmethod def add_options( cls, add_option ): add_option( '--stdcpp', dest='stdcpp', choices=cls.stdcpp_choices, nargs=1, action='store', help="Use this option to override the default language compliance of your cpp compiler which by dafault is the highest compliance available. Value may be one of {}".format( str(cls.stdcpp_choices) ) ) @classmethod def get_options( cls, env ): env['stdcpp'] = env.get_option( 'stdcpp' ) def __init__( self ): pass def __call__( self, env, standard ): if standard not in self.stdcpp_choices: logger.error( "[{}] not in allowed list {}".format( as_error( standard ), as_notice( self.stdcpp_choices ) ) ) return None env[ 'stdcpp' ] = standard toolchain = env['toolchain'] flag = toolchain.stdcpp_flag_for( standard ) env.ReplaceFlags( [ flag ] ) return None @classmethod def add_to_env( cls, cuppa_env ): cuppa_env.add_method( "StdCpp", cls() ) PK{QGæVf»žžcuppa/methods/test.py # Copyright Jamie Allsop 2011-2015 # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) #------------------------------------------------------------------------------- # TestMethod #------------------------------------------------------------------------------- import cuppa.progress from SCons.Script import Flatten class TestMethod(object): def __init__( self, default_test_runner=None ): self._default_runner = default_test_runner def __call__( self, env, source, final_dir=None, data=None, runner=None, expected='passed' ): if final_dir == None: final_dir = env['abs_final_dir'] if not runner: runner = self._default_runner test_builder, test_emitter = env['toolchain'].test_runner( runner, final_dir, expected ) env['BUILDERS']['TestBuilder'] = env.Builder( action=test_builder, emitter=test_emitter ) sources = source if data: sources = Flatten( [ source, data ] ) test = env.TestBuilder( [], sources ) cuppa.progress.NotifyProgress.add( env, test ) return test @classmethod def add_to_env( cls, cuppa_env ): cuppa_env.add_method( "Test", cls( cuppa_env['default_runner'] ) ) test_runners = set() for toolchain in cuppa_env['active_toolchains']: for test_runner in toolchain.test_runners(): test_runners.add( test_runner ) for test_runner in test_runners: cuppa_env.add_method( "{}Test".format( test_runner.title() ), cls( test_runner ) ) PK{QGN‚ïu))cuppa/methods/build_test.py # Copyright Jamie Allsop 2011-2015 # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) #------------------------------------------------------------------------------- # BuildTestMethod #------------------------------------------------------------------------------- from SCons.Script import Flatten class BuildTestMethod: def __init__( self, default_test_runner=None ): self._default_runner = default_test_runner def __call__( self, env, target, source, final_dir=None, data=None, append_variant=None, runner=None, expected='passed', **kwargs ): nodes = [] program = env.Build( target, source, final_dir=final_dir, append_variant=append_variant, **kwargs ) nodes.append( program ) if env['variant_actions'].has_key('test') or env['variant_actions'].has_key('cov'): if not runner: runner = self._default_runner test = env.Test( program, final_dir=final_dir, data=data, runner=runner, expected=expected ) nodes.append( test ) if 'cov' in env['variant_actions']: coverage = env.Coverage( program, source, final_dir=final_dir ) nodes.append( coverage ) return Flatten( nodes ) @classmethod def add_to_env( cls, cuppa_env ): cuppa_env.add_method( "BuildTest", cls( cuppa_env['default_runner'] ) ) test_runners = set() for toolchain in cuppa_env['active_toolchains']: for test_runner in toolchain.test_runners(): test_runners.add( test_runner ) for test_runner in test_runners: cuppa_env.add_method( "Build{}Test".format( test_runner.title() ), cls( test_runner ) ) PK{QGÖ¯×77cuppa/methods/compile.py # Copyright Jamie Allsop 2013-2015 # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) #------------------------------------------------------------------------------- # CompileMethod #------------------------------------------------------------------------------- import cuppa.progress from SCons.Script import Flatten class CompileMethod: def __call__( self, env, source, **kwargs ): sources = Flatten( [ source ] ) objects = [] if 'CPPPATH' in env: env.AppendUnique( INCPATH = env['CPPPATH'] ) for source in sources: objects.append( env.Object( source = source, CPPPATH = env['SYSINCPATH'] + env['INCPATH'], **kwargs ) ) cuppa.progress.NotifyProgress.add( env, objects ) return objects @classmethod def add_to_env( cls, cuppa_env ): cuppa_env.add_method( "Compile", cls() ) PK{QG¦îßCCcuppa/methods/build.py # Copyright Jamie Allsop 2011-2015 # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) #------------------------------------------------------------------------------- # BuildMethod #------------------------------------------------------------------------------- import cuppa.progress import os.path class BuildMethod: @classmethod def build( cls, env, target, source, final_dir = None, append_variant = False, LIBS=[], DYNAMICLIBS=[], STATICLIBS=[], **kwargs ): if final_dir == None: final_dir = env['abs_final_dir'] exe = os.path.join( final_dir, target ) if append_variant and env['variant'] != 'rel': exe += '_' + env['variant'] env.AppendUnique( DYNAMICLIBS = env['LIBS'] ) if 'CPPPATH' in env: env.AppendUnique( INCPATH = env['CPPPATH'] ) all_libs = env['DYNAMICLIBS'] + env['STATICLIBS'] + LIBS + DYNAMICLIBS + STATICLIBS program = env.Program( exe, source, CPPPATH = env['SYSINCPATH'] + env['INCPATH'], LIBS = all_libs, DYNAMICLIBS = env['DYNAMICLIBS'] + LIBS + DYNAMICLIBS, STATICLIBS = env['STATICLIBS'] + STATICLIBS, **kwargs ) cuppa.progress.NotifyProgress.add( env, program ) return program def __call__( self, env, target, source, final_dir = None, append_variant = False, **kwargs ): return self.build( env, target, source, final_dir=final_dir, append_variant=append_variant, **kwargs ) @classmethod def add_to_env( cls, cuppa_env ): cuppa_env.add_method( "Build", cls() ) PK{QG;v´‘¼¼cuppa/methods/replace_flags.py # Copyright Jamie Allsop 2015-2015 # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) #------------------------------------------------------------------------------- # ReplaceFlags method #------------------------------------------------------------------------------- class ReplaceFlagsMethod: def __init__( self ): pass def __call__( self, env, flags ): env.RemoveFlags( flags ) env.MergeFlags( flags ) return None @classmethod def add_to_env( cls, cuppa_env ): cuppa_env.add_method( "ReplaceFlags", cls() ) PK{QGÌúº¸YYcuppa/methods/create_version.py # Copyright Jamie Allsop 2011-2015 # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) #------------------------------------------------------------------------------- # CreateVersionMethod #------------------------------------------------------------------------------- class CreateVersionMethod: def __init__( self ): pass def __call__( self, env, target, source, namespaces, version, location ): create_version_file_builder = env['toolchain'].version_file_builder( env, namespaces, version, location ) create_version_file_emitter = env['toolchain'].version_file_emitter( env, namespaces, version, location ) env.AppendUnique( BUILDERS = { 'CreateVersionFile' : env.Builder( action=create_version_file_builder, emitter=create_version_file_emitter ) } ) return env.CreateVersionFile( target, source ) @classmethod def add_to_env( cls, cuppa_env ): cuppa_env.add_method( "CreateVersion", cls() ) PK{QG?Ä ŽŽ!cuppa/methods/markdown_to_html.py # Copyright Jamie Allsop 2015-2015 # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) #------------------------------------------------------------------------------- # MarkdownToHtmlMethod #------------------------------------------------------------------------------- import os.path import itertools import grip import cuppa.progress class GripRunner(object): def __call__( self, target, source, env ): for s, t in itertools.izip( source, target ): in_file = str(s) out_file = str(t) try: grip.export( path=in_file, render_wide=True, out_filename=out_file ) except Exception as error: print "cuppa: error: grip.export( path={}, render_wide=True, out_filename={}) failed with error [{}]".format( in_file, out_file, error ) return None class GripEmitter(object): def __init__( self, output_dir ): self._output_dir = output_dir def __call__( self, target, source, env ): target = [] for s in source: path = os.path.join( self._output_dir, os.path.split( str(s) )[1] ) t = os.path.splitext(path)[0] + ".html" target.append(t) return target, source class MarkdownToHtmlMethod(object): def __call__( self, env, source, final_dir=None ): if final_dir == None: final_dir = env['abs_final_dir'] env.AppendUnique( BUILDERS = { 'Grip' : env.Builder( action = GripRunner(), emitter = GripEmitter(final_dir) ) } ) html = env.Grip( [], source ) cuppa.progress.NotifyProgress.add( env, html ) return html @classmethod def add_to_env( cls, cuppa_env ): cuppa_env.add_method( "MarkdownToHtml", cls() ) PK{QGÍx‡_99cuppa/methods/build_library.py # Copyright Jamie Allsop 2014-2014 # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) #------------------------------------------------------------------------------- # BuildLibMethods #------------------------------------------------------------------------------- import cuppa.progress import os.path class BuildStaticLibMethod: def __call__( self, env, target, source, final_dir=None, **kwargs ): if final_dir == None: final_dir = env['abs_final_dir'] lib = env.StaticLibrary( os.path.join( final_dir, target ), source, **kwargs ) cuppa.progress.NotifyProgress.add( env, lib ) return lib @classmethod def add_to_env( cls, cuppa_env ): cuppa_env.add_method( "BuildStaticLib", cls() ) class BuildSharedLibMethod: def __call__( self, env, target, source, final_dir=None, **kwargs ): if final_dir == None: final_dir = env['abs_final_dir'] lib = env.SharedLibrary( os.path.join( final_dir, target ), source, **kwargs ) cuppa.progress.NotifyProgress.add( env, lib ) return lib @classmethod def add_to_env( cls, cuppa_env ): cuppa_env.add_method( "BuildSharedLib", cls() ) PK{QG@]cÙµµcuppa/methods/build_profile.py # Copyright Jamie Allsop 2011-2015 # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) #------------------------------------------------------------------------------- # BuildProfileMethod #------------------------------------------------------------------------------- import cuppa.utility class BuildProfileMethod: def __call__( self, env, build_profile ): for profile in build_profile: if cuppa.utility.is_string( profile ): name = profile if name in env['profiles']: profile = env['profiles'][name] else: name = str( profile ) env.AppendUnique( BUILD_PROFILE = name ) profile( env, env['toolchain'], env['variant'].name() ) @classmethod def add_to_env( cls, cuppa_env ): cuppa_env.add_method( "BuildProfile", cls() ) @classmethod def init_env_for_variant( cls, sconscript_exports ): env = sconscript_exports['env'] if env['default_profiles']: env.BuildProfile( env['default_profiles'] ) PK{QG∱êcuppa/variants/dbg.py # Copyright Jamie Allsop 2011-2015 # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) #------------------------------------------------------------------------------- # Dbg #------------------------------------------------------------------------------- class Dbg: @classmethod def name( cls ): return cls.__name__.lower() @classmethod def add_options( cls, add_option ): add_option( '--dbg', dest=cls.name(), action='store_true', help='Build a debug binary' ) @classmethod def add_to_env( cls, env, add_variant, add_action ): add_variant( cls.name(), cls() ) PK-¹ƒF2¨Ô**cuppa/variants/__init__.py # Copyright Jamie Allsop 2011-2015 # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) import cuppa.modules __all__ = cuppa.modules.registration.get_module_list( __file__ ) PK{QG¡.66cuppa/variants/cov.py # Copyright Jamie Allsop 2011-2015 # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) #------------------------------------------------------------------------------- # Cov #------------------------------------------------------------------------------- class Cov: @classmethod def name( cls ): return cls.__name__.lower() @classmethod def add_options( cls, add_option ): add_option( '--cov', dest=cls.name(), action='store_true', help='Build an instrumented binary' ) @classmethod def add_to_env( cls, env, add_variant, add_action ): add_variant( cls.name(), cls() ) add_action( cls.name(), cls() ) PK-¹ƒF¼¨¶€cuppa/variants/test.py # Copyright Jamie Allsop 2011-2015 # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) #------------------------------------------------------------------------------- # Test #------------------------------------------------------------------------------- class Test: @classmethod def name( cls ): return cls.__name__.lower() @classmethod def add_options( cls, add_option ): add_option( '--test', dest=cls.name(), action='store_true', help='Run the binary as a test' ) @classmethod def add_to_env( cls, env, add_variant, add_action ): add_action( cls.name(), cls() ) PK{QG·5¯cuppa/variants/rel.py # Copyright Jamie Allsop 2011-2015 # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) #------------------------------------------------------------------------------- # Rel #------------------------------------------------------------------------------- class Rel: @classmethod def name( cls ): return cls.__name__.lower() @classmethod def add_options( cls, add_option ): add_option( '--rel', dest=cls.name(), action='store_true', help='Build a release (optimised) binary' ) @classmethod def add_to_env( cls, env, add_variant, add_action ): add_variant( cls.name(), cls() ) PK-¹ƒF2¨Ô**cuppa/dependencies/__init__.py # Copyright Jamie Allsop 2011-2015 # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) import cuppa.modules __all__ = cuppa.modules.registration.get_module_list( __file__ ) PKDkRG´*¨XX$cuppa/dependencies/build_with_qt4.py # Copyright Jamie Allsop 2015-2015 # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) #------------------------------------------------------------------------------- # Qt4 #------------------------------------------------------------------------------- import subprocess import shlex import glob # Cuppa Imports import cuppa.location import cuppa.output_processor import cuppa.build_platform from cuppa.colourise import as_info from cuppa.log import logger import SCons.Script class Qt4Exception(Exception): def __init__(self, value): self.parameter = value def __str__(self): return repr(self.parameter) class build_with_qt4(object): _name = "qt4" _qt4_tool = None @classmethod def add_options( cls, add_option ): pass @classmethod def add_to_env( cls, env, add_dependency ): add_dependency( cls._name, cls.create ) @classmethod def create( cls, env ): try: if not cls._qt4_tool: cls._qt4_tool = cls.retrieve_tool( env ) return build_with_qt4( env ) except Qt4Exception: logger.error( "Could not create dependency [{}]. Dependency not available.".format( cls._name ) ) return None @classmethod def retrieve_tool( cls, env ): url = "hg+https://bitbucket.org/dirkbaechle/scons_qt4" try: return cuppa.location.Location( env, url, extra_sub_path = "qt4" ) except cuppa.location.LocationException: logger.warn( "Could not retrieve scons_qt4 from [{}]".format( url ) ) return None def __init__( self, env ): self._version = "4" if cuppa.build_platform.name() in ["Darwin", "Linux"]: if cuppa.output_processor.command_available( "pkg-config" ): if 'QT4DIR' not in env: self._set_qt4_dir( env ) self._version = self._get_qt4_version() elif cuppa.build_platform.name() == "Windows": if 'QT4DIR' not in env: paths = glob.glob( 'C:\\Qt\\4.*\\*' ) if len(paths): paths.sort() env['QT4DIR'] = paths[-1] if 'QT4DIR' not in env: logger.error( "could not detect QT4 installation" ) raise Qt4Exception( "could not detect QT4 installation." ) logger.debug( "Q4DIR detected as [{}]".format( as_info( env['QT4DIR'] ) ) ) def _set_qt4_dir( self, env ): command = "pkg-config --cflags QtCore" try: cflags = subprocess.check_output( shlex.split( command ), stderr=subprocess.STDOUT ).strip() if cflags: flags = env.ParseFlags( cflags ) if 'CPPPATH' in flags: shortest_path = flags['CPPPATH'][0] for include in flags['CPPPATH']: if len(include) < len(shortest_path): shortest_path = include env['QT4DIR'] = shortest_path logger.debug( "Q4DIR detected as [{}]".format( as_info( env['QT4DIR'] ) ) ) except: logger.debug( "In _set_qt4_dir() failed to execute [{}]".format( command ) ) def _get_qt4_version( self ): command = "pkg-config --modversion QtCore" try: return subprocess.check_output( shlex.split( command ), stderr=subprocess.STDOUT ).strip() except: logger.debug( "In _get_qt4_version() failed to execute [{}]".format( command ) ) return None def __call__( self, env, toolchain, variant ): SCons.Script.Tool( 'qt4', toolpath=[ self._qt4_tool.base_local() ] )( env ) if cuppa.build_platform.name() in ["Darwin", "Linux"]: env.MergeFlags("-fPIC") def name( self ): return self._name def version( self ): return self._version def repository( self ): return "N/A" def branch( self ): return "N/A" def revisions( self ): return [] PK)“QGüˆgèè1è1'cuppa/dependencies/build_with_quince.py # Copyright Jamie Allsop 2015-2015 # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) #------------------------------------------------------------------------------- # Quince #------------------------------------------------------------------------------- import os.path import subprocess import shlex import platform import glob # Cuppa Imports import cuppa.location import cuppa.output_processor from cuppa.log import logger class QuinceLibraryMethod(object): def __init__( self, location, src_path ): self._location = location self._src_path = src_path def __call__( self, env, linktype ): build_dir = os.path.join( self._location, env['build_dir'] ) final_dir = os.path.normpath( os.path.join( build_dir, env['final_dir'] ) ) env.BuildWith( 'boost' ) objects = [] for source in env.RecursiveGlob( "*.cpp", start=self._src_path, exclude_dirs=[ env['build_dir'] ] ): rel_path = os.path.relpath( str(source), self._location ) obj_path = os.path.join( build_dir, os.path.splitext( rel_path )[0] ) +env['OBJSUFFIX'] objects.append( env.Object( obj_path, source ) ) if linktype == "static": return env.BuildStaticLib( "quince", objects, final_dir = final_dir ) else: shared_lib = env.BuildSharedLib( "quince", objects, final_dir = final_dir ) return env.Install( env['abs_final_dir'], shared_lib ) class build_with_quince(object): _name = "quince" _location = None @classmethod def add_options( cls, add_option ): location_name = cls._name + "-location" add_option( '--' + location_name, dest=location_name, type='string', nargs=1, action='store', help = cls._name + ' location to build against' ) @classmethod def add_to_env( cls, env, add_dependency ): add_dependency( cls._name, cls.create ) @classmethod def create( cls, env ): if not cls._location: location = env.get_option( cls._name + "-location" ) if not location: logger.error( "Dependency not available - no location specified" ) return None try: cls._location = cuppa.location.Location( env, location ) except cuppa.location.LocationException as error: logger.error( "Dependency not available - retrieving location failed with error [{}]." .format( str(error) ) ) return None return build_with_quince( env ) def __init__( self, env ): self._includes = [ os.path.join( self._location.local(), "include" ) ] self._src_path = os.path.join( self._location.local(), "src" ) env.AddMethod( QuinceLibraryMethod( self._location.local(), self._src_path ), "QuinceLibrary" ) def __call__( self, env, toolchain, variant ): env.AppendUnique( INCPATH = self._includes ) env.AppendUnique( STATICLIBS = [ env.QuinceLibrary( 'static' ), env.BoostStaticLibs( [ 'filesystem', 'system', 'thread', ] ), ] ) def name( self ): return self._name def version( self ): return str(self._location.version()) def repository( self ): return self._location.repository() def branch( self ): return self._location.branch() def revisions( self ): return self._location.revisions() class QuincePostgresqlLibraryMethod(object): def __init__( self, location, src_path ): self._location = location self._src_path = src_path def __call__( self, env, linktype ): build_dir = os.path.join( self._location, env['build_dir'] ) final_dir = os.path.normpath( os.path.join( build_dir, env['final_dir'] ) ) env.BuildWith( 'boost' ) objects = [] for source in env.RecursiveGlob( "*.cpp", start=self._src_path, exclude_dirs=[ env['build_dir'] ] ): rel_path = os.path.relpath( str(source), self._location ) obj_path = os.path.join( build_dir, os.path.splitext( rel_path )[0] ) +env['OBJSUFFIX'] objects.append( env.Object( obj_path, source ) ) if linktype == "static": return env.BuildStaticLib( "quince-postgresql", objects, final_dir = final_dir ) else: shared_lib = env.BuildSharedLib( "quince-postgresql", objects, final_dir = final_dir ) return env.Install( env['abs_final_dir'], shared_lib ) class quince_postgresql(object): _name = "quince-postgresql" _location = None @classmethod def add_options( cls, add_option ): location_name = cls._name + "-location" add_option( '--' + location_name, dest=location_name, type='string', nargs=1, action='store', help = cls._name + ' location to build against' ) @classmethod def add_to_env( cls, env, add_dependency ): add_dependency( cls._name, cls.create ) @classmethod def create( cls, env ): if not cls._location: location = env.get_option( cls._name + "-location" ) if not location: logger.error( "postgresql: Dependency not available - no location specified" ) return None try: cls._location = cuppa.location.Location( env, location ) except cuppa.location.LocationException as error: logger.error( "postgresql: Dependency not available - retrieving location failed with error [{}]." .format( str(error) ) ) return None return quince_postgresql( env ) def __init__( self, env ): self._flags = {} self._flags['INCPATH'] = [ os.path.join( self._location.local(), "include" ) ] pg_config = "pg_config" if platform.system() == "Windows": pg_config = pg_config + ".exe" if not cuppa.output_processor.command_available( pg_config ): # try to find the Postgresql install program_files = os.environ.get( "ProgramW6432" ) postgresql_base = os.path.join( program_files, "PostgreSQL" ) if os.path.exists( postgresql_base ): paths = glob.glob( postgresql_base + '\\*' ) if len(paths): paths.sort() latest = paths[-1] pg_config = '\"' + os.path.join( latest, "bin", pg_config ) + '\"' if cuppa.output_processor.command_available( pg_config ): command = "{pg_config} --includedir".format( pg_config = pg_config ) libpq_include = subprocess.check_output( shlex.split( command ), stderr=subprocess.STDOUT ).strip() self._flags['INCPATH'].append( libpq_include ) command = "{pg_config} --libdir".format( pg_config = pg_config ) libpq_libpath = subprocess.check_output( shlex.split( command ), stderr=subprocess.STDOUT ).strip() self._flags['LIBPATH'] = [ libpq_libpath ] else: logger.warn( "postgresql: pg_config not available so cannot determine LIBPATH for postgres libraries" ) self._flags['LIBPATH'] = [] self._flags['DYNAMICLIBS'] = [ 'pq' ] self._src_path = os.path.join( self._location.local(), "src" ) env.AddMethod( QuincePostgresqlLibraryMethod( self._location.local(), self._src_path ), "QuincePostgresqlLibrary" ) def __call__( self, env, toolchain, variant ): env.AppendUnique( INCPATH = self._flags['INCPATH'] ) env.AppendUnique( LIBPATH = self._flags['LIBPATH'] ) env.AppendUnique( DYNAMICLIBS = self._flags['DYNAMICLIBS'] ) quince_postgresql_lib = env.QuincePostgresqlLibrary('static') quince_lib = env.QuinceLibrary('static') env.Append( STATICLIBS = [ quince_postgresql_lib, quince_lib, env.BoostStaticLibs( [ 'date_time' ] ), ] ) def name( self ): return self._name def version( self ): return str(self._location.version()) def repository( self ): return self._location.repository() def branch( self ): return self._location.branch() def revisions( self ): return self._location.revisions() class QuinceSqliteLibraryMethod(object): def __init__( self, location, src_path ): self._location = location self._src_path = src_path def __call__( self, env, linktype ): build_dir = os.path.join( self._location, env['build_dir'] ) final_dir = os.path.normpath( os.path.join( build_dir, env['final_dir'] ) ) env.BuildWith( 'boost' ) objects = [] for source in env.RecursiveGlob( "*.cpp", start=self._src_path, exclude_dirs=[ env['build_dir'] ] ): rel_path = os.path.relpath( str(source), self._location ) obj_path = os.path.join( build_dir, os.path.splitext( rel_path )[0] ) +env['OBJSUFFIX'] objects.append( env.Object( obj_path, source ) ) if linktype == "static": return env.BuildStaticLib( "quince-sqlite", objects, final_dir = final_dir ) else: shared_lib = env.BuildSharedLib( "quince-sqlite", objects, final_dir = final_dir ) return env.Install( env['abs_final_dir'], shared_lib ) class quince_sqlite(object): _name = "quince-sqlite" _location = None @classmethod def add_options( cls, add_option ): location_name = cls._name + "-location" add_option( '--' + location_name, dest=location_name, type='string', nargs=1, action='store', help = cls._name + ' location to build against' ) @classmethod def add_to_env( cls, env, add_dependency ): add_dependency( cls._name, cls.create ) @classmethod def create( cls, env ): if not cls._location: location = env.get_option( cls._name + "-location" ) if not location: logger.error( "sqlite: Dependency not available - no location specified" ) return None try: cls._location = cuppa.location.Location( env, location ) except cuppa.location.LocationException as error: logger.error( "sqlite: Dependency not available - retrieving location failed with error [{}]." .format( str(error) ) ) return None return quince_sqlite( env ) def __init__( self, env ): self._flags = {} if cuppa.output_processor.command_available( "pkg-config"): command = "pkg-config --cflags --libs sqlite3" cflags = subprocess.check_output( shlex.split( command ), stderr=subprocess.STDOUT ).strip() self._flags = env.ParseFlags( cflags ) if 'CPPPATH' in self._flags: self._flags['SYSINCPATH'] = self._flags['CPPPATH'] del self._flags['CPPPATH'] if 'LIBS' in self._flags: self._flags['DYNAMICLIBS'] = self._flags['LIBS'] del self._flags['LIBS'] if not 'INCPATH' in self._flags: self._flags['INCPATH'] = [] self._flags['INCPATH'].append( os.path.join( self._location.local(), "include" ) ) self._src_path = os.path.join( self._location.local(), "src" ) env.AddMethod( QuinceSqliteLibraryMethod( self._location.local(), self._src_path ), "QuinceSqliteLibrary" ) def __call__( self, env, toolchain, variant ): for name, flags in self._flags.iteritems(): if flags: env.AppendUnique( **{ name: flags } ) quince_sqlite_lib = env.QuinceSqliteLibrary('static') quince_lib = env.QuinceLibrary('static') env.Append( STATICLIBS = [ quince_sqlite_lib, quince_lib, env.BoostStaticLibs( [ 'date_time', 'filesystem', ] ), ] ) def name( self ): return self._name def version( self ): return str(self._location.version()) def repository( self ): return self._location.repository() def branch( self ): return self._location.branch() def revisions( self ): return self._location.revisions() PKq‚RG ÷2€‘˜‘˜&cuppa/dependencies/build_with_boost.py # Copyright Jamie Allsop 2011-2015 # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) #------------------------------------------------------------------------------- # Boost #------------------------------------------------------------------------------- import shlex import subprocess import os import shutil import re import string import platform import lxml.html from exceptions import Exception from SCons.Script import File, AlwaysBuild, Flatten import cuppa.build_platform import cuppa.location from cuppa.output_processor import IncrementalSubProcess, ToolchainProcessor from cuppa.colourise import as_info, as_emphasised, as_notice from cuppa.log import logger class BoostException(Exception): def __init__(self, value): self.parameter = value def __str__(self): return repr(self.parameter) def determine_latest_boost_verion(): current_release = "1.59.0" try: html = lxml.html.parse('http://www.boost.org/users/download/') current_release = html.xpath("/html/body/div[2]/div/div[1]/div/div/div[2]/h3[1]/span")[0].text current_release = str( re.search( r'(\d[.]\d+([.]\d+)?)', current_release ).group(1) ) logger.debug( "latest boost release detected as [{}]".format( as_info( current_release ) ) ) except Exception as e: logger.warn( "cannot determine latest version of boost - [{}]. Assuming [{}].".format( str(e), current_release ) ) return current_release class Boost(object): _cached_boost_locations = {} @classmethod def add_options( cls, add_option ): add_option( '--boost-latest', dest='boost-latest', action='store_true', help='Specify that you want to use boost. The latest version will be downloaded and used.' ) add_option( '--boost-version', dest='boost-version', type='string', nargs=1, action='store', help='Boost Version to build against' ) add_option( '--boost-home', dest='boost-home', type='string', nargs=1, action='store', help='The location of the boost source code' ) add_option( '--boost-location', dest='boost-location', type='string', nargs=1, action='store', help='The location of the boost source code' ) add_option( '--boost-build-always', dest='boost-build-always', action='store_true', help="Pass this if your boost source may change (for example you are patching it)" " and you want boost build to be executed each time the library is asked for" ) add_option( '--boost-verbose-build', dest='boost-verbose-build', action='store_true', help="Pass this option if you wish to see the command-line output of boost build" ) add_option( '--boost-verbose-config', dest='boost-verbose-config', action='store_true', help="Pass this option if you wish to see the configuration output of boost build" ) add_option( '--boost-patch-boost-test', dest='boost-patch-boost-test', action='store_true', help="Use this option to patch boost test so it uses the new Boost.Timer and provides more usable output" ) @classmethod def add_to_env( cls, cuppa_env, add_dependency ): add_dependency( 'boost', cls.create ) @classmethod def _boost_location_id( cls, env ): location = env.get_option( 'boost-location' ) home = env.get_option( 'boost-home' ) version = env.get_option( 'boost-version' ) latest = env.get_option( 'boost-latest' ) thirdparty = env[ 'thirdparty' ] patch_test = env.get_option( 'boost-patch-boost-test' ) base = None if location: base = None elif home: base = home elif thirdparty and version: base = thirdparty elif version: base = None elif latest: version = "latest" return ( location, version, base, patch_test ) @classmethod def _get_boost_location( cls, env, location, version, base, patched ): logger.debug( "Identify boost using location = [{}], version = [{}], base = [{}], patched = [{}]".format( as_info( str(location) ), as_info( str(version) ), as_info( str(base) ), as_info( str(patched) ) ) ) if not base and not version and not location: raise BoostException("Cannot construct Boost Object. Invalid parameters") boost_home = None boost_location = None extra_sub_path = 'clean' if patched: extra_sub_path = 'patched' if location: location = cls.location_from_boost_version( location ) if not location: # use version as a fallback in case both at specified location = cls.location_from_boost_version( version ) boost_location = cuppa.location.Location( env, location, extra_sub_path=extra_sub_path, name_hint="boost" ) elif base: # Find boost locally if not os.path.isabs( base ): base = os.path.abspath( base ) if not version: boost_home = base elif version: search_list = [ os.path.join( base, 'boost', version, 'source' ), os.path.join( base, 'boost', 'boost_' + version ), os.path.join( base, 'boost', version ), os.path.join( base, 'boost_' + version ), ] def exists_in( locations ): for location in locations: home = cls._home_from_path( location ) if home: return home return None boost_home = exists_in( search_list ) if not boost_home: raise BoostException("Cannot construct Boost Object. Home for Version [{}] cannot be found. Seached in [{}]".format(version, str([l for l in search_list]))) else: raise BoostException("Cannot construct Boost Object. No Home or Version specified") logger.debug( "Using boost found at [{}]".format( as_info( boost_home ) ) ) boost_location = cuppa.location.Location( env, boost_home, extra_sub_path=extra_sub_path ) else: location = cls.location_from_boost_version( version ) boost_location = cuppa.location.Location( env, location, extra_sub_path=extra_sub_path ) if patched: cls.apply_patch_if_needed( boost_location.local() ) return boost_location @classmethod def create( cls, env ): boost_id = cls._boost_location_id( env ) if not boost_id in cls._cached_boost_locations: logger.debug( "Adding boost [{}] to env".format( as_notice( str(boost_id) ) ) ) cls._cached_boost_locations[ boost_id ] = cls._get_boost_location( env, boost_id[0], boost_id[1], boost_id[2], boost_id[3] ) location = cls._cached_boost_locations[ boost_id ] boost = None try: boost = cls( env, env[ 'platform' ], location ) except BoostException as e: logger.error( "Could not create boost dependency - {}".format(e) ) return None if not boost: logger.error( "Could not create boost dependency" ) return None build_always = env.get_option( 'boost-build-always' ) verbose_build = env.get_option( 'boost-verbose-build' ) verbose_config = env.get_option( 'boost-verbose-config' ) env.AddMethod( BoostStaticLibraryMethod( add_dependents=False, build_always=build_always, verbose_build=verbose_build, verbose_config=verbose_config), "BoostStaticLibrary" ) env.AddMethod( BoostSharedLibraryMethod( add_dependents=False, build_always=build_always, verbose_build=verbose_build, verbose_config=verbose_config), "BoostSharedLibrary" ) env.AddMethod( BoostStaticLibraryMethod( add_dependents=False, build_always=build_always, verbose_build=verbose_build, verbose_config=verbose_config), "BoostStaticLib" ) env.AddMethod( BoostSharedLibraryMethod( add_dependents=False, build_always=build_always, verbose_build=verbose_build, verbose_config=verbose_config), "BoostSharedLib" ) env.AddMethod( BoostStaticLibraryMethod( add_dependents=True, build_always=build_always, verbose_build=verbose_build, verbose_config=verbose_config), "BoostStaticLibs" ) env.AddMethod( BoostSharedLibraryMethod( add_dependents=True, build_always=build_always, verbose_build=verbose_build, verbose_config=verbose_config), "BoostSharedLibs" ) return boost def get_boost_version( self, location ): version_hpp_path = os.path.join( location, 'boost', 'version.hpp' ) if not os.path.exists( version_hpp_path ): raise BoostException("Boost version.hpp file not found") with open( version_hpp_path ) as version_hpp: for line in version_hpp: match = re.search( r'BOOST_VERSION\s+(?P\d+)', line ) if match: int_version = int(match.group('version')) major = int_version/100000 minor = int_version/100%1000 patch = int_version%100 full_version = "{}.{}.{}".format( major, minor, patch ) short_version = "{}_{}".format( major, minor ) numeric_version = float(major) + float(minor)/100 return full_version, short_version, numeric_version raise BoostException("Could not determine BoostVersion") @classmethod def _home_from_path( cls, path ): if os.path.exists( path ) and os.path.isdir( path ): return path return None @classmethod def location_from_boost_version( cls, location ): if location == "latest" or location == "current": location = determine_latest_boost_verion() if location: match = re.match( r'(boost_)?(?P\d[._]\d\d(?P[._]\d)?)', location ) if match: version = match.group('version') if not match.group('minor'): version += "_0" logger.debug( "Only boost version specified, retrieve from SourceForge if not already cached" ) extension = ".tar.gz" if cuppa.build_platform.name() == "Windows": extension = ".zip" return "http://sourceforge.net/projects/boost/files/boost/{numeric_version}/boost_{string_version}{extension}/download".format( numeric_version = version.translate( string.maketrans( '._', '..' ) ), string_version = version.translate( string.maketrans( '._', '__' ) ), extension = extension ) return location @classmethod def patched_boost_test( cls, home ): patch_applied_path = os.path.join( home, "cuppa_test_patch_applied.txt" ) return os.path.exists( patch_applied_path ) @classmethod def apply_patch_if_needed( cls, home ): patch_applied_path = os.path.join( home, "cuppa_test_patch_applied.txt" ) diff_file = "boost_test_patch.diff" if os.path.exists( patch_applied_path ): logger.debug( "[{}] already applied".format( as_info( diff_file ) ) ) return diff_path = os.path.join( os.path.split( __file__ )[0], "boost", diff_file ) command = "patch --batch -p1 --input={}".format( diff_path ) logger.info( "Applying [{}] using [{}] in [{}]".format( as_info( diff_file ), as_info( command ), as_info( home ) ) ) if subprocess.call( shlex.split( command ), cwd=home ) != 0: logger.error( "Could not apply [{}]".format( diff_file ) ) with open( patch_applied_path, "w" ) as patch_applied_file: pass def __init__( self, cuppa_env, platform, location ): self._location = location self.values = {} self.values['name'] = 'boost' self.values['home'] = self._location.local() self._patched_test = self.patched_boost_test( self.values['home'] ) self.values['full_version'], self.values['version'], self.values['numeric_version'] = self.get_boost_version( self.values['home'] ) self.values['revisions'] = self._location.revisions() self.values['include'] = [ self.values['home'] ] self.values['lib_base'] = os.path.join( self.values['home'], 'build' ) self.values['location'] = self.values['home'] if self.values['numeric_version'] > 1.39: self.values['library_mt_tag'] = '' else: # TODO - nonsense code - need to fix self.values['library_mt_tag'] = '-' + platform['toolchain_tag'] + '-mt' self.values['defines'] = [ 'BOOST_PARAMETER_MAX_ARITY=20', 'BOOST_DATE_TIME_POSIX_TIME_STD_CONFIG' ] def name( self ): return self.values['name'] def version( self ): return self.values['version'] def repository( self ): return self._location.repository() def branch( self ): return self._location.branch() def revisions( self ): return self._location.revisions() def local( self ): return self._location.local() def __call__( self, env, toolchain, variant ): env.AppendUnique( SYSINCPATH = self.values['include'] ) env.AppendUnique( CPPDEFINES = self.values['defines'] ) def numeric_version( self ): return self.values['numeric_version'] def full_version( self ): return self.values['full_version'] def lib( self, library ): return 'boost_' + library + self.values['library_mt_tag'] class BoostStaticLibraryMethod(object): def __init__( self, add_dependents=False, build_always=False, verbose_build=False, verbose_config=False ): self._add_dependents = add_dependents self._build_always = build_always self._verbose_build = verbose_build self._verbose_config = verbose_config def __call__( self, env, libraries ): if not self._add_dependents: logger.warn( "BoostStaticLibrary() is deprecated, use BoostStaticLibs() or BoostStaticLib() instead" ) libraries = Flatten( [ libraries ] ) if not 'boost' in env['BUILD_WITH']: env.BuildWith( 'boost' ) Boost = env['dependencies']['boost']( env ) library = BoostLibraryBuilder( Boost, add_dependents = self._add_dependents, verbose_build = self._verbose_build, verbose_config = self._verbose_config )( env, None, None, libraries, 'static' ) if self._build_always: return AlwaysBuild( library ) else: return library class BoostSharedLibraryMethod(object): def __init__( self, add_dependents=False, build_always=False, verbose_build=False, verbose_config=False ): self._add_dependents = add_dependents self._build_always = build_always self._verbose_build = verbose_build self._verbose_config = verbose_config def __call__( self, env, libraries ): if not self._add_dependents: logger.warn( "BoostSharedLibrary() is deprecated, use BoostSharedLibs() or BoostSharedLib() instead" ) libraries = Flatten( [ libraries ] ) if not 'boost' in env['BUILD_WITH']: env.BuildWith( 'boost' ) Boost = env['dependencies']['boost']( env ) for library in libraries: if library.startswith('log'): env.AppendUnique( CPPDEFINES = 'BOOST_LOG_DYN_LINK' ) elif library == 'chrono': env.AppendUnique( CPPDEFINES = 'BOOST_CHRONO_DYN_LINK' ) elif library == 'filesystem': env.AppendUnique( CPPDEFINES = 'BOOST_FILESYSTEM_DYN_LINK' ) elif library == 'date_time': env.AppendUnique( CPPDEFINES = 'BOOST_DATE_TIME_DYN_LINK' ) elif library == 'system': env.AppendUnique( CPPDEFINES = 'BOOST_SYSTEM_DYN_LINK' ) library = BoostLibraryBuilder( Boost, add_dependents = self._add_dependents, verbose_build = self._verbose_build, verbose_config = self._verbose_config )( env, None, None, libraries, 'shared' ) if self._build_always: return AlwaysBuild( library ) else: return library class ProcessBjamBuild(object): def __call__( self, line ): match = re.search( r'\[COMPILE\] ([\S]+)', line ) if match: self.bjam_exe_path = match.expand( r'\1' ) return line def exe_path( self ): return self.bjam_exe_path class BuildBjam(object): def __init__( self, boost ): self._location = boost.local() self._version = boost.numeric_version() def __call__( self, target, source, env ): build_script_path = os.path.join( self._location, 'tools', 'build' ) if self._version < 1.47: build_script_path = os.path.join( build_script_path, 'src', 'v2', 'engine' ) elif self._version > 1.55: build_script_path = os.path.join( build_script_path, 'src', 'engine' ) else: build_script_path = os.path.join( build_script_path, 'v2', 'engine' ) bjam_build_script = './build.sh' if platform.system() == "Windows": bjam_build_script = os.path.join( build_script_path, 'build.bat' ) logger.debug( "Execute [{}] from [{}]".format( bjam_build_script, str(build_script_path) ) ) process_bjam_build = ProcessBjamBuild() try: IncrementalSubProcess.Popen( process_bjam_build, [ bjam_build_script ], cwd=build_script_path ) bjam_exe_path = process_bjam_build.exe_path() if not bjam_exe_path: logger.critical( "Could not determine bjam exe path" ) return 1 bjam_binary_path = os.path.join( build_script_path, bjam_exe_path ) shutil.copy( bjam_binary_path, target[0].path ) except OSError as error: logger.critical( "Error building bjam [{}]".format( str( error.args ) ) ) return 1 return None def toolset_name_from_toolchain( toolchain ): toolset_name = toolchain.toolset_name() if cuppa.build_platform.name() == "Darwin": if toolset_name == "gcc": toolset_name = "darwin" elif toolset_name == "clang": toolset_name = "clang-darwin" return toolset_name def toolset_from_toolchain( toolchain ): toolset_name = toolset_name_from_toolchain( toolchain ) if toolset_name == "clang-darwin": return toolset_name elif toolset_name == "msvc": return toolset_name toolset = toolchain.cxx_version() and toolset_name + "-" + toolchain.cxx_version() or toolset_name return toolset def build_with_library_name( library ): return library == 'log_setup' and 'log' or library def variant_name( variant ): if variant == 'dbg': return 'debug' else: return 'release' def directory_from_abi_flag( abi_flag ): if abi_flag: flag, value = abi_flag.split('=') if value: return value return abi_flag def stage_directory( toolchain, variant, target_arch, abi_flag ): build_base = "build" abi_dir = directory_from_abi_flag( abi_flag ) if abi_dir: build_base += "." + abi_dir return os.path.join( build_base, toolchain.name(), variant, target_arch ) def boost_dependency_order(): return [ 'graph', 'regex', 'coroutine', 'context', 'log_setup', 'log', 'date_time', 'filesystem', 'test', 'timer', 'chrono', 'system', 'thread' ] def boost_dependency_set(): return set( boost_dependency_order() ) def boost_libraries_with_no_dependencies(): return set( [ 'context', 'date_time', 'exception', 'graph_parallel', 'iostreams', 'locale', 'math', 'mpi', 'program_options', 'python', 'random', 'regex', 'serialization', 'signals', 'system', 'thread', 'wave' ] ) def add_dependent_libraries( boost, linktype, libraries ): version = boost.numeric_version() patched_test = boost._patched_test required_libraries = set( libraries ) for library in libraries: if library in boost_libraries_with_no_dependencies(): continue elif library == 'chrono': required_libraries.update( ['system'] ) elif library == 'coroutine': required_libraries.update( ['context', 'system'] ) if version > 1.55: required_libraries.update( ['thread'] ) if linktype == 'shared': required_libraries.update( ['chrono'] ) elif library == 'filesystem': required_libraries.update( ['system'] ) elif library == 'graph': required_libraries.update( ['regex'] ) elif library == 'log': required_libraries.update( ['date_time', 'filesystem', 'system', 'thread'] ) elif library == 'log_setup': required_libraries.update( ['log', 'date_time', 'filesystem', 'system', 'thread'] ) elif library == 'test' and patched_test: required_libraries.update( ['timer, chrono'] ) elif library == 'timer': required_libraries.update( ['chrono'] ) libraries = [] for library in boost_dependency_order(): if library in required_libraries: libraries.append( library ) for library in required_libraries: if library not in boost_dependency_set(): libraries.append( library ) return libraries def lazy_update_library_list( env, emitting, libraries, built_libraries, add_dependents, linktype, boost ): if add_dependents: if not emitting: libraries = set( build_with_library_name(l) for l in add_dependent_libraries( boost, linktype, libraries ) ) else: libraries = add_dependent_libraries( boost, linktype, libraries ) # Use the sconscript_file + build_dir to identify this instance of the environment variant_instance = env['sconscript_file'] + env['build_dir'] if not variant_instance in built_libraries: built_libraries[ variant_instance ] = set( libraries ) else: libraries = [ l for l in libraries if l not in built_libraries[ variant_instance ] ] return libraries class BoostLibraryAction(object): _built_libraries = {} def __init__( self, env, libraries, add_dependents, linktype, boost, verbose_build, verbose_config ): self._env = env self._libraries = lazy_update_library_list( env, False, libraries, self._built_libraries, add_dependents, linktype, boost ) self._location = boost.local() self._version = boost.numeric_version() self._full_version = boost.full_version() self._verbose_build = verbose_build self._verbose_config = verbose_config self._linktype = linktype self._variant = variant_name( self._env['variant'].name() ) self._target_arch = env['target_arch'] self._toolchain = env['toolchain'] self._job_count = env['job_count'] self._parallel = env['parallel'] def _toolset_name_from_toolchain( self, toolchain ): toolset_name = toolchain.toolset_name() if cuppa.build_platform.name() == "Darwin": if toolset_name == "gcc": toolset_name = "darwin" elif toolset_name == "clang": toolset_name = "clang-darwin" return toolset_name def _build_command( self, env, toolchain, libraries, variant, target_arch, linktype, stage_dir ): verbose = "" if self._verbose_build: verbose += " -d+2" if self._verbose_config: verbose += " --debug-configuration" jobs = "1" if self._job_count >= 2 and self._parallel: if len(libraries)>4: jobs = str( self._job_count - 1 ) else: jobs = str( self._job_count/4 + 1 ) with_libraries = "" for library in libraries: with_libraries += " --with-" + library build_flags = "" abi_flag = toolchain.abi_flag(env) if abi_flag: build_flags = 'cxxflags="' + abi_flag + '"' address_model = "" architecture = "" windows_api = "" if toolchain.family() == "cl": if target_arch == "amd64": address_model = "address-model=64" elif target_arch == "arm": address_model = "architecture=arm" if toolchain.target_store() != "desktop": windows_api = "windows-api=" + toolchain.target_store() build_flags += ' define="BOOST_DATE_TIME_POSIX_TIME_STD_CONFIG"' if linktype == 'shared': build_flags += ' define="BOOST_ALL_DYN_LINK"' build_dir = "bin." + directory_from_abi_flag( abi_flag ) bjam = './bjam' if platform.system() == "Windows": # Use full path on Windows bjam = os.path.join( self._location, 'bjam.exe' ) toolset = toolset_from_toolchain( toolchain ) command_line = "{bjam}{verbose} -j {jobs}{with_libraries} toolset={toolset} variant={variant} {address_model} {architecture} {windows_api} {build_flags} link={linktype} --build-dir=.{path_sep}{build_dir} stage --stagedir=.{path_sep}{stage_dir}".format( bjam = bjam, verbose = verbose, jobs = jobs, with_libraries = with_libraries, toolset = toolset, variant = variant, address_model = address_model, architecture = architecture, windows_api = windows_api, build_flags = build_flags, linktype = linktype, build_dir = build_dir, stage_dir = stage_dir, path_sep = os.path.sep ) print command_line if platform.system() == "Windows": command_line = command_line.replace( "\\", "\\\\" ) command_line = command_line.replace( '"', '\\"' ) return shlex.split( command_line ) def __call__( self, target, source, env ): if not self._libraries: return None stage_dir = stage_directory( self._toolchain, self._variant, self._target_arch, self._toolchain.abi_flag(env) ) args = self._build_command( env, self._toolchain, self._libraries, self._variant, self._target_arch, self._linktype, stage_dir ) processor = BjamOutputProcessor( env, self._verbose_build, self._verbose_config, self._toolset_name_from_toolchain( self._toolchain ) ) returncode = IncrementalSubProcess.Popen( processor, args, cwd=self._location ) summary = processor.summary( returncode ) if summary: print summary if returncode: return returncode return None class BjamOutputProcessor(object): def __init__( self, env, verbose_build, verbose_config, toolset_name ): self._verbose_build = verbose_build self._verbose_config = verbose_config self._toolset_filter = toolset_name + '.' self._minimal_output = not self._verbose_build ignore_duplicates = not self._verbose_build self._toolchain_processor = ToolchainProcessor( env['toolchain'], self._minimal_output, ignore_duplicates ) def __call__( self, line ): if line.startswith( self._toolset_filter ): return line elif not self._verbose_config: if( line.startswith( "Performing configuration" ) or line.startswith( "Component configuration" ) or line.startswith( " - " ) ): return None return self._toolchain_processor( line ) def summary( self, returncode ): summary = self._toolchain_processor.summary( returncode ) if returncode and not self._verbose_build: summary += "\nTry running with {} for more details".format( as_emphasised( '--boost-verbose-build' ) ) return summary def library_tag( toolchain, boost_version, variant, threading ): tag = "-{toolset_tag}{toolset_version}{threading}{abi_flag}-{boost_version}" toolset_tag = toolchain.toolset_tag() abi_flag = variant == "debug" and "-d" or "" if cuppa.build_platform.name() == "Windows": if toolset_tag == "gcc": toolset_tag = "mgw" elif toolset_tag == "vc": abi_flag = variant == "debug" and "-gd" or "" return tag.format( toolset_tag = toolset_tag, toolset_version = toolchain.short_version(), threading = threading and "-mt" or "", abi_flag = abi_flag, boost_version = boost_version ) def static_library_name( env, library, toolchain, boost_version, variant, threading ): name = "{prefix}boost_{library}{tag}{suffix}" tag = "" prefix = env.subst('$LIBPREFIX') if cuppa.build_platform.name() == "Windows": tag = library_tag( toolchain, boost_version, variant, threading ) prefix = "lib" return name.format( prefix = prefix, library = library, tag = tag, suffix = env.subst('$LIBSUFFIX') ) def shared_library_name( env, library, toolchain, boost_version, variant, threading ): name = "{prefix}boost_{library}{tag}{suffix}{version}" tag = "" version = "" if cuppa.build_platform.name() == "Windows": tag = library_tag( toolchain, boost_version, variant, threading ) elif cuppa.build_platform.name() == "Linux": version = "." + boost_version return name.format( prefix = env.subst('$SHLIBPREFIX'), library = library, tag = tag, suffix = env.subst('$SHLIBSUFFIX'), version = version ) class BoostLibraryEmitter(object): _built_libraries = {} def __init__( self, env, libraries, add_dependents, linktype, boost ): self._env = env self._libraries = lazy_update_library_list( env, True, libraries, self._built_libraries, add_dependents, linktype, boost ) self._location = boost.local() self._boost = boost self._linktype = linktype self._version = boost.numeric_version() self._full_version = boost.full_version() self._variant = variant_name( self._env['variant'].name() ) self._target_arch = env['target_arch'] self._toolchain = env['toolchain'] self._threading = True def __call__( self, target, source, env ): stage_dir = stage_directory( self._toolchain, self._variant, self._target_arch, self._toolchain.abi_flag(env) ) for library in self._libraries: filename = None if self._linktype == 'static': filename = static_library_name( env, library, self._toolchain, self._boost.version(), self._variant, self._threading ) else: filename = shared_library_name( env, library, self._toolchain, self._boost.version(), self._variant, self._threading ) built_library_path = os.path.join( self._location, stage_dir, 'lib', filename ) node = File( built_library_path ) target.append( node ) return target, source class WriteToolsetConfigJam(object): def _update_project_config_jam( self, project_config_path, current_toolset, toolset_config_line ): config_added = False changed = False temp_path = os.path.splitext( project_config_path )[0] + ".new_jam" if not os.path.exists( project_config_path ): with open( project_config_path, 'w' ) as project_config_jam: project_config_jam.write( "# File created by cuppa:boost\n" ) with open( project_config_path ) as project_config_jam: with open( temp_path, 'w' ) as temp_file: for line in project_config_jam.readlines(): if line.startswith( current_toolset ): if line != toolset_config_line: temp_file.write( toolset_config_line ) changed = True config_added = True else: temp_file.write( line ) if not config_added: temp_file.write( toolset_config_line ) changed = True if changed: os.remove( project_config_path ) shutil.move( temp_path, project_config_path ) else: os.remove( temp_path ) def __call__( self, target, source, env ): path = str(target[0]) if not os.path.exists( path ): toolchain = env['toolchain'] current_toolset = "using {} : {} :".format( toolset_name_from_toolchain( toolchain ), toolchain.cxx_version() ) toolset_config_line = "{} {} ;\n".format( current_toolset, toolchain.binary() ) with open( path, 'w' ) as toolchain_config: print "cuppa: adding toolset config [{}] to dummy toolset config [{}]".format( str(toolset_config_line.strip()), path ) toolchain_config.write( toolset_config_line ) self._update_project_config_jam( os.path.join( os.path.split( path )[0], "project-config.jam" ), current_toolset, toolset_config_line ) return None class BoostLibraryBuilder(object): _library_targets = {} def __init__( self, boost, add_dependents, verbose_build, verbose_config ): self._boost = boost self._add_dependents = add_dependents self._verbose_build = verbose_build self._verbose_config = verbose_config def __call__( self, env, target, source, libraries, linktype ): library_action = BoostLibraryAction ( env, libraries, self._add_dependents, linktype, self._boost, self._verbose_build, self._verbose_config ) library_emitter = BoostLibraryEmitter( env, libraries, self._add_dependents, linktype, self._boost ) env.AppendUnique( BUILDERS = { 'BoostLibraryBuilder' : env.Builder( action=library_action, emitter=library_emitter ) } ) bjam_exe = 'bjam' if platform.system() == "Windows": bjam_exe += ".exe" bjam_target = os.path.join( self._boost.local(), bjam_exe ) bjam = env.Command( bjam_target, [], BuildBjam( self._boost ) ) env.NoClean( bjam ) built_libraries = env.BoostLibraryBuilder( target, source ) built_library_map = {} for library in built_libraries: # Extract the library name from the library filename. # Possibly use regex instead? name = os.path.split( str(library) )[1] name = name.split( "." )[0] name = name.split( "-" )[0] name = "_".join( name.split( "_" )[1:] ) built_library_map[name] = library variant_instance = env['sconscript_file'] + env['build_dir'] if not variant_instance in self._library_targets: self._library_targets[ variant_instance ] = {} required_libraries = add_dependent_libraries( self._boost, linktype, libraries ) for library in required_libraries: if library in self._library_targets[ variant_instance ]: if library not in built_library_map: env.Depends( built_libraries, self._library_targets[ variant_instance ][library] ) else: self._library_targets[ variant_instance ][library] = built_library_map[library] installed_libraries = [] if not built_libraries: return installed_libraries env.Requires( built_libraries, bjam ) if cuppa.build_platform.name() == "Linux": toolset_target = os.path.join( self._boost.local(), env['toolchain'].name() + "._jam" ) toolset_config_jam = env.Command( toolset_target, [], WriteToolsetConfigJam() ) project_config_target = os.path.join( self._boost.local(), "project-config.jam" ) if not os.path.exists( project_config_target ): project_config_jam = env.Requires( project_config_target, env.AlwaysBuild( toolset_config_jam ) ) env.Requires( built_libraries, project_config_jam ) env.Requires( built_libraries, toolset_config_jam ) install_dir = env['abs_build_dir'] library_path = os.path.split( str(built_libraries[0]) )[1] if linktype == 'shared': install_dir = os.path.split( os.path.join( env['abs_final_dir'], library_path ) )[0] for library in required_libraries: installed_libraries.append( env.Install( install_dir, self._library_targets[ variant_instance ][library] ) ) return installed_libraries PKòkRG§Ef$cuppa/dependencies/build_with_qt5.py # Copyright Jamie Allsop 2015-2015 # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) #------------------------------------------------------------------------------- # Qt5 #------------------------------------------------------------------------------- import subprocess import shlex import glob # Cuppa Imports import cuppa.location import cuppa.output_processor import cuppa.build_platform from cuppa.colourise import as_info from cuppa.log import logger import SCons.Script class Qt5Exception(Exception): def __init__(self, value): self.parameter = value def __str__(self): return repr(self.parameter) class build_with_qt5(object): _name = "qt5" _qt5_tool = None @classmethod def add_options( cls, add_option ): pass @classmethod def add_to_env( cls, cuppa_env, add_dependency ): add_dependency( cls._name, cls.create ) @classmethod def create( cls, env ): try: if not cls._qt5_tool: cls._qt5_tool = cls.retrieve_tool( env ) return build_with_qt5( env ) except Qt5Exception: logger.error( "Could not create dependency [{}]. Dependency not available.".format( cls._name ) ) return None @classmethod def retrieve_tool( cls, env ): url = "hg+https://bitbucket.org/dirkbaechle/scons_qt5" try: return cuppa.location.Location( env, url, extra_sub_path = "qt5" ) except cuppa.location.LocationException: logger.warn( "Could not retrieve scons_qt5 from [{}]".format( url ) ) return None def __init__( self, env ): self._version = "5" if cuppa.build_platform.name() in ["Darwin", "Linux"]: if cuppa.output_processor.command_available( "pkg-config" ): if 'QT5DIR' not in env: self._set_qt5_dir( env ) self._version = self._get_qt5_version() elif cuppa.build_platform.name() == "Windows": if 'QT5DIR' not in env: paths = glob.glob( 'C:\\Qt\\5.*\\*' ) if len(paths): paths.sort() env['QT5DIR'] = paths[-1] if 'QT5DIR' not in env: logger.error( "Could not detect QT5 installation" ) raise Qt5Exception( "Could not detect QT5 installation." ) logger.debug( "Q5DIR detected as [{}]".format( as_info( env['QT5DIR'] ) ) ) def _set_qt5_dir( self, env ): command = "pkg-config --cflags Qt5Core" try: cflags = subprocess.check_output( shlex.split( command ), stderr=subprocess.STDOUT ).strip() if cflags: flags = env.ParseFlags( cflags ) if 'CPPPATH' in flags: shortest_path = flags['CPPPATH'][0] for include in flags['CPPPATH']: if len(include) < len(shortest_path): shortest_path = include env['QT5DIR'] = shortest_path except: logger.debug( "In _set_qt5_dir() failed to execute [{}]".format( command ) ) def _get_qt5_version( self ): command = "pkg-config --modversion Qt5Core" try: return subprocess.check_output( shlex.split( command ), stderr=subprocess.STDOUT ).strip() except: logger.debug( "In _get_qt5_version() failed to execute [{}]".format( command ) ) return None def __call__( self, env, toolchain, variant ): SCons.Script.Tool( 'qt5', toolpath=[ self._qt5_tool.base_local() ] )( env ) if cuppa.build_platform.name() in ["Darwin", "Linux"]: env.MergeFlags("-fPIC") def name( self ): return self._name def version( self ): return self._version def repository( self ): return "N/A" def branch( self ): return "N/A" def revisions( self ): return [] PK•c×FC߈4$cuppa/dependencies/boost/__init__.py PKÖ“üFÎHe33.cuppa/dependencies/boost/boost_test_patch.diffdiff -urN a/boost/test/impl/compiler_log_formatter.ipp b/boost/test/impl/compiler_log_formatter.ipp --- a/boost/test/impl/compiler_log_formatter.ipp 2012-12-13 21:32:58.000000000 +0000 +++ b/boost/test/impl/compiler_log_formatter.ipp 2015-06-21 20:57:34.113753873 +0100 @@ -19,8 +19,10 @@ #include #include #include +#include #include #include +#include // Boost #include @@ -52,6 +54,22 @@ : BOOST_TEST_L( "Test setup" ); } +//____________________________________________________________________________// + +void +print_result( std::ostream& ostr, counter_t v, counter_t total, + const_string name, const_string res ) +{ + if( v > 0 ) { + ostr << v << ' ' << name << ( v != 1 ? "s" : "" ); + if( total > 0 ) + ostr << " out of " << total; + + ostr << ' ' << res << ". "; + } +} + + } // local namespace //____________________________________________________________________________// @@ -90,25 +108,57 @@ void compiler_log_formatter::test_unit_start( std::ostream& output, test_unit const& tu ) { + print_prefix( output, tu.p_file_name, tu.p_line_num ); output << "Entering test " << tu.p_type_name << " \"" << tu.p_name << "\"" << std::endl; } //____________________________________________________________________________// void -compiler_log_formatter::test_unit_finish( std::ostream& output, test_unit const& tu, unsigned long elapsed ) +compiler_log_formatter::test_unit_finish( std::ostream& output, test_unit const& tu, elapsed_t elapsed ) { output << "Leaving test " << tu.p_type_name << " \"" << tu.p_name << "\""; - if( elapsed > 0 ) { + if( has_time( elapsed ) ) { output << "; testing time: "; - if( elapsed % 1000 == 0 ) - output << elapsed/1000 << "ms"; - else - output << elapsed << "mks"; + output << to_string( elapsed ); + } + + output << ". "; + + test_results const& tr = results_collector.results( tu.p_id ); + + const_string status; + + if( tr.passed() ) + status = "passed"; + else if( tr.p_skipped ) + status = "skipped"; + else if( tr.p_aborted ) + status = "aborted"; + else + status = "failed"; + + output << "Test " << ( tu.p_type == tut_case ? "case" : "suite" ) << ' ' << status << ". "; + + if( tr.p_skipped ) { + output << "due to " << ( tu.check_dependencies() ? "test aborting\n" : "failed dependency\n" ); + return; } - output << std::endl; + counter_t total_assertions = tr.p_assertions_passed + tr.p_assertions_failed; + counter_t total_tc = tr.p_test_cases_passed + tr.p_test_cases_failed + tr.p_test_cases_skipped; + + if( total_assertions > 0 || total_tc > 0 ) { + print_result( output, tr.p_assertions_passed, total_assertions, "assertion", "passed" ); + print_result( output, tr.p_assertions_failed, total_assertions, "assertion", "failed" ); + print_result( output, tr.p_expected_failures, 0 , "failure" , "expected" ); + print_result( output, tr.p_test_cases_passed, total_tc , "test case", "passed" ); + print_result( output, tr.p_test_cases_failed, total_tc , "test case", "failed" ); + print_result( output, tr.p_test_cases_skipped, total_tc , "test case", "skipped" ); + print_result( output, tr.p_test_cases_aborted, total_tc , "test case", "aborted" ); + } + output << "\n"; } //____________________________________________________________________________// diff -urN a/boost/test/impl/framework.ipp b/boost/test/impl/framework.ipp --- a/boost/test/impl/framework.ipp 2012-12-13 21:32:58.000000000 +0000 +++ b/boost/test/impl/framework.ipp 2015-06-21 20:58:16.588222869 +0100 @@ -32,9 +32,10 @@ #include #include +#include // Boost -#include +// none // STL #include @@ -135,6 +136,16 @@ } } + void reset() + { + clear(); + m_master_test_suite = 0; + m_curr_test_case = INV_TEST_UNIT_ID; + m_next_test_case_id = MIN_TEST_CASE_ID; + m_next_test_suite_id = MIN_TEST_SUITE_ID; + m_test_in_progress = false; + } + void set_tu_id( test_unit& tu, test_unit_id id ) { tu.p_id.value = id; } // test_tree_visitor interface implementation @@ -150,12 +161,13 @@ BOOST_TEST_FOREACH( test_observer*, to, m_observers ) to->test_unit_start( tc ); - boost::timer tc_timer; + timer_t tc_timer; test_unit_id bkup = m_curr_test_case; m_curr_test_case = tc.p_id; unit_test_monitor_t::error_level run_result = unit_test_monitor.execute_and_translate( tc ); - unsigned long elapsed = static_cast( tc_timer.elapsed() * 1e6 ); + tc_timer.stop(); + elapsed_t elapsed = tc_timer.elapsed(); if( unit_test_monitor.is_critical_error( run_result ) ) { BOOST_TEST_FOREACH( test_observer*, to, m_observers ) @@ -189,7 +201,7 @@ void test_suite_finish( test_suite const& ts ) { BOOST_TEST_FOREACH( test_observer*, to, m_observers ) - to->test_unit_finish( ts, 0 ); + to->test_unit_finish( ts, elapsed_t() ); } ////////////////////////////////////////////////////////////////// @@ -233,8 +245,20 @@ namespace framework { void +reset() +{ + reset_observers(); + s_frk_impl().reset(); +} + +void init( init_unit_test_func init_func, int argc, char* argv[] ) { + if( s_frk_impl().m_is_initialized ) + { + reset(); + } + runtime_config::init( argc, argv ); // set the log level and format diff -urN a/boost/test/impl/progress_monitor.ipp b/boost/test/impl/progress_monitor.ipp --- a/boost/test/impl/progress_monitor.ipp 2012-12-13 21:32:58.000000000 +0000 +++ b/boost/test/impl/progress_monitor.ipp 2015-06-21 20:58:35.818982452 +0100 @@ -20,9 +20,10 @@ #include #include +#include +#include // Boost -#include #include #include @@ -72,7 +73,7 @@ //____________________________________________________________________________// void -progress_monitor_t::test_unit_finish( test_unit const& tu, unsigned long ) +progress_monitor_t::test_unit_finish( test_unit const& tu, elapsed_t ) { if( tu.p_type == tut_case ) ++(*s_pm_impl().m_progress_display); diff -urN a/boost/test/impl/results_collector.ipp b/boost/test/impl/results_collector.ipp --- a/boost/test/impl/results_collector.ipp 2012-12-13 21:32:58.000000000 +0000 +++ b/boost/test/impl/results_collector.ipp 2015-06-21 20:58:49.850807030 +0100 @@ -20,6 +20,7 @@ #include #include #include +#include // Boost #include @@ -201,7 +202,7 @@ //____________________________________________________________________________// void -results_collector_t::test_unit_finish( test_unit const& tu, unsigned long ) +results_collector_t::test_unit_finish( test_unit const& tu, elapsed_t ) { if( tu.p_type == tut_suite ) { results_collect_helper ch( s_rc_impl().m_results_store[tu.p_id], tu ); diff -urN a/boost/test/impl/unit_test_log.ipp b/boost/test/impl/unit_test_log.ipp --- a/boost/test/impl/unit_test_log.ipp 2012-12-13 21:32:58.000000000 +0000 +++ b/boost/test/impl/unit_test_log.ipp 2015-06-21 21:06:43.252888689 +0100 @@ -28,6 +28,8 @@ #include #include +#include + // Boost #include #include @@ -178,7 +180,7 @@ //____________________________________________________________________________// void -unit_test_log_t::test_unit_finish( test_unit const& tu, unsigned long elapsed ) +unit_test_log_t::test_unit_finish( test_unit const& tu, elapsed_t elapsed ) { if( s_log_impl().m_threshold_level > log_test_units ) return; diff -urN a/boost/test/impl/unit_test_parameters.ipp b/boost/test/impl/unit_test_parameters.ipp --- a/boost/test/impl/unit_test_parameters.ipp 2012-12-13 21:32:58.000000000 +0000 +++ b/boost/test/impl/unit_test_parameters.ipp 2015-06-21 21:10:23.607133882 +0100 @@ -154,6 +154,27 @@ namespace { // framework parameters and corresponding command-line arguments +#ifdef BOOST_TEST_USE_QUALIFIED_COMMANDLINE_ARGUMENTS +std::string AUTO_START_DBG = "boost.test.auto_start_dbg"; +std::string BREAK_EXEC_PATH = "boost.test.break_exec_path"; +std::string BUILD_INFO = "boost.test.build_info"; +std::string CATCH_SYS_ERRORS = "boost.test.catch_system_errors"; +std::string DETECT_FP_EXCEPT = "boost.test.detect_fp_exceptions"; +std::string DETECT_MEM_LEAKS = "boost.test.detect_memory_leaks"; +std::string LOG_FORMAT = "boost.test.log_format"; +std::string LOG_LEVEL = "boost.test.log_level"; +std::string LOG_SINK = "boost.test.log_sink"; +std::string OUTPUT_FORMAT = "boost.test.output_format"; +std::string RANDOM_SEED = "boost.test.random"; +std::string REPORT_FORMAT = "boost.test.report_format"; +std::string REPORT_LEVEL = "boost.test.report_level"; +std::string REPORT_SINK = "boost.test.report_sink"; +std::string RESULT_CODE = "boost.test.result_code"; +std::string TESTS_TO_RUN = "boost.test.run_test"; +std::string SAVE_TEST_PATTERN = "boost.test.save_pattern"; +std::string SHOW_PROGRESS = "boost.test.show_progress"; +std::string USE_ALT_STACK = "boost.test.use_alt_stack"; +#else std::string AUTO_START_DBG = "auto_start_dbg"; std::string BREAK_EXEC_PATH = "break_exec_path"; std::string BUILD_INFO = "build_info"; @@ -173,6 +194,7 @@ std::string SAVE_TEST_PATTERN = "save_pattern"; std::string SHOW_PROGRESS = "show_progress"; std::string USE_ALT_STACK = "use_alt_stack"; +#endif fixed_mapping parameter_2_env_var( AUTO_START_DBG , "BOOST_TEST_AUTO_START_DBG", @@ -247,6 +269,8 @@ { using namespace cla; + s_cla_parser.reset(); + try { s_cla_parser - cla::ignore_mismatch << cla::dual_name_parameter( AUTO_START_DBG + "|d" ) diff -urN a/boost/test/impl/unit_test_suite.ipp b/boost/test/impl/unit_test_suite.ipp --- a/boost/test/impl/unit_test_suite.ipp 2012-12-13 21:32:58.000000000 +0000 +++ b/boost/test/impl/unit_test_suite.ipp 2015-06-21 22:15:42.079146241 +0100 @@ -23,9 +23,10 @@ #include #include #include +#include // Boost -#include +// none // STL #include @@ -49,9 +50,11 @@ // ************** test_unit ************** // // ************************************************************************** // -test_unit::test_unit( const_string name, test_unit_type t ) +test_unit::test_unit( const_string name, test_unit_type t, const_string fn, std::size_t ln ) : p_type( t ) , p_type_name( t == tut_case ? "case" : "suite" ) +, p_file_name( fn ) +, p_line_num( ln ) , p_id( INV_TEST_UNIT_ID ) , p_name( std::string( name.begin(), name.size() ) ) , p_enabled( true ) @@ -103,8 +106,8 @@ // ************** test_case ************** // // ************************************************************************** // -test_case::test_case( const_string name, callback0<> const& test_func ) -: test_unit( name, static_cast(type) ) +test_case::test_case( const_string name, callback0<> const& test_func, const_string fn, std::size_t ln ) +: test_unit( name, static_cast(type), fn, ln ) , m_test_func( test_func ) { // !! weirdest MSVC BUG; try to remove this statement; looks like it eats first token of next statement @@ -122,8 +125,8 @@ //____________________________________________________________________________// -test_suite::test_suite( const_string name ) -: test_unit( name, static_cast(type) ) +test_suite::test_suite( const_string name, const_string fn, std::size_t ln ) +: test_unit( name, static_cast(type), fn, ln ) { framework::register_test_unit( this ); } @@ -276,7 +279,7 @@ //____________________________________________________________________________// -auto_test_unit_registrar::auto_test_unit_registrar( const_string ts_name ) +auto_test_unit_registrar::auto_test_unit_registrar( const_string ts_name, const_string fn, std::size_t ln ) { test_unit_id id = curr_ts_store().back()->get( ts_name ); @@ -287,7 +290,7 @@ BOOST_ASSERT( ts->p_parent_id == curr_ts_store().back()->p_id ); } else { - ts = new test_suite( ts_name ); + ts = new test_suite( ts_name, fn, ln ); curr_ts_store().back()->add( ts ); } diff -urN a/boost/test/impl/xml_log_formatter.ipp b/boost/test/impl/xml_log_formatter.ipp --- a/boost/test/impl/xml_log_formatter.ipp 2012-12-13 21:32:58.000000000 +0000 +++ b/boost/test/impl/xml_log_formatter.ipp 2015-06-21 21:07:13.416511592 +0100 @@ -23,6 +23,8 @@ #include +#include + // Boost #include @@ -82,17 +84,24 @@ void xml_log_formatter::test_unit_start( std::ostream& ostr, test_unit const& tu ) { - ostr << "<" << tu_type_name( tu ) << " name" << attr_value() << tu.p_name.get() << ">"; + ostr << "<" << tu_type_name( tu ) << " name" << attr_value() << tu.p_name.get(); + + if( !tu.p_file_name.get().empty() ) + { + ostr << BOOST_TEST_L( " file" ) << attr_value() << tu.p_file_name + << BOOST_TEST_L( " line" ) << attr_value() << tu.p_line_num; + } + ostr << ">"; } //____________________________________________________________________________// void -xml_log_formatter::test_unit_finish( std::ostream& ostr, test_unit const& tu, unsigned long elapsed ) +xml_log_formatter::test_unit_finish( std::ostream& ostr, test_unit const& tu, elapsed_t elapsed ) { if( tu.p_type == tut_case ) - ostr << "" << elapsed << ""; - + ostr << to_xml( elapsed ); + ostr << ""; } diff -urN a/boost/test/output/compiler_log_formatter.hpp b/boost/test/output/compiler_log_formatter.hpp --- a/boost/test/output/compiler_log_formatter.hpp 2012-12-13 21:32:58.000000000 +0000 +++ b/boost/test/output/compiler_log_formatter.hpp 2015-06-21 21:04:44.776369850 +0100 @@ -21,6 +21,8 @@ #include +#include + //____________________________________________________________________________// namespace boost { @@ -41,7 +43,7 @@ void log_build_info( std::ostream& ); void test_unit_start( std::ostream&, test_unit const& tu ); - void test_unit_finish( std::ostream&, test_unit const& tu, unsigned long elapsed ); + void test_unit_finish( std::ostream&, test_unit const& tu, elapsed_t elapsed ); void test_unit_skipped( std::ostream&, test_unit const& tu ); void log_exception( std::ostream&, log_checkpoint_data const&, execution_exception const& ex ); diff -urN a/boost/test/output/xml_log_formatter.hpp b/boost/test/output/xml_log_formatter.hpp --- a/boost/test/output/xml_log_formatter.hpp 2012-12-13 21:32:58.000000000 +0000 +++ b/boost/test/output/xml_log_formatter.hpp 2015-06-21 21:04:54.543247747 +0100 @@ -19,6 +19,8 @@ #include #include +#include + // STL #include // std::size_t @@ -44,7 +46,7 @@ void log_build_info( std::ostream& ); void test_unit_start( std::ostream&, test_unit const& tu ); - void test_unit_finish( std::ostream&, test_unit const& tu, unsigned long elapsed ); + void test_unit_finish( std::ostream&, test_unit const& tu, elapsed_t elapsed ); void test_unit_skipped( std::ostream&, test_unit const& tu ); void log_exception( std::ostream&, log_checkpoint_data const&, execution_exception const& ex ); diff -urN a/boost/test/progress_monitor.hpp b/boost/test/progress_monitor.hpp --- a/boost/test/progress_monitor.hpp 2012-12-13 21:32:58.000000000 +0000 +++ b/boost/test/progress_monitor.hpp 2015-06-21 21:02:33.650009155 +0100 @@ -18,6 +18,7 @@ // Boost.Test #include #include +#include // STL #include // for std::ostream& @@ -42,7 +43,7 @@ void test_aborted(); void test_unit_start( test_unit const& ) {} - void test_unit_finish( test_unit const&, unsigned long ); + void test_unit_finish( test_unit const&, elapsed_t ); void test_unit_skipped( test_unit const& ); void test_unit_aborted( test_unit const& ) {} diff -urN a/boost/test/results_collector.hpp b/boost/test/results_collector.hpp --- a/boost/test/results_collector.hpp 2012-12-13 21:32:58.000000000 +0000 +++ b/boost/test/results_collector.hpp 2015-06-21 21:02:52.590772362 +0100 @@ -25,6 +25,8 @@ #include #include +#include + #include //____________________________________________________________________________// @@ -84,7 +86,7 @@ void test_aborted(); void test_unit_start( test_unit const& ); - void test_unit_finish( test_unit const&, unsigned long elapsed ); + void test_unit_finish( test_unit const&, elapsed_t elapsed ); void test_unit_skipped( test_unit const& ); void test_unit_aborted( test_unit const& ); diff -urN a/boost/test/test_observer.hpp b/boost/test/test_observer.hpp --- a/boost/test/test_observer.hpp 2012-12-13 21:32:58.000000000 +0000 +++ b/boost/test/test_observer.hpp 2015-06-21 20:59:39.020192328 +0100 @@ -22,6 +22,8 @@ #include +#include + //____________________________________________________________________________// namespace boost { @@ -40,7 +42,7 @@ virtual void test_aborted() {} virtual void test_unit_start( test_unit const& ) {} - virtual void test_unit_finish( test_unit const&, unsigned long /* elapsed */ ) {} + virtual void test_unit_finish( test_unit const&, elapsed_t /* elapsed */ ) {} virtual void test_unit_skipped( test_unit const& ) {} virtual void test_unit_aborted( test_unit const& ) {} diff -urN a/boost/test/unit_test_log_formatter.hpp b/boost/test/unit_test_log_formatter.hpp --- a/boost/test/unit_test_log_formatter.hpp 2012-12-13 21:32:58.000000000 +0000 +++ b/boost/test/unit_test_log_formatter.hpp 2015-06-21 21:01:49.045566787 +0100 @@ -22,6 +22,8 @@ #include +#include + // STL #include #include // for std::string @@ -95,7 +97,7 @@ virtual void log_build_info( std::ostream& ) = 0; virtual void test_unit_start( std::ostream&, test_unit const& tu ) = 0; - virtual void test_unit_finish( std::ostream&, test_unit const& tu, unsigned long elapsed ) = 0; + virtual void test_unit_finish( std::ostream&, test_unit const& tu, elapsed_t elapsed ) = 0; virtual void test_unit_skipped( std::ostream&, test_unit const& ) = 0; virtual void log_exception( std::ostream& os, log_checkpoint_data const& cd, execution_exception const& ex ) diff -urN a/boost/test/unit_test_log.hpp b/boost/test/unit_test_log.hpp --- a/boost/test/unit_test_log.hpp 2012-12-13 21:32:58.000000000 +0000 +++ b/boost/test/unit_test_log.hpp 2015-06-21 21:01:36.740720619 +0100 @@ -28,6 +28,8 @@ #include #include +#include + // Boost #include @@ -98,7 +100,7 @@ void test_aborted(); void test_unit_start( test_unit const& ); - void test_unit_finish( test_unit const&, unsigned long elapsed ); + void test_unit_finish( test_unit const&, elapsed_t elapsed ); void test_unit_skipped( test_unit const& ); void test_unit_aborted( test_unit const& ); diff -urN a/boost/test/unit_test_suite.hpp b/boost/test/unit_test_suite.hpp --- a/boost/test/unit_test_suite.hpp 2012-12-13 21:32:58.000000000 +0000 +++ b/boost/test/unit_test_suite.hpp 2015-06-21 22:16:12.496765968 +0100 @@ -26,7 +26,7 @@ // ************************************************************************** // #define BOOST_TEST_CASE( test_function ) \ -boost::unit_test::make_test_case( boost::unit_test::callback0<>(test_function), BOOST_TEST_STRINGIZE( test_function ) ) +boost::unit_test::make_test_case( boost::unit_test::callback0<>(test_function), BOOST_TEST_STRINGIZE( test_function ), __FILE__, __LINE__ ) #define BOOST_CLASS_TEST_CASE( test_function, tc_instance ) \ boost::unit_test::make_test_case((test_function), BOOST_TEST_STRINGIZE( test_function ), tc_instance ) @@ -35,7 +35,7 @@ // ************************************************************************** // #define BOOST_TEST_SUITE( testsuite_name ) \ -( new boost::unit_test::test_suite( testsuite_name ) ) +( new boost::unit_test::test_suite( testsuite_name, __FILE__, __LINE__ ) ) // ************************************************************************** // // ************** BOOST_AUTO_TEST_SUITE ************** // @@ -100,7 +100,7 @@ \ BOOST_AUTO_TU_REGISTRAR( test_name )( \ boost::unit_test::make_test_case( \ - &BOOST_AUTO_TC_INVOKER( test_name ), #test_name ), \ + &BOOST_AUTO_TC_INVOKER( test_name ), #test_name, __FILE__, __LINE__ ), \ boost::unit_test::ut_detail::auto_tc_exp_fail< \ BOOST_AUTO_TC_UNIQUE_ID( test_name )>::instance()->value() ); \ \ diff -urN a/boost/test/unit_test_suite_impl.hpp b/boost/test/unit_test_suite_impl.hpp --- a/boost/test/unit_test_suite_impl.hpp 2012-12-13 21:32:58.000000000 +0000 +++ b/boost/test/unit_test_suite_impl.hpp 2015-06-21 22:16:03.388879832 +0100 @@ -54,7 +54,7 @@ enum { type = tut_any }; // Constructor - test_unit( const_string tu_name, test_unit_type t ); + test_unit( const_string tu_name, test_unit_type t, const_string fn, std::size_t ln ); // dependencies management void depends_on( test_unit* tu ); @@ -65,6 +65,8 @@ typedef BOOST_READONLY_PROPERTY(test_unit_id,(test_suite)) parent_id_t; readonly_property p_type; // type for this test unit readonly_property p_type_name; // "case"/"suite" + readonly_property p_file_name; + readonly_property p_line_num; id_t p_id; // unique id for this test unit parent_id_t p_parent_id; // parent test suite id @@ -105,7 +107,7 @@ enum { type = tut_case }; // Constructor - test_case( const_string tc_name, callback0<> const& test_func ); + test_case( const_string tc_name, callback0<> const& test_func, const_string fn, std::size_t ln ); // Access methods callback0<> const& test_func() const { return m_test_func; } @@ -128,7 +130,7 @@ enum { type = tut_suite }; // Constructor - explicit test_suite( const_string ts_name ); + explicit test_suite( const_string ts_name, const_string fn, std::size_t ln ); // test unit list management void add( test_unit* tu, counter_t expected_failures = 0, unsigned timeout = 0 ); @@ -155,7 +157,7 @@ class BOOST_TEST_DECL master_test_suite_t : public test_suite { public: - master_test_suite_t() : test_suite( "Master Test Suite" ) + master_test_suite_t() : test_suite( "Master Test Suite", "", 0 ) , argc( 0 ) , argv( 0 ) {} @@ -250,9 +252,9 @@ //____________________________________________________________________________// inline test_case* -make_test_case( callback0<> const& test_func, const_string tc_name ) +make_test_case( callback0<> const& test_func, const_string tc_name, const_string fn, std::size_t ln ) { - return new test_case( ut_detail::normalize_test_case_name( tc_name ), test_func ); + return new test_case( ut_detail::normalize_test_case_name( tc_name ), test_func, fn, ln ); } //____________________________________________________________________________// @@ -279,7 +281,7 @@ { // Constructors auto_test_unit_registrar( test_case* tc, counter_t exp_fail ); - explicit auto_test_unit_registrar( const_string ts_name ); + explicit auto_test_unit_registrar( const_string ts_name, const_string fn, std::size_t ln ); explicit auto_test_unit_registrar( test_unit_generator const& tc_gen ); explicit auto_test_unit_registrar( int ); diff -urN a/boost/test/utils/progress.hpp b/boost/test/utils/progress.hpp --- a/boost/test/utils/progress.hpp 1970-01-01 01:00:00.000000000 +0100 +++ b/boost/test/utils/progress.hpp 2014-10-17 17:40:31.000000000 +0100 @@ -0,0 +1,107 @@ +// boost progress.hpp header file ------------------------------------------// + +// Copyright Beman Dawes 1994-99. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/libs/timer for documentation. + +// Revision History +// 1 Dec 01 Add leading progress display strings (suggested by Toon Knapen) +// 20 May 01 Introduce several static_casts<> to eliminate warning messages +// (Fixed by Beman, reported by Herve Bronnimann) +// 12 Jan 01 Change to inline implementation to allow use without library +// builds. See docs for more rationale. (Beman Dawes) +// 22 Jul 99 Name changed to .hpp +// 16 Jul 99 Second beta +// 6 Jul 99 Initial boost version + +#ifndef BOOST_TEST_UTILS_PROGRESS_DISPLAY_HPP +#define BOOST_TEST_UTILS_PROGRESS_DISPLAY_HPP + +#include +#include // for ostream, cout, etc +#include // for string + +namespace boost { + +namespace unit_test { + +// progress_display --------------------------------------------------------// + +// progress_display displays an appropriate indication of +// progress at an appropriate place in an appropriate form. + +// NOTE: (Jan 12, 2001) Tried to change unsigned long to boost::uintmax_t, but +// found some compilers couldn't handle the required conversion to double. +// Reverted to unsigned long until the compilers catch up. + +class progress_display : private noncopyable +{ + public: + explicit progress_display( unsigned long expected_count, + std::ostream & os = std::cout, + const std::string & s1 = "\n", //leading strings + const std::string & s2 = "", + const std::string & s3 = "" ) + // os is hint; implementation may ignore, particularly in embedded systems + : m_os(os), m_s1(s1), m_s2(s2), m_s3(s3) { restart(expected_count); } + + void restart( unsigned long expected_count ) + // Effects: display appropriate scale + // Postconditions: count()==0, expected_count()==expected_count + { + _count = _next_tic_count = _tic = 0; + _expected_count = expected_count; + + m_os << m_s1 << "0% 10 20 30 40 50 60 70 80 90 100%\n" + << m_s2 << "|----|----|----|----|----|----|----|----|----|----|" + << std::endl // endl implies flush, which ensures display + << m_s3; + if ( !_expected_count ) _expected_count = 1; // prevent divide by zero + } // restart + + unsigned long operator+=( unsigned long increment ) + // Effects: Display appropriate progress tic if needed. + // Postconditions: count()== original count() + increment + // Returns: count(). + { + if ( (_count += increment) >= _next_tic_count ) { display_tic(); } + return _count; + } + + unsigned long operator++() { return operator+=( 1 ); } + unsigned long count() const { return _count; } + unsigned long expected_count() const { return _expected_count; } + + private: + std::ostream & m_os; // may not be present in all imps + const std::string m_s1; // string is more general, safer than + const std::string m_s2; // const char *, and efficiency or size are + const std::string m_s3; // not issues + + unsigned long _count, _expected_count, _next_tic_count; + unsigned int _tic; + void display_tic() + { + // use of floating point ensures that both large and small counts + // work correctly. static_cast<>() is also used several places + // to suppress spurious compiler warnings. + unsigned int tics_needed = + static_cast( + (static_cast(_count)/_expected_count)*50.0 ); + do { m_os << '*' << std::flush; } while ( ++_tic < tics_needed ); + _next_tic_count = + static_cast((_tic/50.0)*_expected_count); + if ( _count == _expected_count ) { + if ( _tic < 51 ) m_os << '*'; + m_os << std::endl; + } + } // display_tic +}; + +} // namespace unit_test + +} // namespace boost + +#endif // BOOST_TEST_UTILS_PROGRESS_DISPLAY_HPP diff -urN a/boost/test/utils/runtime/cla/argv_traverser.ipp source/boost/test/utils/runtime/cla/argv_traverser.ipp --- a/boost/test/utils/runtime/cla/argv_traverser.ipp 2012-12-13 21:32:58.000000000 +0000 +++ b/boost/test/utils/runtime/cla/argv_traverser.ipp 2015-06-21 21:11:49.038065848 +0100 @@ -49,6 +49,8 @@ BOOST_RT_PARAM_INLINE void argv_traverser::init( int argc, char_type** argv ) { + m_buffer.clear(); + for( int index = 1; index < argc; ++index ) { m_buffer += argv[index]; if( index != argc-1 ) diff -urN a/boost/test/utils/runtime/cla/parser.hpp b/boost/test/utils/runtime/cla/parser.hpp --- a/boost/test/utils/runtime/cla/parser.hpp 2012-12-13 21:32:58.000000000 +0000 +++ b/boost/test/utils/runtime/cla/parser.hpp 2015-06-21 21:11:49.038065848 +0100 @@ -126,6 +126,8 @@ void usage( out_stream& ostr ); void help( out_stream& ostr ); + void reset( cstring program_name = cstring() ); + private: argument const& valid_argument( cstring string_id ) const; diff -urN a/boost/test/utils/runtime/cla/parser.ipp b/boost/test/utils/runtime/cla/parser.ipp --- a/boost/test/utils/runtime/cla/parser.ipp 2012-12-13 21:32:58.000000000 +0000 +++ b/boost/test/utils/runtime/cla/parser.ipp 2015-06-21 21:12:24.184626456 +0100 @@ -249,6 +249,15 @@ //____________________________________________________________________________// +BOOST_RT_PARAM_INLINE void +parser::reset( cstring program_name ) +{ + assign_op( m_program_name, program_name, 0 ); + m_parameters.clear(); +} + +//____________________________________________________________________________// + } // namespace cla } // namespace BOOST_RT_PARAM_NAMESPACE diff -urN a/boost/test/utils/timer.hpp b/boost/test/utils/timer.hpp --- a/boost/test/utils/timer.hpp 1970-01-01 01:00:00.000000000 +0100 +++ b/boost/test/utils/timer.hpp 2015-06-21 17:27:52.000000000 +0100 @@ -0,0 +1,94 @@ +// (C) Copyright Jamie Allsop 2015. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/libs/test for the library home page. +// +// Description : timer and elapsed types +// *************************************************************************** + +#ifndef BOOST_TEST_UTILS_TIMER_HPP +#define BOOST_TEST_UTILS_TIMER_HPP + +#ifdef BOOST_TEST_USE_DEPRECATED_TIMER +#include +#else +#include +#endif +#include + +namespace boost { + +namespace unit_test { + +// ************************************************************************** // +// ************** opaque timer and elapsed types ************** // +// ************************************************************************** // + +#ifdef BOOST_TEST_USE_DEPRECATED_TIMER + +typedef boost::timer timer_t; +typedef unsigned long elapsed_t; + +inline std::string to_string( elapsed_t elapsed ) +{ + std::ostringstream output; + if( elapsed % 1000 == 0 ) + { + output << elapsed/1000 << "ms"; + } + else + { + output << elapsed << "mks"; + } + return output.str(); +} + +inline std::string to_xml( elapsed_t elapsed ) +{ + std::ostringstream output; + output << "" << elapsed << ""; + return output.str(); +} + +inline bool has_time( const elapsed_t& elapsed ) +{ + return elapsed; +} + +#else + +typedef boost::timer::cpu_timer timer_t; +typedef boost::timer::cpu_times elapsed_t; + +inline std::string to_string( elapsed_t elapsed ) +{ + return boost::timer::format( elapsed, 9, "%ws wall, %us user + %ss system = %ts CPU (%p%)" ); +} + +inline std::string to_xml( elapsed_t elapsed ) +{ + std::ostringstream output; + output << "" << ( elapsed.user + elapsed.system ) << "" + << "" << elapsed.wall << "" + << "" << elapsed.user << "" + << "" << elapsed.system << ""; + return output.str(); +} + +inline bool has_time( const elapsed_t& elapsed ) +{ + return elapsed.wall != 0 || elapsed.user != 0 || elapsed.system != 0; +} + +#endif + +//____________________________________________________________________________// + +} // namespace unit_test + +} // namespace boost + +#endif // BOOST_TEST_UTILS_TIMER_HPP + diff -urN a/cuppa_test_patch_applied.txt b/cuppa_test_patch_applied.txt --- a/cuppa_test_patch_applied.txt 1970-01-01 01:00:00.000000000 +0100 +++ b/cuppa_test_patch_applied.txt 2015-06-23 09:55:02.225423584 +0100 @@ -0,0 +1 @@ + diff -urN a/libs/test/build/Jamfile.v2 b/libs/test/build/Jamfile.v2 --- a/libs/test/build/Jamfile.v2 2012-12-13 21:32:58.000000000 +0000 +++ b/libs/test/build/Jamfile.v2 2015-06-21 21:36:46.092350094 +0100 @@ -14,11 +14,22 @@ shared,msvc:-wd4275 msvc:-wd4671 msvc:-wd4673 + #gcc:-std=gnu++0x + clang:-Wno-c99-extensions + clang:-Wno-variadic-macros all + + # adding a dependency on boost/timer as the header are needed, and the junction needs + # to be there in order to build the library. + /boost/timer//boost_timer : usage-requirements BOOST_TEST_NO_AUTO_LINK=1 # Disable Warning about boost::noncopyable not being exported shared,msvc:-wd4275 + + # Adding a dependency on boost/timer as the headers need to be there in case of the + # header-only usage variant + /boost/timer//boost_timer ; PRG_EXEC_MON_SOURCES = PKDûFC߈4cuppa/test_report/__init__.py PK{QG| N« « +cuppa/test_report/generate_bitten_report.py # Copyright Jamie Allsop 2015-2015 # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) #------------------------------------------------------------------------------- # Generate Bitten Report #------------------------------------------------------------------------------- import json import os import itertools import cgi import cuppa.progress class GenerateReportBuilder(object): def __init__( self, final_dir ): self._final_dir = final_dir def emitter( self, target, source, env ): sources = [] targets = [] try: for s in source: if os.path.splitext( str(s) )[1] == ".json": sources.append( str(s) ) target_report = os.path.splitext( str(s) )[0] + "_bitten.xml" targets.append( target_report ) except StopIteration: pass return targets, sources def GenerateBittenReport( self, target, source, env ): for s, t in itertools.izip( source, target ): test_cases = self._read( str(s) ) self._write( str(t), test_cases ) return None def _read( self, json_report_path ): with open( json_report_path, "r" ) as report: test_cases = json.load( report ) return test_cases def _write( self, destination_path, test_cases ): with open( destination_path, "w" ) as report: report.write( '\n' ) for test in test_cases: report.write( ' \n' ) if not 'file' in test or test['file'] == None: test['file'] = "" if not 'line' in test or test['line'] == None: test['line'] = "" if not 'branch_dir' in test or test['branch_dir'] == None: test['branch_dir'] = "" for key, value in test.iteritems(): if key == "cpu_times" or key == "timer": continue report.write( ' <%s>' % key ) if key == 'stdout': value = ( '' + cgi.escape(line) + '
' for line in value ) value = '' else: value = cgi.escape( str( value ) ) report.write( value ) report.write( '\n' % key ) report.write( '
\n' ) report.write( '
\n' ) class GenerateBittenReportMethod(object): def __call__( self, env, source, final_dir=None ): builder = GenerateReportBuilder( final_dir ) env['BUILDERS']['GenerateBittenReport'] = env.Builder( action=builder.GenerateBittenReport, emitter=builder.emitter ) report = env.GenerateBittenReport( [], source ) cuppa.progress.NotifyProgress.add( env, report ) return report @classmethod def add_to_env( cls, cuppa_env ): cuppa_env.add_method( "GenerateBittenReport", cls() ) PKýûFN]cuppa/test_report/cuppa_json.py # Copyright Jamie Allsop 2015-2015 # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) #------------------------------------------------------------------------------- # Json Encoder for Cuppa Types #------------------------------------------------------------------------------- import json import cuppa.timer class Encoder( json.JSONEncoder ): def default(self, obj): if isinstance( obj, cuppa.timer.CpuTimes ): return { "wall_time" : obj.wall, "process_time" : obj.process, "system_time" : obj.system, "user_time" : obj.user } elif isinstance( obj, cuppa.timer.Timer ): return { "wall_time" : obj.elapsed().wall, "process_time" : obj.elapsed().process, "system_time" : obj.elapsed().system, "user_time" : obj.elapsed().user } return json.JSONEncoder.default( self, obj ) def write_report( report_path, test_cases ): with open( report_path, "w" ) as report: json.dump( test_cases, report, sort_keys = True, indent = 4, separators = (',', ': '), cls = Encoder ) PK)“QGîºÐåÂSÂScuppa/toolchains/clang.py # Copyright Jamie Allsop 2014-2015 # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) #------------------------------------------------------------------------------- # CLANG Toolchain #------------------------------------------------------------------------------- import SCons.Script from subprocess import Popen, PIPE import re import shlex import collections import platform from exceptions import Exception import cuppa.build_platform from cuppa.cpp.create_version_file_cpp import CreateVersionHeaderCpp, CreateVersionFileCpp from cuppa.cpp.run_boost_test import RunBoostTestEmitter, RunBoostTest from cuppa.cpp.run_patched_boost_test import RunPatchedBoostTestEmitter, RunPatchedBoostTest from cuppa.cpp.run_process_test import RunProcessTestEmitter, RunProcessTest from cuppa.cpp.run_gcov_coverage import RunGcovCoverageEmitter, RunGcovCoverage from cuppa.output_processor import command_available from cuppa.colourise import as_info, as_notice from cuppa.log import logger class ClangException(Exception): def __init__(self, value): self.parameter = value def __str__(self): return repr(self.parameter) class Clang(object): @classmethod def add_options( cls, add_option ): std_lib_choices = ("libstdc++", "libc++") add_option( '--clang-stdlib', dest='clang-stdlib', choices=std_lib_choices, nargs=1, action='store', help="!Experimental! Specify the standard library Version to build against. Value may be one of {}".format( str(std_lib_choices) ) ) add_option( '--clang-disable-debug-for-auto', dest='clang-disable-debug-for-auto', action='store_true', help="For clang versions before 3.6 this disables the -g flag so auto can compile" ) @classmethod def version_from_command( cls, cxx ): command = "{} --version".format( cxx ) if command_available( command ): reported_version = Popen( shlex.split( command ), stdout=PIPE).communicate()[0] reported_version = 'clang' + re.search( r'based on LLVM (\d)\.(\d)', reported_version ).expand(r'\1\2') return reported_version return None @classmethod def default_version( cls ): if not hasattr( cls, '_default_version' ): cxx = "clang++" command = "{} --version".format( cxx ) reported_version = cls.version_from_command( command ) cxx_version = "" if reported_version: major = str(reported_version[5]) minor = str(reported_version[6]) version = "{}.{}".format( major, minor ) exists = cls.version_from_command( "clang++-{} --version".format( version ) ) if exists: cxx_version = version else: version = "{}".format( major ) exists = cls.version_from_command( "g++-{} --version".format( version ) ) if exists: cxx_version = version cls._default_version = ( reported_version, cxx_version ) return cls._default_version @classmethod def supported_versions( cls ): return [ "clang", "clang37", "clang36", "clang35", "clang34", "clang33", "clang32" ] @classmethod def available_versions( cls ): if not hasattr( cls, '_available_versions' ): cls._available_versions = collections.OrderedDict() for version in cls.supported_versions(): matches = re.match( r'clang(?P(\d))?(?P(\d))?', version ) if not matches: raise ClangException("Clang toolchain [{}] is not recognised as supported!".format( version ) ) major = matches.group('major') minor = matches.group('minor') if not major and not minor: default_ver, default_cxx = cls.default_version() if default_ver: path = cuppa.build_platform.which( "clang++" ) cls._available_versions[version] = { 'cxx_version': default_cxx, 'version': default_ver, 'path': path } cls._available_versions[default_ver] = { 'cxx_version': default_cxx, 'version': default_ver, 'path': path } elif not minor: cxx_version = "-{}".format( major ) cxx = "clang++{}".format( cxx_version ) reported_version = cls.version_from_command( cxx ) if reported_version: cxx_path = cuppa.build_platform.which( cxx ) cls._available_versions[version] = { 'cxx_version': cxx_version, 'version': reported_version, 'path': cxx_path } cls._available_versions[reported_version] = { 'cxx_version': cxx_version, 'version': reported_version, 'path': cxx_path } else: cxx_version = "-{}.{}".format( major, minor ) cxx = "clang++{}".format( cxx_version ) reported_version = cls.version_from_command( cxx ) if reported_version: if version == reported_version: cxx_path = cuppa.build_platform.which( cxx ) cls._available_versions[version] = { 'cxx_version': cxx_version, 'version': reported_version, 'path': cxx_path } else: raise ClangException("Clang toolchain [{}] reporting version as [{}].".format( version, reported_version ) ) return cls._available_versions @classmethod def add_to_env( cls, env, add_toolchain, add_to_supported ): stdlib = None try: stdlib = env.get_option( 'clang-stdlib' ) suppress_debug_for_auto = env.get_option( 'clang-disable-debug-for-auto' ) except: pass for version in cls.supported_versions(): add_to_supported( version ) for version, clang in cls.available_versions().iteritems(): logger.debug( "Adding toolchain [{}] reported as [{}] with cxx_version [clang++{}] at [{}]".format( as_info(version), as_info(clang['version']), as_info(clang['cxx_version']), as_notice(clang['path']) ) ) add_toolchain( version, cls( version, clang['cxx_version'], clang['version'], clang['path'], stdlib, suppress_debug_for_auto ) ) @classmethod def default_variants( cls ): return [ 'dbg', 'rel' ] @classmethod def host_architecture( cls, env ): arch = env.get('HOST_ARCH') if not arch: arch = platform.machine() return arch def _linux_lib_flags( self, env ): self.values['static_link'] = '-Xlinker -Bstatic' self.values['dynamic_link'] = '-Xlinker -Bdynamic' STATICLIBFLAGS = self.values['static_link'] + ' ' + re.search( r'(.*)(,\s*LIBS\s*,)(.*)', env['_LIBFLAGS'] ).expand( r'\1, STATICLIBS,\3' ) DYNAMICLIBFLAGS = self.values['dynamic_link'] + ' ' + re.search( r'(.*)(,\s*LIBS\s*,)(.*)', env['_LIBFLAGS'] ).expand( r'\1, DYNAMICLIBS,\3' ) return STATICLIBFLAGS + ' ' + DYNAMICLIBFLAGS def __init__( self, version, cxx_version, reported_version, cxx_path, stdlib, suppress_debug_for_auto ): self._version = re.search( r'(\d)(\d)', reported_version ).expand(r'\1.\2') self._short_version = self._version.replace( ".", "" ) self._cxx_version = cxx_version.lstrip('-') self._cxx_path = cxx_path if self._cxx_version == cxx_version: self._cxx_version = "" else: self._cxx_version = self._cxx_version self._name = reported_version self._reported_version = reported_version self._suppress_debug_for_auto = suppress_debug_for_auto self.values = {} self._gcov_format = self._gcov_format_version() self._initialise_toolchain( self._reported_version, stdlib ) self.values['CXX'] = "clang++{}".format( self._cxx_version and "-" + self._cxx_version or "" ) self.values['CC'] = "clang{}".format( self._cxx_version and "-" + self._cxx_version or "" ) env = SCons.Script.DefaultEnvironment() if platform.system() == "Windows": SCons.Script.Tool( 'mingw' )( env ) else: SCons.Script.Tool( 'g++' )( env ) self._host_arch = self.host_architecture( env ) SYSINCPATHS = '${_concat(\"' + self.values['sys_inc_prefix'] + '\", SYSINCPATH, \"'+ self.values['sys_inc_suffix'] + '\", __env__, RDirs, TARGET, SOURCE)}' self.values['_CPPINCFLAGS'] = '$( ' + SYSINCPATHS + ' ${_concat(INCPREFIX, INCPATH, INCSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)' if cuppa.build_platform.name() == "Linux": self.values['_LIBFLAGS'] = self._linux_lib_flags( env ) else: self.values['_LIBFLAGS'] = env['_LIBFLAGS'] def __getitem__( self, key ): return self.values.get( key ) def name( self ): return self._name def family( self ): return "clang" def toolset_name( self ): return "clang" def toolset_tag( self ): return "clang" def version( self ): return self._version def short_version( self ): return self._short_version def cxx_version( self ): return self._cxx_version def binary( self ): return self.values['CXX'] def make_env( self, cuppa_env, variant, target_arch ): env = None if not target_arch: target_arch = self._host_arch if platform.system() == "Windows": env = cuppa_env.create_env( tools = ['mingw'] ) env['ENV']['PATH'] = ";".join( [ env['ENV']['PATH'], self._cxx_path ] ) else: env = cuppa_env.create_env( tools = ['g++'] ) env['CXX'] = self.values['CXX'] env['CC'] = self.values['CC'] env['_CPPINCFLAGS'] = self.values['_CPPINCFLAGS'] env['_LIBFLAGS'] = self.values['_LIBFLAGS'] env['SYSINCPATH'] = [] env['INCPATH'] = [ '#.', '.' ] env['LIBPATH'] = [] env['CPPDEFINES'] = [] env['LIBS'] = [] env['STATICLIBS'] = [] env['DYNAMICLIBS'] = self.values['dynamic_libraries'] self.update_variant( env, variant.name() ) return env, target_arch def variants( self ): pass def supports_coverage( self ): return 'coverage_cxx_flags' in self.values def version_file_builder( self, env, namespace, version, location ): return CreateVersionFileCpp( env, namespace, version, location ) def version_file_emitter( self, env, namespace, version, location ): return CreateVersionHeaderCpp( env, namespace, version, location ) def test_runner( self, tester, final_dir, expected ): if not tester or tester =='process': return RunProcessTest( expected ), RunProcessTestEmitter( final_dir ) elif tester=='boost': return RunBoostTest( expected ), RunBoostTestEmitter( final_dir ) elif tester=='patched_boost': return RunPatchedBoostTest( expected ), RunPatchedBoostTestEmitter( final_dir ) def test_runners( self ): return [ 'process', 'boost', 'patched_boost' ] def coverage_runner( self, program, final_dir ): return RunGcovCoverageEmitter( program, final_dir ), RunGcovCoverage( program, final_dir ) def update_variant( self, env, variant ): if variant == 'dbg': env.MergeFlags( self.values['debug_cxx_flags'] + self.values['debug_c_flags'] ) env.AppendUnique( LINKFLAGS = self.values['debug_link_cxx_flags'] ) elif variant == 'rel': env.MergeFlags( self.values['release_cxx_flags'] + self.values['release_c_flags'] ) env.AppendUnique( LINKFLAGS = self.values['release_link_cxx_flags'] ) elif variant == 'cov': env.MergeFlags( self.values['coverage_flags'] ) env.Append( CXXFLAGS = self.values['coverage_cxx_flags'] ) env.AppendUnique( LINKFLAGS = self.values['coverage_link_flags'] ) if env['stdcpp']: env.ReplaceFlags( "-std={}".format(env['stdcpp']) ) def _gcov_format_version( self ): try: gcov_version = Popen(["gcov", "--version"], stdout=PIPE).communicate()[0] gcov_version = re.search( r'(\d)\.(\d)\.(\d)', gcov_version ).expand(r'\g<1>0\g<2>') return gcov_version + '*' except: return None def _initialise_toolchain( self, version, stdlib ): self.values['sys_inc_prefix'] = '-isystem' self.values['sys_inc_suffix'] = '' self.values['static_link'] = '-Xlinker -Bstatic' self.values['dynamic_link'] = '-Xlinker -Bdynamic' CommonCxxFlags = [ '-Wall', '-fexceptions' ] CommonCFlags = [ '-Wall' ] if not re.match( 'clang3[2-5]', version ) or not self._suppress_debug_for_auto: CommonCxxFlags += [ "-g" ] CommonCFlags += [ "-g" ] if stdlib: CommonCxxFlags += [ "-stdlib={}".format(stdlib) ] if re.match( 'clang3[2-3]', version ): CommonCxxFlags += [ '-std=c++11' ] elif re.match( 'clang3[4-7]', version ): CommonCxxFlags += [ '-std=c++1y' ] self.values['debug_cxx_flags'] = CommonCxxFlags + [] self.values['release_cxx_flags'] = CommonCxxFlags + [ '-O3', '-DNDEBUG' ] coverage_options = "--coverage -Xclang -coverage-cfg-checksum -Xclang -coverage-no-function-names-in-data -Xclang -coverage-version={}".format( self._gcov_format ) self.values['coverage_flags'] = CommonCxxFlags self.values['coverage_cxx_flags'] = coverage_options.split() self.values['debug_c_flags'] = CommonCFlags + [] self.values['release_c_flags'] = CommonCFlags + [ '-O3', '-DNDEBUG' ] CommonLinkCxxFlags = [] if cuppa.build_platform.name() == "Linux": CommonLinkCxxFlags = ['-rdynamic', '-Wl,-rpath=.' ] self.values['debug_link_cxx_flags'] = CommonLinkCxxFlags self.values['release_link_cxx_flags'] = CommonLinkCxxFlags self.values['coverage_link_flags'] = CommonLinkCxxFlags + [ '--coverage' ] DynamicLibraries = [] if cuppa.build_platform.name() == "Linux": DynamicLibraries = [ 'pthread', 'rt' ] if stdlib == "libc++": DynamicLibraries += [ 'c++abi', 'c++', 'c++abi', 'm', 'c', 'gcc_s', 'gcc' ] self.values['dynamic_libraries'] = DynamicLibraries def __get_clang_coverage( self, object_dir, source ): # -l = --long-file-names # -p = --preserve-paths # -b = --branch-probabilities return 'gcov -o ' + object_dir \ + ' -l -p -b ' \ + source + ' > ' + source + '_summary.gcov' def abi_flag( self, env ): if env['stdcpp']: return '-std={}'.format(env['stdcpp']) elif re.match( 'clang3[2-3]', self._name ): return '-std=c++11' elif re.match( 'clang3[4-7]', self._name ): return '-std=c++1y' def stdcpp_flag_for( self, standard ): return "-std={}".format( standard ) def error_format( self ): return "{}:{}: {}" @classmethod def output_interpretors( cls ): return [ { 'title' : "Compiler Error", 'regex' : r"([][{}() \t#%$~\w&_:+/\.-]+)(:([0-9]+):([0-9]+))(:[ \t](error:[ \t].*))", 'meaning' : 'error', 'highlight' : set( [ 1, 2 ] ), 'display' : [ 1, 2, 5 ], 'file' : 1, 'line' : None, 'column' : None, }, { 'title' : "Compiler Warning", 'regex' : r"([][{}() \t#%$~\w&_:+/\.-]+)(:([0-9]+):([0-9]+))(:[ \t](warning:[ \t].*))", 'meaning' : 'warning', 'highlight' : set( [ 1, 2 ] ), 'display' : [ 1, 2, 5 ], 'file' : 1, 'line' : None, 'column' : None, }, { 'title' : "Compiler Note", 'regex' : r"([][{}() \t#%$~\w&_:+/\.-]+)(:([0-9]+):([0-9]+))(:[ \t](note:[ \t].*))", 'meaning' : 'message', 'highlight' : set( [ 1, 2 ] ), 'display' : [ 1, 2, 5 ], 'file' : 1, 'line' : None, 'column' : None, }, { 'title' : "Linker Warning", 'regex' : r"([][{}() \t#%$~\w&_:+/\.-]+)(:\(\.text\+[0-9a-fA-FxX]+\))(:[ \t]([Ww]arning:[ \t].*))", 'meaning' : 'warning', 'highlight' : set( [ 1, 2 ] ), 'display' : [ 1, 2, 4 ], 'file' : 1, 'line' : None, 'column' : None, }, { 'title' : "Linker Error", 'regex' : r"([][{}() \t#%$~\w&_:+/\.-]+)(:([0-9]+):[0-9]+)(:[ \t](.*))", 'meaning' : 'error', 'highlight' : set( [ 1, 2 ] ), 'display' : [ 1, 2, 4 ], 'file' : 1, 'line' : None, 'column' : None, }, { 'title' : "Linker Error 2", 'regex' : r"([][{}() \t#%$~\w&_:+/\.-]+\(.text\+[0-9A-Za-z]+\):([ \tA-Za-z0-9_:+/\.-]+))(:[ \t](.*))", 'meaning' : 'error', 'highlight' : set( [ 1 ] ), 'display' : [ 1, 4 ], 'file' : 1, 'line' : None, 'column' : None, }, { 'title' : "Linker Error 3", 'regex' : r"(([][{}() \t#%$~\w&_:+/\.-]+):\(\.text\+[0-9a-fA-FxX]+\))(:(.*))", 'meaning' : 'error', 'highlight' : set( [ 1 ] ), 'display' : [ 1, 4 ], 'file' : 2, 'line' : None, 'column' : None, }, { 'title' : "Linker Error - lib not found", 'regex' : r"(.*(ld.*):[ \t](cannot find.*))", 'meaning' : 'error', 'highlight' : set( [ 1 ] ), 'display' : [ 1 ], 'file' : None, 'line' : None, 'column' : None, }, { 'title' : "Linker Error - cannot open output file", 'regex' : r"(.*(ld.*):[ \t](cannot open output file.*))(:[ \t](.*))", 'meaning' : 'error', 'highlight' : set( [ 1 ] ), 'display' : [ 1, 4 ], 'file' : None, 'line' : None, 'column' : None, }, { 'title' : "Linker Error - unrecognized option", 'regex' : r"(.*(ld.*))(:[ \t](unrecognized option.*))", 'meaning' : 'error', 'highlight' : set( [ 1 ] ), 'display' : [ 1, 3 ], 'file' : None, 'line' : None, 'column' : None, }, { 'title' : "Undefined Reference", 'regex' : r"([][{}() \t#%$~\w&_:+/\.-]+)(:[ \t](undefined reference.*))", 'meaning' : 'error', 'highlight' : set( [ 1 ] ), 'display' : [ 1, 2 ], 'file' : None, 'line' : None, 'column' : None, }, { 'title' : "No such File or Directory", 'regex' : r"(.*:(.*))(:[ \t](No such file or directory.*))", 'meaning' : 'error', 'highlight' : set( [ 1 ] ), 'display' : [ 1, 3 ], 'file' : None, 'line' : None, 'column' : None, }, { 'title' : "Compiler Error", 'regex' : r"(error:)([ \t].*)", 'meaning' : 'error', 'highlight' : set( [ 1 ] ), 'display' : [ 1, 2 ], 'file' : None, 'line' : None, 'column' : None, }, ] PK-¹ƒF2¨Ô**cuppa/toolchains/__init__.py # Copyright Jamie Allsop 2011-2015 # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) import cuppa.modules __all__ = cuppa.modules.registration.get_module_list( __file__ ) PKòkRG]ðmã + +cuppa/toolchains/cl.py # Copyright Jamie Allsop 2014-2015 # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) #------------------------------------------------------------------------------- # CL Toolchain #------------------------------------------------------------------------------- import os import collections import platform from exceptions import Exception import SCons.Script from SCons.Tool.MSCommon.vc import cached_get_installed_vcs, _VCVER, get_default_version from cuppa.cpp.create_version_file_cpp import CreateVersionHeaderCpp, CreateVersionFileCpp from cuppa.cpp.run_boost_test import RunBoostTestEmitter, RunBoostTest from cuppa.cpp.run_patched_boost_test import RunPatchedBoostTestEmitter, RunPatchedBoostTest from cuppa.cpp.run_process_test import RunProcessTestEmitter, RunProcessTest class ClException(Exception): def __init__(self, value): self.parameter = value def __str__(self): return repr(self.parameter) class Cl(object): _supported_architectures = { "amd64" : "amd64", "emt64" : "amd64", "i386" : "x86", "i486" : "x86", "i586" : "x86", "i686" : "x86", "ia64" : "ia64", "itanium" : "ia64", "x86" : "x86", "x86_64" : "amd64", "x86_amd64" : "x86_amd64", "arm" : "arm" } _target_architectures = { ("x86", "x86") : "x86", ("x86", "amd64") : "x86_amd64", ("x86", "x86_amd64") : "x86_amd64", ("amd64", "x86_amd64") : "x86_amd64", ("amd64", "amd64") : "amd64", ("amd64", "x86") : "x86", ("x86", "ia64") : "x86_ia64", ("x86", "arm") : "x86_arm", ("amd64", "arm") : "amd64_arm", ("arm", "arm") : "arm", } @classmethod def default_version( cls, env ): if not hasattr( cls, '_default_version' ): cls._default_version = get_default_version( env ) return cls._default_version @classmethod def vc_version( cls, long_version ): version = long_version.replace( ".", "" ) version = version.replace( "Exp", "e" ) return 'vc' + version @classmethod def supported_versions( cls ): supported = [ "vc" ] for version in reversed(_VCVER): supported.append( cls.vc_version( version ) ) return supported @classmethod def available_versions( cls, env ): if not hasattr( cls, '_available_versions' ): cls._available_versions = collections.OrderedDict() installed_versions = cached_get_installed_vcs() if installed_versions: default = cls.default_version( env ) cls._available_versions['vc'] = { 'vc_version': cls.vc_version( default ), 'version': default, } for version in installed_versions: vc_version = cls.vc_version( version ) cls._available_versions[vc_version] = { 'vc_version': vc_version, 'version': version, } return cls._available_versions @classmethod def add_options( cls, add_option ): pass @classmethod def add_to_env( cls, env, add_toolchain, add_to_supported ): for version in cls.supported_versions(): add_to_supported( version ) for name, vc in cls.available_versions( env ).iteritems(): add_toolchain( name, cls( name, vc['vc_version'], vc['version'] ) ) @classmethod def default_variants( cls ): return [ 'dbg', 'rel' ] @classmethod def host_architecture( cls, env ): arch = env.get('HOST_ARCH') if not arch: arch = platform.machine() if not arch: arch = os.environ.get( 'PROCESSOR_ARCHITECTURE', '' ) try: arch = cls._supported_architectures[ arch.lower() ] except KeyError: pass return arch def __init__( self, name, vc_version, version ): self.values = {} env = SCons.Script.DefaultEnvironment() SCons.Script.Tool( 'msvc' )( env ) self._host_arch = self.host_architecture( env ) self._name = vc_version self._version = vc_version self._long_version = version self._short_version = vc_version[2:].replace( "e", "" ) self._target_store = "desktop" self.values['sys_inc_prefix'] = env['INCPREFIX'] self.values['sys_inc_suffix'] = env['INCSUFFIX'] SYSINCPATHS = '${_concat(\"' + self.values['sys_inc_prefix'] + '\", SYSINCPATH, \"'+ self.values['sys_inc_suffix'] + '\", __env__, RDirs, TARGET, SOURCE)}' self.values['_CPPINCFLAGS'] = '$( ' + SYSINCPATHS + ' ${_concat(INCPREFIX, INCPATH, INCSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)' self._initialise_toolchain() def __getitem__( self, key ): return self.values.get( key ) def name( self ): return self._name def family( self ): return "cl" def toolset_name( self ): return "msvc" def toolset_tag( self ): return "vc" def version( self ): return self._version def short_version( self ): return self._short_version def cxx_version( self ): return self._version def binary( self ): return self.values['CXX'] def target_store( self ): return self._target_store def make_env( self, cuppa_env, variant, target_arch ): if not target_arch: target_arch = self._host_arch else: target_arch = target_arch.lower() if target_arch not in self._supported_architectures: return None, target_arch else: target_arch = self._supported_architectures[ target_arch ] target_arch = self._target_architectures[ ( self._host_arch, target_arch ) ] env = cuppa_env.create_env( tools = ['msvc'], MSVC_VERSION = self._long_version, TARGET_ARCH = target_arch, ) env['_CPPINCFLAGS'] = self.values['_CPPINCFLAGS'] env['INCPATH'] = [ '#.', '.' ] env['CPPDEFINES'] = [] env['LIBS'] = [] env['STATICLIBS'] = [] self.update_variant( env, variant.name() ) return env, target_arch def variants( self ): pass def supports_coverage( self ): return False def version_file_builder( self, env, namespace, version, location ): return CreateVersionFileCpp( env, namespace, version, location ) def version_file_emitter( self, env, namespace, version, location ): return CreateVersionHeaderCpp( env, namespace, version, location ) def test_runner( self, tester, final_dir, expected ): if not tester or tester =='process': return RunProcessTest( expected ), RunProcessTestEmitter( final_dir ) elif tester=='boost': return RunBoostTest( expected ), RunBoostTestEmitter( final_dir ) elif tester=='patched_boost': return RunPatchedBoostTest( expected ), RunPatchedBoostTestEmitter( final_dir ) def test_runners( self ): return [ 'process', 'boost', 'patched_boost' ] def coverage_runner( self, program, final_dir ): return None def update_variant( self, env, variant ): if variant == 'dbg': env.AppendUnique( CXXFLAGS = self.values['dbg_cxx_flags'] ) env.AppendUnique( LINKFLAGS = self.values['dbg_link_flags'] ) elif variant == 'rel': env.AppendUnique( CXXFLAGS = self.values['rel_cxx_flags'] ) env.AppendUnique( LINKFLAGS = self.values['rel_link_flags'] ) elif variant == 'cov': pass def _initialise_toolchain( self ): CommonCxxFlags = [ '-W4', '-EHac', '-nologo', '-GR' ] self.values['dbg_cxx_flags'] = CommonCxxFlags + [ '-Zi', '-MDd' ] self.values['rel_cxx_flags'] = CommonCxxFlags + [ '-Ox', '-MD' ] CommonLinkFlags = [ '-OPT:REF'] self.values['dbg_link_flags'] = CommonLinkFlags + [] self.values['rel_link_flags'] = CommonLinkFlags + [] def abi_flag( self, library ): return "" def stdcpp_flag_for( self, standard ): return "" def error_format( self ): return "{}({}): error: {}" @classmethod def output_interpretors( cls ): return [ { 'title' : "Compiler Error", 'regex' : r"([][{}() \t#%$~\w&_:+\\/\.-]+)([(]([0-9]+)[)])([ ]?:[ ]error [A-Z0-9]+:.*)", 'meaning' : 'error', 'highlight' : set( [ 1, 2 ] ), 'display' : [ 1, 2, 4 ], 'file' : 1, 'line' : None, 'column' : None, }, { 'title' : "Compiler Warning", 'regex' : r"([][{}() \t#%$~\w&_:+\\/\.-]+)([(]([0-9]+)[)])([ ]?:[ ]warning [A-Z0-9]+:.*)", 'meaning' : 'warning', 'highlight' : set( [ 1, 2 ] ), 'display' : [ 1, 2, 4 ], 'file' : 1, 'line' : None, 'column' : None, }, { 'title' : "Compiler Note", 'regex' : r"([][{}() \t#%$~\w&_:+\\/\.-]+)([(]([0-9]+)[)])([ ]?:[ ]note:.*)", 'meaning' : 'message', 'highlight' : set( [ 1, 2 ] ), 'display' : [ 1, 2, 4 ], 'file' : 1, 'line' : None, 'column' : None, }, { 'title' : "Linker Fatal Error", 'regex' : r"([][{}() \t#%$~\w&_:+\\/\.-]+)([ ]?:[ ]fatal error LNK[0-9]+:)(.*)", 'meaning' : 'error', 'highlight' : set( [ 1, 2 ] ), 'display' : [ 1, 2, 3 ], 'file' : 1, 'line' : None, 'column' : None, }, { 'title' : "Linker Error", 'regex' : r"([][{}() \t#%$~\w&_:+\\/\.-]+)([ ]?:[ ]error LNK[0-9]+:)(.*)", 'meaning' : 'error', 'highlight' : set( [ 1, 2 ] ), 'display' : [ 1, 2, 3 ], 'file' : 1, 'line' : None, 'column' : None, }, { 'title' : "Linker Warning", 'regex' : r"([][{}() \t#%$~\w&_:+\\/\.-]+)([ ]?:[ ]warning LNK[0-9]+:)(.*)", 'meaning' : 'warning', 'highlight' : set( [ 1, 2 ] ), 'display' : [ 1, 2, 3 ], 'file' : 1, 'line' : None, 'column' : None, }, ] PK{QGuTô8c8ccuppa/toolchains/gcc.py # Copyright Jamie Allsop 2011-2015 # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) #------------------------------------------------------------------------------- # GCC Toolchain #------------------------------------------------------------------------------- import SCons.Script from subprocess import Popen, PIPE import re import shlex import collections import platform from exceptions import Exception from cuppa.cpp.create_version_file_cpp import CreateVersionHeaderCpp, CreateVersionFileCpp from cuppa.cpp.run_boost_test import RunBoostTestEmitter, RunBoostTest from cuppa.cpp.run_patched_boost_test import RunPatchedBoostTestEmitter, RunPatchedBoostTest from cuppa.cpp.run_process_test import RunProcessTestEmitter, RunProcessTest from cuppa.cpp.run_gcov_coverage import RunGcovCoverageEmitter, RunGcovCoverage from cuppa.output_processor import command_available from cuppa.log import logger from cuppa.colourise import as_notice, as_info import cuppa.build_platform class GccException(Exception): def __init__(self, value): self.parameter = value def __str__(self): return repr(self.parameter) class Gcc(object): @classmethod def supported_versions( cls ): return [ "gcc", "gcc5", "gcc52", "gcc51", "gcc4", "gcc49", "gcc48", "gcc47", "gcc46", "gcc45", "gcc44", "gcc43", "gcc42", "gcc41", "gcc40", "gcc34" ] @classmethod def version_from_command( cls, cxx ): command = "{} --version".format( cxx ) if command_available( command ): reported_version = Popen( shlex.split( command ), stdout=PIPE).communicate()[0] reported_version = 'gcc' + re.search( r'(\d)\.(\d)', reported_version ).expand(r'\1\2') return reported_version return None @classmethod def default_version( cls ): if not hasattr( cls, '_default_version' ): cxx = "g++" command = "{} --version".format( cxx ) reported_version = cls.version_from_command( command ) cxx_version = "" if reported_version: major = str(reported_version[3]) minor = str(reported_version[4]) version = "{}.{}".format( major, minor ) exists = cls.version_from_command( "g++-{} --version".format( version ) ) if exists: cxx_version = version else: version = "{}".format( major ) exists = cls.version_from_command( "g++-{} --version".format( version ) ) if exists: cxx_version = version cls._default_version = ( reported_version, cxx_version ) return cls._default_version @classmethod def available_versions( cls ): if not hasattr( cls, '_available_versions' ): cls._available_versions = collections.OrderedDict() for version in cls.supported_versions(): matches = re.match( r'gcc(?P(\d))?(?P(\d))?', version ) if not matches: raise GccException("GCC toolchain [{}] is not recognised as supported!.".format( version ) ) major = matches.group('major') minor = matches.group('minor') if not major and not minor: default_ver, default_cxx = cls.default_version() if default_ver: path = cuppa.build_platform.which( "g++" ) cls._available_versions[version] = { 'cxx_version': default_cxx, 'version': default_ver, 'path': path } cls._available_versions[default_ver] = { 'cxx_version': default_cxx, 'version': default_ver, 'path': path } elif not minor: cxx_version = "-{}".format( major ) cxx = "g++{}".format( cxx_version ) reported_version = cls.version_from_command( cxx ) if reported_version: cxx_path = cuppa.build_platform.which( cxx ) cls._available_versions[version] = { 'cxx_version': cxx_version, 'version': reported_version, 'path': cxx_path } cls._available_versions[reported_version] = { 'cxx_version': cxx_version, 'version': reported_version, 'path': cxx_path } else: cxx_version = "-{}.{}".format( major, minor ) cxx = "g++{}".format( cxx_version ) reported_version = cls.version_from_command( cxx ) if reported_version: if version == reported_version: cxx_path = cuppa.build_platform.which( cxx ) cls._available_versions[version] = { 'cxx_version': cxx_version, 'version': reported_version, 'path': cxx_path } else: raise GccException("GCC toolchain [{}] reporting version as [{}].".format( version, reported_version ) ) return cls._available_versions @classmethod def add_options( cls, add_option ): pass @classmethod def add_to_env( cls, env, add_toolchain, add_to_supported ): for version in cls.supported_versions(): add_to_supported( version ) for version, gcc in cls.available_versions().iteritems(): logger.debug( "Adding toolchain [{}] reported as [{}] with cxx_version [g++{}] at [{}]" .format( as_info(version), as_info(gcc['version']), as_info(gcc['cxx_version']), as_notice(gcc['path']) ) ) add_toolchain( version, cls( version, gcc['cxx_version'], gcc['version'], gcc['path'] ) ) @classmethod def default_variants( cls ): return [ 'dbg', 'rel' ] @classmethod def host_architecture( cls, env ): arch = env.get('HOST_ARCH') if not arch: arch = platform.machine() return arch def _linux_lib_flags( self, env ): self.values['static_link'] = '-Xlinker -Bstatic' self.values['dynamic_link'] = '-Xlinker -Bdynamic' STATICLIBFLAGS = self.values['static_link'] + ' ' + re.search( r'(.*)(,\s*LIBS\s*,)(.*)', env['_LIBFLAGS'] ).expand( r'\1, STATICLIBS,\3' ) DYNAMICLIBFLAGS = self.values['dynamic_link'] + ' ' + re.search( r'(.*)(,\s*LIBS\s*,)(.*)', env['_LIBFLAGS'] ).expand( r'\1, DYNAMICLIBS,\3' ) return STATICLIBFLAGS + ' ' + DYNAMICLIBFLAGS def __init__( self, available_version, cxx_version, reported_version, cxx_path ): self.values = {} self._version = re.search( r'(\d)(\d)', reported_version ).expand(r'\1.\2') self._short_version = self._version.replace( ".", "" ) self._cxx_version = cxx_version.lstrip('-') self._cxx_path = cxx_path if self._cxx_version == cxx_version: self._cxx_version = "" else: self._cxx_version = self._cxx_version self._name = reported_version self._reported_version = reported_version self._initialise_toolchain( self._reported_version ) self.values['CXX'] = "g++{}".format( self._cxx_version and "-" + self._cxx_version or "" ) self.values['CC'] = "gcc{}".format( self._cxx_version and "-" + self._cxx_version or "" ) env = SCons.Script.DefaultEnvironment() if platform.system() == "Windows": SCons.Script.Tool( 'mingw' )( env ) else: SCons.Script.Tool( 'g++' )( env ) self._host_arch = self.host_architecture( env ) SYSINCPATHS = '${_concat(\"' + self.values['sys_inc_prefix'] + '\", SYSINCPATH, \"'+ self.values['sys_inc_suffix'] + '\", __env__, RDirs, TARGET, SOURCE)}' self.values['_CPPINCFLAGS'] = '$( ' + SYSINCPATHS + ' ${_concat(INCPREFIX, INCPATH, INCSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)' if cuppa.build_platform.name() == "Linux": self.values['_LIBFLAGS'] = self._linux_lib_flags( env ) else: self.values['_LIBFLAGS'] = env['_LIBFLAGS'] def __getitem__( self, key ): return self.values.get( key ) def name( self ): return self._name def family( self ): return "gcc" def toolset_name( self ): return "gcc" def toolset_tag( self ): return "gcc" def short_version( self ): return self._short_version def version( self ): return self._version def cxx_version( self ): return self._cxx_version def binary( self ): return self.values['CXX'] def make_env( self, cuppa_env, variant, target_arch ): env = None if not target_arch: target_arch = self._host_arch if platform.system() == "Windows": env = cuppa_env.create_env( tools = ['mingw'] ) env['ENV']['PATH'] = ";".join( [ env['ENV']['PATH'], self._cxx_path ] ) else: env = cuppa_env.create_env( tools = ['g++'] ) env['CXX'] = self.values['CXX'] env['CC'] = self.values['CC'] env['_CPPINCFLAGS'] = self.values['_CPPINCFLAGS'] env['_LIBFLAGS'] = self.values['_LIBFLAGS'] env['CCFLAGS'] = [] env['SYSINCPATH'] = [] env['INCPATH'] = [ '#.', '.' ] env['LIBPATH'] = [] env['CPPDEFINES'] = [] env['LIBS'] = [] env['STATICLIBS'] = [] env['DYNAMICLIBS'] = self.values['dynamic_libraries'] self.update_variant( env, variant.name() ) return env, target_arch def variants( self ): pass def supports_coverage( self ): return 'coverage_cxx_flags' in self.values def version_file_builder( self, env, namespace, version, location ): return CreateVersionFileCpp( env, namespace, version, location ) def version_file_emitter( self, env, namespace, version, location ): return CreateVersionHeaderCpp( env, namespace, version, location ) def test_runner( self, tester, final_dir, expected ): if not tester or tester =='process': return RunProcessTest( expected ), RunProcessTestEmitter( final_dir ) elif tester=='boost': return RunBoostTest( expected ), RunBoostTestEmitter( final_dir ) elif tester=='patched_boost': return RunPatchedBoostTest( expected ), RunPatchedBoostTestEmitter( final_dir ) def test_runners( self ): return [ 'process', 'boost', 'patched_boost' ] def coverage_runner( self, program, final_dir ): return RunGcovCoverageEmitter( program, final_dir ), RunGcovCoverage( program, final_dir ) def update_variant( self, env, variant ): if variant == 'dbg': env.MergeFlags( self.values['debug_cxx_flags'] + self.values['debug_c_flags'] + self.values['debug_link_cxx_flags'] ) elif variant == 'rel': env.MergeFlags( self.values['release_cxx_flags'] + self.values['release_c_flags'] + self.values['release_link_cxx_flags'] ) elif variant == 'cov': env.MergeFlags( self.values['coverage_cxx_flags'] + self.values['coverage_c_flags'] ) env.Append( CXXFLAGS = self.values['coverage_cxx_flags'] ) env.AppendUnique( LINKFLAGS = self.values['coverage_link_cxx_flags'] ) if env['stdcpp']: env.ReplaceFlags( "-std={}".format(env['stdcpp']) ) def _initialise_toolchain( self, toolchain ): if toolchain == 'gcc34': self.values['sys_inc_prefix'] = '-I' else: self.values['sys_inc_prefix'] = '-isystem' self.values['sys_inc_suffix'] = '' CommonCxxFlags = [ '-Wall', '-fexceptions', '-g' ] CommonCFlags = [ '-Wall', '-g' ] if re.match( 'gcc4[3-6]', toolchain ): CommonCxxFlags += [ '-std=c++0x' ] elif re.match( 'gcc47', toolchain ): CommonCxxFlags += [ '-std=c++11' ] elif re.match( 'gcc4[8-9]', toolchain ): CommonCxxFlags += [ '-std=c++1y' ] elif re.match( 'gcc5[0-2]', toolchain ): CommonCxxFlags += [ '-std=c++1y' ] self.values['debug_cxx_flags'] = CommonCxxFlags + [] self.values['release_cxx_flags'] = CommonCxxFlags + [ '-O3', '-DNDEBUG' ] self.values['coverage_cxx_flags'] = CommonCxxFlags + [ '--coverage' ] self.values['debug_c_flags'] = CommonCFlags + [] self.values['release_c_flags'] = CommonCFlags + [ '-O3', '-DNDEBUG' ] self.values['coverage_c_flags'] = CommonCFlags + [ '--coverage' ] CommonLinkCxxFlags = [] if cuppa.build_platform.name() == "Linux": CommonLinkCxxFlags = ['-rdynamic', '-Wl,-rpath=.' ] self.values['debug_link_cxx_flags'] = CommonLinkCxxFlags self.values['release_link_cxx_flags'] = CommonLinkCxxFlags self.values['coverage_link_cxx_flags'] = CommonLinkCxxFlags + [ '--coverage' ] DynamicLibraries = [] if cuppa.build_platform.name() == "Linux": DynamicLibraries = [ 'pthread', 'rt' ] self.values['dynamic_libraries'] = DynamicLibraries def __get_gcc_coverage( self, object_dir, source ): # -l = --long-file-names # -p = --preserve-paths # -b = --branch-probabilities return 'gcov -o ' + object_dir \ + ' -l -p -b ' \ + source + ' > ' + source + '_summary.gcov' def abi_flag( self, env ): if env['stdcpp']: return '-std={}'.format(env['stdcpp']) elif re.match( 'gcc4[3-6]', self._reported_version ): return '-std=c++0x' elif re.match( 'gcc47', self._reported_version ): return '-std=c++11' elif re.match( 'gcc4[8-9]', self._reported_version ): return '-std=c++1y' elif re.match( 'gcc5[0-2]', self._reported_version ): return '-std=c++1y' def stdcpp_flag_for( self, standard ): return "-std={}".format( standard ) def error_format( self ): return "{}:{}: {}" @classmethod def output_interpretors( cls ): return [ { 'title' : "Fatal Error", 'regex' : r"(FATAL:[ \t]*(.*))", 'meaning' : 'error', 'highlight' : set( [ 1 ] ), 'display' : [ 1 ], 'file' : None, 'line' : None, 'column' : None, }, { 'title' : "In File Included From", 'regex' : r"(In file included\s+|\s+)(from\s+)([][{}() \t#%$~\w&_:+/\.-]+)(:([0-9]+)(:[0-9]+)?)([,:])", 'meaning' : 'message', 'highlight' : set( [ 1, 3, 4 ] ), 'display' : [ 1, 2, 3, 4, 7 ], 'file' : 3, 'line' : None, 'column' : None, }, { 'title' : "In Function Info", 'regex' : r"([][{}() \t#%$~\w&_:+/\.-]+)(:[ \t]+([iI]n ([cC]lass|[cC]onstructor|[dD]estructor|[fF]unction|[mM]ember [fF]unction|[sS]tatic [fF]unction|[sS]tatic [mM]ember [fF]unction).*))", 'meaning' : 'message', 'highlight' : set( [ 1 ] ), 'display' : [ 1, 2 ], 'file' : 1, 'line' : None, 'column' : None, }, { 'title' : "Skipping Instantiation Contexts 2", 'regex' : r"([][{}() \t#%$~\w&_:+/\.-]+)(:([0-9]+):[0-9]+)(:[ \t]+(\[[ \t]+[Ss]kipping [0-9]+ instantiation contexts[, \t]+.*\]))", 'meaning' : 'message', 'highlight' : set( [ 1, 2 ] ), 'display' : [ 1, 2, 4 ], 'file' : 1, 'line' : None, 'column' : None, }, { 'title' : "Skipping Instantiation Contexts", 'regex' : r"([][{}() \t#%$~\w&_:+/\.-]+)(:([0-9]+))(:[ \t]+(\[[ \t]+[Ss]kipping [0-9]+ instantiation contexts[ \t]+\]))", 'meaning' : 'message', 'highlight' : set( [ 1, 2 ] ), 'display' : [ 1, 2, 4 ], 'file' : 2, 'line' : None, 'column' : None, }, { 'title' : "Instantiated From", 'regex' : r"([][{}() \t#%$~\w&_:+/\.-]+)(:([0-9]+))(:[ \t]+([iI]nstantiated from .*))", 'meaning' : 'message', 'highlight' : set( [ 1, 2] ), 'display' : [ 1, 2, 4 ], 'file' : 1, 'line' : None, 'column' : None, }, { 'title' : "Instantiation of", 'regex' : r"([][{}() \t#%$~\w&_:+/\.-]+)(:[ \t]+(In instantiation of .*))", 'meaning' : 'message', 'highlight' : set( [ 1 ] ), 'display' : [ 1, 2 ], 'file' : 1, 'line' : None, 'column' : None, }, { 'title' : "Required From", 'regex' : r"([][{}() \t#%$~\w&_:+/\.-]+)(:([0-9]+):[0-9]+)(:[ \t]+required from .*)", 'meaning' : 'message', 'highlight' : set( [ 1, 2 ] ), 'display' : [ 1, 2, 4 ], 'file' : 1, 'line' : None, 'column' : None, }, { 'title' : "Compiler Warning 2", 'regex' : r"([][{}() \t#%$~\w&_:+/\.-]+)(:([0-9]+):([0-9]+))(:[ \t]([Ww]arning:[ \t].*))", 'meaning' : 'warning', 'highlight' : set( [ 1, 2 ] ), 'display' : [ 1, 2, 5 ], 'file' : 1, 'line' : None, 'column' : None, }, { 'title' : "Compiler Note 2", 'regex' : r"([][{}() \t#%$~\w&_:+/\.-]+)(:([0-9]+):[0-9]+)(:[ \t]([Nn]ote:[ \t].*))", 'meaning' : 'message', 'highlight' : set( [ 1, 2 ] ), 'display' : [ 1, 2, 4 ], 'file' : 1, 'line' : None, 'column' : None, }, { 'title' : "Compiler Note", 'regex' : r"([][{}() \t#%$~\w&_:+/\.-]+)(:([0-9]+))(:[ \t]([Nn]ote:[ \t].*))", 'meaning' : 'message', 'highlight' : set( [ 1, 2 ] ), 'display' : [ 1, 2, 4 ], 'file' : 1, 'line' : None, 'column' : None, }, { 'title' : "General Note", 'regex' : r"([Nn]ote:[ \t].*)", 'meaning' : 'message', 'highlight' : set( [ 1 ] ), 'display' : [ 1 ], 'file' : None, 'line' : None, 'column' : None, }, { 'title' : "Compiler Error 2", 'regex' : r"([][{}() \t#%$~\w&_:+/\.-]+)(:([0-9]+):[0-9]+)(:[ \t](.*))", 'meaning' : 'error', 'highlight' : set( [ 1, 2 ] ), 'display' : [ 1, 2, 4 ], 'file' : 1, 'line' : None, 'column' : None, }, { 'title' : "Compiler Warning", 'regex' : r"([][{}() \t#%$~\w&_:+/\.-]+)(:([0-9]+))(:[ \t]([Ww]arning:[ \t].*))", 'meaning' : 'warning', 'highlight' : set( [ 1 ] ), 'display' : [ 1, 2, 4 ], 'file' : 1, 'line' : None, 'column' : None, }, { 'title' : "Undefined Reference 2", 'regex' : r"([][{}() \t#%$~\w&_:+/\.-]+\.o:([][{}() \t#%$~\w&_:+/\.-]+):([0-9]+))(:[ \t](undefined reference.*))", 'meaning' : 'warning', 'highlight' : set( [ 1 ] ), 'display' : [ 1, 4 ], 'file' : 2, 'line' : None, 'column' : None, }, { 'title' : "Compiler Error", 'regex' : r"([][{}() \t#%$~\w&_:+/\.-]+)(:([0-9]+))(:[ \t](.*))", 'meaning' : 'error', 'highlight' : set( [ 1, 2 ] ), 'display' : [ 1, 2, 4 ], 'file' : 1, 'line' : None, 'column' : None, }, { 'title' : "Linker Warning", 'regex' : r"([][{}() \t#%$~\w&_:+/\.-]+)(:\(\.text\+[0-9a-fA-FxX]+\))(:[ \t]([Ww]arning:[ \t].*))", 'meaning' : 'warning', 'highlight' : set( [ 1, 2 ] ), 'display' : [ 1, 2, 4 ], 'file' : 1, 'line' : None, 'column' : None, }, { 'title' : "Linker Error", 'regex' : r"([][{}() \t#%$~\w&_:+/\.-]+)(:([0-9]+):[0-9]+)(:[ \t](.*))", 'meaning' : 'error', 'highlight' : set( [ 1, 2 ] ), 'display' : [ 1, 2, 4 ], 'file' : 1, 'line' : None, 'column' : None, }, { 'title' : "Linker Error 2", 'regex' : r"([][{}() \t#%$~\w&_:+/\.-]+\(.text\+[0-9A-Za-z]+\):([ \tA-Za-z0-9_:+/\.-]+))(:[ \t](.*))", 'meaning' : 'error', 'highlight' : set( [ 1 ] ), 'display' : [ 1, 4 ], 'file' : 1, 'line' : None, 'column' : None, }, { 'title' : "Linker Error 3", 'regex' : r"(([][{}() \t#%$~\w&_:+/\.-]+):\(\.text\+[0-9a-fA-FxX]+\))(:(.*))", 'meaning' : 'error', 'highlight' : set( [ 1 ] ), 'display' : [ 1, 4 ], 'file' : 2, 'line' : None, 'column' : None, }, { 'title' : "Linker Error - lib not found", 'regex' : r"(.*(ld.*):[ \t](cannot find.*))", 'meaning' : 'error', 'highlight' : set( [ 1 ] ), 'display' : [ 1 ], 'file' : None, 'line' : None, 'column' : None, }, { 'title' : "Linker Error - cannot open output file", 'regex' : r"(.*(ld.*):[ \t](cannot open output file.*))(:[ \t](.*))", 'meaning' : 'error', 'highlight' : set( [ 1 ] ), 'display' : [ 1, 4 ], 'file' : None, 'line' : None, 'column' : None, }, { 'title' : "Linker Error - unrecognized option", 'regex' : r"(.*(ld.*))(:[ \t](unrecognized option.*))", 'meaning' : 'error', 'highlight' : set( [ 1 ] ), 'display' : [ 1, 3 ], 'file' : None, 'line' : None, 'column' : None, }, { 'title' : "No such File or Directory", 'regex' : r"(.*:(.*))(:[ \t](No such file or directory.*))", 'meaning' : 'error', 'highlight' : set( [ 1 ] ), 'display' : [ 1, 3 ], 'file' : None, 'line' : None, 'column' : None, }, { 'title' : "Undefined Reference", 'regex' : r"([][{}() \t#%$~\w&_:+/\.-]+)(:[ \t](undefined reference.*))", 'meaning' : 'error', 'highlight' : set( [ 1 ] ), 'display' : [ 1, 2 ], 'file' : None, 'line' : None, 'column' : None, }, { 'title' : "General Warning", 'regex' : r"([Ww]arning:[ \t].*)", 'meaning' : 'warning', 'highlight' : set( [ 1 ] ), 'display' : [ 1 ], 'file' : None, 'line' : None, 'column' : None, }, { 'title' : "Auto-Import Info", 'regex' : r"(([Ii]nfo:[ \t].*)\(auto-import\))", 'meaning' : 'message', 'highlight' : set( [ 1 ] ), 'display' : [ 1 ], 'file' : None, 'line' : None, 'column' : None, }, ] PK-¹ƒFó§H=ÔÔcuppa/modules/__init__.py # Copyright Jamie Allsop 2011-2015 # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) PK{QG b¸-cuppa/modules/registration.py # Copyright Jamie Allsop 2011-2015 # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) #------------------------------------------------------------------------------- # Registraion #------------------------------------------------------------------------------- from cuppa.log import logger def get_module_list( path, base=None ): from os import listdir from re import match from os.path import dirname paths = listdir( dirname( path ) ) def unique( seq ): seen = set() seen_add = seen.add return [ x for x in seq if x not in seen and not seen_add(x) ] return unique( [ base and '.'.join( [ base, f.replace('.py','') ] ) or f.replace('.py','') for f in paths for f in paths if match( '[^_.~].*\.py$', f ) ] ) def add_to_env( module_name, env, *args ): __call_classmethod_for_classes_in_module( 'cuppa', module_name, __package('cuppa'), "add_to_env", env, *args ) def add_options( module_name ): import SCons.Script __call_classmethod_for_classes_in_module( 'cuppa', module_name, __package('cuppa'), "add_options", SCons.Script.AddOption ) def get_options( module_name, env ): __call_classmethod_for_classes_in_module( 'cuppa', module_name, __package('cuppa'), "get_options", env ) def init_env_for_variant( module_name, sconscript_exports ): __call_classmethod_for_classes_in_module( 'cuppa', module_name, __package('cuppa'), "init_env_for_variant", sconscript_exports ) #------------------------------------------------------------------------------- import inspect import imp import sys def __package( name ): package = None try: filehandle, pathname, description = imp.find_module( name, None ) try: try: module = sys.modules[ name ] except KeyError, (e): module = imp.load_module( name, filehandle, pathname, description ) package = pathname finally: if filehandle: filehandle.close() except ImportError, (e): pass return package def __call_classmethod_for_classes_in_module( package, name, path, method, *args, **kwargs ): try: filehandle, pathname, description = imp.find_module( name, path and [ path ] or None ) try: try: qualified_name = package and package + "." + name or name module = sys.modules[ qualified_name ] except KeyError, (e): module = imp.load_module( name, filehandle, pathname, description ) for member_name in dir( module ): member = getattr( module, member_name ) if inspect.ismodule( member ): if package: parent_package = package + "." + name else: parent_package = name __call_classmethod_for_classes_in_module( parent_package, member_name, pathname, method, *args, **kwargs ) elif inspect.isclass( member ): try: function = getattr( member, method ) if callable( function ): try: function( *args, **kwargs ) except Exception as error: logger.error( "{} in {} failed with error [{}]".format( method, member, str(error) ) ) except AttributeError, (e): pass finally: if filehandle: filehandle.close() except ImportError, (e): pass #------------------------------------------------------------------------------- PK-¹ƒF3´¾¾cuppa/scms/subversion.py # Copyright Jamie Allsop 2011-2015 # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) #------------------------------------------------------------------------------- # Subversion Source Control Management System #------------------------------------------------------------------------------- import subprocess import shlex import re from exceptions import Exception class SubversionException(Exception): def __init__(self, value): self.parameter = value def __str__(self): return repr(self.parameter) def info( path ): if not path: raise SubversionException("No working copy path specified for calling svnversion with.") url = None repository = None branch = None revision = None try: command = "svn info {}".format( path ) svn_info = subprocess.check_output( shlex.split( command ), stderr=subprocess.STDOUT ) url = re.search( r'URL: ([^\s]+)', svn_info ).expand(r'\1') repository = re.search( r'Repository Root: ([^\s]+)', svn_info ).expand(r'\1') branch = re.search( r'Relative URL: \^/([^\s]+)', svn_info ).expand(r'\1') revision = re.search( r'Revision: (\d+)', svn_info ).expand(r'\1') except subprocess.CalledProcessError: raise SubversionException("Not a Subversion working copy") try: command = "svnversion -n {}".format( path ) revision = subprocess.check_output( shlex.split( command ), stderr=subprocess.STDOUT ) except subprocess.CalledProcessError: pass return url, repository, branch, revision PK-¹ƒFITXŸÓÓcuppa/scms/__init__.py # Copyright Jamie Allsop 2011-2015 # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) PKF©ÜF ê »‡‡cuppa/scms/mercurial.py # Copyright Jamie Allsop 2015-2015 # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) #------------------------------------------------------------------------------- # Mercurial Source Control Management System #------------------------------------------------------------------------------- import subprocess import shlex import os from exceptions import Exception class MercurialException(Exception): def __init__(self, value): self.parameter = value def __str__(self): return repr(self.parameter) def info( path ): if not path: raise MercurialException("No working copy path specified for calling hg commands with.") url = None repository = None branch = None revision = None if not os.path.exists( os.path.join( path, ".hg" ) ): raise MercurialException("Not a Mercurial working copy") try: command = "hg summary" summary = subprocess.check_output( shlex.split( command ), stderr=subprocess.STDOUT, cwd=path ).strip().split('\n') revision = "" branch = "" for line in summary: if not revision and line.startswith( 'parent: ' ): revision = line.replace( 'parent: ', '' ) if branch: break elif not branch and line.startswith( 'branch: ' ): branch = line.replace( 'branch: ', '' ) if revision: break command = "hg path" repository = subprocess.check_output( shlex.split( command ), stderr=subprocess.STDOUT, cwd=path ).strip().split('=')[1] url = repository except subprocess.CalledProcessError: raise MercurialException("Not a Mercurial working copy") return url, repository, branch, revision PK|»ÔFdƒÌ••cuppa/scms/git.py # Copyright Jamie Allsop 2014-2015 # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) #------------------------------------------------------------------------------- # Git Source Control Management System #------------------------------------------------------------------------------- import subprocess import shlex import os from exceptions import Exception class GitException(Exception): def __init__(self, value): self.parameter = value def __str__(self): return repr(self.parameter) def info( path ): if not path: raise GitException("No working copy path specified for calling git commands with.") url = None repository = None branch = None revision = None if not os.path.exists( os.path.join( path, ".git" ) ): raise GitException("Not a Git working copy") try: command = "git describe --always" revision = subprocess.check_output( shlex.split( command ), stderr=subprocess.STDOUT, cwd=path ).strip() command = "git symbolic-ref HEAD" branch = subprocess.check_output( shlex.split( command ), stderr=subprocess.STDOUT, cwd=path ) branch = branch.replace( "refs/heads/", "" ).strip() command = "git config --get remote.origin.url" repository = subprocess.check_output( shlex.split( command ), stderr=subprocess.STDOUT, cwd=path ).strip() url = repository except subprocess.CalledProcessError: raise GitException("Not a Git working copy") return url, repository, branch, revision PK{QG¸±³°V°V#cuppa/cpp/run_patched_boost_test.py # Copyright Jamie Allsop 2011-2015 # Copyright Declan Traynor 2012 # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) #------------------------------------------------------------------------------- # RunPatchedBoostTest #------------------------------------------------------------------------------- import os import sys import shlex import re import cuppa.test_report.cuppa_json import cuppa.build_platform from cuppa.output_processor import IncrementalSubProcess from cuppa.colourise import as_emphasised, as_highlighted, as_colour, emphasise_time_by_digit class Notify(object): def __init__( self, scons_env, show_test_output ): self._show_test_output = show_test_output self._toolchain = scons_env['toolchain'] self.master_suite = {} self.master_suite['status'] = 'passed' def enter_suite(self, suite): sys.stdout.write( as_emphasised( "\nStarting Test Suite [%s]\n" % suite ) ) def exit_suite(self, suite): sys.stdout.write( as_emphasised( "\nTest Suite Finished [%s] " % suite['name'] ) ) label = suite['status'].upper() meaning = suite['status'] store_durations( suite ) sys.stdout.write( as_highlighted( meaning, " = %s = " % label ) ) self.__write_time( suite ) total_tests = int(suite['total_tests']) passed_tests = int(suite['passed_tests']) failed_tests = int(suite['failed_tests']) expected_failures = int(suite['expected_failures']) skipped_tests = int(suite['skipped_tests']) aborted_tests = int(suite['aborted_tests']) total_assertions = int(suite['total_assertions']) passed_assertions = int(suite['passed_assertions']) failed_assertions = int(suite['failed_assertions']) if total_assertions > 0: if suite['status'] == 'passed': sys.stdout.write( as_highlighted( meaning, " ( %s of %s Assertions Passed )" % (passed_assertions, total_assertions) ) ) else: sys.stdout.write( as_highlighted( meaning, " ( %s of %s Assertions Failed )" % (failed_assertions, total_assertions) ) ) else: sys.stdout.write( as_colour( 'notice', " ( No Assertions Checked )" ) ) if suite['status'] == 'passed' and passed_tests > 0: sys.stdout.write( as_highlighted( meaning, " ( %s %s Passed ) " % (passed_tests, passed_tests > 1 and 'Test Cases' or 'Test Case') ) ) elif suite['status'] != 'passed': self.master_suite['status'] = 'failed' if failed_tests > 0: sys.stdout.write( as_highlighted( meaning, " ( %s %s Failed ) " % (failed_tests, failed_tests > 1 and 'Test Cases' or 'Test Case') ) ) if expected_failures > 0: sys.stdout.write( as_highlighted( meaning, " ( %s %s Expected ) " % (expected_failures, expected_failures > 1 and 'Failures' or 'Failure') ) ) if skipped_tests > 0: sys.stdout.write( as_highlighted( meaning, " ( %s %s Skipped ) " % (skipped_tests, skipped_tests > 1 and 'Test Cases' or 'Test Case') ) ) if aborted_tests > 0: sys.stdout.write( as_highlighted( meaning, " ( %s %s Aborted ) " % (aborted_tests, aborted_tests > 1 and 'Test Cases Were' or 'Test Case Was') ) ) sys.stdout.write('\n\n') def enter_test(self, test_case): pass sys.stdout.write( as_emphasised( "\nRunning Test Case [%s] ...\n" % test_case ) ) def exit_test( self, test_case ): label = test_case['status'] meaning = test_case['status'] sys.stdout.write( as_highlighted( meaning, " = %s = " % label ) ) self.__write_time( test_case ) assertions = int(test_case['total']) passed = int(test_case['passed']) failed = int(test_case['failed']) if test_case['status'] == 'passed' and passed > 0: sys.stdout.write( as_colour( meaning, " ( %s of %s Assertions Passed )" % ( passed, assertions ) ) ) if failed > 0: sys.stdout.write( as_colour( meaning, " ( %s of %s Assertions Failed )" % ( failed, assertions ) ) ) if test_case['total'] == 0: sys.stdout.write( as_colour( 'notice'," ( No Assertions )" ) ) sys.stdout.write('\n') def __write_time( self, results ): sys.stdout.write( " Time:" ) if 'wall_duration' in results: sys.stdout.write( " Wall [ %s ]" % emphasise_time_by_digit( results['wall_duration'] ) ) sys.stdout.write( " CPU [ %s ]" % emphasise_time_by_digit( results['cpu_duration'] ) ) if 'wall_cpu_percent' in results: wall_cpu_percent = results['wall_cpu_percent'].upper() format = "%6s%%" if wall_cpu_percent == "N/A": format = "%5s " wall_cpu_percent = format % wall_cpu_percent sys.stdout.write( " CPU/Wall [ %s ]" % as_colour( 'time', wall_cpu_percent ) ) def message(self, line): sys.stdout.write( line + "\n" ) def store_durations( results ): if 'cpu_time' in results: results['cpu_duration'] = duration_from_elapsed(results['cpu_time']) if 'wall_time' in results: results['wall_duration'] = duration_from_elapsed(results['wall_time']) if 'user_time' in results: results['user_duration'] = duration_from_elapsed(results['user_time']) if 'sys_time' in results: results['sys_duration'] = duration_from_elapsed(results['sys_time']) class State: waiting, test_suite, test_case = range(3) class ProcessStdout: def __init__( self, log, branch_root, notify ): self._log = open( log, "w" ) self._branch_root = branch_root self._notify = notify self._state = State.waiting self._test_case_names = [] self._test_cases = {} self._test_suites = {} self._master_test_suite = 'Master Test Suite' self._test = None def entered_test_suite( self, line ): matches = re.match( r'(?:(?P[a-zA-Z0-9._/\s\-]+)?[(](?P[0-9]+)[)]: )?' 'Entering test suite "(?P[a-zA-Z0-9(){}:&_<>/\-, ]+)"', line.strip() ) if matches and matches.group('suite') != self._master_test_suite: self.suite = matches.group('suite') self._test_suites[self.suite] = {} self._test_suites[self.suite]['name'] = self.suite self._test_suites[self.suite]['cpu_time'] = 0 self._test_suites[self.suite]['wall_time'] = 0 self._test_suites[self.suite]['user_time'] = 0 self._test_suites[self.suite]['sys_time'] = 0 self._test_suites[self.suite]['total_tests'] = 0 self._test_suites[self.suite]['expected_failures'] = 0 self._test_suites[self.suite]['passed_tests'] = 0 self._test_suites[self.suite]['failed_tests'] = 0 self._test_suites[self.suite]['skipped_tests'] = 0 self._test_suites[self.suite]['aborted_tests'] = 0 self._test_suites[self.suite]['total_assertions'] = 0 self._test_suites[self.suite]['passed_assertions'] = 0 self._test_suites[self.suite]['failed_assertions'] = 0 self._notify.enter_suite(self.suite) return True return False def leaving_test_suite( self, line ): matches = re.match( r'Leaving test suite "(?P[a-zA-Z0-9(){}:&_<>/\-, ]+)"' '\. Test suite (?Ppassed|failed)\.' '(?: (?P.*))?', line.strip() ) if matches and matches.group('suite') != self._master_test_suite: suite = self._test_suites[matches.group('suite')] if matches.group('status'): suite['status'] = matches.group('status') if matches.group('results'): self.store_suite_results(suite, matches.group('results')) self._notify.exit_suite(suite) return True else: return False def entered_test_case( self, line ): matches = re.match( r'(?:(?P[a-zA-Z0-9._/\\\s\-]+)[(](?P[0-9]+)[)]: )?' 'Entering test case "(?P[a-zA-Z0-9(){}\[\]:;&_<>\-, =]+)"', line.strip() ) if matches: name = matches.group('test') self._test = '[' + self.suite + '] ' + name self._test_cases[ self._test ] = {} self._test_cases[ self._test ]['suite'] = self.suite self._test_cases[ self._test ]['fixture'] = self.suite self._test_cases[ self._test ]['key'] = self._test self._test_cases[ self._test ]['name'] = name self._test_cases[ self._test ]['stdout'] = [] self._test_cases[ self._test ]['file'] = matches.group('file') self._test_cases[ self._test ]['line'] = matches.group('line') self._test_cases[ self._test ]['cpu_time'] = 0 self._test_cases[ self._test ]['branch_dir'] = os.path.relpath( matches.group('file'), self._branch_root ) self._test_cases[ self._test ]['total'] = 0 self._test_cases[ self._test ]['assertions'] = 0 self._test_cases[ self._test ]['passed'] = 0 self._test_cases[ self._test ]['failed'] = 0 self._notify.enter_test(self._test) return True return False def leaving_test_case( self, line ): test = self._test_cases[self._test] matches = re.match( r'Leaving test case "(?:[a-zA-Z0-9(){}\[\]:;&_<>\-, =]+)"' '(?:; testing time: (?P[a-zA-Z0-9.s ,+=()%/]+))?' '\. Test case (?Ppassed|failed|skipped|aborted)\.' '(?: (?P.*))?', line.strip() ) if matches: self.__capture_times( matches.group('testing_time'), test ) if matches.group('status'): test['status'] = matches.group('status') if matches.group('results'): self.store_test_results(test, matches.group('results')) self._test_case_names.append( test['key'] ) self._notify.exit_test(test) return True else: test['stdout'].append( line ) self._notify.message(line) return False def __capture_times( self, time, results ): if time: time = time.strip() test_time = re.match( '(?:(P[0-9]+)(?Pms|mks))', time ) if test_time: multiplier = test_time.group('units') == 'ms' and 1000000 or 1000 subseconds = int(test_time.group('test_time')) total_nanosecs = subseconds * multiplier results['cpu_time'] = total_nanosecs cpu_times = re.match( r'(?P[0-9.]+)s wall, ' '(?P[0-9.]+)s user [+] ' '(?P[0-9.]+)s system [=] ' '(?P[0-9.]+)s CPU [(](?P[nN/aA0-9.]+)%?[)]', time ) if cpu_times: results['wall_time'] = nanosecs_from_time( cpu_times.group('wall_time') ) results['user_time'] = nanosecs_from_time( cpu_times.group('user_time') ) results['sys_time'] = nanosecs_from_time( cpu_times.group('sys_time') ) results['cpu_time'] = nanosecs_from_time( cpu_times.group('cpu_time') ) self._test_suites[results['suite']]['wall_time'] += results['wall_time'] self._test_suites[results['suite']]['user_time'] += results['user_time'] self._test_suites[results['suite']]['sys_time'] += results['sys_time'] results['wall_cpu_percent'] = cpu_times.group('wall_cpu_percent') self._test_suites[results['suite']]['cpu_time'] += results['cpu_time'] store_durations( results ) else: results['cpu_duration'] = duration_from_elapsed(0) ## For backward compatibility - remove later results['elapsed'] = results['cpu_time'] def __call__( self, line ): self._log.write( line + '\n' ) if self._state == State.waiting: if self.entered_test_suite( line ): self._state = State.test_suite elif self.leaving_test_suite( line ): self._state = State.waiting elif self._state == State.test_suite: if self.entered_test_case( line ): self._state = State.test_case elif self.entered_test_suite( line ): self._state = State.test_suite elif self.leaving_test_suite( line ): self._state = State.waiting elif self._state == State.test_case: if self.leaving_test_case( line ): self._state = State.test_suite def __exit__( self, type, value, traceback ): if self._log: self._log.close() def tests( self ): return [ self._test_cases[ name ] for name in self._test_case_names ] def store_test_results(self, test, results): matches = [] for result in results.split('.'): matched = re.match( r'(?P[0-9]+) assertions? out of (?P[0-9]+) (?Ppassed|failed)', result.strip() ) if matched: matches.append(matched) for match in matches: count = match.group('count') total = match.group('total') status = match.group('status') test['total'] = total if status == 'passed': test['passed'] = count elif status == 'failed': test['failed'] = count ## For backward compatibility - remove later test['assertions'] = test['total'] def store_suite_results(self, suite, results): matches = [] for result in results.split('.'): matched = re.match( r'(?P[0-9]+) (?Passertions?|test cases?|failures?) ' '((?Pexpected)|(out of (?P[0-9]+) ' '(?Ppassed|failed|skipped|aborted)))', result.strip() ) if matched: matches.append(matched) for match in matches: count = match.group('count') type = match.group('type') expected_failures = match.group('expected') total = match.group('total') status = match.group('status') if not expected_failures: if type.startswith('test case'): suite['total_tests'] = total elif type.startswith('assertion'): suite['total_assertions'] = total else: suite['expected_failures'] = count if status == 'passed': if type.startswith('test case'): suite['passed_tests'] = count elif type.startswith('assertion'): suite['passed_assertions'] = count elif status == 'failed': if type.startswith('test case'): suite['failed_tests'] = count elif type.startswith('assertion'): suite['failed_assertions'] = count elif status == 'skipped': suite['skipped_tests'] = count elif status == 'aborted': suite['aborted_tests'] = count class ProcessStderr: def __init__( self, log, notify ): self._log = open( log, "w" ) def __call__( self, line ): self._log.write( line + '\n' ) def __exit__( self, type, value, traceback ): if self._log: self._log.close() def stdout_file_name_from( program_file ): return program_file + '.stdout.log' def stderr_file_name_from( program_file ): return program_file + '.stderr.log' def report_file_name_from( program_file ): return program_file + '.report.json' def success_file_name_from( program_file ): return program_file + '.success' class RunPatchedBoostTestEmitter: def __init__( self, final_dir ): self._final_dir = final_dir def __call__( self, target, source, env ): program_file = os.path.join( self._final_dir, os.path.split( str( source[0] ) )[1] ) target = [] target.append( stdout_file_name_from( program_file ) ) target.append( stderr_file_name_from( program_file ) ) target.append( report_file_name_from( program_file ) ) target.append( success_file_name_from( program_file ) ) return target, source class RunPatchedBoostTest: def __init__( self, expected ): self._expected = expected def __call__( self, target, source, env ): executable = str( source[0].abspath ) working_dir = os.path.split( executable )[0] program_path = source[0].path notifier = Notify(env, env['show_test_output']) if cuppa.build_platform.name() == "Windows": executable = '"' + executable + '"' test_command = executable + " --boost.test.log_format=hrf --boost.test.log_level=test_suite --boost.test.report_level=no" print "cuppa: RunPatchedBoostTest: [" + test_command + "]" try: return_code, tests = self._run_test( program_path, test_command, working_dir, env['branch_root'], notifier ) cuppa.test_report.cuppa_json.write_report( report_file_name_from( program_path ), tests ) if return_code < 0: self._write_file_to_stderr( stderr_file_name_from( program_path ) ) print >> sys.stderr, "cuppa: RunPatchedBoostTest: Test was terminated by signal: ", -return_code elif return_code > 0: self._write_file_to_stderr( stderr_file_name_from( program_path ) ) print >> sys.stderr, "cuppa: RunPatchedBoostTest: Test returned with error code: ", return_code elif notifier.master_suite['status'] != 'passed': print >> sys.stderr, "cuppa: RunPatchedBoostTest: Not all test suites passed. " if return_code: self._remove_success_file( success_file_name_from( program_path ) ) else: self._write_success_file( success_file_name_from( program_path ) ) return None except OSError, e: print >> sys.stderr, "Execution of [", test_command, "] failed with error: ", e return 1 def _run_test( self, program_path, test_command, working_dir,branch_root, notifier ): process_stdout = ProcessStdout( stdout_file_name_from( program_path ), branch_root, notifier ) process_stderr = ProcessStderr( stderr_file_name_from( program_path ), notifier ) return_code = IncrementalSubProcess.Popen2( process_stdout, process_stderr, shlex.split( test_command ), cwd=working_dir ) return return_code, process_stdout.tests() def _write_file_to_stderr( self, file_name ): error_file = open( file_name, "r" ) for line in error_file: print >> sys.stderr, line error_file.close() def _write_success_file( self, file_name ): with open( file_name, "w" ) as success_file: success_file.write( "success" ) def _remove_success_file( self, file_name ): try: os.remove( file_name ) except: pass def nanosecs_from_time( time_in_seconds ): seconds, subseconds = time_in_seconds.split('.') nanoseconds = subseconds decimal_places = len(subseconds) if decimal_places < 9: nanoseconds = int(subseconds) * 10**(9-decimal_places) return int(seconds) * 1000000000 + int(nanoseconds) def duration_from_elapsed( total_nanosecs ): secs, remainder = divmod( total_nanosecs, 1000000000 ) millisecs, remainder = divmod( remainder, 1000000 ) microsecs, nanosecs = divmod( remainder, 1000 ) hours, remainder = divmod( secs, 3600 ) minutes, secs = divmod( remainder, 60 ) duration = "%02d:%02d:%02d.%03d,%03d,%03d" % ( hours, minutes, secs, millisecs, microsecs, nanosecs ) return duration PK-¹ƒFó§H=ÔÔcuppa/cpp/__init__.py # Copyright Jamie Allsop 2011-2015 # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) PK{QGL'`à=\=\cuppa/cpp/run_boost_test.py # Copyright Jamie Allsop 2015-2015 # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) #------------------------------------------------------------------------------- # RunBoostTest #------------------------------------------------------------------------------- import os import sys import shlex import re import cuppa.timer import cuppa.test_report.cuppa_json import cuppa.build_platform from cuppa.output_processor import IncrementalSubProcess from cuppa.colourise import as_emphasised, as_highlighted, as_colour, start_colour, colour_reset class Notify(object): def __init__( self, scons_env, show_test_output ): self._show_test_output = show_test_output self._toolchain = scons_env['toolchain'] self.master_suite = {} self.master_suite['status'] = 'passed' def enter_suite(self, suite): sys.stdout.write( as_emphasised( "\nStarting Test Suite [%s]\n" % suite ) ) def exit_suite(self, suite): sys.stdout.write( as_emphasised( "\nTest Suite Finished [%s] " % suite['name'] ) ) label = suite['status'].upper() meaning = suite['status'] sys.stdout.write( as_highlighted( meaning, " = {} = ".format( suite['status'].upper() ) ) ) sys.stdout.write('\n') sys.stdout.write( as_emphasised( "\nSummary\n" ) ) for test in suite['tests']: sys.stdout.write( as_emphasised( "\nTest case [{}]".format( test['name'] ) ) + '\n' ) self._write_test_case( test ) sys.stdout.write('\n') sys.stdout.write( as_highlighted( meaning, " = %s = " % label ) ) cuppa.timer.write_time( suite['total_cpu_times'] ) passed_tests = suite['passed_tests'] failed_tests = suite['failed_tests'] expected_failures = suite['expected_failures'] skipped_tests = suite['skipped_tests'] aborted_tests = suite['aborted_tests'] total_assertions = suite['total_assertions'] passed_assertions = suite['passed_assertions'] failed_assertions = suite['failed_assertions'] if total_assertions > 0: if suite['status'] == 'passed': sys.stdout.write( as_highlighted( meaning, " ( %s of %s Assertions Passed )" % (passed_assertions, total_assertions) ) ) else: sys.stdout.write( as_highlighted( meaning, " ( %s of %s Assertions Failed )" % (failed_assertions, total_assertions) ) ) else: sys.stdout.write( as_colour( 'notice', " ( No Assertions Checked )" ) ) if suite['status'] == 'passed' and passed_tests > 0: sys.stdout.write( as_highlighted( meaning, " ( %s %s Passed ) " % (passed_tests, passed_tests > 1 and 'Test Cases' or 'Test Case') ) ) elif suite['status'] != 'passed': self.master_suite['status'] = 'failed' if failed_tests > 0: sys.stdout.write( as_highlighted( meaning, " ( %s %s Failed ) " % (failed_tests, failed_tests > 1 and 'Test Cases' or 'Test Case') ) ) if expected_failures > 0: sys.stdout.write( as_highlighted( meaning, " ( %s %s Expected ) " % (expected_failures, expected_failures > 1 and 'Failures' or 'Failure') ) ) if len( skipped_tests ): number = len( skipped_tests ) sys.stdout.write( as_highlighted( meaning, " ( %s %s Skipped ) " % (number, number > 1 and 'Test Cases' or 'Test Case') ) ) if aborted_tests > 0: sys.stdout.write( as_highlighted( meaning, " ( %s %s Aborted ) " % (aborted_tests, aborted_tests > 1 and 'Test Cases Were' or 'Test Case Was') ) ) sys.stdout.write('\n\n') def _write_test_case( self, test_case ): label = test_case['status'] meaning = test_case['status'] sys.stdout.write( as_highlighted( meaning, " = %s = " % label ) ) cuppa.timer.write_time( test_case['cpu_times'] ) assertions = test_case['total'] passed = test_case['passed'] failed = test_case['failed'] if test_case['status'] == 'passed' and passed > 0: sys.stdout.write( as_colour( meaning, " ( %s of %s Assertions Passed )" % ( passed, assertions ) ) ) if failed > 0: sys.stdout.write( as_colour( meaning, " ( %s of %s Assertions Failed )" % ( failed, assertions ) ) ) if test_case['total'] == 0: sys.stdout.write( as_colour( 'notice'," ( No Assertions )" ) ) sys.stdout.write('\n') def enter_test_case(self, test_case): sys.stdout.write( as_emphasised( "\nRunning Test Case [%s] ...\n" % test_case['key'] ) ) test_case['timer'] = cuppa.timer.Timer() def exit_test_case( self, test ): self._write_test_case( test ) def failed_assertion(self, line ): def start_error(): return start_colour( "error" ) matches = re.match( r'(?P[a-zA-Z0-9._/\s\-]+)[(](?P[0-9]+)[)]: ' '(?P[a-zA-Z0-9(){}:&_<>/\-=!," \[\]]+)', line ) if matches: path = matches.group( 'file' ) line = matches.group( 'line' ) message = matches.group( 'message') error = self._toolchain.error_format() sys.stdout.write( error.format( start_error() + as_emphasised( path ) + start_error(), as_emphasised( line ) + start_error(), message + colour_reset() ) + "\n" ) else: sys.stdout.write( as_colour( "error", line ) + "\n" ) def message(self, line): if self._show_test_output: sys.stdout.write( line + "\n" ) class State: waiting, test_suite, test_case = range(3) class ProcessStdout: def __init__( self, log, branch_root, notify ): self.log = open( log, "w" ) self.branch_root = branch_root self.notify = notify self.state = State.waiting self.test_case_names = [] self.test_cases = {} self.test_suites = {} self.master_test_suite = 'Master Test Suite' def entered_test_suite( self, line ): matches = re.match( r'(?:(?P[a-zA-Z0-9._/\s\-]+)?[(](?P[0-9]+)[)]: )?' 'Entering test (suite|module) "(?P[a-zA-Z0-9(){}:&_<>/\-, ]+)"', line.strip() ) if matches and matches.group('suite') != self.master_test_suite: self.suite = matches.group('suite') self.test_suites[self.suite] = {} self.test_suites[self.suite]['name'] = self.suite self.test_suites[self.suite]['total_tests'] = 0 self.test_suites[self.suite]['expected_failures'] = 0 self.test_suites[self.suite]['passed_tests'] = 0 self.test_suites[self.suite]['failed_tests'] = 0 self.test_suites[self.suite]['skipped_tests'] = [] self.test_suites[self.suite]['aborted_tests'] = 0 self.test_suites[self.suite]['total_assertions'] = 0 self.test_suites[self.suite]['passed_assertions'] = 0 self.test_suites[self.suite]['failed_assertions'] = 0 self.test_suites[self.suite]['total_cpu_times'] = cuppa.timer.CpuTimes( 0, 0, 0, 0 ) self.test_suites[self.suite]['tests'] = [] self.notify.enter_suite(self.suite) return True return False def leaving_test_suite( self, line ): matches = re.match( r'Leaving test (suite|module) "(?P[a-zA-Z0-9(){}:&_<>/\-, ]+)"' '(\. Test suite (?Ppassed|failed)\.' '(?: (?P.*))?)?', line.strip() ) if matches and matches.group('suite') != self.master_test_suite: suite = self.test_suites[matches.group('suite')] if matches.group('status'): suite['status'] = matches.group('status') if matches.group('results'): self.store_suite_results(suite, matches.group('results')) else: self.collate_suite_results(suite) self.notify.exit_suite(suite) return True else: return False def skipped_test_case( self, line ): matches = re.match( r'Test "(?P[a-zA-Z0-9(){}\[\]:;&_<>\-, =]+)" is skipped', line.strip() ) if matches: name = matches.group('test') self.test_suites[self.suite]['skipped_tests'].append( name ) return True return False def entered_test_case( self, line ): matches = re.match( r'(?:(?P[a-zA-Z0-9._/\\\s\-]+)[(](?P[0-9]+)[)]: )?' 'Entering test case "(?P[a-zA-Z0-9(){}\[\]:;&_<>\-, =]+)"', line.strip() ) if matches: name = matches.group('test') self.test_suites[self.suite]['tests'].append( {} ) test_case = self.test_suites[self.suite]['tests'][-1] test_case['suite'] = self.suite test_case['fixture'] = self.suite test_case['key'] = '[' + self.suite + '] ' + name test_case['name'] = name test_case['stdout'] = [] test_case['total'] = 0 test_case['assertions'] = 0 test_case['passed'] = 0 test_case['failed'] = 0 test_case['skipped'] = False test_case['aborted'] = 0 test_case['line'] = matches.group('line') test_case['file'] = matches.group('file') self.notify.enter_test_case( test_case ) return True return False def leaving_test_case( self, line ): test_case = self.test_suites[self.suite]['tests'][-1] matches = re.match( r'(?:(?P[a-zA-Z0-9._/\\\s\-]+)[(](?P[0-9]+)[)]: )?' 'Leaving test case "(?:[a-zA-Z0-9(){}\[\]:;&_<>\-, =]+)"' '(?:; testing time: (?P[a-zA-Z0-9.s ,+=()%/]+))?' '(\. Test case (?Ppassed|failed|skipped|aborted)\.' '(?: (?P.*))?)?', line.strip() ) if matches: test_case['timer'].stop() test_case['cpu_times'] = test_case['timer'].elapsed() if matches.group('status'): test_case['status'] = matches.group('status') else: test_case['status'] = 'passed' if matches.group('results'): self.store_test_results(test_case, matches.group('results')) else: self.collate_test_case_results( test_case ) self.test_case_names.append( test_case['key'] ) self.notify.exit_test_case(test_case) return True else: test_case['stdout'].append( line ) self.notify.message(line) return False def handle_assertion( self, line ): test_case = self.test_suites[self.suite]['tests'][-1] is_assertion = False write_line = True matches = re.match( r'.*\s(?Ppassed|failed)(\s[\[][^\[\]]+[\]])?$', line.strip() ) if matches: is_assertion = True write_line = False status = matches.group('status') test_case['assertions'] = test_case['assertions'] + 1 test_case[status] = test_case[status] + 1 if status == 'failed': write_line = True self.notify.failed_assertion(line) return is_assertion, write_line def __call__( self, line ): if not self.state == State.test_case: self.log.write( line + '\n' ) if self.state == State.waiting: if self.entered_test_suite( line ): self.state = State.test_suite elif self.leaving_test_suite( line ): self.state = State.waiting elif self.state == State.test_suite: if self.entered_test_case( line ): self.state = State.test_case elif self.skipped_test_case( line ): self.state = State.test_suite elif self.entered_test_suite( line ): self.state = State.test_suite elif self.leaving_test_suite( line ): self.state = State.waiting elif self.state == State.test_case: is_assertion, write_line = self.handle_assertion( line ) if write_line: self.log.write( line + '\n' ) if not is_assertion: if self.leaving_test_case( line ): self.state = State.test_suite def __exit__( self, type, value, traceback ): if self.log: self.log.close() def tests( self ): tests = [] for suite in self.test_suites.itervalues(): for test_case in suite['tests']: tests.append( test_case ) return tests def collate_test_case_results( self, test ): test['status'] = ( test['failed'] or test['aborted'] ) and 'failed' or 'passed' test['total'] = test['assertions'] test['cpu_time'] = test['cpu_times'].process test['wall_time'] = test['cpu_times'].wall test['user_time'] = test['cpu_times'].user test['sys_time'] = test['cpu_times'].system test['cpu_duration'] = cuppa.timer.as_duration_string( test['cpu_time'] ) test['wall_duration'] = cuppa.timer.as_duration_string( test['wall_time'] ) test['user_duration'] = cuppa.timer.as_duration_string( test['user_time'] ) test['sys_duration'] = cuppa.timer.as_duration_string( test['sys_time'] ) test['wall_cpu_percent'] = cuppa.timer.as_wall_cpu_percent_string( test['cpu_times'] ) test_suite = self.test_suites[test['suite']] test_suite['passed_tests'] = test_suite['passed_tests'] + ( test['passed'] and 1 or 0 ) test_suite['failed_tests'] = test_suite['failed_tests'] + ( test['failed'] and 1 or 0 ) test_suite['aborted_tests'] = test_suite['aborted_tests'] + ( test['aborted'] and 1 or 0 ) test_suite['total_assertions'] = test_suite['total_assertions'] + test['total'] test_suite['passed_assertions'] = test_suite['passed_assertions'] + test['passed'] + test['skipped'] test_suite['failed_assertions'] = test_suite['failed_assertions'] + test['failed'] + test['aborted'] test_suite['total_cpu_times'] += test['cpu_times'] def store_test_results(self, test, results): matches = [] for result in results.split('.'): matched = re.match( r'(?P[0-9]+) assertions? out of (?P[0-9]+) (?Ppassed|failed)', result.strip() ) if matched: matches.append(matched) for match in matches: count = match.group('count') total = match.group('total') status = match.group('status') test['total'] = total if status == 'passed': test['passed'] = count elif status == 'failed': test['failed'] = count ## For backward compatibility - remove later test['assertions'] = test['total'] def collate_suite_results( self, suite ): suite['status'] = suite['failed_assertions'] and 'failed' or 'passed' suite['cpu_time'] = suite['total_cpu_times'].process suite['wall_time'] = suite['total_cpu_times'].wall suite['user_time'] = suite['total_cpu_times'].user suite['sys_time'] = suite['total_cpu_times'].system suite['cpu_duration'] = cuppa.timer.as_duration_string( suite['cpu_time'] ) suite['wall_duration'] = cuppa.timer.as_duration_string( suite['wall_time'] ) suite['user_duration'] = cuppa.timer.as_duration_string( suite['user_time'] ) suite['sys_duration'] = cuppa.timer.as_duration_string( suite['sys_time'] ) suite['wall_cpu_percent'] = cuppa.timer.as_wall_cpu_percent_string( suite['total_cpu_times'] ) def store_suite_results(self, suite, results): matches = [] for result in results.split('.'): matched = re.match( r'(?P[0-9]+) (?Passertions?|test cases?|failures?) ' '((?Pexpected)|(out of (?P[0-9]+) ' '(?Ppassed|failed|skipped|aborted)))', result.strip() ) if matched: matches.append(matched) for match in matches: count = match.group('count') type = match.group('type') expected_failures = match.group('expected') total = match.group('total') status = match.group('status') if not expected_failures: if type.startswith('test case'): suite['total_tests'] = total elif type.startswith('assertion'): suite['total_assertions'] = total else: suite['expected_failures'] = count if status == 'passed': if type.startswith('test case'): suite['passed_tests'] = count elif type.startswith('assertion'): suite['passed_assertions'] = count elif status == 'failed': if type.startswith('test case'): suite['failed_tests'] = count elif type.startswith('assertion'): suite['failed_assertions'] = count elif status == 'skipped': suite['skipped_tests'] = count elif status == 'aborted': suite['aborted_tests'] = count class ProcessStderr: def __init__( self, log, notify ): self.log = open( log, "w" ) def __call__( self, line ): self.log.write( line + '\n' ) def __exit__( self, type, value, traceback ): if self.log: self.log.close() def stdout_file_name_from( program_file ): return program_file + '.stdout.log' def stderr_file_name_from( program_file ): return program_file + '.stderr.log' def report_file_name_from( program_file ): return program_file + '.report.json' def success_file_name_from( program_file ): return program_file + '.success' class RunBoostTestEmitter: def __init__( self, final_dir ): self._final_dir = final_dir def __call__( self, target, source, env ): program_file = os.path.join( self._final_dir, os.path.split( str( source[0] ) )[1] ) target = [] target.append( stdout_file_name_from( program_file ) ) target.append( stderr_file_name_from( program_file ) ) target.append( report_file_name_from( program_file ) ) target.append( success_file_name_from( program_file ) ) return target, source class RunBoostTest: def __init__( self, expected ): self._expected = expected def __call__( self, target, source, env ): executable = str( source[0].abspath ) working_dir = os.path.split( executable )[0] program_path = source[0].path notifier = Notify(env, env['show_test_output']) if cuppa.build_platform.name() == "Windows": executable = '"' + executable + '"' test_command = executable + " --log_format=hrf --log_level=all --report_level=no" print "cuppa: RunBoostTest: [" + test_command + "]" try: return_code, tests = self.__run_test( program_path, test_command, working_dir, env['branch_root'], notifier ) cuppa.test_report.cuppa_json.write_report( report_file_name_from( program_path ), tests ) if return_code < 0: self.__write_file_to_stderr( stderr_file_name_from( program_path ) ) print >> sys.stderr, "cuppa: RunBoostTest: Test was terminated by signal: ", -return_code elif return_code > 0: self.__write_file_to_stderr( stderr_file_name_from( program_path ) ) print >> sys.stderr, "cuppa: RunBoostTest: Test returned with error code: ", return_code elif notifier.master_suite['status'] != 'passed': print >> sys.stderr, "cuppa: RunBoostTest: Not all test suites passed. " if return_code: self._remove_success_file( success_file_name_from( program_path ) ) else: self._write_success_file( success_file_name_from( program_path ) ) return None except OSError as e: print >> sys.stderr, "Execution of [", test_command, "] failed with error: ", str(e) return 1 def __run_test( self, program_path, test_command, working_dir, branch_root, notifier ): process_stdout = ProcessStdout( stdout_file_name_from( program_path ), branch_root, notifier ) process_stderr = ProcessStderr( stderr_file_name_from( program_path ), notifier ) return_code = IncrementalSubProcess.Popen2( process_stdout, process_stderr, shlex.split( test_command ), cwd=working_dir ) return return_code, process_stdout.tests() def __write_file_to_stderr( self, file_name ): with open( file_name, "r" ) as error_file: for line in error_file: print >> sys.stderr, line def _write_success_file( self, file_name ): with open( file_name, "w" ) as success_file: success_file.write( "success" ) def _remove_success_file( self, file_name ): try: os.remove( file_name ) except: pass PKòkRGƒËœó0202cuppa/cpp/run_process_test.py # Copyright Jamie Allsop 2013-2015 # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) #------------------------------------------------------------------------------- # RunProcessTest #------------------------------------------------------------------------------- import os import sys import shlex import cuppa.timer import cuppa.progress import cuppa.test_report.cuppa_json from cuppa.output_processor import IncrementalSubProcess from cuppa.colourise import as_emphasised, as_highlighted, as_colour class TestSuite(object): suites = {} @classmethod def create( cls, name, scons_env ): if not name in cls.suites: cls.suites[name] = TestSuite( name, scons_env ) return cls.suites[name] def __init__( self, name, scons_env ): self._name = name self._scons_env = scons_env sys.stdout.write('\n') sys.stdout.write( as_emphasised( "Starting Test Suite [{}]".format( name ) ) ) sys.stdout.write('\n') cuppa.progress.NotifyProgress.register_callback( scons_env, self.on_progress ) self._suite = {} self._suite['total_tests'] = 0 self._suite['passed_tests'] = 0 self._suite['failed_tests'] = 0 self._suite['expected_failures'] = 0 self._suite['skipped_tests'] = 0 self._suite['aborted_tests'] = 0 self._suite['total_cpu_times'] = cuppa.timer.CpuTimes( 0, 0, 0, 0 ) self._tests = [] def on_progress( self, progress, sconscript, variant, env, target, source ): if progress == 'finished': self.exit_suite() suite = env['build_dir'] del self.suites[suite] def enter_test( self, test, expected='passed' ) : sys.stdout.write( as_emphasised( "\nTest [%s]..." % test ) + '\n' ) self._tests.append( {} ) test_case = self._tests[-1] test_case['name'] = test test_case['expected'] = expected test_case['suite'] = self._name test_case['timer'] = cuppa.timer.Timer() def exit_test( self, test, status='passed' ): test_case = self._tests[-1] test_case['timer'].stop() test_case['status'] = status cpu_times = test_case['timer'].elapsed() del test_case['timer'] test_case['cpu_times'] = cpu_times test_case['cpu_time'] = cpu_times.process test_case['wall_time'] = cpu_times.wall test_case['user_time'] = cpu_times.user test_case['sys_time'] = cpu_times.system test_case['cpu_duration'] = cuppa.timer.as_duration_string( test_case['cpu_time'] ) test_case['wall_duration'] = cuppa.timer.as_duration_string( test_case['wall_time'] ) test_case['user_duration'] = cuppa.timer.as_duration_string( test_case['user_time'] ) test_case['sys_duration'] = cuppa.timer.as_duration_string( test_case['sys_time'] ) test_case['wall_cpu_percent'] = cuppa.timer.as_wall_cpu_percent_string( cpu_times ) self._write_test_case( test_case ) self._suite['total_tests'] += 1 if status == 'passed': self._suite['passed_tests'] += 1 elif status == 'failed': self._suite['failed_tests'] += 1 elif status == 'expected_failure': self._suite['expected_failures'] += 1 elif status == 'aborted': self._suite['aborted_tests'] += 1 elif status == 'skipped': self._suite['skipped_tests'] += 1 self._suite['total_cpu_times'] += test_case['cpu_times'] sys.stdout.write('\n\n') def _write_test_case( self, test_case ): expected = test_case['expected'] == test_case['status'] passed = test_case['status'] == 'passed' meaning = test_case['status'] if not expected and passed: meaning = 'unexpected_success' label = " ".join( meaning.upper().split('_') ) cpu_times = test_case['cpu_times'] sys.stdout.write( as_highlighted( meaning, " = %s = " % label ) ) cuppa.timer.write_time( cpu_times ) def exit_suite( self ): suite = self._suite total_tests = suite['total_tests'] passed_tests = suite['passed_tests'] + suite['expected_failures'] + suite['skipped_tests'] failed_tests = suite['failed_tests'] + suite['aborted_tests'] expected_failures = suite['expected_failures'] skipped_tests = suite['skipped_tests'] aborted_tests = suite['aborted_tests'] suite['status'] = 'passed' meaning = 'passed' if total_tests != passed_tests: suite['status'] = 'failed' meaning = 'failed' sys.stdout.write( as_emphasised( "\nTest Suite [{}] ".format( self._name ) ) ) sys.stdout.write( as_highlighted( meaning, " = {} = ".format( suite['status'].upper() ) ) ) sys.stdout.write('\n') sys.stdout.write( as_emphasised( "\nSummary\n" ) ) for test in self._tests: sys.stdout.write( as_emphasised( "\nTest case [{}]".format( test['name'] ) ) + '\n' ) self._write_test_case( test ) sys.stdout.write('\n\n') if total_tests > 0: if suite['status'] == 'passed': sys.stdout.write( as_highlighted( meaning, " ( %s of %s Test Cases Passed )" % ( passed_tests, total_tests ) ) ) else: sys.stdout.write( as_highlighted( meaning, " ( %s of %s Test Cases Failed )" % (failed_tests, total_tests) ) ) else: sys.stdout.write( as_colour( 'notice', " ( No Test Cases Checked )" ) ) if passed_tests > 0: sys.stdout.write( as_highlighted( meaning, " ( %s %s Passed ) " % (passed_tests, passed_tests > 1 and 'Test Cases' or 'Test Case') ) ) if failed_tests > 0: sys.stdout.write( as_highlighted( meaning, " ( %s %s Failed ) " % (failed_tests, failed_tests > 1 and 'Test Cases' or 'Test Case') ) ) if expected_failures > 0: meaning = 'expected_failure' sys.stdout.write( as_highlighted( meaning, " ( %s %s Expected ) " % (expected_failures, expected_failures > 1 and 'Failures' or 'Failure') ) ) if skipped_tests > 0: meaning = 'skipped' sys.stdout.write( as_highlighted( meaning, " ( %s %s Skipped ) " % (skipped_tests, skipped_tests > 1 and 'Test Cases' or 'Test Case') ) ) if aborted_tests > 0: meaning = 'aborted' sys.stdout.write( as_highlighted( meaning, " ( %s %s Aborted ) " % (aborted_tests, aborted_tests > 1 and 'Test Cases Were' or 'Test Case Was') ) ) sys.stdout.write('\n') cuppa.timer.write_time( self._suite['total_cpu_times'], True ) self._tests = [] self._suite = {} sys.stdout.write('\n\n') def message( self, line ): sys.stdout.write( line + "\n" ) def tests( self ): return self._tests def stdout_file_name_from( program_file ): return program_file + '.stdout.log' def stderr_file_name_from( program_file ): return program_file + '.stderr.log' def report_file_name_from( program_file ): return program_file + '.report.json' def success_file_name_from( program_file ): return program_file + '.success' class RunProcessTestEmitter(object): def __init__( self, final_dir ): self._final_dir = final_dir def __call__( self, target, source, env ): program_file = os.path.join( self._final_dir, os.path.split( source[0].path )[1] ) target = [] target.append( stdout_file_name_from( program_file ) ) target.append( stderr_file_name_from( program_file ) ) target.append( report_file_name_from( program_file ) ) target.append( success_file_name_from( program_file ) ) return target, source class ProcessStdout(object): def __init__( self, show_test_output, log ): self._show_test_output = show_test_output self.log = open( log, "w" ) def __call__( self, line ): self.log.write( line + '\n' ) if self._show_test_output: sys.stdout.write( line + '\n' ) def __exit__( self, type, value, traceback ): if self.log: self.log.close() class ProcessStderr(object): def __init__( self, show_test_output, log ): self._show_test_output = show_test_output self.log = open( log, "w" ) def __call__( self, line ): self.log.write( line + '\n' ) if self._show_test_output: sys.stderr.write( line + '\n' ) def __exit__( self, type, value, traceback ): if self.log: self.log.close() class RunProcessTest(object): def __init__( self, expected ): self._expected = expected def __call__( self, target, source, env ): executable = str( source[0].abspath ) working_dir, test = os.path.split( executable ) program_path = source[0].path suite = env['build_dir'] if cuppa.build_platform.name() == "Windows": executable = '"' + executable + '"' test_command = executable test_suite = TestSuite.create( suite, env ) test_suite.enter_test( test, expected=self._expected ) show_test_output = env['show_test_output'] try: return_code = self._run_test( show_test_output, program_path, test_command, working_dir ) if return_code < 0: self.__write_file_to_stderr( stderr_file_name_from( program_path ) ) print >> sys.stderr, "cuppa: ProcessTest: Test was terminated by signal: ", -return_code test_suite.exit_test( test, 'aborted' ) elif return_code > 0: self.__write_file_to_stderr( stderr_file_name_from( program_path ) ) print >> sys.stderr, "cuppa: ProcessTest: Test returned with error code: ", return_code test_suite.exit_test( test, 'failed' ) else: test_suite.exit_test( test, 'passed' ) cuppa.test_report.cuppa_json.write_report( report_file_name_from( program_path ), test_suite.tests() ) if return_code: self._remove_success_file( success_file_name_from( program_path ) ) else: self._write_success_file( success_file_name_from( program_path ) ) return None except OSError, e: print >> sys.stderr, "Execution of [", test_command, "] failed with error: ", e return 1 def _write_success_file( self, file_name ): with open( file_name, "w" ) as success_file: success_file.write( "success" ) def _remove_success_file( self, file_name ): try: os.remove( file_name ) except: pass def _run_test( self, show_test_output, program_path, test_command, working_dir ): process_stdout = ProcessStdout( show_test_output, stdout_file_name_from( program_path ) ) process_stderr = ProcessStderr( show_test_output, stderr_file_name_from( program_path ) ) return_code = IncrementalSubProcess.Popen2( process_stdout, process_stderr, shlex.split( test_command ), cwd=working_dir ) return return_code def __write_file_to_stderr( self, file_name ): error_file = open( file_name, "r" ) for line in error_file: print >> sys.stderr, line error_file.close() PKý«þFkY¨ÞÃÃcuppa/cpp/run_gcov_coverage.py # Copyright Jamie Allsop 2011-2015 # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) #------------------------------------------------------------------------------- # RunGcovCoverage #------------------------------------------------------------------------------- # python standard library imports import os import shlex import re import itertools import glob from SCons.Script import Glob # construct imports import cuppa.progress from cuppa.output_processor import IncrementalSubProcess, command_available def offset_path( path, env ): build_dir = env['build_dir'] offset_dir = env['offset_dir'] path = offset_dir + os.path.sep + os.path.relpath( path, build_dir ) if path.startswith( "." + os.path.sep ): path = path[2:] return path def coverage_base_name( sconscript_file ): if sconscript_file.startswith( "." + os.path.sep ): sconscript_file = sconscript_file[2:] sconscript_file = sconscript_file.replace( ".", '' ) sconscript_file = sconscript_file.replace( "sconscript", '' ) sconscript_file = sconscript_file.replace( os.path.sep, '.' ) return sconscript_file + ".coverage" class WriteToString(object): def __init__( self ): self._output = [] def __call__( self, line ): self._output.append( line ) def string( self ): return "\n".join( self._output ) def run_command( command, working_dir ): print "cuppa: gcov: executing [{}]".format( command ) process_output = WriteToString() return_code = IncrementalSubProcess.Popen( process_output, shlex.split( command ), cwd=working_dir ) return return_code, process_output.string() class CoverageSuite(object): suites = {} @classmethod def create( cls, name, scons_env, final_dir ): if not name in cls.suites: cls.suites[name] = CoverageSuite( name, scons_env, final_dir ) return cls.suites[name] def __init__( self, name, scons_env, final_dir ): self._name = name self._scons_env = scons_env self._final_dir = final_dir cuppa.progress.NotifyProgress.register_callback( scons_env, self.on_progress ) self._suite = {} def on_progress( self, progress, sconscript, variant, env, target, source ): if progress == 'finished': self.exit_suite() del self.suites[self._name] def exit_suite( self ): env = self._scons_env self._run_gcovr( env['build_dir'], self._final_dir, env['working_dir'], env['sconscript_toolchain_build_dir'] ) def _run_gcovr( self, build_dir, output_dir, working_dir, sconscript_id ): command = 'gcovr -h' if not command_available( command ): print "cuppa: gcov: Skipping gcovr output as not available" return base_name = coverage_base_name( sconscript_id ) index_file = base_name + ".html" regex_filter = re.escape( os.path.join( build_dir, "" ) ) regex_filter = ".*" + regex_filter + ".*\.gcov" command = 'gcovr -g --gcov-filter="{}" -k -r . --html --html-details -o {}'.format( regex_filter, index_file ) return_code, output = run_command( command, working_dir ) new_index_file = os.path.join( output_dir, "coverage.html" ) try: os.rename( index_file, new_index_file ) except OSError as e: print "cuppa: gcov: Failed moving coverage file from [{}] to [{}] with error: {}".format( index_file, new_index_file, str(e) ) coverage_files = Glob( base_name + '*.html' ) for coverage_file in coverage_files: new_coverage_file = os.path.join( output_dir, str( coverage_file ) ) try: os.rename( str( coverage_file ), new_coverage_file ) except OSError as e: print "cuppa: gcov: Failed moving coverage file from [{}] to [{}] with error: {}".format( str( coverage_file ), new_coverage_file, str(e) ) print output class RunGcovCoverageEmitter(object): def __init__( self, program, final_dir ): self._program = program self._final_dir = final_dir self._program_id = '##' + os.path.split(str(program[0]))[1] def __call__( self, target, source, env ): for s in source: source_file = os.path.relpath( s.path, env['build_dir'] ) offset_source = offset_path( s.path, env ) gcov_source_path = offset_source.replace( os.path.sep, '#' ) gcno_file = os.path.splitext( source_file )[0] + '.gcno' gcda_file = os.path.splitext( source_file )[0] + '.gcda' gcov_log = source_file + self._program_id + '_gcov.log' env.Clean( source_file, [gcno_file, gcda_file] ) target.append( gcov_log ) gcov_files = Glob( gcov_source_path + '*' ) env.Clean( source_file, gcov_files ) env.Clean( source_file, os.path.join( self._final_dir, "coverage.html" ) ) base_name = coverage_base_name( env['sconscript_toolchain_build_dir'] ) coverage_files = Glob( os.path.join( self._final_dir, base_name + '*.html' ) ) env.Clean( source_file, coverage_files ) return target, source def iter_grouped( items, step=2, fillvalue=None ): it = iter( items ) return itertools.izip_longest( *[it]*step, fillvalue=fillvalue ) class RunGcovCoverage(object): def __init__( self, program, final_dir ): self._program = program self._final_dir = final_dir self._program_id = '##' + os.path.split(str(program[0]))[1] def __call__( self, target, source, env ): for s, t in itertools.izip( source, target ): gcov_path = os.path.splitext( os.path.splitext( t.path )[0] )[0] gcov_log = t.path self._run_gcov( env, s.path, gcov_path, gcov_log ) return None def _run_gcov( self, env, source_path, gcov_path, gcov_log_path ): working_dir = env['working_dir'] build_dir = env['build_dir'] final_dir = self._final_dir if not os.path.isabs( self._final_dir ): final_dir = os.path.normpath( os.path.join( build_dir, self._final_dir ) ) suite_name = working_dir coverage_suite = CoverageSuite.create( suite_name, env, final_dir ) command = 'gcov -o {} -l -p -r -c -b {}'.format( gcov_path, source_path ) return_code, output = run_command( command, working_dir ) if return_code == 0: gcov_source_path = source_path.replace( os.path.sep, '#' ) gcov_files = glob.glob( gcov_source_path + '*gcov' ) for gcov_file in gcov_files: filename, ext = os.path.splitext( str(gcov_file) ) filename = filename + self._program_id + ext new_gcov_file = os.path.join( build_dir, filename ) try: os.rename( str(gcov_file), new_gcov_file ) except OSError as e: print "cuppa: gcov: Failed moving gcov file [{}] to [{}] with error: {}".format( str(gcov_file), new_gcov_file, str(e) ) with open( gcov_log_path, 'w' ) as summary_file: summary_file.write( output ) else: print output os.remove( gcov_log_path ) PK•c×F•Ý«/îBîB$cuppa/cpp/create_version_file_cpp.py # Copyright Jamie Allsop 2011-2015 # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) #------------------------------------------------------------------------------- # CreateVersionFileCpp #------------------------------------------------------------------------------- import os from os.path import splitext, relpath, sep from SCons.Script import File import cuppa.location def offset_path( path, env ): build_dir = env['build_dir'] offset_dir = env['offset_dir'] return offset_dir + sep + relpath( path, build_dir) def hpp_from_cpp( cpp_file ): return splitext( cpp_file )[0] + '.hpp' def txt_from_cpp( cpp_file ): return splitext( cpp_file )[0] + '.txt' class CreateVersionHeaderCpp: def __init__( self, env, namespaces, version, location ): self.__env = env self.__namespace_guard = "_".join( namespaces ) self.__namespaces = namespaces self.__version = version self.__location = location self.__variant = self.__env['variant'].name() self.__working_dir = os.path.join( env['base_path'], env['build_dir'] ) if not os.path.exists( self.__working_dir ): os.makedirs( self.__working_dir ) def __call__( self, target, source, env ): cpp_file = offset_path( target[0].path, env ) hpp_file = hpp_from_cpp( cpp_file ) txt_file = txt_from_cpp( cpp_file ) output_dir = os.path.split( hpp_file )[0] if output_dir: output_dir = os.path.join( self.__working_dir, output_dir ) if not os.path.exists( output_dir ): os.makedirs( output_dir ) version_hpp = open( os.path.join( self.__working_dir, hpp_file ), "w" ) version_hpp.write( get_build_identity_header( self.__namespace_guard, self.__namespaces ) ) version_hpp.close() version_txt = open( os.path.join( self.__working_dir, txt_file ), "w" ) version_txt.write( get_build_identity_txt( self.__version, relpath( env['base_path'], self.__location), self.__namespaces ) ) version_txt.close() target[0] = File( cpp_file ) source.append( hpp_file ) source.append( txt_file ) return target, source def get_build_identity_txt( version, location, namespaces ): lines = [] lines += [ '// v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v\n' '// Version File for product version [ ' + version + ' ]\n' '// Location for dependency versions [ ' + location + ' ]\n' '// Namespace [ ' + "::".join( namespaces ) + ' ]\n' '// v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v\n' ] return "\n".join( lines ) def get_build_identity_header( namespace_guard, namespaces ): lines = [] lines += [ '// G G G G G G G G G G G G G G G G G G G G G G G G G G G G G G G G G G G G G G G\n' '#ifndef INCLUDED_' + namespace_guard.upper() + '_BUILD_GENERATED_VERSION_HPP\n' '#define INCLUDED_' + namespace_guard.upper() + '_BUILD_GENERATED_VERSION_HPP\n' '// G G G G G G G G G G G G G G G G G G G G G G G G G G G G G G G G G G G G G G G\n' '\n' '// I I I I I I I I I I I I I I I I I I I I I I I I I I I I I I I I I I I I I I I\n' '#include \n' '#include \n' '#include \n' '// I I I I I I I I I I I I I I I I I I I I I I I I I I I I I I I I I I I I I I I\n' '\n' '// n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n' ] for namespace in namespaces: lines += [ 'namespace ' + namespace + ' {' ] lines += [ 'namespace build {\n' '// n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n\n' '\n' 'class identity\n' '{\n' 'public:\n' '\n' ' typedef std::string string_t;\n' ' typedef std::vector< string_t > revisions_t;\n' '\n' 'private:\n' '\n' ' struct dependency\n' ' {\n' ' dependency()\n' ' {\n' ' }\n' '\n' ' dependency( const string_t& Name,\n' ' const string_t& Version,\n' ' const string_t& Repository,\n' ' const string_t& Branch,\n' ' const revisions_t& Revisions )\n' ' : name ( Name )\n' ' , version ( Version )\n' ' , repository ( Repository )\n' ' , branch ( Branch )\n' ' , revisions ( Revisions )\n' ' {\n' ' }\n' '\n' ' string_t name;\n' ' string_t version;\n' ' string_t repository;\n' ' string_t branch;\n' ' revisions_t revisions;\n' ' };\n' '\n' 'public:\n' '\n' ' typedef dependency dependency_t;\n' ' typedef std::map< string_t, dependency > dependencies_t;\n' '\n' 'public:\n' ] lines += [ function_declaration_from_variable( 'product_version' ) ] lines += [ function_declaration_from_variable( 'product_repository' ) ] lines += [ function_declaration_from_variable( 'product_branch' ) ] lines += [ function_declaration_from_variable( 'product_revision' ) ] lines += [ function_declaration_from_variable( 'build_variant' ) ] lines += [ function_declaration_from_variable( 'build_time' ) ] lines += [ function_declaration_from_variable( 'build_user' ) ] lines += [ function_declaration_from_variable( 'build_host' ) ] lines += [ function_declaration_dependencies() ] lines += [ function_declaration_report() ] lines += [ '\nprivate:\n' ' static const dependencies_t Dependencies_;\n' ' static const string_t Report_;\n' '};\n' '\n' '// n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n\n' '} //end namespace build' ] for namespace in namespaces: lines += [ '} //end namespace ' + namespace ] lines += [ '// n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n\n' '\n' '// G G G G G G G G G G G G G G G G G G G G G G G G G G G G G G G G G G G G G G G\n' '#endif\n' '// G G G G G G G G G G G G G G G G G G G G G G G G G G G G G G G G G G G G G G G\n' '\n' ] return "\n".join( lines ) def function_declaration_from_variable( name ): lines = [] lines += [ ' static const char* ' + name + '();' ] return "\n".join( lines ) def function_declaration_dependencies(): lines = [] lines += [ ' static const dependencies_t& dependencies();' ] return "\n".join( lines ) def function_declaration_report(): lines = [] lines += [ ' static const char* report();' ] return "\n".join( lines ) class CreateVersionFileCpp: def __init__( self, env, namespaces, version, location ): self.__env = env self.__namespace_guard = "_".join( namespaces ) self.__namespaces = namespaces self.__version = version self.__location = location location = cuppa.location.Location( env, location ) self.__repository = location.repository() self.__branch = location.branch() self.__revision = location.revisions()[0] self.__variant = self.__env['variant'].name() def __call__( self, target, source, env ): cpp_file = target[0].path hpp_file = hpp_from_cpp( cpp_file ) #print "Create CPP Version File at [" + cpp_file + "]" version_cpp = open( cpp_file, "w" ) version_cpp.write( self.get_build_identity_source( env['BUILD_WITH'], hpp_file ) ) version_cpp.close() return None def function_definition_from_variable( self, name, variable ): lines = [] lines += [ '\nconst char* identity::' + name + '()' ] lines += [ '{' ] lines += [ ' return "' + str( variable ) + '";' ] lines += [ '}\n' ] return "\n".join( lines ) def function_definition_dependencies( self ): lines = [] lines += [ '\nconst identity::dependencies_t& identity::dependencies()\n' '{\n' ' return Dependencies_;\n' '}\n' ] return "\n".join( lines ) def initialise_dependencies_definition( self, dependencies ): lines = [] lines += [ '\nidentity::dependencies_t initialise_dependencies()\n' '{\n' ' typedef identity::dependencies_t dependencies_t;\n' ' typedef identity::dependency_t dependency_t;\n' ' typedef identity::revisions_t revisions_t;\n' ' dependencies_t Dependencies;' ] for name in dependencies: if name in self.__env['dependencies']: dependency = self.__env['dependencies'][name] lines += [ ' Dependencies[ "' + name + '" ] = dependency_t( "' + dependency.name() + '", "' + dependency.version() + '", "' + dependency.repository() + '", "' + dependency.branch() + '", revisions_t() );' ] try: if callable( getattr( dependency, 'revisions' ) ): revisions = dependency.revisions() if revisions: for revision in revisions: lines += [ ' Dependencies[ "' + name + '" ].revisions.push_back( "' + revision + '" );' ] except AttributeError: pass lines += [ ' return Dependencies;\n' '}\n' '\n' 'const identity::dependencies_t identity::Dependencies_ = initialise_dependencies();\n' ] return "\n".join( lines ) def function_definition_report( self ): lines = [] lines += [ '\nconst char* identity::report()' ] lines += [ '{' ] lines += [ ' return Report_.c_str();' ] lines += [ '}\n' ] return "\n".join( lines ) def initialise_report_definition( self ): lines = [] lines += [ '\nidentity::string_t initialise_report()\n' '{\n' ' std::ostringstream Report;\n' '\n' ' Report\n' ' << "Product:\\n"\n' ' " |- Version = " << identity::product_version() << "\\n"\n' ' " |- Repository = " << identity::product_repository() << "\\n"\n' ' " |- Branch = " << identity::product_branch() << "\\n"\n' ' " +- Revision = " << identity::product_revision() << "\\n"\n' ' "Build:\\n"\n' ' " |- Variant = " << identity::build_variant() << "\\n"\n' ' " |- Time = " << identity::build_time() << "\\n"\n' ' " |- User = " << identity::build_user() << "\\n"\n' ' " +- Host = " << identity::build_host() << "\\n";\n' '\n' ' if( !identity::dependencies().empty() )\n' ' {\n' ' Report << "Dependencies:\\n";\n' ' }\n' '\n' ' identity::dependencies_t::const_iterator Dependency = identity::dependencies().begin();\n' ' identity::dependencies_t::const_iterator End = identity::dependencies().end();\n' '\n' ' for( ; Dependency != End; ++Dependency )\n' ' {\n' ' Report\n' ' << " " << Dependency->second.name << "\\n"\n' ' << " |- Version = " << Dependency->second.version << "\\n"\n' ' << " |- Repository = " << Dependency->second.repository << "\\n"\n' ' << " |- Branch = " << Dependency->second.branch << "\\n";\n' '\n' ' identity::revisions_t::const_iterator Revision = Dependency->second.revisions.begin();\n' ' identity::revisions_t::const_iterator End = Dependency->second.revisions.end();\n' '\n' ' for( ; Revision != End; )\n' ' {\n' ' identity::string_t Value( *Revision );\n' ' if( ++Revision != End )\n' ' {\n' ' Report << " |";\n' ' }\n' ' else\n' ' {\n' ' Report << " +";\n' ' }\n' ' Report << "- Revision = " << Value << "\\n";\n' ' }\n' ' }\n' '\n' ' return Report.str();\n' '}\n' '\n' 'const identity::string_t identity::Report_ = initialise_report();' ] return "\n".join( lines ) def get_build_identity_source( self, dependencies, header_file ): from datetime import datetime from getpass import getuser from socket import gethostname build_time = datetime.utcnow() build_user = getuser() build_host = gethostname() lines = [] lines += [ '// I I I I I I I I I I I I I I I I I I I I I I I I I I I I I I I I I I I I I I I\n' '// Self Include' ] lines += [ '#include "' + header_file + '"' ] lines += [ '' '// C++ Standard Includes\n' '#include \n' '\n' '// I I I I I I I I I I I I I I I I I I I I I I I I I I I I I I I I I I I I I I I\n' '\n' '// n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n' ] for namespace in self.__namespaces: lines += [ 'namespace ' + namespace + ' {' ] lines += [ 'namespace build {\n' '// n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n\n' ] lines += [ self.function_definition_from_variable( 'product_version', self.__version ) ] lines += [ self.function_definition_from_variable( 'product_repository', self.__repository ) ] lines += [ self.function_definition_from_variable( 'product_branch', self.__branch ) ] lines += [ self.function_definition_from_variable( 'product_revision', self.__revision ) ] lines += [ self.function_definition_from_variable( 'build_variant', self.__variant ) ] lines += [ self.function_definition_from_variable( 'build_time', build_time ) ] lines += [ self.function_definition_from_variable( 'build_user', build_user ) ] lines += [ self.function_definition_from_variable( 'build_host', build_host ) ] lines += [ self.initialise_dependencies_definition( dependencies ) ] lines += [ self.function_definition_dependencies() ] lines += [ self.initialise_report_definition() ] lines += [ self.function_definition_report() ] lines += [ '\n// n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n\n' '} //end namespace build' ] for namespace in self.__namespaces: lines += [ '} //end namespace ' + namespace ] lines += [ '// n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n\n' '\n' ] return "\n".join( lines ) PKÈ»SGgž¿¿%cuppa-0.9.0.dist-info/DESCRIPTION.rstCuppa ===== A simple, extensible build system for use with `Scons `__. **Cuppa** is designed to leverage the capabilities of Scons, while allowing developers to focus on the task of describing what needs to be built. In general **cuppa** supports ``make`` like usage on the command-line. That is developers can simply write: .. code:: sh scons -D and have Scons "do the right thing"; building targets for any ``sconscript`` files found in the current directory. **Cuppa** can be installed as a normal python package or installed locally into a ``site_scons`` directory allowing it to be effortlessly integrated into any Scons setup. Note: ``-D`` tells ``scons`` to look for an ``sconstruct`` file in the current or in parent directories and if it finds one execute the ``sconscript`` files as if called from that directory. This ensures everything works as expected. For more details refer to the `Scons documentation `__ Quick Intro ----------- Get **cuppa** ~~~~~~~~~~~~~ The simpest way to get **cuppa** is to ``pip install`` it using: :: pip install cuppa Sample ``sconstruct`` file ~~~~~~~~~~~~~~~~~~~~~~~~~~ Let's look at a minimal ``sconstruct`` that makes use of **cuppa**. It could look like this: .. code:: python # Pull in all the Cuppa goodies.. import cuppa # Call sconscripts to do the work cuppa.run() Calling the ``run`` method in the ``cuppa`` module starts the build process calling ``sconscript`` files. Sample ``sconscript`` file ~~~~~~~~~~~~~~~~~~~~~~~~~~ Here is an example ``sconscript`` file that builds all \*.cpp files in the directory where it resides: .. code:: python Import( 'env' ) # Build all *.cpp source files as executables for Source in env.GlobFiles('*.cpp'): env.Build( Source[:-4], Source ) The ``env.Build()`` method is provided by **cuppa** and does essentially what ``env.Program()`` does but in addition is both toolchain and variant aware, and further can provide notifications on progress. Note: Source[:-4] simply strips off the file extension ``.cpp``, that is, the last 4 characters of the file name. If our ``sconscript`` file was for a directory containing \*.cpp files that are actually tests then we could instead write the ``sconscript`` file as: .. code:: python Import( 'env' ) # Build all *.cpp source files as executables to be run as tests for Source in env.GlobFiles('*.cpp'): env.BuildTest( Source[:-4], Source ) The ``env.BuildTest()`` method is provided by **cuppa** and builds the sources specified as ``env.Build()`` does. However, in addition, passing ``--test`` on the command-line will also result in the executable produced being run by a **runner**. The default test runner simply treats each executable as a test case and each directory or executables as a test suite. If the process executes cleanly the test passed, if not it failed. To run this on the command-line we would write: .. code:: sh scons -D --test If we only want to build and test *debug* executables we can instead write this: .. code:: sh scons -D --dbg --test Or for release only pass ``--rel``. **cuppa** also makes it easy to work with dependencies. For example, if `boost `__ was a default dependency for all your ``sconscript`` files you could write your sconstruct file as follows: .. code:: python import cuppa cuppa.run( default_options = { 'boost-home': '' }, default_dependencies = [ 'boost' ] ) This will automatically ensure that necessary includes and other compile options are set for the boost version that is found at ``boost-home``. If you need to link against specific boost libraries this can also be done in the sconscript file as follows: .. code:: python Import('env') Test = 'my_complex_test' Sources = [ Test + '.cpp' ] env.AppendUnique( STATICLIBS = [ env.BoostStaticLibrary( 'system' ), env.BoostStaticLibrary( 'log' ), env.BoostStaticLibrary( 'thread' ), env.BoostStaticLibrary( 'timer' ), env.BoostStaticLibrary( 'chrono' ), env.BoostStaticLibrary( 'filesystem' ), ] ) env.BuildTest( Test, Sources ) The ``BoostStaticLibrary()`` method ensures that the library is built in the correct build variant as required. If you preferred to use dynamic linking then that can also be achieved using ``BoostSharedLibrary()``. The point is the complexities of using `boost `__ as a dependency are encapsulated and managed separately from the scontruct and sconscript files allowing developers to focus on intent not method. Design Principles ----------------- **cuppa** has been written primarily to provide a clean and structured way to leverage the power of Scons without the usual problems of hugely complex ``scontruct`` files that diverge between projects. Key goals of **cuppa** are: - minimise the need for adding logic into ``sconscript`` files, keeping them as declarative as possible. - allow declarative ``sconscript``\ s that are both much clearer and significantly simpler than the equivalent ``make`` file, without the need to learn a whole new scripting language like ``make`` or ``cmake``. - provide a clear structure for extending the facilities offered by **cuppa** - provide a clear vocabulary for building projects - codify Scons best practices into **cuppa** itself so that users just need to call appropriate methods knowing that **cuppa** will do the right thing with their intent - provide a framework that allows experts to focus on providing facilities for others to use. Write once, use everywhere. For example one person who knows how best to make `boost `__ available as a dependency can manage that dependency and allow others to use it seamlessly. More Details ------------ For more details refer to the `project homepage `__. Acknowledgements ---------------- This work is based on the build system used in `clearpool.io `__ during development of its next generation exchange platform. PKÆ»SG‚û¸‡‡&cuppa-0.9.0.dist-info/entry_points.txt[cuppa.method.plugins] cuppa.test_report.generate_bitten_report = cuppa.test_report.generate_bitten_report:GenerateBittenReportMethod PKÈ»SGòúïóÖÖ#cuppa-0.9.0.dist-info/metadata.json{"classifiers": ["Topic :: Software Development :: Build Tools", "Intended Audience :: Developers", "Development Status :: 4 - Beta", "License :: OSI Approved", "Operating System :: OS Independent", "Programming Language :: Python :: 2"], "extensions": {"python.details": {"contacts": [{"name": "ja11sop", "role": "author"}], "document_names": {"description": "DESCRIPTION.rst"}, "project_urls": {"Home": "https://github.com/ja11sop/cuppa"}}, "python.exports": {"cuppa.method.plugins": {"cuppa.test_report.generate_bitten_report": "cuppa.test_report.generate_bitten_report:GenerateBittenReportMethod"}}}, "extras": [], "generator": "bdist_wheel (0.24.0)", "keywords": ["scons", "build", "c", ""], "license": "Boost Software License 1.0 - http://www.boost.org/LICENSE_1_0.txt", "metadata_version": "2.0", "name": "cuppa", "run_requires": [{"requires": ["colorama", "gcovr", "lxml", "grip"]}], "summary": "Cuppa, an extension package to simplify and extend Scons", "version": "0.9.0"}PKÆ»SGÜÈm­#cuppa-0.9.0.dist-info/top_level.txtcuppa PKÈ»SG4»´Ø\\cuppa-0.9.0.dist-info/WHEELWheel-Version: 1.0 Generator: bdist_wheel (0.24.0) Root-Is-Purelib: true Tag: py2-none-any PKÈ»SGIoL ddcuppa-0.9.0.dist-info/METADATAMetadata-Version: 2.0 Name: cuppa Version: 0.9.0 Summary: Cuppa, an extension package to simplify and extend Scons Home-page: https://github.com/ja11sop/cuppa Author: ja11sop Author-email: UNKNOWN License: Boost Software License 1.0 - http://www.boost.org/LICENSE_1_0.txt Keywords: scons,build,c++ Platform: UNKNOWN Classifier: Topic :: Software Development :: Build Tools Classifier: Intended Audience :: Developers Classifier: Development Status :: 4 - Beta Classifier: License :: OSI Approved Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python :: 2 Requires-Dist: colorama Requires-Dist: gcovr Requires-Dist: lxml Requires-Dist: grip Cuppa ===== A simple, extensible build system for use with `Scons `__. **Cuppa** is designed to leverage the capabilities of Scons, while allowing developers to focus on the task of describing what needs to be built. In general **cuppa** supports ``make`` like usage on the command-line. That is developers can simply write: .. code:: sh scons -D and have Scons "do the right thing"; building targets for any ``sconscript`` files found in the current directory. **Cuppa** can be installed as a normal python package or installed locally into a ``site_scons`` directory allowing it to be effortlessly integrated into any Scons setup. Note: ``-D`` tells ``scons`` to look for an ``sconstruct`` file in the current or in parent directories and if it finds one execute the ``sconscript`` files as if called from that directory. This ensures everything works as expected. For more details refer to the `Scons documentation `__ Quick Intro ----------- Get **cuppa** ~~~~~~~~~~~~~ The simpest way to get **cuppa** is to ``pip install`` it using: :: pip install cuppa Sample ``sconstruct`` file ~~~~~~~~~~~~~~~~~~~~~~~~~~ Let's look at a minimal ``sconstruct`` that makes use of **cuppa**. It could look like this: .. code:: python # Pull in all the Cuppa goodies.. import cuppa # Call sconscripts to do the work cuppa.run() Calling the ``run`` method in the ``cuppa`` module starts the build process calling ``sconscript`` files. Sample ``sconscript`` file ~~~~~~~~~~~~~~~~~~~~~~~~~~ Here is an example ``sconscript`` file that builds all \*.cpp files in the directory where it resides: .. code:: python Import( 'env' ) # Build all *.cpp source files as executables for Source in env.GlobFiles('*.cpp'): env.Build( Source[:-4], Source ) The ``env.Build()`` method is provided by **cuppa** and does essentially what ``env.Program()`` does but in addition is both toolchain and variant aware, and further can provide notifications on progress. Note: Source[:-4] simply strips off the file extension ``.cpp``, that is, the last 4 characters of the file name. If our ``sconscript`` file was for a directory containing \*.cpp files that are actually tests then we could instead write the ``sconscript`` file as: .. code:: python Import( 'env' ) # Build all *.cpp source files as executables to be run as tests for Source in env.GlobFiles('*.cpp'): env.BuildTest( Source[:-4], Source ) The ``env.BuildTest()`` method is provided by **cuppa** and builds the sources specified as ``env.Build()`` does. However, in addition, passing ``--test`` on the command-line will also result in the executable produced being run by a **runner**. The default test runner simply treats each executable as a test case and each directory or executables as a test suite. If the process executes cleanly the test passed, if not it failed. To run this on the command-line we would write: .. code:: sh scons -D --test If we only want to build and test *debug* executables we can instead write this: .. code:: sh scons -D --dbg --test Or for release only pass ``--rel``. **cuppa** also makes it easy to work with dependencies. For example, if `boost `__ was a default dependency for all your ``sconscript`` files you could write your sconstruct file as follows: .. code:: python import cuppa cuppa.run( default_options = { 'boost-home': '' }, default_dependencies = [ 'boost' ] ) This will automatically ensure that necessary includes and other compile options are set for the boost version that is found at ``boost-home``. If you need to link against specific boost libraries this can also be done in the sconscript file as follows: .. code:: python Import('env') Test = 'my_complex_test' Sources = [ Test + '.cpp' ] env.AppendUnique( STATICLIBS = [ env.BoostStaticLibrary( 'system' ), env.BoostStaticLibrary( 'log' ), env.BoostStaticLibrary( 'thread' ), env.BoostStaticLibrary( 'timer' ), env.BoostStaticLibrary( 'chrono' ), env.BoostStaticLibrary( 'filesystem' ), ] ) env.BuildTest( Test, Sources ) The ``BoostStaticLibrary()`` method ensures that the library is built in the correct build variant as required. If you preferred to use dynamic linking then that can also be achieved using ``BoostSharedLibrary()``. The point is the complexities of using `boost `__ as a dependency are encapsulated and managed separately from the scontruct and sconscript files allowing developers to focus on intent not method. Design Principles ----------------- **cuppa** has been written primarily to provide a clean and structured way to leverage the power of Scons without the usual problems of hugely complex ``scontruct`` files that diverge between projects. Key goals of **cuppa** are: - minimise the need for adding logic into ``sconscript`` files, keeping them as declarative as possible. - allow declarative ``sconscript``\ s that are both much clearer and significantly simpler than the equivalent ``make`` file, without the need to learn a whole new scripting language like ``make`` or ``cmake``. - provide a clear structure for extending the facilities offered by **cuppa** - provide a clear vocabulary for building projects - codify Scons best practices into **cuppa** itself so that users just need to call appropriate methods knowing that **cuppa** will do the right thing with their intent - provide a framework that allows experts to focus on providing facilities for others to use. Write once, use everywhere. For example one person who knows how best to make `boost `__ available as a dependency can manage that dependency and allow others to use it seamlessly. More Details ------------ For more details refer to the `project homepage `__. Acknowledgements ---------------- This work is based on the build system used in `clearpool.io `__ during development of its next generation exchange platform. PKÈ»SGVN?³cccuppa-0.9.0.dist-info/RECORDcuppa/__init__.py,sha256=gc-hRMWYAeSFR5j1O3535M8cPZGg1VMomFZZHQZz8FA,516 cuppa/tree.py,sha256=5z98sBZ3Lyez8MHeVm5v1jJuCNl3yxYxRJzUAr6NpLA,1930 cuppa/location.py,sha256=Rj62rV8rlE10MvHqFrsyz2kNROQjcNe6VFHtYHKBRNk,15600 cuppa/log.py,sha256=ybDF7rnmvEjHRGiPRyfDCLCiQ61iPvWBkLCIumIpYJ0,2833 cuppa/timer.py,sha256=pYY-4NwZSD95SSuztwPdcmwnGoF-458mh2za7T6P-nw,3996 cuppa/build_with_header_library.py,sha256=__oC5BuyeSbVIWL8Auyyi2Bl4B0Nhcb2YAY3gO5-mVI,5155 cuppa/path.py,sha256=MFCZ2NXlfbO8SwujNKPM-tLzgObhdm1E6olbNYZkrXc,1145 cuppa/progress.py,sha256=qy8MnfGty1jPjh8uZZunjiyJQcTI3YRhS9TQVvfR92k,3568 cuppa/colourise.py,sha256=BpAvUr7OOWAA8USlak2g3wyRTr6NxhvbfThgnD_uCQw,7279 cuppa/configure.py,sha256=kq1KVV_Nk5HkbK6oGaVUNcCOG03_bC3G1WERHVRc6P0,7592 cuppa/build_platform.py,sha256=teIDSDNsnKm8D5XKoNl4QSEaPRLzhsL23xiRumRW698,2180 cuppa/recursive_glob.py,sha256=ZNjITAiUgow67-MUTqL1Qiwo7JsKval1Hgb9YbHm0Kk,2235 cuppa/options.py,sha256=F5YJ7GflfrxXWX_1MT9IFW3fTtqBRRsZ9KyIQ0FHbdM,610 cuppa/VERSION,sha256=nYyU8a0-qWseKsSRT9pMuTx2tKPg2Mxt2JdtbAsifRU,6 cuppa/version.py,sha256=j1er-79-d6RAP-GysQzvlNp3fzxPQx3UqVYG43P_t-s,1360 cuppa/output_processor.py,sha256=A5DYSis91oxmP5Iy7y872NzlNb6SPb-9DBwHpeHxJMU,12073 cuppa/utility.py,sha256=7-6A_b_6iTpr9s7Es_TfI_YMXeKQuGuGi8tNu2eQT0o,584 cuppa/core.py,sha256=6HQut8M3cXkKNdAO0Ipve8mCs3SkoEswOIzPQeDo6xY,34781 cuppa/platforms/__init__.py,sha256=OrSC_AV10c5wdwAnQjh3ys-s3KS_2__r9tFMLDC1TRU,298 cuppa/platforms/linux.py,sha256=5xVw6fByF9JYLfLdBsJ4D-Ow3bHjxBzr95HRNHQMYyU,3838 cuppa/platforms/darwin.py,sha256=jq-Lo1iied-VPlzRtqk4XFR5TQjBdGE-UtciR4MrEfA,2983 cuppa/platforms/windows.py,sha256=omjdiT9-m-wr_lv48xHuI1O8RSKu9ImF9B2Z1cPleXs,2122 cuppa/project_generators/__init__.py,sha256=OrSC_AV10c5wdwAnQjh3ys-s3KS_2__r9tFMLDC1TRU,298 cuppa/project_generators/codeblocks.py,sha256=ogNYD5mCWXXIqcdFm57RqlbWtSwwrfsX2PqlERFEfNQ,16559 cuppa/profiles/__init__.py,sha256=OrSC_AV10c5wdwAnQjh3ys-s3KS_2__r9tFMLDC1TRU,298 cuppa/methods/coverage.py,sha256=o4Xa7kUhY0CiVLivMOza5c5Hzx2FhrOrMukK6ppB4hk,1102 cuppa/methods/build_with.py,sha256=zO22MxfJ6CZW0cLUFUkFSqgCPdigD4bKLnOo1IDEbXg,1929 cuppa/methods/using.py,sha256=wcbjdiy4O_3g4e9JLcMHQY9tH-BYvw_d34ERJstcT5M,782 cuppa/methods/toolchain.py,sha256=q_U-fe0rddNT5668r9C78wh6CXyBsy6tku78JVuVdnQ,777 cuppa/methods/relative_recursive_glob.py,sha256=4aERKijZAgujMbV1iwuNDQpVQ-I2iE0h7fu0E-UWk48,2124 cuppa/methods/__init__.py,sha256=OrSC_AV10c5wdwAnQjh3ys-s3KS_2__r9tFMLDC1TRU,298 cuppa/methods/remove_flags.py,sha256=Dbal4Yq0uhiq7BYGcKrkQEEC4EVmMsa1YMGb7WNAP7c,1124 cuppa/methods/target_from.py,sha256=gYUarivbXL80q_1AsG-MDkifnCj3CTeODfuF0pkK-Nc,699 cuppa/methods/stdcpp.py,sha256=E8-PlyFfuKaEnF3hfjoDi329MBWLChQclzTwrBbEPYI,1611 cuppa/methods/test.py,sha256=0FG5tNc1UWMGN31qa6gqmNxw6KZnGDyVH2dShzAdr2A,1694 cuppa/methods/build_test.py,sha256=5uTh892zwovjtMdud9Sa-VnEFBt54n8qKBo1QmqTsK4,1833 cuppa/methods/compile.py,sha256=6dWBWXkoPuoTzc2dO73QcQx5cnW5P_43OJzNMTHbU4M,1079 cuppa/methods/build.py,sha256=TcH8UJ6V40BkqQwePw4pox24ZYwd5bpRJwt5arr7hbk,1859 cuppa/methods/replace_flags.py,sha256=WNIyb_OvV24WcLieWqVeMnnDLNhkVh39E5JEKviSULw,700 cuppa/methods/create_version.py,sha256=Ml1l6DYa3A-OIlvwVJtoAGPmiLOu7nhhjI27JsKY2gI,1113 cuppa/methods/markdown_to_html.py,sha256=aOCTygtkSGCd6ub9AaEjnpiRXSD95EtrhytDPwqTBc0,1934 cuppa/methods/build_library.py,sha256=nJh3pa8aeIQwUMRPvEU--EVRr6B-GMyJUCFWNbx5vYI,1337 cuppa/methods/build_profile.py,sha256=DaMsRZJxQRv8vrwoPYsj_AtniD19SphKOOsH2eFH9UE,1205 cuppa/variants/dbg.py,sha256=HvcDKlUBrx_Jkb9bGq8hVKJCirYNHSiNN6PoVeiUbjM,774 cuppa/variants/__init__.py,sha256=OrSC_AV10c5wdwAnQjh3ys-s3KS_2__r9tFMLDC1TRU,298 cuppa/variants/cov.py,sha256=iI9v4sWj3M7-_rqiqGDk6nSmkujZ3dLeHtswVeIbKj0,822 cuppa/variants/test.py,sha256=sYwaQshL7M4osWAbGSTA3-gexjMwmTnt_qfcOP2509U,782 cuppa/variants/rel.py,sha256=DKOa5Jl1AFYK4UJOxwvhn29GepFBfCmN1d9D0Dhy_Ko,788 cuppa/dependencies/__init__.py,sha256=OrSC_AV10c5wdwAnQjh3ys-s3KS_2__r9tFMLDC1TRU,298 cuppa/dependencies/build_with_qt4.py,sha256=y8Tmg5wSSAaH_uiqYWIL0kCOmSLVj8fN_mC3MjhriN0,4184 cuppa/dependencies/build_with_quince.py,sha256=4Gg8f-mvgqCvkejQYS69lLPoPl5Df2giawt6JkQ4M-Y,12776 cuppa/dependencies/build_with_boost.py,sha256=_Sv_2etnMHlouJ1aJbZEfovqQ4eNkLF2OPPbqMtF_58,39057 cuppa/dependencies/build_with_qt5.py,sha256=_KIYwFBRo_7Nspi7ZMRzHVz2XRpcL9mwAi6du2mSzfw,4102 cuppa/dependencies/boost/__init__.py,sha256=4W8VliAYUP1KY2gLJ_YDy2TmcXYVm-PY7XikQD_bFwA,2 cuppa/dependencies/boost/boost_test_patch.diff,sha256=AKahZU-fEukQU9Akr5_gmATvrzUOOZ48jIckq7_7iAc,36915 cuppa/test_report/__init__.py,sha256=4W8VliAYUP1KY2gLJ_YDy2TmcXYVm-PY7XikQD_bFwA,2 cuppa/test_report/generate_bitten_report.py,sha256=vl9SaPj2NTaB6K6tI3BerjP6o-2ERFJ9ICnsfAgCcfw,3243 cuppa/test_report/cuppa_json.py,sha256=1oVLEaUN81J-E4r2qeZ84lSFbjNJ9lzWhASN66OmuR0,1409 cuppa/toolchains/clang.py,sha256=bLorwNC6wJhFw8X2GwQMa33AWm6GGa6VMT0KwlMYZJI,21442 cuppa/toolchains/__init__.py,sha256=OrSC_AV10c5wdwAnQjh3ys-s3KS_2__r9tFMLDC1TRU,298 cuppa/toolchains/cl.py,sha256=lwRhKsSs06b0-b_WCzjr8e56grlZMuoJ3uRH3r3A6fM,11018 cuppa/toolchains/gcc.py,sha256=RfbukYQC-CFmKBuNDal8H8NFMJh0XyinBl4z3e1dAU0,25400 cuppa/modules/__init__.py,sha256=_J9QQLbV3rEEW2zq_4O8ZDAGiWp-kWwn3_6DN9wdl3g,212 cuppa/modules/registration.py,sha256=7Fzb_fH2MQLVc7Fae1ZCMNtQyuBMwuFS7p1ijzv2M-w,3847 cuppa/scms/subversion.py,sha256=RpajLcRpLtd1Cw-5Mv_eqFcDIKQyEcvRkxl1S7bLDYs,1726 cuppa/scms/__init__.py,sha256=2bcw9YCEUlyvy-sFAU8QaDVn--7Bd2VAHwjSAWKGN1k,211 cuppa/scms/mercurial.py,sha256=itzasF_xp0Mh9yJCYvGehDgMJWLyDja_qk3mKI03ets,1927 cuppa/scms/git.py,sha256=6zArRxHL-CbE94o0n-m8FaasUGbQtwCD3rhpZbuQpoU,1685 cuppa/cpp/run_patched_boost_test.py,sha256=uhZUmkbrSp-u6zEdQs5ZG0VT2WwLvk2BV2HLVRkB8LM,22192 cuppa/cpp/__init__.py,sha256=_J9QQLbV3rEEW2zq_4O8ZDAGiWp-kWwn3_6DN9wdl3g,212 cuppa/cpp/run_boost_test.py,sha256=FPequnCCqE3wTt_uwkZ06Op97yvy4g_izXlimRjtgfY,23613 cuppa/cpp/run_process_test.py,sha256=ZrR0NsLoVruLmq4HNH9E_MEbSNiX4aRTC7iKRFztZ64,12848 cuppa/cpp/run_gcov_coverage.py,sha256=2GfrDX2uTTPnoDf8Y--6glvToEmVYEZhath-iku7Qzc,7875 cuppa/cpp/create_version_file_cpp.py,sha256=LhY0o3kF9Mh3poqgYiosc-zauSymYzC6wmmxh59Iv9E,17134 cuppa-0.9.0.dist-info/entry_points.txt,sha256=ZEldvxCauUUxSl8mebeLfj1jDD6r3Umcdam2qHqoqJM,135 cuppa-0.9.0.dist-info/RECORD,, cuppa-0.9.0.dist-info/metadata.json,sha256=nn6xHlXYQuCZ8aZua-nVMVL0YGAasSU2qXMi5TXSpdc,982 cuppa-0.9.0.dist-info/WHEEL,sha256=54bVun1KfEBTJ68SHUmbxNPj80VxlQ0sHi4gZdGZXEY,92 cuppa-0.9.0.dist-info/DESCRIPTION.rst,sha256=gIOZuoowWxaVot78GAhcdlulTgEt6YcXJlFzUgG20PE,6335 cuppa-0.9.0.dist-info/METADATA,sha256=OqnO-fSe89iFxbLBnkj1sS8c4UyS4qx5CohxlI0wOK4,7012 cuppa-0.9.0.dist-info/top_level.txt,sha256=2jJke2-J2Hsbn_aEY5_RR9Zh2A80XyqsQNpMxV07HQU,6 PK-¹ƒFkÒm•cuppa/__init__.pyPK'™¯FoS‡ÒŠŠ 3cuppa/tree.pyPKDkRG?Ç Âð<ð<è cuppa/location.pyPK{QGÙó†  Gcuppa/log.pyPK{QGr.Ì}œœBRcuppa/timer.pyPKq‚RG#ho##" bcuppa/build_with_header_library.pyPK5¿®F©‚yy mvcuppa/path.pyPKø¹±FÕç‰Ùð ð {cuppa/progress.pyPK{QGÅ\qoo0‰cuppa/colourise.pyPK{QG“W8­¨¨Ï¥cuppa/configure.pyPKÕf=Göìë!„„§Ãcuppa/build_platform.pyPKîcáFew}»»`Ìcuppa/recursive_glob.pyPK-¹ƒF tDøbbPÕcuppa/options.pyPK±»SGG4*K à×cuppa/VERSIONPKQ¶FRâ{PPØcuppa/version.pyPKDkRGÏ«*¼)/)/Ýcuppa/output_processor.pyPK-¹ƒFg¡;ÛHHï cuppa/utility.pyPKDkRG!'„݇݇ ecuppa/core.pyPK-¹ƒF2¨Ô**m—cuppa/platforms/__init__.pyPKAp=GÑzeþþИcuppa/platforms/linux.pyPK-¹ƒF:ï8§ § ¨cuppa/platforms/darwin.pyPKDkRGL4TJJâ³cuppa/platforms/windows.pyPK-¹ƒF2¨Ô**$d¼cuppa/project_generators/__init__.pyPKöRGKPö~¯@¯@&нcuppa/project_generators/codeblocks.pyPK-¹ƒF2¨Ô**Ãþcuppa/profiles/__init__.pyPK{QGtZGNN%cuppa/methods/coverage.pyPK{QG ¯ä‰‰ªcuppa/methods/build_with.pyPK{QGLgül cuppa/methods/using.pyPK{QGb%Þš  ®cuppa/methods/toolchain.pyPK{QGÞÍþLL(ïcuppa/methods/relative_recursive_glob.pyPK-¹ƒF2¨Ô**cuppa/methods/__init__.pyPK{QGÍpddâcuppa/methods/remove_flags.pyPK{QG¨»»!cuppa/methods/target_from.pyPKDkRG‰h8KKv$cuppa/methods/stdcpp.pyPK{QGæVf»žžö*cuppa/methods/test.pyPK{QGN‚ïu))Ç1cuppa/methods/build_test.pyPK{QGÖ¯×77)9cuppa/methods/compile.pyPK{QG¦îßCC–=cuppa/methods/build.pyPK{QG;v´‘¼¼ Ecuppa/methods/replace_flags.pyPK{QGÌúº¸YYHcuppa/methods/create_version.pyPK{QG?Ä ŽŽ!›Lcuppa/methods/markdown_to_html.pyPK{QGÍx‡_99hTcuppa/methods/build_library.pyPK{QG@]cÙµµÝYcuppa/methods/build_profile.pyPK{QG∱êÎ^cuppa/variants/dbg.pyPK-¹ƒF2¨Ô**bcuppa/variants/__init__.pyPK{QG¡.66iccuppa/variants/cov.pyPK-¹ƒF¼¨¶€Òfcuppa/variants/test.pyPK{QG·5¯jcuppa/variants/rel.pyPK-¹ƒF2¨Ô**[mcuppa/dependencies/__init__.pyPKDkRG´*¨XX$Áncuppa/dependencies/build_with_qt4.pyPK)“QGüˆgèè1è1'[cuppa/dependencies/build_with_quince.pyPKq‚RG ÷2€‘˜‘˜&ˆ±cuppa/dependencies/build_with_boost.pyPKòkRG§Ef$]Jcuppa/dependencies/build_with_qt5.pyPK•c×FC߈4$¥Zcuppa/dependencies/boost/__init__.pyPKÖ“üFÎHe33.éZcuppa/dependencies/boost/boost_test_patch.diffPKDûFC߈4hëcuppa/test_report/__init__.pyPK{QG| N« « +¥ëcuppa/test_report/generate_bitten_report.pyPKýûFN]™øcuppa/test_report/cuppa_json.pyPK)“QGîºÐåÂSÂSWþcuppa/toolchains/clang.pyPK-¹ƒF2¨Ô**PRcuppa/toolchains/__init__.pyPKòkRG]ðmã + +´Scuppa/toolchains/cl.pyPK{QGuTô8c8cò~cuppa/toolchains/gcc.pyPK-¹ƒFó§H=ÔÔ_âcuppa/modules/__init__.pyPK{QG b¸-jãcuppa/modules/registration.pyPK-¹ƒF3´¾¾¬òcuppa/scms/subversion.pyPK-¹ƒFITXŸÓÓ ùcuppa/scms/__init__.pyPKF©ÜF ê »‡‡§úcuppa/scms/mercurial.pyPK|»ÔFdƒÌ••ccuppa/scms/git.pyPK{QG¸±³°V°V#' cuppa/cpp/run_patched_boost_test.pyPK-¹ƒFó§H=ÔÔ`cuppa/cpp/__init__.pyPK{QGL'`à=\=\acuppa/cpp/run_boost_test.pyPKòkRGƒËœó0202•½cuppa/cpp/run_process_test.pyPKý«þFkY¨ÞÃÃðcuppa/cpp/run_gcov_coverage.pyPK•c×F•Ý«/îBîB$ÿcuppa/cpp/create_version_file_cpp.pyPKÈ»SGgž¿¿%/Rcuppa-0.9.0.dist-info/DESCRIPTION.rstPKÆ»SG‚û¸‡‡&1kcuppa-0.9.0.dist-info/entry_points.txtPKÈ»SGòúïóÖÖ#ükcuppa-0.9.0.dist-info/metadata.jsonPKÆ»SGÜÈm­#pcuppa-0.9.0.dist-info/top_level.txtPKÈ»SG4»´Ø\\Zpcuppa-0.9.0.dist-info/WHEELPKÈ»SGIoL ddïpcuppa-0.9.0.dist-info/METADATAPKÈ»SGVN?³ccŒcuppa-0.9.0.dist-info/RECORDPKQQä,§