1#!/usr/bin/env python 2 3import argparse 4import os, sys 5import re 6import datetime as dt 7 8# python 3 compatibility 9try: 10 import cStringIO as sstream 11except ImportError: 12 from io import StringIO 13 14description = "Converts sol to a single file for convenience." 15 16# command line parser 17parser = argparse.ArgumentParser(usage='%(prog)s [options...]', description=description) 18parser.add_argument('--output', '-o', help='name and location of where to place file', metavar='file', default='sol.hpp') 19parser.add_argument('--quiet', help='suppress all output', action='store_true') 20args = parser.parse_args() 21 22script_path = os.path.normpath(os.path.dirname(os.path.realpath(__file__))) 23working_dir = os.getcwd() 24os.chdir(script_path) 25 26intro = """// The MIT License (MIT) 27 28// Copyright (c) 2013-2016 Rapptz, ThePhD and contributors 29 30// Permission is hereby granted, free of charge, to any person obtaining a copy of 31// this software and associated documentation files (the "Software"), to deal in 32// the Software without restriction, including without limitation the rights to 33// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 34// the Software, and to permit persons to whom the Software is furnished to do so, 35// subject to the following conditions: 36 37// The above copyright notice and this permission notice shall be included in all 38// copies or substantial portions of the Software. 39 40// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 41// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 42// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 43// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 44// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 45// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 46 47// This file was generated with a script. 48// Generated {time} UTC 49// This header was generated with sol {version} (revision {revision}) 50// https://github.com/ThePhD/sol2 51 52#ifndef {guard} 53#define {guard} 54 55""" 56 57module_path = os.path.join(script_path) 58 59includes = set([]) 60standard_include = re.compile(r'#include <(.*?)>') 61local_include = re.compile(r'#include "(.*?)"') 62ifndef_cpp = re.compile(r'#ifndef SOL_.*?_HPP') 63define_cpp = re.compile(r'#define SOL_.*?_HPP') 64endif_cpp = re.compile(r'#endif // SOL_.*?_HPP') 65 66def get_include(line, base_path): 67 local_match = local_include.match(line) 68 if local_match: 69 # local include found 70 full_path = os.path.normpath(os.path.join(base_path, local_match.group(1))).replace('\\', '/') 71 return full_path 72 73 return None 74 75 76def is_include_guard(line): 77 return ifndef_cpp.match(line) or define_cpp.match(line) or endif_cpp.match(line) 78 79def get_revision(): 80 return os.popen('git rev-parse --short HEAD').read().strip() 81 82def get_version(): 83 return os.popen('git describe --tags --abbrev=0').read().strip() 84 85def process_file(filename, out): 86 global includes 87 filename = os.path.normpath(filename) 88 relativefilename = filename.replace(script_path + os.sep, "").replace("\\", "/") 89 90 if filename in includes: 91 return 92 93 includes.add(filename) 94 95 if not args.quiet: 96 print('processing {}'.format(filename)) 97 98 out.write('// beginning of {}\n\n'.format(relativefilename)) 99 empty_line_state = True 100 101 with open(filename, 'r', encoding='utf-8') as f: 102 for line in f: 103 # skip comments 104 if line.startswith('//'): 105 continue 106 107 # skip include guard non-sense 108 if is_include_guard(line): 109 continue 110 111 # get relative directory 112 base_path = os.path.dirname(filename) 113 114 # check if it's a standard file 115 std = standard_include.search(line) 116 if std: 117 std_file = os.path.join('std', std.group(0)) 118 if std_file in includes: 119 continue 120 includes.add(std_file) 121 122 # see if it's an include file 123 name = get_include(line, base_path) 124 125 if name: 126 process_file(name, out) 127 continue 128 129 empty_line = len(line.strip()) == 0 130 131 if empty_line and empty_line_state: 132 continue 133 134 empty_line_state = empty_line 135 136 # line is fine 137 out.write(line) 138 139 out.write('// end of {}\n\n'.format(relativefilename)) 140 141 142version = get_version() 143revision = get_revision() 144include_guard = 'SOL_SINGLE_INCLUDE_HPP' 145 146if not args.quiet: 147 print('Creating single header for sol') 148 print('Current version: {version} (revision {revision})\n'.format(version = version, revision = revision)) 149 150 151processed_files = [os.path.join(script_path, x) for x in ['sol.hpp']] 152result = '' 153 154ss = StringIO() 155ss.write(intro.format(time=dt.datetime.utcnow(), revision=revision, version=version, guard=include_guard)) 156for processed_file in processed_files: 157 process_file(processed_file, ss) 158 159ss.write('#endif // {}\n'.format(include_guard)) 160result = ss.getvalue() 161ss.close() 162 163with open(args.output, 'w', encoding='utf-8') as f: 164 f.write(result) 165 166