"""Functions used to generate source files during build time All such functions are invoked in a subprocess on Windows to prevent build flakiness. """ from platform_methods import subprocess_main def escape_string(s): def charcode_to_c_escapes(c): rev_result = [] while c >= 256: c, low = (c // 256, c % 256) rev_result.append('\\%03o' % low) rev_result.append('\\%03o' % c) return ''.join(reversed(rev_result)) result = '' if isinstance(s, str): s = s.encode('utf-8') for c in s: if not(32 <= c < 127) or c in (ord('\\'), ord('"')): result += charcode_to_c_escapes(c) else: result += chr(c) return result def make_certs_header(target, source, env): src = source[0] dst = target[0] f = open(src, "rb") g = open(dst, "w", encoding="utf-8") buf = f.read() decomp_size = len(buf) import zlib buf = zlib.compress(buf) g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n") g.write("#ifndef CERTS_COMPRESSED_GEN_H\n") g.write("#define CERTS_COMPRESSED_GEN_H\n") # System certs path. Editor will use them if defined. (for package maintainers) path = env['system_certs_path'] g.write("#define _SYSTEM_CERTS_PATH \"%s\"\n" % str(path)) if env['builtin_certs']: # Defined here and not in env so changing it does not trigger a full rebuild. g.write("#define BUILTIN_CERTS_ENABLED\n") g.write("static const int _certs_compressed_size = " + str(len(buf)) + ";\n") g.write("static const int _certs_uncompressed_size = " + str(decomp_size) + ";\n") g.write("static const unsigned char _certs_compressed[] = {\n") for i in range(len(buf)): g.write("\t" + str(buf[i]) + ",\n") g.write("};\n") g.write("#endif // CERTS_COMPRESSED_GEN_H") g.close() f.close() def make_authors_header(target, source, env): sections = ["Project Founders", "Lead Developer", "Project Manager", "Developers"] sections_id = ["AUTHORS_FOUNDERS", "AUTHORS_LEAD_DEVELOPERS", "AUTHORS_PROJECT_MANAGERS", "AUTHORS_DEVELOPERS"] src = source[0] dst = target[0] f = open(src, "r", encoding="utf-8") g = open(dst, "w", encoding="utf-8") g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n") g.write("#ifndef AUTHORS_GEN_H\n") g.write("#define AUTHORS_GEN_H\n") reading = False def close_section(): g.write("\t0\n") g.write("};\n") for line in f: if reading: if line.startswith(" "): g.write("\t\"" + escape_string(line.strip()) + "\",\n") continue if line.startswith("## "): if reading: close_section() reading = False for section, section_id in zip(sections, sections_id): if line.strip().endswith(section): current_section = escape_string(section_id) reading = True g.write("const char *const " + current_section + "[] = {\n") break if reading: close_section() g.write("#endif // AUTHORS_GEN_H\n") g.close() f.close() def make_donors_header(target, source, env): sections = ["Platinum sponsors", "Gold sponsors", "Mini sponsors", "Gold donors", "Silver donors", "Bronze donors"] sections_id = ["DONORS_SPONSOR_PLAT", "DONORS_SPONSOR_GOLD", "DONORS_SPONSOR_MINI", "DONORS_GOLD", "DONORS_SILVER", "DONORS_BRONZE"] src = source[0] dst = target[0] f = open(src, "r", encoding="utf-8") g = open(dst, "w", encoding="utf-8") g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n") g.write("#ifndef DONORS_GEN_H\n") g.write("#define DONORS_GEN_H\n") reading = False def close_section(): g.write("\t0\n") g.write("};\n") for line in f: if reading >= 0: if line.startswith(" "): g.write("\t\"" + escape_string(line.strip()) + "\",\n") continue if line.startswith("## "): if reading: close_section() reading = False for section, section_id in zip(sections, sections_id): if line.strip().endswith(section): current_section = escape_string(section_id) reading = True g.write("const char *const " + current_section + "[] = {\n") break if reading: close_section() g.write("#endif // DONORS_GEN_H\n") g.close() f.close() def make_license_header(target, source, env): src_copyright = source[0] src_license = source[1] dst = target[0] class LicenseReader: def __init__(self, license_file): self._license_file = license_file self.line_num = 0 self.current = self.next_line() def next_line(self): line = self._license_file.readline() self.line_num += 1 while line.startswith("#"): line = self._license_file.readline() self.line_num += 1 self.current = line return line def next_tag(self): if not ':' in self.current: return ('', []) tag, line = self.current.split(":", 1) lines = [line.strip()] while self.next_line() and self.current.startswith(" "): lines.append(self.current.strip()) return (tag, lines) from collections import OrderedDict projects = OrderedDict() license_list = [] with open(src_copyright, "r", encoding="utf-8") as copyright_file: reader = LicenseReader(copyright_file) part = {} while reader.current: tag, content = reader.next_tag() if tag in ("Files", "Copyright", "License"): part[tag] = content[:] elif tag == "Comment": # attach part to named project projects[content[0]] = projects.get(content[0], []) + [part] if not tag or not reader.current: # end of a paragraph start a new part if "License" in part and not "Files" in part: # no Files tag in this one, so assume standalone license license_list.append(part["License"]) part = {} reader.next_line() data_list = [] for project in iter(projects.values()): for part in project: part["file_index"] = len(data_list) data_list += part["Files"] part["copyright_index"] = len(data_list) data_list += part["Copyright"] with open(dst, "w", encoding="utf-8") as f: f.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n") f.write("#ifndef LICENSE_GEN_H\n") f.write("#define LICENSE_GEN_H\n") f.write("const char *const GODOT_LICENSE_TEXT =") with open(src_license, "r", encoding="utf-8") as license_file: for line in license_file: escaped_string = escape_string(line.strip()) f.write("\n\t\t\"" + escaped_string + "\\n\"") f.write(";\n\n") f.write("struct ComponentCopyrightPart {\n" "\tconst char *license;\n" "\tconst char *const *files;\n" "\tconst char *const *copyright_statements;\n" "\tint file_count;\n" "\tint copyright_count;\n" "};\n\n") f.write("struct ComponentCopyright {\n" "\tconst char *name;\n" "\tconst ComponentCopyrightPart *parts;\n" "\tint part_count;\n" "};\n\n") f.write("const char *const COPYRIGHT_INFO_DATA[] = {\n") for line in data_list: f.write("\t\"" + escape_string(line) + "\",\n") f.write("};\n\n") f.write("const ComponentCopyrightPart COPYRIGHT_PROJECT_PARTS[] = {\n") part_index = 0 part_indexes = {} for project_name, project in iter(projects.items()): part_indexes[project_name] = part_index for part in project: f.write("\t{ \"" + escape_string(part["License"][0]) + "\", " + "©RIGHT_INFO_DATA[" + str(part["file_index"]) + "], " + "©RIGHT_INFO_DATA[" + str(part["copyright_index"]) + "], " + str(len(part["Files"])) + ", " + str(len(part["Copyright"])) + " },\n") part_index += 1 f.write("};\n\n") f.write("const int COPYRIGHT_INFO_COUNT = " + str(len(projects)) + ";\n") f.write("const ComponentCopyright COPYRIGHT_INFO[] = {\n") for project_name, project in iter(projects.items()): f.write("\t{ \"" + escape_string(project_name) + "\", " + "©RIGHT_PROJECT_PARTS[" + str(part_indexes[project_name]) + "], " + str(len(project)) + " },\n") f.write("};\n\n") f.write("const int LICENSE_COUNT = " + str(len(license_list)) + ";\n") f.write("const char *const LICENSE_NAMES[] = {\n") for l in license_list: f.write("\t\"" + escape_string(l[0]) + "\",\n") f.write("};\n\n") f.write("const char *const LICENSE_BODIES[] = {\n\n") for l in license_list: for line in l[1:]: if line == ".": f.write("\t\"\\n\"\n") else: f.write("\t\"" + escape_string(line) + "\\n\"\n") f.write("\t\"\",\n\n") f.write("};\n\n") f.write("#endif // LICENSE_GEN_H\n") if __name__ == '__main__': subprocess_main(globals())