diff --git a/core/SCsub b/core/SCsub index 383aaf0e127e..c4f1cdbe974b 100644 --- a/core/SCsub +++ b/core/SCsub @@ -2,6 +2,8 @@ Import('env') +import methods + env.core_sources = [] @@ -93,6 +95,17 @@ env.add_source_files(env.core_sources, "*.cpp") import make_binders env.Command(['method_bind.gen.inc', 'method_bind_ext.gen.inc'], 'make_binders.py', make_binders.run) +# Authors +env.Depends('#core/authors.gen.h', "../AUTHORS.md") +env.Command('#core/authors.gen.h', "../AUTHORS.md", methods.make_authors_header) + +# Donors +env.Depends('#core/donors.gen.h', "../DONORS.md") +env.Command('#core/donors.gen.h', "../DONORS.md", methods.make_donors_header) + +# License +env.Depends('#core/license.gen.h', ["../COPYRIGHT.txt", "../LICENSE.txt"]) +env.Command('#core/license.gen.h', ["../COPYRIGHT.txt", "../LICENSE.txt"], methods.make_license_header) # Chain load SCsubs SConscript('os/SCsub') diff --git a/core/bind/core_bind.cpp b/core/bind/core_bind.cpp index 3270b33f1ca3..14e380484019 100644 --- a/core/bind/core_bind.cpp +++ b/core/bind/core_bind.cpp @@ -2710,6 +2710,26 @@ Dictionary _Engine::get_version_info() const { return Engine::get_singleton()->get_version_info(); } +Dictionary _Engine::get_author_info() const { + return Engine::get_singleton()->get_author_info(); +} + +Array _Engine::get_copyright_info() const { + return Engine::get_singleton()->get_copyright_info(); +} + +Dictionary _Engine::get_donor_info() const { + return Engine::get_singleton()->get_donor_info(); +} + +Dictionary _Engine::get_license_info() const { + return Engine::get_singleton()->get_license_info(); +} + +String _Engine::get_license_text() const { + return Engine::get_singleton()->get_license_text(); +} + bool _Engine::is_in_physics_frame() const { return Engine::get_singleton()->is_in_physics_frame(); } @@ -2752,6 +2772,11 @@ void _Engine::_bind_methods() { ClassDB::bind_method(D_METHOD("get_main_loop"), &_Engine::get_main_loop); ClassDB::bind_method(D_METHOD("get_version_info"), &_Engine::get_version_info); + ClassDB::bind_method(D_METHOD("get_author_info"), &_Engine::get_author_info); + ClassDB::bind_method(D_METHOD("get_copyright_info"), &_Engine::get_copyright_info); + ClassDB::bind_method(D_METHOD("get_donor_info"), &_Engine::get_donor_info); + ClassDB::bind_method(D_METHOD("get_license_info"), &_Engine::get_license_info); + ClassDB::bind_method(D_METHOD("get_license_text"), &_Engine::get_license_text); ClassDB::bind_method(D_METHOD("is_in_physics_frame"), &_Engine::is_in_physics_frame); diff --git a/core/bind/core_bind.h b/core/bind/core_bind.h index a363f5970f7b..1de5e43b2763 100644 --- a/core/bind/core_bind.h +++ b/core/bind/core_bind.h @@ -689,6 +689,11 @@ public: MainLoop *get_main_loop() const; Dictionary get_version_info() const; + Dictionary get_author_info() const; + Array get_copyright_info() const; + Dictionary get_donor_info() const; + Dictionary get_license_info() const; + String get_license_text() const; bool is_in_physics_frame() const; diff --git a/core/engine.cpp b/core/engine.cpp index b2c34a853c4f..7c8024b9466e 100644 --- a/core/engine.cpp +++ b/core/engine.cpp @@ -30,6 +30,9 @@ #include "engine.h" +#include "authors.gen.h" +#include "donors.gen.h" +#include "license.gen.h" #include "version.h" #include "version_hash.gen.h" @@ -111,6 +114,78 @@ Dictionary Engine::get_version_info() const { return dict; } +static Array array_from_info(const char *const *info_list) { + Array arr; + for (int i = 0; info_list[i] != NULL; i++) { + arr.push_back(info_list[i]); + } + return arr; +} + +static Array array_from_info_count(const char *const *info_list, int info_count) { + Array arr; + for (int i = 0; i < info_count; i++) { + arr.push_back(info_list[i]); + } + return arr; +} + +Dictionary Engine::get_author_info() const { + Dictionary dict; + + dict["lead_developers"] = array_from_info(AUTHORS_LEAD_DEVELOPERS); + dict["project_managers"] = array_from_info(AUTHORS_PROJECT_MANAGERS); + dict["founders"] = array_from_info(AUTHORS_FOUNDERS); + dict["developers"] = array_from_info(AUTHORS_DEVELOPERS); + + return dict; +} + +Array Engine::get_copyright_info() const { + Array components; + for (int component_index = 0; component_index < COPYRIGHT_INFO_COUNT; component_index++) { + const ComponentCopyright &cp_info = COPYRIGHT_INFO[component_index]; + Dictionary component_dict; + component_dict["name"] = cp_info.name; + Array parts; + for (int i = 0; i < cp_info.part_count; i++) { + const ComponentCopyrightPart &cp_part = cp_info.parts[i]; + Dictionary part_dict; + part_dict["files"] = array_from_info_count(cp_part.files, cp_part.file_count); + part_dict["copyright"] = array_from_info_count(cp_part.copyright_statements, cp_part.copyright_count); + part_dict["license"] = cp_part.license; + parts.push_back(part_dict); + } + component_dict["parts"] = parts; + + components.push_back(component_dict); + } + return components; +} + +Dictionary Engine::get_donor_info() const { + Dictionary donors; + donors["platinum_sponsors"] = array_from_info(DONORS_SPONSOR_PLAT); + donors["gold_sponsors"] = array_from_info(DONORS_SPONSOR_GOLD); + donors["mini_sponsors"] = array_from_info(DONORS_SPONSOR_MINI); + donors["gold_donors"] = array_from_info(DONORS_GOLD); + donors["silver_donors"] = array_from_info(DONORS_SILVER); + donors["bronze_donors"] = array_from_info(DONORS_BRONZE); + return donors; +} + +Dictionary Engine::get_license_info() const { + Dictionary licenses; + for (int i = 0; i < LICENSE_COUNT; i++) { + licenses[LICENSE_NAMES[i]] = LICENSE_BODIES[i]; + } + return licenses; +} + +String Engine::get_license_text() const { + return String(GODOT_LICENSE_TEXT); +} + void Engine::add_singleton(const Singleton &p_singleton) { singletons.push_back(p_singleton); diff --git a/core/engine.h b/core/engine.h index 665992699a02..031ba29cd660 100644 --- a/core/engine.h +++ b/core/engine.h @@ -118,6 +118,11 @@ public: #endif Dictionary get_version_info() const; + Dictionary get_author_info() const; + Array get_copyright_info() const; + Dictionary get_donor_info() const; + Dictionary get_license_info() const; + String get_license_text() const; Engine(); }; diff --git a/doc/classes/Engine.xml b/doc/classes/Engine.xml index cc2ae4e7682e..327300539506 100644 --- a/doc/classes/Engine.xml +++ b/doc/classes/Engine.xml @@ -11,6 +11,36 @@ + + + + + Returns engine author information in a Dictionary. + + "lead_developers" - Array of Strings, lead developer names + "founders" - Array of Strings, founder names + "project_managers" - Array of Strings, project manager names + "developers" - Array of Strings, developer names + + + + + + + Returns an Array of copyright information Dictionaries. + + "name" - String, component name + "parts" - Array of Dictionaries {"files", "copyright", "license"} describing subsections of the component + + + + + + + Returns a Dictionary of Arrays of donor names. + {"platinum_sponsors", "gold_sponsors", "mini_sponsors", "gold_donors", "silver_donors", "bronze_donors"} + + @@ -25,6 +55,20 @@ Returns the frames per second of the running game. + + + + + Returns Dictionary of licenses used by Godot and included third party components. + + + + + + + Returns Godot license text. + + diff --git a/editor/SCsub b/editor/SCsub index 4ca6b9e3fd5f..c29da8dd8a60 100644 --- a/editor/SCsub +++ b/editor/SCsub @@ -7,7 +7,6 @@ import os import os.path from compat import encode_utf8, byte_to_str, open_utf8, escape_string - def make_certs_header(target, source, env): src = source[0].srcnode().abspath @@ -147,268 +146,6 @@ def make_translations_header(target, source, env): g.close() - -def make_authors_header(target, source, env): - - sections = ["Project Founders", "Lead Developer", "Project Manager", "Developers"] - sections_id = ["dev_founders", "dev_lead", "dev_manager", "dev_names"] - - src = source[0].srcnode().abspath - dst = target[0].srcnode().abspath - f = open_utf8(src, "r") - g = open_utf8(dst, "w") - - g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n") - g.write("#ifndef _EDITOR_AUTHORS_H\n") - g.write("#define _EDITOR_AUTHORS_H\n") - - current_section = "" - 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 i in range(len(sections)): - if line.strip().endswith(sections[i]): - current_section = escape_string(sections_id[i]) - reading = True - g.write("static const char *" + current_section + "[] = {\n") - break - - if reading: - close_section() - - g.write("#endif\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 = ["donor_s_plat", "donor_s_gold", "donor_s_mini", "donor_gold", "donor_silver", "donor_bronze"] - - src = source[0].srcnode().abspath - dst = target[0].srcnode().abspath - f = open_utf8(src, "r") - g = open_utf8(dst, "w") - - g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n") - g.write("#ifndef _EDITOR_DONORS_H\n") - g.write("#define _EDITOR_DONORS_H\n") - - current_section = "" - 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 i in range(len(sections)): - if line.strip().endswith(sections[i]): - current_section = escape_string(sections_id[i]) - reading = True - g.write("static const char *" + current_section + "[] = {\n") - break - - if reading: - close_section() - - g.write("#endif\n") - - g.close() - f.close() - - -def make_license_header(target, source, env): - - src_copyright = source[0].srcnode().abspath - src_license = source[1].srcnode().abspath - dst = target[0].srcnode().abspath - f = open_utf8(src_license, "r") - fc = open_utf8(src_copyright, "r") - g = open_utf8(dst, "w") - - g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n") - g.write("#ifndef _EDITOR_LICENSE_H\n") - g.write("#define _EDITOR_LICENSE_H\n") - g.write("static const char *about_license =") - - for line in f: - escaped_string = escape_string(line.strip()) - g.write("\n\t\"" + escaped_string + "\\n\"") - - g.write(";\n") - - tp_current = 0 - tp_file = "" - tp_comment = "" - tp_copyright = "" - tp_license = "" - - tp_licensename = "" - tp_licensebody = "" - - tp = [] - tp_licensetext = [] - for line in fc: - if line.startswith("#"): - continue - - if line.startswith("Files:"): - tp_file = line[6:].strip() - tp_current = 1 - elif line.startswith("Comment:"): - tp_comment = line[8:].strip() - tp_current = 2 - elif line.startswith("Copyright:"): - tp_copyright = line[10:].strip() - tp_current = 3 - elif line.startswith("License:"): - if tp_current != 0: - tp_license = line[8:].strip() - tp_current = 4 - else: - tp_licensename = line[8:].strip() - tp_current = 5 - elif line.startswith(" "): - if tp_current == 1: - tp_file += "\n" + line.strip() - elif tp_current == 3: - tp_copyright += "\n" + line.strip() - elif tp_current == 5: - if line.strip() == ".": - tp_licensebody += "\n" - else: - tp_licensebody += line[1:] - else: - if tp_current != 0: - if tp_current == 5: - tp_licensetext.append([tp_licensename, tp_licensebody]) - - tp_licensename = "" - tp_licensebody = "" - else: - added = False - for i in tp: - if i[0] == tp_comment: - i[1].append([tp_file, tp_copyright, tp_license]) - added = True - break - if not added: - tp.append([tp_comment,[[tp_file, tp_copyright, tp_license]]]) - - tp_file = [] - tp_comment = "" - tp_copyright = [] - tp_license = "" - tp_current = 0 - - tp_licensetext.append([tp_licensename, tp_licensebody]) - - about_thirdparty = "" - about_tp_copyright_count = "" - about_tp_license = "" - about_tp_copyright = "" - about_tp_file = "" - - for i in tp: - about_thirdparty += "\t\"" + i[0] + "\",\n" - about_tp_copyright_count += str(len(i[1])) + ", " - for j in i[1]: - file_body = "" - copyright_body = "" - for k in j[0].split("\n"): - if file_body != "": - file_body += "\\n\"\n" - escaped_string = escape_string(k.strip()) - file_body += "\t\"" + escaped_string - for k in j[1].split("\n"): - if copyright_body != "": - copyright_body += "\\n\"\n" - escaped_string = escape_string(k.strip()) - copyright_body += "\t\"" + escaped_string - - about_tp_file += "\t" + file_body + "\",\n" - about_tp_copyright += "\t" + copyright_body + "\",\n" - about_tp_license += "\t\"" + j[2] + "\",\n" - - about_license_name = "" - about_license_body = "" - - for i in tp_licensetext: - body = "" - for j in i[1].split("\n"): - if body != "": - body += "\\n\"\n" - escaped_string = escape_string(j.strip()) - body += "\t\"" + escaped_string - - about_license_name += "\t\"" + i[0] + "\",\n" - about_license_body += "\t" + body + "\",\n" - - g.write("static const char *about_thirdparty[] = {\n") - g.write(about_thirdparty) - g.write("\t0\n") - g.write("};\n") - g.write("#define THIRDPARTY_COUNT " + str(len(tp)) + "\n") - - g.write("static const int about_tp_copyright_count[] = {\n\t") - g.write(about_tp_copyright_count) - g.write("0\n};\n") - - g.write("static const char *about_tp_file[] = {\n") - g.write(about_tp_file) - g.write("\t0\n") - g.write("};\n") - - g.write("static const char *about_tp_copyright[] = {\n") - g.write(about_tp_copyright) - g.write("\t0\n") - g.write("};\n") - - g.write("static const char *about_tp_license[] = {\n") - g.write(about_tp_license) - g.write("\t0\n") - g.write("};\n") - - g.write("static const char *about_license_name[] = {\n") - g.write(about_license_name) - g.write("\t0\n") - g.write("};\n") - g.write("#define LICENSE_COUNT " + str(len(tp_licensetext)) + "\n") - - g.write("static const char *about_license_body[] = {\n") - g.write(about_license_body) - g.write("\t0\n") - g.write("};\n") - - g.write("#endif\n") - - g.close() - fc.close() - f.close() - - def _make_doc_data_class_path(to_path): g = open_utf8(os.path.join(to_path,"doc_data_class_path.gen.h"), "w") g.write("static const int _doc_data_class_path_count = " + str(len(env.doc_class_path)) + ";\n") @@ -474,19 +211,6 @@ if env['tools']: env.Depends('#editor/builtin_fonts.gen.h', flist) env.Command('#editor/builtin_fonts.gen.h', flist, make_fonts_header) - # Authors - env.Depends('#editor/authors.gen.h', "../AUTHORS.md") - env.Command('#editor/authors.gen.h', "../AUTHORS.md", make_authors_header) - - # Donors - env.Depends('#editor/donors.gen.h', "../DONORS.md") - env.Command('#editor/donors.gen.h', "../DONORS.md", make_donors_header) - - # License - env.Depends('#editor/license.gen.h', ["../COPYRIGHT.txt", "../LICENSE.txt"]) - env.Command('#editor/license.gen.h', ["../COPYRIGHT.txt", "../LICENSE.txt"], make_license_header) - - env.add_source_files(env.editor_sources, "*.cpp") env.add_source_files(env.editor_sources, ["#thirdparty/misc/clipper.cpp"]) diff --git a/editor/editor_about.cpp b/editor/editor_about.cpp index 360ed620f6a8..11adcd4661a5 100644 --- a/editor/editor_about.cpp +++ b/editor/editor_about.cpp @@ -31,11 +31,11 @@ #include "editor_about.h" #include "editor_node.h" -#include "authors.gen.h" -#include "donors.gen.h" -#include "license.gen.h" -#include "version.h" -#include "version_hash.gen.h" +#include "core/authors.gen.h" +#include "core/donors.gen.h" +#include "core/license.gen.h" +#include "core/version.h" +#include "core/version_hash.gen.h" void EditorAbout::_notification(int p_what) { @@ -69,7 +69,7 @@ TextureRect *EditorAbout::get_logo() const { return _logo; } -ScrollContainer *EditorAbout::_populate_list(const String &p_name, const List &p_sections, const char **p_src[], const int p_flag_single_column) { +ScrollContainer *EditorAbout::_populate_list(const String &p_name, const List &p_sections, const char *const *const p_src[], const int p_flag_single_column) { ScrollContainer *sc = memnew(ScrollContainer); sc->set_name(p_name); @@ -82,7 +82,7 @@ ScrollContainer *EditorAbout::_populate_list(const String &p_name, const Listadd_child(_populate_list(TTR("Authors"), dev_sections, dev_src, 1)); // Donors @@ -163,7 +164,8 @@ EditorAbout::EditorAbout() { donor_sections.push_back(TTR("Gold Donors")); donor_sections.push_back(TTR("Silver Donors")); donor_sections.push_back(TTR("Bronze Donors")); - const char **donor_src[] = { donor_s_plat, donor_s_gold, donor_s_mini, donor_gold, donor_silver, donor_bronze }; + const char *const *donor_src[] = { DONORS_SPONSOR_PLAT, DONORS_SPONSOR_GOLD, + DONORS_SPONSOR_MINI, DONORS_GOLD, DONORS_SILVER, DONORS_BRONZE }; tc->add_child(_populate_list(TTR("Donors"), donor_sections, donor_src, 3)); // License @@ -172,7 +174,7 @@ EditorAbout::EditorAbout() { _license_text->set_name(TTR("License")); _license_text->set_h_size_flags(Control::SIZE_EXPAND_FILL); _license_text->set_v_size_flags(Control::SIZE_EXPAND_FILL); - _license_text->set_text(String::utf8(about_license)); + _license_text->set_text(String::utf8(GODOT_LICENSE_TEXT)); tc->add_child(_license_text); // Thirdparty License @@ -207,20 +209,27 @@ EditorAbout::EditorAbout() { tpl_ti_lc->set_selectable(0, false); int read_idx = 0; String long_text = ""; - for (int i = 0; i < THIRDPARTY_COUNT; i++) { + for (int component_index = 0; component_index < COPYRIGHT_INFO_COUNT; component_index++) { + const ComponentCopyright &component = COPYRIGHT_INFO[component_index]; TreeItem *ti = _tpl_tree->create_item(tpl_ti_tp); - String thirdparty = String(about_thirdparty[i]); - ti->set_text(0, thirdparty); - String text = thirdparty + "\n"; - long_text += "- " + thirdparty + "\n\n"; - for (int j = 0; j < about_tp_copyright_count[i]; j++) { - - text += "\n Files:\n " + String(about_tp_file[read_idx]).replace("\n", "\n ") + "\n"; - String copyright = String::utf8(" \xc2\xa9 ") + String::utf8(about_tp_copyright[read_idx]).replace("\n", String::utf8("\n \xc2\xa9 ")); + String component_name = component.name; + ti->set_text(0, component_name); + String text = component_name + "\n"; + long_text += "- " + component_name + "\n"; + for (int part_index = 0; part_index < component.part_count; part_index++) { + const ComponentCopyrightPart &part = component.parts[part_index]; + text += "\n Files:"; + for (int file_num = 0; file_num < part.file_count; file_num++) { + text += "\n " + String(part.files[file_num]); + } + String copyright; + for (int copyright_index = 0; copyright_index < part.copyright_count; copyright_index++) { + copyright += String::utf8("\n \xc2\xa9 ") + String::utf8(part.copyright_statements[copyright_index]); + } text += copyright; long_text += copyright; - String license = "\n License: " + String(about_tp_license[read_idx]) + "\n"; + String license = "\n License: " + String(part.license) + "\n"; text += license; long_text += license + "\n"; read_idx++; @@ -230,10 +239,10 @@ EditorAbout::EditorAbout() { for (int i = 0; i < LICENSE_COUNT; i++) { TreeItem *ti = _tpl_tree->create_item(tpl_ti_lc); - String licensename = String(about_license_name[i]); + String licensename = String(LICENSE_NAMES[i]); ti->set_text(0, licensename); long_text += "- " + licensename + "\n\n"; - String licensebody = String(about_license_body[i]); + String licensebody = String(LICENSE_BODIES[i]); ti->set_metadata(0, licensebody); long_text += " " + licensebody.replace("\n", "\n ") + "\n\n"; } diff --git a/editor/editor_about.h b/editor/editor_about.h index b32fdf656702..71d1c9518867 100644 --- a/editor/editor_about.h +++ b/editor/editor_about.h @@ -53,7 +53,7 @@ class EditorAbout : public AcceptDialog { private: void _license_tree_selected(); - ScrollContainer *_populate_list(const String &p_name, const List &p_sections, const char **p_src[], const int p_flag_single_column = 0); + ScrollContainer *_populate_list(const String &p_name, const List &p_sections, const char *const *const p_src[], const int p_flag_single_column = 0); Tree *_tpl_tree; RichTextLabel *_license_text; diff --git a/methods.py b/methods.py index 7cdc160075c1..b5aee9c22d7b 100644 --- a/methods.py +++ b/methods.py @@ -1,5 +1,5 @@ import os -from compat import iteritems +from compat import iteritems, open_utf8, escape_string def add_source_files(self, sources, filetype, lib_env=None, shared=False): @@ -515,6 +515,232 @@ def build_gles2_headers(target, source, env): for x in source: build_legacygl_header(str(x), include="drivers/gles2/shader_gles2.h", class_suffix="GLES2", output_attribs=True, gles2=True) +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].srcnode().abspath + dst = target[0].srcnode().abspath + f = open_utf8(src, "r") + g = open_utf8(dst, "w") + + g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n") + g.write("#ifndef _EDITOR_AUTHORS_H\n") + g.write("#define _EDITOR_AUTHORS_H\n") + + current_section = "" + 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 i in range(len(sections)): + if line.strip().endswith(sections[i]): + current_section = escape_string(sections_id[i]) + reading = True + g.write("const char *const " + current_section + "[] = {\n") + break + + if reading: + close_section() + + g.write("#endif\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].srcnode().abspath + dst = target[0].srcnode().abspath + f = open_utf8(src, "r") + g = open_utf8(dst, "w") + + g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n") + g.write("#ifndef _EDITOR_DONORS_H\n") + g.write("#define _EDITOR_DONORS_H\n") + + current_section = "" + 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 i in range(len(sections)): + if line.strip().endswith(sections[i]): + current_section = escape_string(sections_id[i]) + reading = True + g.write("const char *const " + current_section + "[] = {\n") + break + + if reading: + close_section() + + g.write("#endif\n") + + g.close() + f.close() + + +def make_license_header(target, source, env): + src_copyright = source[0].srcnode().abspath + src_license = source[1].srcnode().abspath + dst = target[0].srcnode().abspath + + 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_utf8(src_copyright, "r") 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 projects.itervalues(): + 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_utf8(dst, "w") as f: + + f.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n") + f.write("#ifndef _EDITOR_LICENSE_H\n") + f.write("#define _EDITOR_LICENSE_H\n") + f.write("const char *const GODOT_LICENSE_TEXT =") + + with open_utf8(src_license, "r") 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 projects.iteritems(): + 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 projects.iteritems(): + 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\n") def add_module_version_string(self,s): self.module_version_string += "." + s