1# Copyright Deniz Bahadir 2015 2# 3# Distributed under the Boost Software License, Version 1.0. 4# (See accompanying file LICENSE_1_0.txt or copy at 5# http://www.boost.org/LICENSE_1_0.txt) 6# 7# See http://www.boost.org/libs/mpl for documentation. 8# See http://stackoverflow.com/a/29627158/3115457 for further information. 9 10import argparse 11import sys 12import os.path 13import re 14import fileinput 15import datetime 16import glob 17 18 19def check_header_comment(filename): 20 """Checks if the header-comment of the given file needs fixing.""" 21 # Check input file. 22 name = os.path.basename( filename ) 23 # Read content of input file. 24 sourcefile = open( filename, "rU" ) 25 content = sourcefile.read() 26 sourcefile.close() 27 # Search content for '$Id$'. 28 match = re.search(r'\$Id\$', content) 29 if match == None: 30 # Make sure that the correct value for '$Id$' was already set. 31 match = re.search(r'\$Id: ' + name + r'\s+[^$]+\$', content) 32 if match != None: 33 # The given file needs no fixing. 34 return False 35 # The given file needs fixing. 36 return True 37 38 39def check_input_files_for_variadic_seq(headerDir, sourceDir): 40 """Checks if files, used as input when pre-processing MPL-containers in their variadic form, need fixing.""" 41 # Check input files in include/source-directories. 42 files = glob.glob( os.path.join( headerDir, "*.hpp" ) ) 43 files += glob.glob( os.path.join( headerDir, "aux_", "*.hpp" ) ) 44 files += glob.glob( os.path.join( sourceDir, "src", "*" ) ) 45 for currentFile in sorted( files ): 46 if check_header_comment( currentFile ): 47 return True 48 return False 49 50 51def check_input_files_for_numbered_seq(sourceDir, suffix, containers): 52 """Check if files, used as input when pre-processing MPL-containers in their numbered form, need fixing.""" 53 # Check input files for each MPL-container type. 54 for container in containers: 55 files = glob.glob( os.path.join( sourceDir, container, container + '*' + suffix ) ) 56 for currentFile in sorted( files ): 57 if check_header_comment( currentFile ): 58 return True 59 return False 60 61 62def check_input_files(headerDir, sourceDir, containers=['vector', 'list', 'set', 'map'], 63 seqType='both', verbose=False): 64 """Checks if source- and header-files, used as input when pre-processing MPL-containers, need fixing.""" 65 # Check the input files for containers in their variadic form. 66 result1 = False 67 if seqType == "both" or seqType == "variadic": 68 if verbose: 69 print "Check if input files for pre-processing Boost.MPL variadic containers need fixing." 70 result1 = check_input_files_for_variadic_seq(headerDir, sourceDir) 71 if verbose: 72 if result1: 73 print " At least one input file needs fixing!" 74 else: 75 print " No input file needs fixing!" 76 # Check the input files for containers in their numbered form. 77 result2 = False 78 result3 = False 79 if seqType == "both" or seqType == "numbered": 80 if verbose: 81 print "Check input files for pre-processing Boost.MPL numbered containers." 82 result2 = check_input_files_for_numbered_seq(headerDir, ".hpp", containers) 83 result3 = check_input_files_for_numbered_seq(sourceDir, ".cpp", containers) 84 if verbose: 85 if result2 or result3: 86 print " At least one input file needs fixing!" 87 else: 88 print " No input file needs fixing!" 89 # Return result. 90 return result1 or result2 or result3 91 92def fix_header_comment(filename, timestamp): 93 """Fixes the header-comment of the given file.""" 94 # Fix input file. 95 name = os.path.basename( filename ) 96 for line in fileinput.input( filename, inplace=1, mode="rU" ): 97 # If header-comment already contains anything for '$Id$', remove it. 98 line = re.sub(r'\$Id:[^$]+\$', r'$Id$', line.rstrip()) 99 # Replace '$Id$' by a string containing the file's name (and a timestamp)! 100 line = re.sub(re.escape(r'$Id$'), r'$Id: ' + name + r' ' + timestamp.isoformat() + r' $', line.rstrip()) 101 print(line) 102 103 104def fix_input_files_for_variadic_seq(headerDir, sourceDir, timestamp): 105 """Fixes files used as input when pre-processing MPL-containers in their variadic form.""" 106 # Fix files in include/source-directories. 107 files = glob.glob( os.path.join( headerDir, "*.hpp" ) ) 108 files += glob.glob( os.path.join( headerDir, "aux_", "*.hpp" ) ) 109 files += glob.glob( os.path.join( sourceDir, "src", "*" ) ) 110 for currentFile in sorted( files ): 111 fix_header_comment( currentFile, timestamp ) 112 113 114def fix_input_files_for_numbered_seq(sourceDir, suffix, timestamp, containers): 115 """Fixes files used as input when pre-processing MPL-containers in their numbered form.""" 116 # Fix input files for each MPL-container type. 117 for container in containers: 118 files = glob.glob( os.path.join( sourceDir, container, container + '*' + suffix ) ) 119 for currentFile in sorted( files ): 120 fix_header_comment( currentFile, timestamp ) 121 122 123def fix_input_files(headerDir, sourceDir, containers=['vector', 'list', 'set', 'map'], 124 seqType='both', verbose=False): 125 """Fixes source- and header-files used as input when pre-processing MPL-containers.""" 126 # The new modification time. 127 timestamp = datetime.datetime.now(); 128 # Fix the input files for containers in their variadic form. 129 if seqType == "both" or seqType == "variadic": 130 if verbose: 131 print "Fix input files for pre-processing Boost.MPL variadic containers." 132 fix_input_files_for_variadic_seq(headerDir, sourceDir, timestamp) 133 # Fix the input files for containers in their numbered form. 134 if seqType == "both" or seqType == "numbered": 135 if verbose: 136 print "Fix input files for pre-processing Boost.MPL numbered containers." 137 fix_input_files_for_numbered_seq(headerDir, ".hpp", timestamp, containers) 138 fix_input_files_for_numbered_seq(sourceDir, ".cpp", timestamp, containers) 139 140 141def to_existing_absolute_path(string): 142 """Converts a path into its absolute path and verifies that it exists or throws an exception.""" 143 value = os.path.abspath(string) 144 if not os.path.exists( value ) or not os.path.isdir( value ): 145 msg = '"%r" is not a valid path to a directory.' % string 146 raise argparse.ArgumentTypeError(msg) 147 return value 148 149 150def main(): 151 """The main function.""" 152 153 # Prepare and run cmdline-parser. 154 cmdlineParser = argparse.ArgumentParser( 155 description="Fixes the input files used for pre-processing of Boost.MPL headers.") 156 cmdlineParser.add_argument("-v", "--verbose", dest='verbose', action='store_true', 157 help="Be a little bit more verbose.") 158 cmdlineParser.add_argument("--check-only", dest='checkonly', action='store_true', 159 help="Only checks if fixing is required.") 160 cmdlineParser.add_argument(dest='sourceDir', metavar="<source-dir>", 161 type=to_existing_absolute_path, 162 help="The source-directory of Boost.") 163 args = cmdlineParser.parse_args() 164 165 # Some verbose debug output. 166 if args.verbose: 167 print "Arguments extracted from command-line:" 168 print " verbose = ", args.verbose 169 print " check-only = ", args.checkonly 170 print " source directory = ", args.sourceDir 171 172 # The directories for header- and source files of Boost.MPL. 173 # NOTE: Assuming 'args.sourceDir' is the source-directory of the entire boost project. 174 headerDir = os.path.join( args.sourceDir, "boost", "mpl" ) 175 sourceDir = os.path.join( args.sourceDir, "libs", "mpl", "preprocessed" ) 176 # Check that the header/source-directories exist. 177 if not os.path.exists( headerDir ) or not os.path.exists( sourceDir ): 178 # Maybe 'args.sourceDir' is not the source-directory of the entire boost project 179 # but instead of the Boost.MPL git-directory, only? 180 headerDir = os.path.join( args.sourceDir, "include", "boost", "mpl" ) 181 sourceDir = os.path.join( args.sourceDir, "preprocessed" ) 182 if not os.path.exists( headerDir ) or not os.path.exists( sourceDir ): 183 cmdlineParser.print_usage() 184 print "error: Cannot find Boost.MPL header/source files in given Boost source-directory!" 185 sys.exit(0) 186 187 # Some verbose debug output. 188 if args.verbose: 189 print "Chosen header-directory: ", headerDir 190 print "Chosen source-directory: ", sourceDir 191 192 if args.checkonly: 193 # Check input files for generating pre-processed headers. 194 result = check_input_files(headerDir, sourceDir, verbose = args.verbose) 195 if result: 196 print "Fixing the input-files used for pre-processing of Boost.MPL headers IS required." 197 else: 198 print "Fixing the input-files used for pre-processing of Boost.MPL headers is NOT required." 199 else: 200 # Fix input files for generating pre-processed headers. 201 fix_input_files(headerDir, sourceDir, verbose = args.verbose) 202 203 204if __name__ == '__main__': 205 main() 206