1 #!/usr/bin/env python 2 3 from __future__ import print_function 4 5 import os 6 import io 7 import sys 8 import re 9 import datetime 10 from glob import glob 11 12 from scriptCommon import catchPath 13 14 def generate(v): 15 includesParser = re.compile( r'\s*#\s*include\s*"(.*)"' ) 16 guardParser = re.compile( r'\s*#.*(TWOBLUECUBES_)?CATCH_.*_INCLUDED') 17 defineParser = re.compile( r'\s*#define\s+(TWOBLUECUBES_)?CATCH_.*_INCLUDED') 18 ifParser = re.compile( r'\s*#ifndef (TWOBLUECUBES_)?CATCH_.*_INCLUDED') 19 endIfParser = re.compile( r'\s*#endif // (TWOBLUECUBES_)?CATCH_.*_INCLUDED') 20 ifImplParser = re.compile( r'\s*#ifdef CATCH_CONFIG_RUNNER' ) 21 commentParser1 = re.compile( r'^\s*/\*') 22 commentParser2 = re.compile( r'^ \*') 23 blankParser = re.compile( r'^\s*$') 24 25 seenHeaders = set([]) 26 rootPath = os.path.join( catchPath, 'include/' ) 27 outputPath = os.path.join( catchPath, 'single_include/catch2/catch.hpp' ) 28 29 globals = { 30 'includeImpl' : True, 31 'ifdefs' : 0, 32 'implIfDefs' : -1 33 } 34 35 for arg in sys.argv[1:]: 36 arg = arg.lower() 37 if arg == "noimpl": 38 globals['includeImpl'] = False 39 print( "Not including impl code" ) 40 else: 41 print( "\n** Unrecognised argument: " + arg + " **\n" ) 42 exit(1) 43 44 45 # ensure that the output directory exists (hopefully no races) 46 outDir = os.path.dirname(outputPath) 47 if not os.path.exists(outDir): 48 os.makedirs(outDir) 49 out = io.open( outputPath, 'w', newline='\n', encoding='utf-8') 50 51 def write( line ): 52 if globals['includeImpl'] or globals['implIfDefs'] == -1: 53 out.write( line ) 54 55 def insertCpps(): 56 dirs = [os.path.join( rootPath, s) for s in ['', 'internal', 'reporters']] 57 cppFiles = [] 58 for dir in dirs: 59 cppFiles += glob(os.path.join(dir, '*.cpp')) 60 # To minimize random diffs, sort the files before processing them 61 for fname in sorted(cppFiles): 62 dir, name = fname.rsplit(os.path.sep, 1) 63 dir += os.path.sep 64 parseFile(dir, name) 65 66 def parseFile( path, filename ): 67 f = io.open( os.path.join(path, filename), 'r', encoding='utf-8' ) 68 blanks = 0 69 write( u"// start {0}\n".format( filename ) ) 70 for line in f: 71 if '// ~*~* CATCH_CPP_STITCH_PLACE *~*~' in line: 72 insertCpps() 73 continue 74 elif ifParser.match( line ): 75 globals['ifdefs'] += 1 76 elif endIfParser.match( line ): 77 globals['ifdefs'] -= 1 78 if globals['ifdefs'] == globals['implIfDefs']: 79 globals['implIfDefs'] = -1 80 m = includesParser.match( line ) 81 if m: 82 header = m.group(1) 83 headerPath, sep, headerFile = header.rpartition( "/" ) 84 if headerFile not in seenHeaders: 85 if headerFile != "tbc_text_format.h" and headerFile != "clara.h": 86 seenHeaders.add( headerFile ) 87 if headerPath == "internal" and path.endswith("internal/"): 88 headerPath = "" 89 sep = "" 90 if os.path.exists( path + headerPath + sep + headerFile ): 91 parseFile( path + headerPath + sep, headerFile ) 92 else: 93 parseFile( rootPath + headerPath + sep, headerFile ) 94 else: 95 if ifImplParser.match(line): 96 globals['implIfDefs'] = globals['ifdefs'] 97 if (not guardParser.match( line ) or defineParser.match( line ) ) and not commentParser1.match( line )and not commentParser2.match( line ): 98 if blankParser.match( line ): 99 blanks = blanks + 1 100 else: 101 blanks = 0 102 if blanks < 2 and not defineParser.match(line): 103 write( line.rstrip() + "\n" ) 104 write( u'// end {}\n'.format(filename) ) 105 106 107 write( u"/*\n" ) 108 write( u" * Catch v{0}\n".format( v.getVersionString() ) ) 109 write( u" * Generated: {0}\n".format( datetime.datetime.now() ) ) 110 write( u" * ----------------------------------------------------------\n" ) 111 write( u" * This file has been merged from multiple headers. Please don't edit it directly\n" ) 112 write( u" * Copyright (c) {} Two Blue Cubes Ltd. All rights reserved.\n".format( datetime.date.today().year ) ) 113 write( u" *\n" ) 114 write( u" * Distributed under the Boost Software License, Version 1.0. (See accompanying\n" ) 115 write( u" * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n" ) 116 write( u" */\n" ) 117 write( u"#ifndef TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED\n" ) 118 write( u"#define TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED\n" ) 119 120 parseFile( rootPath, 'catch.hpp' ) 121 122 write( u"#endif // TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED\n\n" ) 123 out.close() 124 print ("Generated single include for Catch v{0}\n".format( v.getVersionString() ) ) 125 126 127 if __name__ == '__main__': 128 from releaseCommon import Version 129 generate(Version()) 130