123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316 |
- """Functions used to generate source files during build time"""
- import zlib
- 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 = str(source[0])
- dst = str(target[0])
- with open(src, "rb") as f, open(dst, "w", encoding="utf-8", newline="\n") as g:
- buf = f.read()
- decomp_size = len(buf)
- # Use maximum zlib compression level to further reduce file size
- # (at the cost of initial build times).
- buf = zlib.compress(buf, zlib.Z_BEST_COMPRESSION)
- 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")
- 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 = str(source[0])
- dst = str(target[0])
- with open(src, "r", encoding="utf-8") as f, open(dst, "w", encoding="utf-8", newline="\n") as g:
- 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")
- def make_donors_header(target, source, env):
- sections = [
- "Patrons",
- "Platinum sponsors",
- "Gold sponsors",
- "Silver sponsors",
- "Diamond members",
- "Titanium members",
- "Platinum members",
- "Gold members",
- ]
- sections_id = [
- "DONORS_PATRONS",
- "DONORS_SPONSORS_PLATINUM",
- "DONORS_SPONSORS_GOLD",
- "DONORS_SPONSORS_SILVER",
- "DONORS_MEMBERS_DIAMOND",
- "DONORS_MEMBERS_TITANIUM",
- "DONORS_MEMBERS_PLATINUM",
- "DONORS_MEMBERS_GOLD",
- ]
- src = str(source[0])
- dst = str(target[0])
- with open(src, "r", encoding="utf-8") as f, open(dst, "w", encoding="utf-8", newline="\n") as g:
- 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")
- def make_license_header(target, source, env):
- src_copyright = str(source[0])
- src_license = str(source[1])
- dst = str(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: dict = 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 "Files" not in part:
- # no Files tag in this one, so assume standalone license
- license_list.append(part["License"])
- part = {}
- reader.next_line()
- data_list: 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", newline="\n") 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 license in license_list:
- f.write('\t"' + escape_string(license[0]) + '",\n')
- f.write("};\n\n")
- f.write("const char *const LICENSE_BODIES[] = {\n\n")
- for license in license_list:
- for line in license[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")
|