# Copyright Deniz Bahadir 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/mpl for documentation. # See http://stackoverflow.com/a/29627158/3115457 for further information. import argparse import sys import os.path import re import fileinput import datetime import glob def check_header_comment(filename): """Checks if the header-comment of the given file needs fixing.""" # Check input file. name = os.path.basename( filename ) # Read content of input file. sourcefile = open( filename, "rU" ) content = sourcefile.read() sourcefile.close() # Search content for '$Id$'. match = re.search(r'\$Id\$', content) if match == None: # Make sure that the correct value for '$Id$' was already set. match = re.search(r'\$Id: ' + name + r'\s+[^$]+\$', content) if match != None: # The given file needs no fixing. return False # The given file needs fixing. return True def check_input_files_for_variadic_seq(headerDir, sourceDir): """Checks if files, used as input when pre-processing MPL-containers in their variadic form, need fixing.""" # Check input files in include/source-directories. files = glob.glob( os.path.join( headerDir, "*.hpp" ) ) files += glob.glob( os.path.join( headerDir, "aux_", "*.hpp" ) ) files += glob.glob( os.path.join( sourceDir, "src", "*" ) ) for currentFile in sorted( files ): if check_header_comment( currentFile ): return True return False def check_input_files_for_numbered_seq(sourceDir, suffix, containers): """Check if files, used as input when pre-processing MPL-containers in their numbered form, need fixing.""" # Check input files for each MPL-container type. for container in containers: files = glob.glob( os.path.join( sourceDir, container, container + '*' + suffix ) ) for currentFile in sorted( files ): if check_header_comment( currentFile ): return True return False def check_input_files(headerDir, sourceDir, containers=['vector', 'list', 'set', 'map'], seqType='both', verbose=False): """Checks if source- and header-files, used as input when pre-processing MPL-containers, need fixing.""" # Check the input files for containers in their variadic form. result1 = False if seqType == "both" or seqType == "variadic": if verbose: print "Check if input files for pre-processing Boost.MPL variadic containers need fixing." result1 = check_input_files_for_variadic_seq(headerDir, sourceDir) if verbose: if result1: print " At least one input file needs fixing!" else: print " No input file needs fixing!" # Check the input files for containers in their numbered form. result2 = False result3 = False if seqType == "both" or seqType == "numbered": if verbose: print "Check input files for pre-processing Boost.MPL numbered containers." result2 = check_input_files_for_numbered_seq(headerDir, ".hpp", containers) result3 = check_input_files_for_numbered_seq(sourceDir, ".cpp", containers) if verbose: if result2 or result3: print " At least one input file needs fixing!" else: print " No input file needs fixing!" # Return result. return result1 or result2 or result3 def fix_header_comment(filename, timestamp): """Fixes the header-comment of the given file.""" # Fix input file. name = os.path.basename( filename ) for line in fileinput.input( filename, inplace=1, mode="rU" ): # If header-comment already contains anything for '$Id$', remove it. line = re.sub(r'\$Id:[^$]+\$', r'$Id$', line.rstrip()) # Replace '$Id$' by a string containing the file's name (and a timestamp)! line = re.sub(re.escape(r'$Id$'), r'$Id: ' + name + r' ' + timestamp.isoformat() + r' $', line.rstrip()) print(line) def fix_input_files_for_variadic_seq(headerDir, sourceDir, timestamp): """Fixes files used as input when pre-processing MPL-containers in their variadic form.""" # Fix files in include/source-directories. files = glob.glob( os.path.join( headerDir, "*.hpp" ) ) files += glob.glob( os.path.join( headerDir, "aux_", "*.hpp" ) ) files += glob.glob( os.path.join( sourceDir, "src", "*" ) ) for currentFile in sorted( files ): fix_header_comment( currentFile, timestamp ) def fix_input_files_for_numbered_seq(sourceDir, suffix, timestamp, containers): """Fixes files used as input when pre-processing MPL-containers in their numbered form.""" # Fix input files for each MPL-container type. for container in containers: files = glob.glob( os.path.join( sourceDir, container, container + '*' + suffix ) ) for currentFile in sorted( files ): fix_header_comment( currentFile, timestamp ) def fix_input_files(headerDir, sourceDir, containers=['vector', 'list', 'set', 'map'], seqType='both', verbose=False): """Fixes source- and header-files used as input when pre-processing MPL-containers.""" # The new modification time. timestamp = datetime.datetime.now(); # Fix the input files for containers in their variadic form. if seqType == "both" or seqType == "variadic": if verbose: print "Fix input files for pre-processing Boost.MPL variadic containers." fix_input_files_for_variadic_seq(headerDir, sourceDir, timestamp) # Fix the input files for containers in their numbered form. if seqType == "both" or seqType == "numbered": if verbose: print "Fix input files for pre-processing Boost.MPL numbered containers." fix_input_files_for_numbered_seq(headerDir, ".hpp", timestamp, containers) fix_input_files_for_numbered_seq(sourceDir, ".cpp", timestamp, containers) def to_existing_absolute_path(string): """Converts a path into its absolute path and verifies that it exists or throws an exception.""" value = os.path.abspath(string) if not os.path.exists( value ) or not os.path.isdir( value ): msg = '"%r" is not a valid path to a directory.' % string raise argparse.ArgumentTypeError(msg) return value def main(): """The main function.""" # Prepare and run cmdline-parser. cmdlineParser = argparse.ArgumentParser( description="Fixes the input files used for pre-processing of Boost.MPL headers.") cmdlineParser.add_argument("-v", "--verbose", dest='verbose', action='store_true', help="Be a little bit more verbose.") cmdlineParser.add_argument("--check-only", dest='checkonly', action='store_true', help="Only checks if fixing is required.") cmdlineParser.add_argument(dest='sourceDir', metavar="", type=to_existing_absolute_path, help="The source-directory of Boost.") args = cmdlineParser.parse_args() # Some verbose debug output. if args.verbose: print "Arguments extracted from command-line:" print " verbose = ", args.verbose print " check-only = ", args.checkonly print " source directory = ", args.sourceDir # The directories for header- and source files of Boost.MPL. # NOTE: Assuming 'args.sourceDir' is the source-directory of the entire boost project. headerDir = os.path.join( args.sourceDir, "boost", "mpl" ) sourceDir = os.path.join( args.sourceDir, "libs", "mpl", "preprocessed" ) # Check that the header/source-directories exist. if not os.path.exists( headerDir ) or not os.path.exists( sourceDir ): # Maybe 'args.sourceDir' is not the source-directory of the entire boost project # but instead of the Boost.MPL git-directory, only? headerDir = os.path.join( args.sourceDir, "include", "boost", "mpl" ) sourceDir = os.path.join( args.sourceDir, "preprocessed" ) if not os.path.exists( headerDir ) or not os.path.exists( sourceDir ): cmdlineParser.print_usage() print "error: Cannot find Boost.MPL header/source files in given Boost source-directory!" sys.exit(0) # Some verbose debug output. if args.verbose: print "Chosen header-directory: ", headerDir print "Chosen source-directory: ", sourceDir if args.checkonly: # Check input files for generating pre-processed headers. result = check_input_files(headerDir, sourceDir, verbose = args.verbose) if result: print "Fixing the input-files used for pre-processing of Boost.MPL headers IS required." else: print "Fixing the input-files used for pre-processing of Boost.MPL headers is NOT required." else: # Fix input files for generating pre-processed headers. fix_input_files(headerDir, sourceDir, verbose = args.verbose) if __name__ == '__main__': main()